diff --git a/CMakeLists.txt b/CMakeLists.txt index 90cd6983d..3b74693bc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ # -# Copyright 2013-2015 Software Radio Systems Limited +# Copyright 2013-2017 Software Radio Systems Limited # -# This file is part of the srsLTE library. +# 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 @@ -30,30 +30,135 @@ endif(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR}) ######################################################################## # Project setup ######################################################################## -CMAKE_MINIMUM_REQUIRED (VERSION 2.6) -PROJECT (SRSLTE) -MESSAGE( STATUS "CMAKE_SYSTEM: " ${CMAKE_SYSTEM} ) -MESSAGE( STATUS "CMAKE_SYSTEM_PROCESSOR: " ${CMAKE_SYSTEM_PROCESSOR} ) -MESSAGE( STATUS "CMAKE_CXX_COMPILER: " ${CMAKE_CXX_COMPILER} ) +cmake_minimum_required(VERSION 2.6) +project( SRSLTE ) +message( STATUS "CMAKE_SYSTEM: " ${CMAKE_SYSTEM} ) +message( STATUS "CMAKE_SYSTEM_PROCESSOR: " ${CMAKE_SYSTEM_PROCESSOR} ) +message( STATUS "CMAKE_CXX_COMPILER: " ${CMAKE_CXX_COMPILER} ) list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake/modules") include(SRSLTEVersion) #sets version information include(SRSLTEPackage) #setup cpack include(CTest) -set( CTEST_MEMORYCHECK_COMMAND valgrind ) +set(CTEST_MEMORYCHECK_COMMAND valgrind) configure_file( "${CMAKE_CURRENT_SOURCE_DIR}/CTestCustom.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/CTestCustom.cmake" IMMEDIATE @ONLY) +if(NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE Release) + message(STATUS "Build type not specified: defaulting to Release.") +endif(NOT CMAKE_BUILD_TYPE) +set(CMAKE_BUILD_TYPE ${CMAKE_BUILD_TYPE} CACHE STRING "") + ######################################################################## # Options ######################################################################## -option(StaticMKL "StaticMKL" OFF) -option(DisableBladeRF "DisableBladeRF" OFF) +option(STATIC_BUILD "Attempt to build with static linking" OFF) +option(RPATH "Enable RPATH" OFF) +option(ENABLE_VOLK "Enable VOLK SIMD library" OFF) +option(ENABLE_GUI "Enable GUI" ON) +option(ENABLE_SRSUE "Build srsUE application" ON) +option(ENABLE_SRSENB "Build srsENB application" ON) +option(ENABLE_BLADERF "Enable BladeRF" ON) +option(USE_LTE_RATES "Use standard LTE sampling rates" OFF) + set(GCC_ARCH native CACHE STRING "GCC compile for specific architecture.") + +######################################################################## +# Find dependencies +######################################################################## +find_package(Threads REQUIRED) + +find_package(Polarssl) +if (POLARSSL_FOUND) + set(SEC_INCLUDE_DIRS "${POLARSSL_INCLUDE_DIRS}") + set(SEC_LIBRARIES "${POLARSSL_LIBRARIES}") + add_definitions(-DHAVE_POLARSSL) +else(POLARSSL_FOUND) + find_package(MbedTLS REQUIRED) + if (MBEDTLS_FOUND) + set(SEC_INCLUDE_DIRS "${MBEDTLS_INCLUDE_DIRS}") + set(SEC_LIBRARIES "${MBEDTLS_LIBRARIES}") + add_definitions(-DHAVE_MBEDTLS) + endif (MBEDTLS_FOUND) +endif(POLARSSL_FOUND) + +find_package(UHD) +if(UHD_FOUND) + include_directories(${UHD_INCLUDE_DIRS}) + link_directories(${UHD_LIBRARY_DIRS}) +endif(UHD_FOUND) + +if(ENABLE_BLADERF) + find_package(bladeRF) + if(BLADERF_FOUND) + include_directories(${BLADERF_INCLUDE_DIRS}) + link_directories(${BLADERF_LIBRARY_DIRS}) + endif(BLADERF_FOUND) +endif(ENABLE_BLADERF) + +find_package(SoapySDR) +if(SOAPYSDR_FOUND) + include_directories(${SOAPYSDR_INCLUDE_DIRS}) + link_directories(${SOAPYSDR_LIBRARY_DIRS}) +endif(SOAPYSDR_FOUND) + +if(BLADERF_FOUND OR UHD_FOUND OR SOAPYSDR_FOUND) + set(RF_FOUND TRUE CACHE INTERNAL "RF frontend found") +else(BLADERF_FOUND OR UHD_FOUND OR SOAPYSDR_FOUND) + set(RF_FOUND FALSE CACHE INTERNAL "RF frontend found") + add_definitions(-DDISABLE_RF) +endif(BLADERF_FOUND OR UHD_FOUND OR SOAPYSDR_FOUND) + +if(ENABLE_SRSUE OR ENABLE_SRSENB) + # Find Boost + set(BOOST_REQUIRED_COMPONENTS + program_options + system + ) + 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) + + +if(ENABLE_GUI) + find_package(SRSGUI) + if(SRSGUI_FOUND) + add_definitions(-DENABLE_GUI) + include_directories(${SRSGUI_INCLUDE_DIRS}) + link_directories(${SRSGUI_LIBRARY_DIRS}) + endif(SRSGUI_FOUND) +endif(ENABLE_GUI) + +include(CheckFunctionExistsMath) +if(ENABLE_VOLK) + find_package(Volk) + if(VOLK_FOUND) + include_directories(${VOLK_INCLUDE_DIRS}) + link_directories(${VOLK_LIBRARY_DIRS}) + message(STATUS "Compiling with VOLK SIMD library.") + else(VOLK_FOUND) + message(STATUS "VOLK SIMD library NOT found. Using generic implementation.") + endif(VOLK_FOUND) +else(ENABLE_VOLK) + message(STATUS "VOLK library disabled") +endif(ENABLE_VOLK) + ######################################################################## # Install Dirs ######################################################################## @@ -73,13 +178,6 @@ set(INCLUDE_DIR include) set(DOC_DIR "share/doc/${CPACK_PACKAGE_NAME}") set(DATA_DIR share/${CPACK_PACKAGE_NAME}) - -if(NOT CMAKE_BUILD_TYPE) - set(CMAKE_BUILD_TYPE Release) - message(STATUS "Build type not specified: defaulting to Release.") -endif(NOT CMAKE_BUILD_TYPE) -set(CMAKE_BUILD_TYPE ${CMAKE_BUILD_TYPE} CACHE STRING "") - ######################################################################## # Compiler specific setup ######################################################################## @@ -91,69 +189,81 @@ macro(ADD_CXX_COMPILER_FLAG_IF_AVAILABLE flag have) endif(${have}) endmacro(ADD_CXX_COMPILER_FLAG_IF_AVAILABLE) -if(CMAKE_COMPILER_IS_GNUCXX) - #Any additional flags for CXX -endif(CMAKE_COMPILER_IS_GNUCXX) - - -if(CMAKE_COMPILER_IS_GNUCC) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wno-write-strings -Wno-format-extra-args -Winline -Wno-unused-result -Wno-format -std=c99 -D_GNU_SOURCE -g") +if(CMAKE_CXX_COMPILER_ID MATCHES "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=${GCC_ARCH} -Wall -Wno-comment -Wno-reorder -Wno-unused-but-set-variable -Wno-unused-variable -std=c++03") find_package(SSE) if(${CMAKE_BUILD_TYPE} STREQUAL "Debug") - find_package(SSE) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O0 -DDEBUG_MODE") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O0 -DDEBUG_MODE") + else(${CMAKE_BUILD_TYPE} STREQUAL "Debug") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3") + endif(${CMAKE_BUILD_TYPE} STREQUAL "Debug") + + find_package(SSE) + if (HAVE_AVX2) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mfpmath=sse -mavx2 -DLV_HAVE_AVX2 -DLV_HAVE_AVX -DLV_HAVE_SSE") + else (HAVE_AVX2) if(HAVE_AVX) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=${GCC_ARCH} -mfpmath=sse -mavx -DLV_HAVE_AVX -DLV_HAVE_SSE") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mfpmath=sse -mavx -DLV_HAVE_AVX -DLV_HAVE_SSE") elseif(HAVE_SSE) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=${GCC_ARCH} -mfpmath=sse -msse4.1 -DLV_HAVE_SSE") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mfpmath=sse -msse4.1 -DLV_HAVE_SSE") endif(HAVE_AVX) + endif (HAVE_AVX2) +endif(CMAKE_CXX_COMPILER_ID MATCHES "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") + + +if(CMAKE_C_COMPILER_ID MATCHES "GNU" OR CMAKE_C_COMPILER_ID MATCHES "Clang") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=${GCC_ARCH} -Wall -Wno-comment -Wno-write-strings -Wno-format-extra-args -Winline -Wno-unused-result -Wno-format -std=c99 -D_GNU_SOURCE") + + if(${CMAKE_BUILD_TYPE} STREQUAL "Debug") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O0 -DDEBUG_MODE") else(${CMAKE_BUILD_TYPE} STREQUAL "Debug") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3") - if (HAVE_AVX2) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=${GCC_ARCH} -mfpmath=sse -mavx2 -Ofast -funroll-loops -DLV_HAVE_AVX -DLV_HAVE_SSE") - else (HAVE_AVX2) - if(HAVE_AVX) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=${GCC_ARCH} -mfpmath=sse -mavx -Ofast -funroll-loops -DLV_HAVE_AVX -DLV_HAVE_SSE") - elseif(HAVE_SSE) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=${GCC_ARCH} -mfpmath=sse -msse4.1 -Ofast -funroll-loops -DLV_HAVE_SSE") - endif(HAVE_AVX) - endif (HAVE_AVX2) - endif(${CMAKE_BUILD_TYPE} STREQUAL "Debug") - - IF(${CMAKE_SYSTEM_PROCESSOR} MATCHES "arm") -set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mfpu=neon -march=native -DIS_ARM -DHAVE_NEON") -message(STATUS "have ARM") -ELSE(${CMAKE_SYSTEM_PROCESSOR} MATCHES "arm") -ENDIF(${CMAKE_SYSTEM_PROCESSOR} MATCHES "arm") -set(CMAKE_REQUIRED_FLAGS ${CMAKE_C_FLAGS}) + if (USE_LTE_RATES) + message(STATUS "Using standard LTE sampling rates") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DFORCE_STANDARD_RATE") + endif (USE_LTE_RATES) + + find_package(SSE) + if (HAVE_AVX2) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mfpmath=sse -mavx2 -DLV_HAVE_AVX2 -DLV_HAVE_AVX -DLV_HAVE_SSE") + else (HAVE_AVX2) + if(HAVE_AVX) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mfpmath=sse -mavx -DLV_HAVE_AVX -DLV_HAVE_SSE") + elseif(HAVE_SSE) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mfpmath=sse -msse4.1 -DLV_HAVE_SSE") + endif(HAVE_AVX) + endif (HAVE_AVX2) + + if(NOT ${CMAKE_BUILD_TYPE} STREQUAL "Debug") + if(HAVE_SSE) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Ofast -funroll-loops") + endif(HAVE_SSE) + endif(NOT ${CMAKE_BUILD_TYPE} STREQUAL "Debug") + + + if(${CMAKE_SYSTEM_PROCESSOR} MATCHES "arm") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mfpu=neon -march=native -DIS_ARM -DHAVE_NEON") + message(STATUS "have ARM") + endif(${CMAKE_SYSTEM_PROCESSOR} MATCHES "arm") + set(CMAKE_REQUIRED_FLAGS ${CMAKE_C_FLAGS}) if(NOT WIN32) ADD_CXX_COMPILER_FLAG_IF_AVAILABLE(-fvisibility=hidden HAVE_VISIBILITY_HIDDEN) endif(NOT WIN32) -endif(CMAKE_COMPILER_IS_GNUCC) - -if(MSVC) - include_directories(${PROJECT_SOURCE_DIR}/msvc) #missing headers - add_definitions(-D_WIN32_WINNT=0x0501) #minimum version required is windows xp - add_definitions(-DNOMINMAX) #disables stupidity and enables std::min and std::max - add_definitions( #stop all kinds of compatibility warnings - -D_SCL_SECURE_NO_WARNINGS - -D_CRT_SECURE_NO_WARNINGS - -D_CRT_SECURE_NO_DEPRECATE - -D_CRT_NONSTDC_NO_DEPRECATE - ) - add_definitions(/MP) #build with multiple processors -endif(MSVC) +endif(CMAKE_C_COMPILER_ID MATCHES "GNU" OR CMAKE_C_COMPILER_ID MATCHES "Clang") if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") # The following is needed for weak linking to work under OS X set(CMAKE_SHARED_LINKER_FLAGS "-undefined dynamic_lookup") endif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") +message(STATUS "CMAKE_C_FLAGS is ${CMAKE_C_FLAGS}") +message(STATUS "CMAKE_CXX_FLAGS is ${CMAKE_CXX_FLAGS}") + ######################################################################## # Create uninstall targets ######################################################################## @@ -181,10 +291,41 @@ message(STATUS "Building for version: ${VERSION}") ######################################################################## # Add general includes and dependencies ######################################################################## -include_directories(${PROJECT_BINARY_DIR}/srslte/include/) -include_directories(${PROJECT_SOURCE_DIR}/srslte/include/) +include_directories(${PROJECT_BINARY_DIR}/lib/include) +include_directories(${PROJECT_SOURCE_DIR}/lib/include) + +######################################################################## +# Add headers to cmake project (useful for IDEs) +######################################################################## +set(HEADERS_ALL "") +file(GLOB headers *) +foreach(_header ${headers}) + if(IS_DIRECTORY ${_header}) + file(GLOB_RECURSE tmp "${_header}/*.h") + list(APPEND HEADERS_ALL ${tmp}) + endif(IS_DIRECTORY ${_header}) +endforeach() +add_custom_target(add_srslte_headers SOURCES ${HEADERS_ALL}) ######################################################################## # Add the subdirectories ######################################################################## -add_subdirectory(srslte) +add_subdirectory(lib) + +if(RF_FOUND) + if(ENABLE_SRSUE) + message(STATUS "Building with srsUE") + add_subdirectory(srsue) + else(ENABLE_SRSUE) + message(STATUS "srsUE build disabled") + endif(ENABLE_SRSUE) + + if(ENABLE_SRSENB) + message(STATUS "Building with srsENB") + add_subdirectory(srsenb) + else(ENABLE_SRSENB) + message(STATUS "srsUE build disabled") + endif(ENABLE_SRSENB) +else(RF_FOUND) + message(STATUS "srsUE and srsENB builds disabled due to missing RF driver") +endif(RF_FOUND) diff --git a/cmake/modules/FindLibConfig.cmake b/cmake/modules/FindLibConfig.cmake new file mode 100644 index 000000000..49bed9d26 --- /dev/null +++ b/cmake/modules/FindLibConfig.cmake @@ -0,0 +1,75 @@ +# Find the CUnit includes and library +# +# This module defines +# LIBCONFIG_INCLUDE_DIR, where to find cppunit include files, etc. +# LIBCONFIG_LIBRARIES, the libraries to link against to use CppUnit. +# LIBCONFIG_STATIC_LIBRARIY_PATH +# LIBCONFIG_FOUND, If false, do not try to use CppUnit. + +# also defined, but not for general use are +# LIBCONFIG_LIBRARY, where to find the CUnit library. + +#MESSAGE("Searching for libconfig library") + +FIND_PATH(LIBCONFIG_INCLUDE_DIR libconfig.h + /usr/local/include + /usr/include +) + +FIND_PATH(LIBCONFIGPP_INCLUDE_DIR libconfig.h++ + /usr/local/include + /usr/include +) + +FIND_LIBRARY(LIBCONFIG_LIBRARY config + /usr/local/lib + /usr/lib +) + +FIND_LIBRARY(LIBCONFIGPP_LIBRARY config++ + /usr/local/lib + /usr/lib +) + +FIND_LIBRARY(LIBCONFIG_STATIC_LIBRARY "libconfig${CMAKE_STATIC_LIBRARY_SUFFIX}" + /usr/local/lib + /usr/lib +) + +FIND_LIBRARY(LIBCONFIGPP_STATIC_LIBRARY "libconfig++${CMAKE_STATIC_LIBRARY_SUFFIX}" + /usr/local/lib + /usr/lib +) + + +IF(LIBCONFIG_INCLUDE_DIR) + IF(LIBCONFIG_LIBRARY) + SET(LIBCONFIG_FOUND TRUE) + SET(LIBCONFIG_LIBRARIES ${LIBCONFIG_LIBRARY}) + SET(LIBCONFIG_STATIC_LIBRARY_PATH ${LIBCONFIG_STATIC_LIBRARY}) + ENDIF(LIBCONFIG_LIBRARY) +ENDIF(LIBCONFIG_INCLUDE_DIR) + +IF(LIBCONFIGPP_INCLUDE_DIR) + IF(LIBCONFIGPP_LIBRARY) + SET(LIBCONFIGPP_FOUND TRUE) + SET(LIBCONFIGPP_LIBRARIES ${LIBCONFIGPP_LIBRARY}) + SET(LIBCONFIGPP_STATIC_LIBRARY_PATH ${LIBCONFIGPP_STATIC_LIBRARY}) + ENDIF(LIBCONFIGPP_LIBRARY) +ENDIF(LIBCONFIGPP_INCLUDE_DIR) + +IF (LIBCONFIGPP_FOUND) + IF (NOT LibConfig_FIND_QUIETLY) + MESSAGE(STATUS "Found LibConfig++: ${LIBCONFIGPP_LIBRARIES}" ) + MESSAGE(STATUS "static LibConfig++ path: ${LIBCONFIGPP_STATIC_LIBRARY_PATH}") + MESSAGE(STATUS "Found LibConfig: ${LIBCONFIG_LIBRARIES}") + MESSAGE(STATUS "static LibConfig path: ${LIBCONFIG_STATIC_LIBRARY_PATH}") + ENDIF (NOT LibConfig_FIND_QUIETLY) +ELSE (LIBCONFIGPP_FOUND) + IF (LibConfig_FIND_REQUIRED) + MESSAGE(SEND_ERROR "Could NOT find LibConfig") + ENDIF (LibConfig_FIND_REQUIRED) +ENDIF (LIBCONFIGPP_FOUND) + +MARK_AS_ADVANCED(LIBCONFIG_INCLUDE_DIR LIBCONFIG_LIBRARY LIBCONFIG_STATIC_LIBRARY) +MARK_AS_ADVANCED(LIBCONFIGPP_INCLUDE_DIR LIBCONFIGPP_LIBRARY LIBCONFIGPP_STATIC_LIBRARY) diff --git a/cmake/modules/FindLimeSDR.cmake b/cmake/modules/FindLimeSDR.cmake new file mode 100644 index 000000000..0cfec6f17 --- /dev/null +++ b/cmake/modules/FindLimeSDR.cmake @@ -0,0 +1,28 @@ +if(NOT LIMESDR_FOUND) + pkg_check_modules (LIMESDR_PKG LimeSuite) + + find_path(LIMESDR_INCLUDE_DIRS + NAMES LimeSuite.h + PATHS ${LIMESDR_PKG_INCLUDE_DIRS} + /usr/include/lime + /usr/local/include/lime + ) + + find_library(LIMESDR_LIBRARIES + NAMES LimeSuite + PATHS ${LIMESDR_PKG_LIBRARY_DIRS} + /usr/lib + /usr/local/lib + ) + +if(LIMESDR_INCLUDE_DIRS AND LIMESDR_LIBRARIES) + set(LIMESDR_FOUND TRUE CACHE INTERNAL "libLimeSuite found") + message(STATUS "Found libLimeSuite: ${LIMESDR_INCLUDE_DIRS}, ${LIMESDR_LIBRARIES}") +else(LIMESDR_INCLUDE_DIRS AND LIMESDR_LIBRARIES) + set(LIMESDR_FOUND FALSE CACHE INTERNAL "libLimeSuite found") + message(STATUS "libLimeSuite not found.") +endif(LIMESDR_INCLUDE_DIRS AND LIMESDR_LIBRARIES) + +mark_as_advanced(LIMESDR_LIBRARIES LIMESDR_INCLUDE_DIRS) + +endif(NOT LIMESDR_FOUND) diff --git a/cmake/modules/FindMKL.cmake b/cmake/modules/FindMKL.cmake index 80adeafd7..138d4ca59 100644 --- a/cmake/modules/FindMKL.cmake +++ b/cmake/modules/FindMKL.cmake @@ -50,4 +50,4 @@ if(MKL_FOUND) MESSAGE(STATUS "Found MKL_STATIC_LIBRARIES: ${MKL_STATIC_LIBRARIES}" ) endif(MKL_FOUND) -mark_as_advanced(MKL_INCLUDE_DIRS MKL_LIBRARIES MKL_CORE MKL_ILP MKL_SEQ) +mark_as_advanced(MKL_INCLUDE_DIR MKL_FFTW_INCLUDE_DIR MKL_LIBRARIES MKL_CORE MKL_ILP MKL_SEQ) diff --git a/cmake/modules/FindMbedTLS.cmake b/cmake/modules/FindMbedTLS.cmake new file mode 100644 index 000000000..94d814874 --- /dev/null +++ b/cmake/modules/FindMbedTLS.cmake @@ -0,0 +1,40 @@ +# - Try to find mbedtls +# +# Once done this will define +# MBEDTLS_FOUND - System has mbedtls +# MBEDTLS_INCLUDE_DIRS - The mbedtls include directories +# MBEDTLS_LIBRARIES - The mbedtls library + +INCLUDE(FindPkgConfig) +PKG_CHECK_MODULES(PC_MBEDTLS mbedtls) + +#find Mbedtls +FIND_PATH( + MBEDTLS_INCLUDE_DIRS + NAMES mbedtls/md.h + HINTS $ENV{MBEDTLS_DIR}/include + ${PC_MBEDTLS_INCLUDEDIR} + ${CMAKE_INSTALL_PREFIX}/include + PATHS /usr/local/include + /usr/include +) + +FIND_LIBRARY( + MBEDTLS_LIBRARIES + NAMES mbedcrypto + HINTS $ENV{MBEDTLS_DIR}/lib + ${PC_MBEDTLS_LIBDIR} + ${CMAKE_INSTALL_PREFIX}/lib + ${CMAKE_INSTALL_PREFIX}/lib64 + PATHS /usr/local/lib + /usr/local/lib64 + /usr/lib + /usr/lib64 +) + +message(STATUS "MBEDTLS LIBRARIES: " ${MBEDTLS_LIBRARIES}) +message(STATUS "MBEDTLS INCLUDE DIRS: " ${MBEDTLS_INCLUDE_DIRS}) + +INCLUDE(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(MBEDTLS DEFAULT_MSG MBEDTLS_LIBRARIES MBEDTLS_INCLUDE_DIRS) +MARK_AS_ADVANCED(MBEDTLS_LIBRARIES MBEDTLS_INCLUDE_DIRS) diff --git a/cmake/modules/FindPolarssl.cmake b/cmake/modules/FindPolarssl.cmake new file mode 100644 index 000000000..ccf0d6b91 --- /dev/null +++ b/cmake/modules/FindPolarssl.cmake @@ -0,0 +1,39 @@ +# - Try to find polarssl +# +# Once done this will define +# POLARSSL_FOUND - System has polarssl +# POLARSSL_INCLUDE_DIRS - The polarssl include directories +# POLARSSL_LIBRARIES - The polarssl library + +INCLUDE(FindPkgConfig) +PKG_CHECK_MODULES(PC_POLARSSL polarssl) + +FIND_PATH( + POLARSSL_INCLUDE_DIRS + NAMES polarssl/version.h + HINTS $ENV{POLARSSL_DIR}/include + ${PC_POLARSSL_INCLUDEDIR} + ${CMAKE_INSTALL_PREFIX}/include + PATHS /usr/local/include + /usr/include +) + +FIND_LIBRARY( + POLARSSL_LIBRARIES + NAMES polarssl + HINTS $ENV{POLARSSL_DIR}/lib + ${PC_POLARSSL_LIBDIR} + ${CMAKE_INSTALL_PREFIX}/lib + ${CMAKE_INSTALL_PREFIX}/lib64 + PATHS /usr/local/lib + /usr/local/lib64 + /usr/lib + /usr/lib64 +) + +message(STATUS "POLARSSL LIBRARIES: " ${POLARSSL_LIBRARIES}) +message(STATUS "POLARSSL INCLUDE DIRS: " ${POLARSSL_INCLUDE_DIRS}) + +INCLUDE(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(POLARSSL DEFAULT_MSG POLARSSL_LIBRARIES POLARSSL_INCLUDE_DIRS) +MARK_AS_ADVANCED(POLARSSL_LIBRARIES POLARSSL_INCLUDE_DIRS) diff --git a/cmake/modules/FindSCTP.cmake b/cmake/modules/FindSCTP.cmake new file mode 100644 index 000000000..1ce75edff --- /dev/null +++ b/cmake/modules/FindSCTP.cmake @@ -0,0 +1,38 @@ +# - Try to find sctp +# +# Once done this will define +# SCTP_FOUND - System has mbedtls +# SCTP_INCLUDE_DIRS - The mbedtls include directories +# SCTP_LIBRARIES - The mbedtls library + +INCLUDE(FindPkgConfig) +PKG_CHECK_MODULES(PC_SCTP sctp) + +#find Mbedtls +FIND_PATH( + SCTP_INCLUDE_DIRS + NAMES netinet/sctp.h + HINTS ${PC_SCTP_INCLUDEDIR} + ${CMAKE_INSTALL_PREFIX}/include + PATHS /usr/local/include + /usr/include +) + +FIND_LIBRARY( + SCTP_LIBRARIES + NAMES sctp + HINTS ${PC_SCTP_LIBDIR} + ${CMAKE_INSTALL_PREFIX}/lib + ${CMAKE_INSTALL_PREFIX}/lib64 + PATHS /usr/local/lib + /usr/local/lib64 + /usr/lib + /usr/lib64 +) + +message(STATUS "SCTP LIBRARIES: " ${SCTP_LIBRARIES}) +message(STATUS "SCTP INCLUDE DIRS: " ${SCTP_INCLUDE_DIRS}) + +INCLUDE(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(SCTP DEFAULT_MSG SCTP_LIBRARIES SCTP_INCLUDE_DIRS) +MARK_AS_ADVANCED(SCTP_LIBRARIES SCTP_INCLUDE_DIRS) diff --git a/cmake/modules/FindSSE.cmake b/cmake/modules/FindSSE.cmake index a7b41d0a8..306fdc6ff 100644 --- a/cmake/modules/FindSSE.cmake +++ b/cmake/modules/FindSSE.cmake @@ -49,7 +49,8 @@ if (ENABLE_SSE) b = _mm256_loadu_ps( src ); c = _mm256_add_ps( a, b ); _mm256_storeu_ps( dst, c ); - for( int i = 0; i < 8; i++ ){ + int i = 0; + for( i = 0; i < 8; i++ ){ if( ( src[i] + src[i] ) != dst[i] ){ return -1; } @@ -82,7 +83,8 @@ if (ENABLE_SSE) b = _mm256_loadu_si256( (__m256i*)src ); c = _mm256_add_epi32( a, b ); _mm256_storeu_si256( (__m256i*)dst, c ); - for( int i = 0; i < 8; i++ ){ + int i = 0; + for( i = 0; i < 8; i++ ){ if( ( src[i] + src[i] ) != dst[i] ){ return -1; } diff --git a/cmake/modules/FindSoapySDR.cmake b/cmake/modules/FindSoapySDR.cmake new file mode 100644 index 000000000..75b69a85d --- /dev/null +++ b/cmake/modules/FindSoapySDR.cmake @@ -0,0 +1,32 @@ + +message(STATUS "FINDING SOAPY.") +if(NOT SOAPYSDR_FOUND) + pkg_check_modules (SOAPYSDR_PKG SoapySDR) + + find_path(SOAPYSDR_INCLUDE_DIRS + NAMES Device.h + PATHS ${SOAPYSDR_PKG_INCLUDE_DIRS} + /usr/include/SoapySDR + /usr/local/include/SoapySDR + ) + + find_library(SOAPYSDR_LIBRARIES + NAMES SoapySDR + PATHS ${LIMESDR_PKG_LIBRARY_DIRS} + /usr/lib + /usr/local/lib + /usr/lib/arm-linux-gnueabihf + ) + + +if(SOAPYSDR_INCLUDE_DIRS AND SOAPYSDR_LIBRARIES) + set(SOAPYSDR_FOUND TRUE CACHE INTERNAL "libSOAPYSDR found") + message(STATUS "Found libSOAPYSDR: ${SOAPYSDR_INCLUDE_DIRS}, ${SOAPYSDR_LIBRARIES}") +else(SOAPYSDR_INCLUDE_DIRS AND SOAPYSDR_LIBRARIES) + set(SOAPYSDR_FOUND FALSE CACHE INTERNAL "libSOAPYSDR found") + message(STATUS "libSOAPYSDR not found.") +endif(SOAPYSDR_INCLUDE_DIRS AND SOAPYSDR_LIBRARIES) + +mark_as_advanced(SOAPYSDR_LIBRARIES SOAPYSDR_INCLUDE_DIRS) + +endif(NOT SOAPYSDR_FOUND) diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt new file mode 100644 index 000000000..6b638cef5 --- /dev/null +++ b/lib/CMakeLists.txt @@ -0,0 +1,34 @@ +# +# Copyright 2013-2017 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/. +# + +######################################################################## +# Add subdirectories +######################################################################## +add_subdirectory(src) +add_subdirectory(include) +add_subdirectory(examples) +add_subdirectory(test) + +######################################################################## +# Install library headers +######################################################################## +INSTALL( DIRECTORY include/ + DESTINATION "${INCLUDE_DIR}" + FILES_MATCHING PATTERN "*.h" ) diff --git a/srslte/examples/CMakeLists.txt b/lib/examples/CMakeLists.txt similarity index 80% rename from srslte/examples/CMakeLists.txt rename to lib/examples/CMakeLists.txt index b8357fd05..965f2706c 100644 --- a/srslte/examples/CMakeLists.txt +++ b/lib/examples/CMakeLists.txt @@ -1,7 +1,7 @@ # -# Copyright 2013-2015 Software Radio Systems Limited +# Copyright 2013-2017 Software Radio Systems Limited # -# This file is part of the srsLTE library. +# 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 @@ -24,17 +24,17 @@ ################################################################# add_executable(synch_file synch_file.c) -target_link_libraries(synch_file srslte) +target_link_libraries(synch_file srslte_phy) ################################################################# # These can be compiled without UHD or graphics support ################################################################# add_executable(pdsch_ue pdsch_ue.c) -target_link_libraries(pdsch_ue srslte pthread) +target_link_libraries(pdsch_ue srslte_phy pthread) add_executable(pdsch_enodeb pdsch_enodeb.c) -target_link_libraries(pdsch_enodeb srslte pthread) +target_link_libraries(pdsch_enodeb srslte_phy pthread) if(RF_FOUND) @@ -59,19 +59,19 @@ endif(SRSGUI_FOUND) if(RF_FOUND) add_executable(cell_search cell_search.c) - target_link_libraries(cell_search srslte) + target_link_libraries(cell_search srslte_phy) add_executable(cell_measurement cell_measurement.c) - target_link_libraries(cell_measurement srslte) + target_link_libraries(cell_measurement srslte_phy) add_executable(usrp_capture usrp_capture.c) - target_link_libraries(usrp_capture srslte) + target_link_libraries(usrp_capture srslte_phy) add_executable(usrp_capture_sync usrp_capture_sync.c) - target_link_libraries(usrp_capture_sync srslte) + target_link_libraries(usrp_capture_sync srslte_phy) add_executable(usrp_txrx usrp_txrx.c) - target_link_libraries(usrp_txrx srslte) + target_link_libraries(usrp_txrx srslte_phy) message(STATUS " examples will be installed.") diff --git a/srslte/examples/cell_measurement.c b/lib/examples/cell_measurement.c similarity index 97% rename from srslte/examples/cell_measurement.c rename to lib/examples/cell_measurement.c index 8c9d95fe3..bc8262b29 100644 --- a/srslte/examples/cell_measurement.c +++ b/lib/examples/cell_measurement.c @@ -38,8 +38,8 @@ #define ENABLE_AGC_DEFAULT #include "srslte/srslte.h" -#include "srslte/rf/rf.h" -#include "srslte/rf/rf_utils.h" +#include "srslte/phy/rf/rf.h" +#include "srslte/phy/rf/rf_utils.h" cell_search_cfg_t cell_detect_config = { SRSLTE_DEFAULT_MAX_FRAMES_PBCH, @@ -348,7 +348,7 @@ int main(int argc, char **argv) { if ((nframes%100) == 0 || rx_gain_offset == 0) { if (srslte_rf_has_rssi(&rf)) { - rx_gain_offset = 10*log10(rssi)-srslte_rf_get_rssi(&rf); + rx_gain_offset = 10*log10(rssi*1000)-srslte_rf_get_rssi(&rf); } else { rx_gain_offset = srslte_rf_get_rx_gain(&rf); } @@ -357,10 +357,10 @@ int main(int argc, char **argv) { // Plot and Printf if ((nframes%10) == 0) { - printf("CFO: %+8.4f kHz, SFO: %+8.4f kHz, RSSI: %5.1f dBm, RSSI/ref-symbol: %+5.1f dBm, " + printf("CFO: %+8.4f kHz, SFO: %+8.4f Hz, RSSI: %5.1f dBm, RSSI/ref-symbol: %+5.1f dBm, " "RSRP: %+5.1f dBm, RSRQ: %5.1f dB, SNR: %5.1f dB\r", srslte_ue_sync_get_cfo(&ue_sync)/1000, srslte_ue_sync_get_sfo(&ue_sync), - 10*log10(rssi*1000) - rx_gain_offset, + 10*log10(rssi*1000) - rx_gain_offset, 10*log10(rssi_utra*1000)- rx_gain_offset, 10*log10(rsrp*1000) - rx_gain_offset, 10*log10(rsrq), 10*log10(snr)); diff --git a/srslte/examples/cell_search.c b/lib/examples/cell_search.c similarity index 99% rename from srslte/examples/cell_search.c rename to lib/examples/cell_search.c index fc684578a..8ab560e0c 100644 --- a/srslte/examples/cell_search.c +++ b/lib/examples/cell_search.c @@ -37,11 +37,11 @@ #include "srslte/srslte.h" -#include "srslte/rf/rf_utils.h" +#include "srslte/phy/rf/rf_utils.h" #ifndef DISABLE_RF -#include "srslte/rf/rf.h" +#include "srslte/phy/rf/rf.h" #endif #define MHZ 1000000 diff --git a/srslte/examples/pdsch_enodeb.c b/lib/examples/pdsch_enodeb.c similarity index 99% rename from srslte/examples/pdsch_enodeb.c rename to lib/examples/pdsch_enodeb.c index 0d3aa6c4a..800e04de9 100644 --- a/srslte/examples/pdsch_enodeb.c +++ b/lib/examples/pdsch_enodeb.c @@ -41,7 +41,7 @@ #ifndef DISABLE_RF -#include "srslte/rf/rf.h" +#include "srslte/phy/rf/rf.h" srslte_rf_t rf; #else #warning Compiling pdsch_ue with no RF support diff --git a/srslte/examples/pdsch_ue.c b/lib/examples/pdsch_ue.c similarity index 93% rename from srslte/examples/pdsch_ue.c rename to lib/examples/pdsch_ue.c index eb14959de..f7487c529 100644 --- a/srslte/examples/pdsch_ue.c +++ b/lib/examples/pdsch_ue.c @@ -42,8 +42,8 @@ #define ENABLE_AGC_DEFAULT #ifndef DISABLE_RF -#include "srslte/rf/rf.h" -#include "srslte/rf/rf_utils.h" +#include "srslte/phy/rf/rf.h" +#include "srslte/phy/rf/rf_utils.h" cell_search_cfg_t cell_detect_config = { SRSLTE_DEFAULT_MAX_FRAMES_PBCH, @@ -76,6 +76,7 @@ bool plot_track = true; ***********************************************************************/ typedef struct { int nof_subframes; + int cpu_affinity; bool disable_plots; bool disable_plots_except_constellation; bool disable_cfo; @@ -95,7 +96,8 @@ typedef struct { int net_port; char *net_address; int net_port_signal; - char *net_address_signal; + char *net_address_signal; + int decimate; }prog_args_t; void args_default(prog_args_t *args) { @@ -124,6 +126,8 @@ void args_default(prog_args_t *args) { args->net_address = "127.0.0.1"; args->net_port_signal = -1; args->net_address_signal = "127.0.0.1"; + args->decimate = 0; + args->cpu_affinity = -1; } void usage(prog_args_t *args, char *prog) { @@ -155,6 +159,7 @@ void usage(prog_args_t *args, char *prog) { #else printf("\t plots are disabled. Graphics library not available\n"); #endif + printf("\t-y set the cpu affinity mask [Default %d] \n ",args->cpu_affinity); printf("\t-n nof_subframes [Default %d]\n", args->nof_subframes); printf("\t-s remote UDP port to send input signal (-1 does nothing with it) [Default %d]\n", args->net_port_signal); printf("\t-S remote UDP address to send input signal [Default %s]\n", args->net_address_signal); @@ -166,7 +171,7 @@ void usage(prog_args_t *args, char *prog) { void parse_args(prog_args_t *args, int argc, char **argv) { int opt; args_default(args); - while ((opt = getopt(argc, argv, "aAoglipPcOCtdDnvrfuUsS")) != -1) { + while ((opt = getopt(argc, argv, "aAoglipPcOCtdDnvrfuUsSZy")) != -1) { switch (opt) { case 'i': args->input_file_name = argv[optind]; @@ -234,6 +239,12 @@ void parse_args(prog_args_t *args, int argc, char **argv) { case 'v': srslte_verbose++; break; + case 'Z': + args->decimate = atoi(argv[optind]); + break; + case 'y': + args->cpu_affinity = atoi(argv[optind]); + break; default: usage(args, argv[0]); exit(-1); @@ -289,6 +300,7 @@ srslte_netsink_t net_sink, net_sink_signal; int main(int argc, char **argv) { int ret; + int decimate = 1; srslte_cell_t cell; int64_t sf_cnt; srslte_ue_mib_t ue_mib; @@ -302,7 +314,25 @@ int main(int argc, char **argv) { float cfo = 0; parse_args(&prog_args, argc, argv); - + + if(prog_args.cpu_affinity > -1) { + + cpu_set_t cpuset; + pthread_t thread; + + thread = pthread_self(); + for(int i = 0; i < 8;i++){ + if(((prog_args.cpu_affinity >> i) & 0x01) == 1){ + printf("Setting pdsch_ue with affinity to core %d\n", i); + CPU_SET((size_t) i , &cpuset); + } + if(pthread_setaffinity_np(thread, sizeof(cpu_set_t), &cpuset)){ + fprintf(stderr, "Error setting main thread affinity to %d \n", prog_args.cpu_affinity); + exit(-1); + } + } + } + if (prog_args.net_port > 0) { if (srslte_netsink_init(&net_sink, prog_args.net_address, prog_args.net_port, SRSLTE_NETSINK_TCP)) { fprintf(stderr, "Error initiating UDP socket to %s:%d\n", prog_args.net_address, prog_args.net_port); @@ -365,6 +395,7 @@ int main(int argc, char **argv) { } while (ret == 0 && !go_exit); if (go_exit) { + srslte_rf_close(&rf); exit(0); } @@ -412,7 +443,19 @@ int main(int argc, char **argv) { } else { #ifndef DISABLE_RF - if (srslte_ue_sync_init_multi(&ue_sync, cell, srslte_rf_recv_wrapper, prog_args.rf_nof_rx_ant, (void*) &rf)) { + if(prog_args.decimate) + { + if(prog_args.decimate > 4 || prog_args.decimate < 0) + { + printf("Invalid decimation factor, setting to 1 \n"); + } + else + { + decimate = prog_args.decimate; + //ue_sync.decimate = prog_args.decimate; + } + } + if (srslte_ue_sync_init_multi_decim(&ue_sync, cell, srslte_rf_recv_wrapper, prog_args.rf_nof_rx_ant, (void*) &rf,decimate)) { fprintf(stderr, "Error initiating ue_sync\n"); exit(-1); } @@ -515,7 +558,7 @@ int main(int argc, char **argv) { if ((srslte_ue_sync_get_sfidx(&ue_sync) == 5 && (sfn%2)==0)) { decode_pdsch = true; } else { - decode_pdsch = false; + decode_pdsch = true; } } if (decode_pdsch) { diff --git a/srslte/examples/synch_file.c b/lib/examples/synch_file.c similarity index 100% rename from srslte/examples/synch_file.c rename to lib/examples/synch_file.c diff --git a/srslte/examples/tutorial_examples/CMakeLists.txt b/lib/examples/tutorial_examples/CMakeLists.txt similarity index 83% rename from srslte/examples/tutorial_examples/CMakeLists.txt rename to lib/examples/tutorial_examples/CMakeLists.txt index 04248ef9c..95c1f1cb7 100644 --- a/srslte/examples/tutorial_examples/CMakeLists.txt +++ b/lib/examples/tutorial_examples/CMakeLists.txt @@ -1,7 +1,7 @@ # -# Copyright 2013-2015 Software Radio Systems Limited +# Copyright 2013-2017 Software Radio Systems Limited # -# This file is part of the srsLTE library. +# 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 @@ -26,10 +26,10 @@ if(SRSGUI_FOUND AND UHD_FOUND) add_executable(pss pss.c) - target_link_libraries(pss srslte ${SRSGUI_LIBRARIES}) + target_link_libraries(pss srslte_phy ${SRSGUI_LIBRARIES}) add_executable(simple_tx simple_tx.c) - target_link_libraries(simple_tx srslte) + target_link_libraries(simple_tx srslte_phy) endif(SRSGUI_FOUND AND UHD_FOUND) diff --git a/srslte/examples/tutorial_examples/pss.c b/lib/examples/tutorial_examples/pss.c similarity index 99% rename from srslte/examples/tutorial_examples/pss.c rename to lib/examples/tutorial_examples/pss.c index fc2f43242..da487895c 100644 --- a/srslte/examples/tutorial_examples/pss.c +++ b/lib/examples/tutorial_examples/pss.c @@ -35,7 +35,7 @@ #include #include "srslte/srslte.h" -#include "srslte/rf/rf.h" +#include "srslte/phy/rf/rf.h" #ifndef DISABLE_GRAPHICS diff --git a/srslte/examples/tutorial_examples/simple_tx.c b/lib/examples/tutorial_examples/simple_tx.c similarity index 99% rename from srslte/examples/tutorial_examples/simple_tx.c rename to lib/examples/tutorial_examples/simple_tx.c index c82b14748..b56ccb281 100644 --- a/srslte/examples/tutorial_examples/simple_tx.c +++ b/lib/examples/tutorial_examples/simple_tx.c @@ -35,7 +35,7 @@ #include "srslte/srslte.h" -#include "srslte/rf/rf.h" +#include "srslte/phy/rf/rf.h" srslte_rf_t rf; char *output_file_name = NULL; diff --git a/srslte/examples/usrp_capture.c b/lib/examples/usrp_capture.c similarity index 98% rename from srslte/examples/usrp_capture.c rename to lib/examples/usrp_capture.c index 148a6f070..2692deb0d 100644 --- a/srslte/examples/usrp_capture.c +++ b/lib/examples/usrp_capture.c @@ -36,8 +36,8 @@ #include #include "srslte/srslte.h" -#include "srslte/rf/rf.h" -#include "srslte/io/filesink.h" +#include "srslte/phy/rf/rf.h" +#include "srslte/phy/io/filesink.h" static bool keep_running = true; char *output_file_name; diff --git a/srslte/examples/usrp_capture_sync.c b/lib/examples/usrp_capture_sync.c similarity index 98% rename from srslte/examples/usrp_capture_sync.c rename to lib/examples/usrp_capture_sync.c index 6e7f74cb6..6d2ec18dc 100644 --- a/srslte/examples/usrp_capture_sync.c +++ b/lib/examples/usrp_capture_sync.c @@ -36,7 +36,7 @@ #include #include "srslte/srslte.h" -#include "srslte/rf/rf.h" +#include "srslte/phy/rf/rf.h" static bool keep_running = true; char *output_file_name = NULL; @@ -100,7 +100,7 @@ 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(h, data[2], nsamples, 1); + return srslte_rf_recv(h, data[0], nsamples, 1); } int main(int argc, char **argv) { diff --git a/srslte/examples/usrp_txrx.c b/lib/examples/usrp_txrx.c similarity index 99% rename from srslte/examples/usrp_txrx.c rename to lib/examples/usrp_txrx.c index 11af41089..508b4b397 100644 --- a/srslte/examples/usrp_txrx.c +++ b/lib/examples/usrp_txrx.c @@ -33,7 +33,7 @@ #include #include -#include "srslte/rf/rf.h" +#include "srslte/phy/rf/rf.h" #include "srslte/srslte.h" uint32_t nof_prb = 25; diff --git a/srslte/include/CMakeLists.txt b/lib/include/CMakeLists.txt similarity index 90% rename from srslte/include/CMakeLists.txt rename to lib/include/CMakeLists.txt index 96888e1de..483afa049 100644 --- a/srslte/include/CMakeLists.txt +++ b/lib/include/CMakeLists.txt @@ -1,7 +1,7 @@ # -# Copyright 2013-2015 Software Radio Systems Limited +# Copyright 2013-2017 Software Radio Systems Limited # -# This file is part of the srsLTE library. +# 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 diff --git a/srslte/include/srslte/CMakeLists.txt b/lib/include/srslte/CMakeLists.txt similarity index 90% rename from srslte/include/srslte/CMakeLists.txt rename to lib/include/srslte/CMakeLists.txt index 0a0550b96..ee7cfa287 100644 --- a/srslte/include/srslte/CMakeLists.txt +++ b/lib/include/srslte/CMakeLists.txt @@ -1,7 +1,7 @@ # -# Copyright 2013-2015 Software Radio Systems Limited +# Copyright 2013-2017 Software Radio Systems Limited # -# This file is part of the srsLTE library. +# 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 diff --git a/lib/include/srslte/asn1/liblte_common.h b/lib/include/srslte/asn1/liblte_common.h new file mode 100644 index 000000000..36fb32190 --- /dev/null +++ b/lib/include/srslte/asn1/liblte_common.h @@ -0,0 +1,247 @@ +/******************************************************************************* + + Copyright 2012-2014 Ben Wojtowicz + + This program 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. + + This program 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. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + +******************************************************************************* + + File: liblte_common.h + + Description: Contains all the common definitions for the LTE library. + + Revision History + ---------- ------------- -------------------------------------------- + 02/26/2012 Ben Wojtowicz Created file. + 07/21/2013 Ben Wojtowicz Added a common message structure. + 06/15/2014 Ben Wojtowicz Split LIBLTE_MSG_STRUCT into bit and byte + aligned messages. + 08/03/2014 Ben Wojtowicz Commonized value_2_bits and bits_2_value. + 11/29/2014 Ben Wojtowicz Added liblte prefix to value_2_bits and + bits_2_value. + +*******************************************************************************/ + +#ifndef __LIBLTE_COMMON_H__ +#define __LIBLTE_COMMON_H__ + +/******************************************************************************* + INCLUDES +*******************************************************************************/ + +#include +#include +#include +#include + +/******************************************************************************* + DEFINES +*******************************************************************************/ + +// FIXME: This was chosen arbitrarily +#define LIBLTE_ASN1_OID_MAXSUBIDS 128 +#define LIBLTE_MAX_MSG_SIZE_BITS 102048 +#define LIBLTE_MAX_MSG_SIZE_BYTES 12756 +#define LIBLTE_MSG_HEADER_OFFSET 1024 + +/******************************************************************************* + TYPEDEFS +*******************************************************************************/ + +typedef int8_t int8; +typedef uint8_t uint8; +typedef int16_t int16; +typedef uint16_t uint16; +typedef int32_t int32; +typedef uint32_t uint32; +typedef int64_t int64; +typedef uint64_t uint64; + +typedef enum{ + LIBLTE_SUCCESS = 0, + LIBLTE_ERROR_INVALID_INPUTS, + LIBLTE_ERROR_ENCODE_FAIL, + LIBLTE_ERROR_DECODE_FAIL, + LIBLTE_ERROR_INVALID_CRC, + LIBLTE_ERROR_N_ITEMS +}LIBLTE_ERROR_ENUM; +static const char liblte_error_text[LIBLTE_ERROR_N_ITEMS][64] = { + "Invalid inputs", + "Encode failure", + "Decode failure", +}; + +typedef void* LIBLTE_ASN1_OPEN_TYPE_STRUCT; + +typedef struct { + uint32_t numids; // number of subidentifiers + uint32_t subid[LIBLTE_ASN1_OID_MAXSUBIDS]; // subidentifier values +} LIBLTE_ASN1_OID_STRUCT; + +typedef struct{ + bool data_valid; + bool data; +}LIBLTE_BOOL_MSG_STRUCT; + +typedef struct{ + uint32 N_bits; + uint8 msg[LIBLTE_MAX_MSG_SIZE_BITS]; +}LIBLTE_SIMPLE_BIT_MSG_STRUCT; + +typedef struct{ + uint32 N_bytes; + uint8 msg[LIBLTE_MAX_MSG_SIZE_BYTES]; +}LIBLTE_SIMPLE_BYTE_MSG_STRUCT; + + +struct LIBLTE_BYTE_MSG_STRUCT{ + uint32 N_bytes; + uint8 buffer[LIBLTE_MAX_MSG_SIZE_BYTES]; + uint8 *msg; + + LIBLTE_BYTE_MSG_STRUCT():N_bytes(0) + { + msg = &buffer[LIBLTE_MSG_HEADER_OFFSET]; + } + LIBLTE_BYTE_MSG_STRUCT(const LIBLTE_BYTE_MSG_STRUCT& buf) + { + N_bytes = buf.N_bytes; + memcpy(msg, buf.msg, N_bytes); + } + LIBLTE_BYTE_MSG_STRUCT & operator= (const LIBLTE_BYTE_MSG_STRUCT & buf) + { + // avoid self assignment + if (&buf == this) + return *this; + N_bytes = buf.N_bytes; + memcpy(msg, buf.msg, N_bytes); + return *this; + } + uint32 get_headroom() + { + return msg-buffer; + } + void reset() + { + N_bytes = 0; + msg = &buffer[LIBLTE_MSG_HEADER_OFFSET]; + } +}; + +struct LIBLTE_BIT_MSG_STRUCT{ + uint32 N_bits; + uint8 buffer[LIBLTE_MAX_MSG_SIZE_BITS]; + uint8 *msg; + + LIBLTE_BIT_MSG_STRUCT():N_bits(0) + { + msg = &buffer[LIBLTE_MSG_HEADER_OFFSET]; + while( (uint64_t)(msg) % 8 > 0) { + msg++; + } + } + LIBLTE_BIT_MSG_STRUCT(const LIBLTE_BIT_MSG_STRUCT& buf){ + N_bits = buf.N_bits; + memcpy(msg, buf.msg, N_bits); + } + LIBLTE_BIT_MSG_STRUCT & operator= (const LIBLTE_BIT_MSG_STRUCT & buf){ + // avoid self assignment + if (&buf == this) + return *this; + N_bits = buf.N_bits; + memcpy(msg, buf.msg, N_bits); + return *this; + } + uint32 get_headroom() + { + return msg-buffer; + } + void reset() + { + N_bits = 0; + msg = &buffer[LIBLTE_MSG_HEADER_OFFSET]; + while( (uint64_t)(msg) % 8 > 0) { + msg++; + } + } +}; + + +/******************************************************************************* + DECLARATIONS +*******************************************************************************/ + +/********************************************************************* + Name: liblte_value_2_bits + + Description: Converts a value to a bit string +*********************************************************************/ +void liblte_value_2_bits(uint32 value, + uint8 **bits, + uint32 N_bits); + +/********************************************************************* + Name: liblte_bits_2_value + + Description: Converts a bit string to a value +*********************************************************************/ +uint32 liblte_bits_2_value(uint8 **bits, + uint32 N_bits); + +/********************************************************************* + Name: liblte_pack + + Description: Pack a bit array into a byte array +*********************************************************************/ +void liblte_pack(LIBLTE_BIT_MSG_STRUCT *bits, + LIBLTE_BYTE_MSG_STRUCT *bytes); + +/********************************************************************* + Name: liblte_unpack + + Description: Unpack a byte array into a bit array +*********************************************************************/ +void liblte_unpack(LIBLTE_BYTE_MSG_STRUCT *bytes, + LIBLTE_BIT_MSG_STRUCT *bits); + +/********************************************************************* + Name: liblte_pack + + Description: Pack a bit array into a byte array +*********************************************************************/ +void liblte_pack(uint8_t *bits, uint32_t n_bits, uint8_t *bytes); + +/********************************************************************* + Name: liblte_unpack + + Description: Unpack a byte array into a bit array +*********************************************************************/ +void liblte_unpack(uint8_t *bytes, uint32_t n_bytes, uint8_t *bits); + +/********************************************************************* + Name: liblte_align_up + + Description: Aligns a pointer to a multibyte boundary +*********************************************************************/ +void liblte_align_up(uint8_t **ptr, uint32_t align); + +/********************************************************************* + Name: liblte_align_up_zero + + Description: Aligns a pointer to a multibyte boundary and zeros + bytes skipped +*********************************************************************/ +void liblte_align_up_zero(uint8_t **ptr, uint32_t align); + +#endif /* __LIBLTE_COMMON_H__ */ diff --git a/lib/include/srslte/asn1/liblte_mme.h b/lib/include/srslte/asn1/liblte_mme.h new file mode 100644 index 000000000..15799f7ca --- /dev/null +++ b/lib/include/srslte/asn1/liblte_mme.h @@ -0,0 +1,4027 @@ +/******************************************************************************* + + Copyright 2014-2015 Ben Wojtowicz + + This program 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. + + This program 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. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + +******************************************************************************* + + File: liblte_mme.h + + Description: Contains all the definitions for the LTE Mobility Management + Entity library. + + Revision History + ---------- ------------- -------------------------------------------- + 06/15/2014 Ben Wojtowicz Created file. + 08/03/2014 Ben Wojtowicz Added more decoding/encoding. + 09/03/2014 Ben Wojtowicz Added more decoding/encoding. + 11/01/2014 Ben Wojtowicz Added more decoding/encoding. + 11/29/2014 Ben Wojtowicz Added more decoding/encoding. + 12/16/2014 Ben Wojtowicz Added more decoding/encoding. + 12/24/2014 Ben Wojtowicz Cleaned up the Time Zone and Time IE. + 02/15/2015 Ben Wojtowicz Added more decoding/encoding. + +*******************************************************************************/ + +#ifndef __LIBLTE_MME_H__ +#define __LIBLTE_MME_H__ + +/******************************************************************************* + INCLUDES +*******************************************************************************/ + +#include "liblte_common.h" +#include + +/******************************************************************************* + DEFINES +*******************************************************************************/ + + +/******************************************************************************* + TYPEDEFS +*******************************************************************************/ + + +/******************************************************************************* + INFORMATION ELEMENT DECLARATIONS +*******************************************************************************/ + +/********************************************************************* + IE Name: Additional Information + + Description: Provides additional information to upper layers in + relation to the generic NAS message transport + mechanism. + + Document Reference: 24.301 v10.2.0 Section 9.9.2.0 +*********************************************************************/ +// Defines +#define LIBLTE_MME_ADDITIONAL_INFORMATION_MAX_N_OCTETS (LIBLTE_MAX_MSG_SIZE_BITS/2) +// Enums +// Structs +typedef struct{ + uint8 info[LIBLTE_MME_ADDITIONAL_INFORMATION_MAX_N_OCTETS]; + uint32 N_octets; +}LIBLTE_MME_ADDITIONAL_INFORMATION_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_additional_information_ie(LIBLTE_MME_ADDITIONAL_INFORMATION_STRUCT *add_info, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_mme_unpack_additional_information_ie(uint8 **ie_ptr, + LIBLTE_MME_ADDITIONAL_INFORMATION_STRUCT *add_info); + +/********************************************************************* + IE Name: Device Properties + + Description: Indicates if the UE is configured for NAS signalling + low priority. + + Document Reference: 24.301 v10.2.0 Section 9.9.2.0A + 24.008 v10.2.0 Section 10.5.7.8 +*********************************************************************/ +// Defines +// Enums +typedef enum{ + LIBLTE_MME_DEVICE_PROPERTIES_NOT_CONFIGURED_FOR_LOW_PRIORITY = 0, + LIBLTE_MME_DEVICE_PROPERTIES_CONFIGURED_FOR_LOW_PRIORITY, + LIBLTE_MME_DEVICE_PROPERTIES_N_ITEMS, +}LIBLTE_MME_DEVICE_PROPERTIES_ENUM; +static const char liblte_mme_device_properties_text[LIBLTE_MME_DEVICE_PROPERTIES_N_ITEMS][50] = {"Not configured for low priority", + "Configured for low priority"}; +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_device_properties_ie(LIBLTE_MME_DEVICE_PROPERTIES_ENUM device_props, + uint8 bit_offset, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_mme_unpack_device_properties_ie(uint8 **ie_ptr, + uint8 bit_offset, + LIBLTE_MME_DEVICE_PROPERTIES_ENUM *device_props); + +/********************************************************************* + IE Name: EPS Bearer Context Status + + Description: Indicates the state of each EPS bearer context that + can be identified by an EPS bearer identity. + + Document Reference: 24.301 v10.2.0 Section 9.9.2.1 +*********************************************************************/ +// Defines +// Enums +// Structs +typedef struct{ + bool ebi[16]; +}LIBLTE_MME_EPS_BEARER_CONTEXT_STATUS_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_eps_bearer_context_status_ie(LIBLTE_MME_EPS_BEARER_CONTEXT_STATUS_STRUCT *ebcs, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_mme_unpack_eps_bearer_context_status_ie(uint8 **ie_ptr, + LIBLTE_MME_EPS_BEARER_CONTEXT_STATUS_STRUCT *ebcs); + +/********************************************************************* + IE Name: Location Area Identification + + Description: Provides an unambiguous identification of location + areas within the area covered by the 3GPP system. + + Document Reference: 24.301 v10.2.0 Section 9.9.2.2 + 24.008 v10.2.0 Section 10.5.1.3 +*********************************************************************/ +// Defines +// Enums +// Structs +typedef struct{ + uint16 mcc; + uint16 mnc; + uint16 lac; +}LIBLTE_MME_LOCATION_AREA_ID_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_location_area_id_ie(LIBLTE_MME_LOCATION_AREA_ID_STRUCT *lai, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_mme_unpack_location_area_id_ie(uint8 **ie_ptr, + LIBLTE_MME_LOCATION_AREA_ID_STRUCT *lai); + +/********************************************************************* + IE Name: Mobile Identity + + Description: Provides either the IMSI, TMSI/P-TMSI/M-TMSI, IMEI, + IMEISV, or TMGI, associated with the optional MBMS + session identity. + + Document Reference: 24.301 v10.2.0 Section 9.9.2.3 + 24.008 v10.2.0 Section 10.5.1.4 +*********************************************************************/ +// Defines +#define LIBLTE_MME_MOBILE_ID_TYPE_IMSI 0x1 +#define LIBLTE_MME_MOBILE_ID_TYPE_IMEI 0x2 +#define LIBLTE_MME_MOBILE_ID_TYPE_IMEISV 0x3 +#define LIBLTE_MME_MOBILE_ID_TYPE_TMSI 0x4 +#define LIBLTE_MME_MOBILE_ID_TYPE_TMGI 0x5 +// Enums +// Structs +typedef struct{ + uint8 type_of_id; + uint8 imsi[15]; + uint8 imei[15]; + uint8 imeisv[16]; +}LIBLTE_MME_MOBILE_ID_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_mobile_id_ie(LIBLTE_MME_MOBILE_ID_STRUCT *mobile_id, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_mme_unpack_mobile_id_ie(uint8 **ie_ptr, + LIBLTE_MME_MOBILE_ID_STRUCT *mobile_id); + +/********************************************************************* + IE Name: Mobile Station Classmark 2 + + Description: Provides the network with information concerning + aspects of both high and low priority of the UE. + + Document Reference: 24.301 v10.2.0 Section 9.9.2.4 + 24.008 v10.2.0 Section 10.5.1.6 +*********************************************************************/ +// Defines +// Enums +typedef enum{ + LIBLTE_MME_REVISION_LEVEL_GSM_PHASE_1 = 0, + LIBLTE_MME_REVISION_LEVEL_GSM_PHASE_2, + LIBLTE_MME_REVISION_LEVEL_R99, + LIBLTE_MME_REVISION_LEVEL_RESERVED, + LIBLTE_MME_REVISION_LEVEL_N_ITEMS, +}LIBLTE_MME_REVISION_LEVEL_ENUM; +static const char liblte_mme_revision_level_text[LIBLTE_MME_REVISION_LEVEL_N_ITEMS][20] = {"GSM Phase 1", + "GSM Phase 2", + "R99", + "RESERVED"}; +typedef enum{ + LIBLTE_MME_RF_POWER_CAPABILITY_CLASS_1 = 0, + LIBLTE_MME_RF_POWER_CAPABILITY_CLASS_2, + LIBLTE_MME_RF_POWER_CAPABILITY_CLASS_3, + LIBLTE_MME_RF_POWER_CAPABILITY_CLASS_4, + LIBLTE_MME_RF_POWER_CAPABILITY_CLASS_5, + LIBLTE_MME_RF_POWER_CAPABILITY_N_ITEMS, +}LIBLTE_MME_RF_POWER_CAPABILITY_ENUM; +static const char liblte_mme_rf_power_capability_text[LIBLTE_MME_RF_POWER_CAPABILITY_N_ITEMS][20] = {"Class 1", + "Class 2", + "Class 3", + "Class 4", + "Class 5"}; +typedef enum{ + LIBLTE_MME_SS_SCREEN_INDICATOR_0 = 0, + LIBLTE_MME_SS_SCREEN_INDICATOR_1, + LIBLTE_MME_SS_SCREEN_INDICATOR_2, + LIBLTE_MME_SS_SCREEN_INDICATOR_3, + LIBLTE_MME_SS_SCREEN_INDICATOR_N_ITEMS, +}LIBLTE_MME_SS_SCREEN_INDICATOR_ENUM; +static const char liblte_mme_ss_screen_indicator_text[LIBLTE_MME_SS_SCREEN_INDICATOR_N_ITEMS][100] = {"Default Phase 1", + "Ellipsis Notation Phase 2", + "RESERVED", + "RESERVED"}; +// Structs +typedef struct{ + LIBLTE_MME_REVISION_LEVEL_ENUM rev_lev; + LIBLTE_MME_RF_POWER_CAPABILITY_ENUM rf_power_cap; + LIBLTE_MME_SS_SCREEN_INDICATOR_ENUM ss_screen_ind; + bool es_ind; + bool a5_1; + bool ps_cap; + bool sm_cap; + bool vbs; + bool vgcs; + bool fc; + bool cm3; + bool lcsva_cap; + bool ucs2; + bool solsa; + bool cmsp; + bool a5_3; + bool a5_2; +}LIBLTE_MME_MOBILE_STATION_CLASSMARK_2_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_mobile_station_classmark_2_ie(LIBLTE_MME_MOBILE_STATION_CLASSMARK_2_STRUCT *ms_cm2, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_mme_unpack_mobile_station_classmark_2_ie(uint8 **ie_ptr, + LIBLTE_MME_MOBILE_STATION_CLASSMARK_2_STRUCT *ms_cm2); + +/********************************************************************* + IE Name: Mobile Station Classmark 3 + + Description: Provides the network with information concerning + aspects of the UE. + + Document Reference: 24.301 v10.2.0 Section 9.9.2.5 + 24.008 v10.2.0 Section 10.5.1.7 +*********************************************************************/ +// Defines +// Enums +// Structs +typedef struct{ + // FIXME +}LIBLTE_MME_MOBILE_STATION_CLASSMARK_3_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_mobile_station_classmark_3_ie(LIBLTE_MME_MOBILE_STATION_CLASSMARK_3_STRUCT *ms_cm3, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_mme_unpack_mobile_station_classmark_3_ie(uint8 **ie_ptr, + LIBLTE_MME_MOBILE_STATION_CLASSMARK_3_STRUCT *ms_cm3); + +/********************************************************************* + IE Name: NAS Security Parameters From E-UTRA + + Description: Provides the UE with information that enables the UE + to create a mapped UMTS security context. + + Document Reference: 24.301 v10.2.0 Section 9.9.2.6 +*********************************************************************/ +// Defines +// Enums +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_nas_security_parameters_from_eutra_ie(uint8 dl_nas_count, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_mme_unpack_nas_security_parameters_from_eutra_ie(uint8 **ie_ptr, + uint8 *dl_nas_count); + +/********************************************************************* + IE Name: NAS Security Parameters To E-UTRA + + Description: Provides the UE with parameters that enables the UE + to create a mapped EPS security context and take + this context into use after inter-system handover to + S1 mode. + + Document Reference: 24.301 v10.2.0 Section 9.9.2.7 +*********************************************************************/ +// Defines +// Enums +typedef enum{ + LIBLTE_MME_TYPE_OF_INTEGRITY_ALGORITHM_EIA0 = 0, + LIBLTE_MME_TYPE_OF_INTEGRITY_ALGORITHM_128_EIA1, + LIBLTE_MME_TYPE_OF_INTEGRITY_ALGORITHM_128_EIA2, + LIBLTE_MME_TYPE_OF_INTEGRITY_ALGORITHM_EIA3, + LIBLTE_MME_TYPE_OF_INTEGRITY_ALGORITHM_EIA4, + LIBLTE_MME_TYPE_OF_INTEGRITY_ALGORITHM_EIA5, + LIBLTE_MME_TYPE_OF_INTEGRITY_ALGORITHM_EIA6, + LIBLTE_MME_TYPE_OF_INTEGRITY_ALGORITHM_EIA7, + LIBLTE_MME_TYPE_OF_INTEGRITY_ALGORITHM_N_ITEMS, +}LIBLTE_MME_TYPE_OF_INTEGRITY_ALGORITHM_ENUM; +static const char liblte_mme_type_of_integrity_algorithm_text[LIBLTE_MME_TYPE_OF_INTEGRITY_ALGORITHM_N_ITEMS][20] = {"EIA0", + "128-EIA1", + "128-EIA2", + "EIA3", + "EIA4", + "EIA5", + "EIA6", + "EIA7"}; +typedef enum{ + LIBLTE_MME_TYPE_OF_CIPHERING_ALGORITHM_EEA0 = 0, + LIBLTE_MME_TYPE_OF_CIPHERING_ALGORITHM_128_EEA1, + LIBLTE_MME_TYPE_OF_CIPHERING_ALGORITHM_128_EEA2, + LIBLTE_MME_TYPE_OF_CIPHERING_ALGORITHM_EEA3, + LIBLTE_MME_TYPE_OF_CIPHERING_ALGORITHM_EEA4, + LIBLTE_MME_TYPE_OF_CIPHERING_ALGORITHM_EEA5, + LIBLTE_MME_TYPE_OF_CIPHERING_ALGORITHM_EEA6, + LIBLTE_MME_TYPE_OF_CIPHERING_ALGORITHM_EEA7, + LIBLTE_MME_TYPE_OF_CIPHERING_ALGORITHM_N_ITEMS, +}LIBLTE_MME_TYPE_OF_CIPHERING_ALGORITHM_ENUM; +static const char liblte_mme_type_of_ciphering_algorithm_text[LIBLTE_MME_TYPE_OF_CIPHERING_ALGORITHM_N_ITEMS][20] = {"EEA0", + "128-EEA1", + "128-EEA2", + "EEA3", + "EEA4", + "EEA5", + "EEA6", + "EEA7"}; +typedef enum{ + LIBLTE_MME_TYPE_OF_SECURITY_CONTEXT_FLAG_NATIVE = 0, + LIBLTE_MME_TYPE_OF_SECURITY_CONTEXT_FLAG_MAPPED, + LIBLTE_MME_TYPE_OF_SECURITY_CONTEXT_FLAG_N_ITEMS, +}LIBLTE_MME_TYPE_OF_SECURITY_CONTEXT_FLAG_ENUM; +static const char liblte_mme_type_of_security_context_flag_text[LIBLTE_MME_TYPE_OF_SECURITY_CONTEXT_FLAG_N_ITEMS][20] = {"Native", + "Mapped"}; +// Structs +typedef struct{ + LIBLTE_MME_TYPE_OF_CIPHERING_ALGORITHM_ENUM eea; + LIBLTE_MME_TYPE_OF_INTEGRITY_ALGORITHM_ENUM eia; + LIBLTE_MME_TYPE_OF_SECURITY_CONTEXT_FLAG_ENUM tsc_flag; + uint32 nonce_mme; + uint8 nas_ksi; +}LIBLTE_MME_NAS_SECURITY_PARAMETERS_TO_EUTRA_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_nas_security_parameters_to_eutra_ie(LIBLTE_MME_NAS_SECURITY_PARAMETERS_TO_EUTRA_STRUCT *sec_params, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_mme_unpack_nas_security_parameters_to_eutra_ie(uint8 **ie_ptr, + LIBLTE_MME_NAS_SECURITY_PARAMETERS_TO_EUTRA_STRUCT *sec_params); + +/********************************************************************* + IE Name: PLMN List + + Description: Provides a list of PLMN codes to the UE. + + Document Reference: 24.301 v10.2.0 Section 9.9.2.8 + 24.008 v10.2.0 Section 10.5.1.13 +*********************************************************************/ +// Defines +#define LIBLTE_MME_PLMN_LIST_MAX_SIZE 15 +// Enums +// Structs +typedef struct{ + uint32 N_plmns; + uint16 mcc[LIBLTE_MME_PLMN_LIST_MAX_SIZE]; + uint16 mnc[LIBLTE_MME_PLMN_LIST_MAX_SIZE]; +}LIBLTE_MME_PLMN_LIST_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_plmn_list_ie(LIBLTE_MME_PLMN_LIST_STRUCT *plmn_list, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_mme_unpack_plmn_list_ie(uint8 **ie_ptr, + LIBLTE_MME_PLMN_LIST_STRUCT *plmn_list); + +/********************************************************************* + IE Name: Spare Half Octet + + Description: Used in the description of EMM and ESM messages when + an odd number of half octet type 1 information + elements are used. + + Document Reference: 24.301 v10.2.0 Section 9.9.2.9 +*********************************************************************/ +// Defines +// Enums +// Structs +// Functions + +/********************************************************************* + IE Name: Supported Codec List + + Description: Provides the network with information about the + speech codecs supported by the UE. + + Document Reference: 24.301 v10.2.0 Section 9.9.2.10 + 24.008 v10.2.0 Section 10.5.4.32 +*********************************************************************/ +// Defines +#define LIBLTE_MME_MAX_N_SUPPORTED_CODECS (LIBLTE_MAX_MSG_SIZE_BITS/16) +// Enums +// Structs +typedef struct{ + uint8 sys_id; + uint16 codec_bitmap; +}LIBLTE_MME_SUPPORTED_CODEC_STRUCT; +typedef struct{ + LIBLTE_MME_SUPPORTED_CODEC_STRUCT supported_codec[LIBLTE_MME_MAX_N_SUPPORTED_CODECS]; + uint32 N_supported_codecs; +}LIBLTE_MME_SUPPORTED_CODEC_LIST_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_supported_codec_list_ie(LIBLTE_MME_SUPPORTED_CODEC_LIST_STRUCT *supported_codec_list, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_mme_unpack_supported_codec_list_ie(uint8 **ie_ptr, + LIBLTE_MME_SUPPORTED_CODEC_LIST_STRUCT *supported_codec_list); + +/********************************************************************* + IE Name: Additional Update Result + + Description: Provides additional information about the result of + a combined attached procedure or a combined tracking + area updating procedure. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.0A +*********************************************************************/ +// Defines +// Enums +typedef enum{ + LIBLTE_MME_ADDITIONAL_UPDATE_RESULT_NO_ADDITIONAL_INFO = 0, + LIBLTE_MME_ADDITIONAL_UPDATE_RESULT_CS_FALLBACK_NOT_PREFERRED, + LIBLTE_MME_ADDITIONAL_UPDATE_RESULT_SMS_ONLY, + LIBLTE_MME_ADDITIONAL_UPDATE_RESULT_RESERVED, + LIBLTE_MME_ADDITIONAL_UPDATE_RESULT_N_ITEMS, +}LIBLTE_MME_ADDITIONAL_UPDATE_RESULT_ENUM; +static const char liblte_mme_additional_update_result_text[LIBLTE_MME_ADDITIONAL_UPDATE_RESULT_N_ITEMS][100] = {"No Additional Information", + "CS Fallback Not Preferred", + "SMS Only", + "RESERVED"}; +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_additional_update_result_ie(LIBLTE_MME_ADDITIONAL_UPDATE_RESULT_ENUM result, + uint8 bit_offset, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_mme_unpack_additional_update_result_ie(uint8 **ie_ptr, + uint8 bit_offset, + LIBLTE_MME_ADDITIONAL_UPDATE_RESULT_ENUM *result); + +/********************************************************************* + IE Name: Additional Update Type + + Description: Provides additional information about the type of + request for a combined attach or a combined tracking + area updating procedure. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.0B +*********************************************************************/ +// Defines +// Enums +typedef enum{ + LIBLTE_MME_ADDITIONAL_UPDATE_TYPE_NO_ADDITIONAL_INFO = 0, + LIBLTE_MME_ADDITIONAL_UPDATE_TYPE_SMS_ONLY, + LIBLTE_MME_ADDITIONAL_UPDATE_TYPE_N_ITEMS, +}LIBLTE_MME_ADDITIONAL_UPDATE_TYPE_ENUM; +static const char liblte_mme_additional_update_type_text[LIBLTE_MME_ADDITIONAL_UPDATE_TYPE_N_ITEMS][20] = {"No additional info", + "SMS Only"}; +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_additional_update_type_ie(LIBLTE_MME_ADDITIONAL_UPDATE_TYPE_ENUM aut, + uint8 bit_offset, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_mme_unpack_additional_update_type_ie(uint8 **ie_ptr, + uint8 bit_offset, + LIBLTE_MME_ADDITIONAL_UPDATE_TYPE_ENUM *aut); + +/********************************************************************* + IE Name: Authentication Failure Parameter + + Description: Provides the network with the necessary information + to begin a re-authentication procedure in the case + of a 'Synch failure', following a UMTS or EPS + authentication challenge. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.1 + 24.008 v10.2.0 Section 10.5.3.2.2 +*********************************************************************/ +// Defines +// Enums +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_authentication_failure_parameter_ie(uint8 *auth_fail_param, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_mme_unpack_authentication_failure_parameter_ie(uint8 **ie_ptr, + uint8 *auth_fail_param); + +/********************************************************************* + IE Name: Authentication Parameter AUTN + + Description: Provides the UE with a means of authenticating the + network. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.2 + 24.008 v10.2.0 Section 10.5.3.1.1 +*********************************************************************/ +// Defines +// Enums +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_authentication_parameter_autn_ie(uint8 *autn, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_mme_unpack_authentication_parameter_autn_ie(uint8 **ie_ptr, + uint8 *autn); + +/********************************************************************* + IE Name: Authentication Parameter RAND + + Description: Provides the UE with a non-predictable number to be + used to calculate the authentication signature SRES + and the ciphering key Kc (for a GSM authentication + challenge), or the response RES and both the + ciphering key CK and the integrity key IK (for a + UMTS authentication challenge). + + Document Reference: 24.301 v10.2.0 Section 9.9.3.3 + 24.008 v10.2.0 Section 10.5.3.1 +*********************************************************************/ +// Defines +// Enums +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_authentication_parameter_rand_ie(uint8 *rand_val, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_mme_unpack_authentication_parameter_rand_ie(uint8 **ie_ptr, + uint8 *rand_val); + +/********************************************************************* + IE Name: Authentication Response Parameter + + Description: Provides the network with the authentication + response calculated in the USIM. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.4 +*********************************************************************/ +// Defines +// Enums +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_authentication_response_parameter_ie(uint8 *res, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_mme_unpack_authentication_response_parameter_ie(uint8 **ie_ptr, + uint8 *res); + +/********************************************************************* + IE Name: Ciphering Key Sequence Number + + Description: Makes it possible for the network to identify the + ciphering key Kc which is stored in the UE without + invoking the authentication procedure. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.4A + 24.008 v10.2.0 Section 10.5.1.2 +*********************************************************************/ +// Defines +// Enums +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_ciphering_key_sequence_number_ie(uint8 key_seq, + uint8 bit_offset, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_mme_unpack_ciphering_key_sequence_number_ie(uint8 **ie_ptr, + uint8 bit_offset, + uint8 *key_seq); + +/********************************************************************* + IE Name: CSFB Response + + Description: Indicates whether the UE accepts or rejects a paging + for CS fallback. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.5 +*********************************************************************/ +// Defines +#define LIBLTE_MME_CSFB_REJECTED_BY_THE_UE 0x0 +#define LIBLTE_MME_CSFB_ACCEPTED_BY_THE_UE 0x1 +// Enums +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_csfb_response_ie(uint8 csfb_resp, + uint8 bit_offset, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_mme_unpack_csfb_response_ie(uint8 **ie_ptr, + uint8 bit_offset, + uint8 *csfb_resp); + +/********************************************************************* + IE Name: Daylight Saving Time + + Description: Encodes the daylight saving time in steps of 1 hour. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.6 + 24.008 v10.2.0 Section 10.5.3.12 +*********************************************************************/ +// Defines +// Enums +typedef enum{ + LIBLTE_MME_DAYLIGHT_SAVING_TIME_NO_ADJUSTMENT = 0, + LIBLTE_MME_DAYLIGHT_SAVING_TIME_PLUS_ONE_HOUR, + LIBLTE_MME_DAYLIGHT_SAVING_TIME_PLUS_TWO_HOURS, + LIBLTE_MME_DAYLIGHT_SAVING_TIME_RESERVED, + LIBLTE_MME_DAYLIGHT_SAVING_TIME_N_ITEMS, +}LIBLTE_MME_DAYLIGHT_SAVING_TIME_ENUM; +static const char liblte_mme_daylight_saving_time_text[LIBLTE_MME_DAYLIGHT_SAVING_TIME_N_ITEMS][20] = {"No Adjustment", + "+1 Hour", + "+2 Hours", + "RESERVED"}; +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_daylight_saving_time_ie(LIBLTE_MME_DAYLIGHT_SAVING_TIME_ENUM dst, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_mme_unpack_daylight_saving_time_ie(uint8 **ie_ptr, + LIBLTE_MME_DAYLIGHT_SAVING_TIME_ENUM *dst); + +/********************************************************************* + IE Name: Detach Type + + Description: Indicates the type of detach. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.7 +*********************************************************************/ +// Defines +#define LIBLTE_MME_SO_FLAG_NORMAL_DETACH 0 +#define LIBLTE_MME_SO_FLAG_SWITCH_OFF 1 +#define LIBLTE_MME_TOD_UL_EPS_DETACH 0x1 +#define LIBLTE_MME_TOD_UL_IMSI_DETACH 0x2 +#define LIBLTE_MME_TOD_UL_COMBINED_DETACH 0x3 +#define LIBLTE_MME_TOD_DL_REATTACH_REQUIRED 0x1 +#define LIBLTE_MME_TOD_DL_REATTACH_NOT_REQUIRED 0x2 +#define LIBLTE_MME_TOD_DL_IMSI_DETACH 0x3 +// Enums +// Structs +typedef struct{ + uint8 switch_off; + uint8 type_of_detach; +}LIBLTE_MME_DETACH_TYPE_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_detach_type_ie(LIBLTE_MME_DETACH_TYPE_STRUCT *detach_type, + uint8 bit_offset, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_mme_unpack_detach_type_ie(uint8 **ie_ptr, + uint8 bit_offset, + LIBLTE_MME_DETACH_TYPE_STRUCT *detach_type); + +/********************************************************************* + IE Name: DRX Parameter + + Description: Indicates whether the UE uses DRX mode or not. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.8 + 24.008 v10.2.0 Section 10.5.5.6 +*********************************************************************/ +// Defines +// Enums +typedef enum{ + LIBLTE_MME_NON_DRX_TIMER_NO_NON_DRX_MODE = 0, + LIBLTE_MME_NON_DRX_TIMER_MAX_1S_NON_DRX_MODE, + LIBLTE_MME_NON_DRX_TIMER_MAX_2S_NON_DRX_MODE, + LIBLTE_MME_NON_DRX_TIMER_MAX_4S_NON_DRX_MODE, + LIBLTE_MME_NON_DRX_TIMER_MAX_8S_NON_DRX_MODE, + LIBLTE_MME_NON_DRX_TIMER_MAX_16S_NON_DRX_MODE, + LIBLTE_MME_NON_DRX_TIMER_MAX_32S_NON_DRX_MODE, + LIBLTE_MME_NON_DRX_TIMER_MAX_64S_NON_DRX_MODE, + LIBLTE_MME_NON_DRX_TIMER_N_ITEMS, +}LIBLTE_MME_NON_DRX_TIMER_ENUM; +static const char liblte_mme_non_drx_timer_text[LIBLTE_MME_NON_DRX_TIMER_N_ITEMS][100] = {"No Non-DRX Mode", + "Max 1s Non-DRX Mode", + "Max 2s Non-DRX Mode", + "Max 4s Non-DRX Mode", + "Max 8s Non-DRX Mode", + "Max 16s Non-DRX Mode", + "Max 32s Non-DRX Mode", + "Max 64s Non-DRX Mode"}; +// Structs +typedef struct{ + LIBLTE_MME_NON_DRX_TIMER_ENUM non_drx_timer; + uint8 split_pg_cycle_code; + uint8 drx_cycle_len_coeff_and_value; + bool split_on_ccch; +}LIBLTE_MME_DRX_PARAMETER_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_drx_parameter_ie(LIBLTE_MME_DRX_PARAMETER_STRUCT *drx_param, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_mme_unpack_drx_parameter_ie(uint8 **ie_ptr, + LIBLTE_MME_DRX_PARAMETER_STRUCT *drx_param); + +/********************************************************************* + IE Name: EMM Cause + + Description: Indicates the reason why an EMM request from the UE + is rejected by the network. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.9 +*********************************************************************/ +// Defines +#define LIBLTE_MME_EMM_CAUSE_IMSI_UNKNOWN_IN_HSS 0x02 +#define LIBLTE_MME_EMM_CAUSE_ILLEGAL_UE 0x03 +#define LIBLTE_MME_EMM_CAUSE_IMEI_NOT_ACCEPTED 0x05 +#define LIBLTE_MME_EMM_CAUSE_ILLEGAL_ME 0x06 +#define LIBLTE_MME_EMM_CAUSE_EPS_SERVICES_NOT_ALLOWED 0x07 +#define LIBLTE_MME_EMM_CAUSE_EPS_SERVICES_AND_NON_EPS_SERVICES_NOT_ALLOWED 0x08 +#define LIBLTE_MME_EMM_CAUSE_UE_IDENTITY_CANNOT_BE_DERIVED_BY_THE_NETWORK 0x09 +#define LIBLTE_MME_EMM_CAUSE_IMPLICITLY_DETACHED 0x0A +#define LIBLTE_MME_EMM_CAUSE_PLMN_NOT_ALLOWED 0x0B +#define LIBLTE_MME_EMM_CAUSE_TRACKING_AREA_NOT_ALLOWED 0x0C +#define LIBLTE_MME_EMM_CAUSE_ROAMING_NOT_ALLOWED_IN_THIS_TRACKING_AREA 0x0D +#define LIBLTE_MME_EMM_CAUSE_EPS_SERVICES_NOT_ALLOWED_IN_THIS_PLMN 0x0E +#define LIBLTE_MME_EMM_CAUSE_NO_SUITABLE_CELLS_IN_TRACKING_AREA 0x0F +#define LIBLTE_MME_EMM_CAUSE_MSC_TEMPORARILY_NOT_REACHABLE 0x10 +#define LIBLTE_MME_EMM_CAUSE_NETWORK_FAILURE 0x11 +#define LIBLTE_MME_EMM_CAUSE_CS_DOMAIN_NOT_AVAILABLE 0x12 +#define LIBLTE_MME_EMM_CAUSE_ESM_FAILURE 0x13 +#define LIBLTE_MME_EMM_CAUSE_MAC_FAILURE 0x14 +#define LIBLTE_MME_EMM_CAUSE_SYNCH_FAILURE 0x15 +#define LIBLTE_MME_EMM_CAUSE_CONGESTION 0x16 +#define LIBLTE_MME_EMM_CAUSE_UE_SECURITY_CAPABILITIES_MISMATCH 0x17 +#define LIBLTE_MME_EMM_CAUSE_SECURITY_MODE_REJECTED_UNSPECIFIED 0x18 +#define LIBLTE_MME_EMM_CAUSE_NOT_AUTHORIZED_FOR_THIS_CSG 0x19 +#define LIBLTE_MME_EMM_CAUSE_NON_EPS_AUTHENTICATION_UNACCEPTABLE 0x1A +#define LIBLTE_MME_EMM_CAUSE_CS_SERVICE_TEMPORARILY_NOT_AVAILABLE 0x27 +#define LIBLTE_MME_EMM_CAUSE_NO_EPS_BEARER_CONTEXT_ACTIVATED 0x28 +#define LIBLTE_MME_EMM_CAUSE_SEMANTICALLY_INCORRECT_MESSAGE 0x5F +#define LIBLTE_MME_EMM_CAUSE_INVALID_MANDATORY_INFORMATION 0x60 +#define LIBLTE_MME_EMM_CAUSE_MESSAGE_TYPE_NON_EXISTENT_OR_NOT_IMPLEMENTED 0x61 +#define LIBLTE_MME_EMM_CAUSE_MESSAGE_TYPE_NOT_COMPATIBLE_WITH_THE_PROTOCOL_STATE 0x62 +#define LIBLTE_MME_EMM_CAUSE_INFORMATION_ELEMENT_NON_EXISTENT_OR_NOT_IMPLEMENTED 0x63 +#define LIBLTE_MME_EMM_CAUSE_CONDITIONAL_IE_ERROR 0x64 +#define LIBLTE_MME_EMM_CAUSE_MESSAGE_NOT_COMPATIBLE_WITH_THE_PROTOCOL_STATE 0x65 +#define LIBLTE_MME_EMM_CAUSE_PROTOCOL_ERROR_UNSPECIFIED 0x6F +// Enums +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_emm_cause_ie(uint8 emm_cause, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_mme_unpack_emm_cause_ie(uint8 **ie_ptr, + uint8 *emm_cause); + +/********************************************************************* + IE Name: EPS Attach Result + + Description: Specifies the result of an attach procedure. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.10 +*********************************************************************/ +// Defines +#define LIBLTE_MME_EPS_ATTACH_RESULT_EPS_ONLY 0x1 +#define LIBLTE_MME_EPS_ATTACH_RESULT_COMBINED_EPS_IMSI_ATTACH 0x2 +// Enums +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_eps_attach_result_ie(uint8 result, + uint8 bit_offset, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_mme_unpack_eps_attach_result_ie(uint8 **ie_ptr, + uint8 bit_offset, + uint8 *result); + +/********************************************************************* + IE Name: EPS Attach Type + + Description: Indicates the type of the requested attach. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.11 +*********************************************************************/ +// Defines +#define LIBLTE_MME_EPS_ATTACH_TYPE_EPS_ATTACH 0x1 +#define LIBLTE_MME_EPS_ATTACH_TYPE_COMBINED_EPS_IMSI_ATTACH 0x2 +#define LIBLTE_MME_EPS_ATTACH_TYPE_EPS_EMERGENCY_ATTACH 0x6 +// Enums +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_eps_attach_type_ie(uint8 attach_type, + uint8 bit_offset, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_mme_unpack_eps_attach_type_ie(uint8 **ie_ptr, + uint8 bit_offset, + uint8 *attach_type); + +/********************************************************************* + IE Name: EPS Mobile Identity + + Description: Provides either the IMSI, the GUTI, or the IMEI. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.12 +*********************************************************************/ +// Defines +#define LIBLTE_MME_EPS_MOBILE_ID_TYPE_IMSI 0x1 +#define LIBLTE_MME_EPS_MOBILE_ID_TYPE_GUTI 0x6 +#define LIBLTE_MME_EPS_MOBILE_ID_TYPE_IMEI 0x3 +// Enums +// Structs +typedef struct{ + uint32 m_tmsi; + uint16 mcc; + uint16 mnc; + uint16 mme_group_id; + uint8 mme_code; +}LIBLTE_MME_EPS_MOBILE_ID_GUTI_STRUCT; +typedef struct{ + LIBLTE_MME_EPS_MOBILE_ID_GUTI_STRUCT guti; + uint8 type_of_id; + uint8 imsi[15]; + uint8 imei[15]; +}LIBLTE_MME_EPS_MOBILE_ID_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_eps_mobile_id_ie(LIBLTE_MME_EPS_MOBILE_ID_STRUCT *eps_mobile_id, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_mme_unpack_eps_mobile_id_ie(uint8 **ie_ptr, + LIBLTE_MME_EPS_MOBILE_ID_STRUCT *eps_mobile_id); + +/********************************************************************* + IE Name: EPS Network Feature Support + + Description: Indicates whether certain features are supported by + the network. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.12A +*********************************************************************/ +// Defines +#define LIBLTE_MME_EPS_NETWORK_FEATURE_SUPPORT_NOT_SUPPORTED 0 +#define LIBLTE_MME_EPS_NETWORK_FEATURE_SUPPORT_SUPPORTED 1 +// Enums +typedef enum{ + LIBLTE_MME_CS_LCS_NO_INFORMATION_AVAILABLE = 0, + LIBLTE_MME_CS_LCS_NOT_SUPPORTED, + LIBLTE_MME_CS_LCS_SUPPORTED, + LIBLTE_MME_CS_LCS_RESERVED, + LIBLTE_MME_CS_LCS_N_ITEMS, +}LIBLTE_MME_CS_LCS_ENUM; +static const char liblte_mme_cs_lcs_text[LIBLTE_MME_CS_LCS_N_ITEMS][100] = {"No Information Available", + "Not Supported", + "Supported", + "RESERVED"}; +// Structs +typedef struct{ + LIBLTE_MME_CS_LCS_ENUM cs_lcs; + bool esrps; + bool epc_lcs; + bool emc_bs; + bool ims_vops; +}LIBLTE_MME_EPS_NETWORK_FEATURE_SUPPORT_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_eps_network_feature_support_ie(LIBLTE_MME_EPS_NETWORK_FEATURE_SUPPORT_STRUCT *eps_nfs, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_mme_unpack_eps_network_feature_support_ie(uint8 **ie_ptr, + LIBLTE_MME_EPS_NETWORK_FEATURE_SUPPORT_STRUCT *eps_nfs); + +/********************************************************************* + IE Name: EPS Update Result + + Description: Specifies the result of the associated updating + procedure. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.13 +*********************************************************************/ +// Defines +#define LIBLTE_MME_EPS_UPDATE_RESULT_TA_UPDATED 0x0 +#define LIBLTE_MME_EPS_UPDATE_RESULT_COMBINED_TA_LA_UPDATED 0x1 +#define LIBLTE_MME_EPS_UPDATE_RESULT_TA_UPDATED_AND_ISR_ACTIVATED 0x4 +#define LIBLTE_MME_EPS_UPDATE_RESULT_COMBINED_TA_LA_UPDATED_AND_ISR_ACTIVATED 0x5 +// Enums +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_eps_update_result_ie(uint8 eps_update_res, + uint8 bit_offset, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_mme_unpack_eps_update_result_ie(uint8 **ie_ptr, + uint8 bit_offset, + uint8 *eps_update_res); + +/********************************************************************* + IE Name: EPS Update Type + + Description: Specifies the area the updating procedure is + associated with. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.14 +*********************************************************************/ +// Defines +// Enums +typedef enum{ + LIBLTE_MME_EPS_UPDATE_TYPE_TA_UPDATING = 0, + LIBLTE_MME_EPS_UPDATE_TYPE_COMBINED_TA_LA_UPDATING, + LIBLTE_MME_EPS_UPDATE_TYPE_COMBINED_TA_LA_UPDATING_WITH_IMSI_ATTACH, + LIBLTE_MME_EPS_UPDATE_TYPE_PERIODIC_UPDATING, + LIBLTE_MME_EPS_UPDATE_TYPE_N_ITEMS, +}LIBLTE_MME_EPS_UPDATE_TYPE_ENUM; +static const char liblte_mme_eps_update_type_text[LIBLTE_MME_EPS_UPDATE_TYPE_N_ITEMS][100] = {"TA Updating", + "Combined TA/LA Updating", + "Combined TA/LA Updating With IMSI Attach", + "Periodic Updating"}; +// Structs +typedef struct{ + LIBLTE_MME_EPS_UPDATE_TYPE_ENUM type; + bool active_flag; +}LIBLTE_MME_EPS_UPDATE_TYPE_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_eps_update_type_ie(LIBLTE_MME_EPS_UPDATE_TYPE_STRUCT *eps_update_type, + uint8 bit_offset, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_mme_unpack_eps_update_type_ie(uint8 **ie_ptr, + uint8 bit_offset, + LIBLTE_MME_EPS_UPDATE_TYPE_STRUCT *eps_update_type); + +/********************************************************************* + IE Name: ESM Message Container + + Description: Enables piggybacked transfer of a single ESM message + within an EMM message. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.15 +*********************************************************************/ +// Defines +// Enums +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_esm_message_container_ie(LIBLTE_BYTE_MSG_STRUCT *esm_msg, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_mme_unpack_esm_message_container_ie(uint8 **ie_ptr, + LIBLTE_BYTE_MSG_STRUCT *esm_msg); + +/********************************************************************* + IE Name: GPRS Timer + + Description: Specifies GPRS specific timer values. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.16 + 24.008 v10.2.0 Section 10.5.7.3 +*********************************************************************/ +// Defines +#define LIBLTE_MME_GPRS_TIMER_UNIT_2_SECONDS 0x0 +#define LIBLTE_MME_GPRS_TIMER_UNIT_1_MINUTE 0x1 +#define LIBLTE_MME_GPRS_TIMER_UNIT_6_MINUTES 0x2 +#define LIBLTE_MME_GPRS_TIMER_DEACTIVATED 0x7 +// Enums +// Structs +typedef struct{ + uint8 unit; + uint8 value; +}LIBLTE_MME_GPRS_TIMER_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_gprs_timer_ie(LIBLTE_MME_GPRS_TIMER_STRUCT *timer, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_mme_unpack_gprs_timer_ie(uint8 **ie_ptr, + LIBLTE_MME_GPRS_TIMER_STRUCT *timer); + +/********************************************************************* + IE Name: GPRS Timer 2 + + Description: Specifies GPRS specific timer values. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.16A + 24.008 v10.2.0 Section 10.5.7.4 +*********************************************************************/ +// Defines +// Enums +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_gprs_timer_2_ie(uint8 value, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_mme_unpack_gprs_timer_2_ie(uint8 **ie_ptr, + uint8 *value); + +/********************************************************************* + IE Name: GPRS Timer 3 + + Description: Specifies GPRS specific timer values. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.16B + 24.008 v10.2.0 Section 10.5.7.4A +*********************************************************************/ +// Defines +#define LIBLTE_MME_GPRS_TIMER_3_UNIT_10_MINUTES 0x0 +#define LIBLTE_MME_GPRS_TIMER_3_UNIT_1_HOUR 0x1 +#define LIBLTE_MME_GPRS_TIMER_3_UNIT_10_HOURS 0x2 +#define LIBLTE_MME_GPRS_TIMER_3_DEACTIVATED 0x7 +// Enums +// Structs +typedef struct{ + uint8 unit; + uint8 value; +}LIBLTE_MME_GPRS_TIMER_3_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_gprs_timer_3_ie(LIBLTE_MME_GPRS_TIMER_3_STRUCT *timer, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_mme_unpack_gprs_timer_3_ie(uint8 **ie_ptr, + LIBLTE_MME_GPRS_TIMER_3_STRUCT *timer); + +/********************************************************************* + IE Name: Identity Type 2 + + Description: Specifies which identity is requested. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.17 + 24.008 v10.2.0 Section 10.5.5.9 +*********************************************************************/ +// Defines +#define LIBLTE_MME_ID_TYPE_2_IMSI 0x1 +#define LIBLTE_MME_ID_TYPE_2_IMEI 0x2 +#define LIBLTE_MME_ID_TYPE_2_IMEISV 0x3 +#define LIBLTE_MME_ID_TYPE_2_TMSI 0x4 +// Enums +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_identity_type_2_ie(uint8 id_type, + uint8 bit_offset, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_mme_unpack_identity_type_2_ie(uint8 **ie_ptr, + uint8 bit_offset, + uint8 *id_type); + +/********************************************************************* + IE Name: IMEISV Request + + Description: Indicates that the IMEISV shall be included by the + UE in the authentication and ciphering response + message. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.18 + 24.008 v10.2.0 Section 10.5.5.10 +*********************************************************************/ +// Defines +// Enums +typedef enum{ + LIBLTE_MME_IMEISV_NOT_REQUESTED = 0, + LIBLTE_MME_IMEISV_REQUESTED, + LIBLTE_MME_IMEISV_REQUEST_N_ITEMS, +}LIBLTE_MME_IMEISV_REQUEST_ENUM; +static const char liblte_mme_imeisv_request_text[LIBLTE_MME_IMEISV_REQUEST_N_ITEMS][20] = {"Not Requested", + "Requested"}; +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_imeisv_request_ie(LIBLTE_MME_IMEISV_REQUEST_ENUM imeisv_req, + uint8 bit_offset, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_mme_unpack_imeisv_request_ie(uint8 **ie_ptr, + uint8 bit_offset, + LIBLTE_MME_IMEISV_REQUEST_ENUM *imeisv_req); + +/********************************************************************* + IE Name: KSI And Sequence Number + + Description: Provides the network with the key set identifier + (KSI) value of the current EPS security context and + the 5 least significant bits of the NAS COUNT value + applicable for the message including this information + element. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.19 +*********************************************************************/ +// Defines +// Enums +// Structs +typedef struct{ + uint8 ksi; + uint8 seq_num; +}LIBLTE_MME_KSI_AND_SEQUENCE_NUMBER_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_ksi_and_sequence_number_ie(LIBLTE_MME_KSI_AND_SEQUENCE_NUMBER_STRUCT *ksi_and_seq_num, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_mme_unpack_ksi_and_sequence_number_ie(uint8 **ie_ptr, + LIBLTE_MME_KSI_AND_SEQUENCE_NUMBER_STRUCT *ksi_and_seq_num); + +/********************************************************************* + IE Name: MS Network Capability + + Description: Provides the network with information concerning + aspects of the UE related to GPRS. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.20 + 24.008 v10.2.0 Section 10.5.5.12 +*********************************************************************/ +// Defines +// Enums +typedef enum{ + LIBLTE_MME_SS_SCREENING_INDICATOR_PHASE_1 = 0, + LIBLTE_MME_SS_SCREENING_INDICATOR_PHASE_2, + LIBLTE_MME_SS_SCREENING_INDICATOR_RESERVED_1, + LIBLTE_MME_SS_SCREENING_INDICATOR_RESERVED_2, + LIBLTE_MME_SS_SCREENING_INDICATOR_N_ITEMS, +}LIBLTE_MME_SS_SCREENING_INDICATOR_ENUM; +static const char liblte_mme_ss_screening_indicator_text[LIBLTE_MME_SS_SCREENING_INDICATOR_N_ITEMS][20] = {"Phase 1", + "Phase 2", + "Reserved 1", + "Reserved 2"}; +// Structs +typedef struct{ + LIBLTE_MME_SS_SCREENING_INDICATOR_ENUM ss_screening; + bool gea[8]; + bool sm_cap_ded; + bool sm_cap_gprs; + bool ucs2; + bool solsa; + bool revision; + bool pfc; + bool lcsva; + bool ho_g2u_via_iu; + bool ho_g2e_via_s1; + bool emm_comb; + bool isr; + bool srvcc; + bool epc; + bool nf; +}LIBLTE_MME_MS_NETWORK_CAPABILITY_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_ms_network_capability_ie(LIBLTE_MME_MS_NETWORK_CAPABILITY_STRUCT *ms_network_cap, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_mme_unpack_ms_network_capability_ie(uint8 **ie_ptr, + LIBLTE_MME_MS_NETWORK_CAPABILITY_STRUCT *ms_network_cap); + +/********************************************************************* + IE Name: NAS Key Set Identifier + + Description: Provides the NAS key set identifier that is allocated + by the network. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.21 +*********************************************************************/ +// Defines +// Enums +// Structs +typedef struct{ + LIBLTE_MME_TYPE_OF_SECURITY_CONTEXT_FLAG_ENUM tsc_flag; + uint8 nas_ksi; +}LIBLTE_MME_NAS_KEY_SET_ID_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_nas_key_set_id_ie(LIBLTE_MME_NAS_KEY_SET_ID_STRUCT *nas_ksi, + uint8 bit_offset, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_mme_unpack_nas_key_set_id_ie(uint8 **ie_ptr, + uint8 bit_offset, + LIBLTE_MME_NAS_KEY_SET_ID_STRUCT *nas_ksi); + +/********************************************************************* + IE Name: NAS Message Container + + Description: Encapsulates the SMS messages transferred between + the UE and the network. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.22 +*********************************************************************/ +// Defines +// Enums +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_nas_message_container_ie(LIBLTE_BYTE_MSG_STRUCT *nas_msg, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_mme_unpack_nas_message_container_ie(uint8 **ie_ptr, + LIBLTE_BYTE_MSG_STRUCT *nas_msg); + +/********************************************************************* + IE Name: NAS Security Algorithms + + Description: Indicates the algorithms to be used for ciphering + and integrity protection. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.23 +*********************************************************************/ +// Defines +// Enums +// Structs +typedef struct{ + LIBLTE_MME_TYPE_OF_CIPHERING_ALGORITHM_ENUM type_of_eea; + LIBLTE_MME_TYPE_OF_INTEGRITY_ALGORITHM_ENUM type_of_eia; +}LIBLTE_MME_NAS_SECURITY_ALGORITHMS_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_nas_security_algorithms_ie(LIBLTE_MME_NAS_SECURITY_ALGORITHMS_STRUCT *nas_sec_algs, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_mme_unpack_nas_security_algorithms_ie(uint8 **ie_ptr, + LIBLTE_MME_NAS_SECURITY_ALGORITHMS_STRUCT *nas_sec_algs); + +/********************************************************************* + IE Name: Network Name + + Description: Passes a text string to the UE. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.24 + 24.008 v10.2.0 Section 10.5.3.5A +*********************************************************************/ +// Defines +// Enums +typedef enum{ + LIBLTE_MME_ADD_CI_DONT_ADD = 0, + LIBLTE_MME_ADD_CI_ADD, + LIBLTE_MME_ADD_CI_N_ITEMS, +}LIBLTE_MME_ADD_CI_ENUM; +static const char liblte_mme_add_ci_text[LIBLTE_MME_ADD_CI_N_ITEMS][20] = {"Don't add", + "Add"}; +// Structs +typedef struct{ + std::string name; + LIBLTE_MME_ADD_CI_ENUM add_ci; +}LIBLTE_MME_NETWORK_NAME_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_network_name_ie(LIBLTE_MME_NETWORK_NAME_STRUCT *net_name, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_mme_unpack_network_name_ie(uint8 **ie_ptr, + LIBLTE_MME_NETWORK_NAME_STRUCT *net_name); + +/********************************************************************* + IE Name: Nonce + + Description: Transfers a 32-bit nonce value to support deriving + a new mapped EPS security context. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.25 +*********************************************************************/ +// Defines +// Enums +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_nonce_ie(uint32 nonce, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_mme_unpack_nonce_ie(uint8 **ie_ptr, + uint32 *nonce); + +/********************************************************************* + IE Name: Paging Identity + + Description: Indicates the identity used for paging for non-EPS + services. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.25A +*********************************************************************/ +// Defines +#define LIBLTE_MME_PAGING_IDENTITY_IMSI 0 +#define LIBLTE_MME_PAGING_IDENTITY_TMSI 1 +// Enums +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_paging_identity_ie(uint8 paging_id, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_mme_unpack_paging_identity_ie(uint8 **ie_ptr, + uint8 *paging_id); + +/********************************************************************* + IE Name: P-TMSI Signature + + Description: Identifies a GMM context of a UE. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.26 + 24.008 v10.2.0 Section 10.5.5.8 +*********************************************************************/ +// Defines +// Enums +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_p_tmsi_signature_ie(uint32 p_tmsi_signature, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_mme_unpack_p_tmsi_signature_ie(uint8 **ie_ptr, + uint32 *p_tmsi_signature); + +/********************************************************************* + IE Name: Service Type + + Description: Specifies the purpose of the service request + procedure. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.27 +*********************************************************************/ +// Defines +#define LIBLTE_MME_SERVICE_TYPE_MO_CSFB 0x0 +#define LIBLTE_MME_SERVICE_TYPE_MT_CSFB 0x1 +#define LIBLTE_MME_SERVICE_TYPE_MO_CSFB_EMERGENCY 0x2 +#define LIBLTE_MME_SERVICE_TYPE_PACKET_SERVICES 0x8 +// Enums +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_service_type_ie(uint8 value, + uint8 bit_offset, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_mme_unpack_service_type_ie(uint8 **ie_ptr, + uint8 bit_offset, + uint8 *value); + +/********************************************************************* + IE Name: Short MAC + + Description: Protects the integrity of a SERVICE REQUEST message. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.28 +*********************************************************************/ +// Defines +// Enums +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_short_mac_ie(uint16 short_mac, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_mme_unpack_short_mac_ie(uint8 **ie_ptr, + uint16 *short_mac); + +/********************************************************************* + IE Name: Time Zone + + Description: Encodes the offset between universal time and local + time in steps of 15 minutes. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.29 + 24.008 v10.2.0 Section 10.5.3.8 +*********************************************************************/ +// Defines +// Enums +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_time_zone_ie(uint8 tz, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_mme_unpack_time_zone_ie(uint8 **ie_ptr, + uint8 *tz); + +/********************************************************************* + IE Name: Time Zone And Time + + Description: Encodes the offset between universal time and local + time in steps of 15 minutes and encodes the universal + time at which the IE may have been sent by the + network. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.30 + 24.008 v10.2.0 Section 10.5.3.9 +*********************************************************************/ +// Defines +// Enums +// Structs +typedef struct{ + uint16 year; + uint8 month; + uint8 day; + uint8 hour; + uint8 minute; + uint8 second; + uint8 tz; +}LIBLTE_MME_TIME_ZONE_AND_TIME_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_time_zone_and_time_ie(LIBLTE_MME_TIME_ZONE_AND_TIME_STRUCT *ttz, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_mme_unpack_time_zone_and_time_ie(uint8 **ie_ptr, + LIBLTE_MME_TIME_ZONE_AND_TIME_STRUCT *ttz); + +/********************************************************************* + IE Name: TMSI Status + + Description: Indicates whether a valid TMSI is available in the + UE or not. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.31 + 24.008 v10.2.0 Section 10.5.5.4 +*********************************************************************/ +// Defines +// Enums +typedef enum{ + LIBLTE_MME_TMSI_STATUS_NO_VALID_TMSI = 0, + LIBLTE_MME_TMSI_STATUS_VALID_TMSI, + LIBLTE_MME_TMSI_STATUS_N_ITEMS, +}LIBLTE_MME_TMSI_STATUS_ENUM; +static const char liblte_mme_tmsi_status_text[LIBLTE_MME_TMSI_STATUS_N_ITEMS][20] = {"No valid TMSI", + "Valid TMSI"}; +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_tmsi_status_ie(LIBLTE_MME_TMSI_STATUS_ENUM tmsi_status, + uint8 bit_offset, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_mme_unpack_tmsi_status_ie(uint8 **ie_ptr, + uint8 bit_offset, + LIBLTE_MME_TMSI_STATUS_ENUM *tmsi_status); + +/********************************************************************* + IE Name: Tracking Area Identity + + Description: Provides an unambiguous identification of tracking + areas within the area covered by the 3GPP system. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.32 +*********************************************************************/ +// Defines +// Enums +// Structs +typedef struct{ + uint16 mcc; + uint16 mnc; + uint16 tac; +}LIBLTE_MME_TRACKING_AREA_ID_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_tracking_area_id_ie(LIBLTE_MME_TRACKING_AREA_ID_STRUCT *tai, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_mme_unpack_tracking_area_id_ie(uint8 **ie_ptr, + LIBLTE_MME_TRACKING_AREA_ID_STRUCT *tai); + +/********************************************************************* + IE Name: Tracking Area Identity List + + Description: Transfers a list of tracking areas from the network + to the UE. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.33 +*********************************************************************/ +// Defines +#define LIBLTE_MME_TRACKING_AREA_IDENTITY_LIST_MAX_SIZE 16 +// Enums +typedef enum{ + LIBLTE_MME_TRACKING_AREA_IDENTITY_LIST_TYPE_ONE_PLMN_NON_CONSECUTIVE_TACS = 0, + LIBLTE_MME_TRACKING_AREA_IDENTITY_LIST_TYPE_ONE_PLMN_CONSECUTIVE_TACS, + LIBLTE_MME_TRACKING_AREA_IDENTITY_LIST_TYPE_DIFFERENT_PLMNS, + LIBLTE_MME_TRACKING_AREA_IDENTITY_LIST_TYPE_N_ITEMS, +}LIBLTE_MME_TRACKING_AREA_IDENTITY_LIST_TYPE_ENUM; +static const char liblte_mme_tracking_area_identity_list_type_text[LIBLTE_MME_TRACKING_AREA_IDENTITY_LIST_TYPE_N_ITEMS][100] = {"One PLMN, Non-Consecutive TACs", + "One PLMN, Consecutive TACs", + "Different PLMNs"}; +// Structs +typedef struct{ + LIBLTE_MME_TRACKING_AREA_ID_STRUCT tai[LIBLTE_MME_TRACKING_AREA_IDENTITY_LIST_MAX_SIZE]; + uint32 N_tais; +}LIBLTE_MME_TRACKING_AREA_IDENTITY_LIST_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_tracking_area_identity_list_ie(LIBLTE_MME_TRACKING_AREA_IDENTITY_LIST_STRUCT *tai_list, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_mme_unpack_tracking_area_identity_list_ie(uint8 **ie_ptr, + LIBLTE_MME_TRACKING_AREA_IDENTITY_LIST_STRUCT *tai_list); + +/********************************************************************* + IE Name: UE Network Capability + + Description: Provides the network with information concerning + aspects of the UE related to EPS or interworking with + GPRS. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.34 +*********************************************************************/ +// Defines +// Enums +// Structs +typedef struct{ + bool eea[8]; + bool eia[8]; + bool uea[8]; + bool uea_present; + bool ucs2; + bool ucs2_present; + bool uia[8]; + bool uia_present; + bool lpp; + bool lpp_present; + bool lcs; + bool lcs_present; + bool onexsrvcc; + bool onexsrvcc_present; + bool nf; + bool nf_present; +}LIBLTE_MME_UE_NETWORK_CAPABILITY_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_ue_network_capability_ie(LIBLTE_MME_UE_NETWORK_CAPABILITY_STRUCT *ue_network_cap, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_mme_unpack_ue_network_capability_ie(uint8 **ie_ptr, + LIBLTE_MME_UE_NETWORK_CAPABILITY_STRUCT *ue_network_cap); + +/********************************************************************* + IE Name: UE Radio Capability Update Needed + + Description: Indicates whether the MME shall delete the stored + UE radio capability information, if any. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.35 +*********************************************************************/ +// Defines +#define LIBLTE_MME_URC_UPDATE_NOT_NEEDED 0 +#define LIBLTE_MME_URC_UPDATE_NEEDED 1 +// Enums +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_ue_radio_capability_update_needed_ie(uint8 urc_update, + uint8 bit_offset, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_mme_unpack_ue_radio_capability_update_needed_ie(uint8 **ie_ptr, + uint8 bit_offset, + uint8 *urc_update); + +/********************************************************************* + IE Name: UE Security Capability + + Description: Indicates which security algorithms are supported by + the UE in S1 mode. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.36 +*********************************************************************/ +// Defines +// Enums +// Structs +typedef struct{ + bool eea[8]; + bool eia[8]; + bool uea[8]; + bool uea_present; + bool uia[8]; + bool uia_present; + bool gea[8]; + bool gea_present; +}LIBLTE_MME_UE_SECURITY_CAPABILITIES_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_ue_security_capabilities_ie(LIBLTE_MME_UE_SECURITY_CAPABILITIES_STRUCT *ue_sec_cap, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_mme_unpack_ue_security_capabilities_ie(uint8 **ie_ptr, + LIBLTE_MME_UE_SECURITY_CAPABILITIES_STRUCT *ue_sec_cap); + +/********************************************************************* + IE Name: Emergency Number List + + Description: Encodes emergency number(s) for use within the + country (as indicated by MCC) where the IE is + received. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.37 + 24.008 v10.2.0 Section 10.5.3.13 +*********************************************************************/ +// Defines +#define LIBLTE_MME_EMERGENCY_NUMBER_LIST_MAX_SIZE 12 +#define LIBLTE_MME_EMERGENCY_NUMBER_MAX_NUM_DIGITS 92 +// Enums +typedef enum{ + LIBLTE_MME_EMERGENCY_SERVICE_CATEGORY_POLICE = 0, + LIBLTE_MME_EMERGENCY_SERVICE_CATEGORY_AMBULANCE, + LIBLTE_MME_EMERGENCY_SERVICE_CATEGORY_FIRE, + LIBLTE_MME_EMERGENCY_SERVICE_CATEGORY_MARINE_GUARD, + LIBLTE_MME_EMERGENCY_SERVICE_CATEGORY_MOUNTAIN_RESCUE, + LIBLTE_MME_EMERGENCY_SERVICE_CATEGORY_MANUALLY_INITIATED_ECALL, + LIBLTE_MME_EMERGENCY_SERVICE_CATEGORY_AUTOMATICALLY_INITIATED_ECALL, + LIBLTE_MME_EMERGENCY_SERVICE_CATEGORY_N_ITEMS, +}LIBLTE_MME_EMERGENCY_SERVICE_CATEGORY_ENUM; +static const char liblte_mme_emergency_service_category_text[LIBLTE_MME_EMERGENCY_SERVICE_CATEGORY_N_ITEMS][100] = {"Police", + "Ambulance", + "Fire", + "Marine Guard", + "Mountain Rescue", + "Manually Initiated ECall", + "Automatically Initiated ECall"}; +// Structs +typedef struct{ + LIBLTE_MME_EMERGENCY_SERVICE_CATEGORY_ENUM emerg_service_cat; + uint32 N_emerg_num_digits; + uint8 emerg_num[LIBLTE_MME_EMERGENCY_NUMBER_MAX_NUM_DIGITS]; +}LIBLTE_MME_EMERGENCY_NUMBER_STRUCT; +typedef struct{ + LIBLTE_MME_EMERGENCY_NUMBER_STRUCT emerg_num[LIBLTE_MME_EMERGENCY_NUMBER_LIST_MAX_SIZE]; + uint32 N_emerg_nums; +}LIBLTE_MME_EMERGENCY_NUMBER_LIST_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_emergency_number_list_ie(LIBLTE_MME_EMERGENCY_NUMBER_LIST_STRUCT *emerg_num_list, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_mme_unpack_emergency_number_list_ie(uint8 **ie_ptr, + LIBLTE_MME_EMERGENCY_NUMBER_LIST_STRUCT *emerg_num_list); + +/********************************************************************* + IE Name: CLI + + Description: Conveys information about the calling line for a + terminated call to a CS fallback capable UE. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.38 +*********************************************************************/ +// Defines +// Enums +// Structs +// Functions +// FIXME + +/********************************************************************* + IE Name: SS Code + + Description: Conveys information related to a network initiated + supplementary service request to a CS fallback + capable UE. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.39 +*********************************************************************/ +// Defines +// Enums +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_ss_code_ie(uint8 code, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_mme_unpack_ss_code_ie(uint8 **ie_ptr, + uint8 *code); + +/********************************************************************* + IE Name: LCS Indicator + + Description: Indicates that the origin of the message is due to a + LCS request and the type of this request to a CS + fallback capable UE. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.40 +*********************************************************************/ +// Defines +#define LIBLTE_MME_LCS_INDICATOR_MT_LR 0x01 +// Enums +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_lcs_indicator_ie(uint8 lcs_ind, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_mme_unpack_lcs_indicator_ie(uint8 **ie_ptr, + uint8 *lcs_ind); + +/********************************************************************* + IE Name: LCS Client Identity + + Description: Conveys information related to the client of a LCS + request for a CS fallback capable UE. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.41 +*********************************************************************/ +// Defines +// Enums +// Structs +// Functions +// FIXME + +/********************************************************************* + IE Name: Generic Message Container Type + + Description: Specifies the type of message contained in the + generic message container IE. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.42 +*********************************************************************/ +// Defines +#define LIBLTE_MME_GENERIC_MESSAGE_CONTAINER_TYPE_LPP 0x01 +#define LIBLTE_MME_GENERIC_MESSAGE_CONTAINER_TYPE_LOCATION_SERVICES 0x02 +// Enums +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_generic_message_container_type_ie(uint8 msg_cont_type, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_mme_unpack_generic_message_container_type_ie(uint8 **ie_ptr, + uint8 *msg_cont_type); + +/********************************************************************* + IE Name: Generic Message Container + + Description: Encapsulates the application message transferred + between the UE and the network. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.43 +*********************************************************************/ +// Defines +// Enums +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_generic_message_container_ie(LIBLTE_BYTE_MSG_STRUCT *msg, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_mme_unpack_generic_message_container_ie(uint8 **ie_ptr, + LIBLTE_BYTE_MSG_STRUCT *msg); + +/********************************************************************* + IE Name: Voice Domain Preference and UE's Usage Setting + + Description: Provides the network with the UE's usage setting and + the voice domain preference for the E-UTRAN. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.44 + 24.008 v10.2.0 Section 10.5.5.28 +*********************************************************************/ +// Defines +// Enums +typedef enum{ + LIBLTE_MME_UE_USAGE_SETTING_VOICE_CENTRIC = 0, + LIBLTE_MME_UE_USAGE_SETTING_DATA_CENTRIC, + LIBLTE_MME_UE_USAGE_SETTING_N_ITEMS, +}LIBLTE_MME_UE_USAGE_SETTING_ENUM; +static const char liblte_mme_ue_usage_setting_text[LIBLTE_MME_UE_USAGE_SETTING_N_ITEMS][20] = {"Voice Centric", + "Data Centric"}; +typedef enum{ + LIBLTE_MME_VOICE_DOMAIN_PREF_CS_ONLY = 0, + LIBLTE_MME_VOICE_DOMAIN_PREF_PS_ONLY, + LIBLTE_MME_VOICE_DOMAIN_PREF_CS_PREFFERED, + LIBLTE_MME_VOICE_DOMAIN_PREF_PS_PREFFERED, + LIBLTE_MME_VOICE_DOMAIN_PREF_N_ITEMS, +}LIBLTE_MME_VOICE_DOMAIN_PREF_ENUM; +static const char liblte_mme_voice_domain_pref_text[LIBLTE_MME_VOICE_DOMAIN_PREF_N_ITEMS][20] = {"CS Only", + "PS Only", + "CS Preffered", + "PS Preffered"}; +// Structs +typedef struct{ + LIBLTE_MME_UE_USAGE_SETTING_ENUM ue_usage_setting; + LIBLTE_MME_VOICE_DOMAIN_PREF_ENUM voice_domain_pref; +}LIBLTE_MME_VOICE_DOMAIN_PREF_AND_UE_USAGE_SETTING_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_voice_domain_pref_and_ue_usage_setting_ie(LIBLTE_MME_VOICE_DOMAIN_PREF_AND_UE_USAGE_SETTING_STRUCT *voice_domain_pref_and_ue_usage_setting, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_mme_unpack_voice_domain_pref_and_ue_usage_setting_ie(uint8 **ie_ptr, + LIBLTE_MME_VOICE_DOMAIN_PREF_AND_UE_USAGE_SETTING_STRUCT *voice_domain_pref_and_ue_usage_setting); + +/********************************************************************* + IE Name: GUTI Type + + Description: Indicates whether the GUTI included in the same + message in an information element of type EPS + mobility identity represents a native GUTI or a + mapped GUTI. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.45 +*********************************************************************/ +// Defines +// Enums +typedef enum{ + LIBLTE_MME_GUTI_TYPE_NATIVE = 0, + LIBLTE_MME_GUTI_TYPE_MAPPED, + LIBLTE_MME_GUTI_TYPE_N_ITEMS, +}LIBLTE_MME_GUTI_TYPE_ENUM; +static const char liblte_mme_guti_type_text[LIBLTE_MME_GUTI_TYPE_N_ITEMS][20] = {"Native", + "Mapped"}; +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_guti_type_ie(LIBLTE_MME_GUTI_TYPE_ENUM guti_type, + uint8 bit_offset, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_mme_unpack_guti_type_ie(uint8 **ie_ptr, + uint8 bit_offset, + LIBLTE_MME_GUTI_TYPE_ENUM *guti_type); + +/********************************************************************* + IE Name: Access Point Name + + Description: Identifies the packet data network to which the GPRS + user wishes to connect and notifies the access point + of the packet data network that wishes to connect to + the UE. + + Document Reference: 24.301 v10.2.0 Section 9.9.4.1 + 24.008 v10.2.0 Section 10.5.6.1 +*********************************************************************/ +// Defines +// Enums +// Structs +typedef struct{ + std::string apn; +}LIBLTE_MME_ACCESS_POINT_NAME_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_access_point_name_ie(LIBLTE_MME_ACCESS_POINT_NAME_STRUCT *apn, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_mme_unpack_access_point_name_ie(uint8 **ie_ptr, + LIBLTE_MME_ACCESS_POINT_NAME_STRUCT *apn); + +/********************************************************************* + IE Name: APN Aggregate Maximum Bit Rate + + Description: Indicates the initial subscribed APN-AMBR when the + UE establishes a PDN connection or indicates the new + APN-AMBR if it is changed by the network. + + Document Reference: 24.301 v10.2.0 Section 9.9.4.2 +*********************************************************************/ +// Defines +// Enums +// Structs +typedef struct{ + uint8 apn_ambr_dl; + uint8 apn_ambr_ul; + uint8 apn_ambr_dl_ext; + uint8 apn_ambr_ul_ext; + uint8 apn_ambr_dl_ext2; + uint8 apn_ambr_ul_ext2; + bool ext_present; + bool ext2_present; +}LIBLTE_MME_APN_AGGREGATE_MAXIMUM_BIT_RATE_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_apn_aggregate_maximum_bit_rate_ie(LIBLTE_MME_APN_AGGREGATE_MAXIMUM_BIT_RATE_STRUCT *apn_ambr, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_mme_unpack_apn_aggregate_maximum_bit_rate_ie(uint8 **ie_ptr, + LIBLTE_MME_APN_AGGREGATE_MAXIMUM_BIT_RATE_STRUCT *apn_ambr); + +/********************************************************************* + IE Name: Connectivity Type + + Description: Specifies the type of connectivity selected by the + network for the PDN connection. + + Document Reference: 24.301 v10.2.0 Section 9.9.4.2A + 24.008 v10.2.0 Section 10.5.6.19 +*********************************************************************/ +// Defines +#define LIBLTE_MME_CONNECTIVITY_TYPE_NOT_INDICATED 0x0 +#define LIBLTE_MME_CONNECTIVITY_TYPE_LIPA_PDN 0x1 +// Enums +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_connectivity_type_ie(uint8 con_type, + uint8 bit_offset, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_mme_unpack_connectivity_type_ie(uint8 **ie_ptr, + uint8 bit_offset, + uint8 *con_type); + +/********************************************************************* + IE Name: EPS Quality Of Service + + Description: Specifies the QoS parameters for an EPS bearer + context. + + Document Reference: 24.301 v10.2.0 Section 9.9.4.3 +*********************************************************************/ +// Defines +// Enums +// Structs +typedef struct{ + uint8 qci; + uint8 mbr_ul; + uint8 mbr_dl; + uint8 gbr_ul; + uint8 gbr_dl; + uint8 mbr_ul_ext; + uint8 mbr_dl_ext; + uint8 gbr_ul_ext; + uint8 gbr_dl_ext; + bool br_present; + bool br_ext_present; +}LIBLTE_MME_EPS_QUALITY_OF_SERVICE_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_eps_quality_of_service_ie(LIBLTE_MME_EPS_QUALITY_OF_SERVICE_STRUCT *qos, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_mme_unpack_eps_quality_of_service_ie(uint8 **ie_ptr, + LIBLTE_MME_EPS_QUALITY_OF_SERVICE_STRUCT *qos); + +/********************************************************************* + IE Name: ESM Cause + + Description: Indicates the reason why a session management request + is rejected. + + Document Reference: 24.301 v10.2.0 Section 9.9.4.4 +*********************************************************************/ +// Defines +#define LIBLTE_MME_ESM_CAUSE_OPERATOR_DETERMINED_BARRING 0x08 +#define LIBLTE_MME_ESM_CAUSE_INSUFFICIENT_RESOURCES 0x1A +#define LIBLTE_MME_ESM_CAUSE_UNKNOWN_OR_MISSING_APN 0x1B +#define LIBLTE_MME_ESM_CAUSE_UNKNOWN_PDN_TYPE 0x1C +#define LIBLTE_MME_ESM_CAUSE_USER_AUTHENTICATION_FAILED 0x1D +#define LIBLTE_MME_ESM_CAUSE_REQUEST_REJECTED_BY_SERVING_OR_PDN_GW 0x1E +#define LIBLTE_MME_ESM_CAUSE_REQUEST_REJECTED_UNSPECIFIED 0x1F +#define LIBLTE_MME_ESM_CAUSE_SERVICE_OPTION_NOT_SUPPORTED 0x20 +#define LIBLTE_MME_ESM_CAUSE_REQUESTED_SERVICE_OPTION_NOT_SUBSCRIBED 0x21 +#define LIBLTE_MME_ESM_CAUSE_SERVICE_OPTION_TEMPORARILY_OUT_OF_ORDER 0x22 +#define LIBLTE_MME_ESM_CAUSE_PTI_ALREADY_IN_USE 0x23 +#define LIBLTE_MME_ESM_CAUSE_REGULAR_DEACTIVATION 0x24 +#define LIBLTE_MME_ESM_CAUSE_EPS_QOS_NOT_ACCEPTED 0x25 +#define LIBLTE_MME_ESM_CAUSE_NETWORK_FAILURE 0x26 +#define LIBLTE_MME_ESM_CAUSE_REACTIVATION_REQUESTED 0x27 +#define LIBLTE_MME_ESM_CAUSE_SEMANTIC_ERROR_IN_THE_TFT_OPERATION 0x29 +#define LIBLTE_MME_ESM_CAUSE_SYNTACTICAL_ERROR_IN_THE_TFT_OPERATION 0x2A +#define LIBLTE_MME_ESM_CAUSE_INVALID_EPS_BEARER_IDENTITY 0x2B +#define LIBLTE_MME_ESM_CAUSE_SEMANTIC_ERRORS_IN_PACKET_FILTERS 0x2C +#define LIBLTE_MME_ESM_CAUSE_SYNTACTICAL_ERRORS_IN_PACKET_FILTERS 0x2D +#define LIBLTE_MME_ESM_CAUSE_UNUSED 0x2E +#define LIBLTE_MME_ESM_CAUSE_PTI_MISMATCH 0x2F +#define LIBLTE_MME_ESM_CAUSE_LAST_PDN_DISCONNECTION_NOT_ALLOWED 0x31 +#define LIBLTE_MME_ESM_CAUSE_PDN_TYPE_IPV4_ONLY_ALLOWED 0x32 +#define LIBLTE_MME_ESM_CAUSE_PDN_TYPE_IPV6_ONLY_ALLOWED 0x33 +#define LIBLTE_MME_ESM_CAUSE_SINGLE_ADDRESS_BEARERS_ONLY_ALLOWED 0x34 +#define LIBLTE_MME_ESM_CAUSE_ESM_INFORMATION_NOT_RECEIVED 0x35 +#define LIBLTE_MME_ESM_CAUSE_PDN_CONNECTION_DOES_NOT_EXIST 0x36 +#define LIBLTE_MME_ESM_CAUSE_MULTIPLE_PDN_CONNECTIONS_FOR_A_GIVEN_APN_NOT_ALLOWED 0x37 +#define LIBLTE_MME_ESM_CAUSE_COLLISION_WITH_NETWORK_INITIATED_REQUEST 0x38 +#define LIBLTE_MME_ESM_CAUSE_UNSUPPORTED_QCI_VALUE 0x3B +#define LIBLTE_MME_ESM_CAUSE_BEARER_HANDLING_NOT_SUPPORTED 0x3C +#define LIBLTE_MME_ESM_CAUSE_INVALID_PTI_VALUE 0x51 +#define LIBLTE_MME_ESM_CAUSE_SEMANTICALLY_INCORRECT_MESSAGE 0x5F +#define LIBLTE_MME_ESM_CAUSE_INVALID_MANDATORY_INFORMATION 0x60 +#define LIBLTE_MME_ESM_CAUSE_MESSAGE_TYPE_NON_EXISTENT_OR_NOT_IMPLEMENTED 0x61 +#define LIBLTE_MME_ESM_CAUSE_MESSAGE_TYPE_NOT_COMPATIBLE_WITH_THE_PROTOCOL_STATE 0x62 +#define LIBLTE_MME_ESM_CAUSE_INFORMATION_ELEMENT_NON_EXISTENT_OR_NOT_IMPLEMENTED 0x63 +#define LIBLTE_MME_ESM_CAUSE_CONDITIONAL_IE_ERROR 0x64 +#define LIBLTE_MME_ESM_CAUSE_MESSAGE_NOT_COMPATIBLE_WITH_THE_PROTOCOL_STATE 0x65 +#define LIBLTE_MME_ESM_CAUSE_PROTOCOL_ERROR_UNSPECIFIED 0x6F +#define LIBLTE_MME_ESM_CAUSE_APN_RESTRICTION_VALUE_INCOMPATIBLE_WITH_ACTIVE_EPS_BEARER_CONTEXT 0x70 +// Enums +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_esm_cause_ie(uint8 cause, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_mme_unpack_esm_cause_ie(uint8 **ie_ptr, + uint8 *cause); + +/********************************************************************* + IE Name: ESM Information Transfer Flag + + Description: Indicates whether ESM information, i.e. protocol + configuration options or APN or both, is to be + transferred security protected. + + Document Reference: 24.301 v10.2.0 Section 9.9.4.5 +*********************************************************************/ +// Defines +// Enums +typedef enum{ + LIBLTE_MME_ESM_INFO_TRANSFER_FLAG_NOT_REQUIRED = 0, + LIBLTE_MME_ESM_INFO_TRANSFER_FLAG_REQUIRED, + LIBLTE_MME_ESM_INFO_TRANSFER_FLAG_N_ITEMS, +}LIBLTE_MME_ESM_INFO_TRANSFER_FLAG_ENUM; +static const char liblte_mme_esm_info_transfer_flag_text[LIBLTE_MME_ESM_INFO_TRANSFER_FLAG_N_ITEMS][20] = {"Not Required", + "Required"}; +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_esm_info_transfer_flag_ie(LIBLTE_MME_ESM_INFO_TRANSFER_FLAG_ENUM esm_info_transfer_flag, + uint8 bit_offset, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_mme_unpack_esm_info_transfer_flag_ie(uint8 **ie_ptr, + uint8 bit_offset, + LIBLTE_MME_ESM_INFO_TRANSFER_FLAG_ENUM *esm_info_transfer_flag); + +/********************************************************************* + IE Name: Linked EPS Bearer Identity + + Description: Identifies the default bearer that is associated + with a dedicated EPS bearer or identifies the EPS + bearer (default or dedicated) with which one or more + packet filters specified in a traffic flow aggregate + are associated. + + Document Reference: 24.301 v10.2.0 Section 9.9.4.6 +*********************************************************************/ +// Defines +#define LIBLTE_MME_LINKED_EPS_BEARER_IDENTITY_5 0x5 +#define LIBLTE_MME_LINKED_EPS_BEARER_IDENTITY_6 0x6 +#define LIBLTE_MME_LINKED_EPS_BEARER_IDENTITY_7 0x7 +#define LIBLTE_MME_LINKED_EPS_BEARER_IDENTITY_8 0x8 +#define LIBLTE_MME_LINKED_EPS_BEARER_IDENTITY_9 0x9 +#define LIBLTE_MME_LINKED_EPS_BEARER_IDENTITY_10 0xA +#define LIBLTE_MME_LINKED_EPS_BEARER_IDENTITY_11 0xB +#define LIBLTE_MME_LINKED_EPS_BEARER_IDENTITY_12 0xC +#define LIBLTE_MME_LINKED_EPS_BEARER_IDENTITY_13 0xD +#define LIBLTE_MME_LINKED_EPS_BEARER_IDENTITY_14 0xE +#define LIBLTE_MME_LINKED_EPS_BEARER_IDENTITY_15 0xF +// Enums +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_linked_eps_bearer_identity_ie(uint8 bearer_id, + uint8 bit_offset, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_mme_unpack_linked_eps_bearer_identity_ie(uint8 **ie_ptr, + uint8 bit_offset, + uint8 *bearer_id); + +/********************************************************************* + IE Name: LLC Service Access Point Identifier + + Description: Identifies the service access point that is used for + the GPRS data transfer at LLC layer. + + Document Reference: 24.301 v10.2.0 Section 9.9.4.7 + 24.008 v10.2.0 Section 10.5.6.9 +*********************************************************************/ +// Defines +#define LIBLTE_MME_LLC_SAPI_NOT_ASSIGNED 0x0 +#define LIBLTE_MME_LLC_SAPI_3 0x3 +#define LIBLTE_MME_LLC_SAPI_5 0x5 +#define LIBLTE_MME_LLC_SAPI_9 0x9 +#define LIBLTE_MME_LLC_SAPI_11 0xB +// Enums +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_llc_service_access_point_identifier_ie(uint8 llc_sapi, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_mme_unpack_llc_service_access_point_identifier_ie(uint8 **ie_ptr, + uint8 *llc_sapi); + +/********************************************************************* + IE Name: Notification Indicator + + Description: Informs the UE about an event which is relevant for + the upper layer using an EPS bearer context or + having requested a procedure transaction. + + Document Reference: 24.301 v10.2.0 Section 9.9.4.7A +*********************************************************************/ +// Defines +#define LIBLTE_MME_NOTIFICATION_INDICATOR_SRVCC_HO_CANCELLED_IMS_SESSION_REEST_REQ 0x01 +// Enums +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_notification_indicator_ie(uint8 notification_ind, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_mme_unpack_notification_indicator_ie(uint8 **ie_ptr, + uint8 *notification_ind); + +/********************************************************************* + IE Name: Packet Flow Identifier + + Description: Indicates the packet flow identifier for a packet + flow context. + + Document Reference: 24.301 v10.2.0 Section 9.9.4.8 + 24.008 v10.2.0 Section 10.5.6.11 +*********************************************************************/ +// Defines +#define LIBLTE_MME_PACKET_FLOW_ID_BEST_EFFORT 0x00 +#define LIBLTE_MME_PACKET_FLOW_ID_SIGNALLING 0x01 +#define LIBLTE_MME_PACKET_FLOW_ID_SMS 0x02 +#define LIBLTE_MME_PACKET_FLOW_ID_TOM8 0x03 +// Enums +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_packet_flow_identifier_ie(uint8 packet_flow_id, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_mme_unpack_packet_flow_identifier_ie(uint8 **ie_ptr, + uint8 *packet_flow_id); + +/********************************************************************* + IE Name: PDN Address + + Description: Assigns an IPv4 address to the UE associated with a + packet data network and provides the UE with an + interface identifier to be used to build the IPv6 + link local address. + + Document Reference: 24.301 v10.2.0 Section 9.9.4.9 +*********************************************************************/ +// Defines +#define LIBLTE_MME_PDN_TYPE_IPV4 0x1 +#define LIBLTE_MME_PDN_TYPE_IPV6 0x2 +#define LIBLTE_MME_PDN_TYPE_IPV4V6 0x3 +// Enums +// Structs +typedef struct{ + uint8 pdn_type; + uint8 addr[12]; +}LIBLTE_MME_PDN_ADDRESS_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_pdn_address_ie(LIBLTE_MME_PDN_ADDRESS_STRUCT *pdn_addr, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_mme_unpack_pdn_address_ie(uint8 **ie_ptr, + LIBLTE_MME_PDN_ADDRESS_STRUCT *pdn_addr); + +/********************************************************************* + IE Name: PDN Type + + Description: Indicates the IP version capability of the IP stack + associated with the UE. + + Document Reference: 24.301 v10.2.0 Section 9.9.4.10 +*********************************************************************/ +// Defines +#define LIBLTE_MME_PDN_TYPE_IPV4 0x1 +#define LIBLTE_MME_PDN_TYPE_IPV6 0x2 +#define LIBLTE_MME_PDN_TYPE_IPV4V6 0x3 +#define LIBLTE_MME_PDN_TYPE_UNUSED 0x4 +// Enums +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_pdn_type_ie(uint8 pdn_type, + uint8 bit_offset, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_mme_unpack_pdn_type_ie(uint8 **ie_ptr, + uint8 bit_offset, + uint8 *pdn_type); + +/********************************************************************* + IE Name: Protocol Configuration Options + + Description: Transfers external network protocol options + associated with a PDP context activation and + transfers additional (protocol) data (e.g. + configuration parameters, error codes or messages/ + events) associated with an external protocol or an + application. + + Document Reference: 24.301 v10.2.0 Section 9.9.4.11 + 24.008 v10.2.0 Section 10.5.6.3 +*********************************************************************/ +// Defines +#define LIBLTE_MME_MAX_PROTOCOL_CONFIG_OPTIONS 83 +#define LIBLTE_MME_MAX_PROTOCOL_CONFIG_LEN 248 +#define LIBLTE_MME_CONFIGURATION_PROTOCOL_OPTIONS_LCP 0xC021 +#define LIBLTE_MME_CONFIGURATION_PROTOCOL_OPTIONS_PAP 0xC023 +#define LIBLTE_MME_CONFIGURATION_PROTOCOL_OPTIONS_CHAP 0xC223 +#define LIBLTE_MME_CONFIGURATION_PROTOCOL_OPTIONS_IPCP 0x8021 +#define LIBLTE_MME_ADDITIONAL_PARAMETERS_UL_P_CSCF_IPV6_ADDRESS_REQUEST 0x0001 +#define LIBLTE_MME_ADDITIONAL_PARAMETERS_UL_IM_CN_SUBSYSTEM_SIGNALLING_FLAG 0x0002 +#define LIBLTE_MME_ADDITIONAL_PARAMETERS_UL_DNS_SERVER_IPV6_ADDRESS_REQUEST 0x0003 +#define LIBLTE_MME_ADDITIONAL_PARAMETERS_UL_MS_SUPPORT_OF_NETWORK_REQUESTED_BEARER_CONTROL_INDICATOR 0x0005 +#define LIBLTE_MME_ADDITIONAL_PARAMETERS_UL_DSMIPV6_HOME_AGENT_ADDRESS_REQUEST 0x0007 +#define LIBLTE_MME_ADDITIONAL_PARAMETERS_UL_DSMIPV6_HOME_NETWORK_PREFIX_REQUEST 0x0008 +#define LIBLTE_MME_ADDITIONAL_PARAMETERS_UL_DSMIPV6_IPV4_HOME_AGENT_ADDRESS_REQUEST 0x0009 +#define LIBLTE_MME_ADDITIONAL_PARAMETERS_UL_IP_ADDRESS_ALLOCATION_VIA_NAS_SIGNALLING 0x000A +#define LIBLTE_MME_ADDITIONAL_PARAMETERS_UL_IPV4_ADDRESS_ALLOCATION_VIA_DHCPV4 0x000B +#define LIBLTE_MME_ADDITIONAL_PARAMETERS_UL_P_CSCF_IPV4_ADDRESS_REQUEST 0x000C +#define LIBLTE_MME_ADDITIONAL_PARAMETERS_UL_DNS_SERVER_IPV4_ADDRESS_REQUEST 0x000D +#define LIBLTE_MME_ADDITIONAL_PARAMETERS_UL_MSISDN_REQUEST 0x000E +#define LIBLTE_MME_ADDITIONAL_PARAMETERS_UL_IFOM_SUPPORT_REQUEST 0x000F +#define LIBLTE_MME_ADDITIONAL_PARAMETERS_UL_IPV4_LINK_MTU_REQUEST 0x0010 +#define LIBLTE_MME_ADDITIONAL_PARAMETERS_DL_P_CSCF_IPV6_ADDRESS 0x0001 +#define LIBLTE_MME_ADDITIONAL_PARAMETERS_DL_IM_CN_SUBSYSTEM_SIGNALLING_FLAG 0x0002 +#define LIBLTE_MME_ADDITIONAL_PARAMETERS_DL_DNS_SERVER_IPV6_ADDRESS 0x0003 +#define LIBLTE_MME_ADDITIONAL_PARAMETERS_DL_POLICY_CONTROL_REJECTION_CODE 0x0004 +#define LIBLTE_MME_ADDITIONAL_PARAMETERS_DL_SELECTED_BEARER_CONTROL_MODE 0x0005 +#define LIBLTE_MME_ADDITIONAL_PARAMETERS_DL_DSMIPV6_HOME_AGENT_ADDRESS 0x0007 +#define LIBLTE_MME_ADDITIONAL_PARAMETERS_DL_DSMIPV6_HOME_NETWORK_PREFIX 0x0008 +#define LIBLTE_MME_ADDITIONAL_PARAMETERS_DL_DSMIPV6_IPV4_HOME_AGENT_ADDRESS 0x0009 +#define LIBLTE_MME_ADDITIONAL_PARAMETERS_DL_P_CSCF_IPV4_ADDRESS 0x000C +#define LIBLTE_MME_ADDITIONAL_PARAMETERS_DL_DNS_SERVER_IPV4_ADDRESS 0x000D +#define LIBLTE_MME_ADDITIONAL_PARAMETERS_DL_MSISDN 0x000E +#define LIBLTE_MME_ADDITIONAL_PARAMETERS_DL_IFOM_SUPPORT 0x000F +#define LIBLTE_MME_ADDITIONAL_PARAMETERS_DL_IPV4_LINK_MTU 0x0010 +// Enums +// Structs +typedef struct{ + uint16 id; + uint8 len; + uint8 contents[LIBLTE_MME_MAX_PROTOCOL_CONFIG_LEN]; +}LIBLTE_MME_PROTOCOL_CONFIG_STRUCT; +typedef struct{ + LIBLTE_MME_PROTOCOL_CONFIG_STRUCT opt[LIBLTE_MME_MAX_PROTOCOL_CONFIG_OPTIONS]; + uint32 N_opts; +}LIBLTE_MME_PROTOCOL_CONFIG_OPTIONS_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_protocol_config_options_ie(LIBLTE_MME_PROTOCOL_CONFIG_OPTIONS_STRUCT *protocol_cnfg_opts, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_mme_unpack_protocol_config_options_ie(uint8 **ie_ptr, + LIBLTE_MME_PROTOCOL_CONFIG_OPTIONS_STRUCT *protocol_cnfg_opts); + +/********************************************************************* + IE Name: Quality Of Service + + Description: Specifies the QoS parameters for a PDP context. + + Document Reference: 24.301 v10.2.0 Section 9.9.4.12 + 24.008 v10.2.0 Section 10.5.6.5 +*********************************************************************/ +// Defines +#define LIBLTE_MME_QOS_DELAY_CLASS_UL_SUBSCRIBED 0x0 +#define LIBLTE_MME_QOS_DELAY_CLASS_DL_RESERVED 0x0 +#define LIBLTE_MME_QOS_DELAY_CLASS_1 0x1 +#define LIBLTE_MME_QOS_DELAY_CLASS_2 0x2 +#define LIBLTE_MME_QOS_DELAY_CLASS_3 0x3 +#define LIBLTE_MME_QOS_DELAY_CLASS_4 0x4 +#define LIBLTE_MME_QOS_DELAY_CLASS_RESERVED 0x7 +#define LIBLTE_MME_QOS_RELIABILITY_CLASS_UL_SUBSCRIBED 0x0 +#define LIBLTE_MME_QOS_RELIABILITY_CLASS_DL_RESERVED 0x0 +#define LIBLTE_MME_QOS_RELIABILITY_CLASS_UNUSED 0x1 +#define LIBLTE_MME_QOS_RELIABILITY_CLASS_UNACK_GTP_ACK_LLC_RLC_PROTECTED 0x2 +#define LIBLTE_MME_QOS_RELIABILITY_CLASS_UNACK_GTP_LLC_ACK_RLC_PROTECTED 0x3 +#define LIBLTE_MME_QOS_RELIABILITY_CLASS_UNACK_GTP_LLC_RLC_PROTECTED 0x4 +#define LIBLTE_MME_QOS_RELIABILITY_CLASS_UNACK_GTP_LLC_RLC_UNPROTECTED 0x5 +#define LIBLTE_MME_QOS_RELIABILITY_CLASS_RESERVED 0x7 +#define LIBLTE_MME_QOS_PEAK_THROUGHPUT_UL_SUBSCRIBED 0x0 +#define LIBLTE_MME_QOS_PEAK_THROUGHPUT_DL_RESERVED 0x0 +#define LIBLTE_MME_QOS_PEAK_THROUGHPUT_UP_TO_1000BPS 0x1 +#define LIBLTE_MME_QOS_PEAK_THROUGHPUT_UP_TO_2000BPS 0x2 +#define LIBLTE_MME_QOS_PEAK_THROUGHPUT_UP_TO_4000BPS 0x3 +#define LIBLTE_MME_QOS_PEAK_THROUGHPUT_UP_TO_8000BPS 0x4 +#define LIBLTE_MME_QOS_PEAK_THROUGHPUT_UP_TO_16000BPS 0x5 +#define LIBLTE_MME_QOS_PEAK_THROUGHPUT_UP_TO_32000BPS 0x6 +#define LIBLTE_MME_QOS_PEAK_THROUGHPUT_UP_TO_64000BPS 0x7 +#define LIBLTE_MME_QOS_PEAK_THROUGHPUT_UP_TO_128000BPS 0x8 +#define LIBLTE_MME_QOS_PEAK_THROUGHPUT_UP_TO_256000BPS 0x9 +#define LIBLTE_MME_QOS_PEAK_THROUGHPUT_RESERVED 0xF +#define LIBLTE_MME_QOS_PRECEDENCE_CLASS_UL_SUBSCRIBED 0x0 +#define LIBLTE_MME_QOS_PRECEDENCE_CLASS_DL_RESERVED 0x0 +#define LIBLTE_MME_QOS_PRECEDENCE_CLASS_HIGH_PRIORITY 0x1 +#define LIBLTE_MME_QOS_PRECEDENCE_CLASS_NORMAL_PRIORITY 0x2 +#define LIBLTE_MME_QOS_PRECEDENCE_CLASS_LOW_PRIORITY 0x3 +#define LIBLTE_MME_QOS_PRECEDENCE_CLASS_RESERVED 0x7 +#define LIBLTE_MME_QOS_MEAN_THROUGHPUT_UL_SUBSCRIBED 0x00 +#define LIBLTE_MME_QOS_MEAN_THROUGHPUT_DL_RESERVED 0x00 +#define LIBLTE_MME_QOS_MEAN_THROUGHPUT_100BPH 0x01 +#define LIBLTE_MME_QOS_MEAN_THROUGHPUT_200BPH 0x02 +#define LIBLTE_MME_QOS_MEAN_THROUGHPUT_500BPH 0x03 +#define LIBLTE_MME_QOS_MEAN_THROUGHPUT_1000BPH 0x04 +#define LIBLTE_MME_QOS_MEAN_THROUGHPUT_2000BPH 0x05 +#define LIBLTE_MME_QOS_MEAN_THROUGHPUT_5000BPH 0x06 +#define LIBLTE_MME_QOS_MEAN_THROUGHPUT_10000BPH 0x07 +#define LIBLTE_MME_QOS_MEAN_THROUGHPUT_20000BPH 0x08 +#define LIBLTE_MME_QOS_MEAN_THROUGHPUT_50000BPH 0x09 +#define LIBLTE_MME_QOS_MEAN_THROUGHPUT_100000BPH 0x0A +#define LIBLTE_MME_QOS_MEAN_THROUGHPUT_200000BPH 0x0B +#define LIBLTE_MME_QOS_MEAN_THROUGHPUT_500000BPH 0x0C +#define LIBLTE_MME_QOS_MEAN_THROUGHPUT_1000000BPH 0x0D +#define LIBLTE_MME_QOS_MEAN_THROUGHPUT_2000000BPH 0x0E +#define LIBLTE_MME_QOS_MEAN_THROUGHPUT_5000000BPH 0x0F +#define LIBLTE_MME_QOS_MEAN_THROUGHPUT_10000000BPH 0x10 +#define LIBLTE_MME_QOS_MEAN_THROUGHPUT_20000000BPH 0x11 +#define LIBLTE_MME_QOS_MEAN_THROUGHPUT_50000000BPH 0x12 +#define LIBLTE_MME_QOS_MEAN_THROUGHPUT_RESERVED 0x1E +#define LIBLTE_MME_QOS_MEAN_THROUGHPUT_BEST_EFFORT 0x1F +#define LIBLTE_MME_QOS_TRAFFIC_CLASS_UL_SUBSCRIBED 0x0 +#define LIBLTE_MME_QOS_TRAFFIC_CLASS_DL_RESERVED 0x0 +#define LIBLTE_MME_QOS_TRAFFIC_CLASS_CONVERSATIONAL 0x1 +#define LIBLTE_MME_QOS_TRAFFIC_CLASS_STREAMING 0x2 +#define LIBLTE_MME_QOS_TRAFFIC_CLASS_INTERACTIVE 0x3 +#define LIBLTE_MME_QOS_TRAFFIC_CLASS_BACKGROUND 0x4 +#define LIBLTE_MME_QOS_TRAFFIC_CLASS_RESERVED 0x7 +#define LIBLTE_MME_QOS_DELIVERY_ORDER_UL_SUBSCRIBED 0x0 +#define LIBLTE_MME_QOS_DELIVERY_ORDER_DL_RESERVED 0x0 +#define LIBLTE_MME_QOS_DELIVERY_ORDER_WITH_DELIVERY_ORDER_YES 0x1 +#define LIBLTE_MME_QOS_DELIVERY_ORDER_WITHOUT_DELIVERY_ORDER_NO 0x2 +#define LIBLTE_MME_QOS_DELIVERY_ORDER_RESERVED 0x3 +#define LIBLTE_MME_QOS_DELIVERY_OF_ERRONEOUS_SDU_UL_SUBSCRIBED 0x0 +#define LIBLTE_MME_QOS_DELIVERY_OF_ERRONEOUS_SDU_DL_RESERVED 0x0 +#define LIBLTE_MME_QOS_DELIVERY_OF_ERRONEOUS_SDU_NO_DETECT 0x1 +#define LIBLTE_MME_QOS_DELIVERY_OF_ERRONEOUS_SDU_DELIVERED 0x2 +#define LIBLTE_MME_QOS_DELIVERY_OF_ERRONEOUS_SDU_NOT_DELIVERED 0x3 +#define LIBLTE_MME_QOS_DELIVERY_OF_ERRONEOUS_SDU_RESERVED 0x7 +#define LIBLTE_MME_QOS_MAX_SDU_SIZE_UL_SUBSCRIBED 0x00 +#define LIBLTE_MME_QOS_MAX_SDU_SIZE_DL_RESERVED 0x00 +#define LIBLTE_MME_QOS_MAX_SDU_SIZE_RESERVED 0xFF +#define LIBLTE_MME_QOS_RESIDUAL_BER_UL_SUBSCRIBED 0x0 +#define LIBLTE_MME_QOS_RESIDUAL_BER_DL_RESERVED 0x0 +#define LIBLTE_MME_QOS_RESIDUAL_BER_5_E_NEG_2 0x1 +#define LIBLTE_MME_QOS_RESIDUAL_BER_1_E_NEG_2 0x2 +#define LIBLTE_MME_QOS_RESIDUAL_BER_5_E_NEG_3 0x3 +#define LIBLTE_MME_QOS_RESIDUAL_BER_4_E_NEG_3 0x4 +#define LIBLTE_MME_QOS_RESIDUAL_BER_1_E_NEG_3 0x5 +#define LIBLTE_MME_QOS_RESIDUAL_BER_1_E_NEG_4 0x6 +#define LIBLTE_MME_QOS_RESIDUAL_BER_1_E_NEG_5 0x7 +#define LIBLTE_MME_QOS_RESIDUAL_BER_1_E_NEG_6 0x8 +#define LIBLTE_MME_QOS_RESIDUAL_BER_6_E_NEG_8 0x9 +#define LIBLTE_MME_QOS_RESIDUAL_BER_RESERVED 0xF +#define LIBLTE_MME_QOS_SDU_ERROR_RATIO_UL_SUBSCRIBED 0x0 +#define LIBLTE_MME_QOS_SDU_ERROR_RATIO_DL_RESERVED 0x0 +#define LIBLTE_MME_QOS_SDU_ERROR_RATIO_1_E_NEG_2 0x1 +#define LIBLTE_MME_QOS_SDU_ERROR_RATIO_7_E_NEG_3 0x2 +#define LIBLTE_MME_QOS_SDU_ERROR_RATIO_1_E_NEG_3 0x3 +#define LIBLTE_MME_QOS_SDU_ERROR_RATIO_1_E_NEG_4 0x4 +#define LIBLTE_MME_QOS_SDU_ERROR_RATIO_1_E_NEG_5 0x5 +#define LIBLTE_MME_QOS_SDU_ERROR_RATIO_1_E_NEG_6 0x6 +#define LIBLTE_MME_QOS_SDU_ERROR_RATIO_1_E_NEG_1 0x7 +#define LIBLTE_MME_QOS_SDU_ERROR_RATIO_RESERVED 0xF +#define LIBLTE_MME_QOS_TRANSFER_DELAY_UL_SUBSCRIBED 0x00 +#define LIBLTE_MME_QOS_TRANSFER_DELAY_DL_RESERVED 0x00 +#define LIBLTE_MME_QOS_TRANSFER_DELAY_RESERVED 0x3F +#define LIBLTE_MME_QOS_TRAFFIC_HANDLING_PRIORITY_UL_SUBSCRIBED 0x0 +#define LIBLTE_MME_QOS_TRAFFIC_HANDLING_PRIORITY_DL_RESERVED 0x0 +#define LIBLTE_MME_QOS_TRAFFIC_HANDLING_PRIORITY_LEVEL_1 0x1 +#define LIBLTE_MME_QOS_TRAFFIC_HANDLING_PRIORITY_LEVEL_2 0x2 +#define LIBLTE_MME_QOS_TRAFFIC_HANDLING_PRIORITY_LEVEL_3 0x3 +#define LIBLTE_MME_QOS_SIGNALLING_INDICATOR_NOT_OPTIMIZED_FOR_SIGNALLING 0x0 +#define LIBLTE_MME_QOS_SIGNALLING_INDICATOR_OPTIMIZED_FOR_SIGNALLING 0x1 +#define LIBLTE_MME_QOS_SOURCE_STATISTICS_DESCRIPTOR_UNKNOWN 0x0 +#define LIBLTE_MME_QOS_SOURCE_STATISTICS_DESCRIPTOR_SPEECH 0x1 +// Enums +// Structs +typedef struct{ + uint8 delay_class; + uint8 reliability_class; + uint8 peak_throughput; + uint8 precedence_class; + uint8 mean_throughput; + uint8 traffic_class; + uint8 delivery_order; + uint8 delivery_of_erroneous_sdu; + uint8 max_sdu_size; + uint8 mbr_ul; + uint8 mbr_dl; + uint8 residual_ber; + uint8 sdu_error_ratio; + uint8 transfer_delay; + uint8 traffic_handling_prio; + uint8 gbr_ul; + uint8 gbr_dl; + uint8 signalling_ind; + uint8 source_stats_descriptor; + uint8 mbr_dl_ext; + uint8 gbr_dl_ext; + uint8 mbr_ul_ext; + uint8 gbr_ul_ext; + bool dl_ext_present; + bool ul_ext_present; +}LIBLTE_MME_QUALITY_OF_SERVICE_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_quality_of_service_ie(LIBLTE_MME_QUALITY_OF_SERVICE_STRUCT *qos, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_mme_unpack_quality_of_service_ie(uint8 **ie_ptr, + LIBLTE_MME_QUALITY_OF_SERVICE_STRUCT *qos); + +/********************************************************************* + IE Name: Radio Priority + + Description: Specifies the priority level the UE shall use at the + lower layers for transmission of data related to a + PDP context or for mobile originated SMS + transmission. + + Document Reference: 24.301 v10.2.0 Section 9.9.4.13 + 24.008 v10.2.0 Section 10.5.7.2 +*********************************************************************/ +// Defines +#define LIBLTE_MME_RADIO_PRIORITY_LEVEL_1 0x1 +#define LIBLTE_MME_RADIO_PRIORITY_LEVEL_2 0x2 +#define LIBLTE_MME_RADIO_PRIORITY_LEVEL_3 0x3 +#define LIBLTE_MME_RADIO_PRIORITY_LEVEL_4 0x4 +// Enums +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_radio_priority_ie(uint8 radio_prio, + uint8 bit_offset, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_mme_unpack_radio_priority_ie(uint8 **ie_ptr, + uint8 bit_offset, + uint8 *radio_prio); + +/********************************************************************* + IE Name: Request Type + + Description: Indicates whether the UE requests to establish a new + connectivity to a PDN or keep the connection(s) to + which it has connected via non-3GPP access. + + Document Reference: 24.301 v10.2.0 Section 9.9.4.14 + 24.008 v10.2.0 Section 10.5.6.17 +*********************************************************************/ +// Defines +#define LIBLTE_MME_REQUEST_TYPE_INITIAL_REQUEST 0x1 +#define LIBLTE_MME_REQUEST_TYPE_HANDOVER 0x2 +#define LIBLTE_MME_REQUEST_TYPE_UNUSED 0x3 +#define LIBLTE_MME_REQUEST_TYPE_EMERGENCY 0x4 +// Enums +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_request_type_ie(uint8 req_type, + uint8 bit_offset, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_mme_unpack_request_type_ie(uint8 **ie_ptr, + uint8 bit_offset, + uint8 *req_type); + +/********************************************************************* + IE Name: Traffic Flow Aggregate Description + + Description: Specifies the aggregate of one or more packet filters + and their related parameters and operations. + + Document Reference: 24.301 v10.2.0 Section 9.9.4.15 +*********************************************************************/ +// Defines +#define LIBLTE_MME_PACKET_FILTER_LIST_MAX_SIZE 15 +#define LIBLTE_MME_PACKET_FILTER_MAX_SIZE 20 +#define LIBLTE_MME_PARAMETER_LIST_MAX_SIZE 15 +#define LIBLTE_MME_PARAMETER_MAX_SIZE 20 +#define LIBLTE_MME_TFT_PACKET_FILTER_COMPONENT_TYPE_ID_IPV4_REMOTE_ADDRESS_TYPE 0x10 +#define LIBLTE_MME_TFT_PACKET_FILTER_COMPONENT_TYPE_ID_IPV6_REMOTE_ADDRESS_TYPE 0x20 +#define LIBLTE_MME_TFT_PACKET_FILTER_COMPONENT_TYPE_ID_PROTOCOL_ID_NEXT_HEADER_TYPE 0x30 +#define LIBLTE_MME_TFT_PACKET_FILTER_COMPONENT_TYPE_ID_SINGLE_LOCAL_PORT_TYPE 0x40 +#define LIBLTE_MME_TFT_PACKET_FILTER_COMPONENT_TYPE_ID_LOCAL_PORT_RANGE_TYPE 0x41 +#define LIBLTE_MME_TFT_PACKET_FILTER_COMPONENT_TYPE_ID_SINGLE_REMOTE_PORT_TYPE 0x50 +#define LIBLTE_MME_TFT_PACKET_FILTER_COMPONENT_TYPE_ID_REMOTE_PORT_RANGE_TYPE 0x51 +#define LIBLTE_MME_TFT_PACKET_FILTER_COMPONENT_TYPE_ID_SECURITY_PARAMETER_INDEX_TYPE 0x60 +#define LIBLTE_MME_TFT_PACKET_FILTER_COMPONENT_TYPE_ID_TYPE_OF_SERVICE_TRAFFIC_CLASS_TYPE 0x70 +#define LIBLTE_MME_TFT_PACKET_FILTER_COMPONENT_TYPE_ID_FLOW_LABEL_TYPE 0x80 +// Enums +typedef enum{ + LIBLTE_MME_TFT_OPERATION_CODE_SPARE = 0, + LIBLTE_MME_TFT_OPERATION_CODE_CREATE_NEW_TFT, + LIBLTE_MME_TFT_OPERATION_CODE_DELETE_EXISTING_TFT, + LIBLTE_MME_TFT_OPERATION_CODE_ADD_PACKET_FILTERS_TO_EXISTING_TFT, + LIBLTE_MME_TFT_OPERATION_CODE_REPLACE_PACKET_FILTERS_IN_EXISTING_TFT, + LIBLTE_MME_TFT_OPERATION_CODE_DELETE_PACKET_FILTERS_FROM_EXISTING_TFT, + LIBLTE_MME_TFT_OPERATION_CODE_NO_TFT_OPERATION, + LIBLTE_MME_TFT_OPERATION_CODE_RESERVED, + LIBLTE_MME_TFT_OPERATION_CODE_N_ITEMS, +}LIBLTE_MME_TFT_OPERATION_CODE_ENUM; +static const char liblte_mme_tft_operation_code_text[LIBLTE_MME_TFT_OPERATION_CODE_N_ITEMS][100] = {"SPARE", + "Create New TFT", + "Delete Existing TFT", + "Add Packet Filters to Existing TFT", + "Replace Packet Filters in Existing TFT", + "Delete Packet Filters from Existing TFT", + "No TFT Operation", + "RESERVED"}; +typedef enum{ + LIBLTE_MME_TFT_PACKET_FILTER_DIRECTION_PRE_REL_7_TFT_FILTER = 0, + LIBLTE_MME_TFT_PACKET_FILTER_DIRECTION_DOWNLINK_ONLY, + LIBLTE_MME_TFT_PACKET_FILTER_DIRECTION_UPLINK_ONLY, + LIBLTE_MME_TFT_PACKET_FILTER_DIRECTION_BIDIRECTIONAL, + LIBLTE_MME_TFT_PACKET_FILTER_DIRECTION_N_ITEMS, +}LIBLTE_MME_TFT_PACKET_FILTER_DIRECTION_ENUM; +static const char liblte_mme_tft_packet_filter_direction_text[LIBLTE_MME_TFT_PACKET_FILTER_DIRECTION_N_ITEMS][100] = {"Pre Rel-7 TFT Filter", + "Downlink Only", + "Uplink Only", + "Bidirectional"}; +// Structs +typedef struct{ + LIBLTE_MME_TFT_PACKET_FILTER_DIRECTION_ENUM dir; + uint8 id; + uint8 eval_precedence; + uint8 filter[LIBLTE_MME_PACKET_FILTER_MAX_SIZE]; + uint8 filter_size; +}LIBLTE_MME_PACKET_FILTER_STRUCT; +typedef struct{ + uint8 id; + uint8 parameter[LIBLTE_MME_PARAMETER_MAX_SIZE]; + uint8 parameter_size; +}LIBLTE_MME_PARAMETER_STRUCT; +typedef struct{ + LIBLTE_MME_PACKET_FILTER_STRUCT packet_filter_list[LIBLTE_MME_PACKET_FILTER_LIST_MAX_SIZE]; + LIBLTE_MME_PARAMETER_STRUCT parameter_list[LIBLTE_MME_PARAMETER_LIST_MAX_SIZE]; + LIBLTE_MME_TFT_OPERATION_CODE_ENUM tft_op_code; + uint8 packet_filter_list_size; + uint8 parameter_list_size; +}LIBLTE_MME_TRAFFIC_FLOW_TEMPLATE_STRUCT; +typedef LIBLTE_MME_TRAFFIC_FLOW_TEMPLATE_STRUCT LIBLTE_MME_TRAFFIC_FLOW_AGGREGATE_DESCRIPTION_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_traffic_flow_aggregate_description_ie(LIBLTE_MME_TRAFFIC_FLOW_AGGREGATE_DESCRIPTION_STRUCT *tfad, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_mme_unpack_traffic_flow_aggregate_description_ie(uint8 **ie_ptr, + LIBLTE_MME_TRAFFIC_FLOW_AGGREGATE_DESCRIPTION_STRUCT *tfad); + +/********************************************************************* + IE Name: Traffic Flow Template + + Description: Specifies the TFT parameters and operations for a + PDP context. + + Document Reference: 24.301 v10.2.0 Section 9.9.4.16 + 24.008 v10.2.0 Section 10.5.6.12 +*********************************************************************/ +// Defines +// Traffic Flow Template defines defined above +// Enums +// Traffic Flow Template enums defined above +// Structs +// Traffic Flow Template structs defined above +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_traffic_flow_template_ie(LIBLTE_MME_TRAFFIC_FLOW_TEMPLATE_STRUCT *tft, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_mme_unpack_traffic_flow_template_ie(uint8 **ie_ptr, + LIBLTE_MME_TRAFFIC_FLOW_TEMPLATE_STRUCT *tft); + +/********************************************************************* + IE Name: Transaction Identifier + + Description: Represents the corresponding PDP context in A/Gb + mode or Iu mode which is mapped from the EPS bearer + context. + + Document Reference: 24.301 v10.2.0 Section 9.9.4.17 + 24.008 v10.2.0 Section 10.5.6.7 +*********************************************************************/ +// Defines +#define LIBLTE_MME_TI_FLAG_SENT_FROM_ORIGINATOR 0 +#define LIBLTE_MME_TI_FLAG_SENT_TO_ORIGINATOR 1 +#define LIBLTE_MME_TI_VALUE_IS_GIVEN_BY_TIE 0x7 +// Enums +// Structs +typedef struct{ + uint8 ti_flag; + uint8 tio; + uint8 tie; +}LIBLTE_MME_TRANSACTION_IDENTIFIER_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_transaction_identifier_ie(LIBLTE_MME_TRANSACTION_IDENTIFIER_STRUCT *trans_id, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_mme_unpack_transaction_identifier_ie(uint8 **ie_ptr, + LIBLTE_MME_TRANSACTION_IDENTIFIER_STRUCT *trans_id); + +/******************************************************************************* + MESSAGE DECLARATIONS +*******************************************************************************/ + +/********************************************************************* + Message Name: Message Header (Plain NAS Message) + + Description: Message header for plain NAS messages. + + Document Reference: 24.301 v10.2.0 Section 9.1 +*********************************************************************/ +// Defines +#define LIBLTE_MME_PD_EPS_SESSION_MANAGEMENT 0x2 +#define LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT 0x7 +#define LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS 0x0 +#define LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY 0x1 +#define LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED 0x2 +#define LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_WITH_NEW_EPS_SECURITY_CONTEXT 0x3 +#define LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED_WITH_NEW_EPS_SECURITY_CONTEXT 0x4 +#define LIBLTE_MME_SECURITY_HDR_TYPE_SERVICE_REQUEST 0xC +#define LIBLTE_MME_MSG_TYPE_ATTACH_REQUEST 0x41 +#define LIBLTE_MME_MSG_TYPE_ATTACH_ACCEPT 0x42 +#define LIBLTE_MME_MSG_TYPE_ATTACH_COMPLETE 0x43 +#define LIBLTE_MME_MSG_TYPE_ATTACH_REJECT 0x44 +#define LIBLTE_MME_MSG_TYPE_DETACH_REQUEST 0x45 +#define LIBLTE_MME_MSG_TYPE_DETACH_ACCEPT 0x46 +#define LIBLTE_MME_MSG_TYPE_TRACKING_AREA_UPDATE_REQUEST 0x48 +#define LIBLTE_MME_MSG_TYPE_TRACKING_AREA_UPDATE_ACCEPT 0x49 +#define LIBLTE_MME_MSG_TYPE_TRACKING_AREA_UPDATE_COMPLETE 0x4A +#define LIBLTE_MME_MSG_TYPE_TRACKING_AREA_UPDATE_REJECT 0x4B +#define LIBLTE_MME_MSG_TYPE_EXTENDED_SERVICE_REQUEST 0x4C +#define LIBLTE_MME_MSG_TYPE_SERVICE_REJECT 0x4E +#define LIBLTE_MME_MSG_TYPE_GUTI_REALLOCATION_COMMAND 0x50 +#define LIBLTE_MME_MSG_TYPE_GUTI_REALLOCATION_COMPLETE 0x51 +#define LIBLTE_MME_MSG_TYPE_AUTHENTICATION_REQUEST 0x52 +#define LIBLTE_MME_MSG_TYPE_AUTHENTICATION_RESPONSE 0x53 +#define LIBLTE_MME_MSG_TYPE_AUTHENTICATION_REJECT 0x54 +#define LIBLTE_MME_MSG_TYPE_AUTHENTICATION_FAILURE 0x5C +#define LIBLTE_MME_MSG_TYPE_IDENTITY_REQUEST 0x55 +#define LIBLTE_MME_MSG_TYPE_IDENTITY_RESPONSE 0x56 +#define LIBLTE_MME_MSG_TYPE_SECURITY_MODE_COMMAND 0x5D +#define LIBLTE_MME_MSG_TYPE_SECURITY_MODE_COMPLETE 0x5E +#define LIBLTE_MME_MSG_TYPE_SECURITY_MODE_REJECT 0x5F +#define LIBLTE_MME_MSG_TYPE_EMM_STATUS 0x60 +#define LIBLTE_MME_MSG_TYPE_EMM_INFORMATION 0x61 +#define LIBLTE_MME_MSG_TYPE_DOWNLINK_NAS_TRANSPORT 0x62 +#define LIBLTE_MME_MSG_TYPE_UPLINK_NAS_TRANSPORT 0x63 +#define LIBLTE_MME_MSG_TYPE_CS_SERVICE_NOTIFICATION 0x64 +#define LIBLTE_MME_MSG_TYPE_DOWNLINK_GENERIC_NAS_TRANSPORT 0x68 +#define LIBLTE_MME_MSG_TYPE_UPLINK_GENERIC_NAS_TRANSPORT 0x69 +#define LIBLTE_MME_MSG_TYPE_ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST 0xC1 +#define LIBLTE_MME_MSG_TYPE_ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_ACCEPT 0xC2 +#define LIBLTE_MME_MSG_TYPE_ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REJECT 0xC3 +#define LIBLTE_MME_MSG_TYPE_ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REQUEST 0xC5 +#define LIBLTE_MME_MSG_TYPE_ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_ACCEPT 0xC6 +#define LIBLTE_MME_MSG_TYPE_ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REJECT 0xC7 +#define LIBLTE_MME_MSG_TYPE_MODIFY_EPS_BEARER_CONTEXT_REQUEST 0xC9 +#define LIBLTE_MME_MSG_TYPE_MODIFY_EPS_BEARER_CONTEXT_ACCEPT 0xCA +#define LIBLTE_MME_MSG_TYPE_MODIFY_EPS_BEARER_CONTEXT_REJECT 0xCB +#define LIBLTE_MME_MSG_TYPE_DEACTIVATE_EPS_BEARER_CONTEXT_REQUEST 0xCD +#define LIBLTE_MME_MSG_TYPE_DEACTIVATE_EPS_BEARER_CONTEXT_ACCEPT 0xCE +#define LIBLTE_MME_MSG_TYPE_PDN_CONNECTIVITY_REQUEST 0xD0 +#define LIBLTE_MME_MSG_TYPE_PDN_CONNECTIVITY_REJECT 0xD1 +#define LIBLTE_MME_MSG_TYPE_PDN_DISCONNECT_REQUEST 0xD2 +#define LIBLTE_MME_MSG_TYPE_PDN_DISCONNECT_REJECT 0xD3 +#define LIBLTE_MME_MSG_TYPE_BEARER_RESOURCE_ALLOCATION_REQUEST 0xD4 +#define LIBLTE_MME_MSG_TYPE_BEARER_RESOURCE_ALLOCATION_REJECT 0xD5 +#define LIBLTE_MME_MSG_TYPE_BEARER_RESOURCE_MODIFICATION_REQUEST 0xD6 +#define LIBLTE_MME_MSG_TYPE_BEARER_RESOURCE_MODIFICATION_REJECT 0xD7 +#define LIBLTE_MME_MSG_TYPE_ESM_INFORMATION_REQUEST 0xD9 +#define LIBLTE_MME_MSG_TYPE_ESM_INFORMATION_RESPONSE 0xDA +#define LIBLTE_MME_MSG_TYPE_NOTIFICATION 0xDB +#define LIBLTE_MME_MSG_TYPE_ESM_STATUS 0xE8 +// Enums +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_mme_parse_msg_header(LIBLTE_BYTE_MSG_STRUCT *msg, + uint8 *pd, + uint8 *msg_type); +LIBLTE_ERROR_ENUM liblte_mme_pack_security_protected_nas_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + uint8 sec_hdr_type, + uint32 count, + LIBLTE_BYTE_MSG_STRUCT *sec_msg); + +/********************************************************************* + Message Name: Attach Accept + + Description: Sent by the network to the UE to indicate that the + corresponding attach request has been accepted. + + Document Reference: 24.301 v10.2.0 Section 8.2.1 +*********************************************************************/ +// Defines +#define LIBLTE_MME_GUTI_IEI 0x50 +#define LIBLTE_MME_LOCATION_AREA_IDENTIFICATION_IEI 0x13 +#define LIBLTE_MME_MS_IDENTITY_IEI 0x23 +#define LIBLTE_MME_EMM_CAUSE_IEI 0x53 +#define LIBLTE_MME_T3402_VALUE_IEI 0x17 +#define LIBLTE_MME_T3423_VALUE_IEI 0x59 +#define LIBLTE_MME_EQUIVALENT_PLMNS_IEI 0x4A +#define LIBLTE_MME_EMERGENCY_NUMBER_LIST_IEI 0x34 +#define LIBLTE_MME_EPS_NETWORK_FEATURE_SUPPORT_IEI 0x64 +#define LIBLTE_MME_ADDITIONAL_UPDATE_RESULT_IEI 0xF +#define LIBLTE_MME_T3412_EXTENDED_VALUE_IEI 0x5E +// Enums +// Structs +typedef struct{ + LIBLTE_MME_GPRS_TIMER_STRUCT t3412; + LIBLTE_MME_TRACKING_AREA_IDENTITY_LIST_STRUCT tai_list; + LIBLTE_BYTE_MSG_STRUCT esm_msg; + LIBLTE_MME_EPS_MOBILE_ID_STRUCT guti; + LIBLTE_MME_LOCATION_AREA_ID_STRUCT lai; + LIBLTE_MME_MOBILE_ID_STRUCT ms_id; + LIBLTE_MME_GPRS_TIMER_STRUCT t3402; + LIBLTE_MME_GPRS_TIMER_STRUCT t3423; + LIBLTE_MME_PLMN_LIST_STRUCT equivalent_plmns; + LIBLTE_MME_EMERGENCY_NUMBER_LIST_STRUCT emerg_num_list; + LIBLTE_MME_EPS_NETWORK_FEATURE_SUPPORT_STRUCT eps_network_feature_support; + LIBLTE_MME_GPRS_TIMER_3_STRUCT t3412_ext; + LIBLTE_MME_ADDITIONAL_UPDATE_RESULT_ENUM additional_update_result; + uint8 eps_attach_result; + uint8 emm_cause; + bool guti_present; + bool lai_present; + bool ms_id_present; + bool emm_cause_present; + bool t3402_present; + bool t3423_present; + bool equivalent_plmns_present; + bool emerg_num_list_present; + bool eps_network_feature_support_present; + bool additional_update_result_present; + bool t3412_ext_present; +}LIBLTE_MME_ATTACH_ACCEPT_MSG_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_attach_accept_msg(LIBLTE_MME_ATTACH_ACCEPT_MSG_STRUCT *attach_accept, + uint8 sec_hdr_type, + uint32 count, + LIBLTE_BYTE_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_mme_unpack_attach_accept_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_ATTACH_ACCEPT_MSG_STRUCT *attach_accept); + +/********************************************************************* + Message Name: Attach Complete + + Description: Sent by the UE to the network in response to an + ATTACH ACCEPT message. + + Document Reference: 24.301 v10.2.0 Section 8.2.2 +*********************************************************************/ +// Defines +// Enums +// Structs +typedef struct{ + LIBLTE_BYTE_MSG_STRUCT esm_msg; +}LIBLTE_MME_ATTACH_COMPLETE_MSG_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_attach_complete_msg(LIBLTE_MME_ATTACH_COMPLETE_MSG_STRUCT *attach_comp, + uint8 sec_hdr_type, + uint32 count, + LIBLTE_BYTE_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_mme_unpack_attach_complete_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_ATTACH_COMPLETE_MSG_STRUCT *attach_comp); + +/********************************************************************* + Message Name: Attach Reject + + Description: Sent by the network to the UE to indicate that the + corresponding attach request has been rejected. + + Document Reference: 24.301 v10.2.0 Section 8.2.3 +*********************************************************************/ +// Defines +#define LIBLTE_MME_ESM_MSG_CONTAINER_IEI 0x78 +#define LIBLTE_MME_T3446_VALUE_IEI 0x5F +// Enums +// Structs +typedef struct{ + LIBLTE_BYTE_MSG_STRUCT esm_msg; + uint8 emm_cause; + uint8 t3446_value; + bool esm_msg_present; + bool t3446_value_present; +}LIBLTE_MME_ATTACH_REJECT_MSG_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_attach_reject_msg(LIBLTE_MME_ATTACH_REJECT_MSG_STRUCT *attach_rej, + LIBLTE_BYTE_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_mme_unpack_attach_reject_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_ATTACH_REJECT_MSG_STRUCT *attach_rej); + +/********************************************************************* + Message Name: Attach Request + + Description: Sent by the UE to the network to perform an attach + procedure. + + Document Reference: 24.301 v10.2.0 Section 8.2.4 +*********************************************************************/ +// Defines +#define LIBLTE_MME_P_TMSI_SIGNATURE_IEI 0x19 +#define LIBLTE_MME_ADDITIONAL_GUTI_IEI 0x50 +#define LIBLTE_MME_LAST_VISITED_REGISTERED_TAI_IEI 0x52 +#define LIBLTE_MME_DRX_PARAMETER_IEI 0x5C +#define LIBLTE_MME_MS_NETWORK_CAPABILITY_IEI 0x31 +#define LIBLTE_MME_TMSI_STATUS_IEI 0x9 +#define LIBLTE_MME_MS_CLASSMARK_2_IEI 0x11 +#define LIBLTE_MME_MS_CLASSMARK_3_IEI 0x20 +#define LIBLTE_MME_SUPPORTED_CODEC_LIST_IEI 0x40 +#define LIBLTE_MME_ADDITIONAL_UPDATE_TYPE_IEI 0xF +#define LIBLTE_MME_VOICE_DOMAIN_PREF_AND_UE_USAGE_SETTING_IEI 0x5D +#define LIBLTE_MME_ATTACH_REQUEST_DEVICE_PROPERTIES_IEI 0xD +#define LIBLTE_MME_GUTI_TYPE_IEI 0xE +// Enums +// Structs +typedef struct{ + LIBLTE_MME_NAS_KEY_SET_ID_STRUCT nas_ksi; + LIBLTE_MME_EPS_MOBILE_ID_STRUCT eps_mobile_id; + LIBLTE_MME_UE_NETWORK_CAPABILITY_STRUCT ue_network_cap; + LIBLTE_BYTE_MSG_STRUCT esm_msg; + LIBLTE_MME_EPS_MOBILE_ID_STRUCT additional_guti; + LIBLTE_MME_TRACKING_AREA_ID_STRUCT last_visited_registered_tai; + LIBLTE_MME_DRX_PARAMETER_STRUCT drx_param; + LIBLTE_MME_MS_NETWORK_CAPABILITY_STRUCT ms_network_cap; + LIBLTE_MME_LOCATION_AREA_ID_STRUCT old_lai; + LIBLTE_MME_MOBILE_STATION_CLASSMARK_2_STRUCT ms_cm2; + LIBLTE_MME_MOBILE_STATION_CLASSMARK_3_STRUCT ms_cm3; + LIBLTE_MME_SUPPORTED_CODEC_LIST_STRUCT supported_codecs; + LIBLTE_MME_VOICE_DOMAIN_PREF_AND_UE_USAGE_SETTING_STRUCT voice_domain_pref_and_ue_usage_setting; + LIBLTE_MME_TMSI_STATUS_ENUM tmsi_status; + LIBLTE_MME_ADDITIONAL_UPDATE_TYPE_ENUM additional_update_type; + LIBLTE_MME_DEVICE_PROPERTIES_ENUM device_properties; + LIBLTE_MME_GUTI_TYPE_ENUM old_guti_type; + uint32 old_p_tmsi_signature; + uint8 eps_attach_type; + bool old_p_tmsi_signature_present; + bool additional_guti_present; + bool last_visited_registered_tai_present; + bool drx_param_present; + bool ms_network_cap_present; + bool old_lai_present; + bool tmsi_status_present; + bool ms_cm2_present; + bool ms_cm3_present; + bool supported_codecs_present; + bool additional_update_type_present; + bool voice_domain_pref_and_ue_usage_setting_present; + bool device_properties_present; + bool old_guti_type_present; +}LIBLTE_MME_ATTACH_REQUEST_MSG_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_attach_request_msg(LIBLTE_MME_ATTACH_REQUEST_MSG_STRUCT *attach_req, + LIBLTE_BYTE_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_mme_unpack_attach_request_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_ATTACH_REQUEST_MSG_STRUCT *attach_req); + +/********************************************************************* + Message Name: Authentication Failure + + Description: Sent by the UE to the network to indicate that + authentication of the network has failed. + + Document Reference: 24.301 v10.2.0 Section 8.2.5 +*********************************************************************/ +// Defines +#define LIBLTE_MME_AUTHENTICATION_FAILURE_PARAMETER_IEI 0x30 +// Enums +// Structs +typedef struct{ + uint8 emm_cause; + uint8 auth_fail_param[16]; + bool auth_fail_param_present; +}LIBLTE_MME_AUTHENTICATION_FAILURE_MSG_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_authentication_failure_msg(LIBLTE_MME_AUTHENTICATION_FAILURE_MSG_STRUCT *auth_fail, + LIBLTE_BYTE_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_mme_unpack_authentication_failure_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_AUTHENTICATION_FAILURE_MSG_STRUCT *auth_fail); + +/********************************************************************* + Message Name: Authentication Reject + + Description: Sent by the network to the UE to indicate that the + authentication procedure has failed and that the UE + shall abort all activities. + + Document Reference: 24.301 v10.2.0 Section 8.2.6 +*********************************************************************/ +// Defines +// Enums +// Structs +typedef struct{ +}LIBLTE_MME_AUTHENTICATION_REJECT_MSG_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_authentication_reject_msg(LIBLTE_MME_AUTHENTICATION_REJECT_MSG_STRUCT *auth_reject, + LIBLTE_BYTE_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_mme_unpack_authentication_reject_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_AUTHENTICATION_REJECT_MSG_STRUCT *auth_reject); + +/********************************************************************* + Message Name: Authentication Request + + Description: Sent by the network to the UE to initiate + authentication of the UE identity. + + Document Reference: 24.301 v10.2.0 Section 8.2.7 +*********************************************************************/ +// Defines +// Enums +// Structs +typedef struct{ + LIBLTE_MME_NAS_KEY_SET_ID_STRUCT nas_ksi; + uint8 autn[16]; + uint8 rand[16]; +}LIBLTE_MME_AUTHENTICATION_REQUEST_MSG_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_authentication_request_msg(LIBLTE_MME_AUTHENTICATION_REQUEST_MSG_STRUCT *auth_req, + LIBLTE_BYTE_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_mme_unpack_authentication_request_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_AUTHENTICATION_REQUEST_MSG_STRUCT *auth_req); + +/********************************************************************* + Message Name: Authentication Response + + Description: Sent by the UE to the network to deliver a calculated + authentication response to the network. + + Document Reference: 24.301 v10.2.0 Section 8.2.8 +*********************************************************************/ +// Defines +// Enums +// Structs +typedef struct{ + uint8 res[16]; +}LIBLTE_MME_AUTHENTICATION_RESPONSE_MSG_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_authentication_response_msg(LIBLTE_MME_AUTHENTICATION_RESPONSE_MSG_STRUCT *auth_resp, + LIBLTE_BYTE_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_mme_unpack_authentication_response_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_AUTHENTICATION_RESPONSE_MSG_STRUCT *auth_resp); + +/********************************************************************* + Message Name: CS Service Notification + + Description: Sent by the network when a paging request with CS + call indicator was received via SGs for a UE, and a + NAS signalling connection is already established for + the UE. + + Document Reference: 24.301 v10.2.0 Section 8.2.9 +*********************************************************************/ +// Defines +// Enums +// Structs +// Functions +// FIXME + +/********************************************************************* + Message Name: Detach Accept + + Description: Sent by the network to indicate that the detach + procedure has been completed. + + Document Reference: 24.301 v10.2.0 Section 8.2.10 +*********************************************************************/ +// Defines +// Enums +// Structs +typedef struct{ +}LIBLTE_MME_DETACH_ACCEPT_MSG_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_detach_accept_msg(LIBLTE_MME_DETACH_ACCEPT_MSG_STRUCT *detach_accept, + uint8 sec_hdr_type, + uint32 count, + LIBLTE_BYTE_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_mme_unpack_detach_accept_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_DETACH_ACCEPT_MSG_STRUCT *detach_accept); + +/********************************************************************* + Message Name: Detach Request + + Description: Sent by the UE to request the release of an EMM + context. + + Document Reference: 24.301 v10.2.0 Section 8.2.11 +*********************************************************************/ +// Defines +// Enums +// Structs +typedef struct{ + LIBLTE_MME_DETACH_TYPE_STRUCT detach_type; + LIBLTE_MME_NAS_KEY_SET_ID_STRUCT nas_ksi; + LIBLTE_MME_EPS_MOBILE_ID_STRUCT eps_mobile_id; +}LIBLTE_MME_DETACH_REQUEST_MSG_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_detach_request_msg(LIBLTE_MME_DETACH_REQUEST_MSG_STRUCT *detach_req, + uint8 sec_hdr_type, + uint32 count, + LIBLTE_BYTE_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_mme_unpack_detach_request_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_DETACH_REQUEST_MSG_STRUCT *detach_req); + +/********************************************************************* + Message Name: Downlink NAS Transport + + Description: Sent by the network to the UE in order to carry an + SMS message in encapsulated format. + + Document Reference: 24.301 v10.2.0 Section 8.2.12 +*********************************************************************/ +// Defines +// Enums +// Structs +typedef struct{ + LIBLTE_BYTE_MSG_STRUCT nas_msg; +}LIBLTE_MME_DOWNLINK_NAS_TRANSPORT_MSG_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_downlink_nas_transport_msg(LIBLTE_MME_DOWNLINK_NAS_TRANSPORT_MSG_STRUCT *dl_nas_transport, + uint8 sec_hdr_type, + uint32 count, + LIBLTE_BYTE_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_mme_unpack_downlink_nas_transport_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_DOWNLINK_NAS_TRANSPORT_MSG_STRUCT *dl_nas_transport); + +/********************************************************************* + Message Name: EMM Information + + Description: Sent by the network at any time during EMM context is + established to send certain information to the UE. + + Document Reference: 24.301 v10.2.0 Section 8.2.13 +*********************************************************************/ +// Defines +#define LIBLTE_MME_FULL_NAME_FOR_NETWORK_IEI 0x43 +#define LIBLTE_MME_SHORT_NAME_FOR_NETWORK_IEI 0x45 +#define LIBLTE_MME_LOCAL_TIME_ZONE_IEI 0x46 +#define LIBLTE_MME_UNIVERSAL_TIME_AND_LOCAL_TIME_ZONE_IEI 0x47 +#define LIBLTE_MME_NETWORK_DAYLIGHT_SAVING_TIME_IEI 0x49 +// Enums +// Structs +typedef struct{ + LIBLTE_MME_NETWORK_NAME_STRUCT full_net_name; + LIBLTE_MME_NETWORK_NAME_STRUCT short_net_name; + LIBLTE_MME_TIME_ZONE_AND_TIME_STRUCT utc_and_local_time_zone; + LIBLTE_MME_DAYLIGHT_SAVING_TIME_ENUM net_dst; + uint8 local_time_zone; + bool full_net_name_present; + bool short_net_name_present; + bool local_time_zone_present; + bool utc_and_local_time_zone_present; + bool net_dst_present; +}LIBLTE_MME_EMM_INFORMATION_MSG_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_emm_information_msg(LIBLTE_MME_EMM_INFORMATION_MSG_STRUCT *emm_info, + uint8 sec_hdr_type, + uint32 count, + LIBLTE_BYTE_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_mme_unpack_emm_information_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_EMM_INFORMATION_MSG_STRUCT *emm_info); + +/********************************************************************* + Message Name: EMM Status + + Description: Sent by the UE or by the network at any time to + report certain error conditions. + + Document Reference: 24.301 v10.2.0 Section 8.2.14 +*********************************************************************/ +// Defines +// Enums +// Structs +typedef struct{ + uint8 emm_cause; +}LIBLTE_MME_EMM_STATUS_MSG_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_emm_status_msg(LIBLTE_MME_EMM_STATUS_MSG_STRUCT *emm_status, + uint8 sec_hdr_type, + uint32 count, + LIBLTE_BYTE_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_mme_unpack_emm_status_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_EMM_STATUS_MSG_STRUCT *emm_status); + +/********************************************************************* + Message Name: Extended Service Request + + Description: Sent by the UE to the network to initiate a CS + fallback or 1xCS fallback call or respond to a mobile + terminated CS fallback or 1xCS fallback request from + the network or to request the establishment of a NAS + signalling connection and of the radio and S1 bearers + for packet services, if the UE needs to provide + additional information that cannot be provided via a + SERVICE REQUEST message. + + Document Reference: 24.301 v10.2.0 Section 8.2.15 +*********************************************************************/ +// Defines +#define LIBLTE_MME_CSFB_RESPONSE_IEI 0xB +#define LIBLTE_MME_EPS_BEARER_CONTEXT_STATUS_IEI 0x57 +#define LIBLTE_MME_EXTENDED_SERVICE_REQUEST_DEVICE_PROPERTIES_IEI 0xD +// Enums +// Structs +typedef struct{ + LIBLTE_MME_NAS_KEY_SET_ID_STRUCT nas_ksi; + LIBLTE_MME_MOBILE_ID_STRUCT m_tmsi; + LIBLTE_MME_EPS_BEARER_CONTEXT_STATUS_STRUCT eps_bearer_context_status; + LIBLTE_MME_DEVICE_PROPERTIES_ENUM device_props; + uint8 service_type; + uint8 csfb_resp; + bool csfb_resp_present; + bool eps_bearer_context_status_present; + bool device_props_present; +}LIBLTE_MME_EXTENDED_SERVICE_REQUEST_MSG_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_extended_service_request_msg(LIBLTE_MME_EXTENDED_SERVICE_REQUEST_MSG_STRUCT *ext_service_req, + uint8 sec_hdr_type, + uint32 count, + LIBLTE_BYTE_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_mme_unpack_extended_service_request_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_EXTENDED_SERVICE_REQUEST_MSG_STRUCT *ext_service_req); + +/********************************************************************* + Message Name: GUTI Reallocation Command + + Description: Sent by the network to the UE to reallocate a GUTI + and optionally provide a new TAI list. + + Document Reference: 24.301 v10.2.0 Section 8.2.16 +*********************************************************************/ +// Defines +#define LIBLTE_MME_TAI_LIST_IEI 0x54 +// Enums +// Structs +typedef struct{ + LIBLTE_MME_EPS_MOBILE_ID_STRUCT guti; + LIBLTE_MME_TRACKING_AREA_IDENTITY_LIST_STRUCT tai_list; + bool tai_list_present; +}LIBLTE_MME_GUTI_REALLOCATION_COMMAND_MSG_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_guti_reallocation_command_msg(LIBLTE_MME_GUTI_REALLOCATION_COMMAND_MSG_STRUCT *guti_realloc_cmd, + uint8 sec_hdr_type, + uint32 count, + LIBLTE_BYTE_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_mme_unpack_guti_reallocation_command_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_GUTI_REALLOCATION_COMMAND_MSG_STRUCT *guti_realloc_cmd); + +/********************************************************************* + Message Name: GUTI Reallocation Complete + + Description: Sent by the UE to the network to indicate that + reallocation of a GUTI has taken place. + + Document Reference: 24.301 v10.2.0 Section 8.2.17 +*********************************************************************/ +// Defines +// Enums +// Structs +typedef struct{ +}LIBLTE_MME_GUTI_REALLOCATION_COMPLETE_MSG_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_guti_reallocation_complete_msg(LIBLTE_MME_GUTI_REALLOCATION_COMPLETE_MSG_STRUCT *guti_realloc_complete, + uint8 sec_hdr_type, + uint32 count, + LIBLTE_BYTE_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_mme_unpack_guti_reallocation_complete_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_GUTI_REALLOCATION_COMPLETE_MSG_STRUCT *guti_realloc_complete); + +/********************************************************************* + Message Name: Identity Request + + Description: Sent by the network to the UE to request the UE to + provide the specified identity. + + Document Reference: 24.301 v10.2.0 Section 8.2.18 +*********************************************************************/ +// Defines +// Enums +// Structs +typedef struct{ + uint8 id_type; +}LIBLTE_MME_ID_REQUEST_MSG_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_identity_request_msg(LIBLTE_MME_ID_REQUEST_MSG_STRUCT *id_req, + LIBLTE_BYTE_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_mme_unpack_identity_request_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_ID_REQUEST_MSG_STRUCT *id_req); + +/********************************************************************* + Message Name: Identity Response + + Description: Sent by the UE to the network in response to an + IDENTITY REQUEST message and provides the requested + identity. + + Document Reference: 24.301 v10.2.0 Section 8.2.19 +*********************************************************************/ +// Defines +// Enums +// Structs +typedef struct{ + LIBLTE_MME_MOBILE_ID_STRUCT mobile_id; +}LIBLTE_MME_ID_RESPONSE_MSG_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_identity_response_msg(LIBLTE_MME_ID_RESPONSE_MSG_STRUCT *id_resp, + 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); + +/********************************************************************* + Message Name: Security Mode Command + + Description: Sent by the network to the UE to establish NAS + signalling security. + + Document Reference: 24.301 v10.2.0 Section 8.2.20 +*********************************************************************/ +// Defines +#define LIBLTE_MME_IMEISV_REQUEST_IEI 0xC +#define LIBLTE_MME_REPLAYED_NONCE_UE_IEI 0x55 +#define LIBLTE_MME_NONCE_MME_IEI 0x56 +// Enums +// Structs +typedef struct{ + LIBLTE_MME_NAS_SECURITY_ALGORITHMS_STRUCT selected_nas_sec_algs; + LIBLTE_MME_NAS_KEY_SET_ID_STRUCT nas_ksi; + LIBLTE_MME_UE_SECURITY_CAPABILITIES_STRUCT ue_security_cap; + LIBLTE_MME_IMEISV_REQUEST_ENUM imeisv_req; + uint32 nonce_ue; + uint32 nonce_mme; + bool imeisv_req_present; + bool nonce_ue_present; + bool nonce_mme_present; +}LIBLTE_MME_SECURITY_MODE_COMMAND_MSG_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_security_mode_command_msg(LIBLTE_MME_SECURITY_MODE_COMMAND_MSG_STRUCT *sec_mode_cmd, + uint8 sec_hdr_type, + uint32 count, + LIBLTE_BYTE_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_mme_unpack_security_mode_command_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_SECURITY_MODE_COMMAND_MSG_STRUCT *sec_mode_cmd); + +/********************************************************************* + Message Name: Security Mode Complete + + Description: Sent by the UE to the network in response to a + SECURITY MODE COMMAND message. + + Document Reference: 24.301 v10.2.0 Section 8.2.21 +*********************************************************************/ +// Defines +#define LIBLTE_MME_IMEISV_IEI 0x23 +// Enums +// Structs +typedef struct{ + LIBLTE_MME_MOBILE_ID_STRUCT imeisv; + bool imeisv_present; +}LIBLTE_MME_SECURITY_MODE_COMPLETE_MSG_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_security_mode_complete_msg(LIBLTE_MME_SECURITY_MODE_COMPLETE_MSG_STRUCT *sec_mode_comp, + uint8 sec_hdr_type, + uint32 count, + LIBLTE_BYTE_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_mme_unpack_security_mode_complete_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_SECURITY_MODE_COMPLETE_MSG_STRUCT *sec_mode_comp); + +/********************************************************************* + Message Name: Security Mode Reject + + Description: Sent by the UE to the network to indicate that the + corresponding security mode command has been + rejected. + + Document Reference: 24.301 v10.2.0 Section 8.2.22 +*********************************************************************/ +// Defines +// Enums +// Structs +typedef struct{ + uint8 emm_cause; +}LIBLTE_MME_SECURITY_MODE_REJECT_MSG_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_security_mode_reject_msg(LIBLTE_MME_SECURITY_MODE_REJECT_MSG_STRUCT *sec_mode_rej, + LIBLTE_BYTE_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_mme_unpack_security_mode_reject_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_SECURITY_MODE_REJECT_MSG_STRUCT *sec_mode_rej); + +/********************************************************************* + Message Name: Service Reject + + Description: Sent by the network to the UE in order to reject the + service request procedure. + + Document Reference: 24.301 v10.2.0 Section 8.2.24 +*********************************************************************/ +// Defines +#define LIBLTE_MME_T3442_VALUE_IEI 0x5B +// Enums +// Structs +typedef struct{ + LIBLTE_MME_GPRS_TIMER_STRUCT t3442; + uint8 emm_cause; + uint8 t3446; + bool t3442_present; + bool t3446_present; +}LIBLTE_MME_SERVICE_REJECT_MSG_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_service_reject_msg(LIBLTE_MME_SERVICE_REJECT_MSG_STRUCT *service_rej, + uint8 sec_hdr_type, + uint32 count, + LIBLTE_BYTE_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_mme_unpack_service_reject_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_SERVICE_REJECT_MSG_STRUCT *service_rej); + +/********************************************************************* + Message Name: Service Request + + Description: Sent by the UE to the network to request the + establishment of a NAS signalling connection and of + the radio and S1 bearers. + + Document Reference: 24.301 v10.2.0 Section 8.2.25 +*********************************************************************/ +// Defines +// Enums +// Structs +typedef struct{ + LIBLTE_MME_KSI_AND_SEQUENCE_NUMBER_STRUCT ksi_and_seq_num; + uint16 short_mac; +}LIBLTE_MME_SERVICE_REQUEST_MSG_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_service_request_msg(LIBLTE_MME_SERVICE_REQUEST_MSG_STRUCT *service_req, + LIBLTE_BYTE_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_mme_unpack_service_request_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_SERVICE_REQUEST_MSG_STRUCT *service_req); + +/********************************************************************* + Message Name: Tracking Area Update Accept + + Description: Sent by the network to the UE to provide the UE with + EPS mobility management related data in response to + a tracking area update request message. + + Document Reference: 24.301 v10.2.0 Section 8.2.26 +*********************************************************************/ +// Defines +#define LIBLTE_MME_T3412_VALUE_IEI 0x5A +// Enums +// Structs +typedef struct{ + LIBLTE_MME_GPRS_TIMER_STRUCT t3412; + LIBLTE_MME_EPS_MOBILE_ID_STRUCT guti; + LIBLTE_MME_TRACKING_AREA_IDENTITY_LIST_STRUCT tai_list; + LIBLTE_MME_EPS_BEARER_CONTEXT_STATUS_STRUCT eps_bearer_context_status; + LIBLTE_MME_LOCATION_AREA_ID_STRUCT lai; + LIBLTE_MME_MOBILE_ID_STRUCT ms_id; + LIBLTE_MME_GPRS_TIMER_STRUCT t3402; + LIBLTE_MME_GPRS_TIMER_STRUCT t3423; + LIBLTE_MME_PLMN_LIST_STRUCT equivalent_plmns; + LIBLTE_MME_EMERGENCY_NUMBER_LIST_STRUCT emerg_num_list; + LIBLTE_MME_EPS_NETWORK_FEATURE_SUPPORT_STRUCT eps_network_feature_support; + LIBLTE_MME_GPRS_TIMER_3_STRUCT t3412_ext; + LIBLTE_MME_ADDITIONAL_UPDATE_RESULT_ENUM additional_update_result; + uint8 eps_update_result; + uint8 emm_cause; + bool t3412_present; + bool guti_present; + bool tai_list_present; + bool eps_bearer_context_status_present; + bool lai_present; + bool ms_id_present; + bool emm_cause_present; + bool t3402_present; + bool t3423_present; + bool equivalent_plmns_present; + bool emerg_num_list_present; + bool eps_network_feature_support_present; + bool additional_update_result_present; + bool t3412_ext_present; +}LIBLTE_MME_TRACKING_AREA_UPDATE_ACCEPT_MSG_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_tracking_area_update_accept_msg(LIBLTE_MME_TRACKING_AREA_UPDATE_ACCEPT_MSG_STRUCT *ta_update_accept, + uint8 sec_hdr_type, + uint32 count, + LIBLTE_BYTE_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_mme_unpack_tracking_area_update_accept_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_TRACKING_AREA_UPDATE_ACCEPT_MSG_STRUCT *ta_update_accept); + +/********************************************************************* + Message Name: Tracking Area Update Complete + + Description: Sent by the UE to the network in response to a + tracking area update accept message if a GUTI has + been changed or a new TMSI has been assigned. + + Document Reference: 24.301 v10.2.0 Section 8.2.27 +*********************************************************************/ +// Defines +// Enums +// Structs +typedef struct{ +}LIBLTE_MME_TRACKING_AREA_UPDATE_COMPLETE_MSG_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_tracking_area_update_complete_msg(LIBLTE_MME_TRACKING_AREA_UPDATE_COMPLETE_MSG_STRUCT *ta_update_complete, + uint8 sec_hdr_type, + uint32 count, + LIBLTE_BYTE_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_mme_unpack_tracking_area_update_complete_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_TRACKING_AREA_UPDATE_COMPLETE_MSG_STRUCT *ta_update_complete); + +/********************************************************************* + Message Name: Tracking Area Update Reject + + Description: Sent by the network to the UE in order to reject the + tracking area updating procedure. + + Document Reference: 24.301 v10.2.0 Section 8.2.28 +*********************************************************************/ +// Defines +// Enums +// Structs +typedef struct{ + uint8 emm_cause; + uint8 t3446; + bool t3446_present; +}LIBLTE_MME_TRACKING_AREA_UPDATE_REJECT_MSG_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_tracking_area_update_reject_msg(LIBLTE_MME_TRACKING_AREA_UPDATE_REJECT_MSG_STRUCT *ta_update_rej, + uint8 sec_hdr_type, + uint32 count, + LIBLTE_BYTE_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_mme_unpack_tracking_area_update_reject_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_TRACKING_AREA_UPDATE_REJECT_MSG_STRUCT *ta_update_rej); + +/********************************************************************* + Message Name: Tracking Area Update Request + + Description: Sent by the UE to the network to initiate a tracking + area updating procedure. + + Document Reference: 24.301 v10.2.0 Section 8.2.29 +*********************************************************************/ +// Defines +// Enums +// Structs +// Functions +// FIXME + +/********************************************************************* + Message Name: Uplink NAS Transport + + Description: Sent by the UE to the network in order to carry an + SMS message in encapsulated format. + + Document Reference: 24.301 v10.2.0 Section 8.2.30 +*********************************************************************/ +// Defines +// Enums +// Structs +typedef struct{ + LIBLTE_BYTE_MSG_STRUCT nas_msg; +}LIBLTE_MME_UPLINK_NAS_TRANSPORT_MSG_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_uplink_nas_transport_msg(LIBLTE_MME_UPLINK_NAS_TRANSPORT_MSG_STRUCT *ul_nas_transport, + uint8 sec_hdr_type, + uint32 count, + LIBLTE_BYTE_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_mme_unpack_uplink_nas_transport_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_UPLINK_NAS_TRANSPORT_MSG_STRUCT *ul_nas_transport); + +/********************************************************************* + Message Name: Downlink Generic NAS Transport + + Description: Sent by the network to the UE in order to carry an + application message in encapsulated format. + + Document Reference: 24.301 v10.2.0 Section 8.2.31 +*********************************************************************/ +// Defines +// Enums +// Structs +typedef struct{ + LIBLTE_BYTE_MSG_STRUCT generic_msg_cont; + LIBLTE_MME_ADDITIONAL_INFORMATION_STRUCT add_info; + uint8 generic_msg_cont_type; + bool add_info_present; +}LIBLTE_MME_DOWNLINK_GENERIC_NAS_TRANSPORT_MSG_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_downlink_generic_nas_transport_msg(LIBLTE_MME_DOWNLINK_GENERIC_NAS_TRANSPORT_MSG_STRUCT *dl_generic_nas_transport, + uint8 sec_hdr_type, + uint32 count, + LIBLTE_BYTE_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_mme_unpack_downlink_generic_nas_transport_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_DOWNLINK_GENERIC_NAS_TRANSPORT_MSG_STRUCT *dl_generic_nas_transport); + +/********************************************************************* + Message Name: Uplink Generic NAS Transport + + Description: Sent by the UE to the network in order to carry an + application protocol message in encapsulated format. + + Document Reference: 24.301 v10.2.0 Section 8.2.32 +*********************************************************************/ +// Defines +// Enums +// Structs +typedef struct{ + LIBLTE_BYTE_MSG_STRUCT generic_msg_cont; + LIBLTE_MME_ADDITIONAL_INFORMATION_STRUCT add_info; + uint8 generic_msg_cont_type; + bool add_info_present; +}LIBLTE_MME_UPLINK_GENERIC_NAS_TRANSPORT_MSG_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_uplink_generic_nas_transport_msg(LIBLTE_MME_UPLINK_GENERIC_NAS_TRANSPORT_MSG_STRUCT *ul_generic_nas_transport, + uint8 sec_hdr_type, + uint32 count, + LIBLTE_BYTE_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_mme_unpack_uplink_generic_nas_transport_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_UPLINK_GENERIC_NAS_TRANSPORT_MSG_STRUCT *ul_generic_nas_transport); + +/********************************************************************* + Message Name: Activate Dedicated EPS Bearer Context Accept + + Description: Sent by the UE to the network to acknowledge + activation of a dedicated EPS bearer context + associated with the same PDN address(es) and APN as + an already active EPS bearer context. + + Document Reference: 24.301 v10.2.0 Section 8.3.1 +*********************************************************************/ +// Defines +#define LIBLTE_MME_PROTOCOL_CONFIGURATION_OPTIONS_IEI 0x27 +// Enums +// Structs +typedef struct{ + LIBLTE_MME_PROTOCOL_CONFIG_OPTIONS_STRUCT protocol_cnfg_opts; + uint8 eps_bearer_id; + uint8 proc_transaction_id; + bool protocol_cnfg_opts_present; +}LIBLTE_MME_ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_ACCEPT_MSG_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_activate_dedicated_eps_bearer_context_accept_msg(LIBLTE_MME_ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_ACCEPT_MSG_STRUCT *act_ded_eps_bearer_context_accept, + LIBLTE_BYTE_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_mme_unpack_activate_dedicated_eps_bearer_context_accept_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_ACCEPT_MSG_STRUCT *act_ded_eps_bearer_context_accept); + +/********************************************************************* + Message Name: Activate Dedicated EPS Bearer Context Reject + + Description: Sent by the UE to the network to reject activation + of a dedicated EPS bearer context. + + Document Reference: 24.301 v10.2.0 Section 8.3.2 +*********************************************************************/ +// Defines +// Enums +// Structs +typedef struct{ + LIBLTE_MME_PROTOCOL_CONFIG_OPTIONS_STRUCT protocol_cnfg_opts; + uint8 eps_bearer_id; + uint8 proc_transaction_id; + uint8 esm_cause; + bool protocol_cnfg_opts_present; +}LIBLTE_MME_ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REJECT_MSG_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_activate_dedicated_eps_bearer_context_reject_msg(LIBLTE_MME_ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REJECT_MSG_STRUCT *act_ded_eps_bearer_context_rej, + LIBLTE_BYTE_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_mme_unpack_activate_dedicated_eps_bearer_context_reject_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REJECT_MSG_STRUCT *act_ded_eps_bearer_context_rej); + +/********************************************************************* + Message Name: Activate Dedicated EPS Bearer Context Request + + Description: Sent by the network to the UE to request activation + of a dedicated EPS bearer context associated with + the same PDN address(es) and APN as an already + active default EPS bearer context. + + Document Reference: 24.301 v10.2.0 Section 8.3.3 +*********************************************************************/ +// Defines +// Enums +// Structs +typedef struct{ + LIBLTE_MME_EPS_QUALITY_OF_SERVICE_STRUCT eps_qos; + LIBLTE_MME_TRAFFIC_FLOW_TEMPLATE_STRUCT tft; + LIBLTE_MME_TRANSACTION_IDENTIFIER_STRUCT transaction_id; + LIBLTE_MME_QUALITY_OF_SERVICE_STRUCT negotiated_qos; + LIBLTE_MME_PROTOCOL_CONFIG_OPTIONS_STRUCT protocol_cnfg_opts; + uint8 eps_bearer_id; + uint8 proc_transaction_id; + uint8 linked_eps_bearer_id; + uint8 llc_sapi; + uint8 radio_prio; + uint8 packet_flow_id; + bool transaction_id_present; + bool negotiated_qos_present; + bool llc_sapi_present; + bool radio_prio_present; + bool packet_flow_id_present; + bool protocol_cnfg_opts_present; +}LIBLTE_MME_ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REQUEST_MSG_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_activate_dedicated_eps_bearer_context_request_msg(LIBLTE_MME_ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REQUEST_MSG_STRUCT *act_ded_eps_bearer_context_req, + LIBLTE_BYTE_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_mme_unpack_activate_dedicated_eps_bearer_context_request_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REQUEST_MSG_STRUCT *act_ded_eps_bearer_context_req); + +/********************************************************************* + Message Name: Activate Default EPS Bearer Context Accept + + Description: Sent by the UE to the network to acknowledge + activation of a default EPS bearer context. + + Document Reference: 24.301 v10.2.0 Section 8.3.4 +*********************************************************************/ +// Defines +// Enums +// Structs +typedef struct{ + LIBLTE_MME_PROTOCOL_CONFIG_OPTIONS_STRUCT protocol_cnfg_opts; + uint8 eps_bearer_id; + uint8 proc_transaction_id; + bool protocol_cnfg_opts_present; +}LIBLTE_MME_ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_ACCEPT_MSG_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_activate_default_eps_bearer_context_accept_msg(LIBLTE_MME_ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_ACCEPT_MSG_STRUCT *act_def_eps_bearer_context_accept, + LIBLTE_BYTE_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_mme_unpack_activate_default_eps_bearer_context_accept_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_ACCEPT_MSG_STRUCT *act_def_eps_bearer_context_accept); + +/********************************************************************* + Message Name: Activate Default EPS Bearer Context Reject + + Description: Sent by the UE to the network to reject activation + of a default EPS bearer context. + + Document Reference: 24.301 v10.2.0 Section 8.3.5 +*********************************************************************/ +// Defines +// Enums +// Structs +typedef struct{ + LIBLTE_MME_PROTOCOL_CONFIG_OPTIONS_STRUCT protocol_cnfg_opts; + uint8 eps_bearer_id; + uint8 proc_transaction_id; + uint8 esm_cause; + bool protocol_cnfg_opts_present; +}LIBLTE_MME_ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REJECT_MSG_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_activate_default_eps_bearer_context_reject_msg(LIBLTE_MME_ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REJECT_MSG_STRUCT *act_def_eps_bearer_context_rej, + LIBLTE_BYTE_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_mme_unpack_activate_default_eps_bearer_context_reject_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REJECT_MSG_STRUCT *act_def_eps_bearer_context_rej); + +/********************************************************************* + Message Name: Activate Default EPS Bearer Context Request + + Description: Sent by the network to the UE to request activation + of a default EPS bearer context. + + Document Reference: 24.301 v10.2.0 Section 8.3.6 +*********************************************************************/ +// Defines +#define LIBLTE_MME_TRANSACTION_IDENTIFIER_IEI 0x5D +#define LIBLTE_MME_QUALITY_OF_SERVICE_IEI 0x30 +#define LIBLTE_MME_LLC_SAPI_IEI 0x32 +#define LIBLTE_MME_RADIO_PRIORITY_IEI 0x8 +#define LIBLTE_MME_PACKET_FLOW_IDENTIFIER_IEI 0x34 +#define LIBLTE_MME_APN_AMBR_IEI 0x5E +#define LIBLTE_MME_ESM_CAUSE_IEI 0x58 +#define LIBLTE_MME_CONNECTIVITY_TYPE_IEI 0xB +// Enums +// Structs +typedef struct{ + LIBLTE_MME_EPS_QUALITY_OF_SERVICE_STRUCT eps_qos; + LIBLTE_MME_ACCESS_POINT_NAME_STRUCT apn; + LIBLTE_MME_PDN_ADDRESS_STRUCT pdn_addr; + LIBLTE_MME_TRANSACTION_IDENTIFIER_STRUCT transaction_id; + LIBLTE_MME_QUALITY_OF_SERVICE_STRUCT negotiated_qos; + LIBLTE_MME_APN_AGGREGATE_MAXIMUM_BIT_RATE_STRUCT apn_ambr; + LIBLTE_MME_PROTOCOL_CONFIG_OPTIONS_STRUCT protocol_cnfg_opts; + uint8 eps_bearer_id; + uint8 proc_transaction_id; + uint8 llc_sapi; + uint8 radio_prio; + uint8 packet_flow_id; + uint8 esm_cause; + uint8 connectivity_type; + bool transaction_id_present; + bool negotiated_qos_present; + bool llc_sapi_present; + bool radio_prio_present; + bool packet_flow_id_present; + bool apn_ambr_present; + bool esm_cause_present; + bool protocol_cnfg_opts_present; + bool connectivity_type_present; +}LIBLTE_MME_ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_MSG_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_activate_default_eps_bearer_context_request_msg(LIBLTE_MME_ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_MSG_STRUCT *act_def_eps_bearer_context_req, + LIBLTE_BYTE_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_mme_unpack_activate_default_eps_bearer_context_request_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_MSG_STRUCT *act_def_eps_bearer_context_req); + +/********************************************************************* + Message Name: Bearer Resource Allocation Reject + + Description: Sent by the network to the UE to reject the + allocation of a dedicated bearer resource. + + Document Reference: 24.301 v10.2.0 Section 8.3.7 +*********************************************************************/ +// Defines +#define LIBLTE_MME_T3496_VALUE_IEI 0x37 +// Enums +// Structs +typedef struct{ + LIBLTE_MME_PROTOCOL_CONFIG_OPTIONS_STRUCT protocol_cnfg_opts; + LIBLTE_MME_GPRS_TIMER_3_STRUCT t3496; + uint8 eps_bearer_id; + uint8 proc_transaction_id; + uint8 esm_cause; + bool protocol_cnfg_opts_present; + bool t3496_present; +}LIBLTE_MME_BEARER_RESOURCE_ALLOCATION_REJECT_MSG_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_bearer_resource_allocation_reject_msg(LIBLTE_MME_BEARER_RESOURCE_ALLOCATION_REJECT_MSG_STRUCT *bearer_res_alloc_rej, + LIBLTE_BYTE_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_mme_unpack_bearer_resource_allocation_reject_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_BEARER_RESOURCE_ALLOCATION_REJECT_MSG_STRUCT *bearer_res_alloc_rej); + +/********************************************************************* + Message Name: Bearer Resource Allocation Request + + Description: Sent by the UE to the network to request the + allocation of a dedicated bearer resource. + + Document Reference: 24.301 v10.2.0 Section 8.3.8 +*********************************************************************/ +// Defines +#define LIBLTE_MME_BEARER_RESOURCE_ALLOCATION_REQUEST_DEVICE_PROPERTIES_IEI 0xC +// Enums +// Structs +typedef struct{ + LIBLTE_MME_TRAFFIC_FLOW_AGGREGATE_DESCRIPTION_STRUCT tfa; + LIBLTE_MME_EPS_QUALITY_OF_SERVICE_STRUCT req_tf_qos; + LIBLTE_MME_PROTOCOL_CONFIG_OPTIONS_STRUCT protocol_cnfg_opts; + LIBLTE_MME_DEVICE_PROPERTIES_ENUM device_properties; + uint8 eps_bearer_id; + uint8 proc_transaction_id; + uint8 linked_eps_bearer_id; + bool protocol_cnfg_opts_present; + bool device_properties_present; +}LIBLTE_MME_BEARER_RESOURCE_ALLOCATION_REQUEST_MSG_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_bearer_resource_allocation_request_msg(LIBLTE_MME_BEARER_RESOURCE_ALLOCATION_REQUEST_MSG_STRUCT *bearer_res_alloc_req, + LIBLTE_BYTE_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_mme_unpack_bearer_resource_allocation_request_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_BEARER_RESOURCE_ALLOCATION_REQUEST_MSG_STRUCT *bearer_res_alloc_req); + +/********************************************************************* + Message Name: Bearer Resource Modification Reject + + Description: Sent by the network to the UE to reject the + modification of a dedicated bearer resource. + + Document Reference: 24.301 v10.2.0 Section 8.3.9 +*********************************************************************/ +// Defines +// Enums +// Structs +typedef struct{ + LIBLTE_MME_PROTOCOL_CONFIG_OPTIONS_STRUCT protocol_cnfg_opts; + LIBLTE_MME_GPRS_TIMER_3_STRUCT t3496; + uint8 eps_bearer_id; + uint8 proc_transaction_id; + uint8 esm_cause; + bool protocol_cnfg_opts_present; + bool t3496_present; +}LIBLTE_MME_BEARER_RESOURCE_MODIFICATION_REJECT_MSG_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_bearer_resource_modification_reject_msg(LIBLTE_MME_BEARER_RESOURCE_MODIFICATION_REJECT_MSG_STRUCT *bearer_res_mod_rej, + LIBLTE_BYTE_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_mme_unpack_bearer_resource_modification_reject_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_BEARER_RESOURCE_MODIFICATION_REJECT_MSG_STRUCT *bearer_res_mod_rej); + +/********************************************************************* + Message Name: Bearer Resource Modification Request + + Description: Sent by the UE to the network to request the + modification of a dedicated bearer resource. + + Document Reference: 24.301 v10.2.0 Section 8.3.10 +*********************************************************************/ +// Defines +#define LIBLTE_MME_EPS_QUALITY_OF_SERVICE_IEI 0x5B +#define LIBLTE_MME_BEARER_RESOURCE_MODIFICATION_REQUEST_DEVICE_PROPERTIES_IEI 0xC +// Enums +// Structs +typedef struct{ + LIBLTE_MME_TRAFFIC_FLOW_AGGREGATE_DESCRIPTION_STRUCT tfa; + LIBLTE_MME_EPS_QUALITY_OF_SERVICE_STRUCT req_tf_qos; + LIBLTE_MME_PROTOCOL_CONFIG_OPTIONS_STRUCT protocol_cnfg_opts; + LIBLTE_MME_DEVICE_PROPERTIES_ENUM device_properties; + uint8 eps_bearer_id; + uint8 proc_transaction_id; + uint8 eps_bearer_id_for_packet_filter; + uint8 esm_cause; + bool req_tf_qos_present; + bool esm_cause_present; + bool protocol_cnfg_opts_present; + bool device_properties_present; +}LIBLTE_MME_BEARER_RESOURCE_MODIFICATION_REQUEST_MSG_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_bearer_resource_modification_request_msg(LIBLTE_MME_BEARER_RESOURCE_MODIFICATION_REQUEST_MSG_STRUCT *bearer_res_mod_req, + LIBLTE_BYTE_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_mme_unpack_bearer_resource_modification_request_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_BEARER_RESOURCE_MODIFICATION_REQUEST_MSG_STRUCT *bearer_res_mod_req); + +/********************************************************************* + Message Name: Deactivate EPS Bearer Context Accept + + Description: Sent by the UE to acknowledge deactivation of the + EPS bearer context requested in the corresponding + deactivate EPS bearer context request message. + + Document Reference: 24.301 v10.2.0 Section 8.3.11 +*********************************************************************/ +// Defines +// Enums +// Structs +typedef struct{ + LIBLTE_MME_PROTOCOL_CONFIG_OPTIONS_STRUCT protocol_cnfg_opts; + uint8 eps_bearer_id; + uint8 proc_transaction_id; + bool protocol_cnfg_opts_present; +}LIBLTE_MME_DEACTIVATE_EPS_BEARER_CONTEXT_ACCEPT_MSG_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_deactivate_eps_bearer_context_accept_msg(LIBLTE_MME_DEACTIVATE_EPS_BEARER_CONTEXT_ACCEPT_MSG_STRUCT *deact_eps_bearer_context_accept, + LIBLTE_BYTE_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_mme_unpack_deactivate_eps_bearer_context_accept_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_DEACTIVATE_EPS_BEARER_CONTEXT_ACCEPT_MSG_STRUCT *deact_eps_bearer_context_accept); + +/********************************************************************* + Message Name: Deactivate EPS Bearer Context Request + + Description: Sent by the network to request deactivation of an + EPS bearer context. + + Document Reference: 24.301 v10.2.0 Section 8.3.12 +*********************************************************************/ +// Defines +// Enums +// Structs +typedef struct{ + LIBLTE_MME_PROTOCOL_CONFIG_OPTIONS_STRUCT protocol_cnfg_opts; + uint8 eps_bearer_id; + uint8 proc_transaction_id; + uint8 esm_cause; + bool protocol_cnfg_opts_present; +}LIBLTE_MME_DEACTIVATE_EPS_BEARER_CONTEXT_REQUEST_MSG_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_deactivate_eps_bearer_context_request_msg(LIBLTE_MME_DEACTIVATE_EPS_BEARER_CONTEXT_REQUEST_MSG_STRUCT *deact_eps_bearer_context_req, + LIBLTE_BYTE_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_mme_unpack_deactivate_eps_bearer_context_request_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_DEACTIVATE_EPS_BEARER_CONTEXT_REQUEST_MSG_STRUCT *deact_eps_bearer_context_req); + +/********************************************************************* + Message Name: ESM Information Request + + Description: Sent by the network to the UE to request the UE to + provide ESM information, i.e. protocol configuration + options or APN or both. + + Document Reference: 24.301 v10.2.0 Section 8.3.13 +*********************************************************************/ +// Defines +// Enums +// Structs +typedef struct{ + uint8 eps_bearer_id; + uint8 proc_transaction_id; +}LIBLTE_MME_ESM_INFORMATION_REQUEST_MSG_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_esm_information_request_msg(LIBLTE_MME_ESM_INFORMATION_REQUEST_MSG_STRUCT *esm_info_req, + LIBLTE_BYTE_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_mme_unpack_esm_information_request_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_ESM_INFORMATION_REQUEST_MSG_STRUCT *esm_info_req); + +/********************************************************************* + Message Name: ESM Information Response + + Description: Sent by the UE to the network in response to an ESM + INFORMATION REQUEST message and provides the + requested ESM information. + + Document Reference: 24.301 v10.2.0 Section 8.3.14 +*********************************************************************/ +// Defines +// Enums +// Structs +typedef struct{ + LIBLTE_MME_ACCESS_POINT_NAME_STRUCT apn; + LIBLTE_MME_PROTOCOL_CONFIG_OPTIONS_STRUCT protocol_cnfg_opts; + uint8 eps_bearer_id; + uint8 proc_transaction_id; + bool apn_present; + bool protocol_cnfg_opts_present; +}LIBLTE_MME_ESM_INFORMATION_RESPONSE_MSG_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_esm_information_response_msg(LIBLTE_MME_ESM_INFORMATION_RESPONSE_MSG_STRUCT *esm_info_resp, + LIBLTE_BYTE_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_mme_unpack_esm_information_response_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_ESM_INFORMATION_RESPONSE_MSG_STRUCT *esm_info_resp); + +/********************************************************************* + Message Name: ESM Status + + Description: Sent by the network or the UE to pass information on + the status of the indicated EPS bearer context and + report certain error conditions. + + Document Reference: 24.301 v10.2.0 Section 8.3.15 +*********************************************************************/ +// Defines +// Enums +// Structs +typedef struct{ + uint8 eps_bearer_id; + uint8 proc_transaction_id; + uint8 esm_cause; +}LIBLTE_MME_ESM_STATUS_MSG_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_esm_status_msg(LIBLTE_MME_ESM_STATUS_MSG_STRUCT *esm_status, + LIBLTE_BYTE_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_mme_unpack_esm_status_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_ESM_STATUS_MSG_STRUCT *esm_status); + +/********************************************************************* + Message Name: Modify EPS Bearer Context Accept + + Description: Sent by the UE to the network to acknowledge the + modification of an active EPS bearer context. + + Document Reference: 24.301 v10.2.0 Section 8.3.16 +*********************************************************************/ +// Defines +// Enums +// Structs +typedef struct{ + LIBLTE_MME_PROTOCOL_CONFIG_OPTIONS_STRUCT protocol_cnfg_opts; + uint8 eps_bearer_id; + uint8 proc_transaction_id; + bool protocol_cnfg_opts_present; +}LIBLTE_MME_MODIFY_EPS_BEARER_CONTEXT_ACCEPT_MSG_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_modify_eps_bearer_context_accept_msg(LIBLTE_MME_MODIFY_EPS_BEARER_CONTEXT_ACCEPT_MSG_STRUCT *mod_eps_bearer_context_accept, + LIBLTE_BYTE_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_mme_unpack_modify_eps_bearer_context_accept_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_MODIFY_EPS_BEARER_CONTEXT_ACCEPT_MSG_STRUCT *mod_eps_bearer_context_accept); + +/********************************************************************* + Message Name: Modify EPS Bearer Context Reject + + Description: Sent by the UE or the network to reject a + modification of an active EPS bearer context. + + Document Reference: 24.301 v10.2.0 Section 8.3.17 +*********************************************************************/ +// Defines +// Enums +// Structs +typedef struct{ + LIBLTE_MME_PROTOCOL_CONFIG_OPTIONS_STRUCT protocol_cnfg_opts; + uint8 eps_bearer_id; + uint8 proc_transaction_id; + uint8 esm_cause; + bool protocol_cnfg_opts_present; +}LIBLTE_MME_MODIFY_EPS_BEARER_CONTEXT_REJECT_MSG_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_modify_eps_bearer_context_reject_msg(LIBLTE_MME_MODIFY_EPS_BEARER_CONTEXT_REJECT_MSG_STRUCT *mod_eps_bearer_context_rej, + LIBLTE_BYTE_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_mme_unpack_modify_eps_bearer_context_reject_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_MODIFY_EPS_BEARER_CONTEXT_REJECT_MSG_STRUCT *mod_eps_bearer_context_rej); + +/********************************************************************* + Message Name: Modify EPS Bearer Context Request + + Description: Sent by the network to the UE to request modification + of an active EPS bearer context. + + Document Reference: 24.301 v10.2.0 Section 8.3.18 +*********************************************************************/ +// Defines +#define LIBLTE_MME_TRAFFIC_FLOW_TEMPLATE_IEI 0x36 +#define LIBLTE_MME_QUALITY_OF_SERVICE_IEI 0x30 +// Enums +// Structs +typedef struct{ + LIBLTE_MME_EPS_QUALITY_OF_SERVICE_STRUCT new_eps_qos; + LIBLTE_MME_TRAFFIC_FLOW_TEMPLATE_STRUCT tft; + LIBLTE_MME_QUALITY_OF_SERVICE_STRUCT new_qos; + LIBLTE_MME_APN_AGGREGATE_MAXIMUM_BIT_RATE_STRUCT apn_ambr; + LIBLTE_MME_PROTOCOL_CONFIG_OPTIONS_STRUCT protocol_cnfg_opts; + uint8 eps_bearer_id; + uint8 proc_transaction_id; + uint8 negotiated_llc_sapi; + uint8 radio_prio; + uint8 packet_flow_id; + bool new_eps_qos_present; + bool tft_present; + bool new_qos_present; + bool negotiated_llc_sapi_present; + bool radio_prio_present; + bool packet_flow_id_present; + bool apn_ambr_present; + bool protocol_cnfg_opts_present; +}LIBLTE_MME_MODIFY_EPS_BEARER_CONTEXT_REQUEST_MSG_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_modify_eps_bearer_context_request_msg(LIBLTE_MME_MODIFY_EPS_BEARER_CONTEXT_REQUEST_MSG_STRUCT *mod_eps_bearer_context_req, + LIBLTE_BYTE_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_mme_unpack_modify_eps_bearer_context_request_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_MODIFY_EPS_BEARER_CONTEXT_REQUEST_MSG_STRUCT *mod_eps_bearer_context_req); + +/********************************************************************* + Message Name: Notification + + Description: Sent by the network to inform the UE about events + which are relevant for the upper layer using an EPS + bearer context or having requested a procedure + transaction. + + Document Reference: 24.301 v10.2.0 Section 8.3.18A +*********************************************************************/ +// Defines +// Enums +// Structs +typedef struct{ + uint8 eps_bearer_id; + uint8 proc_transaction_id; + uint8 notification_ind; +}LIBLTE_MME_NOTIFICATION_MSG_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_notification_msg(LIBLTE_MME_NOTIFICATION_MSG_STRUCT *notification, + LIBLTE_BYTE_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_mme_unpack_notification_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_NOTIFICATION_MSG_STRUCT *notification); + +/********************************************************************* + Message Name: PDN Connectivity Reject + + Description: Sent by the network to the UE to reject establishment + of a PDN connection. + + Document Reference: 24.301 v10.2.0 Section 8.3.19 +*********************************************************************/ +// Defines +// Enums +// Structs +typedef struct{ + LIBLTE_MME_PROTOCOL_CONFIG_OPTIONS_STRUCT protocol_cnfg_opts; + LIBLTE_MME_GPRS_TIMER_3_STRUCT t3496; + uint8 eps_bearer_id; + uint8 proc_transaction_id; + uint8 esm_cause; + bool protocol_cnfg_opts_present; + bool t3496_present; +}LIBLTE_MME_PDN_CONNECTIVITY_REJECT_MSG_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_pdn_connectivity_reject_msg(LIBLTE_MME_PDN_CONNECTIVITY_REJECT_MSG_STRUCT *pdn_con_rej, + LIBLTE_BYTE_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_mme_unpack_pdn_connectivity_reject_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_PDN_CONNECTIVITY_REJECT_MSG_STRUCT *pdn_con_rej); + +/********************************************************************* + Message Name: PDN Connectivity Request + + Description: Sent by the UE to the network to initiate + establishment of a PDN connection. + + Document Reference: 24.301 v10.2.0 Section 8.3.20 +*********************************************************************/ +// Defines +#define LIBLTE_MME_ESM_INFO_TRANSFER_FLAG_IEI 0xD +#define LIBLTE_MME_ACCESS_POINT_NAME_IEI 0x28 +#define LIBLTE_MME_PDN_CONNECTIVITY_REQUEST_DEVICE_PROPERTIES_IEI 0xC +// Enums +// Structs +typedef struct{ + LIBLTE_MME_ACCESS_POINT_NAME_STRUCT apn; + LIBLTE_MME_PROTOCOL_CONFIG_OPTIONS_STRUCT protocol_cnfg_opts; + LIBLTE_MME_ESM_INFO_TRANSFER_FLAG_ENUM esm_info_transfer_flag; + LIBLTE_MME_DEVICE_PROPERTIES_ENUM device_properties; + uint8 eps_bearer_id; + uint8 proc_transaction_id; + uint8 pdn_type; + uint8 request_type; + bool esm_info_transfer_flag_present; + bool apn_present; + bool protocol_cnfg_opts_present; + bool device_properties_present; +}LIBLTE_MME_PDN_CONNECTIVITY_REQUEST_MSG_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_pdn_connectivity_request_msg(LIBLTE_MME_PDN_CONNECTIVITY_REQUEST_MSG_STRUCT *pdn_con_req, + LIBLTE_BYTE_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_mme_unpack_pdn_connectivity_request_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_PDN_CONNECTIVITY_REQUEST_MSG_STRUCT *pdn_con_req); + +/********************************************************************* + Message Name: PDN Disconnect Reject + + Description: Sent by the network to the UE to reject release of a + PDN connection. + + Document Reference: 24.301 v10.2.0 Section 8.3.21 +*********************************************************************/ +// Defines +// Enums +// Structs +typedef struct{ + LIBLTE_MME_PROTOCOL_CONFIG_OPTIONS_STRUCT protocol_cnfg_opts; + uint8 eps_bearer_id; + uint8 proc_transaction_id; + uint8 esm_cause; + bool protocol_cnfg_opts_present; +}LIBLTE_MME_PDN_DISCONNECT_REJECT_MSG_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_pdn_disconnect_reject_msg(LIBLTE_MME_PDN_DISCONNECT_REJECT_MSG_STRUCT *pdn_discon_rej, + LIBLTE_BYTE_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_mme_unpack_pdn_disconnect_reject_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_PDN_DISCONNECT_REJECT_MSG_STRUCT *pdn_discon_rej); + +/********************************************************************* + Message Name: PDN Disconnect Request + + Description: Sent by the UE to the network to initiate release of + a PDN connection. + + Document Reference: 24.301 v10.2.0 Section 8.3.22 +*********************************************************************/ +// Defines +// Enums +// Structs +typedef struct{ + LIBLTE_MME_PROTOCOL_CONFIG_OPTIONS_STRUCT protocol_cnfg_opts; + uint8 eps_bearer_id; + uint8 proc_transaction_id; + uint8 linked_eps_bearer_id; + bool protocol_cnfg_opts_present; +}LIBLTE_MME_PDN_DISCONNECT_REQUEST_MSG_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_mme_pack_pdn_disconnect_request_msg(LIBLTE_MME_PDN_DISCONNECT_REQUEST_MSG_STRUCT *pdn_discon_req, + LIBLTE_BYTE_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_mme_unpack_pdn_disconnect_request_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_PDN_DISCONNECT_REQUEST_MSG_STRUCT *pdn_discon_req); + +#endif /* __LIBLTE_MME_H__ */ diff --git a/lib/include/srslte/asn1/liblte_rrc.h b/lib/include/srslte/asn1/liblte_rrc.h new file mode 100644 index 000000000..5a8515dbb --- /dev/null +++ b/lib/include/srslte/asn1/liblte_rrc.h @@ -0,0 +1,6921 @@ +/******************************************************************************* + + Copyright 2012-2014 Ben Wojtowicz + Copyright 2014 Andrew Murphy (SIB13 unpack) + + This program 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. + + This program 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. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + +******************************************************************************* + + File: liblte_rrc.h + + Description: Contains all the definitions for the LTE Radio Resource + Control Layer library. + + Revision History + ---------- ------------- -------------------------------------------- + 03/24/2012 Ben Wojtowicz Created file. + 04/21/2012 Ben Wojtowicz Added SIB1 parameters, IEs, and messages + 05/28/2012 Ben Wojtowicz Added SIB1 pack functionality + 08/19/2012 Ben Wojtowicz Added functionality to support SIB2, SIB3, + SIB4, and SIB8 packing and unpacking + 10/06/2012 Ben Wojtowicz Added more decoding/encoding. + 12/26/2012 Ben Wojtowicz Added text versions of some enums. + 03/03/2013 Ben Wojtowicz Added a test fill pattern, text and number + mappings for all enums, carrier_freqs_geran, + SIB5, SIB6, SIB7, and paging packing and + unpacking. + 07/21/2013 Ben Wojtowicz Using the common msg structure. + 03/26/2014 Ben Wojtowicz Added support for RRC Connection Request, + RRC Connection Reestablishment Request, + and UL CCCH Messages. + 05/04/2014 Ben Wojtowicz Added support for DL CCCH Messages. + 06/15/2014 Ben Wojtowicz Added support for UL DCCH Messages. + 08/03/2014 Ben Wojtowicz Added more decoding/encoding. + 09/19/2014 Andrew Murphy Added SIB13 unpack. + 11/01/2014 Ben Wojtowicz Added more decoding/encoding. + 11/09/2014 Ben Wojtowicz Added SIB13 pack. + 11/29/2014 Ben Wojtowicz Fixed a bug in RRC connection reestablishment + UE identity. + +*******************************************************************************/ + +#ifndef __LIBLTE_RRC_H__ +#define __LIBLTE_RRC_H__ + +/******************************************************************************* + INCLUDES +*******************************************************************************/ + +#include "liblte_common.h" + +/******************************************************************************* + DEFINES +*******************************************************************************/ + + +/******************************************************************************* + TYPEDEFS +*******************************************************************************/ + +static const uint8 liblte_rrc_test_fill[8] = {1,0,1,0,0,1,0,1}; + +typedef void (*log_handler_t)(void *ctx, char *str); + +void liblte_rrc_log_register_handler(void *ctx, log_handler_t handler); + +/******************************************************************************* + INFORMATION ELEMENT DECLARATIONS +*******************************************************************************/ + +/********************************************************************* + IE Name: MBSFN Notification Config + + Description: Specifies the MBMS notification related configuration + parameters, that are applicable for all MBSFN areas + + Document Reference: 36.331 v10.0.0 Section 6.3.7 +*********************************************************************/ +// Defines +// Enums +typedef enum{ + LIBLTE_RRC_NOTIFICATION_REPETITION_COEFF_R9_N2 = 0, + LIBLTE_RRC_NOTIFICATION_REPETITION_COEFF_R9_N4, + LIBLTE_RRC_NOTIFICATION_REPETITION_COEFF_R9_N_ITEMS, +}LIBLTE_RRC_NOTIFICATION_REPETITION_COEFF_R9_ENUM; +static const char liblte_rrc_notification_repetition_coeff_r9_text[LIBLTE_RRC_NOTIFICATION_REPETITION_COEFF_R9_N_ITEMS][20] = {"2", "4"}; +static const uint8 liblte_rrc_notification_repetition_coeff_r9_num[LIBLTE_RRC_NOTIFICATION_REPETITION_COEFF_R9_N_ITEMS] = {2, 4}; +// Structs +typedef struct{ + LIBLTE_RRC_NOTIFICATION_REPETITION_COEFF_R9_ENUM repetition_coeff; + uint8 offset; + uint8 sf_index; +}LIBLTE_RRC_MBSFN_NOTIFICATION_CONFIG_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_mbsfn_notification_config_ie(LIBLTE_RRC_MBSFN_NOTIFICATION_CONFIG_STRUCT *mbsfn_notification_cnfg, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_mbsfn_notification_config_ie(uint8 **ie_ptr, + LIBLTE_RRC_MBSFN_NOTIFICATION_CONFIG_STRUCT *mbsfn_notification_cnfg); + +/********************************************************************* + IE Name: MBSFN Area Info List + + Description: Contains the information required to acquire the MBMS + control information associated with one or more MBSFN + areas + + Document Reference: 36.331 v10.0.0 Section 6.3.7 +*********************************************************************/ +// Defines +#define LIBLTE_RRC_MAX_MBSFN_AREAS 8 +// Enums +typedef enum{ + LIBLTE_RRC_NON_MBSFN_REGION_LENGTH_S1 = 0, + LIBLTE_RRC_NON_MBSFN_REGION_LENGTH_S2, + LIBLTE_RRC_NON_MBSFN_REGION_LENGTH_N_ITEMS, +}LIBLTE_RRC_NON_MBSFN_REGION_LENGTH_ENUM; +static const char liblte_rrc_non_mbsfn_region_length_text[LIBLTE_RRC_NON_MBSFN_REGION_LENGTH_N_ITEMS][20] = {"1", "2"}; +static const uint8 liblte_rrc_non_mbsfn_region_length_num[LIBLTE_RRC_NON_MBSFN_REGION_LENGTH_N_ITEMS] = {1, 2}; +typedef enum{ + LIBLTE_RRC_MCCH_REPETITION_PERIOD_RF32 = 0, + LIBLTE_RRC_MCCH_REPETITION_PERIOD_RF64, + LIBLTE_RRC_MCCH_REPETITION_PERIOD_RF128, + LIBLTE_RRC_MCCH_REPETITION_PERIOD_RF256, + LIBLTE_RRC_MCCH_REPETITION_PERIOD_N_ITEMS, +}LIBLTE_RRC_MCCH_REPETITION_PERIOD_ENUM; +static const char liblte_rrc_mcch_repetition_period_r9_text[LIBLTE_RRC_MCCH_REPETITION_PERIOD_N_ITEMS][20] = {"32", "64", "128", "256"}; +static const uint16 liblte_rrc_mcch_repetition_period_r9_num[LIBLTE_RRC_MCCH_REPETITION_PERIOD_N_ITEMS] = {32, 64, 128, 256}; +typedef enum{ + LIBLTE_RRC_MCCH_MODIFICATION_PERIOD_512 = 0, + LIBLTE_RRC_MCCH_MODIFICATION_PERIOD_1024, + LIBLTE_RRC_MCCH_MODIFICATION_PERIOD_N_ITEMS, +}LIBLTE_RRC_MCCH_MODIFICATION_PERIOD_ENUM; +static const char liblte_rrc_mcch_modification_period_r9_text[LIBLTE_RRC_MCCH_MODIFICATION_PERIOD_N_ITEMS][20] = {"512", "1024"}; +static const uint16 liblte_rrc_mcch_modification_period_r9_num[LIBLTE_RRC_MCCH_MODIFICATION_PERIOD_N_ITEMS] = {512, 1024}; +typedef enum{ + LIBLTE_RRC_MCCH_SIGNALLING_MCS_N2 = 0, + LIBLTE_RRC_MCCH_SIGNALLING_MCS_N7, + LIBLTE_RRC_MCCH_SIGNALLING_MCS_N13, + LIBLTE_RRC_MCCH_SIGNALLING_MCS_N19, + LIBLTE_RRC_MCCH_SIGNALLING_MCS_N_ITEMS, +}LIBLTE_RRC_MCCH_SIGNALLING_MCS_ENUM; +static const char liblte_rrc_mcch_signalling_mcs_r9_text[LIBLTE_RRC_MCCH_SIGNALLING_MCS_N_ITEMS][20] = {"2", "7", "13", "19"}; +static const uint8 liblte_rrc_mcch_signalling_mcs_r9_num[LIBLTE_RRC_MCCH_SIGNALLING_MCS_N_ITEMS] = {2, 7, 13, 19}; +// Structs +typedef struct{ + LIBLTE_RRC_NON_MBSFN_REGION_LENGTH_ENUM non_mbsfn_region_length; + LIBLTE_RRC_MCCH_REPETITION_PERIOD_ENUM mcch_repetition_period_r9; + LIBLTE_RRC_MCCH_MODIFICATION_PERIOD_ENUM mcch_modification_period_r9; + LIBLTE_RRC_MCCH_SIGNALLING_MCS_ENUM signalling_mcs_r9; + uint8 mbsfn_area_id_r9; + uint8 notification_indicator_r9; + uint8 mcch_offset_r9; + uint8 sf_alloc_info_r9; +}LIBLTE_RRC_MBSFN_AREA_INFO_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_mbsfn_area_info_ie(LIBLTE_RRC_MBSFN_AREA_INFO_STRUCT *mbsfn_area_info, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_mbsfn_area_info_ie(uint8 **ie_ptr, + LIBLTE_RRC_MBSFN_AREA_INFO_STRUCT *mbsfn_area_info); + +/********************************************************************* + IE Name: MBSFN Subframe Config + + Description: Defines subframes that are reserved for MBSFN in + downlink + + Document Reference: 36.331 v10.0.0 Section 6.3.7 +*********************************************************************/ +// Defines +#define LIBLTE_RRC_MAX_MBSFN_ALLOCATIONS 8 +// Enums +typedef enum{ + LIBLTE_RRC_RADIO_FRAME_ALLOCATION_PERIOD_N1 = 0, + LIBLTE_RRC_RADIO_FRAME_ALLOCATION_PERIOD_N2, + LIBLTE_RRC_RADIO_FRAME_ALLOCATION_PERIOD_N4, + LIBLTE_RRC_RADIO_FRAME_ALLOCATION_PERIOD_N8, + LIBLTE_RRC_RADIO_FRAME_ALLOCATION_PERIOD_N16, + LIBLTE_RRC_RADIO_FRAME_ALLOCATION_PERIOD_N32, + LIBLTE_RRC_RADIO_FRAME_ALLOCATION_PERIOD_N_ITEMS, +}LIBLTE_RRC_RADIO_FRAME_ALLOCATION_PERIOD_ENUM; +static const char liblte_rrc_radio_frame_allocation_period_text[LIBLTE_RRC_RADIO_FRAME_ALLOCATION_PERIOD_N_ITEMS][20] = { "1", "2", "4", "8", + "16", "32"}; +static const uint8 liblte_rrc_radio_frame_allocation_period_num[LIBLTE_RRC_RADIO_FRAME_ALLOCATION_PERIOD_N_ITEMS] = {1, 2, 4, 8, 16, 32}; +typedef enum{ + LIBLTE_RRC_SUBFRAME_ALLOCATION_NUM_FRAMES_ONE = 0, + LIBLTE_RRC_SUBFRAME_ALLOCATION_NUM_FRAMES_FOUR, + LIBLTE_RRC_SUBFRAME_ALLOCATION_NUM_FRAMES_N_ITEMS, +}LIBLTE_RRC_SUBFRAME_ALLOCATION_NUM_FRAMES_ENUM; +static const char liblte_rrc_subframe_allocation_num_frames_text[LIBLTE_RRC_SUBFRAME_ALLOCATION_NUM_FRAMES_N_ITEMS][20] = {"1", "4"}; +static const uint8 liblte_rrc_subframe_allocation_num_frames_num[LIBLTE_RRC_SUBFRAME_ALLOCATION_NUM_FRAMES_N_ITEMS] = {1, 4}; +// Structs +typedef struct{ + LIBLTE_RRC_RADIO_FRAME_ALLOCATION_PERIOD_ENUM radio_fr_alloc_period; + LIBLTE_RRC_SUBFRAME_ALLOCATION_NUM_FRAMES_ENUM subfr_alloc_num_frames; + uint32 subfr_alloc; + uint8 radio_fr_alloc_offset; +}LIBLTE_RRC_MBSFN_SUBFRAME_CONFIG_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_mbsfn_subframe_config_ie(LIBLTE_RRC_MBSFN_SUBFRAME_CONFIG_STRUCT *mbsfn_subfr_cnfg, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_mbsfn_subframe_config_ie(uint8 **ie_ptr, + LIBLTE_RRC_MBSFN_SUBFRAME_CONFIG_STRUCT *mbsfn_subfr_cnfg); + +/********************************************************************* + IE Name: PMCH Info List + + Description: Specifies configuration of all PMCHs of an MBSFN area + + Document Reference: 36.331 v10.0.0 Section 6.3.7 +*********************************************************************/ +// Defines +// Enums +// Structs +// Functions +// FIXME + +/********************************************************************* + IE Name: C-RNTI + + Description: Identifies a UE having a RRC connection within a cell + + Document Reference: 36.331 v10.0.0 Section 6.3.6 +*********************************************************************/ +// Defines +// Enums +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_c_rnti_ie(uint16 rnti, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_c_rnti_ie(uint8 **ie_ptr, + uint16 *rnti); + +/********************************************************************* + IE Name: Dedicated Info CDMA2000 + + Description: Transfers UE specific CDMA2000 information between + the network and the UE + + Document Reference: 36.331 v10.0.0 Section 6.3.6 +*********************************************************************/ +// Defines +// Enums +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_dedicated_info_cdma2000_ie(LIBLTE_BYTE_MSG_STRUCT *ded_info_cdma2000, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_dedicated_info_cdma2000_ie(uint8 **ie_ptr, + LIBLTE_BYTE_MSG_STRUCT *ded_info_cdma2000); + +/********************************************************************* + IE Name: Dedicated Info NAS + + Description: Transfers UE specific NAS layer information between + the network and the UE + + Document Reference: 36.331 v10.0.0 Section 6.3.6 +*********************************************************************/ +// Defines +// Enums +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_dedicated_info_nas_ie(LIBLTE_BYTE_MSG_STRUCT *ded_info_nas, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_dedicated_info_nas_ie(uint8 **ie_ptr, + LIBLTE_BYTE_MSG_STRUCT *ded_info_nas); + +/********************************************************************* + IE Name: Filter Coefficient + + Description: Specifies the measurement filtering coefficient + + Document Reference: 36.331 v10.0.0 Section 6.3.6 +*********************************************************************/ +// Defines +// Enums +typedef enum{ + LIBLTE_RRC_FILTER_COEFFICIENT_FC0 = 0, + LIBLTE_RRC_FILTER_COEFFICIENT_FC1, + LIBLTE_RRC_FILTER_COEFFICIENT_FC2, + LIBLTE_RRC_FILTER_COEFFICIENT_FC3, + LIBLTE_RRC_FILTER_COEFFICIENT_FC4, + LIBLTE_RRC_FILTER_COEFFICIENT_FC5, + LIBLTE_RRC_FILTER_COEFFICIENT_FC6, + LIBLTE_RRC_FILTER_COEFFICIENT_FC7, + LIBLTE_RRC_FILTER_COEFFICIENT_FC8, + LIBLTE_RRC_FILTER_COEFFICIENT_FC9, + LIBLTE_RRC_FILTER_COEFFICIENT_FC11, + LIBLTE_RRC_FILTER_COEFFICIENT_FC13, + LIBLTE_RRC_FILTER_COEFFICIENT_FC15, + LIBLTE_RRC_FILTER_COEFFICIENT_FC17, + LIBLTE_RRC_FILTER_COEFFICIENT_FC19, + LIBLTE_RRC_FILTER_COEFFICIENT_SPARE1, + LIBLTE_RRC_FILTER_COEFFICIENT_N_ITEMS, +}LIBLTE_RRC_FILTER_COEFFICIENT_ENUM; +static const char liblte_rrc_filter_coefficient_text[LIBLTE_RRC_FILTER_COEFFICIENT_N_ITEMS][20] = { "0", "1", "2", "3", + "4", "5", "6", "7", + "8", "9", "11", "13", + "15", "17", "19", "SPARE"}; +static const int8 liblte_rrc_filter_coefficient_num[LIBLTE_RRC_FILTER_COEFFICIENT_N_ITEMS] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 13, 15, 17, 19, -1}; +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_filter_coefficient_ie(LIBLTE_RRC_FILTER_COEFFICIENT_ENUM filter_coeff, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_filter_coefficient_ie(uint8 **ie_ptr, + LIBLTE_RRC_FILTER_COEFFICIENT_ENUM *filter_coeff); + +/********************************************************************* + IE Name: MMEC + + Description: Identifies an MME within the scope of an MME group + within a PLMN + + Document Reference: 36.331 v10.0.0 Section 6.3.6 +*********************************************************************/ +// Defines +// Enums +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_mmec_ie(uint8 mmec, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_mmec_ie(uint8 **ie_ptr, + uint8 *mmec); + +/********************************************************************* + IE Name: Neigh Cell Config + + Description: Provides the information related to MBSFN and TDD + UL/DL configuration of neighbor cells + + Document Reference: 36.331 v10.0.0 Section 6.3.6 +*********************************************************************/ +// Defines +// Enums +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_neigh_cell_config_ie(uint8 neigh_cell_config, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_neigh_cell_config_ie(uint8 **ie_ptr, + uint8 *neigh_cell_config); + +/********************************************************************* + IE Name: Other Config + + Description: Contains configuration related to other configuration + + Document Reference: 36.331 v10.0.0 Section 6.3.6 +*********************************************************************/ +// Defines +// Enums +typedef enum{ + LIBLTE_RRC_REPORT_PROXIMITY_INDICATION_EUTRA_R9_ENABLED = 0, + LIBLTE_RRC_REPORT_PROXIMITY_INDICATION_EUTRA_R9_N_ITEMS, +}LIBLTE_RRC_REPORT_PROXIMITY_INDICATION_EUTRA_R9_ENUM; +static const char liblte_rrc_report_proximity_indication_eutra_r9_text[LIBLTE_RRC_REPORT_PROXIMITY_INDICATION_EUTRA_R9_N_ITEMS][20] = {"Enabled"}; +typedef enum{ + LIBLTE_RRC_REPORT_PROXIMITY_INDICATION_UTRA_R9_ENABLED = 0, + LIBLTE_RRC_REPORT_PROXIMITY_INDICATION_UTRA_R9_N_ITEMS, +}LIBLTE_RRC_REPORT_PROXIMITY_INDICATION_UTRA_R9_ENUM; +static const char liblte_rrc_report_proximity_indication_utra_r9_text[LIBLTE_RRC_REPORT_PROXIMITY_INDICATION_UTRA_R9_N_ITEMS][20] = {"Enabled"}; +// Structs +typedef struct{ + LIBLTE_RRC_REPORT_PROXIMITY_INDICATION_EUTRA_R9_ENUM report_proximity_ind_eutra; + LIBLTE_RRC_REPORT_PROXIMITY_INDICATION_UTRA_R9_ENUM report_proximity_ind_utra; + bool report_proximity_ind_eutra_present; + bool report_proximity_ind_utra_present; +}LIBLTE_RRC_REPORT_PROXIMITY_CONFIG_R9_STRUCT; +typedef struct{ + LIBLTE_RRC_REPORT_PROXIMITY_CONFIG_R9_STRUCT report_proximity_cnfg; + bool report_proximity_cnfg_present; +}LIBLTE_RRC_OTHER_CONFIG_R9_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_other_config_ie(LIBLTE_RRC_OTHER_CONFIG_R9_STRUCT *other_cnfg, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_other_config_ie(uint8 **ie_ptr, + LIBLTE_RRC_OTHER_CONFIG_R9_STRUCT *other_cnfg); + +/********************************************************************* + IE Name: RAND CDMA2000 (1xRTT) + + Description: Contains a random value, generated by the eNB, to be + passed to the CDMA2000 upper layers + + Document Reference: 36.331 v10.0.0 Section 6.3.6 +*********************************************************************/ +// Defines +// Enums +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_rand_cdma2000_1xrtt_ie(uint32 rand, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_rand_cdma2000_1xrtt_ie(uint8 **ie_ptr, + uint32 *rand); + +/********************************************************************* + IE Name: RAT Type + + Description: Indicates the radio access technology (RAT), + including E-UTRA, of the requested/transferred UE + capabilities + + Document Reference: 36.331 v10.0.0 Section 6.3.6 +*********************************************************************/ +// Defines +// Enums +typedef enum{ + LIBLTE_RRC_RAT_TYPE_EUTRA = 0, + LIBLTE_RRC_RAT_TYPE_UTRA, + LIBLTE_RRC_RAT_TYPE_GERAN_CS, + LIBLTE_RRC_RAT_TYPE_GERAN_PS, + LIBLTE_RRC_RAT_TYPE_CDMA2000_1XRTT, + LIBLTE_RRC_RAT_TYPE_SPARE_3, + LIBLTE_RRC_RAT_TYPE_SPARE_2, + LIBLTE_RRC_RAT_TYPE_SPARE_1, + LIBLTE_RRC_RAT_TYPE_N_ITEMS, +}LIBLTE_RRC_RAT_TYPE_ENUM; +static const char liblte_rrc_rat_type_text[LIBLTE_RRC_RAT_TYPE_N_ITEMS][20] = { "EUTRA", "UTRA", "GERAN_CS", "GERAN_PS", + "CDMA2000_1XRTT", "SPARE", "SPARE", "SPARE"}; +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_rat_type_ie(LIBLTE_RRC_RAT_TYPE_ENUM rat_type, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_rat_type_ie(uint8 **ie_ptr, + LIBLTE_RRC_RAT_TYPE_ENUM *rat_type); + +/********************************************************************* + IE Name: RRC Transaction Identifier + + Description: Identifies an RRC procedure along with the message + type + + Document Reference: 36.331 v10.0.0 Section 6.3.6 +*********************************************************************/ +// Defines +// Enums +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_rrc_transaction_identifier_ie(uint8 rrc_transaction_id, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_rrc_transaction_identifier_ie(uint8 **ie_ptr, + uint8 *rrc_transaction_id); + +/********************************************************************* + IE Name: S-TMSI + + Description: Contains an S-Temporary Mobile Subscriber Identity, + a temporary UE identity provided by the EPC which + uniquely identifies the UE within the tracking area + + Document Reference: 36.331 v10.0.0 Section 6.3.6 +*********************************************************************/ +// Defines +// Enums +// Structs +typedef struct{ + uint32 m_tmsi; + uint8 mmec; +}LIBLTE_RRC_S_TMSI_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_s_tmsi_ie(LIBLTE_RRC_S_TMSI_STRUCT *s_tmsi, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_s_tmsi_ie(uint8 **ie_ptr, + LIBLTE_RRC_S_TMSI_STRUCT *s_tmsi); + +/********************************************************************* + IE Name: UE Capability RAT Container List + + Description: Contains list of containers, one for each RAT for + which UE capabilities are transferred + + Document Reference: 36.331 v10.0.0 Section 6.3.6 +*********************************************************************/ +// Defines +// Enums +// Structs +// Functions +// FIXME + +/********************************************************************* + IE Name: UE EUTRA Capability + + Description: Conveys the E-UTRA UE Radio Access Capability + Parameters + + Document Reference: 36.331 v10.0.0 Section 6.3.6 +*********************************************************************/ +// Defines +#define LIBLTE_RRC_MAXBANDS 64 + +// Enums +typedef enum{ + LIBLTE_RRC_ACCESS_STRATUM_RELEASE_REL8 = 0, + LIBLTE_RRC_ACCESS_STRATUM_RELEASE_REL9, + LIBLTE_RRC_ACCESS_STRATUM_RELEASE_SPARE6, + LIBLTE_RRC_ACCESS_STRATUM_RELEASE_SPARE5, + LIBLTE_RRC_ACCESS_STRATUM_RELEASE_SPARE4, + LIBLTE_RRC_ACCESS_STRATUM_RELEASE_SPARE3, + LIBLTE_RRC_ACCESS_STRATUM_RELEASE_SPARE2, + LIBLTE_RRC_ACCESS_STRATUM_RELEASE_SPARE1, + LIBLTE_RRC_ACCESS_STRATUM_RELEASE_N_ITEMS +}LIBLTE_RRC_ACCESS_STRATUM_RELEASE_ENUM; +static const char liblte_rrc_access_stratum_release_text[LIBLTE_RRC_ACCESS_STRATUM_RELEASE_N_ITEMS][20] = { "rel8", "rel9", "spare6", "spare5", + "spare4", "spare3", "spare2", "spare1"}; + +typedef enum{ + LIBLTE_RRC_ROHC_PROFILES_0x0001, + LIBLTE_RRC_ROHC_PROFILES_0x0002, + LIBLTE_RRC_ROHC_PROFILES_0x0003, + LIBLTE_RRC_ROHC_PROFILES_0x0004, + LIBLTE_RRC_ROHC_PROFILES_0x0006, + LIBLTE_RRC_ROHC_PROFILES_0x0101, + LIBLTE_RRC_ROHC_PROFILES_0x0102, + LIBLTE_RRC_ROHC_PROFILES_0x0103, + LIBLTE_RRC_ROHC_PROFILES_0x0104, + LIBLTE_RRC_ROHC_PROFILES_NITEMS +}LIBLTE_RRC_ROHC_PROFILES_ENUM; +static const char liblte_rrc_rohc_profiles_text[LIBLTE_RRC_ROHC_PROFILES_NITEMS][20] = {"profile0x0001", + "profile0x0002", + "profile0x0003", + "profile0x0004", + "profile0x0006", + "profile0x0101", + "profile0x0102", + "profile0x0103", + "profile0x0104"}; + +typedef enum{ + LIBLTE_RRC_MAX_ROHC_CTXTS_CS2 = 0, + LIBLTE_RRC_MAX_ROHC_CTXTS_CS4, + LIBLTE_RRC_MAX_ROHC_CTXTS_CS8, + LIBLTE_RRC_MAX_ROHC_CTXTS_CS12, + LIBLTE_RRC_MAX_ROHC_CTXTS_CS16, + LIBLTE_RRC_MAX_ROHC_CTXTS_CS24, + LIBLTE_RRC_MAX_ROHC_CTXTS_CS32, + LIBLTE_RRC_MAX_ROHC_CTXTS_CS48, + LIBLTE_RRC_MAX_ROHC_CTXTS_CS64, + LIBLTE_RRC_MAX_ROHC_CTXTS_CS128, + LIBLTE_RRC_MAX_ROHC_CTXTS_CS256, + LIBLTE_RRC_MAX_ROHC_CTXTS_CS512, + LIBLTE_RRC_MAX_ROHC_CTXTS_CS1024, + LIBLTE_RRC_MAX_ROHC_CTXTS_CS16384, + LIBLTE_RRC_MAX_ROHC_CTXTS_SPARE1, + LIBLTE_RRC_MAX_ROHC_CTXTS_SPARE2, + LIBLTE_RRC_MAX_ROHC_CTXTS_N_ITEMS +}LIBLTE_RRC_MAX_ROHC_CTXTS_ENUM; +static const char liblte_rrc_max_rohc_ctxts_text[LIBLTE_RRC_MAX_ROHC_CTXTS_N_ITEMS][20] = { "cs2", "cs4", "cs8", "cs12", "cs16", "cs24", "cs32", + "cs48", "cs64", "cs128", "cs256", "cs512", "cs1024", + "cs16384", "spare2", "spare1"}; + +typedef enum{ + LIBLTE_RRC_BAND_1 = 0, + LIBLTE_RRC_BAND_2, + LIBLTE_RRC_BAND_3, + LIBLTE_RRC_BAND_4, + LIBLTE_RRC_BAND_5, + LIBLTE_RRC_BAND_6, + LIBLTE_RRC_BAND_7, + LIBLTE_RRC_BAND_8, + LIBLTE_RRC_BAND_9, + LIBLTE_RRC_BAND_10, + LIBLTE_RRC_BAND_11, + LIBLTE_RRC_BAND_12, + LIBLTE_RRC_BAND_13, + LIBLTE_RRC_BAND_14, + LIBLTE_RRC_BAND_17, + LIBLTE_RRC_BAND_18, + LIBLTE_RRC_BAND_19, + LIBLTE_RRC_BAND_20, + LIBLTE_RRC_BAND_21, + LIBLTE_RRC_BAND_22, + LIBLTE_RRC_BAND_23, + LIBLTE_RRC_BAND_24, + LIBLTE_RRC_BAND_25, + LIBLTE_RRC_BAND_33, + LIBLTE_RRC_BAND_34, + LIBLTE_RRC_BAND_35, + LIBLTE_RRC_BAND_36, + LIBLTE_RRC_BAND_37, + LIBLTE_RRC_BAND_38, + LIBLTE_RRC_BAND_39, + LIBLTE_RRC_BAND_40, + LIBLTE_RRC_BAND_41, + LIBLTE_RRC_BAND_42, + LIBLTE_RRC_BAND_43, + LIBLTE_RRC_BAND_N_ITEMS, +}LIBLTE_RRC_BAND_ENUM; +static const char liblte_rrc_band_text[LIBLTE_RRC_BAND_N_ITEMS][20] = { "1", "2", "3", "4", + "5", "6", "7", "8", + "9", "10", "11", "12", + "13", "14", "17", "18", + "19", "20", "21", "22", + "23", "24", "25", "33", + "34", "35", "36", "37", + "38", "39", "40", "41", + "42", "43"}; +static const uint8 liblte_rrc_band_num[LIBLTE_RRC_BAND_N_ITEMS] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43}; + +// Structs +typedef struct{ + bool supported_rohc_profiles[9]; + LIBLTE_RRC_MAX_ROHC_CTXTS_ENUM max_rohc_ctxts; + bool max_rohc_ctxts_present; +}LIBLTE_RRC_PDCP_PARAMS_STRUCT; + +LIBLTE_ERROR_ENUM liblte_rrc_pack_pdcp_params_ie(LIBLTE_RRC_PDCP_PARAMS_STRUCT *pdcp_params, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_pdcp_params_ie(uint8 **ie_ptr, + LIBLTE_RRC_PDCP_PARAMS_STRUCT *pdcp_params); + +typedef struct{ + bool tx_antenna_selection_supported; + bool specific_ref_sigs_supported; +}LIBLTE_RRC_PHY_LAYER_PARAMS_STRUCT; + +LIBLTE_ERROR_ENUM liblte_rrc_pack_phy_layer_params_ie(LIBLTE_RRC_PHY_LAYER_PARAMS_STRUCT *params, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_phy_layer_params_ie(uint8 **ie_ptr, + LIBLTE_RRC_PHY_LAYER_PARAMS_STRUCT *params); + +typedef struct{ + uint8 band_eutra; + bool half_duplex; +}LIBLTE_RRC_SUPPORTED_BAND_EUTRA_STRUCT; + +typedef struct{ + LIBLTE_RRC_SUPPORTED_BAND_EUTRA_STRUCT supported_band_eutra[LIBLTE_RRC_MAXBANDS]; + uint32 N_supported_band_eutras; +}LIBLTE_RRC_RF_PARAMS_STRUCT; + +LIBLTE_ERROR_ENUM liblte_rrc_pack_rf_params_ie(LIBLTE_RRC_RF_PARAMS_STRUCT *params, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_rf_params_ie(uint8 **ie_ptr, + LIBLTE_RRC_RF_PARAMS_STRUCT *params); + +typedef struct{ + bool inter_freq_need_for_gaps[LIBLTE_RRC_MAXBANDS]; + uint32 N_inter_freq_need_for_gaps; +}LIBLTE_RRC_BAND_INFO_EUTRA_STRUCT; + +LIBLTE_ERROR_ENUM liblte_rrc_pack_band_info_eutra_ie(LIBLTE_RRC_BAND_INFO_EUTRA_STRUCT *info, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_band_info_eutra_ie(uint8 **ie_ptr, + LIBLTE_RRC_BAND_INFO_EUTRA_STRUCT *info); + +typedef struct{ + LIBLTE_RRC_BAND_INFO_EUTRA_STRUCT band_list_eutra[LIBLTE_RRC_MAXBANDS]; + uint32 N_band_list_eutra; +}LIBLTE_RRC_MEAS_PARAMS_STRUCT; + +LIBLTE_ERROR_ENUM liblte_rrc_pack_meas_params_ie(LIBLTE_RRC_MEAS_PARAMS_STRUCT *params, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_meas_params_ie(uint8 **ie_ptr, + LIBLTE_RRC_MEAS_PARAMS_STRUCT *params); + +typedef struct{ + // WARNING: hardcoding these options to not present + bool utra_fdd_present; + bool utra_tdd128_present; + bool utra_tdd384_present; + bool utra_tdd768_present; + bool geran_present; + bool cdma2000_hrpd_present; + bool cdma2000_1xrtt_present; +}LIBLTE_RRC_INTER_RAT_PARAMS_STRUCT; + +LIBLTE_ERROR_ENUM liblte_rrc_pack_inter_rat_params_ie(LIBLTE_RRC_INTER_RAT_PARAMS_STRUCT *params, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_inter_rat_params_ie(uint8 **ie_ptr, + LIBLTE_RRC_INTER_RAT_PARAMS_STRUCT *params); + +typedef struct{ + uint8 access_stratum_release; + uint8 ue_category; + LIBLTE_RRC_PDCP_PARAMS_STRUCT pdcp_params; + LIBLTE_RRC_PHY_LAYER_PARAMS_STRUCT phy_params; + LIBLTE_RRC_RF_PARAMS_STRUCT rf_params; + LIBLTE_RRC_MEAS_PARAMS_STRUCT meas_params; + uint32 feature_group_indicator; + LIBLTE_RRC_INTER_RAT_PARAMS_STRUCT inter_rat_params; + bool feature_group_indicator_present; +}LIBLTE_RRC_UE_EUTRA_CAPABILITY_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_ue_eutra_capability_ie(LIBLTE_RRC_UE_EUTRA_CAPABILITY_STRUCT *ue_eutra_capability, + LIBLTE_BIT_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_ue_eutra_capability_ie(uint8 **ie_ptr, + LIBLTE_RRC_UE_EUTRA_CAPABILITY_STRUCT *ue_eutra_capability); + + +/********************************************************************* + IE Name: UE Timers and Constants + + Description: Contains timers and constants used by the UE in + either RRC_CONNECTED or RRC_IDLE + + Document Reference: 36.331 v10.0.0 Section 6.3.6 +*********************************************************************/ +// Defines +// Enums +typedef enum{ + LIBLTE_RRC_T300_MS100 = 0, + LIBLTE_RRC_T300_MS200, + LIBLTE_RRC_T300_MS300, + LIBLTE_RRC_T300_MS400, + LIBLTE_RRC_T300_MS600, + LIBLTE_RRC_T300_MS1000, + LIBLTE_RRC_T300_MS1500, + LIBLTE_RRC_T300_MS2000, + LIBLTE_RRC_T300_N_ITEMS, +}LIBLTE_RRC_T300_ENUM; +static const char liblte_rrc_t300_text[LIBLTE_RRC_T300_N_ITEMS][20] = { "100", "200", "300", "400", + "600", "1000", "1500", "2000"}; +static const uint16 liblte_rrc_t300_num[LIBLTE_RRC_T300_N_ITEMS] = {100, 200, 300, 400, 600, 1000, 1500, 2000}; +typedef enum{ + LIBLTE_RRC_T301_MS100 = 0, + LIBLTE_RRC_T301_MS200, + LIBLTE_RRC_T301_MS300, + LIBLTE_RRC_T301_MS400, + LIBLTE_RRC_T301_MS600, + LIBLTE_RRC_T301_MS1000, + LIBLTE_RRC_T301_MS1500, + LIBLTE_RRC_T301_MS2000, + LIBLTE_RRC_T301_N_ITEMS, +}LIBLTE_RRC_T301_ENUM; +static const char liblte_rrc_t301_text[LIBLTE_RRC_T301_N_ITEMS][20] = { "100", "200", "300", "400", + "600", "1000", "1500", "2000"}; +static const uint16 liblte_rrc_t301_num[LIBLTE_RRC_T301_N_ITEMS] = {100, 200, 300, 400, 600, 1000, 1500, 2000}; +typedef enum{ + LIBLTE_RRC_T310_MS0 = 0, + LIBLTE_RRC_T310_MS50, + LIBLTE_RRC_T310_MS100, + LIBLTE_RRC_T310_MS200, + LIBLTE_RRC_T310_MS500, + LIBLTE_RRC_T310_MS1000, + LIBLTE_RRC_T310_MS2000, + LIBLTE_RRC_T310_N_ITEMS, +}LIBLTE_RRC_T310_ENUM; +static const char liblte_rrc_t310_text[LIBLTE_RRC_T310_N_ITEMS][20] = { "0", "50", "100", "200", + "500", "1000", "2000"}; +static const uint16 liblte_rrc_t310_num[LIBLTE_RRC_T310_N_ITEMS] = {0, 50, 100, 200, 500, 1000, 2000}; +typedef enum{ + LIBLTE_RRC_N310_N1 = 0, + LIBLTE_RRC_N310_N2, + LIBLTE_RRC_N310_N3, + LIBLTE_RRC_N310_N4, + LIBLTE_RRC_N310_N6, + LIBLTE_RRC_N310_N8, + LIBLTE_RRC_N310_N10, + LIBLTE_RRC_N310_N20, + LIBLTE_RRC_N310_N_ITEMS, +}LIBLTE_RRC_N310_ENUM; +static const char liblte_rrc_n310_text[LIBLTE_RRC_N310_N_ITEMS][20] = { "1", "2", "3", "4", + "6", "8", "10", "20"}; +static const uint8 liblte_rrc_n310_num[LIBLTE_RRC_N310_N_ITEMS] = {1, 2, 3, 4, 6, 8, 10, 20}; +typedef enum{ + LIBLTE_RRC_T311_MS1000 = 0, + LIBLTE_RRC_T311_MS3000, + LIBLTE_RRC_T311_MS5000, + LIBLTE_RRC_T311_MS10000, + LIBLTE_RRC_T311_MS15000, + LIBLTE_RRC_T311_MS20000, + LIBLTE_RRC_T311_MS30000, + LIBLTE_RRC_T311_N_ITEMS, +}LIBLTE_RRC_T311_ENUM; +static const char liblte_rrc_t311_text[LIBLTE_RRC_T311_N_ITEMS][20] = { "1000", "3000", "5000", "10000", + "15000", "20000", "30000"}; +static const uint16 liblte_rrc_t311_num[LIBLTE_RRC_T311_N_ITEMS] = {1000, 3000, 5000, 10000, 15000, 20000, 30000}; +typedef enum{ + LIBLTE_RRC_N311_N1 = 0, + LIBLTE_RRC_N311_N2, + LIBLTE_RRC_N311_N3, + LIBLTE_RRC_N311_N4, + LIBLTE_RRC_N311_N5, + LIBLTE_RRC_N311_N6, + LIBLTE_RRC_N311_N8, + LIBLTE_RRC_N311_N10, + LIBLTE_RRC_N311_N_ITEMS, +}LIBLTE_RRC_N311_ENUM; +static const char liblte_rrc_n311_text[LIBLTE_RRC_N311_N_ITEMS][20] = { "1", "2", "3", "4", + "5", "6", "8", "10"}; +static const uint8 liblte_rrc_n311_num[LIBLTE_RRC_N311_N_ITEMS] = {1, 2, 3, 4, 5, 6, 8, 10}; +// Structs +typedef struct{ + LIBLTE_RRC_T300_ENUM t300; + LIBLTE_RRC_T301_ENUM t301; + LIBLTE_RRC_T310_ENUM t310; + LIBLTE_RRC_N310_ENUM n310; + LIBLTE_RRC_T311_ENUM t311; + LIBLTE_RRC_N311_ENUM n311; +}LIBLTE_RRC_UE_TIMERS_AND_CONSTANTS_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_ue_timers_and_constants_ie(LIBLTE_RRC_UE_TIMERS_AND_CONSTANTS_STRUCT *ue_timers_and_constants, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_ue_timers_and_constants_ie(uint8 **ie_ptr, + LIBLTE_RRC_UE_TIMERS_AND_CONSTANTS_STRUCT *ue_timers_and_constants); + +/********************************************************************* + IE Name: Allowed Meas Bandwidth + + Description: Indicates the maximum allowed measurement bandwidth + on a carrier frequency as defined by the parameter + Transmission Bandwidth Configuration + + Document Reference: 36.331 v10.0.0 Section 6.3.5 +*********************************************************************/ +// Defines +// Enums +typedef enum{ + LIBLTE_RRC_ALLOWED_MEAS_BANDWIDTH_MBW6 = 0, + LIBLTE_RRC_ALLOWED_MEAS_BANDWIDTH_MBW15, + LIBLTE_RRC_ALLOWED_MEAS_BANDWIDTH_MBW25, + LIBLTE_RRC_ALLOWED_MEAS_BANDWIDTH_MBW50, + LIBLTE_RRC_ALLOWED_MEAS_BANDWIDTH_MBW75, + LIBLTE_RRC_ALLOWED_MEAS_BANDWIDTH_MBW100, + LIBLTE_RRC_ALLOWED_MEAS_BANDWIDTH_N_ITEMS, +}LIBLTE_RRC_ALLOWED_MEAS_BANDWIDTH_ENUM; +static const char liblte_rrc_allowed_meas_bandwidth_text[LIBLTE_RRC_ALLOWED_MEAS_BANDWIDTH_N_ITEMS][20] = {"1.4", "3", "5", "10", + "15", "20"}; +static const double liblte_rrc_allowed_meas_bandwidth_num[LIBLTE_RRC_ALLOWED_MEAS_BANDWIDTH_N_ITEMS] = {1.4, 3, 5, 10, 15, 20}; +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_allowed_meas_bandwidth_ie(LIBLTE_RRC_ALLOWED_MEAS_BANDWIDTH_ENUM allowed_meas_bw, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_allowed_meas_bandwidth_ie(uint8 **ie_ptr, + LIBLTE_RRC_ALLOWED_MEAS_BANDWIDTH_ENUM *allowed_meas_bw); + +/********************************************************************* + IE Name: Hysteresis + + Description: Used within the entry and leave condition of an + event triggered reporting condition + + Document Reference: 36.331 v10.0.0 Section 6.3.5 +*********************************************************************/ +// Defines +// Enums +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_hysteresis_ie(uint8 hysteresis, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_hysteresis_ie(uint8 **ie_ptr, + uint8 *hysteresis); + +/********************************************************************* + IE Name: Location Info + + Description: Transfers location information available at the UE to + correlate measurements and UE position information + + Document Reference: 36.331 v10.0.0 Section 6.3.5 +*********************************************************************/ +// Defines +// Enums +// Structs +// Functions +// FIXME + +/********************************************************************* + IE Name: Meas Config + + Description: Specifies measurements to be performed by the UE, + and covers intra-frequency, inter-frequency and + inter-RAT mobility as well as configuration of + measurement gaps + + Document Reference: 36.331 v10.0.0 Section 6.3.5 +*********************************************************************/ +// Defines +#define LIBLTE_RRC_MAX_EXPLICIT_LIST_OF_ARFCNS 31 +#define LIBLTE_RRC_MAX_CELL_MEAS 32 +#define LIBLTE_RRC_MAX_OBJECT_ID 32 +#define LIBLTE_RRC_MAX_REPORT_CONFIG_ID 32 +#define LIBLTE_RRC_MAX_MEAS_ID 32 +// Enums +typedef enum{ + LIBLTE_RRC_BAND_CLASS_CDMA2000_BC0 = 0, + LIBLTE_RRC_BAND_CLASS_CDMA2000_BC1, + LIBLTE_RRC_BAND_CLASS_CDMA2000_BC2, + LIBLTE_RRC_BAND_CLASS_CDMA2000_BC3, + LIBLTE_RRC_BAND_CLASS_CDMA2000_BC4, + LIBLTE_RRC_BAND_CLASS_CDMA2000_BC5, + LIBLTE_RRC_BAND_CLASS_CDMA2000_BC6, + LIBLTE_RRC_BAND_CLASS_CDMA2000_BC7, + LIBLTE_RRC_BAND_CLASS_CDMA2000_BC8, + LIBLTE_RRC_BAND_CLASS_CDMA2000_BC9, + LIBLTE_RRC_BAND_CLASS_CDMA2000_BC10, + LIBLTE_RRC_BAND_CLASS_CDMA2000_BC11, + LIBLTE_RRC_BAND_CLASS_CDMA2000_BC12, + LIBLTE_RRC_BAND_CLASS_CDMA2000_BC13, + LIBLTE_RRC_BAND_CLASS_CDMA2000_BC14, + LIBLTE_RRC_BAND_CLASS_CDMA2000_BC15, + LIBLTE_RRC_BAND_CLASS_CDMA2000_BC16, + LIBLTE_RRC_BAND_CLASS_CDMA2000_BC17, + LIBLTE_RRC_BAND_CLASS_CDMA2000_SPARE14, + LIBLTE_RRC_BAND_CLASS_CDMA2000_SPARE13, + LIBLTE_RRC_BAND_CLASS_CDMA2000_SPARE12, + LIBLTE_RRC_BAND_CLASS_CDMA2000_SPARE11, + LIBLTE_RRC_BAND_CLASS_CDMA2000_SPARE10, + LIBLTE_RRC_BAND_CLASS_CDMA2000_SPARE9, + LIBLTE_RRC_BAND_CLASS_CDMA2000_SPARE8, + LIBLTE_RRC_BAND_CLASS_CDMA2000_SPARE7, + LIBLTE_RRC_BAND_CLASS_CDMA2000_SPARE6, + LIBLTE_RRC_BAND_CLASS_CDMA2000_SPARE5, + LIBLTE_RRC_BAND_CLASS_CDMA2000_SPARE4, + LIBLTE_RRC_BAND_CLASS_CDMA2000_SPARE3, + LIBLTE_RRC_BAND_CLASS_CDMA2000_SPARE2, + LIBLTE_RRC_BAND_CLASS_CDMA2000_SPARE1, + LIBLTE_RRC_BAND_CLASS_CDMA2000_N_ITEMS, +}LIBLTE_RRC_BAND_CLASS_CDMA2000_ENUM; +static const char liblte_rrc_band_class_cdma2000_text[LIBLTE_RRC_BAND_CLASS_CDMA2000_N_ITEMS][20] = { "0", "1", "2", "3", + "4", "5", "6", "7", + "8", "9", "10", "11", + "12", "13", "14", "15", + "16", "17", "SPARE", "SPARE", + "SPARE", "SPARE", "SPARE", "SPARE", + "SPARE", "SPARE", "SPARE", "SPARE", + "SPARE", "SPARE", "SPARE", "SPARE"}; +static const int8 liblte_rrc_band_class_cdma2000_num[LIBLTE_RRC_BAND_CLASS_CDMA2000_N_ITEMS] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; +typedef enum{ + LIBLTE_RRC_BAND_INDICATOR_GERAN_DCS1800 = 0, + LIBLTE_RRC_BAND_INDICATOR_GERAN_PCS1900, + LIBLTE_RRC_BAND_INDICATOR_GERAN_N_ITEMS, +}LIBLTE_RRC_BAND_INDICATOR_GERAN_ENUM; +static const char liblte_rrc_band_indicator_geran_text[LIBLTE_RRC_BAND_INDICATOR_GERAN_N_ITEMS][20] = {"DCS1800", "PCS1900"}; +typedef enum{ + LIBLTE_RRC_FOLLOWING_ARFCNS_EXPLICIT_LIST = 0, + LIBLTE_RRC_FOLLOWING_ARFCNS_EQUALLY_SPACED, + LIBLTE_RRC_FOLLOWING_ARFCNS_VARIABLE_BIT_MAP, + LIBLTE_RRC_FOLLOWING_ARFCNS_N_ITEMS, +}LIBLTE_RRC_FOLLOWING_ARFCNS_ENUM; +static const char liblte_rrc_following_arfcns_text[LIBLTE_RRC_FOLLOWING_ARFCNS_N_ITEMS][20] = {"Explicit List", "Equally Spaced", "Variable Bit Map"}; +typedef enum{ + LIBLTE_RRC_CDMA2000_TYPE_1XRTT = 0, + LIBLTE_RRC_CDMA2000_TYPE_HRPD, + LIBLTE_RRC_CDMA2000_TYPE_N_ITEMS, +}LIBLTE_RRC_CDMA2000_TYPE_ENUM; +static const char liblte_rrc_cdma2000_type_text[LIBLTE_RRC_CDMA2000_TYPE_N_ITEMS][20] = {"1xrtt", "hrpd"}; +typedef enum{ + LIBLTE_RRC_T_EVALUATION_S30 = 0, + LIBLTE_RRC_T_EVALUATION_S60, + LIBLTE_RRC_T_EVALUATION_S120, + LIBLTE_RRC_T_EVALUATION_S180, + LIBLTE_RRC_T_EVALUATION_S240, + LIBLTE_RRC_T_EVALUATION_SPARE3, + LIBLTE_RRC_T_EVALUATION_SPARE2, + LIBLTE_RRC_T_EVALUATION_SPARE1, + LIBLTE_RRC_T_EVALUATION_N_ITEMS, +}LIBLTE_RRC_T_EVALUATION_ENUM; +static const char liblte_rrc_t_evaluation_text[LIBLTE_RRC_T_EVALUATION_N_ITEMS][20] = { "30", "60", "120", "180", + "240", "SPARE", "SPARE", "SPARE"}; +static const int16 liblte_rrc_t_evaluation_num[LIBLTE_RRC_T_EVALUATION_N_ITEMS] = {30, 60, 120, 180, 240, -1, -1, -1}; +typedef enum{ + LIBLTE_RRC_T_HYST_NORMAL_S30 = 0, + LIBLTE_RRC_T_HYST_NORMAL_S60, + LIBLTE_RRC_T_HYST_NORMAL_S120, + LIBLTE_RRC_T_HYST_NORMAL_S180, + LIBLTE_RRC_T_HYST_NORMAL_S240, + LIBLTE_RRC_T_HYST_NORMAL_SPARE3, + LIBLTE_RRC_T_HYST_NORMAL_SPARE2, + LIBLTE_RRC_T_HYST_NORMAL_SPARE1, + LIBLTE_RRC_T_HYST_NORMAL_N_ITEMS, +}LIBLTE_RRC_T_HYST_NORMAL_ENUM; +static const char liblte_rrc_t_hyst_normal_text[LIBLTE_RRC_T_HYST_NORMAL_N_ITEMS][20] = { "30", "60", "120", "180", + "240", "SPARE", "SPARE", "SPARE"}; +static const int16 liblte_rrc_t_hyst_normal_num[LIBLTE_RRC_T_HYST_NORMAL_N_ITEMS] = {30, 60, 120, 180, 240, -1, -1, -1}; +typedef enum{ + LIBLTE_RRC_PHYS_CELL_ID_RANGE_N4 = 0, + LIBLTE_RRC_PHYS_CELL_ID_RANGE_N8, + LIBLTE_RRC_PHYS_CELL_ID_RANGE_N12, + LIBLTE_RRC_PHYS_CELL_ID_RANGE_N16, + LIBLTE_RRC_PHYS_CELL_ID_RANGE_N24, + LIBLTE_RRC_PHYS_CELL_ID_RANGE_N32, + LIBLTE_RRC_PHYS_CELL_ID_RANGE_N48, + LIBLTE_RRC_PHYS_CELL_ID_RANGE_N64, + LIBLTE_RRC_PHYS_CELL_ID_RANGE_N84, + LIBLTE_RRC_PHYS_CELL_ID_RANGE_N96, + LIBLTE_RRC_PHYS_CELL_ID_RANGE_N128, + LIBLTE_RRC_PHYS_CELL_ID_RANGE_N168, + LIBLTE_RRC_PHYS_CELL_ID_RANGE_N252, + LIBLTE_RRC_PHYS_CELL_ID_RANGE_N504, + LIBLTE_RRC_PHYS_CELL_ID_RANGE_SPARE2, + LIBLTE_RRC_PHYS_CELL_ID_RANGE_SPARE1, + LIBLTE_RRC_PHYS_CELL_ID_RANGE_N1, + LIBLTE_RRC_PHYS_CELL_ID_RANGE_N_ITEMS, +}LIBLTE_RRC_PHYS_CELL_ID_RANGE_ENUM; +static const char liblte_rrc_phys_cell_id_range_text[LIBLTE_RRC_PHYS_CELL_ID_RANGE_N_ITEMS][20] = { "4", "8", "12", "16", + "24", "32", "48", "64", + "84", "96", "128", "168", + "252", "504", "SPARE", "SPARE", + "1"}; +static const int16 liblte_rrc_phys_cell_id_range_num[LIBLTE_RRC_PHYS_CELL_ID_RANGE_N_ITEMS] = {4, 8, 12, 16, 24, 32, 48, 64, 84, 96, 128, 168, 252, 504, -1, -1, 1}; +typedef enum{ + LIBLTE_RRC_Q_OFFSET_RANGE_DB_N24 = 0, + LIBLTE_RRC_Q_OFFSET_RANGE_DB_N22, + LIBLTE_RRC_Q_OFFSET_RANGE_DB_N20, + LIBLTE_RRC_Q_OFFSET_RANGE_DB_N18, + LIBLTE_RRC_Q_OFFSET_RANGE_DB_N16, + LIBLTE_RRC_Q_OFFSET_RANGE_DB_N14, + LIBLTE_RRC_Q_OFFSET_RANGE_DB_N12, + LIBLTE_RRC_Q_OFFSET_RANGE_DB_N10, + LIBLTE_RRC_Q_OFFSET_RANGE_DB_N8, + LIBLTE_RRC_Q_OFFSET_RANGE_DB_N6, + LIBLTE_RRC_Q_OFFSET_RANGE_DB_N5, + LIBLTE_RRC_Q_OFFSET_RANGE_DB_N4, + LIBLTE_RRC_Q_OFFSET_RANGE_DB_N3, + LIBLTE_RRC_Q_OFFSET_RANGE_DB_N2, + LIBLTE_RRC_Q_OFFSET_RANGE_DB_N1, + LIBLTE_RRC_Q_OFFSET_RANGE_DB_0, + LIBLTE_RRC_Q_OFFSET_RANGE_DB_1, + LIBLTE_RRC_Q_OFFSET_RANGE_DB_2, + LIBLTE_RRC_Q_OFFSET_RANGE_DB_3, + LIBLTE_RRC_Q_OFFSET_RANGE_DB_4, + LIBLTE_RRC_Q_OFFSET_RANGE_DB_5, + LIBLTE_RRC_Q_OFFSET_RANGE_DB_6, + LIBLTE_RRC_Q_OFFSET_RANGE_DB_8, + LIBLTE_RRC_Q_OFFSET_RANGE_DB_10, + LIBLTE_RRC_Q_OFFSET_RANGE_DB_12, + LIBLTE_RRC_Q_OFFSET_RANGE_DB_14, + LIBLTE_RRC_Q_OFFSET_RANGE_DB_16, + LIBLTE_RRC_Q_OFFSET_RANGE_DB_18, + LIBLTE_RRC_Q_OFFSET_RANGE_DB_20, + LIBLTE_RRC_Q_OFFSET_RANGE_DB_22, + LIBLTE_RRC_Q_OFFSET_RANGE_DB_24, + LIBLTE_RRC_Q_OFFSET_RANGE_N_ITEMS, +}LIBLTE_RRC_Q_OFFSET_RANGE_ENUM; +static const char liblte_rrc_q_offset_range_text[LIBLTE_RRC_Q_OFFSET_RANGE_N_ITEMS][20] = {"-24", "-22", "-20", "-18", + "-16", "-14", "-12", "-10", + "-8", "-6", "-5", "-4", + "-3", "-2", "-1", "0", + "1", "2", "3", "4", + "5", "6", "8", "10", + "12", "14", "16", "18", + "20", "22", "24"}; +static const int8 liblte_rrc_q_offset_range_num[LIBLTE_RRC_Q_OFFSET_RANGE_N_ITEMS] = {-24, -22, -20, -18, -16, -14, -12, -10, -8, -6, -5, -4, -3, -2, -1, 0, + 1, 2, 3, 4, 5, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24}; +typedef enum{ + LIBLTE_RRC_SSSF_MEDIUM_0DOT25 = 0, + LIBLTE_RRC_SSSF_MEDIUM_0DOT5, + LIBLTE_RRC_SSSF_MEDIUM_0DOT75, + LIBLTE_RRC_SSSF_MEDIUM_1DOT0, + LIBLTE_RRC_SSSF_MEDIUM_N_ITEMS, +}LIBLTE_RRC_SSSF_MEDIUM_ENUM; +static const char liblte_rrc_sssf_medium_text[LIBLTE_RRC_SSSF_MEDIUM_N_ITEMS][20] = {"0.25", "0.5", "0.75", "1.0"}; +static const double liblte_rrc_sssf_medium_num[LIBLTE_RRC_SSSF_MEDIUM_N_ITEMS] = {0.25, 0.5, 0.75, 1.0}; +typedef enum{ + LIBLTE_RRC_SSSF_HIGH_0DOT25 = 0, + LIBLTE_RRC_SSSF_HIGH_0DOT5, + LIBLTE_RRC_SSSF_HIGH_0DOT75, + LIBLTE_RRC_SSSF_HIGH_1DOT0, + LIBLTE_RRC_SSSF_HIGH_N_ITEMS, +}LIBLTE_RRC_SSSF_HIGH_ENUM; +static const char liblte_rrc_sssf_high_text[LIBLTE_RRC_SSSF_HIGH_N_ITEMS][20] = {"0.25", "0.5", "0.75", "1.0"}; +static const double liblte_rrc_sssf_high_num[LIBLTE_RRC_SSSF_HIGH_N_ITEMS] = {0.25, 0.5, 0.75, 1.0}; +typedef enum{ + LIBLTE_RRC_GAP_OFFSET_TYPE_GP0 = 0, + LIBLTE_RRC_GAP_OFFSET_TYPE_GP1, + LIBLTE_RRC_GAP_OFFSET_TYPE_N_ITEMS, +}LIBLTE_RRC_GAP_OFFSET_TYPE_ENUM; +static const char liblte_rrc_gap_offset_type_text[LIBLTE_RRC_GAP_OFFSET_TYPE_N_ITEMS][20] = {"GP0", + "GP1"}; +typedef enum{ + LIBLTE_RRC_UTRA_SYSTEM_TYPE_FDD = 0, + LIBLTE_RRC_UTRA_SYSTEM_TYPE_TDD, + LIBLTE_RRC_UTRA_SYSTEM_TYPE_N_ITEMS, +}LIBLTE_RRC_UTRA_SYSTEM_TYPE_ENUM; +static const char liblte_rrc_utra_system_type_text[LIBLTE_RRC_UTRA_SYSTEM_TYPE_N_ITEMS][20] = {"FDD", + "TDD"}; +typedef enum{ + LIBLTE_RRC_MEAS_OBJECT_TYPE_EUTRA = 0, + LIBLTE_RRC_MEAS_OBJECT_TYPE_UTRA, + LIBLTE_RRC_MEAS_OBJECT_TYPE_GERAN, + LIBLTE_RRC_MEAS_OBJECT_TYPE_CDMA2000, + LIBLTE_RRC_MEAS_OBJECT_TYPE_N_ITEMS, +}LIBLTE_RRC_MEAS_OBJECT_TYPE_ENUM; +static const char liblte_rrc_meas_object_type_text[LIBLTE_RRC_MEAS_OBJECT_TYPE_N_ITEMS][20] = {"EUTRA", + "UTRA", + "GERAN", + "CDMA2000"}; +typedef enum{ + LIBLTE_RRC_MEAS_QUANTITY_UTRA_FDD_CPICH_RSCP = 0, + LIBLTE_RRC_MEAS_QUANTITY_UTRA_FDD_CPICH_ECNO, + LIBLTE_RRC_MEAS_QUANTITY_UTRA_FDD_N_ITEMS, +}LIBLTE_RRC_MEAS_QUANTITY_UTRA_FDD_ENUM; +static const char liblte_rrc_meas_quantity_utra_fdd_text[LIBLTE_RRC_MEAS_QUANTITY_UTRA_FDD_N_ITEMS][20] = {"CPICH RSCP", + "CPICH Ec/No"}; +typedef enum{ + LIBLTE_RRC_MEAS_QUANTITY_UTRA_TDD_PCCPCH_RSCP = 0, + LIBLTE_RRC_MEAS_QUANTITY_UTRA_TDD_N_ITEMS, +}LIBLTE_RRC_MEAS_QUANTITY_UTRA_TDD_ENUM; +static const char liblte_rrc_meas_quantity_utra_tdd_text[LIBLTE_RRC_MEAS_QUANTITY_UTRA_TDD_N_ITEMS][20] = {"PCCPCH RSCP"}; +typedef enum{ + LIBLTE_RRC_MEAS_QUANTITY_GERAN_RSSI = 0, + LIBLTE_RRC_MEAS_QUANTITY_GERAN_N_ITEMS, +}LIBLTE_RRC_MEAS_QUANTITY_GERAN_ENUM; +static const char liblte_rrc_meas_quantity_geran_text[LIBLTE_RRC_MEAS_QUANTITY_GERAN_N_ITEMS][20] = {"RSSI"}; +typedef enum{ + LIBLTE_RRC_MEAS_QUANTITY_CDMA2000_PILOT_STRENGTH = 0, + LIBLTE_RRC_MEAS_QUANTITY_CDMA2000_PILOT_PN_PHASE_AND_STRENGTH, + LIBLTE_RRC_MEAS_QUANTITY_CDMA2000_N_ITEMS, +}LIBLTE_RRC_MEAS_QUANTITY_CDMA2000_ENUM; +static const char liblte_rrc_meas_quantity_cdma2000_text[LIBLTE_RRC_MEAS_QUANTITY_CDMA2000_N_ITEMS][100] = {"Pilot Strength", + "Pilot PN Phase and Strength"}; +typedef enum{ + LIBLTE_RRC_REPORT_INTERVAL_MS120 = 0, + LIBLTE_RRC_REPORT_INTERVAL_MS240, + LIBLTE_RRC_REPORT_INTERVAL_MS480, + LIBLTE_RRC_REPORT_INTERVAL_MS640, + LIBLTE_RRC_REPORT_INTERVAL_MS1024, + LIBLTE_RRC_REPORT_INTERVAL_MS2048, + LIBLTE_RRC_REPORT_INTERVAL_MS5120, + LIBLTE_RRC_REPORT_INTERVAL_MS10240, + LIBLTE_RRC_REPORT_INTERVAL_MIN1, + LIBLTE_RRC_REPORT_INTERVAL_MIN6, + LIBLTE_RRC_REPORT_INTERVAL_MIN12, + LIBLTE_RRC_REPORT_INTERVAL_MIN30, + LIBLTE_RRC_REPORT_INTERVAL_MIN60, + LIBLTE_RRC_REPORT_INTERVAL_SPARE3, + LIBLTE_RRC_REPORT_INTERVAL_SPARE2, + LIBLTE_RRC_REPORT_INTERVAL_SPARE1, + LIBLTE_RRC_REPORT_INTERVAL_N_ITEMS, +}LIBLTE_RRC_REPORT_INTERVAL_ENUM; +static const char liblte_rrc_report_interval_text[LIBLTE_RRC_REPORT_INTERVAL_N_ITEMS][20] = { "120", "240", "480", "640", + "1024", "2048", "5120", "10240", + "60000", "360000", "720000", "1800000", + "3600000", "SPARE", "SPARE", "SPARE"}; +static const int32 liblte_rrc_report_interval_num[LIBLTE_RRC_REPORT_INTERVAL_N_ITEMS] = {120, 240, 480, 640, 1024, 2048, 5120, 10240, 60000, 360000, 720000, 1800000, 3600000, -1, -1, -1}; +typedef enum{ + LIBLTE_RRC_TIME_TO_TRIGGER_MS0 = 0, + LIBLTE_RRC_TIME_TO_TRIGGER_MS40, + LIBLTE_RRC_TIME_TO_TRIGGER_MS64, + LIBLTE_RRC_TIME_TO_TRIGGER_MS80, + LIBLTE_RRC_TIME_TO_TRIGGER_MS100, + LIBLTE_RRC_TIME_TO_TRIGGER_MS128, + LIBLTE_RRC_TIME_TO_TRIGGER_MS160, + LIBLTE_RRC_TIME_TO_TRIGGER_MS256, + LIBLTE_RRC_TIME_TO_TRIGGER_MS320, + LIBLTE_RRC_TIME_TO_TRIGGER_MS480, + LIBLTE_RRC_TIME_TO_TRIGGER_MS512, + LIBLTE_RRC_TIME_TO_TRIGGER_MS640, + LIBLTE_RRC_TIME_TO_TRIGGER_MS1024, + LIBLTE_RRC_TIME_TO_TRIGGER_MS1280, + LIBLTE_RRC_TIME_TO_TRIGGER_MS2560, + LIBLTE_RRC_TIME_TO_TRIGGER_MS5120, + LIBLTE_RRC_TIME_TO_TRIGGER_N_ITEMS, +}LIBLTE_RRC_TIME_TO_TRIGGER_ENUM; +static const char liblte_rrc_time_to_trigger_text[LIBLTE_RRC_TIME_TO_TRIGGER_N_ITEMS][20] = { "0", "40", "64", "80", + "100", "128", "160", "256", + "320", "480", "512", "640", + "1024", "1280", "2560", "5120"}; +static const uint16 liblte_rrc_time_to_trigger_num[LIBLTE_RRC_TIME_TO_TRIGGER_N_ITEMS] = {0, 40, 64, 80, 100, 128, 160, 256, 320, 480, 512, 640, 1024, 1280, 2560, 5120}; +typedef enum{ + LIBLTE_RRC_THRESHOLD_EUTRA_TYPE_RSRP = 0, + LIBLTE_RRC_THRESHOLD_EUTRA_TYPE_RSRQ, + LIBLTE_RRC_THRESHOLD_EUTRA_TYPE_N_ITEMS, +}LIBLTE_RRC_THRESHOLD_EUTRA_TYPE_ENUM; +static const char liblte_rrc_threshold_eutra_type_text[LIBLTE_RRC_THRESHOLD_EUTRA_TYPE_N_ITEMS][20] = {"RSRP", + "RSRQ"}; +typedef enum{ + LIBLTE_RRC_EVENT_ID_EUTRA_A1 = 0, + LIBLTE_RRC_EVENT_ID_EUTRA_A2, + LIBLTE_RRC_EVENT_ID_EUTRA_A3, + LIBLTE_RRC_EVENT_ID_EUTRA_A4, + LIBLTE_RRC_EVENT_ID_EUTRA_A5, + LIBLTE_RRC_EVENT_ID_EUTRA_A6, + LIBLTE_RRC_EVENT_ID_EUTRA_N_ITEMS, +}LIBLTE_RRC_EVENT_ID_EUTRA_ENUM; +static const char liblte_rrc_event_id_eutra_text[LIBLTE_RRC_EVENT_ID_EUTRA_N_ITEMS][20] = {"A1", "A2", "A3", + "A4", "A5", "A6"}; +typedef enum{ + LIBLTE_RRC_PURPOSE_EUTRA_REPORT_STRONGEST_CELL = 0, + LIBLTE_RRC_PURPOSE_EUTRA_REPORT_CGI, + LIBLTE_RRC_PURPOSE_EUTRA_N_ITEMS, +}LIBLTE_RRC_PURPOSE_EUTRA_ENUM; +static const char liblte_rrc_purpose_eutra_text[LIBLTE_RRC_PURPOSE_EUTRA_N_ITEMS][100] = {"Report Strongest Cell", + "Report CGI"}; +typedef enum{ + LIBLTE_RRC_TRIGGER_TYPE_EUTRA_EVENT = 0, + LIBLTE_RRC_TRIGGER_TYPE_EUTRA_PERIODICAL, + LIBLTE_RRC_TRIGGER_TYPE_EUTRA_N_ITEMS, +}LIBLTE_RRC_TRIGGER_TYPE_EUTRA_ENUM; +static const char liblte_rrc_trigger_type_eutra_text[LIBLTE_RRC_TRIGGER_TYPE_EUTRA_N_ITEMS][20] = {"Event", + "Periodical"}; +typedef enum{ + LIBLTE_RRC_TRIGGER_QUANTITY_RSRP = 0, + LIBLTE_RRC_TRIGGER_QUANTITY_RSRQ, + LIBLTE_RRC_TRIGGER_QUANTITY_N_ITEMS, +}LIBLTE_RRC_TRIGGER_QUANTITY_ENUM; +static const char liblte_rrc_trigger_quantity_text[LIBLTE_RRC_TRIGGER_QUANTITY_N_ITEMS][20] = {"RSRP", + "RSRQ"}; +typedef enum{ + LIBLTE_RRC_REPORT_QUANTITY_SAME_AS_TRIGGER_QUANTITY = 0, + LIBLTE_RRC_REPORT_QUANTITY_BOTH, + LIBLTE_RRC_REPORT_QUANTITY_N_ITEMS, +}LIBLTE_RRC_REPORT_QUANTITY_ENUM; +static const char liblte_rrc_report_quantity_text[LIBLTE_RRC_REPORT_QUANTITY_N_ITEMS][100] = {"Same As Trigger Quantity", + "Both"}; +typedef enum{ + LIBLTE_RRC_REPORT_AMOUNT_R1 = 0, + LIBLTE_RRC_REPORT_AMOUNT_R2, + LIBLTE_RRC_REPORT_AMOUNT_R4, + LIBLTE_RRC_REPORT_AMOUNT_R8, + LIBLTE_RRC_REPORT_AMOUNT_R16, + LIBLTE_RRC_REPORT_AMOUNT_R32, + LIBLTE_RRC_REPORT_AMOUNT_R64, + LIBLTE_RRC_REPORT_AMOUNT_INFINITY, + LIBLTE_RRC_REPORT_AMOUNT_N_ITEMS, +}LIBLTE_RRC_REPORT_AMOUNT_ENUM; +static const char liblte_rrc_report_amount_text[LIBLTE_RRC_REPORT_AMOUNT_N_ITEMS][20] = { "r1", "r2", "r4", "r8", + "r16", "r32", "r64", "INFINITY"}; +typedef enum{ + LIBLTE_RRC_THRESHOLD_UTRA_TYPE_RSCP = 0, + LIBLTE_RRC_THRESHOLD_UTRA_TYPE_ECNO, + LIBLTE_RRC_THRESHOLD_UTRA_TYPE_N_ITEMS, +}LIBLTE_RRC_THRESHOLD_UTRA_TYPE_ENUM; +static const char liblte_rrc_threshold_utra_type_text[LIBLTE_RRC_THRESHOLD_UTRA_TYPE_N_ITEMS][20] = {"RSCP", + "Ec/No"}; +typedef enum{ + LIBLTE_RRC_THRESHOLD_INTER_RAT_TYPE_UTRA = 0, + LIBLTE_RRC_THRESHOLD_INTER_RAT_TYPE_GERAN, + LIBLTE_RRC_THRESHOLD_INTER_RAT_TYPE_CDMA2000, + LIBLTE_RRC_THRESHOLD_INTER_RAT_TYPE_N_ITEMS, +}LIBLTE_RRC_THRESHOLD_INTER_RAT_TYPE_ENUM; +static const char liblte_rrc_threshold_inter_rat_type_text[LIBLTE_RRC_THRESHOLD_INTER_RAT_TYPE_N_ITEMS][20] = {"UTRA", + "GERAN", + "CDMA2000"}; +typedef enum{ + LIBLTE_RRC_EVENT_ID_INTER_RAT_B1 = 0, + LIBLTE_RRC_EVENT_ID_INTER_RAT_B2, + LIBLTE_RRC_EVENT_ID_INTER_RAT_N_ITEMS, +}LIBLTE_RRC_EVENT_ID_INTER_RAT_ENUM; +static const char liblte_rrc_event_id_inter_rat_text[LIBLTE_RRC_EVENT_ID_INTER_RAT_N_ITEMS][20] = {"B1", + "B2"}; +typedef enum{ + LIBLTE_RRC_PURPOSE_INTER_RAT_REPORT_STRONGEST_CELLS = 0, + LIBLTE_RRC_PURPOSE_INTER_RAT_REPORT_STRONGEST_CELLS_FOR_SON, + LIBLTE_RRC_PURPOSE_INTER_RAT_REPORT_CGI, + LIBLTE_RRC_PURPOSE_INTER_RAT_N_ITEMS, +}LIBLTE_RRC_PURPOSE_INTER_RAT_ENUM; +static const char liblte_rrc_purpose_inter_rat_text[LIBLTE_RRC_PURPOSE_INTER_RAT_N_ITEMS][100] = {"Report Strongest Cells", + "Report Strongest Cells for SON", + "Report CGI"}; +typedef enum{ + LIBLTE_RRC_TRIGGER_TYPE_INTER_RAT_EVENT = 0, + LIBLTE_RRC_TRIGGER_TYPE_INTER_RAT_PERIODICAL, + LIBLTE_RRC_TRIGGER_TYPE_INTER_RAT_N_ITEMS, +}LIBLTE_RRC_TRIGGER_TYPE_INTER_RAT_ENUM; +static const char liblte_rrc_trigger_type_inter_rat_text[LIBLTE_RRC_TRIGGER_TYPE_INTER_RAT_N_ITEMS][20] = {"Event", + "Periodical"}; +typedef enum{ + LIBLTE_RRC_REPORT_CONFIG_TYPE_EUTRA = 0, + LIBLTE_RRC_REPORT_CONFIG_TYPE_INTER_RAT, + LIBLTE_RRC_REPORT_CONFIG_TYPE_N_ITEMS, +}LIBLTE_RRC_REPORT_CONFIG_TYPE_ENUM; +static const char liblte_rrc_report_config_type_text[LIBLTE_RRC_REPORT_CONFIG_TYPE_N_ITEMS][20] = {"EUTRA", + "Inter RAT"}; +// Structs +typedef struct{ + LIBLTE_RRC_BAND_CLASS_CDMA2000_ENUM bandclass; + uint16 arfcn; +}LIBLTE_RRC_CARRIER_FREQ_CDMA2000_STRUCT; +typedef struct{ + uint8 arfcn_spacing; + uint8 number_of_arfcns; +}LIBLTE_RRC_EQUALLY_SPACED_ARFCNS_STRUCT; +typedef struct{ + LIBLTE_RRC_EQUALLY_SPACED_ARFCNS_STRUCT equally_spaced_arfcns; + LIBLTE_RRC_BAND_INDICATOR_GERAN_ENUM band_indicator; + LIBLTE_RRC_FOLLOWING_ARFCNS_ENUM following_arfcns; + uint16 starting_arfcn; + uint16 explicit_list_of_arfcns[LIBLTE_RRC_MAX_EXPLICIT_LIST_OF_ARFCNS]; + uint16 variable_bit_map_of_arfcns; + uint8 explicit_list_of_arfcns_size; +}LIBLTE_RRC_CARRIER_FREQS_GERAN_STRUCT; +typedef struct{ + uint32 N_cell_idx; + uint8 cell_idx[LIBLTE_RRC_MAX_CELL_MEAS]; +}LIBLTE_RRC_CELL_INDEX_LIST_STRUCT; +typedef struct{ + LIBLTE_RRC_T_EVALUATION_ENUM t_eval; + LIBLTE_RRC_T_HYST_NORMAL_ENUM t_hyst_normal; + uint8 n_cell_change_medium; + uint8 n_cell_change_high; +}LIBLTE_RRC_MOBILITY_STATE_PARAMETERS_STRUCT; +typedef struct{ + LIBLTE_RRC_PHYS_CELL_ID_RANGE_ENUM range; + uint16 start; +}LIBLTE_RRC_PHYS_CELL_ID_RANGE_STRUCT; +typedef struct{ + uint8 ncc; + uint8 bcc; +}LIBLTE_RRC_PHYS_CELL_ID_GERAN_STRUCT; +typedef struct{ + uint8 pre_reg_zone_id; + uint8 secondary_pre_reg_zone_id_list[2]; + uint8 secondary_pre_reg_zone_id_list_size; + bool pre_reg_allowed; + bool pre_reg_zone_id_present; +}LIBLTE_RRC_PRE_REGISTRATION_INFO_HRPD_STRUCT; +typedef struct{ + LIBLTE_RRC_SSSF_MEDIUM_ENUM sf_medium; + LIBLTE_RRC_SSSF_HIGH_ENUM sf_high; +}LIBLTE_RRC_SPEED_STATE_SCALE_FACTORS_STRUCT; +typedef struct{ + LIBLTE_RRC_GAP_OFFSET_TYPE_ENUM gap_offset_type; + uint8 gap_offset; + bool setup_present; +}LIBLTE_RRC_MEAS_GAP_CONFIG_STRUCT; +typedef struct{ + uint8 meas_id; + uint8 meas_obj_id; + uint8 rep_cnfg_id; +}LIBLTE_RRC_MEAS_ID_TO_ADD_MOD_STRUCT; +typedef struct{ + LIBLTE_RRC_MEAS_ID_TO_ADD_MOD_STRUCT meas_id_list[LIBLTE_RRC_MAX_MEAS_ID]; + uint32 N_meas_id; +}LIBLTE_RRC_MEAS_ID_TO_ADD_MOD_LIST_STRUCT; +typedef struct{ + uint16 pci; + uint8 cell_idx; +}LIBLTE_RRC_CELLS_TO_ADD_MOD_CDMA2000_STRUCT; +typedef struct{ + LIBLTE_RRC_CARRIER_FREQ_CDMA2000_STRUCT carrier_freq; + LIBLTE_RRC_CELL_INDEX_LIST_STRUCT cells_to_remove_list; + LIBLTE_RRC_CELLS_TO_ADD_MOD_CDMA2000_STRUCT cells_to_add_mod_list[LIBLTE_RRC_MAX_CELL_MEAS]; + LIBLTE_RRC_CDMA2000_TYPE_ENUM cdma2000_type; + uint32 N_cells_to_add_mod; + uint16 cell_for_which_to_rep_cgi; + uint8 search_win_size; + int8 offset_freq; + bool search_win_size_present; + bool cells_to_remove_list_present; + bool cell_for_which_to_rep_cgi_present; +}LIBLTE_RRC_MEAS_OBJECT_CDMA2000_STRUCT; +typedef struct{ + LIBLTE_RRC_Q_OFFSET_RANGE_ENUM cell_offset; + uint16 pci; + uint8 cell_idx; +}LIBLTE_RRC_CELLS_TO_ADD_MOD_STRUCT; +typedef struct{ + LIBLTE_RRC_PHYS_CELL_ID_RANGE_STRUCT pci_range; + uint8 cell_idx; +}LIBLTE_RRC_BLACK_CELLS_TO_ADD_MOD_STRUCT; +typedef struct{ + LIBLTE_RRC_CELL_INDEX_LIST_STRUCT cells_to_remove_list; + LIBLTE_RRC_CELLS_TO_ADD_MOD_STRUCT cells_to_add_mod_list[LIBLTE_RRC_MAX_CELL_MEAS]; + LIBLTE_RRC_CELL_INDEX_LIST_STRUCT black_cells_to_remove_list; + LIBLTE_RRC_BLACK_CELLS_TO_ADD_MOD_STRUCT black_cells_to_add_mod_list[LIBLTE_RRC_MAX_CELL_MEAS]; + LIBLTE_RRC_ALLOWED_MEAS_BANDWIDTH_ENUM allowed_meas_bw; + LIBLTE_RRC_Q_OFFSET_RANGE_ENUM offset_freq; + uint32 N_cells_to_add_mod; + uint32 N_black_cells_to_add_mod; + uint16 carrier_freq; + uint16 cell_for_which_to_rep_cgi; + uint8 neigh_cell_cnfg; + bool offset_freq_not_default; + bool presence_ant_port_1; + bool cells_to_remove_list_present; + bool black_cells_to_remove_list_present; + bool cell_for_which_to_rep_cgi_present; +}LIBLTE_RRC_MEAS_OBJECT_EUTRA_STRUCT; +typedef struct{ + LIBLTE_RRC_CARRIER_FREQS_GERAN_STRUCT carrier_freqs; + LIBLTE_RRC_PHYS_CELL_ID_GERAN_STRUCT cell_for_which_to_rep_cgi; + int8 offset_freq; + uint8 ncc_permitted; + bool cell_for_which_to_rep_cgi_present; +}LIBLTE_RRC_MEAS_OBJECT_GERAN_STRUCT; +typedef struct{ + uint16 pci; + uint8 cell_idx; +}LIBLTE_RRC_CELLS_TO_ADD_MOD_LIST_UTRA_FDD_STRUCT; +typedef struct{ + uint8 cell_idx; + uint8 pci; +}LIBLTE_RRC_CELLS_TO_ADD_MOD_LIST_UTRA_TDD_STRUCT; +typedef struct{ + LIBLTE_RRC_CELLS_TO_ADD_MOD_LIST_UTRA_FDD_STRUCT cells_fdd[LIBLTE_RRC_MAX_CELL_MEAS]; + LIBLTE_RRC_CELLS_TO_ADD_MOD_LIST_UTRA_TDD_STRUCT cells_tdd[LIBLTE_RRC_MAX_CELL_MEAS]; + LIBLTE_RRC_UTRA_SYSTEM_TYPE_ENUM type; + uint32 N_cells; +}LIBLTE_RRC_CELLS_TO_ADD_MOD_LIST_UTRA_STRUCT; +typedef struct{ + LIBLTE_RRC_UTRA_SYSTEM_TYPE_ENUM type; + uint16 pci_fdd; + uint8 pci_tdd; +}LIBLTE_RRC_CELLS_FOR_WHICH_TO_REPORT_CGI_STRUCT; +typedef struct{ + LIBLTE_RRC_CELL_INDEX_LIST_STRUCT cells_to_remove_list; + LIBLTE_RRC_CELLS_TO_ADD_MOD_LIST_UTRA_STRUCT cells_to_add_mod_list; + LIBLTE_RRC_CELLS_FOR_WHICH_TO_REPORT_CGI_STRUCT cells_for_which_to_rep_cgi; + uint16 carrier_freq; + int8 offset_freq; + bool cells_to_remove_list_present; + bool cells_to_add_mod_list_present; + bool cells_for_which_to_rep_cgi_present; +}LIBLTE_RRC_MEAS_OBJECT_UTRA_STRUCT; +typedef struct{ + LIBLTE_RRC_MEAS_OBJECT_EUTRA_STRUCT meas_obj_eutra; + LIBLTE_RRC_MEAS_OBJECT_UTRA_STRUCT meas_obj_utra; + LIBLTE_RRC_MEAS_OBJECT_GERAN_STRUCT meas_obj_geran; + LIBLTE_RRC_MEAS_OBJECT_CDMA2000_STRUCT meas_obj_cdma2000; + LIBLTE_RRC_MEAS_OBJECT_TYPE_ENUM meas_obj_type; + uint8 meas_obj_id; +}LIBLTE_RRC_MEAS_OBJECT_TO_ADD_MOD_STRUCT; +typedef struct{ + LIBLTE_RRC_MEAS_OBJECT_TO_ADD_MOD_STRUCT meas_obj_list[LIBLTE_RRC_MAX_OBJECT_ID]; + uint32 N_meas_obj; +}LIBLTE_RRC_MEAS_OBJECT_TO_ADD_MOD_LIST_STRUCT; +typedef struct{ + LIBLTE_RRC_FILTER_COEFFICIENT_ENUM fc_rsrp; + LIBLTE_RRC_FILTER_COEFFICIENT_ENUM fc_rsrq; + bool fc_rsrp_not_default; + bool fc_rsrq_not_default; +}LIBLTE_RRC_QUANTITY_CONFIG_EUTRA_STRUCT; +typedef struct{ + LIBLTE_RRC_MEAS_QUANTITY_UTRA_FDD_ENUM mq_fdd; + LIBLTE_RRC_MEAS_QUANTITY_UTRA_TDD_ENUM mq_tdd; + LIBLTE_RRC_FILTER_COEFFICIENT_ENUM fc; + bool fc_not_default; +}LIBLTE_RRC_QUANTITY_CONFIG_UTRA_STRUCT; +typedef struct{ + LIBLTE_RRC_MEAS_QUANTITY_GERAN_ENUM mq; + LIBLTE_RRC_FILTER_COEFFICIENT_ENUM fc; + bool fc_not_default; +}LIBLTE_RRC_QUANTITY_CONFIG_GERAN_STRUCT; +typedef struct{ + LIBLTE_RRC_MEAS_QUANTITY_CDMA2000_ENUM mq; +}LIBLTE_RRC_QUANTITY_CONFIG_CDMA2000_STRUCT; +typedef struct{ + LIBLTE_RRC_QUANTITY_CONFIG_EUTRA_STRUCT qc_eutra; + LIBLTE_RRC_QUANTITY_CONFIG_UTRA_STRUCT qc_utra; + LIBLTE_RRC_QUANTITY_CONFIG_GERAN_STRUCT qc_geran; + LIBLTE_RRC_QUANTITY_CONFIG_CDMA2000_STRUCT qc_cdma2000; + bool qc_eutra_present; + bool qc_utra_present; + bool qc_geran_present; + bool qc_cdma2000_present; +}LIBLTE_RRC_QUANTITY_CONFIG_STRUCT; +typedef struct{ + LIBLTE_RRC_THRESHOLD_EUTRA_TYPE_ENUM type; + uint8 range; +}LIBLTE_RRC_THRESHOLD_EUTRA_STRUCT; +typedef struct{ + LIBLTE_RRC_THRESHOLD_EUTRA_STRUCT eutra; +}LIBLTE_RRC_EVENT_A1_STRUCT; +typedef struct{ + LIBLTE_RRC_THRESHOLD_EUTRA_STRUCT eutra; +}LIBLTE_RRC_EVENT_A2_STRUCT; +typedef struct{ + int8 offset; + bool report_on_leave; +}LIBLTE_RRC_EVENT_A3_STRUCT; +typedef struct{ + LIBLTE_RRC_THRESHOLD_EUTRA_STRUCT eutra; +}LIBLTE_RRC_EVENT_A4_STRUCT; +typedef struct{ + LIBLTE_RRC_THRESHOLD_EUTRA_STRUCT eutra1; + LIBLTE_RRC_THRESHOLD_EUTRA_STRUCT eutra2; +}LIBLTE_RRC_EVENT_A5_STRUCT; +typedef struct{ + int8 offset; + bool report_on_leave; +}LIBLTE_RRC_EVENT_A6_STRUCT; +typedef struct{ + LIBLTE_RRC_EVENT_A1_STRUCT event_a1; + LIBLTE_RRC_EVENT_A2_STRUCT event_a2; + LIBLTE_RRC_EVENT_A3_STRUCT event_a3; + LIBLTE_RRC_EVENT_A4_STRUCT event_a4; + LIBLTE_RRC_EVENT_A5_STRUCT event_a5; + LIBLTE_RRC_EVENT_A6_STRUCT event_a6; + LIBLTE_RRC_EVENT_ID_EUTRA_ENUM event_id; + LIBLTE_RRC_TIME_TO_TRIGGER_ENUM time_to_trigger; + uint8 hysteresis; +}LIBLTE_RRC_EVENT_EUTRA_STRUCT; +typedef struct{ + LIBLTE_RRC_PURPOSE_EUTRA_ENUM purpose; +}LIBLTE_RRC_PERIODICAL_EUTRA_STRUCT; +typedef struct{ + LIBLTE_RRC_EVENT_EUTRA_STRUCT event; + LIBLTE_RRC_PERIODICAL_EUTRA_STRUCT periodical; + LIBLTE_RRC_TRIGGER_TYPE_EUTRA_ENUM trigger_type; + LIBLTE_RRC_TRIGGER_QUANTITY_ENUM trigger_quantity; + LIBLTE_RRC_REPORT_QUANTITY_ENUM report_quantity; + LIBLTE_RRC_REPORT_INTERVAL_ENUM report_interval; + LIBLTE_RRC_REPORT_AMOUNT_ENUM report_amount; + uint8 max_report_cells; +}LIBLTE_RRC_REPORT_CONFIG_EUTRA_STRUCT; +typedef struct{ + LIBLTE_RRC_THRESHOLD_UTRA_TYPE_ENUM type; + int8 value; +}LIBLTE_RRC_THRESHOLD_UTRA_STRUCT; +typedef struct{ + LIBLTE_RRC_THRESHOLD_UTRA_STRUCT utra; + LIBLTE_RRC_THRESHOLD_INTER_RAT_TYPE_ENUM type; + uint8 geran; + uint8 cdma2000; +}LIBLTE_RRC_EVENT_B1_STRUCT; +typedef struct{ + LIBLTE_RRC_THRESHOLD_UTRA_STRUCT utra; + LIBLTE_RRC_THRESHOLD_EUTRA_STRUCT eutra; + LIBLTE_RRC_THRESHOLD_INTER_RAT_TYPE_ENUM type2; + uint8 geran; + uint8 cdma2000; +}LIBLTE_RRC_EVENT_B2_STRUCT; +typedef struct{ + LIBLTE_RRC_EVENT_B1_STRUCT event_b1; + LIBLTE_RRC_EVENT_B2_STRUCT event_b2; + LIBLTE_RRC_EVENT_ID_INTER_RAT_ENUM event_id; + LIBLTE_RRC_TIME_TO_TRIGGER_ENUM time_to_trigger; + uint8 hysteresis; +}LIBLTE_RRC_EVENT_INTER_RAT_STRUCT; +typedef struct{ + LIBLTE_RRC_PURPOSE_INTER_RAT_ENUM purpose; +}LIBLTE_RRC_PERIODICAL_INTER_RAT_STRUCT; +typedef struct{ + LIBLTE_RRC_EVENT_INTER_RAT_STRUCT event; + LIBLTE_RRC_PERIODICAL_INTER_RAT_STRUCT periodical; + LIBLTE_RRC_TRIGGER_TYPE_INTER_RAT_ENUM trigger_type; + LIBLTE_RRC_REPORT_INTERVAL_ENUM report_interval; + LIBLTE_RRC_REPORT_AMOUNT_ENUM report_amount; + uint8 max_report_cells; +}LIBLTE_RRC_REPORT_CONFIG_INTER_RAT_STRUCT; +typedef struct{ + LIBLTE_RRC_REPORT_CONFIG_EUTRA_STRUCT rep_cnfg_eutra; + LIBLTE_RRC_REPORT_CONFIG_INTER_RAT_STRUCT rep_cnfg_inter_rat; + LIBLTE_RRC_REPORT_CONFIG_TYPE_ENUM rep_cnfg_type; + uint8 rep_cnfg_id; +}LIBLTE_RRC_REPORT_CONFIG_TO_ADD_MOD_STRUCT; +typedef struct{ + LIBLTE_RRC_REPORT_CONFIG_TO_ADD_MOD_STRUCT rep_cnfg_list[LIBLTE_RRC_MAX_REPORT_CONFIG_ID]; + uint32 N_rep_cnfg; +}LIBLTE_RRC_REPORT_CONFIG_TO_ADD_MOD_LIST_STRUCT; +typedef struct{ + LIBLTE_RRC_MOBILITY_STATE_PARAMETERS_STRUCT mob_state_params; + LIBLTE_RRC_SPEED_STATE_SCALE_FACTORS_STRUCT time_to_trig_sf; +}LIBLTE_RRC_SPEED_STATE_PARAMS_STRUCT; +typedef struct{ + LIBLTE_RRC_MEAS_OBJECT_TO_ADD_MOD_LIST_STRUCT meas_obj_to_add_mod_list; + LIBLTE_RRC_REPORT_CONFIG_TO_ADD_MOD_LIST_STRUCT rep_cnfg_to_add_mod_list; + LIBLTE_RRC_MEAS_ID_TO_ADD_MOD_LIST_STRUCT meas_id_to_add_mod_list; + LIBLTE_RRC_QUANTITY_CONFIG_STRUCT quantity_cnfg; + LIBLTE_RRC_MEAS_GAP_CONFIG_STRUCT meas_gap_cnfg; + LIBLTE_RRC_PRE_REGISTRATION_INFO_HRPD_STRUCT pre_reg_info_hrpd; + LIBLTE_RRC_SPEED_STATE_PARAMS_STRUCT speed_state_params; + uint32 N_meas_obj_to_remove; + uint32 N_rep_cnfg_to_remove; + uint32 N_meas_id_to_remove; + uint8 meas_obj_to_remove_list[LIBLTE_RRC_MAX_OBJECT_ID]; + uint8 rep_cnfg_to_remove_list[LIBLTE_RRC_MAX_REPORT_CONFIG_ID]; + uint8 meas_id_to_remove_list[LIBLTE_RRC_MAX_MEAS_ID]; + uint8 s_meas; + bool meas_obj_to_add_mod_list_present; + bool rep_cnfg_to_add_mod_list_present; + bool meas_id_to_add_mod_list_present; + bool quantity_cnfg_present; + bool meas_gap_cnfg_present; + bool s_meas_present; + bool pre_reg_info_hrpd_present; + bool speed_state_params_present; +}LIBLTE_RRC_MEAS_CONFIG_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_meas_config_ie(LIBLTE_RRC_MEAS_CONFIG_STRUCT *meas_cnfg, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_meas_config_ie(uint8 **ie_ptr, + LIBLTE_RRC_MEAS_CONFIG_STRUCT *meas_cnfg); + +/********************************************************************* + IE Name: Meas Gap Config + + Description: Specifies the measurement gap configuration and + controls setup/release of measurement gaps + + Document Reference: 36.331 v10.0.0 Section 6.3.5 +*********************************************************************/ +// Defines +// Enums +// Meas Gap Config enum defined above +// Structs +// Meas Gap Config struct defined above +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_meas_gap_config_ie(LIBLTE_RRC_MEAS_GAP_CONFIG_STRUCT *meas_gap_cnfg, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_meas_gap_config_ie(uint8 **ie_ptr, + LIBLTE_RRC_MEAS_GAP_CONFIG_STRUCT *meas_gap_cnfg); + +/********************************************************************* + IE Name: Meas ID + + Description: Identifies a measurement configuration, i.e. linking + of a measurement object and a reporting configuration + + Document Reference: 36.331 v10.0.0 Section 6.3.5 +*********************************************************************/ +// Defines +// Enums +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_meas_id_ie(uint8 meas_id, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_meas_id_ie(uint8 **ie_ptr, + uint8 *meas_id); + +/********************************************************************* + IE Name: Meas Id To Add Mod List + + Description: Concerns a list of measurement identities to add or + modify, with for each entry the meas ID, the + associated meas object ID and the associated report + config ID + + Document Reference: 36.331 v10.0.0 Section 6.3.5 +*********************************************************************/ +// Defines +// Enums +// Structs +// Meas ID To Add Mod List structs defined above +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_meas_id_to_add_mod_list_ie(LIBLTE_RRC_MEAS_ID_TO_ADD_MOD_LIST_STRUCT *list, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_meas_id_to_add_mod_list_ie(uint8 **ie_ptr, + LIBLTE_RRC_MEAS_ID_TO_ADD_MOD_LIST_STRUCT *list); + +/********************************************************************* + IE Name: Meas Object CDMA2000 + + Description: Specifies information applicable for inter-RAT + CDMA2000 neighboring cells + + Document Reference: 36.331 v10.0.0 Section 6.3.5 +*********************************************************************/ +// Defines +// Enums +// Structs +// Meas Object CDMA2000 structs defined above +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_meas_object_cdma2000_ie(LIBLTE_RRC_MEAS_OBJECT_CDMA2000_STRUCT *meas_obj_cdma2000, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_meas_object_cdma2000_ie(uint8 **ie_ptr, + LIBLTE_RRC_MEAS_OBJECT_CDMA2000_STRUCT *meas_obj_cdma2000); + +/********************************************************************* + IE Name: Meas Object EUTRA + + Description: Specifies information applicable for intra-frequency + or inter-frequency E-UTRA cells + + Document Reference: 36.331 v10.0.0 Section 6.3.5 +*********************************************************************/ +// Defines +// Enums +// Structs +// Meas Object EUTRA structs defined above +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_meas_object_eutra_ie(LIBLTE_RRC_MEAS_OBJECT_EUTRA_STRUCT *meas_obj_eutra, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_meas_object_eutra_ie(uint8 **ie_ptr, + LIBLTE_RRC_MEAS_OBJECT_EUTRA_STRUCT *meas_obj_eutra); + +/********************************************************************* + IE Name: Meas Object GERAN + + Description: Specifies information applicable for inter-RAT + GERAN neighboring frequencies + + Document Reference: 36.331 v10.0.0 Section 6.3.5 +*********************************************************************/ +// Defines +// Enums +// Structs +// Meas Object GERAN struct defined above +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_meas_object_geran_ie(LIBLTE_RRC_MEAS_OBJECT_GERAN_STRUCT *meas_obj_geran, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_meas_object_geran_ie(uint8 **ie_ptr, + LIBLTE_RRC_MEAS_OBJECT_GERAN_STRUCT *meas_obj_geran); + +/********************************************************************* + IE Name: Meas Object ID + + Description: Identifies a measurement object configuration + + Document Reference: 36.331 v10.0.0 Section 6.3.5 +*********************************************************************/ +// Defines +// Enums +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_meas_object_id_ie(uint8 meas_object_id, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_meas_object_id_ie(uint8 **ie_ptr, + uint8 *meas_object_id); + +/********************************************************************* + IE Name: Meas Object To Add Mod List + + Description: Concerns a list of measurement objects to add or + modify + + Document Reference: 36.331 v10.0.0 Section 6.3.5 +*********************************************************************/ +// Defines +// Enums +// Meas Object To Add Mod List enum defined above +// Structs +// Meas Object To Add Mod List structs defined above +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_meas_object_to_add_mod_list_ie(LIBLTE_RRC_MEAS_OBJECT_TO_ADD_MOD_LIST_STRUCT *list, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_meas_object_to_add_mod_list_ie(uint8 **ie_ptr, + LIBLTE_RRC_MEAS_OBJECT_TO_ADD_MOD_LIST_STRUCT *list); + +/********************************************************************* + IE Name: Meas Object UTRA + + Description: Specifies information applicable for inter-RAT UTRA + neighboring cells + + Document Reference: 36.331 v10.0.0 Section 6.3.5 +*********************************************************************/ +// Defines +// Meas Object UTRA define defined above +// Enums +// Meas Object UTRA enum defined above +// Structs +// Meas Object UTRA structs defined above +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_meas_object_utra_ie(LIBLTE_RRC_MEAS_OBJECT_UTRA_STRUCT *meas_obj_utra, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_meas_object_utra_ie(uint8 **ie_ptr, + LIBLTE_RRC_MEAS_OBJECT_UTRA_STRUCT *meas_obj_utra); + +/********************************************************************* + IE Name: Meas Results + + Description: Covers measured results for intra-frequency, + inter-frequency and inter-RAT mobility + + Document Reference: 36.331 v10.0.0 Section 6.3.5 +*********************************************************************/ +// Defines +// Enums +// Structs +// Functions +// FIXME + +/********************************************************************* + IE Name: Quantity Config + + Description: Specifies the measurement quantities and layer 3 + filtering coefficients for E-UTRA and inter-RAT + measurements + + Document Reference: 36.331 v10.0.0 Section 6.3.5 +*********************************************************************/ +// Defines +// Enums +// Quantity Config enums defined above +// Structs +// Quantity Config structs defined above +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_quantity_config_ie(LIBLTE_RRC_QUANTITY_CONFIG_STRUCT *qc, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_quantity_config_ie(uint8 **ie_ptr, + LIBLTE_RRC_QUANTITY_CONFIG_STRUCT *qc); + +/********************************************************************* + IE Name: Report Config EUTRA + + Description: Specifies criteria for triggering of an E-UTRA + measurement reporting event + + Document Reference: 36.331 v10.0.0 Section 6.3.5 +*********************************************************************/ +// Defines +// Enums +// Report Config EUTRA enums defined above +// Structs +// Report Config EUTRA structs defined above +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_report_config_eutra_ie(LIBLTE_RRC_REPORT_CONFIG_EUTRA_STRUCT *rep_cnfg_eutra, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_report_config_eutra_ie(uint8 **ie_ptr, + LIBLTE_RRC_REPORT_CONFIG_EUTRA_STRUCT *rep_cnfg_eutra); + +/********************************************************************* + IE Name: Report Config ID + + Description: Identifies a measurement reporting configuration + + Document Reference: 36.331 v10.0.0 Section 6.3.5 +*********************************************************************/ +// Defines +// Enums +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_report_config_id_ie(uint8 report_cnfg_id, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_report_config_id_ie(uint8 **ie_ptr, + uint8 *report_cnfg_id); + +/********************************************************************* + IE Name: Report Config Inter RAT + + Description: Specifies criteria for triggering of an inter-RAT + measurement reporting event + + Document Reference: 36.331 v10.0.0 Section 6.3.5 +*********************************************************************/ +// Defines +// Enums +// Report Config Inter RAT enums defined above +// Structs +// Report Config Inter RAT structs defined above +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_report_config_inter_rat_ie(LIBLTE_RRC_REPORT_CONFIG_INTER_RAT_STRUCT *rep_cnfg_inter_rat, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_report_config_inter_rat_ie(uint8 **ie_ptr, + LIBLTE_RRC_REPORT_CONFIG_INTER_RAT_STRUCT *rep_cnfg_inter_rat); + +/********************************************************************* + IE Name: Report Config To Add Mod List + + Description: Concerns a list of reporting configurations to add + or modify + + Document Reference: 36.331 v10.0.0 Section 6.3.5 +*********************************************************************/ +// Defines +// Enums +// Report Config To Add Mod List enum defined above +// Structs +// Report Config To Add Mod List structs defined above +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_report_config_to_add_mod_list_ie(LIBLTE_RRC_REPORT_CONFIG_TO_ADD_MOD_LIST_STRUCT *list, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_report_config_to_add_mod_list_ie(uint8 **ie_ptr, + LIBLTE_RRC_REPORT_CONFIG_TO_ADD_MOD_LIST_STRUCT *list); + +/********************************************************************* + IE Name: Report Interval + + Description: Indicates the interval between periodic reports + + Document Reference: 36.331 v10.0.0 Section 6.3.5 +*********************************************************************/ +// Defines +// Enums +// Report Interval enum defined above +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_report_interval_ie(LIBLTE_RRC_REPORT_INTERVAL_ENUM report_int, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_report_interval_ie(uint8 **ie_ptr, + LIBLTE_RRC_REPORT_INTERVAL_ENUM *report_int); + +/********************************************************************* + IE Name: RSRP Range + + Description: Specifies the value range used in RSRP measurements + and thresholds + + Document Reference: 36.331 v10.0.0 Section 6.3.5 +*********************************************************************/ +// Defines +// Enums +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_rsrp_range_ie(uint8 rsrp_range, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_rsrp_range_ie(uint8 **ie_ptr, + uint8 *rsrp_range); + +/********************************************************************* + IE Name: RSRQ Range + + Description: Specifies the value range used in RSRQ measurements + and thresholds + + Document Reference: 36.331 v10.0.0 Section 6.3.5 +*********************************************************************/ +// Defines +// Enums +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_rsrq_range_ie(uint8 rsrq_range, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_rsrq_range_ie(uint8 **ie_ptr, + uint8 *rsrq_range); + +/********************************************************************* + IE Name: Time To Trigger + + Description: Specifies the value range used for the time to + trigger parameter, which concerns the time during + which specific criteria for the event needs to be + met in order to trigger a measurement report + + Document Reference: 36.331 v10.0.0 Section 6.3.5 +*********************************************************************/ +// Defines +// Enums +// Time To Trigger enum defined above +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_time_to_trigger_ie(LIBLTE_RRC_TIME_TO_TRIGGER_ENUM time_to_trigger, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_time_to_trigger_ie(uint8 **ie_ptr, + LIBLTE_RRC_TIME_TO_TRIGGER_ENUM *time_to_trigger); + +/********************************************************************* + IE Name: Additional Spectrum Emission + + Description: FIXME + + Document Reference: 36.331 v10.0.0 Section 6.3.4 +*********************************************************************/ +// Defines +// Enums +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_additional_spectrum_emission_ie(uint8 add_spect_em, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_additional_spectrum_emission_ie(uint8 **ie_ptr, + uint8 *add_spect_em); + +/********************************************************************* + IE Name: ARFCN value CDMA2000 + + Description: Indicates the CDMA2000 carrier frequency within + a CDMA2000 band + + Document Reference: 36.331 v10.0.0 Section 6.3.4 +*********************************************************************/ +// Defines +// Enums +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_arfcn_value_cdma2000_ie(uint16 arfcn, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_arfcn_value_cdma2000_ie(uint8 **ie_ptr, + uint16 *arfcn); + +/********************************************************************* + IE Name: ARFCN value EUTRA + + Description: Indicates the ARFCN applicable for a downlink, + uplink, or bi-directional (TDD) E-UTRA carrier + frequency + + Document Reference: 36.331 v10.0.0 Section 6.3.4 +*********************************************************************/ +// Defines +// Enums +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_arfcn_value_eutra_ie(uint16 arfcn, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_arfcn_value_eutra_ie(uint8 **ie_ptr, + uint16 *arfcn); + +/********************************************************************* + IE Name: ARFCN value GERAN + + Description: Specifies the ARFCN value applicable for a GERAN + BCCH carrier frequency + + Document Reference: 36.331 v10.0.0 Section 6.3.4 +*********************************************************************/ +// Defines +// Enums +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_arfcn_value_geran_ie(uint16 arfcn, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_arfcn_value_geran_ie(uint8 **ie_ptr, + uint16 *arfcn); + +/********************************************************************* + IE Name: ARFCN value UTRA + + Description: Indicates the ARFCN applicable for a downlink (Nd, + FDD) or bi-directional (Nt, TDD) UTRA carrier + frequency + + Document Reference: 36.331 v10.0.0 Section 6.3.4 +*********************************************************************/ +// Defines +// Enums +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_arfcn_value_utra_ie(uint16 arfcn, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_arfcn_value_utra_ie(uint8 **ie_ptr, + uint16 *arfcn); + +/********************************************************************* + IE Name: Band Class CDMA2000 + + Description: Defines the CDMA2000 band in which the CDMA2000 + carrier frequency can be found + + Document Reference: 36.331 v10.0.0 Section 6.3.4 +*********************************************************************/ +// Defines +// Enums +// Band Class CDMA2000 enum defined above +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_band_class_cdma2000_ie(LIBLTE_RRC_BAND_CLASS_CDMA2000_ENUM bc_cdma2000, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_band_class_cdma2000_ie(uint8 **ie_ptr, + LIBLTE_RRC_BAND_CLASS_CDMA2000_ENUM *bc_cdma2000); + +/********************************************************************* + IE Name: Band Indicator GERAN + + Description: Indicates how to interpret an associated GERAN + carrier ARFCN + + Document Reference: 36.331 v10.0.0 Section 6.3.4 +*********************************************************************/ +// Defines +// Enums +// Band Indicator GERAN enum defined above +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_band_indicator_geran_ie(LIBLTE_RRC_BAND_INDICATOR_GERAN_ENUM bi_geran, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_band_indicator_geran_ie(uint8 **ie_ptr, + LIBLTE_RRC_BAND_INDICATOR_GERAN_ENUM *bi_geran); + +/********************************************************************* + IE Name: Carrier Freq CDMA2000 + + Description: Provides the CDMA2000 carrier information + + Document Reference: 36.331 v10.0.0 Section 6.3.4 +*********************************************************************/ +// Defines +// Enums +// Structs +// Carrier Freq CDMA2000 struct defined above +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_carrier_freq_cdma2000_ie(LIBLTE_RRC_CARRIER_FREQ_CDMA2000_STRUCT *carrier_freq, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_carrier_freq_cdma2000_ie(uint8 **ie_ptr, + LIBLTE_RRC_CARRIER_FREQ_CDMA2000_STRUCT *carrier_freq); + +/********************************************************************* + IE Name: Carrier Freq GERAN + + Description: Provides an unambiguous carrier frequency description + of a GERAN cell + + Document Reference: 36.331 v10.0.0 Section 6.3.4 +*********************************************************************/ +// Defines +// Enums +// Structs +typedef struct{ + LIBLTE_RRC_BAND_INDICATOR_GERAN_ENUM band_indicator; + uint16 arfcn; +}LIBLTE_RRC_CARRIER_FREQ_GERAN_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_carrier_freq_geran_ie(LIBLTE_RRC_CARRIER_FREQ_GERAN_STRUCT *carrier_freq, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_carrier_freq_geran_ie(uint8 **ie_ptr, + LIBLTE_RRC_CARRIER_FREQ_GERAN_STRUCT *carrier_freq); + +/********************************************************************* + IE Name: Carrier Freqs GERAN + + Description: Provides one or more GERAN ARFCN values, which + represent a list of GERAN BCCH carrier frequencies + + Document Reference: 36.331 v10.0.0 Section 6.3.4 +*********************************************************************/ +// Defines +// Carrier Freqs GERAN define defined above +// Enums +// Carrier Freqs GERAN enum defined above +// Structs +// Carrier Freqs GERAN structs defined above +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_carrier_freqs_geran_ie(LIBLTE_RRC_CARRIER_FREQS_GERAN_STRUCT *carrier_freqs, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_carrier_freqs_geran_ie(uint8 **ie_ptr, + LIBLTE_RRC_CARRIER_FREQS_GERAN_STRUCT *carrier_freqs); + +/********************************************************************* + IE Name: CDMA2000 Type + + Description: Describes the type of CDMA2000 network + + Document Reference: 36.331 v10.0.0 Section 6.3.4 +*********************************************************************/ +// Defines +// Enums +// CDMA2000 Type enum defined above +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_cdma2000_type_ie(LIBLTE_RRC_CDMA2000_TYPE_ENUM cdma2000_type, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_cdma2000_type_ie(uint8 **ie_ptr, + LIBLTE_RRC_CDMA2000_TYPE_ENUM *cdma2000_type); + +/********************************************************************* + IE Name: Cell Identity + + Description: Unambiguously identifies a cell within a PLMN + + Document Reference: 36.331 v10.0.0 Section 6.3.4 +*********************************************************************/ +// Defines +// Enums +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_cell_identity_ie(uint32 cell_id, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_cell_identity_ie(uint8 **ie_ptr, + uint32 *cell_id); + +/********************************************************************* + IE Name: Cell Index List + + Description: Concerns a list of cell indecies, which may be used + for different purposes + + Document Reference: 36.331 v10.0.0 Section 6.3.4 +*********************************************************************/ +// Defines +// Enums +// Structs +// Cell Index List struct defined above +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_cell_index_list_ie(LIBLTE_RRC_CELL_INDEX_LIST_STRUCT *cell_idx_list, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_cell_index_list_ie(uint8 **ie_ptr, + LIBLTE_RRC_CELL_INDEX_LIST_STRUCT *cell_idx_list); + +/********************************************************************* + IE Name: Cell Reselection Priority + + Description: Contains the absolute priority of the concerned + carrier frequency/set of frequencies (GERAN)/ + bandclass (CDMA2000), as used by the cell + reselection procedure + + Document Reference: 36.331 v10.0.0 Section 6.3.4 +*********************************************************************/ +// Defines +// Enums +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_cell_reselection_priority_ie(uint8 cell_resel_prio, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_cell_reselection_priority_ie(uint8 **ie_ptr, + uint8 *cell_resel_prio); + +/********************************************************************* + IE Name: CSFB Registration Param 1xRTT + + Description: Indicates whether or not the UE shall perform a + CDMA2000 1xRTT pre-registration if the UE does not + have a valid/current pre-registration + + Document Reference: 36.331 v10.0.0 Section 6.3.4 +*********************************************************************/ +// Defines +// Enums +typedef enum{ + LIBLTE_RRC_POWER_DOWN_REG_R9_TRUE = 0, + LIBLTE_RRC_POWER_DOWN_REG_R9_N_ITEMS, +}LIBLTE_RRC_POWER_DOWN_REG_R9_ENUM; +static const char liblte_rrc_power_down_reg_r9_text[LIBLTE_RRC_POWER_DOWN_REG_R9_N_ITEMS][20] = {"TRUE"}; +// Structs +typedef struct{ + uint16 sid; + uint16 nid; + uint16 reg_zone; + uint8 reg_period; + uint8 total_zone; + uint8 zone_timer; + bool multiple_sid; + bool multiple_nid; + bool home_reg; + bool foreign_sid_reg; + bool foreign_nid_reg; + bool param_reg; + bool power_up_reg; +}LIBLTE_RRC_CSFB_REGISTRATION_PARAM_1XRTT_STRUCT; +typedef struct{ + LIBLTE_RRC_POWER_DOWN_REG_R9_ENUM power_down_reg; +}LIBLTE_RRC_CSFB_REGISTRATION_PARAM_1XRTT_V920_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_csfb_registration_param_1xrtt_ie(LIBLTE_RRC_CSFB_REGISTRATION_PARAM_1XRTT_STRUCT *csfb_reg_param, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_csfb_registration_param_1xrtt_ie(uint8 **ie_ptr, + LIBLTE_RRC_CSFB_REGISTRATION_PARAM_1XRTT_STRUCT *csfb_reg_param); +LIBLTE_ERROR_ENUM liblte_rrc_pack_csfb_registration_param_1xrtt_v920_ie(LIBLTE_RRC_CSFB_REGISTRATION_PARAM_1XRTT_V920_STRUCT *csfb_reg_param, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_csfb_registration_param_1xrtt_v920_ie(uint8 **ie_ptr, + LIBLTE_RRC_CSFB_REGISTRATION_PARAM_1XRTT_V920_STRUCT *csfb_reg_param); + +/********************************************************************* + IE Name: Cell Global ID EUTRA + + Description: Specifies the Evolved Cell Global Identifier (ECGI), + the globally unique identity of a cell in E-UTRA + + Document Reference: 36.331 v10.0.0 Section 6.3.4 +*********************************************************************/ +// Defines +// Enums +// Structs +typedef struct{ + uint16 mcc; + uint16 mnc; +}LIBLTE_RRC_PLMN_IDENTITY_STRUCT; +typedef struct{ + LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id; + uint32 cell_id; +}LIBLTE_RRC_CELL_GLOBAL_ID_EUTRA_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_cell_global_id_eutra_ie(LIBLTE_RRC_CELL_GLOBAL_ID_EUTRA_STRUCT *cell_global_id, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_cell_global_id_eutra_ie(uint8 **ie_ptr, + LIBLTE_RRC_CELL_GLOBAL_ID_EUTRA_STRUCT *cell_global_id); + +/********************************************************************* + IE Name: Cell Global ID UTRA + + Description: Specifies the global UTRAN Cell Identifier, the + globally unique identity of a cell in UTRA + + Document Reference: 36.331 v10.0.0 Section 6.3.4 +*********************************************************************/ +// Defines +// Enums +// Structs +typedef struct{ + LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id; + uint32 cell_id; +}LIBLTE_RRC_CELL_GLOBAL_ID_UTRA_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_cell_global_id_utra_ie(LIBLTE_RRC_CELL_GLOBAL_ID_UTRA_STRUCT *cell_global_id, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_cell_global_id_utra_ie(uint8 **ie_ptr, + LIBLTE_RRC_CELL_GLOBAL_ID_UTRA_STRUCT *cell_global_id); + +/********************************************************************* + IE Name: Cell Global ID GERAN + + Description: Specifies the Cell Global Identity (CGI), the + globally unique identity of a cell in GERAN + + Document Reference: 36.331 v10.0.0 Section 6.3.4 +*********************************************************************/ +// Defines +// Enums +// Structs +typedef struct{ + LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id; + uint16 lac; + uint16 cell_id; +}LIBLTE_RRC_CELL_GLOBAL_ID_GERAN_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_cell_global_id_geran_ie(LIBLTE_RRC_CELL_GLOBAL_ID_GERAN_STRUCT *cell_global_id, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_cell_global_id_geran_ie(uint8 **ie_ptr, + LIBLTE_RRC_CELL_GLOBAL_ID_GERAN_STRUCT *cell_global_id); + +/********************************************************************* + IE Name: Cell Global ID CDMA2000 + + Description: Specifies the Cell Global Identity (CGI), the + globally unique identity of a cell in CDMA2000 + + Document Reference: 36.331 v10.0.0 Section 6.3.4 +*********************************************************************/ +// Defines +// Enums +// Structs +typedef struct{ + uint64 onexrtt; + uint32 hrpd[4]; +}LIBLTE_RRC_CELL_GLOBAL_ID_CDMA2000_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_cell_global_id_cdma2000_ie(LIBLTE_RRC_CELL_GLOBAL_ID_CDMA2000_STRUCT *cell_global_id, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_cell_global_id_cdma2000_ie(uint8 **ie_ptr, + LIBLTE_RRC_CELL_GLOBAL_ID_CDMA2000_STRUCT *cell_global_id); + +/********************************************************************* + IE Name: CSG Identity + + Description: Identifies a Closed Subscriber Group + + Document Reference: 36.331 v10.0.0 Section 6.3.4 +*********************************************************************/ +// Defines +#define LIBLTE_RRC_CSG_IDENTITY_NOT_PRESENT 0xFFFFFFFF +// Enums +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_csg_identity_ie(uint32 csg_id, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_csg_identity_ie(uint8 **ie_ptr, + uint32 *csg_id); + +/********************************************************************* + IE Name: Mobility Control Info + + Description: Includes parameters relevant for network controlled + mobility to/within E-UTRA + + Document Reference: 36.331 v10.0.0 Section 6.3.4 +*********************************************************************/ +// Defines +// Enums +typedef enum{ + LIBLTE_RRC_ANTENNA_PORTS_COUNT_AN1 = 0, + LIBLTE_RRC_ANTENNA_PORTS_COUNT_AN2, + LIBLTE_RRC_ANTENNA_PORTS_COUNT_AN4, + LIBLTE_RRC_ANTENNA_PORTS_COUNT_SPARE1, + LIBLTE_RRC_ANTENNA_PORTS_COUNT_N_ITEMS, +}LIBLTE_RRC_ANTENNA_PORTS_COUNT_ENUM; +static const char liblte_rrc_antenna_ports_count_text[LIBLTE_RRC_ANTENNA_PORTS_COUNT_N_ITEMS][20] = {"an1", "an2", "an4", "SPARE"}; +typedef enum{ + LIBLTE_RRC_PHICH_DURATION_NORMAL = 0, + LIBLTE_RRC_PHICH_DURATION_EXTENDED, + LIBLTE_RRC_PHICH_DURATION_N_ITEMS, +}LIBLTE_RRC_PHICH_DURATION_ENUM; +static const char liblte_rrc_phich_duration_text[LIBLTE_RRC_PHICH_DURATION_N_ITEMS][20] = {"Normal", "Extended"}; +typedef enum{ + LIBLTE_RRC_PHICH_RESOURCE_1_6 = 0, + LIBLTE_RRC_PHICH_RESOURCE_1_2, + LIBLTE_RRC_PHICH_RESOURCE_1, + LIBLTE_RRC_PHICH_RESOURCE_2, + LIBLTE_RRC_PHICH_RESOURCE_N_ITEMS, +}LIBLTE_RRC_PHICH_RESOURCE_ENUM; +static const char liblte_rrc_phich_resource_text[LIBLTE_RRC_PHICH_RESOURCE_N_ITEMS][20] = {"1/6", "1/2", "1", "2"}; +static const double liblte_rrc_phich_resource_num[LIBLTE_RRC_PHICH_RESOURCE_N_ITEMS] = {0.16666667, 0.5, 1, 2}; +typedef enum{ + LIBLTE_RRC_DELTA_PUCCH_SHIFT_DS1 = 0, + LIBLTE_RRC_DELTA_PUCCH_SHIFT_DS2, + LIBLTE_RRC_DELTA_PUCCH_SHIFT_DS3, + LIBLTE_RRC_DELTA_PUCCH_SHIFT_N_ITEMS, +}LIBLTE_RRC_DELTA_PUCCH_SHIFT_ENUM; +static const char liblte_rrc_delta_pucch_shift_text[LIBLTE_RRC_DELTA_PUCCH_SHIFT_N_ITEMS][20] = {"1", "2", "3"}; +static const uint8 liblte_rrc_delta_pucch_shift_num[LIBLTE_RRC_DELTA_PUCCH_SHIFT_N_ITEMS] = {1, 2, 3}; +typedef enum{ + LIBLTE_RRC_HOPPING_MODE_INTER_SUBFRAME = 0, + LIBLTE_RRC_HOPPING_MODE_INTRA_AND_INTER_SUBFRAME, + LIBLTE_RRC_HOOPPING_MODE_N_ITEMS, +}LIBLTE_RRC_HOPPING_MODE_ENUM; +static const char liblte_rrc_hopping_mode_text[LIBLTE_RRC_HOOPPING_MODE_N_ITEMS][20] = {"inter-subframe","intra-subframe"}; +typedef enum{ + LIBLTE_RRC_NUMBER_OF_RA_PREAMBLES_N4 = 0, + LIBLTE_RRC_NUMBER_OF_RA_PREAMBLES_N8, + LIBLTE_RRC_NUMBER_OF_RA_PREAMBLES_N12, + LIBLTE_RRC_NUMBER_OF_RA_PREAMBLES_N16, + LIBLTE_RRC_NUMBER_OF_RA_PREAMBLES_N20, + LIBLTE_RRC_NUMBER_OF_RA_PREAMBLES_N24, + LIBLTE_RRC_NUMBER_OF_RA_PREAMBLES_N28, + LIBLTE_RRC_NUMBER_OF_RA_PREAMBLES_N32, + LIBLTE_RRC_NUMBER_OF_RA_PREAMBLES_N36, + LIBLTE_RRC_NUMBER_OF_RA_PREAMBLES_N40, + LIBLTE_RRC_NUMBER_OF_RA_PREAMBLES_N44, + LIBLTE_RRC_NUMBER_OF_RA_PREAMBLES_N48, + LIBLTE_RRC_NUMBER_OF_RA_PREAMBLES_N52, + LIBLTE_RRC_NUMBER_OF_RA_PREAMBLES_N56, + LIBLTE_RRC_NUMBER_OF_RA_PREAMBLES_N60, + LIBLTE_RRC_NUMBER_OF_RA_PREAMBLES_N64, + LIBLTE_RRC_NUMBER_OF_RA_PREAMBLES_N_ITEMS, +}LIBLTE_RRC_NUMBER_OF_RA_PREAMBLES_ENUM; +static const char liblte_rrc_number_of_ra_preambles_text[LIBLTE_RRC_NUMBER_OF_RA_PREAMBLES_N_ITEMS][20] = { "4", "8", "12", "16", + "20", "24", "28", "32", + "36", "40", "44", "48", + "52", "56", "60", "64"}; +static const uint8 liblte_rrc_number_of_ra_preambles_num[LIBLTE_RRC_NUMBER_OF_RA_PREAMBLES_N_ITEMS] = {4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60, 64}; +typedef enum{ + LIBLTE_RRC_SIZE_OF_RA_PREAMBLES_GROUP_A_N4 = 0, + LIBLTE_RRC_SIZE_OF_RA_PREAMBLES_GROUP_A_N8, + LIBLTE_RRC_SIZE_OF_RA_PREAMBLES_GROUP_A_N12, + LIBLTE_RRC_SIZE_OF_RA_PREAMBLES_GROUP_A_N16, + LIBLTE_RRC_SIZE_OF_RA_PREAMBLES_GROUP_A_N20, + LIBLTE_RRC_SIZE_OF_RA_PREAMBLES_GROUP_A_N24, + LIBLTE_RRC_SIZE_OF_RA_PREAMBLES_GROUP_A_N28, + LIBLTE_RRC_SIZE_OF_RA_PREAMBLES_GROUP_A_N32, + LIBLTE_RRC_SIZE_OF_RA_PREAMBLES_GROUP_A_N36, + LIBLTE_RRC_SIZE_OF_RA_PREAMBLES_GROUP_A_N40, + LIBLTE_RRC_SIZE_OF_RA_PREAMBLES_GROUP_A_N44, + LIBLTE_RRC_SIZE_OF_RA_PREAMBLES_GROUP_A_N48, + LIBLTE_RRC_SIZE_OF_RA_PREAMBLES_GROUP_A_N52, + LIBLTE_RRC_SIZE_OF_RA_PREAMBLES_GROUP_A_N56, + LIBLTE_RRC_SIZE_OF_RA_PREAMBLES_GROUP_A_N60, + LIBLTE_RRC_SIZE_OF_RA_PREAMBLES_GROUP_A_N_ITEMS, +}LIBLTE_RRC_SIZE_OF_RA_PREAMBLES_GROUP_A_ENUM; +static const char liblte_rrc_size_of_ra_preambles_group_a_text[LIBLTE_RRC_SIZE_OF_RA_PREAMBLES_GROUP_A_N_ITEMS][20] = { "4", "8", "12", "16", + "20", "24", "28", "32", + "36", "40", "44", "48", + "52", "56", "60"}; +static const uint8 liblte_rrc_size_of_ra_preambles_group_a_num[LIBLTE_RRC_SIZE_OF_RA_PREAMBLES_GROUP_A_N_ITEMS] = {4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60}; +typedef enum{ + LIBLTE_RRC_MESSAGE_SIZE_GROUP_A_B56 = 0, + LIBLTE_RRC_MESSAGE_SIZE_GROUP_A_B144, + LIBLTE_RRC_MESSAGE_SIZE_GROUP_A_B208, + LIBLTE_RRC_MESSAGE_SIZE_GROUP_A_B256, + LIBLTE_RRC_MESSAGE_SIZE_GROUP_A_N_ITEMS, +}LIBLTE_RRC_MESSAGE_SIZE_GROUP_A_ENUM; +static const char liblte_rrc_message_size_group_a_text[LIBLTE_RRC_MESSAGE_SIZE_GROUP_A_N_ITEMS][20] = {"56", "144", "208", "256"}; +static const uint16 liblte_rrc_message_size_group_a_num[LIBLTE_RRC_MESSAGE_SIZE_GROUP_A_N_ITEMS] = {56, 144, 208, 256}; +typedef enum{ + LIBLTE_RRC_MESSAGE_POWER_OFFSET_GROUP_B_MINUS_INFINITY = 0, + LIBLTE_RRC_MESSAGE_POWER_OFFSET_GROUP_B_DB0, + LIBLTE_RRC_MESSAGE_POWER_OFFSET_GROUP_B_DB5, + LIBLTE_RRC_MESSAGE_POWER_OFFSET_GROUP_B_DB8, + LIBLTE_RRC_MESSAGE_POWER_OFFSET_GROUP_B_DB10, + LIBLTE_RRC_MESSAGE_POWER_OFFSET_GROUP_B_DB12, + LIBLTE_RRC_MESSAGE_POWER_OFFSET_GROUP_B_DB15, + LIBLTE_RRC_MESSAGE_POWER_OFFSET_GROUP_B_DB18, + LIBLTE_RRC_MESSAGE_POWER_OFFSET_GROUP_B_N_ITEMS, +}LIBLTE_RRC_MESSAGE_POWER_OFFSET_GROUP_B_ENUM; +static const char liblte_rrc_message_power_offset_group_b_text[LIBLTE_RRC_MESSAGE_POWER_OFFSET_GROUP_B_N_ITEMS][20] = {"-INFINITY", "0", "5", "8", + "10", "12", "15", "18"}; +static const int liblte_rrc_message_power_offset_group_b_num[LIBLTE_RRC_MESSAGE_POWER_OFFSET_GROUP_B_N_ITEMS] = {-1, 0, 5, 8, + 10, 12, 15, 18}; +typedef enum{ + LIBLTE_RRC_POWER_RAMPING_STEP_DB0 = 0, + LIBLTE_RRC_POWER_RAMPING_STEP_DB2, + LIBLTE_RRC_POWER_RAMPING_STEP_DB4, + LIBLTE_RRC_POWER_RAMPING_STEP_DB6, + LIBLTE_RRC_POWER_RAMPING_STEP_N_ITEMS, +}LIBLTE_RRC_POWER_RAMPING_STEP_ENUM; +static const char liblte_rrc_power_ramping_step_text[LIBLTE_RRC_POWER_RAMPING_STEP_N_ITEMS][20] = {"0", "2", "4", "6"}; +static const uint8 liblte_rrc_power_ramping_step_num[LIBLTE_RRC_POWER_RAMPING_STEP_N_ITEMS] = {0, 2, 4, 6}; +typedef enum{ + LIBLTE_RRC_PREAMBLE_INITIAL_RECEIVED_TARGET_POWER_DBM_N120 = 0, + LIBLTE_RRC_PREAMBLE_INITIAL_RECEIVED_TARGET_POWER_DBM_N118, + LIBLTE_RRC_PREAMBLE_INITIAL_RECEIVED_TARGET_POWER_DBM_N116, + LIBLTE_RRC_PREAMBLE_INITIAL_RECEIVED_TARGET_POWER_DBM_N114, + LIBLTE_RRC_PREAMBLE_INITIAL_RECEIVED_TARGET_POWER_DBM_N112, + LIBLTE_RRC_PREAMBLE_INITIAL_RECEIVED_TARGET_POWER_DBM_N110, + LIBLTE_RRC_PREAMBLE_INITIAL_RECEIVED_TARGET_POWER_DBM_N108, + LIBLTE_RRC_PREAMBLE_INITIAL_RECEIVED_TARGET_POWER_DBM_N106, + LIBLTE_RRC_PREAMBLE_INITIAL_RECEIVED_TARGET_POWER_DBM_N104, + LIBLTE_RRC_PREAMBLE_INITIAL_RECEIVED_TARGET_POWER_DBM_N102, + LIBLTE_RRC_PREAMBLE_INITIAL_RECEIVED_TARGET_POWER_DBM_N100, + LIBLTE_RRC_PREAMBLE_INITIAL_RECEIVED_TARGET_POWER_DBM_N98, + LIBLTE_RRC_PREAMBLE_INITIAL_RECEIVED_TARGET_POWER_DBM_N96, + LIBLTE_RRC_PREAMBLE_INITIAL_RECEIVED_TARGET_POWER_DBM_N94, + LIBLTE_RRC_PREAMBLE_INITIAL_RECEIVED_TARGET_POWER_DBM_N92, + LIBLTE_RRC_PREAMBLE_INITIAL_RECEIVED_TARGET_POWER_DBM_N90, + LIBLTE_RRC_PREAMBLE_INITIAL_RECEIVED_TARGET_POWER_N_ITEMS, +}LIBLTE_RRC_PREAMBLE_INITIAL_RECEIVED_TARGET_POWER_ENUM; +static const char liblte_rrc_preamble_initial_received_target_power_text[LIBLTE_RRC_PREAMBLE_INITIAL_RECEIVED_TARGET_POWER_N_ITEMS][20] = {"-120", "-118", "-116", "-114", + "-112", "-110", "-108", "-106", + "-104", "-102", "-100", "-98", + "-96", "-94", "-92", "-90"}; +static const int8 liblte_rrc_preamble_initial_received_target_power_num[LIBLTE_RRC_PREAMBLE_INITIAL_RECEIVED_TARGET_POWER_N_ITEMS] = {-120, -118, -116, -114, -112, -110, -108, -106, + -104, -102, -100, -98, -96, -94, -92, -90}; +typedef enum{ + LIBLTE_RRC_PREAMBLE_TRANS_MAX_N3 = 0, + LIBLTE_RRC_PREAMBLE_TRANS_MAX_N4, + LIBLTE_RRC_PREAMBLE_TRANS_MAX_N5, + LIBLTE_RRC_PREAMBLE_TRANS_MAX_N6, + LIBLTE_RRC_PREAMBLE_TRANS_MAX_N7, + LIBLTE_RRC_PREAMBLE_TRANS_MAX_N8, + LIBLTE_RRC_PREAMBLE_TRANS_MAX_N10, + LIBLTE_RRC_PREAMBLE_TRANS_MAX_N20, + LIBLTE_RRC_PREAMBLE_TRANS_MAX_N50, + LIBLTE_RRC_PREAMBLE_TRANS_MAX_N100, + LIBLTE_RRC_PREAMBLE_TRANS_MAX_N200, + LIBLTE_RRC_PREAMBLE_TRANS_MAX_N_ITEMS, +}LIBLTE_RRC_PREAMBLE_TRANS_MAX_ENUM; +static const char liblte_rrc_preamble_trans_max_text[LIBLTE_RRC_PREAMBLE_TRANS_MAX_N_ITEMS][20] = { "3", "4", "5", "6", + "7", "8", "10", "20", + "50", "100", "200"}; +static const uint8 liblte_rrc_preamble_trans_max_num[LIBLTE_RRC_PREAMBLE_TRANS_MAX_N_ITEMS] = {3, 4, 5, 6, 7, 8, 10, 20, 50, 100, 200}; +typedef enum{ + LIBLTE_RRC_RA_RESPONSE_WINDOW_SIZE_SF2 = 0, + LIBLTE_RRC_RA_RESPONSE_WINDOW_SIZE_SF3, + LIBLTE_RRC_RA_RESPONSE_WINDOW_SIZE_SF4, + LIBLTE_RRC_RA_RESPONSE_WINDOW_SIZE_SF5, + LIBLTE_RRC_RA_RESPONSE_WINDOW_SIZE_SF6, + LIBLTE_RRC_RA_RESPONSE_WINDOW_SIZE_SF7, + LIBLTE_RRC_RA_RESPONSE_WINDOW_SIZE_SF8, + LIBLTE_RRC_RA_RESPONSE_WINDOW_SIZE_SF10, + LIBLTE_RRC_RA_RESPONSE_WINDOW_SIZE_N_ITEMS, +}LIBLTE_RRC_RA_RESPONSE_WINDOW_SIZE_ENUM; +static const char liblte_rrc_ra_response_window_size_text[LIBLTE_RRC_RA_RESPONSE_WINDOW_SIZE_N_ITEMS][20] = { "2", "3", "4", "5", + "6", "7", "8", "10"}; +static const uint8 liblte_rrc_ra_response_window_size_num[LIBLTE_RRC_RA_RESPONSE_WINDOW_SIZE_N_ITEMS] = {2, 3, 4, 5, 6, 7, 8, 10}; +typedef enum{ + LIBLTE_RRC_MAC_CONTENTION_RESOLUTION_TIMER_SF8 = 0, + LIBLTE_RRC_MAC_CONTENTION_RESOLUTION_TIMER_SF16, + LIBLTE_RRC_MAC_CONTENTION_RESOLUTION_TIMER_SF24, + LIBLTE_RRC_MAC_CONTENTION_RESOLUTION_TIMER_SF32, + LIBLTE_RRC_MAC_CONTENTION_RESOLUTION_TIMER_SF40, + LIBLTE_RRC_MAC_CONTENTION_RESOLUTION_TIMER_SF48, + LIBLTE_RRC_MAC_CONTENTION_RESOLUTION_TIMER_SF56, + LIBLTE_RRC_MAC_CONTENTION_RESOLUTION_TIMER_SF64, + LIBLTE_RRC_MAC_CONTENTION_RESOLUTION_TIMER_N_ITEMS, +}LIBLTE_RRC_MAC_CONTENTION_RESOLUTION_TIMER_ENUM; +static const char liblte_rrc_mac_contention_resolution_timer_text[LIBLTE_RRC_MAC_CONTENTION_RESOLUTION_TIMER_N_ITEMS][20] = { "8", "16", "24", "32", + "40", "48", "56", "64"}; +static const uint8 liblte_rrc_mac_contention_resolution_timer_num[LIBLTE_RRC_MAC_CONTENTION_RESOLUTION_TIMER_N_ITEMS] = {8, 16, 24, 32, 40, 48, 56, 64}; +typedef enum{ + LIBLTE_RRC_UL_CP_LENGTH_1 = 0, + LIBLTE_RRC_UL_CP_LENGTH_2, + LIBLTE_RRC_UL_CP_LENGTH_N_ITEMS, +}LIBLTE_RRC_UL_CP_LENGTH_ENUM; +static const char liblte_rrc_ul_cp_length_text[LIBLTE_RRC_UL_CP_LENGTH_N_ITEMS][20] = {"Normal", "Extended"}; +typedef enum{ + LIBLTE_RRC_SRS_BW_CONFIG_0 = 0, + LIBLTE_RRC_SRS_BW_CONFIG_1, + LIBLTE_RRC_SRS_BW_CONFIG_2, + LIBLTE_RRC_SRS_BW_CONFIG_3, + LIBLTE_RRC_SRS_BW_CONFIG_4, + LIBLTE_RRC_SRS_BW_CONFIG_5, + LIBLTE_RRC_SRS_BW_CONFIG_6, + LIBLTE_RRC_SRS_BW_CONFIG_7, + LIBLTE_RRC_SRS_BW_CONFIG_N_ITEMS, +}LIBLTE_RRC_SRS_BW_CONFIG_ENUM; +static const char liblte_rrc_srs_bw_config_text[LIBLTE_RRC_SRS_BW_CONFIG_N_ITEMS][20] = {"0", "1", "2", "3", + "4", "5", "6", "7"}; +static const uint8 liblte_rrc_srs_bw_config_num[LIBLTE_RRC_SRS_BW_CONFIG_N_ITEMS] = {0, 1, 2, 3, 4, 5, 6, 7}; +typedef enum{ + LIBLTE_RRC_SRS_SUBFR_CONFIG_0 = 0, + LIBLTE_RRC_SRS_SUBFR_CONFIG_1, + LIBLTE_RRC_SRS_SUBFR_CONFIG_2, + LIBLTE_RRC_SRS_SUBFR_CONFIG_3, + LIBLTE_RRC_SRS_SUBFR_CONFIG_4, + LIBLTE_RRC_SRS_SUBFR_CONFIG_5, + LIBLTE_RRC_SRS_SUBFR_CONFIG_6, + LIBLTE_RRC_SRS_SUBFR_CONFIG_7, + LIBLTE_RRC_SRS_SUBFR_CONFIG_8, + LIBLTE_RRC_SRS_SUBFR_CONFIG_9, + LIBLTE_RRC_SRS_SUBFR_CONFIG_10, + LIBLTE_RRC_SRS_SUBFR_CONFIG_11, + LIBLTE_RRC_SRS_SUBFR_CONFIG_12, + LIBLTE_RRC_SRS_SUBFR_CONFIG_13, + LIBLTE_RRC_SRS_SUBFR_CONFIG_14, + LIBLTE_RRC_SRS_SUBFR_CONFIG_15, + LIBLTE_RRC_SRS_SUBFR_CONFIG_N_ITEMS, +}LIBLTE_RRC_SRS_SUBFR_CONFIG_ENUM; +static const char liblte_rrc_srs_subfr_config_text[LIBLTE_RRC_SRS_SUBFR_CONFIG_N_ITEMS][20] = { "0", "1", "2", "3", + "4", "5", "6", "7", + "8", "9", "10", "11", + "12", "13", "14", "15"}; +static const uint8 liblte_rrc_srs_subfr_config_num[LIBLTE_RRC_SRS_SUBFR_CONFIG_N_ITEMS] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}; +typedef enum{ + LIBLTE_RRC_SUBFRAME_ASSIGNMENT_0 = 0, + LIBLTE_RRC_SUBFRAME_ASSIGNMENT_1, + LIBLTE_RRC_SUBFRAME_ASSIGNMENT_2, + LIBLTE_RRC_SUBFRAME_ASSIGNMENT_3, + LIBLTE_RRC_SUBFRAME_ASSIGNMENT_4, + LIBLTE_RRC_SUBFRAME_ASSIGNMENT_5, + LIBLTE_RRC_SUBFRAME_ASSIGNMENT_6, + LIBLTE_RRC_SUBFRAME_ASSIGNMENT_N_ITEMS, +}LIBLTE_RRC_SUBFRAME_ASSIGNMENT_ENUM; +static const char liblte_rrc_subframe_assignment_text[LIBLTE_RRC_SUBFRAME_ASSIGNMENT_N_ITEMS][20] = {"0", "1", "2", "3", + "4", "5", "6"}; +static const uint8 liblte_rrc_subframe_assignment_num[LIBLTE_RRC_SUBFRAME_ASSIGNMENT_N_ITEMS] = {0, 1, 2, 3, 4, 5, 6}; +typedef enum{ + LIBLTE_RRC_SPECIAL_SUBFRAME_PATTERNS_0 = 0, + LIBLTE_RRC_SPECIAL_SUBFRAME_PATTERNS_1, + LIBLTE_RRC_SPECIAL_SUBFRAME_PATTERNS_2, + LIBLTE_RRC_SPECIAL_SUBFRAME_PATTERNS_3, + LIBLTE_RRC_SPECIAL_SUBFRAME_PATTERNS_4, + LIBLTE_RRC_SPECIAL_SUBFRAME_PATTERNS_5, + LIBLTE_RRC_SPECIAL_SUBFRAME_PATTERNS_6, + LIBLTE_RRC_SPECIAL_SUBFRAME_PATTERNS_7, + LIBLTE_RRC_SPECIAL_SUBFRAME_PATTERNS_8, + LIBLTE_RRC_SPECIAL_SUBFRAME_PATTERNS_N_ITEMS, +}LIBLTE_RRC_SPECIAL_SUBFRAME_PATTERNS_ENUM; +static const char liblte_rrc_special_subframe_patterns_text[LIBLTE_RRC_SPECIAL_SUBFRAME_PATTERNS_N_ITEMS][20] = {"0", "1", "2", "3", + "4", "5", "6", "7", + "8"}; +static const uint8 liblte_rrc_special_subframe_patterns_num[LIBLTE_RRC_SPECIAL_SUBFRAME_PATTERNS_N_ITEMS] = {0, 1, 2, 3, 4, 5, 6, 7, 8}; +typedef enum{ + LIBLTE_RRC_UL_POWER_CONTROL_ALPHA_0 = 0, + LIBLTE_RRC_UL_POWER_CONTROL_ALPHA_04, + LIBLTE_RRC_UL_POWER_CONTROL_ALPHA_05, + LIBLTE_RRC_UL_POWER_CONTROL_ALPHA_06, + LIBLTE_RRC_UL_POWER_CONTROL_ALPHA_07, + LIBLTE_RRC_UL_POWER_CONTROL_ALPHA_08, + LIBLTE_RRC_UL_POWER_CONTROL_ALPHA_09, + LIBLTE_RRC_UL_POWER_CONTROL_ALPHA_1, + LIBLTE_RRC_UL_POWER_CONTROL_ALPHA_N_ITEMS, +}LIBLTE_RRC_UL_POWER_CONTROL_ALPHA_ENUM; +static const char liblte_rrc_ul_power_control_alpha_text[LIBLTE_RRC_UL_POWER_CONTROL_ALPHA_N_ITEMS][20] = {"0.0", "0.4", "0.5", "0.6", + "0.7", "0.8", "0.9", "1.0"}; +static const double liblte_rrc_ul_power_control_alpha_num[LIBLTE_RRC_UL_POWER_CONTROL_ALPHA_N_ITEMS] = {0.0, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0}; +typedef enum{ + LIBLTE_RRC_DELTA_F_PUCCH_FORMAT_1_NEG_2 = 0, + LIBLTE_RRC_DELTA_F_PUCCH_FORMAT_1_0, + LIBLTE_RRC_DELTA_F_PUCCH_FORMAT_1_2, + LIBLTE_RRC_DELTA_F_PUCCH_FORMAT_1_N_ITEMS, +}LIBLTE_RRC_DELTA_F_PUCCH_FORMAT_1_ENUM; +static const char liblte_rrc_delta_f_pucch_format_1_text[LIBLTE_RRC_DELTA_F_PUCCH_FORMAT_1_N_ITEMS][20] = {"-2", "0", "2"}; +static const int8 liblte_rrc_delta_f_pucch_format_1_num[LIBLTE_RRC_DELTA_F_PUCCH_FORMAT_1_N_ITEMS] = {-2, 0, 2}; +typedef enum{ + LIBLTE_RRC_DELTA_F_PUCCH_FORMAT_1B_1 = 0, + LIBLTE_RRC_DELTA_F_PUCCH_FORMAT_1B_3, + LIBLTE_RRC_DELTA_F_PUCCH_FORMAT_1B_5, + LIBLTE_RRC_DELTA_F_PUCCH_FORMAT_1B_N_ITEMS, +}LIBLTE_RRC_DELTA_F_PUCCH_FORMAT_1B_ENUM; +static const char liblte_rrc_delta_f_pucch_format_1b_text[LIBLTE_RRC_DELTA_F_PUCCH_FORMAT_1B_N_ITEMS][20] = {"1", "3", "5"}; +static const uint8 liblte_rrc_delta_f_pucch_format_1b_num[LIBLTE_RRC_DELTA_F_PUCCH_FORMAT_1B_N_ITEMS] = {1, 3, 5}; +typedef enum{ + LIBLTE_RRC_DELTA_F_PUCCH_FORMAT_2_NEG_2 = 0, + LIBLTE_RRC_DELTA_F_PUCCH_FORMAT_2_0, + LIBLTE_RRC_DELTA_F_PUCCH_FORMAT_2_1, + LIBLTE_RRC_DELTA_F_PUCCH_FORMAT_2_2, + LIBLTE_RRC_DELTA_F_PUCCH_FORMAT_2_N_ITEMS, +}LIBLTE_RRC_DELTA_F_PUCCH_FORMAT_2_ENUM; +static const char liblte_rrc_delta_f_pucch_format_2_text[LIBLTE_RRC_DELTA_F_PUCCH_FORMAT_2_N_ITEMS][20] = {"-2", "0", "1", "2"}; +static const int8 liblte_rrc_delta_f_pucch_format_2_num[LIBLTE_RRC_DELTA_F_PUCCH_FORMAT_2_N_ITEMS] = {-2, 0, 1, 2}; +typedef enum{ + LIBLTE_RRC_DELTA_F_PUCCH_FORMAT_2A_NEG_2 = 0, + LIBLTE_RRC_DELTA_F_PUCCH_FORMAT_2A_0, + LIBLTE_RRC_DELTA_F_PUCCH_FORMAT_2A_2, + LIBLTE_RRC_DELTA_F_PUCCH_FORMAT_2A_N_ITEMS, +}LIBLTE_RRC_DELTA_F_PUCCH_FORMAT_2A_ENUM; +static const char liblte_rrc_delta_f_pucch_format_2a_text[LIBLTE_RRC_DELTA_F_PUCCH_FORMAT_2A_N_ITEMS][20] = {"-2", "0", "2"}; +static const int8 liblte_rrc_delta_f_pucch_format_2a_num[LIBLTE_RRC_DELTA_F_PUCCH_FORMAT_2A_N_ITEMS] = {-2, 0, 2}; +typedef enum{ + LIBLTE_RRC_DELTA_F_PUCCH_FORMAT_2B_NEG_2 = 0, + LIBLTE_RRC_DELTA_F_PUCCH_FORMAT_2B_0, + LIBLTE_RRC_DELTA_F_PUCCH_FORMAT_2B_2, + LIBLTE_RRC_DELTA_F_PUCCH_FORMAT_2B_N_ITEMS, +}LIBLTE_RRC_DELTA_F_PUCCH_FORMAT_2B_ENUM; +static const char liblte_rrc_delta_f_pucch_format_2b_text[LIBLTE_RRC_DELTA_F_PUCCH_FORMAT_2B_N_ITEMS][20] = {"-2", "0", "2"}; +static const int8 liblte_rrc_delta_f_pucch_format_2b_num[LIBLTE_RRC_DELTA_F_PUCCH_FORMAT_2B_N_ITEMS] = {-2, 0, 2}; +typedef enum{ + LIBLTE_RRC_BANDWIDTH_N6 = 0, + LIBLTE_RRC_BANDWIDTH_N15, + LIBLTE_RRC_BANDWIDTH_N25, + LIBLTE_RRC_BANDWIDTH_N50, + LIBLTE_RRC_BANDWIDTH_N75, + LIBLTE_RRC_BANDWIDTH_N100, + LIBLTE_RRC_BANDWIDTH_SPARE10, + LIBLTE_RRC_BANDWIDTH_SPARE9, + LIBLTE_RRC_BANDWIDTH_SPARE8, + LIBLTE_RRC_BANDWIDTH_SPARE7, + LIBLTE_RRC_BANDWIDTH_SPARE6, + LIBLTE_RRC_BANDWIDTH_SPARE5, + LIBLTE_RRC_BANDWIDTH_SPARE4, + LIBLTE_RRC_BANDWIDTH_SPARE3, + LIBLTE_RRC_BANDWIDTH_SPARE2, + LIBLTE_RRC_BANDWIDTH_SPARE1, + LIBLTE_RRC_BANDWIDTH_N_ITEMS, +}LIBLTE_RRC_BANDWIDTH_ENUM; +static const char liblte_rrc_bandwidth_text[LIBLTE_RRC_BANDWIDTH_N_ITEMS][20] = { "1.4", "3", "5", "10", + "15", "20", "SPARE", "SPARE", + "SPARE", "SPARE", "SPARE", "SPARE", + "SPARE", "SPARE", "SPARE", "SPARE"}; +typedef enum{ + LIBLTE_RRC_T304_MS50 = 0, + LIBLTE_RRC_T304_MS100, + LIBLTE_RRC_T304_MS150, + LIBLTE_RRC_T304_MS200, + LIBLTE_RRC_T304_MS500, + LIBLTE_RRC_T304_MS1000, + LIBLTE_RRC_T304_MS2000, + LIBLTE_RRC_T304_SPARE, + LIBLTE_RRC_T304_N_ITEMS, +}LIBLTE_RRC_T304_ENUM; +static const char liblte_rrc_t304_text[LIBLTE_RRC_T304_N_ITEMS][20] = { "50", "100", "150", "200", + "500", "1000", "2000", "SPARE"}; +// Structs +typedef struct{ + uint8 p_b; + int8 rs_power; +}LIBLTE_RRC_PDSCH_CONFIG_COMMON_STRUCT; +typedef struct{ + LIBLTE_RRC_PHICH_DURATION_ENUM dur; + LIBLTE_RRC_PHICH_RESOURCE_ENUM res; +}LIBLTE_RRC_PHICH_CONFIG_STRUCT; +typedef struct{ + uint8 prach_config_index; + uint8 zero_correlation_zone_config; + uint8 prach_freq_offset; + bool high_speed_flag; +}LIBLTE_RRC_PRACH_CONFIG_INFO_STRUCT; +typedef struct{ + LIBLTE_RRC_PRACH_CONFIG_INFO_STRUCT prach_cnfg_info; + uint16 root_sequence_index; +}LIBLTE_RRC_PRACH_CONFIG_SIB_STRUCT; +typedef struct{ + LIBLTE_RRC_PRACH_CONFIG_INFO_STRUCT prach_cnfg_info; + uint16 root_sequence_index; + bool prach_cnfg_info_present; +}LIBLTE_RRC_PRACH_CONFIG_STRUCT; +typedef struct{ + LIBLTE_RRC_DELTA_PUCCH_SHIFT_ENUM delta_pucch_shift; + uint16 n1_pucch_an; + uint8 n_rb_cqi; + uint8 n_cs_an; +}LIBLTE_RRC_PUCCH_CONFIG_COMMON_STRUCT; +typedef struct{ + uint8 group_assignment_pusch; + uint8 cyclic_shift; + bool group_hopping_enabled; + bool sequence_hopping_enabled; +}LIBLTE_RRC_UL_RS_PUSCH_STRUCT; +typedef struct{ + LIBLTE_RRC_UL_RS_PUSCH_STRUCT ul_rs; + LIBLTE_RRC_HOPPING_MODE_ENUM hopping_mode; + uint8 n_sb; + uint8 pusch_hopping_offset; + bool enable_64_qam; +}LIBLTE_RRC_PUSCH_CONFIG_COMMON_STRUCT; +typedef struct{ + LIBLTE_RRC_SIZE_OF_RA_PREAMBLES_GROUP_A_ENUM size_of_ra; + LIBLTE_RRC_MESSAGE_SIZE_GROUP_A_ENUM msg_size; + LIBLTE_RRC_MESSAGE_POWER_OFFSET_GROUP_B_ENUM msg_pwr_offset_group_b; + bool present; +}LIBLTE_RRC_PREAMBLES_GROUP_A_STRUCT; +typedef struct{ + LIBLTE_RRC_PREAMBLES_GROUP_A_STRUCT preambles_group_a_cnfg; + LIBLTE_RRC_NUMBER_OF_RA_PREAMBLES_ENUM num_ra_preambles; + LIBLTE_RRC_POWER_RAMPING_STEP_ENUM pwr_ramping_step; + LIBLTE_RRC_PREAMBLE_INITIAL_RECEIVED_TARGET_POWER_ENUM preamble_init_rx_target_pwr; + LIBLTE_RRC_PREAMBLE_TRANS_MAX_ENUM preamble_trans_max; + LIBLTE_RRC_RA_RESPONSE_WINDOW_SIZE_ENUM ra_resp_win_size; + LIBLTE_RRC_MAC_CONTENTION_RESOLUTION_TIMER_ENUM mac_con_res_timer; + uint8 max_harq_msg3_tx; +}LIBLTE_RRC_RACH_CONFIG_COMMON_STRUCT; +typedef struct{ + uint8 preamble_index; + uint8 prach_mask_index; +}LIBLTE_RRC_RACH_CONFIG_DEDICATED_STRUCT; +typedef struct{ + LIBLTE_RRC_SRS_BW_CONFIG_ENUM bw_cnfg; + LIBLTE_RRC_SRS_SUBFR_CONFIG_ENUM subfr_cnfg; + bool ack_nack_simul_tx; + bool max_up_pts; + bool max_up_pts_present; + bool present; +}LIBLTE_RRC_SRS_UL_CONFIG_COMMON_STRUCT; +typedef struct{ + LIBLTE_RRC_SUBFRAME_ASSIGNMENT_ENUM sf_assignment; + LIBLTE_RRC_SPECIAL_SUBFRAME_PATTERNS_ENUM special_sf_patterns; +}LIBLTE_RRC_TDD_CONFIG_STRUCT; +typedef struct{ + LIBLTE_RRC_DELTA_F_PUCCH_FORMAT_1_ENUM format_1; + LIBLTE_RRC_DELTA_F_PUCCH_FORMAT_1B_ENUM format_1b; + LIBLTE_RRC_DELTA_F_PUCCH_FORMAT_2_ENUM format_2; + LIBLTE_RRC_DELTA_F_PUCCH_FORMAT_2A_ENUM format_2a; + LIBLTE_RRC_DELTA_F_PUCCH_FORMAT_2B_ENUM format_2b; +}LIBLTE_RRC_DELTA_FLIST_PUCCH_STRUCT; +typedef struct{ + LIBLTE_RRC_DELTA_FLIST_PUCCH_STRUCT delta_flist_pucch; + LIBLTE_RRC_UL_POWER_CONTROL_ALPHA_ENUM alpha; + int8 p0_nominal_pusch; + int8 p0_nominal_pucch; + int8 delta_preamble_msg3; +}LIBLTE_RRC_UL_POWER_CONTROL_COMMON_STRUCT; +typedef struct{ + LIBLTE_RRC_RACH_CONFIG_COMMON_STRUCT rach_cnfg; + LIBLTE_RRC_PRACH_CONFIG_STRUCT prach_cnfg; + LIBLTE_RRC_PDSCH_CONFIG_COMMON_STRUCT pdsch_cnfg; + LIBLTE_RRC_PUSCH_CONFIG_COMMON_STRUCT pusch_cnfg; + LIBLTE_RRC_PHICH_CONFIG_STRUCT phich_cnfg; + LIBLTE_RRC_PUCCH_CONFIG_COMMON_STRUCT pucch_cnfg; + LIBLTE_RRC_SRS_UL_CONFIG_COMMON_STRUCT srs_ul_cnfg; + LIBLTE_RRC_UL_POWER_CONTROL_COMMON_STRUCT ul_pwr_ctrl; + LIBLTE_RRC_TDD_CONFIG_STRUCT tdd_cnfg; + LIBLTE_RRC_ANTENNA_PORTS_COUNT_ENUM ant_info; + LIBLTE_RRC_UL_CP_LENGTH_ENUM ul_cp_length; + int8 p_max; + bool rach_cnfg_present; + bool pdsch_cnfg_present; + bool phich_cnfg_present; + bool pucch_cnfg_present; + bool srs_ul_cnfg_present; + bool ul_pwr_ctrl_present; + bool ant_info_present; + bool p_max_present; + bool tdd_cnfg_present; +}LIBLTE_RRC_RR_CONFIG_COMMON_STRUCT; +typedef struct{ + uint16 dl_carrier_freq; + uint16 ul_carrier_freq; + bool ul_carrier_freq_present; +}LIBLTE_RRC_CARRIER_FREQ_EUTRA_STRUCT; +typedef struct{ + LIBLTE_RRC_BANDWIDTH_ENUM dl_bw; + LIBLTE_RRC_BANDWIDTH_ENUM ul_bw; + bool ul_bw_present; +}LIBLTE_RRC_CARRIER_BANDWIDTH_EUTRA_STRUCT; +typedef struct{ + LIBLTE_RRC_CARRIER_FREQ_EUTRA_STRUCT carrier_freq_eutra; + LIBLTE_RRC_CARRIER_BANDWIDTH_EUTRA_STRUCT carrier_bw_eutra; + LIBLTE_RRC_RR_CONFIG_COMMON_STRUCT rr_cnfg_common; + LIBLTE_RRC_RACH_CONFIG_DEDICATED_STRUCT rach_cnfg_ded; + LIBLTE_RRC_T304_ENUM t304; + uint16 target_pci; + uint16 new_ue_id; + uint8 add_spect_em; + bool carrier_freq_eutra_present; + bool carrier_bw_eutra_present; + bool add_spect_em_present; + bool rach_cnfg_ded_present; +}LIBLTE_RRC_MOBILITY_CONTROL_INFO_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_mobility_control_info_ie(LIBLTE_RRC_MOBILITY_CONTROL_INFO_STRUCT *mob_ctrl_info, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_mobility_control_info_ie(uint8 **ie_ptr, + LIBLTE_RRC_MOBILITY_CONTROL_INFO_STRUCT *mob_ctrl_info); + +/********************************************************************* + IE Name: Mobility Parameters CDMA2000 (1xRTT) + + Description: Contains the parameters provided to the UE for + handover and (enhanced) CSFB to 1xRTT support + + Document Reference: 36.331 v10.0.0 Section 6.3.4 +*********************************************************************/ +// Defines +// Enums +// Structs +// Functions +// FIXME + +/********************************************************************* + IE Name: Mobility State Parameters + + Description: Contains parameters to determine UE mobility state + + Document Reference: 36.331 v10.0.0 Section 6.3.4 +*********************************************************************/ +// Defines +// Enums +// Mobility State Parameters enums defined above +// Structs +// Mobility State Parameters struct defined above +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_mobility_state_parameters_ie(LIBLTE_RRC_MOBILITY_STATE_PARAMETERS_STRUCT *mobility_state_params, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_mobility_state_parameters_ie(uint8 **ie_ptr, + LIBLTE_RRC_MOBILITY_STATE_PARAMETERS_STRUCT *mobility_state_params); + +/********************************************************************* + IE Name: Phys Cell ID + + Description: Indicates the physical layer identity of the cell + + Document Reference: 36.331 v10.0.0 Section 6.3.4 +*********************************************************************/ +// Defines +// Enums +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_phys_cell_id_ie(uint16 phys_cell_id, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_phys_cell_id_ie(uint8 **ie_ptr, + uint16 *phys_cell_id); + +/********************************************************************* + IE Name: Phys Cell ID Range + + Description: Encodes either a single or a range of physical cell + identities + + Document Reference: 36.331 v10.0.0 Section 6.3.4 +*********************************************************************/ +// Defines +// Enums +// Phys Cell ID Range enum defined above +// Structs +// Phys Cell ID Range struct defined above +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_phys_cell_id_range_ie(LIBLTE_RRC_PHYS_CELL_ID_RANGE_STRUCT *phys_cell_id_range, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_phys_cell_id_range_ie(uint8 **ie_ptr, + LIBLTE_RRC_PHYS_CELL_ID_RANGE_STRUCT *phys_cell_id_range); + +/********************************************************************* + IE Name: Phys Cell ID Range UTRA FDD List + + Description: Encodes one or more of Phys Cell ID Range UTRA FDD + + Document Reference: 36.331 v10.0.0 Section 6.3.4 +*********************************************************************/ +// Defines +// Enums +// Structs +// Functions +// FIXME + +/********************************************************************* + IE Name: Phys Cell ID CDMA2000 + + Description: Identifies the PN offset that represents the + "Physical cell identity" in CDMA2000 + + Document Reference: 36.331 v10.0.0 Section 6.3.4 +*********************************************************************/ +// Defines +#define LIBLTE_RRC_MAX_PN_OFFSET 511 +// Enums +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_phys_cell_id_cdma2000_ie(uint16 phys_cell_id, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_phys_cell_id_cdma2000_ie(uint8 **ie_ptr, + uint16 *phys_cell_id); + +/********************************************************************* + IE Name: Phys Cell ID GERAN + + Description: Contains the Base Station Identity Code (BSIC) + + Document Reference: 36.331 v10.0.0 Section 6.3.4 +*********************************************************************/ +// Defines +// Enums +// Structs +// Phys Cell ID GERAN struct defined above +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_phys_cell_id_geran_ie(LIBLTE_RRC_PHYS_CELL_ID_GERAN_STRUCT *phys_cell_id, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_phys_cell_id_geran_ie(uint8 **ie_ptr, + LIBLTE_RRC_PHYS_CELL_ID_GERAN_STRUCT *phys_cell_id); + +/********************************************************************* + IE Name: Phys Cell ID UTRA FDD + + Description: Indicates the physical layer identity of the cell + + Document Reference: 36.331 v10.0.0 Section 6.3.4 +*********************************************************************/ +// Defines +// Enums +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_phys_cell_id_utra_fdd_ie(uint16 phys_cell_id, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_phys_cell_id_utra_fdd_ie(uint8 **ie_ptr, + uint16 *phys_cell_id); + +/********************************************************************* + IE Name: Phys Cell ID UTRA TDD + + Description: Indicates the physical layer identity of the cell + + Document Reference: 36.331 v10.0.0 Section 6.3.4 +*********************************************************************/ +// Defines +// Enums +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_phys_cell_id_utra_tdd_ie(uint8 phys_cell_id, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_phys_cell_id_utra_tdd_ie(uint8 **ie_ptr, + uint8 *phys_cell_id); + +/********************************************************************* + IE Name: PLMN Identity + + Description: Identifies a Public Land Mobile Network + + Document Reference: 36.331 v10.0.0 Section 6.3.4 +*********************************************************************/ +// Defines +#define LIBLTE_RRC_MCC_NOT_PRESENT 0xFFFF +// Enums +// Structs +// PLMN Identity struct defined above +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_plmn_identity_ie(LIBLTE_RRC_PLMN_IDENTITY_STRUCT *plmn_id, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_plmn_identity_ie(uint8 **ie_ptr, + LIBLTE_RRC_PLMN_IDENTITY_STRUCT *plmn_id); + +/********************************************************************* + IE Name: Pre Registration Info HRPD + + Description: FIXME + + Document Reference: 36.331 v10.0.0 Section 6.3.4 +*********************************************************************/ +// Defines +// Enums +// Structs +// Pre Registration Info HRPD struct defined above +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_pre_registration_info_hrpd_ie(LIBLTE_RRC_PRE_REGISTRATION_INFO_HRPD_STRUCT *pre_reg_info_hrpd, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_pre_registration_info_hrpd_ie(uint8 **ie_ptr, + LIBLTE_RRC_PRE_REGISTRATION_INFO_HRPD_STRUCT *pre_reg_info_hrpd); + +/********************************************************************* + IE Name: Q Qual Min + + Description: Indicates for cell selection/re-selection the + required minimum received RSRQ level in the (E-UTRA) + cell + + Document Reference: 36.331 v10.0.0 Section 6.3.4 +*********************************************************************/ +// Defines +// Enums +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_q_qual_min_ie(int8 q_qual_min, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_q_qual_min_ie(uint8 **ie_ptr, + int8 *q_qual_min); + +/********************************************************************* + IE Name: Q Rx Lev Min + + Description: Indicates the required minimum received RSRP level in + the (E-UTRA) cell for cell selection/re-selection + + Document Reference: 36.331 v10.0.0 Section 6.3.4 +*********************************************************************/ +// Defines +// Enums +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_q_rx_lev_min_ie(int16 q_rx_lev_min, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_q_rx_lev_min_ie(uint8 **ie_ptr, + int16 *q_rx_lev_min); + +/********************************************************************* + IE Name: Q Offset Range + + Description: Indicates a cell or frequency specific offset to be + applied when evaluating candidates for cell + reselection or when evaluating triggering conditions + for measurement reporting + + Document Reference: 36.331 v10.0.0 Section 6.3.4 +*********************************************************************/ +// Defines +// Enums +// Q Offset Range enum defined above +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_q_offset_range_ie(LIBLTE_RRC_Q_OFFSET_RANGE_ENUM q_offset_range, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_q_offset_range_ie(uint8 **ie_ptr, + LIBLTE_RRC_Q_OFFSET_RANGE_ENUM *q_offset_range); + +/********************************************************************* + IE Name: Q Offset Range Inter RAT + + Description: Indicates a frequency specific offset to be applied + when evaluating triggering conditions for + measurement reporting + + Document Reference: 36.331 v10.0.0 Section 6.3.4 +*********************************************************************/ +// Defines +// Enums +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_q_offset_range_inter_rat_ie(int8 q_offset_range_inter_rat, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_q_offset_range_inter_rat_ie(uint8 **ie_ptr, + int8 *q_offset_range_inter_rat); + +/********************************************************************* + IE Name: Reselection Threshold + + Description: Indicates an RX level threshold for cell reselection + + Document Reference: 36.331 v10.0.0 Section 6.3.4 +*********************************************************************/ +// Defines +// Enums +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_reselection_threshold_ie(uint8 resel_thresh, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_reselection_threshold_ie(uint8 **ie_ptr, + uint8 *resel_thresh); + +/********************************************************************* + IE Name: Reselection Threshold Q + + Description: Indicates a quality level threshold for cell + reselection + + Document Reference: 36.331 v10.0.0 Section 6.3.4 +*********************************************************************/ +// Defines +// Enums +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_reselection_threshold_q_ie(uint8 resel_thresh_q, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_reselection_threshold_q_ie(uint8 **ie_ptr, + uint8 *resel_thresh_q); + +/********************************************************************* + IE Name: S Cell Index + + Description: Contains a short identity, used to identify an + SCell + + Document Reference: 36.331 v10.0.0 Section 6.3.4 +*********************************************************************/ +// Defines +// Enums +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_s_cell_index_ie(uint8 s_cell_idx, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_s_cell_index_ie(uint8 **ie_ptr, + uint8 *s_cell_idx); + +/********************************************************************* + IE Name: Serv Cell Index + + Description: Contains a short identity, used to identify a + serving cell + + Document Reference: 36.331 v10.0.0 Section 6.3.4 +*********************************************************************/ +// Defines +// Enums +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_serv_cell_index_ie(uint8 serv_cell_idx, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_serv_cell_index_ie(uint8 **ie_ptr, + uint8 *serv_cell_idx); + +/********************************************************************* + IE Name: Speed State Scale Factors + + Description: Contains factors, to be applied when the UE is in + medium or high speed state, used for scaling a + mobility control related parameter + + Document Reference: 36.331 v10.0.0 Section 6.3.4 +*********************************************************************/ +// Defines +// Enums +// Speed State Scale Factors enums defined above +// Structs +// Speed State Scale Factors struct defined above +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_speed_state_scale_factors_ie(LIBLTE_RRC_SPEED_STATE_SCALE_FACTORS_STRUCT *speed_state_scale_factors, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_speed_state_scale_factors_ie(uint8 **ie_ptr, + LIBLTE_RRC_SPEED_STATE_SCALE_FACTORS_STRUCT *speed_state_scale_factors); + +/********************************************************************* + IE Name: System Info List GERAN + + Description: Contains system information of a GERAN cell + + Document Reference: 36.331 v10.0.0 Section 6.3.4 +*********************************************************************/ +// Defines +// Enums +// Structs +// Functions +// FIXME + +/********************************************************************* + IE Name: System Time Info CDMA2000 + + Description: Informs the UE about the absolute time in the current + cell + + Document Reference: 36.331 v10.0.0 Section 6.3.4 +*********************************************************************/ +// Defines +// Enums +// Structs +typedef struct{ + uint64 system_time; + bool system_time_async; + bool cdma_eutra_sync; +}LIBLTE_RRC_SYSTEM_TIME_INFO_CDMA2000_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_system_time_info_cdma2000_ie(LIBLTE_RRC_SYSTEM_TIME_INFO_CDMA2000_STRUCT *sys_time_info_cdma2000, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_system_time_info_cdma2000_ie(uint8 **ie_ptr, + LIBLTE_RRC_SYSTEM_TIME_INFO_CDMA2000_STRUCT *sys_time_info_cdma2000); + +/********************************************************************* + IE Name: Tracking Area Code + + Description: Identifies a tracking area within the scope of a + PLMN + + Document Reference: 36.331 v10.0.0 Section 6.3.4 +*********************************************************************/ +// Defines +// Enums +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_tracking_area_code_ie(uint16 tac, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_tracking_area_code_ie(uint8 **ie_ptr, + uint16 *tac); + +/********************************************************************* + IE Name: T Reselection + + Description: Contains the timer T_reselection_rat for E-UTRA, + UTRA, GERAN, or CDMA2000 + + Document Reference: 36.331 v10.0.0 Section 6.3.4 +*********************************************************************/ +// Defines +// Enums +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_t_reselection_ie(uint8 t_resel, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_t_reselection_ie(uint8 **ie_ptr, + uint8 *t_resel); + +/********************************************************************* + IE Name: Next Hop Chaining Count + + Description: Updates the Kenb key and corresponds to parameter + NCC + + Document Reference: 36.331 v10.0.0 Section 6.3.3 +*********************************************************************/ +// Defines +// Enums +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_next_hop_chaining_count_ie(uint8 next_hop_chaining_count, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_next_hop_chaining_count_ie(uint8 **ie_ptr, + uint8 *next_hop_chaining_count); + +/********************************************************************* + IE Name: Security Algorithm Config + + Description: Configures AS integrity protection algorithm (SRBs) + and AS ciphering algorithm (SRBs and DRBs) + + Document Reference: 36.331 v10.0.0 Section 6.3.3 +*********************************************************************/ +// Defines +// Enums +typedef enum{ + LIBLTE_RRC_CIPHERING_ALGORITHM_EEA0 = 0, + LIBLTE_RRC_CIPHERING_ALGORITHM_EEA1, + LIBLTE_RRC_CIPHERING_ALGORITHM_EEA2, + LIBLTE_RRC_CIPHERING_ALGORITHM_SPARE5, + LIBLTE_RRC_CIPHERING_ALGORITHM_SPARE4, + LIBLTE_RRC_CIPHERING_ALGORITHM_SPARE3, + LIBLTE_RRC_CIPHERING_ALGORITHM_SPARE2, + LIBLTE_RRC_CIPHERING_ALGORITHM_SPARE1, + LIBLTE_RRC_CIPHERING_ALGORITHM_N_ITEMS, +}LIBLTE_RRC_CIPHERING_ALGORITHM_ENUM; +static const char liblte_rrc_ciphering_algorithm_text[LIBLTE_RRC_CIPHERING_ALGORITHM_N_ITEMS][20] = { "EEA0", "EEA1", "EEA2", "SPARE", + "SPARE", "SPARE", "SPARE", "SPARE"}; +typedef enum{ + LIBLTE_RRC_INTEGRITY_PROT_ALGORITHM_EIA0_V920 = 0, + LIBLTE_RRC_INTEGRITY_PROT_ALGORITHM_EIA1, + LIBLTE_RRC_INTEGRITY_PROT_ALGORITHM_EIA2, + LIBLTE_RRC_INTEGRITY_PROT_ALGORITHM_SPARE5, + LIBLTE_RRC_INTEGRITY_PROT_ALGORITHM_SPARE4, + LIBLTE_RRC_INTEGRITY_PROT_ALGORITHM_SPARE3, + LIBLTE_RRC_INTEGRITY_PROT_ALGORITHM_SPARE2, + LIBLTE_RRC_INTEGRITY_PROT_ALGORITHM_SPARE1, + LIBLTE_RRC_INTEGRITY_PROT_ALGORITHM_N_ITEMS, +}LIBLTE_RRC_INTEGRITY_PROT_ALGORITHM_ENUM; +static const char liblte_rrc_integrity_prot_algorithm_text[LIBLTE_RRC_INTEGRITY_PROT_ALGORITHM_N_ITEMS][20] = { "EIA0", "EIA1", "EIA2", "SPARE", + "SPARE", "SPARE", "SPARE", "SPARE"}; +// Structs +typedef struct{ + LIBLTE_RRC_CIPHERING_ALGORITHM_ENUM cipher_alg; + LIBLTE_RRC_INTEGRITY_PROT_ALGORITHM_ENUM int_alg; +}LIBLTE_RRC_SECURITY_ALGORITHM_CONFIG_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_security_algorithm_config_ie(LIBLTE_RRC_SECURITY_ALGORITHM_CONFIG_STRUCT *sec_alg_cnfg, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_security_algorithm_config_ie(uint8 **ie_ptr, + LIBLTE_RRC_SECURITY_ALGORITHM_CONFIG_STRUCT *sec_alg_cnfg); + +/********************************************************************* + IE Name: Short MAC I + + Description: Identifies and verifies the UE at RRC connection + re-establishment + + Document Reference: 36.331 v10.0.0 Section 6.3.3 +*********************************************************************/ +// Defines +// Enums +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_short_mac_i_ie(uint16 short_mac_i, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_short_mac_i_ie(uint8 **ie_ptr, + uint16 *short_mac_i); + +/********************************************************************* + IE Name: Antenna Info + + Description: Specifies the common and the UE specific antenna + configuration + + Document Reference: 36.331 v10.0.0 Section 6.3.2 +*********************************************************************/ +// Defines +// Enums +// Antenna Ports Count enum defined above +typedef enum{ + LIBLTE_RRC_TRANSMISSION_MODE_1 = 0, + LIBLTE_RRC_TRANSMISSION_MODE_2, + LIBLTE_RRC_TRANSMISSION_MODE_3, + LIBLTE_RRC_TRANSMISSION_MODE_4, + LIBLTE_RRC_TRANSMISSION_MODE_5, + LIBLTE_RRC_TRANSMISSION_MODE_6, + LIBLTE_RRC_TRANSMISSION_MODE_7, + LIBLTE_RRC_TRANSMISSION_MODE_8, + LIBLTE_RRC_TRANSMISSION_MODE_N_ITEMS, +}LIBLTE_RRC_TRANSMISSION_MODE_ENUM; +static const char liblte_rrc_transmission_mode_text[LIBLTE_RRC_TRANSMISSION_MODE_N_ITEMS][20] = {"1", "2", "3", "4", + "5", "6", "7", "8"}; +static const uint8 liblte_rrc_transmission_mode_num[LIBLTE_RRC_TRANSMISSION_MODE_N_ITEMS] = {1, 2, 3, 4, 5, 6, 7, 8}; +typedef enum{ + LIBLTE_RRC_CODEBOOK_SUBSET_RESTRICTION_N2_TM3 = 0, + LIBLTE_RRC_CODEBOOK_SUBSET_RESTRICTION_N4_TM3, + LIBLTE_RRC_CODEBOOK_SUBSET_RESTRICTION_N2_TM4, + LIBLTE_RRC_CODEBOOK_SUBSET_RESTRICTION_N4_TM4, + LIBLTE_RRC_CODEBOOK_SUBSET_RESTRICTION_N2_TM5, + LIBLTE_RRC_CODEBOOK_SUBSET_RESTRICTION_N4_TM5, + LIBLTE_RRC_CODEBOOK_SUBSET_RESTRICTION_N2_TM6, + LIBLTE_RRC_CODEBOOK_SUBSET_RESTRICTION_N4_TM6, + LIBLTE_RRC_CODEBOOK_SUBSET_RESTRICTION_N_ITEMS, +}LIBLTE_RRC_CODEBOOK_SUBSET_RESTRICTION_CHOICE_ENUM; +static const char liblte_rrc_codebook_subset_restriction_choice_text[LIBLTE_RRC_CODEBOOK_SUBSET_RESTRICTION_N_ITEMS][20] = {"n2_tm3", "n4_tm3", "n2_tm4", "n4_tm4", + "n2_tm5", "n4_tm5", "n2_tm6", "n4_tm6"}; +typedef enum{ + LIBLTE_RRC_UE_TX_ANTENNA_SELECTION_CLOSED_LOOP = 0, + LIBLTE_RRC_UE_TX_ANTENNA_SELECTION_OPEN_LOOP, + LIBLTE_RRC_UE_TX_ANTENNA_SELECTION_N_ITEMS, +}LIBLTE_RRC_UE_TX_ANTENNA_SELECTION_ENUM; +static const char liblte_rrc_ue_tx_antenna_selection_text[LIBLTE_RRC_UE_TX_ANTENNA_SELECTION_N_ITEMS][20] = {"closed_loop", "open_loop"}; +// Structs +typedef struct{ + LIBLTE_RRC_TRANSMISSION_MODE_ENUM tx_mode; + LIBLTE_RRC_CODEBOOK_SUBSET_RESTRICTION_CHOICE_ENUM codebook_subset_restriction_choice; + LIBLTE_RRC_UE_TX_ANTENNA_SELECTION_ENUM ue_tx_antenna_selection_setup; + uint64 codebook_subset_restriction; + bool codebook_subset_restriction_present; + bool ue_tx_antenna_selection_setup_present; +}LIBLTE_RRC_ANTENNA_INFO_DEDICATED_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_antenna_info_common_ie(LIBLTE_RRC_ANTENNA_PORTS_COUNT_ENUM antenna_ports_cnt, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_antenna_info_common_ie(uint8 **ie_ptr, + LIBLTE_RRC_ANTENNA_PORTS_COUNT_ENUM *antenna_ports_cnt); +LIBLTE_ERROR_ENUM liblte_rrc_pack_antenna_info_dedicated_ie(LIBLTE_RRC_ANTENNA_INFO_DEDICATED_STRUCT *antenna_info, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_antenna_info_dedicated_ie(uint8 **ie_ptr, + LIBLTE_RRC_ANTENNA_INFO_DEDICATED_STRUCT *antenna_info); + +/********************************************************************* + IE Name: CQI Report Config + + Description: Specifies the CQI reporting configuration + + Document Reference: 36.331 v10.0.0 Section 6.3.2 +*********************************************************************/ +// Defines +// Enums +typedef enum{ + LIBLTE_RRC_CQI_REPORT_MODE_APERIODIC_RM12 = 0, + LIBLTE_RRC_CQI_REPORT_MODE_APERIODIC_RM20, + LIBLTE_RRC_CQI_REPORT_MODE_APERIODIC_RM22, + LIBLTE_RRC_CQI_REPORT_MODE_APERIODIC_RM30, + LIBLTE_RRC_CQI_REPORT_MODE_APERIODIC_RM31, + LIBLTE_RRC_CQI_REPORT_MODE_APERIODIC_SPARE3, + LIBLTE_RRC_CQI_REPORT_MODE_APERIODIC_SPARE2, + LIBLTE_RRC_CQI_REPORT_MODE_APERIODIC_SPARE1, + LIBLTE_RRC_CQI_REPORT_MODE_APERIODIC_N_ITEMS, +}LIBLTE_RRC_CQI_REPORT_MODE_APERIODIC_ENUM; +static const char liblte_rrc_cqi_report_mode_aperiodic_text[LIBLTE_RRC_CQI_REPORT_MODE_APERIODIC_N_ITEMS][20] = { "rm12", "rm20", "rm22", "rm30", + "rm31", "SPARE", "SPARE", "SPARE"}; +typedef enum{ + LIBLTE_RRC_CQI_FORMAT_INDICATOR_PERIODIC_WIDEBAND_CQI = 0, + LIBLTE_RRC_CQI_FORMAT_INDICATOR_PERIODIC_SUBBAND_CQI, + LIBLTE_RRC_CQI_FORMAT_INDICATOR_PERIODIC_N_ITEMS, +}LIBLTE_RRC_CQI_FORMAT_INDICATOR_PERIODIC_ENUM; +static const char liblte_rrc_cqi_format_indicator_periodic_text[LIBLTE_RRC_CQI_FORMAT_INDICATOR_PERIODIC_N_ITEMS][20] = {"wideband_cqi", "subband_cqi"}; +// Structs +typedef struct{ + LIBLTE_RRC_CQI_FORMAT_INDICATOR_PERIODIC_ENUM format_ind_periodic; + uint32 pucch_resource_idx; + uint32 pmi_cnfg_idx; + uint32 ri_cnfg_idx; + uint32 format_ind_periodic_subband_k; + bool ri_cnfg_idx_present; + bool simult_ack_nack_and_cqi; +}LIBLTE_RRC_CQI_REPORT_PERIODIC_STRUCT; +typedef struct{ + LIBLTE_RRC_CQI_REPORT_PERIODIC_STRUCT report_periodic; + LIBLTE_RRC_CQI_REPORT_MODE_APERIODIC_ENUM report_mode_aperiodic; + int32 nom_pdsch_rs_epre_offset; + bool report_mode_aperiodic_present; + bool report_periodic_present; + bool report_periodic_setup_present; +}LIBLTE_RRC_CQI_REPORT_CONFIG_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_cqi_report_config_ie(LIBLTE_RRC_CQI_REPORT_CONFIG_STRUCT *cqi_report_cnfg, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_cqi_report_config_ie(uint8 **ie_ptr, + LIBLTE_RRC_CQI_REPORT_CONFIG_STRUCT *cqi_report_cnfg); + +/********************************************************************* + IE Name: Cross Carrier Scheduling Config + + Description: Specifies the configuration when the cross carrier + scheduling is used in a cell + + Document Reference: 36.331 v10.0.0 Section 6.3.2 +*********************************************************************/ +// Defines +// Enums +// Structs +// Functions +// FIXME + +/********************************************************************* + IE Name: CSI RS Config + + Description: Specifies the CSI (Channel State Information) + reference signal configuration + + Document Reference: 36.331 v10.0.0 Section 6.3.2 +*********************************************************************/ +// Defines +// Enums +// Structs +// Functions +// FIXME + +/********************************************************************* + IE Name: DRB Identity + + Description: Identifies a DRB used by a UE + + Document Reference: 36.331 v10.0.0 Section 6.3.2 +*********************************************************************/ +// Defines +// Enums +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_drb_identity_ie(uint8 drb_id, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_drb_identity_ie(uint8 **ie_ptr, + uint8 *drb_id); + +/********************************************************************* + IE Name: Logical Channel Config + + Description: Configures the logical channel parameters + + Document Reference: 36.331 v10.0.0 Section 6.3.2 +*********************************************************************/ +// Defines +// Enums +typedef enum{ + LIBLTE_RRC_PRIORITIZED_BIT_RATE_KBPS_0 = 0, + LIBLTE_RRC_PRIORITIZED_BIT_RATE_KBPS_8, + LIBLTE_RRC_PRIORITIZED_BIT_RATE_KBPS_16, + LIBLTE_RRC_PRIORITIZED_BIT_RATE_KBPS_32, + LIBLTE_RRC_PRIORITIZED_BIT_RATE_KBPS_64, + LIBLTE_RRC_PRIORITIZED_BIT_RATE_KBPS_128, + LIBLTE_RRC_PRIORITIZED_BIT_RATE_KBPS_256, + LIBLTE_RRC_PRIORITIZED_BIT_RATE_INFINITY, + LIBLTE_RRC_PRIORITIZED_BIT_RATE_SPARE8, + LIBLTE_RRC_PRIORITIZED_BIT_RATE_SPARE7, + LIBLTE_RRC_PRIORITIZED_BIT_RATE_SPARE6, + LIBLTE_RRC_PRIORITIZED_BIT_RATE_SPARE5, + LIBLTE_RRC_PRIORITIZED_BIT_RATE_SPARE4, + LIBLTE_RRC_PRIORITIZED_BIT_RATE_SPARE3, + LIBLTE_RRC_PRIORITIZED_BIT_RATE_SPARE2, + LIBLTE_RRC_PRIORITIZED_BIT_RATE_SPARE1, + LIBLTE_RRC_PRIORITIZED_BIT_RATE_N_ITEMS, +}LIBLTE_RRC_PRIORITIZED_BIT_RATE_ENUM; +static const char liblte_rrc_prioritized_bit_rate_text[LIBLTE_RRC_PRIORITIZED_BIT_RATE_N_ITEMS][20] = { "0", "8", "16", "32", + "64", "128", "256", "INFINITY", + "SPARE", "SPARE", "SPARE", "SPARE", + "SPARE", "SPARE", "SPARE", "SPARE"}; +static const int liblte_rrc_prioritized_bit_rate_num[LIBLTE_RRC_PRIORITIZED_BIT_RATE_N_ITEMS] = { 0 , 8 , 16 , 32 , + 64 , 128 , 256 , -1 , + -1 , -1 , -1 , -1 , + -1 , -1 , -1 , -1 }; +typedef enum{ + LIBLTE_RRC_BUCKET_SIZE_DURATION_MS50 = 0, + LIBLTE_RRC_BUCKET_SIZE_DURATION_MS100, + LIBLTE_RRC_BUCKET_SIZE_DURATION_MS150, + LIBLTE_RRC_BUCKET_SIZE_DURATION_MS300, + LIBLTE_RRC_BUCKET_SIZE_DURATION_MS500, + LIBLTE_RRC_BUCKET_SIZE_DURATION_MS1000, + LIBLTE_RRC_BUCKET_SIZE_DURATION_SPARE2, + LIBLTE_RRC_BUCKET_SIZE_DURATION_SPARE1, + LIBLTE_RRC_BUCKET_SIZE_DURATION_N_ITEMS, +}LIBLTE_RRC_BUCKET_SIZE_DURATION_ENUM; +static const char liblte_rrc_bucket_size_duration_text[LIBLTE_RRC_BUCKET_SIZE_DURATION_N_ITEMS][20] = { "50", "100", "150", "300", + "500", "1000", "SPARE", "SPARE"}; +static const int16 liblte_rrc_bucket_size_duration_num[LIBLTE_RRC_BUCKET_SIZE_DURATION_N_ITEMS] = {50, 100, 150, 300, 500, 1000, -1, -1}; +typedef enum{ + LIBLTE_RRC_LOGICAL_CHANNEL_SR_MASK_R9_SETUP = 0, + LIBLTE_RRC_LOGICAL_CHANNEL_SR_MASK_R9_N_ITEMS, +}LIBLTE_RRC_LOGICAL_CHANNEL_SR_MASK_R9_ENUM; +static const char liblte_rrc_logical_channel_sr_mask_r9_text[LIBLTE_RRC_LOGICAL_CHANNEL_SR_MASK_R9_N_ITEMS][20] = {"SETUP"}; +// Structs +typedef struct{ + LIBLTE_RRC_PRIORITIZED_BIT_RATE_ENUM prioritized_bit_rate; + LIBLTE_RRC_BUCKET_SIZE_DURATION_ENUM bucket_size_duration; + uint8 priority; + uint8 log_chan_group; + bool log_chan_group_present; +}LIBLTE_RRC_UL_SPECIFIC_PARAMETERS_STRUCT; +typedef struct{ + LIBLTE_RRC_UL_SPECIFIC_PARAMETERS_STRUCT ul_specific_params; + LIBLTE_RRC_LOGICAL_CHANNEL_SR_MASK_R9_ENUM log_chan_sr_mask; + bool ul_specific_params_present; + bool log_chan_sr_mask_present; +}LIBLTE_RRC_LOGICAL_CHANNEL_CONFIG_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_logical_channel_config_ie(LIBLTE_RRC_LOGICAL_CHANNEL_CONFIG_STRUCT *log_chan_cnfg, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_logical_channel_config_ie(uint8 **ie_ptr, + LIBLTE_RRC_LOGICAL_CHANNEL_CONFIG_STRUCT *log_chan_cnfg); + +/********************************************************************* + IE Name: MAC Main Config + + Description: Specifies the MAC main configuration for signalling + and data radio bearers + + Document Reference: 36.331 v10.0.0 Section 6.3.2 +*********************************************************************/ +// Defines +// Enums +typedef enum{ + LIBLTE_RRC_MAX_HARQ_TX_N1 = 0, + LIBLTE_RRC_MAX_HARQ_TX_N2, + LIBLTE_RRC_MAX_HARQ_TX_N3, + LIBLTE_RRC_MAX_HARQ_TX_N4, + LIBLTE_RRC_MAX_HARQ_TX_N5, + LIBLTE_RRC_MAX_HARQ_TX_N6, + LIBLTE_RRC_MAX_HARQ_TX_N7, + LIBLTE_RRC_MAX_HARQ_TX_N8, + LIBLTE_RRC_MAX_HARQ_TX_N10, + LIBLTE_RRC_MAX_HARQ_TX_N12, + LIBLTE_RRC_MAX_HARQ_TX_N16, + LIBLTE_RRC_MAX_HARQ_TX_N20, + LIBLTE_RRC_MAX_HARQ_TX_N24, + LIBLTE_RRC_MAX_HARQ_TX_N28, + LIBLTE_RRC_MAX_HARQ_TX_SPARE2, + LIBLTE_RRC_MAX_HARQ_TX_SPARE1, + LIBLTE_RRC_MAX_HARQ_TX_N_ITEMS, +}LIBLTE_RRC_MAX_HARQ_TX_ENUM; +static const char liblte_rrc_max_harq_tx_text[LIBLTE_RRC_MAX_HARQ_TX_N_ITEMS][20] = { "1", "2", "3", "4", + "5", "6", "7", "8", + "10", "12", "16", "20", + "24", "28", "SPARE", "SPARE"}; +static const int8 liblte_rrc_max_harq_tx_num[LIBLTE_RRC_MAX_HARQ_TX_N_ITEMS] = {1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 16, 20, 24, 28, -1, -1}; +typedef enum{ + LIBLTE_RRC_PERIODIC_BSR_TIMER_SF5 = 0, + LIBLTE_RRC_PERIODIC_BSR_TIMER_SF10, + LIBLTE_RRC_PERIODIC_BSR_TIMER_SF16, + LIBLTE_RRC_PERIODIC_BSR_TIMER_SF20, + LIBLTE_RRC_PERIODIC_BSR_TIMER_SF32, + LIBLTE_RRC_PERIODIC_BSR_TIMER_SF40, + LIBLTE_RRC_PERIODIC_BSR_TIMER_SF64, + LIBLTE_RRC_PERIODIC_BSR_TIMER_SF80, + LIBLTE_RRC_PERIODIC_BSR_TIMER_SF128, + LIBLTE_RRC_PERIODIC_BSR_TIMER_SF160, + LIBLTE_RRC_PERIODIC_BSR_TIMER_SF320, + LIBLTE_RRC_PERIODIC_BSR_TIMER_SF640, + LIBLTE_RRC_PERIODIC_BSR_TIMER_SF1280, + LIBLTE_RRC_PERIODIC_BSR_TIMER_SF2560, + LIBLTE_RRC_PERIODIC_BSR_TIMER_INFINITY, + LIBLTE_RRC_PERIODIC_BSR_TIMER_SPARE, + LIBLTE_RRC_PERIODIC_BSR_TIMER_N_ITEMS, +}LIBLTE_RRC_PERIODIC_BSR_TIMER_ENUM; +static const char liblte_rrc_periodic_bsr_timer_text[LIBLTE_RRC_PERIODIC_BSR_TIMER_N_ITEMS][20] = { "sf5", "sf10", "sf16", "sf20", + "sf32", "sf40", "sf64", "sf80", + "sf128", "sf160", "sf320", "sf640", + "sf1280", "sf2560", "INFINITY", "SPARE"}; +static const int32 liblte_rrc_periodic_bsr_timer_num[LIBLTE_RRC_PERIODIC_BSR_TIMER_N_ITEMS] = { 5, 10, 16, 20, 32, 40, 64, 80, 128, 160, 320, 640, + 1280, 2560, -1, -1}; +typedef enum{ + LIBLTE_RRC_RETRANSMISSION_BSR_TIMER_SF320 = 0, + LIBLTE_RRC_RETRANSMISSION_BSR_TIMER_SF640, + LIBLTE_RRC_RETRANSMISSION_BSR_TIMER_SF1280, + LIBLTE_RRC_RETRANSMISSION_BSR_TIMER_SF2560, + LIBLTE_RRC_RETRANSMISSION_BSR_TIMER_SF5120, + LIBLTE_RRC_RETRANSMISSION_BSR_TIMER_SF10240, + LIBLTE_RRC_RETRANSMISSION_BSR_TIMER_SPARE2, + LIBLTE_RRC_RETRANSMISSION_BSR_TIMER_SPARE1, + LIBLTE_RRC_RETRANSMISSION_BSR_TIMER_N_ITEMS, +}LIBLTE_RRC_RETRANSMISSION_BSR_TIMER_ENUM; +static const char liblte_rrc_retransmission_bsr_timer_text[LIBLTE_RRC_RETRANSMISSION_BSR_TIMER_N_ITEMS][20] = { "sf320", "sf640", "sf1280", "sf2560", + "sf5120", "sf10240", "SPARE", "SPARE"}; +static const int32 liblte_rrc_retransmission_bsr_timer_num[LIBLTE_RRC_RETRANSMISSION_BSR_TIMER_N_ITEMS] = { 320, 640, 1280, 2560, 5120, 10240, -1, -1}; +typedef enum{ + LIBLTE_RRC_ON_DURATION_TIMER_PSF1 = 0, + LIBLTE_RRC_ON_DURATION_TIMER_PSF2, + LIBLTE_RRC_ON_DURATION_TIMER_PSF3, + LIBLTE_RRC_ON_DURATION_TIMER_PSF4, + LIBLTE_RRC_ON_DURATION_TIMER_PSF5, + LIBLTE_RRC_ON_DURATION_TIMER_PSF6, + LIBLTE_RRC_ON_DURATION_TIMER_PSF8, + LIBLTE_RRC_ON_DURATION_TIMER_PSF10, + LIBLTE_RRC_ON_DURATION_TIMER_PSF20, + LIBLTE_RRC_ON_DURATION_TIMER_PSF30, + LIBLTE_RRC_ON_DURATION_TIMER_PSF40, + LIBLTE_RRC_ON_DURATION_TIMER_PSF50, + LIBLTE_RRC_ON_DURATION_TIMER_PSF60, + LIBLTE_RRC_ON_DURATION_TIMER_PSF80, + LIBLTE_RRC_ON_DURATION_TIMER_PSF100, + LIBLTE_RRC_ON_DURATION_TIMER_PSF200, + LIBLTE_RRC_ON_DURATION_TIMER_N_ITEMS, +}LIBLTE_RRC_ON_DURATION_TIMER_ENUM; +static const char liblte_rrc_on_duration_timer_text[LIBLTE_RRC_ON_DURATION_TIMER_N_ITEMS][20] = { "psf1", "psf2", "psf3", "psf4", + "psf5", "psf6", "psf8", "psf10", + "psf20", "psf30", "psf40", "psf50", + "psf60", "psf80", "psf100", "psf200"}; +typedef enum{ + LIBLTE_RRC_DRX_INACTIVITY_TIMER_PSF1 = 0, + LIBLTE_RRC_DRX_INACTIVITY_TIMER_PSF2, + LIBLTE_RRC_DRX_INACTIVITY_TIMER_PSF3, + LIBLTE_RRC_DRX_INACTIVITY_TIMER_PSF4, + LIBLTE_RRC_DRX_INACTIVITY_TIMER_PSF5, + LIBLTE_RRC_DRX_INACTIVITY_TIMER_PSF6, + LIBLTE_RRC_DRX_INACTIVITY_TIMER_PSF8, + LIBLTE_RRC_DRX_INACTIVITY_TIMER_PSF10, + LIBLTE_RRC_DRX_INACTIVITY_TIMER_PSF20, + LIBLTE_RRC_DRX_INACTIVITY_TIMER_PSF30, + LIBLTE_RRC_DRX_INACTIVITY_TIMER_PSF40, + LIBLTE_RRC_DRX_INACTIVITY_TIMER_PSF50, + LIBLTE_RRC_DRX_INACTIVITY_TIMER_PSF60, + LIBLTE_RRC_DRX_INACTIVITY_TIMER_PSF80, + LIBLTE_RRC_DRX_INACTIVITY_TIMER_PSF100, + LIBLTE_RRC_DRX_INACTIVITY_TIMER_PSF200, + LIBLTE_RRC_DRX_INACTIVITY_TIMER_PSF300, + LIBLTE_RRC_DRX_INACTIVITY_TIMER_PSF500, + LIBLTE_RRC_DRX_INACTIVITY_TIMER_PSF750, + LIBLTE_RRC_DRX_INACTIVITY_TIMER_PSF1280, + LIBLTE_RRC_DRX_INACTIVITY_TIMER_PSF1920, + LIBLTE_RRC_DRX_INACTIVITY_TIMER_PSF2560, + LIBLTE_RRC_DRX_INACTIVITY_TIMER_SPARE10, + LIBLTE_RRC_DRX_INACTIVITY_TIMER_SPARE9, + LIBLTE_RRC_DRX_INACTIVITY_TIMER_SPARE8, + LIBLTE_RRC_DRX_INACTIVITY_TIMER_SPARE7, + LIBLTE_RRC_DRX_INACTIVITY_TIMER_SPARE6, + LIBLTE_RRC_DRX_INACTIVITY_TIMER_SPARE5, + LIBLTE_RRC_DRX_INACTIVITY_TIMER_SPARE4, + LIBLTE_RRC_DRX_INACTIVITY_TIMER_SPARE3, + LIBLTE_RRC_DRX_INACTIVITY_TIMER_SPARE2, + LIBLTE_RRC_DRX_INACTIVITY_TIMER_SPARE1, + LIBLTE_RRC_DRX_INACTIVITY_TIMER_N_ITEMS, +}LIBLTE_RRC_DRX_INACTIVITY_TIMER_ENUM; +static const char liblte_rrc_drx_inactivity_timer_text[LIBLTE_RRC_DRX_INACTIVITY_TIMER_N_ITEMS][20] = { "psf1", "psf2", "psf3", "psf4", + "psf5", "psf6", "psf8", "psf10", + "psf20", "psf30", "psf40", "psf50", + "psf60", "psf80", "psf100", "psf200", + "psf300", "psf500", "psf750", "psf1280", + "psf1920", "psf2560", "SPARE", "SPARE", + "SPARE", "SPARE", "SPARE", "SPARE", + "SPARE", "SPARE", "SPARE", "SPARE"}; +typedef enum{ + LIBLTE_RRC_DRX_RETRANSMISSION_TIMER_PSF1 = 0, + LIBLTE_RRC_DRX_RETRANSMISSION_TIMER_PSF2, + LIBLTE_RRC_DRX_RETRANSMISSION_TIMER_PSF4, + LIBLTE_RRC_DRX_RETRANSMISSION_TIMER_PSF6, + LIBLTE_RRC_DRX_RETRANSMISSION_TIMER_PSF8, + LIBLTE_RRC_DRX_RETRANSMISSION_TIMER_PSF16, + LIBLTE_RRC_DRX_RETRANSMISSION_TIMER_PSF24, + LIBLTE_RRC_DRX_RETRANSMISSION_TIMER_PSF33, + LIBLTE_RRC_DRX_RETRANSMISSION_TIMER_N_ITEMS, +}LIBLTE_RRC_DRX_RETRANSMISSION_TIMER_ENUM; +static const char liblte_rrc_drx_retransmission_timer_text[LIBLTE_RRC_DRX_RETRANSMISSION_TIMER_N_ITEMS][20] = { "psf1", "psf2", "psf4", "psf6", + "psf8", "psf16", "psf24", "psf33"}; +typedef enum{ + LIBLTE_RRC_LONG_DRX_CYCLE_START_OFFSET_SF10 = 0, + LIBLTE_RRC_LONG_DRX_CYCLE_START_OFFSET_SF20, + LIBLTE_RRC_LONG_DRX_CYCLE_START_OFFSET_SF32, + LIBLTE_RRC_LONG_DRX_CYCLE_START_OFFSET_SF40, + LIBLTE_RRC_LONG_DRX_CYCLE_START_OFFSET_SF64, + LIBLTE_RRC_LONG_DRX_CYCLE_START_OFFSET_SF80, + LIBLTE_RRC_LONG_DRX_CYCLE_START_OFFSET_SF128, + LIBLTE_RRC_LONG_DRX_CYCLE_START_OFFSET_SF160, + LIBLTE_RRC_LONG_DRX_CYCLE_START_OFFSET_SF256, + LIBLTE_RRC_LONG_DRX_CYCLE_START_OFFSET_SF320, + LIBLTE_RRC_LONG_DRX_CYCLE_START_OFFSET_SF512, + LIBLTE_RRC_LONG_DRX_CYCLE_START_OFFSET_SF640, + LIBLTE_RRC_LONG_DRX_CYCLE_START_OFFSET_SF1024, + LIBLTE_RRC_LONG_DRX_CYCLE_START_OFFSET_SF1280, + LIBLTE_RRC_LONG_DRX_CYCLE_START_OFFSET_SF2048, + LIBLTE_RRC_LONG_DRX_CYCLE_START_OFFSET_SF2560, + LIBLTE_RRC_LONG_DRX_CYCLE_START_OFFSET_N_ITEMS, +}LIBLTE_RRC_LONG_DRX_CYCLE_START_OFFSET_CHOICE_ENUM; +static const char liblte_rrc_long_drx_cycle_start_offset_choice_text[LIBLTE_RRC_LONG_DRX_CYCLE_START_OFFSET_N_ITEMS][20] = { "sf10", "sf20", "sf32", "sf40", + "sf64", "sf80", "sf128", "sf160", + "sf256", "sf320", "sf512", "sf640", + "sf1024", "sf1280", "sf2048", "sf2560"}; +typedef enum{ + LIBLTE_RRC_SHORT_DRX_CYCLE_SF2 = 0, + LIBLTE_RRC_SHORT_DRX_CYCLE_SF5, + LIBLTE_RRC_SHORT_DRX_CYCLE_SF8, + LIBLTE_RRC_SHORT_DRX_CYCLE_SF10, + LIBLTE_RRC_SHORT_DRX_CYCLE_SF16, + LIBLTE_RRC_SHORT_DRX_CYCLE_SF20, + LIBLTE_RRC_SHORT_DRX_CYCLE_SF32, + LIBLTE_RRC_SHORT_DRX_CYCLE_SF40, + LIBLTE_RRC_SHORT_DRX_CYCLE_SF64, + LIBLTE_RRC_SHORT_DRX_CYCLE_SF80, + LIBLTE_RRC_SHORT_DRX_CYCLE_SF128, + LIBLTE_RRC_SHORT_DRX_CYCLE_SF160, + LIBLTE_RRC_SHORT_DRX_CYCLE_SF256, + LIBLTE_RRC_SHORT_DRX_CYCLE_SF320, + LIBLTE_RRC_SHORT_DRX_CYCLE_SF512, + LIBLTE_RRC_SHORT_DRX_CYCLE_SF640, + LIBLTE_RRC_SHORT_DRX_CYCLE_N_ITEMS, +}LIBLTE_RRC_SHORT_DRX_CYCLE_ENUM; +static const char liblte_rrc_short_drx_cycle_text[LIBLTE_RRC_SHORT_DRX_CYCLE_N_ITEMS][20] = { "sf2", "sf5", "sf8", "sf10", + "sf16", "sf20", "sf32", "sf40", + "sf64", "sf80", "sf128", "sf160", + "sf256", "sf320", "sf512", "sf640"}; +typedef enum{ + LIBLTE_RRC_TIME_ALIGNMENT_TIMER_SF500 = 0, + LIBLTE_RRC_TIME_ALIGNMENT_TIMER_SF750, + LIBLTE_RRC_TIME_ALIGNMENT_TIMER_SF1280, + LIBLTE_RRC_TIME_ALIGNMENT_TIMER_SF1920, + LIBLTE_RRC_TIME_ALIGNMENT_TIMER_SF2560, + LIBLTE_RRC_TIME_ALIGNMENT_TIMER_SF5120, + LIBLTE_RRC_TIME_ALIGNMENT_TIMER_SF10240, + LIBLTE_RRC_TIME_ALIGNMENT_TIMER_INFINITY, + LIBLTE_RRC_TIME_ALIGNMENT_TIMER_N_ITEMS, +}LIBLTE_RRC_TIME_ALIGNMENT_TIMER_ENUM; +static const char liblte_rrc_time_alignment_timer_text[LIBLTE_RRC_TIME_ALIGNMENT_TIMER_N_ITEMS][20] = { "sf500", "sf750", "sf1280", "sf1920", + "sf2560", "sf5120", "sf10240", "INFINITY"}; +static const int liblte_rrc_time_alignment_timer_num[LIBLTE_RRC_TIME_ALIGNMENT_TIMER_N_ITEMS] = { 500, 750, 1280, 1920, 2560, 5120, 10240, -1}; +typedef enum{ + LIBLTE_RRC_PERIODIC_PHR_TIMER_SF10 = 0, + LIBLTE_RRC_PERIODIC_PHR_TIMER_SF20, + LIBLTE_RRC_PERIODIC_PHR_TIMER_SF50, + LIBLTE_RRC_PERIODIC_PHR_TIMER_SF100, + LIBLTE_RRC_PERIODIC_PHR_TIMER_SF200, + LIBLTE_RRC_PERIODIC_PHR_TIMER_SF500, + LIBLTE_RRC_PERIODIC_PHR_TIMER_SF1000, + LIBLTE_RRC_PERIODIC_PHR_TIMER_INFINITY, + LIBLTE_RRC_PERIODIC_PHR_TIMER_N_ITEMS, +}LIBLTE_RRC_PERIODIC_PHR_TIMER_ENUM; +static const char liblte_rrc_periodic_phr_timer_text[LIBLTE_RRC_PERIODIC_PHR_TIMER_N_ITEMS][20] = { "sf10", "sf20", "sf50", "sf100", + "sf200", "sf500", "sf1000", "INFINITY"}; +static int liblte_rrc_periodic_phr_timer_num[LIBLTE_RRC_PERIODIC_PHR_TIMER_N_ITEMS] = {10, 20, 50, 100, 200, 500, 1000, -1}; + +typedef enum{ + LIBLTE_RRC_PROHIBIT_PHR_TIMER_SF0 = 0, + LIBLTE_RRC_PROHIBIT_PHR_TIMER_SF10, + LIBLTE_RRC_PROHIBIT_PHR_TIMER_SF20, + LIBLTE_RRC_PROHIBIT_PHR_TIMER_SF50, + LIBLTE_RRC_PROHIBIT_PHR_TIMER_SF100, + LIBLTE_RRC_PROHIBIT_PHR_TIMER_SF200, + LIBLTE_RRC_PROHIBIT_PHR_TIMER_SF500, + LIBLTE_RRC_PROHIBIT_PHR_TIMER_SF1000, + LIBLTE_RRC_PROHIBIT_PHR_TIMER_N_ITEMS, +}LIBLTE_RRC_PROHIBIT_PHR_TIMER_ENUM; +static const char liblte_rrc_prohibit_phr_timer_text[LIBLTE_RRC_PROHIBIT_PHR_TIMER_N_ITEMS][20] = { "sf0", "sf10", "sf20", "sf50", + "sf100", "sf200", "sf500", "sf1000"}; + +static int liblte_rrc_prohibit_phr_timer_num[LIBLTE_RRC_PROHIBIT_PHR_TIMER_N_ITEMS] = {0, 10, 20, 50, 100, 200, 500, 1000}; + +typedef enum{ + LIBLTE_RRC_DL_PATHLOSS_CHANGE_DB1 = 0, + LIBLTE_RRC_DL_PATHLOSS_CHANGE_DB3, + LIBLTE_RRC_DL_PATHLOSS_CHANGE_DB6, + LIBLTE_RRC_DL_PATHLOSS_CHANGE_INFINITY, + LIBLTE_RRC_DL_PATHLOSS_CHANGE_N_ITEMS, +}LIBLTE_RRC_DL_PATHLOSS_CHANGE_ENUM; +static const char liblte_rrc_dl_pathloss_change_text[LIBLTE_RRC_DL_PATHLOSS_CHANGE_N_ITEMS][20] = {"1dB", "3dB", "6dB", "INFINITY"}; + +static int liblte_rrc_dl_pathloss_change_num[LIBLTE_RRC_DL_PATHLOSS_CHANGE_N_ITEMS] = {1, 3, 6, -1}; + +// Structs +typedef struct{ + LIBLTE_RRC_MAX_HARQ_TX_ENUM max_harq_tx; + LIBLTE_RRC_PERIODIC_BSR_TIMER_ENUM periodic_bsr_timer; + LIBLTE_RRC_RETRANSMISSION_BSR_TIMER_ENUM retx_bsr_timer; + bool tti_bundling; + bool max_harq_tx_present; + bool periodic_bsr_timer_present; +}LIBLTE_RRC_ULSCH_CONFIG_STRUCT; +typedef struct{ + LIBLTE_RRC_ON_DURATION_TIMER_ENUM on_duration_timer; + LIBLTE_RRC_DRX_INACTIVITY_TIMER_ENUM drx_inactivity_timer; + LIBLTE_RRC_DRX_RETRANSMISSION_TIMER_ENUM drx_retx_timer; + LIBLTE_RRC_LONG_DRX_CYCLE_START_OFFSET_CHOICE_ENUM long_drx_cycle_start_offset_choice; + LIBLTE_RRC_SHORT_DRX_CYCLE_ENUM short_drx_cycle; + uint32 long_drx_cycle_start_offset; + uint32 short_drx_cycle_timer; + bool setup_present; + bool short_drx_present; +}LIBLTE_RRC_DRX_CONFIG_STRUCT; +typedef struct{ + LIBLTE_RRC_PERIODIC_PHR_TIMER_ENUM periodic_phr_timer; + LIBLTE_RRC_PROHIBIT_PHR_TIMER_ENUM prohibit_phr_timer; + LIBLTE_RRC_DL_PATHLOSS_CHANGE_ENUM dl_pathloss_change; + bool setup_present; +}LIBLTE_RRC_PHR_CONFIG_STRUCT; +typedef struct{ + LIBLTE_RRC_ULSCH_CONFIG_STRUCT ulsch_cnfg; + LIBLTE_RRC_DRX_CONFIG_STRUCT drx_cnfg; + LIBLTE_RRC_PHR_CONFIG_STRUCT phr_cnfg; + LIBLTE_RRC_TIME_ALIGNMENT_TIMER_ENUM time_alignment_timer; + bool ulsch_cnfg_present; + bool drx_cnfg_present; + bool phr_cnfg_present; +}LIBLTE_RRC_MAC_MAIN_CONFIG_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_mac_main_config_ie(LIBLTE_RRC_MAC_MAIN_CONFIG_STRUCT *mac_main_cnfg, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_mac_main_config_ie(uint8 **ie_ptr, + LIBLTE_RRC_MAC_MAIN_CONFIG_STRUCT *mac_main_cnfg); + +/********************************************************************* + IE Name: PDCP Config + + Description: Sets the configurable PDCP parameters for data + radio bearers + + Document Reference: 36.331 v10.0.0 Section 6.3.2 +*********************************************************************/ +// Defines +// Enums +typedef enum{ + LIBLTE_RRC_DISCARD_TIMER_MS50 = 0, + LIBLTE_RRC_DISCARD_TIMER_MS100, + LIBLTE_RRC_DISCARD_TIMER_MS150, + LIBLTE_RRC_DISCARD_TIMER_MS300, + LIBLTE_RRC_DISCARD_TIMER_MS500, + LIBLTE_RRC_DISCARD_TIMER_MS750, + LIBLTE_RRC_DISCARD_TIMER_MS1500, + LIBLTE_RRC_DISCARD_TIMER_INFINITY, + LIBLTE_RRC_DISCARD_TIMER_N_ITEMS, +}LIBLTE_RRC_DISCARD_TIMER_ENUM; +static const char liblte_rrc_discard_timer_text[LIBLTE_RRC_DISCARD_TIMER_N_ITEMS][20] = { "ms50", "ms100", "ms150", "ms300", + "ms500", "ms750", "ms1500", "INFINITY"}; +static const int32 liblte_rrc_discard_timer_num[LIBLTE_RRC_DISCARD_TIMER_N_ITEMS] = { 50, 100, 150, 300, 500, 750, 1500, -1}; +typedef enum{ + LIBLTE_RRC_PDCP_SN_SIZE_7_BITS = 0, + LIBLTE_RRC_PDCP_SN_SIZE_12_BITS, + LIBLTE_RRC_PDCP_SN_SIZE_N_ITEMS, +}LIBLTE_RRC_PDCP_SN_SIZE_ENUM; +static const char liblte_rrc_pdcp_sn_size_text[LIBLTE_RRC_PDCP_SN_SIZE_N_ITEMS][20] = {"7-bits", "12-bits"}; + +static const int8 liblte_rrc_pdcp_sn_size_num[LIBLTE_RRC_PDCP_SN_SIZE_N_ITEMS] = {7, 12}; + +// Structs +typedef struct{ + LIBLTE_RRC_DISCARD_TIMER_ENUM discard_timer; + LIBLTE_RRC_PDCP_SN_SIZE_ENUM rlc_um_pdcp_sn_size; + uint32 hdr_compression_max_cid; + bool hdr_compression_rohc; + bool hdr_compression_profile_0001; + bool hdr_compression_profile_0002; + bool hdr_compression_profile_0003; + bool hdr_compression_profile_0004; + bool hdr_compression_profile_0006; + bool hdr_compression_profile_0101; + bool hdr_compression_profile_0102; + bool hdr_compression_profile_0103; + bool hdr_compression_profile_0104; + bool discard_timer_present; + bool rlc_am_status_report_required_present; + bool rlc_am_status_report_required; + bool rlc_um_pdcp_sn_size_present; +}LIBLTE_RRC_PDCP_CONFIG_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_pdcp_config_ie(LIBLTE_RRC_PDCP_CONFIG_STRUCT *pdcp_cnfg, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_pdcp_config_ie(uint8 **ie_ptr, + LIBLTE_RRC_PDCP_CONFIG_STRUCT *pdcp_cnfg); + +/********************************************************************* + IE Name: PDSCH Config + + Description: Specifies the common and the UE specific PDSCH + configuration + + Document Reference: 36.331 v10.0.0 Section 6.3.2 +*********************************************************************/ +// Defines +// Enums +typedef enum{ + LIBLTE_RRC_PDSCH_CONFIG_P_A_DB_N6 = 0, + LIBLTE_RRC_PDSCH_CONFIG_P_A_DB_N4_DOT_77, + LIBLTE_RRC_PDSCH_CONFIG_P_A_DB_N3, + LIBLTE_RRC_PDSCH_CONFIG_P_A_DB_N1_DOT_77, + LIBLTE_RRC_PDSCH_CONFIG_P_A_DB_0, + LIBLTE_RRC_PDSCH_CONFIG_P_A_DB_1, + LIBLTE_RRC_PDSCH_CONFIG_P_A_DB_2, + LIBLTE_RRC_PDSCH_CONFIG_P_A_DB_3, + LIBLTE_RRC_PDSCH_CONFIG_P_A_N_ITEMS, +}LIBLTE_RRC_PDSCH_CONFIG_P_A_ENUM; +static const char liblte_rrc_pdsch_config_p_a_text[LIBLTE_RRC_PDSCH_CONFIG_P_A_N_ITEMS][20] = { "-6", "-4.77", "-3", "-1.77", + "0", "1", "2", "3"}; +static const double liblte_rrc_pdsch_config_p_a_num[LIBLTE_RRC_PDSCH_CONFIG_P_A_N_ITEMS] = {-6, -4.77, -3, -1.77, 0, 1, 2, 3}; +// Structs +// PDSCH Config Common struct defined above +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_pdsch_config_common_ie(LIBLTE_RRC_PDSCH_CONFIG_COMMON_STRUCT *pdsch_config, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_pdsch_config_common_ie(uint8 **ie_ptr, + LIBLTE_RRC_PDSCH_CONFIG_COMMON_STRUCT *pdsch_config); +LIBLTE_ERROR_ENUM liblte_rrc_pack_pdsch_config_dedicated_ie(LIBLTE_RRC_PDSCH_CONFIG_P_A_ENUM p_a, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_pdsch_config_dedicated_ie(uint8 **ie_ptr, + LIBLTE_RRC_PDSCH_CONFIG_P_A_ENUM *p_a); + +/********************************************************************* + IE Name: PHICH Config + + Description: Specifies the PHICH configuration + + Document Reference: 36.331 v10.0.0 Section 6.3.2 +*********************************************************************/ +// Defines +// Enums +// PHICH Config enums defined above +// Structs +// PHICH Config struct defined above +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_phich_config_ie(LIBLTE_RRC_PHICH_CONFIG_STRUCT *phich_config, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_phich_config_ie(uint8 **ie_ptr, + LIBLTE_RRC_PHICH_CONFIG_STRUCT *phich_config); + +/********************************************************************* + IE Name: Physical Config Dedicated + + Description: Specifies the UE specific physical channel + configuration + + Document Reference: 36.331 v10.0.0 Section 6.3.2 +*********************************************************************/ +// Defines +// Enums +typedef enum{ + LIBLTE_RRC_ACK_NACK_REPETITION_FACTOR_N2 = 0, + LIBLTE_RRC_ACK_NACK_REPETITION_FACTOR_N4, + LIBLTE_RRC_ACK_NACK_REPETITION_FACTOR_N6, + LIBLTE_RRC_ACK_NACK_REPETITION_FACTOR_SPARE1, + LIBLTE_RRC_ACK_NACK_REPETITION_FACTOR_N_ITEMS, +}LIBLTE_RRC_ACK_NACK_REPETITION_FACTOR_ENUM; +static const char liblte_rrc_ack_nack_repetition_factor_text[LIBLTE_RRC_ACK_NACK_REPETITION_FACTOR_N_ITEMS][20] = {"n2", "n4", "n6", "SPARE"}; +typedef enum{ + LIBLTE_RRC_TDD_ACK_NACK_FEEDBACK_MODE_BUNDLING = 0, + LIBLTE_RRC_TDD_ACK_NACK_FEEDBACK_MODE_MULTIPLEXING, + LIBLTE_RRC_TDD_ACK_NACK_FEEDBACK_MODE_N_ITEMS, +}LIBLTE_RRC_TDD_ACK_NACK_FEEDBACK_MODE_ENUM; +static const char liblte_rrc_tdd_ack_nack_feedback_mode_text[LIBLTE_RRC_TDD_ACK_NACK_FEEDBACK_MODE_N_ITEMS][20] = {"bundling", "multiplexing"}; +typedef enum{ + LIBLTE_RRC_DSR_TRANS_MAX_N4 = 0, + LIBLTE_RRC_DSR_TRANS_MAX_N8, + LIBLTE_RRC_DSR_TRANS_MAX_N16, + LIBLTE_RRC_DSR_TRANS_MAX_N32, + LIBLTE_RRC_DSR_TRANS_MAX_N64, + LIBLTE_RRC_DSR_TRANS_MAX_SPARE3, + LIBLTE_RRC_DSR_TRANS_MAX_SPARE2, + LIBLTE_RRC_DSR_TRANS_MAX_SPARE1, + LIBLTE_RRC_DSR_TRANS_MAX_N_ITEMS, +}LIBLTE_RRC_DSR_TRANS_MAX_ENUM; +static const char liblte_rrc_dsr_trans_max_text[LIBLTE_RRC_DSR_TRANS_MAX_N_ITEMS][20] = { "n4", "n8", "n16", "n32", + "n64", "SPARE", "SPARE", "SPARE"}; +static const int32 liblte_rrc_dsr_trans_max_num[LIBLTE_RRC_DSR_TRANS_MAX_N_ITEMS] = {4, 8, 16, 32, 64, -1, -1, -1}; + +typedef enum{ + LIBLTE_RRC_DELTA_MCS_ENABLED_EN0 = 0, + LIBLTE_RRC_DELTA_MCS_ENABLED_EN1, + LIBLTE_RRC_DELTA_MCS_ENABLED_N_ITEMS, +}LIBLTE_RRC_DELTA_MCS_ENABLED_ENUM; +static const char liblte_rrc_delta_mcs_enabled_text[LIBLTE_RRC_DELTA_MCS_ENABLED_N_ITEMS][20] = {"en0", "en1"}; +typedef enum{ + LIBLTE_RRC_TPC_INDEX_FORMAT_3 = 0, + LIBLTE_RRC_TPC_INDEX_FORMAT_3A, + LIBLTE_RRC_TPC_INDEX_N_ITEMS, +}LIBLTE_RRC_TPC_INDEX_ENUM; +static const char liblte_rrc_tpc_index_text[LIBLTE_RRC_TPC_INDEX_N_ITEMS][20] = {"format_3", "format_3a"}; +typedef enum{ + LIBLTE_RRC_SRS_BANDWIDTH_BW0 = 0, + LIBLTE_RRC_SRS_BANDWIDTH_BW1, + LIBLTE_RRC_SRS_BANDWIDTH_BW2, + LIBLTE_RRC_SRS_BANDWIDTH_BW3, + LIBLTE_RRC_SRS_BANDWIDTH_N_ITEMS, +}LIBLTE_RRC_SRS_BANDWIDTH_ENUM; +static const char liblte_rrc_srs_bandwidth_text[LIBLTE_RRC_SRS_BANDWIDTH_N_ITEMS][20] = {"bw0", "bw1", "bw2", "bw3"}; +typedef enum{ + LIBLTE_RRC_SRS_HOPPING_BANDWIDTH_HBW0 = 0, + LIBLTE_RRC_SRS_HOPPING_BANDWIDTH_HBW1, + LIBLTE_RRC_SRS_HOPPING_BANDWIDTH_HBW2, + LIBLTE_RRC_SRS_HOPPING_BANDWIDTH_HBW3, + LIBLTE_RRC_SRS_HOPPING_BANDWIDTH_N_ITEMS, +}LIBLTE_RRC_SRS_HOPPING_BANDWIDTH_ENUM; +static const char liblte_rrc_srs_hopping_bandwidth_text[LIBLTE_RRC_SRS_HOPPING_BANDWIDTH_N_ITEMS][20] = {"hbw0", "hbw1", "hbw2", "hbw3"}; +typedef enum{ + LIBLTE_RRC_CYCLIC_SHIFT_CS0 = 0, + LIBLTE_RRC_CYCLIC_SHIFT_CS1, + LIBLTE_RRC_CYCLIC_SHIFT_CS2, + LIBLTE_RRC_CYCLIC_SHIFT_CS3, + LIBLTE_RRC_CYCLIC_SHIFT_CS4, + LIBLTE_RRC_CYCLIC_SHIFT_CS5, + LIBLTE_RRC_CYCLIC_SHIFT_CS6, + LIBLTE_RRC_CYCLIC_SHIFT_CS7, + LIBLTE_RRC_CYCLIC_SHIFT_N_ITEMS, +}LIBLTE_RRC_CYCLIC_SHIFT_ENUM; +static const char liblte_rrc_cyclic_shift_text[LIBLTE_RRC_CYCLIC_SHIFT_N_ITEMS][20] = {"cs0", "cs1", "cs2", "cs3", + "cs4", "cs5", "cs6", "cs7"}; +// Structs +typedef struct{ + LIBLTE_RRC_ACK_NACK_REPETITION_FACTOR_ENUM ack_nack_repetition_factor; + LIBLTE_RRC_TDD_ACK_NACK_FEEDBACK_MODE_ENUM tdd_ack_nack_feedback_mode; + uint32 ack_nack_repetition_n1_pucch_an; + bool tdd_ack_nack_feedback_mode_present; + bool ack_nack_repetition_setup_present; +}LIBLTE_RRC_PUCCH_CONFIG_DEDICATED_STRUCT; +typedef struct{ + uint8 beta_offset_ack_idx; + uint8 beta_offset_ri_idx; + uint8 beta_offset_cqi_idx; +}LIBLTE_RRC_PUSCH_CONFIG_DEDICATED_STRUCT; +typedef struct{ + LIBLTE_RRC_DELTA_MCS_ENABLED_ENUM delta_mcs_en; + LIBLTE_RRC_FILTER_COEFFICIENT_ENUM filter_coeff; + uint32 p_srs_offset; + int32 p0_ue_pusch; + int32 p0_ue_pucch; + bool accumulation_en; + bool filter_coeff_present; +}LIBLTE_RRC_UL_POWER_CONTROL_DEDICATED_STRUCT; +typedef struct{ + LIBLTE_RRC_TPC_INDEX_ENUM tpc_idx_choice; + uint32 tpc_rnti; + uint32 tpc_idx; + bool setup_present; +}LIBLTE_RRC_TPC_PDCCH_CONFIG_STRUCT; +typedef struct{ + LIBLTE_RRC_SRS_BANDWIDTH_ENUM srs_bandwidth; + LIBLTE_RRC_SRS_HOPPING_BANDWIDTH_ENUM srs_hopping_bandwidth; + LIBLTE_RRC_CYCLIC_SHIFT_ENUM cyclic_shift; + uint32 freq_domain_pos; + uint32 srs_cnfg_idx; + uint32 tx_comb; + bool setup_present; + bool duration; +}LIBLTE_RRC_SRS_UL_CONFIG_DEDICATED_STRUCT; +typedef struct{ + LIBLTE_RRC_DSR_TRANS_MAX_ENUM dsr_trans_max; + uint32 sr_pucch_resource_idx; + uint32 sr_cnfg_idx; + bool setup_present; +}LIBLTE_RRC_SCHEDULING_REQUEST_CONFIG_STRUCT; +typedef struct{ + LIBLTE_RRC_PUCCH_CONFIG_DEDICATED_STRUCT pucch_cnfg_ded; + LIBLTE_RRC_PUSCH_CONFIG_DEDICATED_STRUCT pusch_cnfg_ded; + LIBLTE_RRC_UL_POWER_CONTROL_DEDICATED_STRUCT ul_pwr_ctrl_ded; + LIBLTE_RRC_TPC_PDCCH_CONFIG_STRUCT tpc_pdcch_cnfg_pucch; + LIBLTE_RRC_TPC_PDCCH_CONFIG_STRUCT tpc_pdcch_cnfg_pusch; + LIBLTE_RRC_CQI_REPORT_CONFIG_STRUCT cqi_report_cnfg; + LIBLTE_RRC_SRS_UL_CONFIG_DEDICATED_STRUCT srs_ul_cnfg_ded; + LIBLTE_RRC_ANTENNA_INFO_DEDICATED_STRUCT antenna_info_explicit_value; + LIBLTE_RRC_SCHEDULING_REQUEST_CONFIG_STRUCT sched_request_cnfg; + LIBLTE_RRC_PDSCH_CONFIG_P_A_ENUM pdsch_cnfg_ded; + bool pdsch_cnfg_ded_present; + bool pucch_cnfg_ded_present; + bool pusch_cnfg_ded_present; + bool ul_pwr_ctrl_ded_present; + bool tpc_pdcch_cnfg_pucch_present; + bool tpc_pdcch_cnfg_pusch_present; + bool cqi_report_cnfg_present; + bool srs_ul_cnfg_ded_present; + bool antenna_info_present; + bool antenna_info_default_value; + bool sched_request_cnfg_present; +}LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_physical_config_dedicated_ie(LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT *phy_cnfg_ded, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_physical_config_dedicated_ie(uint8 **ie_ptr, + LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT *phy_cnfg_ded); + +/********************************************************************* + IE Name: P Max + + Description: Limits the UE's uplink transmission power on a + carrier frequency and is used to calculate the + parameter P Compensation + + Document Reference: 36.331 v10.0.0 Section 6.3.2 +*********************************************************************/ +// Defines +// Enums +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_p_max_ie(int8 p_max, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_p_max_ie(uint8 **ie_ptr, + int8 *p_max); + +/********************************************************************* + IE Name: PRACH Config + + Description: Specifies the PRACH configuration in the system + information and in the mobility control information + + Document Reference: 36.331 v10.0.0 Section 6.3.2 +*********************************************************************/ +// Defines +// Enums +// Structs +// PRACH Config structs defined above +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_prach_config_sib_ie(LIBLTE_RRC_PRACH_CONFIG_SIB_STRUCT *prach_cnfg, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_prach_config_sib_ie(uint8 **ie_ptr, + LIBLTE_RRC_PRACH_CONFIG_SIB_STRUCT *prach_cnfg); +LIBLTE_ERROR_ENUM liblte_rrc_pack_prach_config_ie(LIBLTE_RRC_PRACH_CONFIG_STRUCT *prach_cnfg, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_prach_config_ie(uint8 **ie_ptr, + LIBLTE_RRC_PRACH_CONFIG_STRUCT *prach_cnfg); +LIBLTE_ERROR_ENUM liblte_rrc_pack_prach_config_scell_r10_ie(uint8 prach_cnfg_idx, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_prach_config_scell_r10_ie(uint8 **ie_ptr, + uint8 *prach_cnfg_idx); + +/********************************************************************* + IE Name: Presence Antenna Port 1 + + Description: Indicates whether all the neighboring cells use + antenna port 1 + + Document Reference: 36.331 v10.0.0 Section 6.3.2 +*********************************************************************/ +// Defines +// Enums +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_presence_antenna_port_1_ie(bool presence_ant_port_1, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_presence_antenna_port_1_ie(uint8 **ie_ptr, + bool *presence_ant_port_1); + +/********************************************************************* + IE Name: PUCCH Config + + Description: Specifies the common and the UE specific PUCCH + configuration + + Document Reference: 36.331 v10.0.0 Section 6.3.2 +*********************************************************************/ +// Defines +// Enums +// PUCCH Config enum defined above +// Structs +// PUCCH Config structs defined above +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_pucch_config_common_ie(LIBLTE_RRC_PUCCH_CONFIG_COMMON_STRUCT *pucch_cnfg, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_pucch_config_common_ie(uint8 **ie_ptr, + LIBLTE_RRC_PUCCH_CONFIG_COMMON_STRUCT *pucch_cnfg); +LIBLTE_ERROR_ENUM liblte_rrc_pack_pucch_config_dedicated_ie(LIBLTE_RRC_PUCCH_CONFIG_DEDICATED_STRUCT *pucch_cnfg, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_pucch_config_dedicated_ie(uint8 **ie_ptr, + LIBLTE_RRC_PUCCH_CONFIG_DEDICATED_STRUCT *pucch_cnfg); + +/********************************************************************* + IE Name: PUSCH Config + + Description: Specifies the common and the UE specific PUSCH + configuration and the reference signal configuration + for PUSCH and PUCCH + + Document Reference: 36.331 v10.0.0 Section 6.3.2 +*********************************************************************/ +// Defines +// Enums +// PUSCH Config enum defined above +// Structs +// PUSCH Config structs defined above +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_pusch_config_common_ie(LIBLTE_RRC_PUSCH_CONFIG_COMMON_STRUCT *pusch_cnfg, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_pusch_config_common_ie(uint8 **ie_ptr, + LIBLTE_RRC_PUSCH_CONFIG_COMMON_STRUCT *pusch_cnfg); +LIBLTE_ERROR_ENUM liblte_rrc_pack_pusch_config_dedicated_ie(LIBLTE_RRC_PUSCH_CONFIG_DEDICATED_STRUCT *pusch_cnfg, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_pusch_config_dedicated_ie(uint8 **ie_ptr, + LIBLTE_RRC_PUSCH_CONFIG_DEDICATED_STRUCT *pusch_cnfg); + +/********************************************************************* + IE Name: RACH Config Common + + Description: Specifies the generic random access parameters + + Document Reference: 36.331 v10.0.0 Section 6.3.2 +*********************************************************************/ +// Defines +// Enums +// RACH Config Common enums defined above +// Structs +// RACH Config Common structs defined above +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_rach_config_common_ie(LIBLTE_RRC_RACH_CONFIG_COMMON_STRUCT *rach_cnfg, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_rach_config_common_ie(uint8 **ie_ptr, + LIBLTE_RRC_RACH_CONFIG_COMMON_STRUCT *rach_cnfg); + +/********************************************************************* + IE Name: RACH Config Dedicated + + Description: Specifies the dedicated random access parameters + + Document Reference: 36.331 v10.0.0 Section 6.3.2 +*********************************************************************/ +// Defines +// Enums +// Structs +// RACH Config Dedicated struct defined above +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_rach_config_dedicated_ie(LIBLTE_RRC_RACH_CONFIG_DEDICATED_STRUCT *rach_cnfg, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_rach_config_dedicated_ie(uint8 **ie_ptr, + LIBLTE_RRC_RACH_CONFIG_DEDICATED_STRUCT *rach_cnfg); + +/********************************************************************* + IE Name: Radio Resource Config Common + + Description: Specifies the common radio resource configurations + in the system information and in the mobility control + information, including random access parameters + and static physical layer parameters + + Document Reference: 36.331 v10.0.0 Section 6.3.2 +*********************************************************************/ +// Defines +// Enums +typedef enum{ + LIBLTE_RRC_MODIFICATION_PERIOD_COEFF_N2 = 0, + LIBLTE_RRC_MODIFICATION_PERIOD_COEFF_N4, + LIBLTE_RRC_MODIFICATION_PERIOD_COEFF_N8, + LIBLTE_RRC_MODIFICATION_PERIOD_COEFF_N16, + LIBLTE_RRC_MODIFICATION_PERIOD_COEFF_N_ITEMS, +}LIBLTE_RRC_MODIFICATION_PERIOD_COEFF_ENUM; +static const char liblte_rrc_modification_period_coeff_text[LIBLTE_RRC_MODIFICATION_PERIOD_COEFF_N_ITEMS][20] = {"2", "4", "8", "16"}; +static const uint8 liblte_rrc_modification_period_coeff_num[LIBLTE_RRC_MODIFICATION_PERIOD_COEFF_N_ITEMS] = {2, 4, 8, 16}; +typedef enum{ + LIBLTE_RRC_DEFAULT_PAGING_CYCLE_RF32 = 0, + LIBLTE_RRC_DEFAULT_PAGING_CYCLE_RF64, + LIBLTE_RRC_DEFAULT_PAGING_CYCLE_RF128, + LIBLTE_RRC_DEFAULT_PAGING_CYCLE_RF256, + LIBLTE_RRC_DEFAULT_PAGING_CYCLE_N_ITEMS, +}LIBLTE_RRC_DEFAULT_PAGING_CYCLE_ENUM; +static const char liblte_rrc_default_paging_cycle_text[LIBLTE_RRC_DEFAULT_PAGING_CYCLE_N_ITEMS][20] = {"32", "64", "128", "256"}; +static const uint16 liblte_rrc_default_paging_cycle_num[LIBLTE_RRC_DEFAULT_PAGING_CYCLE_N_ITEMS] = {32, 64, 128, 256}; +typedef enum{ + LIBLTE_RRC_NB_FOUR_T = 0, + LIBLTE_RRC_NB_TWO_T, + LIBLTE_RRC_NB_ONE_T, + LIBLTE_RRC_NB_HALF_T, + LIBLTE_RRC_NB_QUARTER_T, + LIBLTE_RRC_NB_ONE_EIGHTH_T, + LIBLTE_RRC_NB_ONE_SIXTEENTH_T, + LIBLTE_RRC_NB_ONE_THIRTY_SECOND_T, + LIBLTE_RRC_NB_N_ITEMS, +}LIBLTE_RRC_NB_ENUM; +static const char liblte_rrc_nb_text[LIBLTE_RRC_NB_N_ITEMS][20] = { "4", "2", "1", "1/2", + "1/4", "1/8", "1/16", "1/32"}; +static const double liblte_rrc_nb_num[LIBLTE_RRC_NB_N_ITEMS] = {4.0, 2.0, 1.0, 0.5, 0.25, 0.125, 0.0625, 0.03125}; +// Structs +typedef struct{ + LIBLTE_RRC_MODIFICATION_PERIOD_COEFF_ENUM modification_period_coeff; +}LIBLTE_RRC_BCCH_CONFIG_STRUCT; +typedef struct{ + LIBLTE_RRC_DEFAULT_PAGING_CYCLE_ENUM default_paging_cycle; + LIBLTE_RRC_NB_ENUM nB; +}LIBLTE_RRC_PCCH_CONFIG_STRUCT; +typedef struct{ + LIBLTE_RRC_RACH_CONFIG_COMMON_STRUCT rach_cnfg; + LIBLTE_RRC_BCCH_CONFIG_STRUCT bcch_cnfg; + LIBLTE_RRC_PCCH_CONFIG_STRUCT pcch_cnfg; + LIBLTE_RRC_PRACH_CONFIG_SIB_STRUCT prach_cnfg; + LIBLTE_RRC_PDSCH_CONFIG_COMMON_STRUCT pdsch_cnfg; + LIBLTE_RRC_PUSCH_CONFIG_COMMON_STRUCT pusch_cnfg; + LIBLTE_RRC_PUCCH_CONFIG_COMMON_STRUCT pucch_cnfg; + LIBLTE_RRC_SRS_UL_CONFIG_COMMON_STRUCT srs_ul_cnfg; + LIBLTE_RRC_UL_POWER_CONTROL_COMMON_STRUCT ul_pwr_ctrl; + LIBLTE_RRC_UL_CP_LENGTH_ENUM ul_cp_length; +}LIBLTE_RRC_RR_CONFIG_COMMON_SIB_STRUCT; +// RR Config Common struct defined above +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_rr_config_common_sib_ie(LIBLTE_RRC_RR_CONFIG_COMMON_SIB_STRUCT *rr_cnfg, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_rr_config_common_sib_ie(uint8 **ie_ptr, + LIBLTE_RRC_RR_CONFIG_COMMON_SIB_STRUCT *rr_cnfg); +LIBLTE_ERROR_ENUM liblte_rrc_pack_rr_config_common_ie(LIBLTE_RRC_RR_CONFIG_COMMON_STRUCT *rr_cnfg, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_rr_config_common_ie(uint8 **ie_ptr, + LIBLTE_RRC_RR_CONFIG_COMMON_STRUCT *rr_cnfg); + +/********************************************************************* + IE Name: Radio Resource Config Dedicated + + Description: Sets up/Modifies/Releases RBs, modifies the MAC + main configuration, modifies the SPS configuration + and modifies dedicated physical configuration + + Document Reference: 36.331 v10.0.0 Section 6.3.2 +*********************************************************************/ +// Defines +#define LIBLTE_RRC_MAX_DRB 11 +// Enums +typedef enum{ + LIBLTE_RRC_T_POLL_RETRANSMIT_MS5 = 0, + LIBLTE_RRC_T_POLL_RETRANSMIT_MS10, + LIBLTE_RRC_T_POLL_RETRANSMIT_MS15, + LIBLTE_RRC_T_POLL_RETRANSMIT_MS20, + LIBLTE_RRC_T_POLL_RETRANSMIT_MS25, + LIBLTE_RRC_T_POLL_RETRANSMIT_MS30, + LIBLTE_RRC_T_POLL_RETRANSMIT_MS35, + LIBLTE_RRC_T_POLL_RETRANSMIT_MS40, + LIBLTE_RRC_T_POLL_RETRANSMIT_MS45, + LIBLTE_RRC_T_POLL_RETRANSMIT_MS50, + LIBLTE_RRC_T_POLL_RETRANSMIT_MS55, + LIBLTE_RRC_T_POLL_RETRANSMIT_MS60, + LIBLTE_RRC_T_POLL_RETRANSMIT_MS65, + LIBLTE_RRC_T_POLL_RETRANSMIT_MS70, + LIBLTE_RRC_T_POLL_RETRANSMIT_MS75, + LIBLTE_RRC_T_POLL_RETRANSMIT_MS80, + LIBLTE_RRC_T_POLL_RETRANSMIT_MS85, + LIBLTE_RRC_T_POLL_RETRANSMIT_MS90, + LIBLTE_RRC_T_POLL_RETRANSMIT_MS95, + LIBLTE_RRC_T_POLL_RETRANSMIT_MS100, + LIBLTE_RRC_T_POLL_RETRANSMIT_MS105, + LIBLTE_RRC_T_POLL_RETRANSMIT_MS110, + LIBLTE_RRC_T_POLL_RETRANSMIT_MS115, + LIBLTE_RRC_T_POLL_RETRANSMIT_MS120, + LIBLTE_RRC_T_POLL_RETRANSMIT_MS125, + LIBLTE_RRC_T_POLL_RETRANSMIT_MS130, + LIBLTE_RRC_T_POLL_RETRANSMIT_MS135, + LIBLTE_RRC_T_POLL_RETRANSMIT_MS140, + LIBLTE_RRC_T_POLL_RETRANSMIT_MS145, + LIBLTE_RRC_T_POLL_RETRANSMIT_MS150, + LIBLTE_RRC_T_POLL_RETRANSMIT_MS155, + LIBLTE_RRC_T_POLL_RETRANSMIT_MS160, + LIBLTE_RRC_T_POLL_RETRANSMIT_MS165, + LIBLTE_RRC_T_POLL_RETRANSMIT_MS170, + LIBLTE_RRC_T_POLL_RETRANSMIT_MS175, + LIBLTE_RRC_T_POLL_RETRANSMIT_MS180, + LIBLTE_RRC_T_POLL_RETRANSMIT_MS185, + LIBLTE_RRC_T_POLL_RETRANSMIT_MS190, + LIBLTE_RRC_T_POLL_RETRANSMIT_MS195, + LIBLTE_RRC_T_POLL_RETRANSMIT_MS200, + LIBLTE_RRC_T_POLL_RETRANSMIT_MS205, + LIBLTE_RRC_T_POLL_RETRANSMIT_MS210, + LIBLTE_RRC_T_POLL_RETRANSMIT_MS215, + LIBLTE_RRC_T_POLL_RETRANSMIT_MS220, + LIBLTE_RRC_T_POLL_RETRANSMIT_MS225, + LIBLTE_RRC_T_POLL_RETRANSMIT_MS230, + LIBLTE_RRC_T_POLL_RETRANSMIT_MS235, + LIBLTE_RRC_T_POLL_RETRANSMIT_MS240, + LIBLTE_RRC_T_POLL_RETRANSMIT_MS245, + LIBLTE_RRC_T_POLL_RETRANSMIT_MS250, + LIBLTE_RRC_T_POLL_RETRANSMIT_MS300, + LIBLTE_RRC_T_POLL_RETRANSMIT_MS350, + LIBLTE_RRC_T_POLL_RETRANSMIT_MS400, + LIBLTE_RRC_T_POLL_RETRANSMIT_MS450, + LIBLTE_RRC_T_POLL_RETRANSMIT_MS500, + LIBLTE_RRC_T_POLL_RETRANSMIT_SPARE9, + LIBLTE_RRC_T_POLL_RETRANSMIT_SPARE8, + LIBLTE_RRC_T_POLL_RETRANSMIT_SPARE7, + LIBLTE_RRC_T_POLL_RETRANSMIT_SPARE6, + LIBLTE_RRC_T_POLL_RETRANSMIT_SPARE5, + LIBLTE_RRC_T_POLL_RETRANSMIT_SPARE4, + LIBLTE_RRC_T_POLL_RETRANSMIT_SPARE3, + LIBLTE_RRC_T_POLL_RETRANSMIT_SPARE2, + LIBLTE_RRC_T_POLL_RETRANSMIT_SPARE1, + LIBLTE_RRC_T_POLL_RETRANSMIT_N_ITEMS, +}LIBLTE_RRC_T_POLL_RETRANSMIT_ENUM; +static const char liblte_rrc_t_poll_retransmit_text[LIBLTE_RRC_T_POLL_RETRANSMIT_N_ITEMS][20] = { "5ms", "10ms", "15ms", "20ms", + "25ms", "30ms", "35ms", "40ms", + "45ms", "50ms", "55ms", "60ms", + "65ms", "70ms", "75ms", "80ms", + "85ms", "90ms", "95ms", "100ms", + "105ms", "110ms", "115ms", "120ms", + "125ms", "130ms", "135ms", "140ms", + "145ms", "150ms", "155ms", "160ms", + "165ms", "170ms", "175ms", "180ms", + "185ms", "190ms", "195ms", "200ms", + "205ms", "210ms", "215ms", "220ms", + "225ms", "230ms", "235ms", "240ms", + "245ms", "250ms", "300ms", "350ms", + "400ms", "450ms", "500ms", "SPARE", + "SPARE", "SPARE", "SPARE", "SPARE", + "SPARE", "SPARE", "SPARE", "SPARE"}; +static const int32 liblte_rrc_t_poll_retransmit_num[LIBLTE_RRC_T_POLL_RETRANSMIT_N_ITEMS] = { 5, 10, 15, 20, + 25, 30, 35, 40, + 45, 50, 55, 60, + 65, 70, 75, 80, + 85, 90, 95, 100, + 105, 110, 115, 120, + 125, 130, 135, 140, + 145, 150, 155, 160, + 165, 170, 175, 180, + 185, 190, 195, 200, + 205, 210, 215, 220, + 225, 230, 235, 240, + 245, 250, 300, 350, + 400, 450, 500, -1, + -1, -1, -1, -1, + -1, -1, -1, -1}; +typedef enum{ + LIBLTE_RRC_POLL_PDU_P4 = 0, + LIBLTE_RRC_POLL_PDU_P8, + LIBLTE_RRC_POLL_PDU_P16, + LIBLTE_RRC_POLL_PDU_P32, + LIBLTE_RRC_POLL_PDU_P64, + LIBLTE_RRC_POLL_PDU_P128, + LIBLTE_RRC_POLL_PDU_P256, + LIBLTE_RRC_POLL_PDU_INFINITY, + LIBLTE_RRC_POLL_PDU_N_ITEMS, +}LIBLTE_RRC_POLL_PDU_ENUM; +static const char liblte_rrc_poll_pdu_text[LIBLTE_RRC_POLL_PDU_N_ITEMS][20] = { "p4", "p8", "p16", "p32", + "p64", "p128", "p256", "INFINITY"}; +static const int32 liblte_rrc_poll_pdu_num[LIBLTE_RRC_POLL_PDU_N_ITEMS] = { 4, 8, 16, 32, + 64, 128, 256, -1}; +typedef enum{ + LIBLTE_RRC_POLL_BYTE_KB25 = 0, + LIBLTE_RRC_POLL_BYTE_KB50, + LIBLTE_RRC_POLL_BYTE_KB75, + LIBLTE_RRC_POLL_BYTE_KB100, + LIBLTE_RRC_POLL_BYTE_KB125, + LIBLTE_RRC_POLL_BYTE_KB250, + LIBLTE_RRC_POLL_BYTE_KB375, + LIBLTE_RRC_POLL_BYTE_KB500, + LIBLTE_RRC_POLL_BYTE_KB750, + LIBLTE_RRC_POLL_BYTE_KB1000, + LIBLTE_RRC_POLL_BYTE_KB1250, + LIBLTE_RRC_POLL_BYTE_KB1500, + LIBLTE_RRC_POLL_BYTE_KB2000, + LIBLTE_RRC_POLL_BYTE_KB3000, + LIBLTE_RRC_POLL_BYTE_INFINITY, + LIBLTE_RRC_POLL_BYTE_SPARE1, + LIBLTE_RRC_POLL_BYTE_N_ITEMS, +}LIBLTE_RRC_POLL_BYTE_ENUM; +static const char liblte_rrc_poll_byte_text[LIBLTE_RRC_POLL_BYTE_N_ITEMS][20] = { "25kB", "50kB", "75kB", "100kB", + "125kB", "250kB", "375kB", "500kB", + "750kB", "1000kB", "1250kB", "1500kB", + "2000kB", "3000kB", "INFINITY", "SPARE"}; +static const int32 liblte_rrc_poll_byte_num[LIBLTE_RRC_POLL_BYTE_N_ITEMS] = { 25, 50, 75, 100, + 125, 250, 375, 500, + 750, 1000, 1250, 1500, + 2000, 3000, -1, -1}; +typedef enum{ + LIBLTE_RRC_MAX_RETX_THRESHOLD_T1 = 0, + LIBLTE_RRC_MAX_RETX_THRESHOLD_T2, + LIBLTE_RRC_MAX_RETX_THRESHOLD_T3, + LIBLTE_RRC_MAX_RETX_THRESHOLD_T4, + LIBLTE_RRC_MAX_RETX_THRESHOLD_T6, + LIBLTE_RRC_MAX_RETX_THRESHOLD_T8, + LIBLTE_RRC_MAX_RETX_THRESHOLD_T16, + LIBLTE_RRC_MAX_RETX_THRESHOLD_T32, + LIBLTE_RRC_MAX_RETX_THRESHOLD_N_ITEMS, +}LIBLTE_RRC_MAX_RETX_THRESHOLD_ENUM; +static const char liblte_rrc_max_retx_threshold_text[LIBLTE_RRC_MAX_RETX_THRESHOLD_N_ITEMS][20] = { "t1", "t2", "t3", "t4", + "t6", "t8", "t16", "t32"}; +static const uint32_t liblte_rrc_max_retx_threshold_num[LIBLTE_RRC_MAX_RETX_THRESHOLD_N_ITEMS] = { 1, 2, 3, 4, + 6, 8, 16, 32}; +typedef enum{ + LIBLTE_RRC_T_REORDERING_MS0 = 0, + LIBLTE_RRC_T_REORDERING_MS5, + LIBLTE_RRC_T_REORDERING_MS10, + LIBLTE_RRC_T_REORDERING_MS15, + LIBLTE_RRC_T_REORDERING_MS20, + LIBLTE_RRC_T_REORDERING_MS25, + LIBLTE_RRC_T_REORDERING_MS30, + LIBLTE_RRC_T_REORDERING_MS35, + LIBLTE_RRC_T_REORDERING_MS40, + LIBLTE_RRC_T_REORDERING_MS45, + LIBLTE_RRC_T_REORDERING_MS50, + LIBLTE_RRC_T_REORDERING_MS55, + LIBLTE_RRC_T_REORDERING_MS60, + LIBLTE_RRC_T_REORDERING_MS65, + LIBLTE_RRC_T_REORDERING_MS70, + LIBLTE_RRC_T_REORDERING_MS75, + LIBLTE_RRC_T_REORDERING_MS80, + LIBLTE_RRC_T_REORDERING_MS85, + LIBLTE_RRC_T_REORDERING_MS90, + LIBLTE_RRC_T_REORDERING_MS95, + LIBLTE_RRC_T_REORDERING_MS100, + LIBLTE_RRC_T_REORDERING_MS110, + LIBLTE_RRC_T_REORDERING_MS120, + LIBLTE_RRC_T_REORDERING_MS130, + LIBLTE_RRC_T_REORDERING_MS140, + LIBLTE_RRC_T_REORDERING_MS150, + LIBLTE_RRC_T_REORDERING_MS160, + LIBLTE_RRC_T_REORDERING_MS170, + LIBLTE_RRC_T_REORDERING_MS180, + LIBLTE_RRC_T_REORDERING_MS190, + LIBLTE_RRC_T_REORDERING_MS200, + LIBLTE_RRC_T_REORDERING_SPARE1, + LIBLTE_RRC_T_REORDERING_N_ITEMS, +}LIBLTE_RRC_T_REORDERING_ENUM; +static const char liblte_rrc_t_reordering_text[LIBLTE_RRC_T_REORDERING_N_ITEMS][20] = { "ms0", "ms5", "ms10", "ms15", + "ms20", "ms25", "ms30", "ms35", + "ms40", "ms45", "ms50", "ms55", + "ms60", "ms65", "ms70", "ms75", + "ms80", "ms85", "ms90", "ms95", + "ms100", "ms110", "ms120", "ms130", + "ms140", "ms150", "ms160", "ms170", + "ms180", "ms190", "ms200", "SPARE"}; +static const int32 liblte_rrc_t_reordering_num[LIBLTE_RRC_T_REORDERING_N_ITEMS] = { 0, 5, 10, 15, + 20, 25, 30, 35, + 40, 45, 50, 55, + 60, 65, 70, 75, + 80, 85, 90, 95, + 100, 110, 120, 130, + 140, 150, 160, 170, + 180, 190, 200, -1}; +typedef enum{ + LIBLTE_RRC_RLC_MODE_AM = 0, + LIBLTE_RRC_RLC_MODE_UM_BI, + LIBLTE_RRC_RLC_MODE_UM_UNI_UL, + LIBLTE_RRC_RLC_MODE_UM_UNI_DL, + LIBLTE_RRC_RLC_MODE_N_ITEMS, +}LIBLTE_RRC_RLC_MODE_ENUM; +static const char liblte_rrc_rlc_mode_text[LIBLTE_RRC_RLC_MODE_N_ITEMS][20] = {"AM", + "UM BI", + "UM UNI UL", + "UM UNI DL"}; +typedef enum{ + LIBLTE_RRC_T_STATUS_PROHIBIT_MS0 = 0, + LIBLTE_RRC_T_STATUS_PROHIBIT_MS5, + LIBLTE_RRC_T_STATUS_PROHIBIT_MS10, + LIBLTE_RRC_T_STATUS_PROHIBIT_MS15, + LIBLTE_RRC_T_STATUS_PROHIBIT_MS20, + LIBLTE_RRC_T_STATUS_PROHIBIT_MS25, + LIBLTE_RRC_T_STATUS_PROHIBIT_MS30, + LIBLTE_RRC_T_STATUS_PROHIBIT_MS35, + LIBLTE_RRC_T_STATUS_PROHIBIT_MS40, + LIBLTE_RRC_T_STATUS_PROHIBIT_MS45, + LIBLTE_RRC_T_STATUS_PROHIBIT_MS50, + LIBLTE_RRC_T_STATUS_PROHIBIT_MS55, + LIBLTE_RRC_T_STATUS_PROHIBIT_MS60, + LIBLTE_RRC_T_STATUS_PROHIBIT_MS65, + LIBLTE_RRC_T_STATUS_PROHIBIT_MS70, + LIBLTE_RRC_T_STATUS_PROHIBIT_MS75, + LIBLTE_RRC_T_STATUS_PROHIBIT_MS80, + LIBLTE_RRC_T_STATUS_PROHIBIT_MS85, + LIBLTE_RRC_T_STATUS_PROHIBIT_MS90, + LIBLTE_RRC_T_STATUS_PROHIBIT_MS95, + LIBLTE_RRC_T_STATUS_PROHIBIT_MS100, + LIBLTE_RRC_T_STATUS_PROHIBIT_MS105, + LIBLTE_RRC_T_STATUS_PROHIBIT_MS110, + LIBLTE_RRC_T_STATUS_PROHIBIT_MS115, + LIBLTE_RRC_T_STATUS_PROHIBIT_MS120, + LIBLTE_RRC_T_STATUS_PROHIBIT_MS125, + LIBLTE_RRC_T_STATUS_PROHIBIT_MS130, + LIBLTE_RRC_T_STATUS_PROHIBIT_MS135, + LIBLTE_RRC_T_STATUS_PROHIBIT_MS140, + LIBLTE_RRC_T_STATUS_PROHIBIT_MS145, + LIBLTE_RRC_T_STATUS_PROHIBIT_MS150, + LIBLTE_RRC_T_STATUS_PROHIBIT_MS155, + LIBLTE_RRC_T_STATUS_PROHIBIT_MS160, + LIBLTE_RRC_T_STATUS_PROHIBIT_MS165, + LIBLTE_RRC_T_STATUS_PROHIBIT_MS170, + LIBLTE_RRC_T_STATUS_PROHIBIT_MS175, + LIBLTE_RRC_T_STATUS_PROHIBIT_MS180, + LIBLTE_RRC_T_STATUS_PROHIBIT_MS185, + LIBLTE_RRC_T_STATUS_PROHIBIT_MS190, + LIBLTE_RRC_T_STATUS_PROHIBIT_MS195, + LIBLTE_RRC_T_STATUS_PROHIBIT_MS200, + LIBLTE_RRC_T_STATUS_PROHIBIT_MS205, + LIBLTE_RRC_T_STATUS_PROHIBIT_MS210, + LIBLTE_RRC_T_STATUS_PROHIBIT_MS215, + LIBLTE_RRC_T_STATUS_PROHIBIT_MS220, + LIBLTE_RRC_T_STATUS_PROHIBIT_MS225, + LIBLTE_RRC_T_STATUS_PROHIBIT_MS230, + LIBLTE_RRC_T_STATUS_PROHIBIT_MS235, + LIBLTE_RRC_T_STATUS_PROHIBIT_MS240, + LIBLTE_RRC_T_STATUS_PROHIBIT_MS245, + LIBLTE_RRC_T_STATUS_PROHIBIT_MS250, + LIBLTE_RRC_T_STATUS_PROHIBIT_MS300, + LIBLTE_RRC_T_STATUS_PROHIBIT_MS350, + LIBLTE_RRC_T_STATUS_PROHIBIT_MS400, + LIBLTE_RRC_T_STATUS_PROHIBIT_MS450, + LIBLTE_RRC_T_STATUS_PROHIBIT_MS500, + LIBLTE_RRC_T_STATUS_PROHIBIT_SPARE8, + LIBLTE_RRC_T_STATUS_PROHIBIT_SPARE7, + LIBLTE_RRC_T_STATUS_PROHIBIT_SPARE6, + LIBLTE_RRC_T_STATUS_PROHIBIT_SPARE5, + LIBLTE_RRC_T_STATUS_PROHIBIT_SPARE4, + LIBLTE_RRC_T_STATUS_PROHIBIT_SPARE3, + LIBLTE_RRC_T_STATUS_PROHIBIT_SPARE2, + LIBLTE_RRC_T_STATUS_PROHIBIT_SPARE1, + LIBLTE_RRC_T_STATUS_PROHIBIT_N_ITEMS, +}LIBLTE_RRC_T_STATUS_PROHIBIT_ENUM; +static const char liblte_rrc_t_status_prohibit_text[LIBLTE_RRC_T_STATUS_PROHIBIT_N_ITEMS][20] = { "ms0", "ms5", "ms10", "ms15", + "ms20", "ms25", "ms30", "ms35", + "ms40", "ms45", "ms50", "ms55", + "ms60", "ms65", "ms70", "ms75", + "ms80", "ms85", "ms90", "ms95", + "ms100", "ms105", "ms110", "ms115", + "ms120", "ms125", "ms130", "ms135", + "ms140", "ms145", "ms150", "ms155", + "ms160", "ms165", "ms170", "ms175", + "ms180", "ms185", "ms190", "ms195", + "ms200", "ms205", "ms210", "ms215", + "ms220", "ms225", "ms230", "ms235", + "ms240", "ms245", "ms250", "ms300", + "ms350", "ms400", "ms450", "ms500", + "SPARE", "SPARE", "SPARE", "SPARE", + "SPARE", "SPARE", "SPARE", "SPARE"}; +static const int32 liblte_rrc_t_status_prohibit_num[LIBLTE_RRC_T_STATUS_PROHIBIT_N_ITEMS] = { 0, 5, 10, 15, + 20, 25, 30, 35, + 40, 45, 50, 55, + 60, 65, 70, 75, + 80, 85, 90, 95, + 100, 105, 110, 115, + 120, 125, 130, 135, + 140, 145, 150, 155, + 160, 165, 170, 175, + 180, 185, 190, 195, + 200, 205, 210, 215, + 220, 225, 230, 235, + 240, 245, 250, 300, + 350, 400, 450, 500, + -1, -1, -1, -1, + -1, -1, -1, -1}; +typedef enum{ + LIBLTE_RRC_SN_FIELD_LENGTH_SIZE5 = 0, + LIBLTE_RRC_SN_FIELD_LENGTH_SIZE10, + LIBLTE_RRC_SN_FIELD_LENGTH_N_ITEMS, +}LIBLTE_RRC_SN_FIELD_LENGTH_ENUM; +static const char liblte_rrc_sn_field_length_text[LIBLTE_RRC_SN_FIELD_LENGTH_N_ITEMS][20] = {"size5", "size10"}; +static const uint8 liblte_rrc_sn_field_length_num[LIBLTE_RRC_SN_FIELD_LENGTH_N_ITEMS] = {5, 10}; +typedef enum{ + LIBLTE_RRC_SPS_INTERVAL_DL_SF10 = 0, + LIBLTE_RRC_SPS_INTERVAL_DL_SF20, + LIBLTE_RRC_SPS_INTERVAL_DL_SF32, + LIBLTE_RRC_SPS_INTERVAL_DL_SF40, + LIBLTE_RRC_SPS_INTERVAL_DL_SF64, + LIBLTE_RRC_SPS_INTERVAL_DL_SF80, + LIBLTE_RRC_SPS_INTERVAL_DL_SF128, + LIBLTE_RRC_SPS_INTERVAL_DL_SF160, + LIBLTE_RRC_SPS_INTERVAL_DL_SF320, + LIBLTE_RRC_SPS_INTERVAL_DL_SF640, + LIBLTE_RRC_SPS_INTERVAL_DL_SPARE6, + LIBLTE_RRC_SPS_INTERVAL_DL_SPARE5, + LIBLTE_RRC_SPS_INTERVAL_DL_SPARE4, + LIBLTE_RRC_SPS_INTERVAL_DL_SPARE3, + LIBLTE_RRC_SPS_INTERVAL_DL_SPARE2, + LIBLTE_RRC_SPS_INTERVAL_DL_SPARE1, + LIBLTE_RRC_SPS_INTERVAL_DL_N_ITEMS, +}LIBLTE_RRC_SPS_INTERVAL_DL_ENUM; +static const char liblte_rrc_sps_interval_dl_text[LIBLTE_RRC_SPS_INTERVAL_DL_N_ITEMS][20] = { "sf10", "sf20", "sf32", "sf40", + "sf64", "sf80", "sf128", "sf160", + "sf320", "sf640", "SPARE", "SPARE", + "SPARE", "SPARE", "SPARE", "SPARE"}; +typedef enum{ + LIBLTE_RRC_SPS_INTERVAL_UL_SF10 = 0, + LIBLTE_RRC_SPS_INTERVAL_UL_SF20, + LIBLTE_RRC_SPS_INTERVAL_UL_SF32, + LIBLTE_RRC_SPS_INTERVAL_UL_SF40, + LIBLTE_RRC_SPS_INTERVAL_UL_SF64, + LIBLTE_RRC_SPS_INTERVAL_UL_SF80, + LIBLTE_RRC_SPS_INTERVAL_UL_SF128, + LIBLTE_RRC_SPS_INTERVAL_UL_SF160, + LIBLTE_RRC_SPS_INTERVAL_UL_SF320, + LIBLTE_RRC_SPS_INTERVAL_UL_SF640, + LIBLTE_RRC_SPS_INTERVAL_UL_SPARE6, + LIBLTE_RRC_SPS_INTERVAL_UL_SPARE5, + LIBLTE_RRC_SPS_INTERVAL_UL_SPARE4, + LIBLTE_RRC_SPS_INTERVAL_UL_SPARE3, + LIBLTE_RRC_SPS_INTERVAL_UL_SPARE2, + LIBLTE_RRC_SPS_INTERVAL_UL_SPARE1, + LIBLTE_RRC_SPS_INTERVAL_UL_N_ITEMS, +}LIBLTE_RRC_SPS_INTERVAL_UL_ENUM; +static const char liblte_rrc_sps_interval_ul_text[LIBLTE_RRC_SPS_INTERVAL_UL_N_ITEMS][20] = { "sf10", "sf20", "sf32", "sf40", + "sf64", "sf80", "sf128", "sf160", + "sf320", "sf640", "SPARE", "SPARE", + "SPARE", "SPARE", "SPARE", "SPARE"}; +typedef enum{ + LIBLTE_RRC_IMPLICIT_RELEASE_AFTER_E2 = 0, + LIBLTE_RRC_IMPLICIT_RELEASE_AFTER_E3, + LIBLTE_RRC_IMPLICIT_RELEASE_AFTER_E4, + LIBLTE_RRC_IMPLICIT_RELEASE_AFTER_E8, + LIBLTE_RRC_IMPLICIT_RELEASE_AFTER_N_ITEMS, +}LIBLTE_RRC_IMPLICIT_RELEASE_AFTER_ENUM; +static const char liblte_rrc_implicit_release_after_text[LIBLTE_RRC_IMPLICIT_RELEASE_AFTER_N_ITEMS][20] = {"e2", "e3", "e4", "e8"}; +typedef enum{ + LIBLTE_RRC_TWO_INTERVALS_CONFIG_TRUE = 0, + LIBLTE_RRC_TWO_INTERVALS_CONFIG_N_ITEMS, +}LIBLTE_RRC_TWO_INTERVALS_CONFIG_ENUM; +static const char liblte_rrc_two_intervals_config_text[LIBLTE_RRC_TWO_INTERVALS_CONFIG_N_ITEMS][20] = {"TRUE"}; +// Structs +typedef struct{ + LIBLTE_RRC_T_POLL_RETRANSMIT_ENUM t_poll_retx; + LIBLTE_RRC_POLL_PDU_ENUM poll_pdu; + LIBLTE_RRC_POLL_BYTE_ENUM poll_byte; + LIBLTE_RRC_MAX_RETX_THRESHOLD_ENUM max_retx_thresh; +}LIBLTE_RRC_UL_AM_RLC_STRUCT; +typedef struct{ + LIBLTE_RRC_T_REORDERING_ENUM t_reordering; + LIBLTE_RRC_T_STATUS_PROHIBIT_ENUM t_status_prohibit; +}LIBLTE_RRC_DL_AM_RLC_STRUCT; +typedef struct{ + LIBLTE_RRC_SN_FIELD_LENGTH_ENUM sn_field_len; +}LIBLTE_RRC_UL_UM_RLC_STRUCT; +typedef struct{ + LIBLTE_RRC_SN_FIELD_LENGTH_ENUM sn_field_len; + LIBLTE_RRC_T_REORDERING_ENUM t_reordering; +}LIBLTE_RRC_DL_UM_RLC_STRUCT; +typedef struct{ + LIBLTE_RRC_UL_AM_RLC_STRUCT ul_am_rlc; + LIBLTE_RRC_DL_AM_RLC_STRUCT dl_am_rlc; + LIBLTE_RRC_UL_UM_RLC_STRUCT ul_um_bi_rlc; + LIBLTE_RRC_DL_UM_RLC_STRUCT dl_um_bi_rlc; + LIBLTE_RRC_UL_UM_RLC_STRUCT ul_um_uni_rlc; + LIBLTE_RRC_DL_UM_RLC_STRUCT dl_um_uni_rlc; + LIBLTE_RRC_RLC_MODE_ENUM rlc_mode; +}LIBLTE_RRC_RLC_CONFIG_STRUCT; +typedef struct{ + LIBLTE_RRC_RLC_CONFIG_STRUCT rlc_explicit_cnfg; + LIBLTE_RRC_LOGICAL_CHANNEL_CONFIG_STRUCT lc_explicit_cnfg; + uint32 srb_id; + bool rlc_cnfg_present; + bool rlc_default_cnfg_present; + bool lc_cnfg_present; + bool lc_default_cnfg_present; +}LIBLTE_RRC_SRB_TO_ADD_MOD_STRUCT; +typedef struct{ + LIBLTE_RRC_PDCP_CONFIG_STRUCT pdcp_cnfg; + LIBLTE_RRC_RLC_CONFIG_STRUCT rlc_cnfg; + LIBLTE_RRC_LOGICAL_CHANNEL_CONFIG_STRUCT lc_cnfg; + uint32 eps_bearer_id; + uint32 lc_id; + uint8 drb_id; + bool eps_bearer_id_present; + bool pdcp_cnfg_present; + bool rlc_cnfg_present; + bool lc_id_present; + bool lc_cnfg_present; +}LIBLTE_RRC_DRB_TO_ADD_MOD_STRUCT; +typedef struct{ + LIBLTE_RRC_MAC_MAIN_CONFIG_STRUCT explicit_value; + bool default_value; +}LIBLTE_RRC_MAC_MAIN_CONFIG_CHOICE_STRUCT; +typedef struct{ + LIBLTE_RRC_SPS_INTERVAL_DL_ENUM sps_interval_dl; + uint32 n1_pucch_an_persistent_list[4]; + uint32 n1_pucch_an_persistent_list_size; + uint8 N_sps_processes; + bool setup_present; +}LIBLTE_RRC_SPS_CONFIG_DL_STRUCT; +typedef struct{ + LIBLTE_RRC_SPS_INTERVAL_UL_ENUM sps_interval_ul; + LIBLTE_RRC_IMPLICIT_RELEASE_AFTER_ENUM implicit_release_after; + LIBLTE_RRC_TWO_INTERVALS_CONFIG_ENUM two_intervals_cnfg; + int32 p0_nominal_pusch; + int32 p0_ue_pusch; + bool setup_present; + bool p0_persistent_present; + bool two_intervals_cnfg_present; +}LIBLTE_RRC_SPS_CONFIG_UL_STRUCT; +typedef struct{ + LIBLTE_RRC_SPS_CONFIG_DL_STRUCT sps_cnfg_dl; + LIBLTE_RRC_SPS_CONFIG_UL_STRUCT sps_cnfg_ul; + uint16 sps_c_rnti; + bool sps_c_rnti_present; + bool sps_cnfg_dl_present; + bool sps_cnfg_ul_present; +}LIBLTE_RRC_SPS_CONFIG_STRUCT; +typedef struct{ + LIBLTE_RRC_T301_ENUM t301; + LIBLTE_RRC_T310_ENUM t310; + LIBLTE_RRC_N310_ENUM n310; + LIBLTE_RRC_T311_ENUM t311; + LIBLTE_RRC_N311_ENUM n311; +}LIBLTE_RRC_RLF_TIMERS_AND_CONSTANTS_STRUCT; +typedef struct{ + LIBLTE_RRC_SRB_TO_ADD_MOD_STRUCT srb_to_add_mod_list[2]; + LIBLTE_RRC_DRB_TO_ADD_MOD_STRUCT drb_to_add_mod_list[LIBLTE_RRC_MAX_DRB]; + LIBLTE_RRC_MAC_MAIN_CONFIG_CHOICE_STRUCT mac_main_cnfg; + LIBLTE_RRC_SPS_CONFIG_STRUCT sps_cnfg; + LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT phy_cnfg_ded; + LIBLTE_RRC_RLF_TIMERS_AND_CONSTANTS_STRUCT rlf_timers_and_constants; + uint32 srb_to_add_mod_list_size; + uint32 drb_to_add_mod_list_size; + uint32 drb_to_release_list_size; + uint8 drb_to_release_list[LIBLTE_RRC_MAX_DRB]; + bool mac_main_cnfg_present; + bool sps_cnfg_present; + bool phy_cnfg_ded_present; + bool rlf_timers_and_constants_present; +}LIBLTE_RRC_RR_CONFIG_DEDICATED_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_rr_config_dedicated_ie(LIBLTE_RRC_RR_CONFIG_DEDICATED_STRUCT *rr_cnfg, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_rr_config_dedicated_ie(uint8 **ie_ptr, + LIBLTE_RRC_RR_CONFIG_DEDICATED_STRUCT *rr_cnfg); + +/********************************************************************* + IE Name: RLC Config + + Description: Specifies the RLC configuration of SRBs and DRBs + + Document Reference: 36.331 v10.0.0 Section 6.3.2 +*********************************************************************/ +// Defines +// Enums +// Structs +// RLC Config struct defined above +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_rlc_config_ie(LIBLTE_RRC_RLC_CONFIG_STRUCT *rlc_cnfg, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_rlc_config_ie(uint8 **ie_ptr, + LIBLTE_RRC_RLC_CONFIG_STRUCT *rlc_cnfg); + +/********************************************************************* + IE Name: RLF Timers and Constants + + Description: Contains UE specific timers and constants applicable + for UEs in RRC_CONNECTED + + Document Reference: 36.331 v10.0.0 Section 6.3.2 +*********************************************************************/ +// Defines +// Enums +// Structs +// RLF Timers and Constants struct defined above +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_rlf_timers_and_constants_ie(LIBLTE_RRC_RLF_TIMERS_AND_CONSTANTS_STRUCT *rlf_timers_and_constants, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_rlf_timers_and_constants_ie(uint8 **ie_ptr, + LIBLTE_RRC_RLF_TIMERS_AND_CONSTANTS_STRUCT *rlf_timers_and_constants); + +/********************************************************************* + IE Name: RN Subframe Config + + Description: Specifies the subframe configuration for an RN + + Document Reference: 36.331 v10.0.0 Section 6.3.2 +*********************************************************************/ +// Defines +// Enums +// Structs +// Functions +// FIXME + +/********************************************************************* + IE Name: Scheduling Request Config + + Description: Specifies the scheduling request related parameters + + Document Reference: 36.331 v10.0.0 Section 6.3.2 +*********************************************************************/ +// Defines +// Enums +// Structs +// Scheduling Request Config struct defined above +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_scheduling_request_config_ie(LIBLTE_RRC_SCHEDULING_REQUEST_CONFIG_STRUCT *sched_request_cnfg, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_scheduling_request_config_ie(uint8 **ie_ptr, + LIBLTE_RRC_SCHEDULING_REQUEST_CONFIG_STRUCT *sched_request_cnfg); + +/********************************************************************* + IE Name: Sounding RS UL Config + + Description: Specifies the uplink Sounding RS configuration for + periodic and aperiodic sounding + + Document Reference: 36.331 v10.0.0 Section 6.3.2 +*********************************************************************/ +// Defines +// Enums +// Sounding RS UL Config enums defined above +// Structs +// Sounding RS UL Config struct defined above +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_srs_ul_config_common_ie(LIBLTE_RRC_SRS_UL_CONFIG_COMMON_STRUCT *srs_ul_cnfg, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_srs_ul_config_common_ie(uint8 **ie_ptr, + LIBLTE_RRC_SRS_UL_CONFIG_COMMON_STRUCT *srs_ul_cnfg); +LIBLTE_ERROR_ENUM liblte_rrc_pack_srs_ul_config_dedicated_ie(LIBLTE_RRC_SRS_UL_CONFIG_DEDICATED_STRUCT *srs_ul_cnfg, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_srs_ul_config_dedicated_ie(uint8 **ie_ptr, + LIBLTE_RRC_SRS_UL_CONFIG_DEDICATED_STRUCT *srs_ul_cnfg); + +/********************************************************************* + IE Name: SPS Config + + Description: Specifies the semi-persistent scheduling + configuration + + Document Reference: 36.331 v10.0.0 Section 6.3.2 +*********************************************************************/ +// Defines +// Enums +// Structs +// SPS Config struct defined above +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_sps_config_ie(LIBLTE_RRC_SPS_CONFIG_STRUCT *sps_cnfg, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_sps_config_ie(uint8 **ie_ptr, + LIBLTE_RRC_SPS_CONFIG_STRUCT *sps_cnfg); + +/********************************************************************* + IE Name: TDD Config + + Description: Specifies the TDD specific physical channel + configuration + + Document Reference: 36.331 v10.0.0 Section 6.3.2 +*********************************************************************/ +// Defines +// Enums +// TDD Config enums defined above +// Structs +// TDD Config struct defined above +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_tdd_config_ie(LIBLTE_RRC_TDD_CONFIG_STRUCT *tdd_cnfg, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_tdd_config_ie(uint8 **ie_ptr, + LIBLTE_RRC_TDD_CONFIG_STRUCT *tdd_cnfg); + +/********************************************************************* + IE Name: Time Alignment Timer + + Description: Controls how long the UE is considered uplink time + aligned + + Document Reference: 36.331 v10.0.0 Section 6.3.2 +*********************************************************************/ +// Defines +// Enums +// Time Alignment Timer enum defined above +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_time_alignment_timer_ie(LIBLTE_RRC_TIME_ALIGNMENT_TIMER_ENUM time_alignment_timer, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_time_alignment_timer_ie(uint8 **ie_ptr, + LIBLTE_RRC_TIME_ALIGNMENT_TIMER_ENUM *time_alignment_timer); + +/********************************************************************* + IE Name: TPC PDCCH Config + + Description: Specifies the RNTIs and indecies for PUCCH and PUSCH + power control + + Document Reference: 36.331 v10.0.0 Section 6.3.2 +*********************************************************************/ +// Defines +// Enums +// Structs +// TPC PDCCH Config struct defined above +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_tpc_pdcch_config_ie(LIBLTE_RRC_TPC_PDCCH_CONFIG_STRUCT *tpc_pdcch_cnfg, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_tpc_pdcch_config_ie(uint8 **ie_ptr, + LIBLTE_RRC_TPC_PDCCH_CONFIG_STRUCT *tpc_pdcch_cnfg); + +/********************************************************************* + IE Name: UL Antenna Info + + Description: Specifies the UL antenna configuration + + Document Reference: 36.331 v10.0.0 Section 6.3.2 +*********************************************************************/ +// Defines +// Enums +typedef enum{ + LIBLTE_RRC_UL_TRANSMISSION_MODE_R10_TM1 = 0, + LIBLTE_RRC_UL_TRANSMISSION_MODE_R10_TM2, + LIBLTE_RRC_UL_TRANSMISSION_MODE_R10_SPARE6, + LIBLTE_RRC_UL_TRANSMISSION_MODE_R10_SPARE5, + LIBLTE_RRC_UL_TRANSMISSION_MODE_R10_SPARE4, + LIBLTE_RRC_UL_TRANSMISSION_MODE_R10_SPARE3, + LIBLTE_RRC_UL_TRANSMISSION_MODE_R10_SPARE2, + LIBLTE_RRC_UL_TRANSMISSION_MODE_R10_SPARE1, + LIBLTE_RRC_UL_TRANSMISSION_MODE_R10_N_ITEMS, +}LIBLTE_RRC_UL_TRANSMISSION_MODE_R10_ENUM; +static const char liblte_rrc_ul_transmission_mode_r10_text[LIBLTE_RRC_UL_TRANSMISSION_MODE_R10_N_ITEMS][20] = { "TM1", "TM2", "SPARE", "SPARE", + "SPARE", "SPARE", "SPARE", "SPARE"}; +// Structs +typedef struct{ + LIBLTE_RRC_UL_TRANSMISSION_MODE_R10_ENUM ul_tx_mode; + bool four_ant_port_activated; +}LIBLTE_RRC_UL_ANTENNA_INFO_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_ul_antenna_info_ie(LIBLTE_RRC_UL_ANTENNA_INFO_STRUCT *ul_ant_info, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_ul_antenna_info_ie(uint8 **ie_ptr, + LIBLTE_RRC_UL_ANTENNA_INFO_STRUCT *ul_ant_info); + +/********************************************************************* + IE Name: Uplink Power Control + + Description: Specifies the parameters for uplink power control in + the system information and in the dedicated + signalling + + Document Reference: 36.331 v10.0.0 Section 6.3.2 +*********************************************************************/ +// Defines +// Enums +// Uplink Power Control enums defined above +// Structs +// Uplink Power Control structs defined above +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_ul_power_control_common_ie(LIBLTE_RRC_UL_POWER_CONTROL_COMMON_STRUCT *ul_pwr_ctrl, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_ul_power_control_common_ie(uint8 **ie_ptr, + LIBLTE_RRC_UL_POWER_CONTROL_COMMON_STRUCT *ul_pwr_ctrl); +LIBLTE_ERROR_ENUM liblte_rrc_pack_ul_power_control_dedicated_ie(LIBLTE_RRC_UL_POWER_CONTROL_DEDICATED_STRUCT *ul_pwr_ctrl, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_ul_power_control_dedicated_ie(uint8 **ie_ptr, + LIBLTE_RRC_UL_POWER_CONTROL_DEDICATED_STRUCT *ul_pwr_ctrl); + +/********************************************************************* + IE Name: System Information Block Type 2 + + Description: Contains radio resource configuration that is common + for all UEs + + Document Reference: 36.331 v10.0.0 Section 6.3.1 +*********************************************************************/ +// Defines +// Enums +typedef enum{ + LIBLTE_RRC_AC_BARRING_FACTOR_P00 = 0, + LIBLTE_RRC_AC_BARRING_FACTOR_P05, + LIBLTE_RRC_AC_BARRING_FACTOR_P10, + LIBLTE_RRC_AC_BARRING_FACTOR_P15, + LIBLTE_RRC_AC_BARRING_FACTOR_P20, + LIBLTE_RRC_AC_BARRING_FACTOR_P25, + LIBLTE_RRC_AC_BARRING_FACTOR_P30, + LIBLTE_RRC_AC_BARRING_FACTOR_P40, + LIBLTE_RRC_AC_BARRING_FACTOR_P50, + LIBLTE_RRC_AC_BARRING_FACTOR_P60, + LIBLTE_RRC_AC_BARRING_FACTOR_P70, + LIBLTE_RRC_AC_BARRING_FACTOR_P75, + LIBLTE_RRC_AC_BARRING_FACTOR_P80, + LIBLTE_RRC_AC_BARRING_FACTOR_P85, + LIBLTE_RRC_AC_BARRING_FACTOR_P90, + LIBLTE_RRC_AC_BARRING_FACTOR_P95, + LIBLTE_RRC_AC_BARRING_FACTOR_N_ITEMS, +}LIBLTE_RRC_AC_BARRING_FACTOR_ENUM; +static const char liblte_rrc_ac_barring_factor_text[LIBLTE_RRC_AC_BARRING_FACTOR_N_ITEMS][20] = {"0.00", "0.05", "0.10", "0.15", + "0.20", "0.25", "0.30", "0.40", + "0.50", "0.60", "0.70", "0.75", + "0.80", "0.85", "0.90", "0.95"}; +static const double liblte_rrc_ac_barring_factor_num[LIBLTE_RRC_AC_BARRING_FACTOR_N_ITEMS] = {0.00, 0.05, 0.10, 0.15, 0.20, 0.25, 0.30, 0.40, + 0.50, 0.60, 0.70, 0.75, 0.80, 0.85, 0.90, 0.95}; +typedef enum{ + LIBLTE_RRC_AC_BARRING_TIME_S4 = 0, + LIBLTE_RRC_AC_BARRING_TIME_S8, + LIBLTE_RRC_AC_BARRING_TIME_S16, + LIBLTE_RRC_AC_BARRING_TIME_S32, + LIBLTE_RRC_AC_BARRING_TIME_S64, + LIBLTE_RRC_AC_BARRING_TIME_S128, + LIBLTE_RRC_AC_BARRING_TIME_S256, + LIBLTE_RRC_AC_BARRING_TIME_S512, + LIBLTE_RRC_AC_BARRING_TIME_N_ITEMS, +}LIBLTE_RRC_AC_BARRING_TIME_ENUM; +static const char liblte_rrc_ac_barring_time_text[LIBLTE_RRC_AC_BARRING_TIME_N_ITEMS][20] = { "4", "8", "16", "32", + "64", "128", "256", "512"}; +static const uint16 liblte_rrc_ac_barring_time_num[LIBLTE_RRC_AC_BARRING_TIME_N_ITEMS] = {4, 8, 16, 32, 64, 128, 256, 512}; +typedef enum{ + LIBLTE_RRC_UL_BW_N6 = 0, + LIBLTE_RRC_UL_BW_N15, + LIBLTE_RRC_UL_BW_N25, + LIBLTE_RRC_UL_BW_N50, + LIBLTE_RRC_UL_BW_N75, + LIBLTE_RRC_UL_BW_N100, + LIBLTE_RRC_UL_BW_N_ITEMS, +}LIBLTE_RRC_UL_BW_ENUM; +static const char liblte_rrc_ul_bw_text[LIBLTE_RRC_UL_BW_N_ITEMS][20] = {"1.4", "3", "5", "10", + "15", "20"}; +static const double liblte_rrc_ul_bw_num[LIBLTE_RRC_UL_BW_N_ITEMS] = {1.4, 3, 5, 10, 15, 20}; +// Structs +typedef struct{ + LIBLTE_RRC_AC_BARRING_FACTOR_ENUM factor; + LIBLTE_RRC_AC_BARRING_TIME_ENUM time; + uint8 for_special_ac; + bool enabled; +}LIBLTE_RRC_AC_BARRING_CONFIG_STRUCT; +typedef struct{ + uint16 value; + bool present; +}LIBLTE_RRC_ARFCN_VALUE_EUTRA_STRUCT; +typedef struct{ + LIBLTE_RRC_UL_BW_ENUM bw; + bool present; +}LIBLTE_RRC_UL_BW_STRUCT; +typedef struct{ + LIBLTE_RRC_AC_BARRING_CONFIG_STRUCT ac_barring_for_mo_signalling; + LIBLTE_RRC_AC_BARRING_CONFIG_STRUCT ac_barring_for_mo_data; + LIBLTE_RRC_RR_CONFIG_COMMON_SIB_STRUCT rr_config_common_sib; + LIBLTE_RRC_UE_TIMERS_AND_CONSTANTS_STRUCT ue_timers_and_constants; + LIBLTE_RRC_ARFCN_VALUE_EUTRA_STRUCT arfcn_value_eutra; + LIBLTE_RRC_UL_BW_STRUCT ul_bw; + LIBLTE_RRC_MBSFN_SUBFRAME_CONFIG_STRUCT mbsfn_subfr_cnfg[LIBLTE_RRC_MAX_MBSFN_ALLOCATIONS]; + LIBLTE_RRC_TIME_ALIGNMENT_TIMER_ENUM time_alignment_timer; + uint32 mbsfn_subfr_cnfg_list_size; + uint8 additional_spectrum_emission; + bool ac_barring_for_emergency; + bool ac_barring_info_present; +}LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_sys_info_block_type_2_ie(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT *sib2, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_sys_info_block_type_2_ie(uint8 **ie_ptr, + LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT *sib2); + +/********************************************************************* + IE Name: System Information Block Type 3 + + Description: Contains cell reselection information common for + intra-frequency, inter-frequency, and/or inter-RAT + cell re-selection as well as intra-frequency cell + re-selection information other than neighboring + cell related + + Document Reference: 36.331 v10.0.0 Section 6.3.1 +*********************************************************************/ +// Defines +// Enums +typedef enum{ + LIBLTE_RRC_Q_HYST_DB_0 = 0, + LIBLTE_RRC_Q_HYST_DB_1, + LIBLTE_RRC_Q_HYST_DB_2, + LIBLTE_RRC_Q_HYST_DB_3, + LIBLTE_RRC_Q_HYST_DB_4, + LIBLTE_RRC_Q_HYST_DB_5, + LIBLTE_RRC_Q_HYST_DB_6, + LIBLTE_RRC_Q_HYST_DB_8, + LIBLTE_RRC_Q_HYST_DB_10, + LIBLTE_RRC_Q_HYST_DB_12, + LIBLTE_RRC_Q_HYST_DB_14, + LIBLTE_RRC_Q_HYST_DB_16, + LIBLTE_RRC_Q_HYST_DB_18, + LIBLTE_RRC_Q_HYST_DB_20, + LIBLTE_RRC_Q_HYST_DB_22, + LIBLTE_RRC_Q_HYST_DB_24, + LIBLTE_RRC_Q_HYST_N_ITEMS, +}LIBLTE_RRC_Q_HYST_ENUM; +static const char liblte_rrc_q_hyst_text[LIBLTE_RRC_Q_HYST_N_ITEMS][20] = { "0", "1", "2", "3", + "4", "5", "6", "8", + "10", "12", "14", "16", + "18", "20", "22", "24"}; +static const uint8 liblte_rrc_q_hyst_num[LIBLTE_RRC_Q_HYST_N_ITEMS] = {0, 1, 2, 3, 4, 5, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24}; +typedef enum{ + LIBLTE_RRC_SF_MEDIUM_DB_N6 = 0, + LIBLTE_RRC_SF_MEDIUM_DB_N4, + LIBLTE_RRC_SF_MEDIUM_DB_N2, + LIBLTE_RRC_SF_MEDIUM_DB_0, + LIBLTE_RRC_SF_MEDIUM_N_ITEMS, +}LIBLTE_RRC_SF_MEDIUM_ENUM; +static const char liblte_rrc_sf_medium_text[LIBLTE_RRC_SF_MEDIUM_N_ITEMS][20] = {"-6", "-4", "-2", "0"}; +static const int8 liblte_rrc_sf_medium_num[LIBLTE_RRC_SF_MEDIUM_N_ITEMS] = {-6, -4, -2, 0}; +typedef enum{ + LIBLTE_RRC_SF_HIGH_DB_N6 = 0, + LIBLTE_RRC_SF_HIGH_DB_N4, + LIBLTE_RRC_SF_HIGH_DB_N2, + LIBLTE_RRC_SF_HIGH_DB_0, + LIBLTE_RRC_SF_HIGH_N_ITEMS, +}LIBLTE_RRC_SF_HIGH_ENUM; +static const char liblte_rrc_sf_high_text[LIBLTE_RRC_SF_HIGH_N_ITEMS][20] = {"-6", "-4", "-2", "0"}; +static const int8 liblte_rrc_sf_high_num[LIBLTE_RRC_SF_HIGH_N_ITEMS] = {-6, -4, -2, 0}; +// Structs +typedef struct{ + LIBLTE_RRC_SF_MEDIUM_ENUM medium; + LIBLTE_RRC_SF_HIGH_ENUM high; +}LIBLTE_RRC_Q_HYST_SF_STRUCT; +typedef struct{ + LIBLTE_RRC_MOBILITY_STATE_PARAMETERS_STRUCT mobility_state_params; + LIBLTE_RRC_Q_HYST_SF_STRUCT q_hyst_sf; + bool present; +}LIBLTE_RRC_SPEED_STATE_RESELECTION_PARS_STRUCT; +typedef struct{ + LIBLTE_RRC_SPEED_STATE_RESELECTION_PARS_STRUCT speed_state_resel_params; + LIBLTE_RRC_SPEED_STATE_SCALE_FACTORS_STRUCT t_resel_eutra_sf; + LIBLTE_RRC_Q_HYST_ENUM q_hyst; + LIBLTE_RRC_ALLOWED_MEAS_BANDWIDTH_ENUM allowed_meas_bw; + int16 q_rx_lev_min; + uint8 s_non_intra_search; + uint8 thresh_serving_low; + uint8 cell_resel_prio; + uint8 s_intra_search; + uint8 neigh_cell_cnfg; + uint8 t_resel_eutra; + int8 p_max; + bool s_non_intra_search_present; + bool presence_ant_port_1; + bool p_max_present; + bool s_intra_search_present; + bool allowed_meas_bw_present; + bool t_resel_eutra_sf_present; +}LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_3_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_sys_info_block_type_3_ie(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_3_STRUCT *sib3, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_sys_info_block_type_3_ie(uint8 **ie_ptr, + LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_3_STRUCT *sib3); + +/********************************************************************* + IE Name: System Information Block Type 4 + + Description: Contains the neighboring cell related information + relevant only for intra-frequency cell reselection + + Document Reference: 36.331 v10.0.0 Section 6.3.1 +*********************************************************************/ +// Defines +#define LIBLTE_RRC_MAX_CELL_INTRA 16 +#define LIBLTE_RRC_MAX_CELL_BLACK 16 +// Enums +// Structs +typedef struct{ + LIBLTE_RRC_Q_OFFSET_RANGE_ENUM q_offset_range; + uint16 phys_cell_id; +}LIBLTE_RRC_INTRA_FREQ_NEIGH_CELL_INFO_STRUCT; +typedef struct{ + LIBLTE_RRC_INTRA_FREQ_NEIGH_CELL_INFO_STRUCT intra_freq_neigh_cell_list[LIBLTE_RRC_MAX_CELL_INTRA]; + LIBLTE_RRC_PHYS_CELL_ID_RANGE_STRUCT intra_freq_black_cell_list[LIBLTE_RRC_MAX_CELL_BLACK]; + LIBLTE_RRC_PHYS_CELL_ID_RANGE_STRUCT csg_phys_cell_id_range; + uint32 intra_freq_neigh_cell_list_size; + uint32 intra_freq_black_cell_list_size; + bool csg_phys_cell_id_range_present; +}LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_4_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_sys_info_block_type_4_ie(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_4_STRUCT *sib4, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_sys_info_block_type_4_ie(uint8 **ie_ptr, + LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_4_STRUCT *sib4); + +/********************************************************************* + IE Name: System Information Block Type 5 + + Description: Contains information relevant only for + inter-frequency cell reselection, i.e. information + about other E-UTRA frequencies and inter-frequency + neighboring cells relevant for cell reselection + + Document Reference: 36.331 v10.0.0 Section 6.3.1 +*********************************************************************/ +// Defines +#define LIBLTE_RRC_MAX_FREQ 8 +#define LIBLTE_RRC_MAX_CELL_INTER 16 +// Enums +// Structs +typedef struct{ + LIBLTE_RRC_Q_OFFSET_RANGE_ENUM q_offset_cell; + uint16 phys_cell_id; +}LIBLTE_RRC_INTER_FREQ_NEIGH_CELL_STRUCT; +typedef struct{ + LIBLTE_RRC_SPEED_STATE_SCALE_FACTORS_STRUCT t_resel_eutra_sf; + LIBLTE_RRC_INTER_FREQ_NEIGH_CELL_STRUCT inter_freq_neigh_cell_list[LIBLTE_RRC_MAX_CELL_INTER]; + LIBLTE_RRC_PHYS_CELL_ID_RANGE_STRUCT inter_freq_black_cell_list[LIBLTE_RRC_MAX_CELL_BLACK]; + LIBLTE_RRC_ALLOWED_MEAS_BANDWIDTH_ENUM allowed_meas_bw; + LIBLTE_RRC_Q_OFFSET_RANGE_ENUM q_offset_freq; + uint16 dl_carrier_freq; + int16 q_rx_lev_min; + uint8 t_resel_eutra; + uint8 threshx_high; + uint8 threshx_low; + uint8 cell_resel_prio; + uint8 neigh_cell_cnfg; + uint8 inter_freq_neigh_cell_list_size; + uint8 inter_freq_black_cell_list_size; + int8 p_max; + bool presence_ant_port_1; + bool p_max_present; + bool t_resel_eutra_sf_present; + bool cell_resel_prio_present; +}LIBLTE_RRC_INTER_FREQ_CARRIER_FREQ_INFO_STRUCT; +typedef struct{ + LIBLTE_RRC_INTER_FREQ_CARRIER_FREQ_INFO_STRUCT inter_freq_carrier_freq_list[LIBLTE_RRC_MAX_FREQ]; + uint32 inter_freq_carrier_freq_list_size; +}LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_5_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_sys_info_block_type_5_ie(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_5_STRUCT *sib5, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_sys_info_block_type_5_ie(uint8 **ie_ptr, + LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_5_STRUCT *sib5); + +/********************************************************************* + IE Name: System Information Block Type 6 + + Description: Contains information relevant only for inter-RAT + cell reselection, i.e. information about UTRA + frequencies and UTRA neighboring cells relevant for + cell reselection + + Document Reference: 36.331 v10.0.0 Section 6.3.1 +*********************************************************************/ +// Defines +#define LIBLTE_RRC_MAX_UTRA_FDD_CARRIER 16 +#define LIBLTE_RRC_MAX_UTRA_TDD_CARRIER 16 +// Enums +// Structs +typedef struct{ + uint16 carrier_freq; + uint8 cell_resel_prio; + uint8 threshx_high; + uint8 threshx_low; + int8 q_rx_lev_min; + int8 p_max_utra; + int8 q_qual_min; + bool cell_resel_prio_present; +}LIBLTE_RRC_CARRIER_FREQ_UTRA_FDD_STRUCT; +typedef struct{ + uint16 carrier_freq; + uint8 cell_resel_prio; + uint8 threshx_high; + uint8 threshx_low; + int8 q_rx_lev_min; + int8 p_max_utra; + bool cell_resel_prio_present; +}LIBLTE_RRC_CARRIER_FREQ_UTRA_TDD_STRUCT; +typedef struct{ + LIBLTE_RRC_CARRIER_FREQ_UTRA_FDD_STRUCT carrier_freq_list_utra_fdd[LIBLTE_RRC_MAX_UTRA_FDD_CARRIER]; + LIBLTE_RRC_CARRIER_FREQ_UTRA_TDD_STRUCT carrier_freq_list_utra_tdd[LIBLTE_RRC_MAX_UTRA_TDD_CARRIER]; + LIBLTE_RRC_SPEED_STATE_SCALE_FACTORS_STRUCT t_resel_utra_sf; + uint8 t_resel_utra; + uint8 carrier_freq_list_utra_fdd_size; + uint8 carrier_freq_list_utra_tdd_size; + bool t_resel_utra_sf_present; +}LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_6_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_sys_info_block_type_6_ie(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_6_STRUCT *sib6, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_sys_info_block_type_6_ie(uint8 **ie_ptr, + LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_6_STRUCT *sib6); + +/********************************************************************* + IE Name: System Information Block Type 7 + + Description: Contains information relevant only for inter-RAT + cell reselection, i.e. information about GERAN + frequencies relevant for cell reselection + + Document Reference: 36.331 v10.0.0 Section 6.3.1 +*********************************************************************/ +// Defines +#define LIBLTE_RRC_MAX_GNFG 16 +// Enums +// Structs +typedef struct{ + LIBLTE_RRC_CARRIER_FREQS_GERAN_STRUCT carrier_freqs; + uint8 cell_resel_prio; + uint8 ncc_permitted; + uint8 p_max_geran; + uint8 threshx_high; + uint8 threshx_low; + int8 q_rx_lev_min; + bool cell_resel_prio_present; + bool p_max_geran_present; +}LIBLTE_RRC_CARRIER_FREQS_INFO_LIST_GERAN_STRUCT; +typedef struct{ + LIBLTE_RRC_SPEED_STATE_SCALE_FACTORS_STRUCT t_resel_geran_sf; + LIBLTE_RRC_CARRIER_FREQS_INFO_LIST_GERAN_STRUCT carrier_freqs_info_list[LIBLTE_RRC_MAX_GNFG]; + uint8 t_resel_geran; + uint8 carrier_freqs_info_list_size; + bool t_resel_geran_sf_present; +}LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_7_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_sys_info_block_type_7_ie(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_7_STRUCT *sib7, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_sys_info_block_type_7_ie(uint8 **ie_ptr, + LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_7_STRUCT *sib7); + +/********************************************************************* + IE Name: System Information Block Type 8 + + Description: Contains information relevant only for inter-RAT + cell re-selection i.e. information about CDMA2000 + frequencies and CDMA2000 neighboring cells relevant + for cell re-selection + + Document Reference: 36.331 v10.0.0 Section 6.3.1 +*********************************************************************/ +// Defines +#define LIBLTE_RRC_MAX_CDMA_BAND_CLASS 32 +// Enums +// Structs +typedef struct{ + LIBLTE_RRC_BAND_CLASS_CDMA2000_ENUM band_class; + uint8 cell_resel_prio; + uint8 thresh_x_high; + uint8 thresh_x_low; + bool cell_resel_prio_present; +}LIBLTE_RRC_BAND_CLASS_INFO_CDMA2000_STRUCT; +typedef struct{ + uint16 arfcn; + uint16 phys_cell_id_list[16]; + uint8 phys_cell_id_list_size; +}LIBLTE_RRC_NEIGH_CELLS_PER_BAND_CLASS_CDMA2000_STRUCT; +typedef struct{ + LIBLTE_RRC_BAND_CLASS_CDMA2000_ENUM band_class; + LIBLTE_RRC_NEIGH_CELLS_PER_BAND_CLASS_CDMA2000_STRUCT neigh_cells_per_freq_list[16]; + uint8 neigh_cells_per_freq_list_size; +}LIBLTE_RRC_NEIGH_CELL_CDMA2000_STRUCT; +typedef struct{ + LIBLTE_RRC_BAND_CLASS_INFO_CDMA2000_STRUCT band_class_list[LIBLTE_RRC_MAX_CDMA_BAND_CLASS]; + LIBLTE_RRC_NEIGH_CELL_CDMA2000_STRUCT neigh_cell_list[16]; + LIBLTE_RRC_SPEED_STATE_SCALE_FACTORS_STRUCT t_resel_cdma2000_sf; + uint8 band_class_list_size; + uint8 neigh_cell_list_size; + uint8 t_resel_cdma2000; + bool t_resel_cdma2000_sf_present; +}LIBLTE_RRC_CELL_RESELECTION_PARAMS_CDMA2000_STRUCT; +typedef struct{ + LIBLTE_RRC_SYSTEM_TIME_INFO_CDMA2000_STRUCT sys_time_info_cdma2000; + LIBLTE_RRC_PRE_REGISTRATION_INFO_HRPD_STRUCT pre_reg_info_hrpd; + LIBLTE_RRC_CELL_RESELECTION_PARAMS_CDMA2000_STRUCT cell_resel_params_hrpd; + LIBLTE_RRC_CSFB_REGISTRATION_PARAM_1XRTT_STRUCT csfb_reg_param_1xrtt; + LIBLTE_RRC_CELL_RESELECTION_PARAMS_CDMA2000_STRUCT cell_resel_params_1xrtt; + uint64 long_code_state_1xrtt; + uint8 search_win_size; + bool sys_time_info_present; + bool search_win_size_present; + bool params_hrpd_present; + bool cell_resel_params_hrpd_present; + bool params_1xrtt_present; + bool csfb_reg_param_1xrtt_present; + bool long_code_state_1xrtt_present; + bool cell_resel_params_1xrtt_present; +}LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_8_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_sys_info_block_type_8_ie(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_8_STRUCT *sib8, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_sys_info_block_type_8_ie(uint8 **ie_ptr, + LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_8_STRUCT *sib8); + +/********************************************************************* + IE Name: System Information Block Type 9 + + Description: Contains a home eNB name (HNB name) + + Document Reference: 36.331 v10.0.0 Section 6.3.1 +*********************************************************************/ +// Defines +// Enums +// Structs +// lb:1, ub:48 +typedef struct{ + uint32 hnb_name_size; + uint8 hnb_name[48]; + bool hnb_name_present; +}LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_9_STRUCT; + +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_sys_info_block_type_9_ie(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_9_STRUCT *sib9, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_sys_info_block_type_9_ie(uint8 **ie_ptr, + LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_9_STRUCT *sib9); + +/********************************************************************* + IE Name: System Information Block Type 10 + + Description: Contains an ETWS primary notification + + Document Reference: 36.331 v10.0.0 Section 6.3.1 +*********************************************************************/ +// Defines +// Enums +// Structs +// Functions +// FIXME + +/********************************************************************* + IE Name: System Information Block Type 11 + + Description: Contains an ETWS secondary notification + + Document Reference: 36.331 v10.0.0 Section 6.3.1 +*********************************************************************/ +// Defines +// Enums +// Structs +// Functions +// FIXME + +/********************************************************************* + IE Name: System Information Block Type 12 + + Description: Contains a CMAS notification + + Document Reference: 36.331 v10.0.0 Section 6.3.1 +*********************************************************************/ +// Defines +// Enums +// Structs +// Functions +// FIXME + +/********************************************************************* + IE Name: System Information Block Type 13 + + Description: Contains the information required to acquire the + MBMS control information associated with one or more + MBSFN areas + + Document Reference: 36.331 v10.0.0 Section 6.3.1 +*********************************************************************/ +// Defines +// Enums +// Structs +typedef struct{ + LIBLTE_RRC_MBSFN_AREA_INFO_STRUCT mbsfn_area_info_list_r9[LIBLTE_RRC_MAX_MBSFN_AREAS]; + LIBLTE_RRC_MBSFN_NOTIFICATION_CONFIG_STRUCT mbms_notification_config; + uint8 mbsfn_area_info_list_r9_size; +}LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_13_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_sys_info_block_type_13_ie(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_13_STRUCT *sib13, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_sys_info_block_type_13_ie(uint8 **ie_ptr, + LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_13_STRUCT *sib13); + +/******************************************************************************* + MESSAGE DECLARATIONS +*******************************************************************************/ + +/********************************************************************* + Message Name: UL Information Transfer + + Description: Used for the uplink transfer dedicated NAS + information + + Document Reference: 36.331 v10.0.0 Section 6.2.2 +*********************************************************************/ +// Defines +// Enums +typedef enum{ + LIBLTE_RRC_UL_INFORMATION_TRANSFER_TYPE_NAS = 0, + LIBLTE_RRC_UL_INFORMATION_TRANSFER_TYPE_CDMA2000_1XRTT, + LIBLTE_RRC_UL_INFORMATION_TRANSFER_TYPE_CDMA2000_HRPD, + LIBLTE_RRC_UL_INFORMATION_TRANSFER_TYPE_N_ITEMS, +}LIBLTE_RRC_UL_INFORMATION_TRANSFER_TYPE_ENUM; +static const char liblte_rrc_ul_information_transfer_type_text[LIBLTE_RRC_UL_INFORMATION_TRANSFER_TYPE_N_ITEMS][20] = {"NAS", + "CDMA2000-1XRTT", + "CDMA2000-HRPD"}; +// Structs +typedef struct{ + LIBLTE_SIMPLE_BYTE_MSG_STRUCT dedicated_info; + LIBLTE_RRC_UL_INFORMATION_TRANSFER_TYPE_ENUM dedicated_info_type; +}LIBLTE_RRC_UL_INFORMATION_TRANSFER_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_ul_information_transfer_msg(LIBLTE_RRC_UL_INFORMATION_TRANSFER_STRUCT *ul_info_transfer, + LIBLTE_BIT_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_ul_information_transfer_msg(LIBLTE_BIT_MSG_STRUCT *msg, + LIBLTE_RRC_UL_INFORMATION_TRANSFER_STRUCT *ul_info_transfer); + +/********************************************************************* + Message Name: UL Handover Preparation Transfer (CDMA2000) + + Description: Used for the uplink transfer of handover related + CDMA2000 information when requested by the higher + layers + + Document Reference: 36.331 v10.0.0 Section 6.2.2 +*********************************************************************/ +// Defines +// Enums +// Structs +typedef struct{ + // FIXME +}LIBLTE_RRC_UL_HANDOVER_PREPARATION_TRANSFER_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_ul_handover_preparation_transfer_msg(LIBLTE_RRC_UL_HANDOVER_PREPARATION_TRANSFER_STRUCT *ul_handover_prep_transfer, + LIBLTE_BIT_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_ul_handover_preparation_transfer_msg(LIBLTE_BIT_MSG_STRUCT *msg, + LIBLTE_RRC_UL_HANDOVER_PREPARATION_TRANSFER_STRUCT *ul_handover_prep_transfer); + +/********************************************************************* + Message Name: UE Information Response + + Description: Used by the UE to transfer the information requested + by the E-UTRAN + + Document Reference: 36.331 v10.0.0 Section 6.2.2 +*********************************************************************/ +// Defines +// Enums +// Structs +typedef struct{ + // FIXME +}LIBLTE_RRC_UE_INFORMATION_RESPONSE_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_ue_information_response_msg(LIBLTE_RRC_UE_INFORMATION_RESPONSE_STRUCT *ue_info_resp, + LIBLTE_BIT_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_ue_information_response_msg(LIBLTE_BIT_MSG_STRUCT *msg, + LIBLTE_RRC_UE_INFORMATION_RESPONSE_STRUCT *ue_info_resp); + +/********************************************************************* + Message Name: UE Information Request + + Description: Used by E-UTRAN to retrieve information from the UE + + Document Reference: 36.331 v10.0.0 Section 6.2.2 +*********************************************************************/ +// Defines +// Enums +// Structs +typedef struct{ + uint8 rrc_transaction_id; + bool rach_report_req; + bool rlf_report_req; +}LIBLTE_RRC_UE_INFORMATION_REQUEST_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_ue_information_request_msg(LIBLTE_RRC_UE_INFORMATION_REQUEST_STRUCT *ue_info_req, + LIBLTE_BIT_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_ue_information_request_msg(LIBLTE_BIT_MSG_STRUCT *msg, + LIBLTE_RRC_UE_INFORMATION_REQUEST_STRUCT *ue_info_req); + +/********************************************************************* + Message Name: UE Capability Information + + Description: Used to transfer UE radio access capabilities + requested by the E-UTRAN + + Document Reference: 36.331 v10.0.0 Section 6.2.2 +*********************************************************************/ +// Defines +#define LIBLTE_RRC_MAX_RAT_CAPABILITIES 8 +// Enums +// Structs +typedef struct{ + LIBLTE_RRC_RAT_TYPE_ENUM rat_type; + LIBLTE_RRC_UE_EUTRA_CAPABILITY_STRUCT eutra_capability; +}LIBLTE_RRC_UE_CAPABILITY_RAT_CONTAINER_STRUCT; + +typedef struct{ + uint8 rrc_transaction_id; + LIBLTE_RRC_UE_CAPABILITY_RAT_CONTAINER_STRUCT ue_capability_rat[LIBLTE_RRC_MAX_RAT_CAPABILITIES]; + uint32 N_ue_caps; +}LIBLTE_RRC_UE_CAPABILITY_INFORMATION_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_ue_capability_information_msg(LIBLTE_RRC_UE_CAPABILITY_INFORMATION_STRUCT *ue_capability_info, + LIBLTE_BIT_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_ue_capability_information_msg(LIBLTE_BIT_MSG_STRUCT *msg, + LIBLTE_RRC_UE_CAPABILITY_INFORMATION_STRUCT *ue_capability_info); + +/********************************************************************* + Message Name: UE Capability Enquiry + + Description: Used to request the transfer of UE radio access + capabilities for E-UTRA as well as for other RATs + + Document Reference: 36.331 v10.0.0 Section 6.2.2 +*********************************************************************/ +// Defines +// Enums +// Structs +typedef struct{ + uint8 rrc_transaction_id; + LIBLTE_RRC_RAT_TYPE_ENUM ue_capability_request[LIBLTE_RRC_MAX_RAT_CAPABILITIES]; + uint32 N_ue_cap_reqs; + +}LIBLTE_RRC_UE_CAPABILITY_ENQUIRY_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_ue_capability_enquiry_msg(LIBLTE_RRC_UE_CAPABILITY_ENQUIRY_STRUCT *ue_cap_enquiry, + LIBLTE_BIT_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_ue_capability_enquiry_msg(LIBLTE_BIT_MSG_STRUCT *msg, + LIBLTE_RRC_UE_CAPABILITY_ENQUIRY_STRUCT *ue_cap_enquiry); + +/********************************************************************* + Message Name: System Information Block Type 1 + + Description: Contains information relevant when evaluating if a + UE is allowed to access a cell and defines the + scheduling of other system information + + Document Reference: 36.331 v10.0.0 Section 6.2.2 +*********************************************************************/ +// Defines +#define LIBLTE_RRC_MAX_N_PLMN_IDENTITIES 6 +#define LIBLTE_RRC_MAX_SIB 32 +#define LIBLTE_RRC_MAX_SI_MESSAGE 32 +// Enums +typedef enum{ + LIBLTE_RRC_CELL_BARRED = 0, + LIBLTE_RRC_CELL_NOT_BARRED, + LIBLTE_RRC_CELL_BARRED_N_ITEMS, +}LIBLTE_RRC_CELL_BARRED_ENUM; +static const char liblte_rrc_cell_barred_text[LIBLTE_RRC_CELL_BARRED_N_ITEMS][20] = {"Barred", "Not Barred"}; +typedef enum{ + LIBLTE_RRC_INTRA_FREQ_RESELECTION_ALLOWED = 0, + LIBLTE_RRC_INTRA_FREQ_RESELECTION_NOT_ALLOWED, + LIBLTE_RRC_INTRA_FREQ_RESELECTION_N_ITEMS, +}LIBLTE_RRC_INTRA_FREQ_RESELECTION_ENUM; +static const char liblte_rrc_intra_freq_reselection_text[LIBLTE_RRC_INTRA_FREQ_RESELECTION_N_ITEMS][20] = {"Allowed", "Not Allowed"}; +typedef enum{ + LIBLTE_RRC_SI_WINDOW_LENGTH_MS1 = 0, + LIBLTE_RRC_SI_WINDOW_LENGTH_MS2, + LIBLTE_RRC_SI_WINDOW_LENGTH_MS5, + LIBLTE_RRC_SI_WINDOW_LENGTH_MS10, + LIBLTE_RRC_SI_WINDOW_LENGTH_MS15, + LIBLTE_RRC_SI_WINDOW_LENGTH_MS20, + LIBLTE_RRC_SI_WINDOW_LENGTH_MS40, + LIBLTE_RRC_SI_WINDOW_LENGTH_N_ITEMS, +}LIBLTE_RRC_SI_WINDOW_LENGTH_ENUM; +static const char liblte_rrc_si_window_length_text[LIBLTE_RRC_SI_WINDOW_LENGTH_N_ITEMS][20] = { "1", "2", "5", "10", + "15", "20", "40"}; +static const uint8 liblte_rrc_si_window_length_num[LIBLTE_RRC_SI_WINDOW_LENGTH_N_ITEMS] = {1, 2, 5, 10, 15, 20, 40}; +typedef enum{ + LIBLTE_RRC_RESV_FOR_OPER = 0, + LIBLTE_RRC_NOT_RESV_FOR_OPER, + LIBLTE_RRC_RESV_FOR_OPER_N_ITEMS, +}LIBLTE_RRC_RESV_FOR_OPER_ENUM; +static const char liblte_rrc_resv_for_oper_text[LIBLTE_RRC_RESV_FOR_OPER_N_ITEMS][20] = {"Reserved", "Not Reserved"}; +typedef enum{ + LIBLTE_RRC_SI_PERIODICITY_RF8 = 0, + LIBLTE_RRC_SI_PERIODICITY_RF16, + LIBLTE_RRC_SI_PERIODICITY_RF32, + LIBLTE_RRC_SI_PERIODICITY_RF64, + LIBLTE_RRC_SI_PERIODICITY_RF128, + LIBLTE_RRC_SI_PERIODICITY_RF256, + LIBLTE_RRC_SI_PERIODICITY_RF512, + LIBLTE_RRC_SI_PERIODICITY_N_ITEMS, +}LIBLTE_RRC_SI_PERIODICITY_ENUM; +static const char liblte_rrc_si_periodicity_text[LIBLTE_RRC_SI_PERIODICITY_N_ITEMS][20] = { "8", "16", "32", "64", + "128", "256", "512"}; +static const uint16 liblte_rrc_si_periodicity_num[LIBLTE_RRC_SI_PERIODICITY_N_ITEMS] = {8, 16, 32, 64, 128, 256, 512}; +typedef enum{ + LIBLTE_RRC_SIB_TYPE_3 = 0, + LIBLTE_RRC_SIB_TYPE_4, + LIBLTE_RRC_SIB_TYPE_5, + LIBLTE_RRC_SIB_TYPE_6, + LIBLTE_RRC_SIB_TYPE_7, + LIBLTE_RRC_SIB_TYPE_8, + LIBLTE_RRC_SIB_TYPE_9, + LIBLTE_RRC_SIB_TYPE_10, + LIBLTE_RRC_SIB_TYPE_11, + LIBLTE_RRC_SIB_TYPE_12_v920, + LIBLTE_RRC_SIB_TYPE_13_v920, + LIBLTE_RRC_SIB_TYPE_SPARE_5, + LIBLTE_RRC_SIB_TYPE_SPARE_4, + LIBLTE_RRC_SIB_TYPE_SPARE_3, + LIBLTE_RRC_SIB_TYPE_SPARE_2, + LIBLTE_RRC_SIB_TYPE_SPARE_1, + LIBLTE_RRC_SIB_TYPE_N_ITEMS, +}LIBLTE_RRC_SIB_TYPE_ENUM; +static const char liblte_rrc_sib_type_text[LIBLTE_RRC_SIB_TYPE_N_ITEMS][20] = { "3", "4", "5", "6", + "7", "8", "9", "10", + "11", "12", "13", "SPARE", + "SPARE", "SPARE", "SPARE", "SPARE"}; +static const uint8 liblte_rrc_sib_type_num[LIBLTE_RRC_SIB_TYPE_N_ITEMS] = {3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 0, 0, 0, 0, 0}; +// Structs +typedef struct{ + LIBLTE_RRC_PLMN_IDENTITY_STRUCT id; + LIBLTE_RRC_RESV_FOR_OPER_ENUM resv_for_oper; +}LIBLTE_RRC_PLMN_IDENTITY_LIST_STRUCT; +typedef struct{ + LIBLTE_RRC_SIB_TYPE_ENUM sib_type; +}LIBLTE_RRC_SIB_MAPPING_INFO_STRUCT; +typedef struct{ + LIBLTE_RRC_SIB_MAPPING_INFO_STRUCT sib_mapping_info[LIBLTE_RRC_MAX_SIB]; + LIBLTE_RRC_SI_PERIODICITY_ENUM si_periodicity; + uint32 N_sib_mapping_info; +}LIBLTE_RRC_SCHEDULING_INFO_STRUCT; +typedef struct{ + LIBLTE_RRC_PLMN_IDENTITY_LIST_STRUCT plmn_id[LIBLTE_RRC_MAX_N_PLMN_IDENTITIES]; + LIBLTE_RRC_SCHEDULING_INFO_STRUCT sched_info[LIBLTE_RRC_MAX_SI_MESSAGE]; + LIBLTE_RRC_TDD_CONFIG_STRUCT tdd_cnfg; + LIBLTE_RRC_CELL_BARRED_ENUM cell_barred; + LIBLTE_RRC_INTRA_FREQ_RESELECTION_ENUM intra_freq_reselection; + LIBLTE_RRC_SI_WINDOW_LENGTH_ENUM si_window_length; + uint32 cell_id; + uint32 csg_id; + uint32 N_plmn_ids; + uint32 N_sched_info; + uint16 tracking_area_code; + int16 q_rx_lev_min; + uint8 csg_indication; + uint8 q_rx_lev_min_offset; + uint8 freq_band_indicator; + uint8 system_info_value_tag; + int8 p_max; + bool tdd; + bool p_max_present; +}LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_sys_info_block_type_1_msg(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1_STRUCT *sib1, + LIBLTE_BIT_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_sys_info_block_type_1_msg(LIBLTE_BIT_MSG_STRUCT *msg, + LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1_STRUCT *sib1, + uint32 *N_bits_used); + +/********************************************************************* + Message Name: System Information + + Description: Conveys one or more System Information Blocks + + Document Reference: 36.331 v10.0.0 Section 6.2.2 +*********************************************************************/ +// Defines +// Enums +typedef enum{ + LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2 = 0, + LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_3, + LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_4, + LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_5, + LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_6, + LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_7, + LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_8, + LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_9, + LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_10, + LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_11, + LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_12, + LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_13, + LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1, // Intentionally not first + LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_N_ITEMS, +}LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_ENUM; +static const char liblte_rrc_sys_info_block_type_text[LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_N_ITEMS][20] = { "2", "3", "4", "5", + "6", "7", "8", "9", + "10", "11", "12", "13", + "1"}; +static const uint8 liblte_rrc_sys_info_block_type_num[LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_N_ITEMS] = {2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 1}; +// Structs +typedef union{ + LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1_STRUCT sib1; + LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT sib2; + LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_3_STRUCT sib3; + LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_4_STRUCT sib4; + LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_5_STRUCT sib5; + LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_6_STRUCT sib6; + LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_7_STRUCT sib7; + LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_8_STRUCT sib8; + LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_9_STRUCT sib9; + LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_13_STRUCT sib13; +}LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_UNION; +typedef struct{ + LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_UNION sib; + LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_ENUM sib_type; +}LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_STRUCT; +typedef struct{ + LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_STRUCT sibs[LIBLTE_RRC_MAX_SIB]; + uint32 N_sibs; +}LIBLTE_RRC_SYS_INFO_MSG_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_sys_info_msg(LIBLTE_RRC_SYS_INFO_MSG_STRUCT *sibs, + LIBLTE_BIT_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_sys_info_msg(LIBLTE_BIT_MSG_STRUCT *msg, + LIBLTE_RRC_SYS_INFO_MSG_STRUCT *sibs); + +/********************************************************************* + Message Name: Security Mode Failure + + Description: Used to indicate an unsuccessful completion of a + security mode command + + Document Reference: 36.331 v10.0.0 Section 6.2.2 +*********************************************************************/ +// Defines +// Enums +// Structs +typedef struct{ + uint8 rrc_transaction_id; +}LIBLTE_RRC_SECURITY_MODE_FAILURE_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_security_mode_failure_msg(LIBLTE_RRC_SECURITY_MODE_FAILURE_STRUCT *security_mode_failure, + LIBLTE_BIT_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_security_mode_failure_msg(LIBLTE_BIT_MSG_STRUCT *msg, + LIBLTE_RRC_SECURITY_MODE_FAILURE_STRUCT *security_mode_failure); + +/********************************************************************* + Message Name: Security Mode Complete + + Description: Used to confirm the successful completion of a + security mode command + + Document Reference: 36.331 v10.0.0 Section 6.2.2 +*********************************************************************/ +// Defines +// Enums +// Structs +typedef struct{ + uint8 rrc_transaction_id; +}LIBLTE_RRC_SECURITY_MODE_COMPLETE_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_security_mode_complete_msg(LIBLTE_RRC_SECURITY_MODE_COMPLETE_STRUCT *security_mode_complete, + LIBLTE_BIT_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_security_mode_complete_msg(LIBLTE_BIT_MSG_STRUCT *msg, + LIBLTE_RRC_SECURITY_MODE_COMPLETE_STRUCT *security_mode_complete); + +/********************************************************************* + Message Name: Security Mode Command + + Description: Used to command the activation of AS security + + Document Reference: 36.331 v10.0.0 Section 6.2.2 +*********************************************************************/ +// Defines +// Enums +// Structs +typedef struct{ + LIBLTE_RRC_SECURITY_ALGORITHM_CONFIG_STRUCT sec_algs; + uint8 rrc_transaction_id; +}LIBLTE_RRC_SECURITY_MODE_COMMAND_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_security_mode_command_msg(LIBLTE_RRC_SECURITY_MODE_COMMAND_STRUCT *security_mode_cmd, + LIBLTE_BIT_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_security_mode_command_msg(LIBLTE_BIT_MSG_STRUCT *msg, + LIBLTE_RRC_SECURITY_MODE_COMMAND_STRUCT *security_mode_cmd); + +/********************************************************************* + Message Name: RRC Connection Setup Complete + + Description: Used to confirm the successful completion of an RRC + connection + + Document Reference: 36.331 v10.0.0 Section 6.2.2 +*********************************************************************/ +// Defines +// Enums +// Structs +typedef struct{ + LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id; + uint16 mmegi; + uint8 mmec; + bool plmn_id_present; +}LIBLTE_RRC_REGISTERED_MME_STRUCT; +typedef struct{ + LIBLTE_RRC_REGISTERED_MME_STRUCT registered_mme; + LIBLTE_SIMPLE_BYTE_MSG_STRUCT dedicated_info_nas; + uint8 rrc_transaction_id; + uint8 selected_plmn_id; + bool registered_mme_present; +}LIBLTE_RRC_CONNECTION_SETUP_COMPLETE_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_rrc_connection_setup_complete_msg(LIBLTE_RRC_CONNECTION_SETUP_COMPLETE_STRUCT *con_setup_complete, + LIBLTE_BIT_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_rrc_connection_setup_complete_msg(LIBLTE_BIT_MSG_STRUCT *msg, + LIBLTE_RRC_CONNECTION_SETUP_COMPLETE_STRUCT *con_setup_complete); + +/********************************************************************* + Message Name: RRC Connection Setup + + Description: Used to establish SRB1 + + Document Reference: 36.331 v10.0.0 Section 6.2.2 +*********************************************************************/ +// Defines +// Enums +// Structs +typedef struct{ + LIBLTE_RRC_RR_CONFIG_DEDICATED_STRUCT rr_cnfg; + uint8 rrc_transaction_id; +}LIBLTE_RRC_CONNECTION_SETUP_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_rrc_connection_setup_msg(LIBLTE_RRC_CONNECTION_SETUP_STRUCT *con_setup, + LIBLTE_BIT_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_rrc_connection_setup_msg(LIBLTE_BIT_MSG_STRUCT *msg, + LIBLTE_RRC_CONNECTION_SETUP_STRUCT *con_setup); + +/********************************************************************* + Message Name: RRC Connection Request + + Description: Used to request the establishment of an RRC + connection + + Document Reference: 36.331 v10.0.0 Section 6.2.2 +*********************************************************************/ +// Defines +// Enums +typedef enum{ + LIBLTE_RRC_CON_REQ_UE_ID_TYPE_S_TMSI = 0, + LIBLTE_RRC_CON_REQ_UE_ID_TYPE_RANDOM_VALUE, + LIBLTE_RRC_CON_REQ_UE_ID_TYPE_N_ITEMS, +}LIBLTE_RRC_CON_REQ_UE_ID_TYPE_ENUM; +static const char liblte_rrc_con_req_ue_id_type_text[LIBLTE_RRC_CON_REQ_UE_ID_TYPE_N_ITEMS][20] = {"S-TMSI", + "Random Value"}; +typedef enum{ + LIBLTE_RRC_CON_REQ_EST_CAUSE_EMERGENCY = 0, + LIBLTE_RRC_CON_REQ_EST_CAUSE_HIGH_PRIO_ACCESS, + LIBLTE_RRC_CON_REQ_EST_CAUSE_MT_ACCESS, + LIBLTE_RRC_CON_REQ_EST_CAUSE_MO_SIGNALLING, + LIBLTE_RRC_CON_REQ_EST_CAUSE_MO_DATA, + LIBLTE_RRC_CON_REQ_EST_CAUSE_SPARE3, + LIBLTE_RRC_CON_REQ_EST_CAUSE_SPARE2, + LIBLTE_RRC_CON_REQ_EST_CAUSE_SPARE1, + LIBLTE_RRC_CON_REQ_EST_CAUSE_N_ITEMS, +}LIBLTE_RRC_CON_REQ_EST_CAUSE_ENUM; +static const char liblte_rrc_con_req_est_cause_text[LIBLTE_RRC_CON_REQ_EST_CAUSE_N_ITEMS][100] = {"Emergency", + "High Priority Access", + "MT Access", + "MO Signalling", + "MO Data", + "SPARE", + "SPARE", + "SPARE"}; +// Structs +typedef union{ + LIBLTE_RRC_S_TMSI_STRUCT s_tmsi; + uint64 random; +}LIBLTE_RRC_CON_REQ_UE_ID_UNION; +typedef struct{ + LIBLTE_RRC_CON_REQ_UE_ID_UNION ue_id; + LIBLTE_RRC_CON_REQ_UE_ID_TYPE_ENUM ue_id_type; + LIBLTE_RRC_CON_REQ_EST_CAUSE_ENUM cause; +}LIBLTE_RRC_CONNECTION_REQUEST_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_rrc_connection_request_msg(LIBLTE_RRC_CONNECTION_REQUEST_STRUCT *con_req, + LIBLTE_BIT_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_rrc_connection_request_msg(LIBLTE_BIT_MSG_STRUCT *msg, + LIBLTE_RRC_CONNECTION_REQUEST_STRUCT *con_req); + +/********************************************************************* + Message Name: RRC Connection Release + + Description: Used to command the release of an RRC connection + + Document Reference: 36.331 v10.0.0 Section 6.2.2 +*********************************************************************/ +// Defines +// Enums +typedef enum{ + LIBLTE_RRC_RELEASE_CAUSE_LOAD_BALANCING_TAU_REQUIRED = 0, + LIBLTE_RRC_RELEASE_CAUSE_OTHER, + LIBLTE_RRC_RELEASE_CAUSE_CS_FALLBACK_HIGH_PRIORITY, + LIBLTE_RRC_RELEASE_CAUSE_SPARE1, + LIBLTE_RRC_RELEASE_CAUSE_N_ITEMS, +}LIBLTE_RRC_RELEASE_CAUSE_ENUM; +static const char liblte_rrc_release_cause_text[LIBLTE_RRC_RELEASE_CAUSE_N_ITEMS][100] = {"Load Balancing TAU Required", + "Other", + "CS Fallback High Priority", + "SPARE"}; +// Structs +typedef struct{ + LIBLTE_RRC_RELEASE_CAUSE_ENUM release_cause; + uint8 rrc_transaction_id; +}LIBLTE_RRC_CONNECTION_RELEASE_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_rrc_connection_release_msg(LIBLTE_RRC_CONNECTION_RELEASE_STRUCT *con_release, + LIBLTE_BIT_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_rrc_connection_release_msg(LIBLTE_BIT_MSG_STRUCT *msg, + LIBLTE_RRC_CONNECTION_RELEASE_STRUCT *con_release); + +/********************************************************************* + Message Name: RRC Connection Reject + + Description: Used to reject the RRC connection establishment + + Document Reference: 36.331 v10.0.0 Section 6.2.2 +*********************************************************************/ +// Defines +// Enums +// Structs +typedef struct{ + uint8 wait_time; +}LIBLTE_RRC_CONNECTION_REJECT_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_rrc_connection_reject_msg(LIBLTE_RRC_CONNECTION_REJECT_STRUCT *con_rej, + LIBLTE_BIT_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_rrc_connection_reject_msg(LIBLTE_BIT_MSG_STRUCT *msg, + LIBLTE_RRC_CONNECTION_REJECT_STRUCT *con_rej); + +/********************************************************************* + Message Name: RRC Connection Reestablishment Request + + Description: Used to request the reestablishment of an RRC + connection + + Document Reference: 36.331 v10.0.0 Section 6.2.2 +*********************************************************************/ +// Defines +// Enums +typedef enum{ + LIBLTE_RRC_CON_REEST_REQ_CAUSE_RECONFIG_FAILURE = 0, + LIBLTE_RRC_CON_REEST_REQ_CAUSE_HANDOVER_FAILURE, + LIBLTE_RRC_CON_REEST_REQ_CAUSE_OTHER_FAILURE, + LIBLTE_RRC_CON_REEST_REQ_CAUSE_SPARE1, + LIBLTE_RRC_CON_REEST_REQ_CAUSE_N_ITEMS, +}LIBLTE_RRC_CON_REEST_REQ_CAUSE_ENUM; +static const char liblte_rrc_con_reest_req_cause_text[LIBLTE_RRC_CON_REEST_REQ_CAUSE_N_ITEMS][100] = {"Reconfiguration Failure", + "Handover Failure", + "Other Failure", + "SPARE"}; +// Structs +typedef struct{ + uint16 c_rnti; + uint16 phys_cell_id; + uint16 short_mac_i; +}LIBLTE_RRC_CON_REEST_REQ_UE_ID_STRUCT; +typedef struct{ + LIBLTE_RRC_CON_REEST_REQ_UE_ID_STRUCT ue_id; + LIBLTE_RRC_CON_REEST_REQ_CAUSE_ENUM cause; +}LIBLTE_RRC_CONNECTION_REESTABLISHMENT_REQUEST_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_rrc_connection_reestablishment_request_msg(LIBLTE_RRC_CONNECTION_REESTABLISHMENT_REQUEST_STRUCT *con_reest_req, + LIBLTE_BIT_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_rrc_connection_reestablishment_request_msg(LIBLTE_BIT_MSG_STRUCT *msg, + LIBLTE_RRC_CONNECTION_REESTABLISHMENT_REQUEST_STRUCT *con_reest_req); + +/********************************************************************* + Message Name: RRC Connection Reestablishment Reject + + Description: Used to indicate the rejection of an RRC connection + reestablishment request + + Document Reference: 36.331 v10.0.0 Section 6.2.2 +*********************************************************************/ +// Defines +// Enums +// Structs +typedef struct{ +}LIBLTE_RRC_CONNECTION_REESTABLISHMENT_REJECT_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_rrc_connection_reestablishment_reject_msg(LIBLTE_RRC_CONNECTION_REESTABLISHMENT_REJECT_STRUCT *con_reest_rej, + LIBLTE_BIT_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_rrc_connection_reestablishment_reject_msg(LIBLTE_BIT_MSG_STRUCT *msg, + LIBLTE_RRC_CONNECTION_REESTABLISHMENT_REJECT_STRUCT *con_reest_rej); + +/********************************************************************* + Message Name: RRC Connection Reestablishment Complete + + Description: Used to confirm the successful completion of an RRC + connection reestablishment + + Document Reference: 36.331 v10.0.0 Section 6.2.2 +*********************************************************************/ +// Defines +// Enums +// Structs +typedef struct{ + uint8 rrc_transaction_id; +}LIBLTE_RRC_CONNECTION_REESTABLISHMENT_COMPLETE_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_rrc_connection_reestablishment_complete_msg(LIBLTE_RRC_CONNECTION_REESTABLISHMENT_COMPLETE_STRUCT *con_reest_complete, + LIBLTE_BIT_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_rrc_connection_reestablishment_complete_msg(LIBLTE_BIT_MSG_STRUCT *msg, + LIBLTE_RRC_CONNECTION_REESTABLISHMENT_COMPLETE_STRUCT *con_reest_complete); + +/********************************************************************* + Message Name: RRC Connection Reestablishment + + Description: Used to resolve contention and to re-establish SRB1 + + Document Reference: 36.331 v10.0.0 Section 6.2.2 +*********************************************************************/ +// Defines +// Enums +// Structs +typedef struct{ + LIBLTE_RRC_RR_CONFIG_DEDICATED_STRUCT rr_cnfg; + uint8 rrc_transaction_id; + uint8 next_hop_chaining_count; +}LIBLTE_RRC_CONNECTION_REESTABLISHMENT_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_rrc_connection_reestablishment_msg(LIBLTE_RRC_CONNECTION_REESTABLISHMENT_STRUCT *con_reest, + LIBLTE_BIT_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_rrc_connection_reestablishment_msg(LIBLTE_BIT_MSG_STRUCT *msg, + LIBLTE_RRC_CONNECTION_REESTABLISHMENT_STRUCT *con_reest); + +/********************************************************************* + Message Name: RRC Connection Reconfiguration Complete + + Description: Used to confirm the successful completion of an RRC + connection reconfiguration + + Document Reference: 36.331 v10.0.0 Section 6.2.2 +*********************************************************************/ +// Defines +// Enums +// Structs +typedef struct{ + uint8 rrc_transaction_id; +}LIBLTE_RRC_CONNECTION_RECONFIGURATION_COMPLETE_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_rrc_connection_reconfiguration_complete_msg(LIBLTE_RRC_CONNECTION_RECONFIGURATION_COMPLETE_STRUCT *con_reconfig_complete, + LIBLTE_BIT_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_rrc_connection_reconfiguration_complete_msg(LIBLTE_BIT_MSG_STRUCT *msg, + LIBLTE_RRC_CONNECTION_RECONFIGURATION_COMPLETE_STRUCT *con_reconfig_complete); + +/********************************************************************* + Message Name: RRC Connection Reconfiguration + + Description: Modifies an RRC connection + + Document Reference: 36.331 v10.0.0 Section 6.2.2 +*********************************************************************/ +// Defines +// Enums +typedef enum{ + LIBLTE_RRC_HANDOVER_TYPE_INTRA_LTE = 0, + LIBLTE_RRC_HANDOVER_TYPE_INTER_RAT, + LIBLTE_RRC_HANDOVER_TYPE_N_ITEMS, +}LIBLTE_RRC_HANDOVER_TYPE_ENUM; +static const char liblte_rrc_handover_type_text[LIBLTE_RRC_HANDOVER_TYPE_N_ITEMS][20] = {"Intra LTE", + "Inter RAT"}; +// Structs +typedef struct{ + LIBLTE_RRC_SECURITY_ALGORITHM_CONFIG_STRUCT sec_alg_cnfg; + uint8 next_hop_chaining_count; + bool key_change_ind; + bool sec_alg_cnfg_present; +}LIBLTE_RRC_INTRA_LTE_HANDOVER_STRUCT; +typedef struct{ + LIBLTE_RRC_SECURITY_ALGORITHM_CONFIG_STRUCT sec_alg_cnfg; + uint8 nas_sec_param_to_eutra[6]; +}LIBLTE_RRC_INTER_RAT_HANDOVER_STRUCT; +typedef struct{ + LIBLTE_RRC_INTRA_LTE_HANDOVER_STRUCT intra_lte; + LIBLTE_RRC_INTER_RAT_HANDOVER_STRUCT inter_rat; + LIBLTE_RRC_HANDOVER_TYPE_ENUM ho_type; +}LIBLTE_RRC_SECURITY_CONFIG_HO_STRUCT; +typedef struct{ + LIBLTE_RRC_MEAS_CONFIG_STRUCT meas_cnfg; + LIBLTE_RRC_MOBILITY_CONTROL_INFO_STRUCT mob_ctrl_info; + LIBLTE_SIMPLE_BYTE_MSG_STRUCT ded_info_nas_list[LIBLTE_RRC_MAX_DRB]; + LIBLTE_RRC_RR_CONFIG_DEDICATED_STRUCT rr_cnfg_ded; + LIBLTE_RRC_SECURITY_CONFIG_HO_STRUCT sec_cnfg_ho; + uint32 N_ded_info_nas; + uint8 rrc_transaction_id; + bool meas_cnfg_present; + bool mob_ctrl_info_present; + bool rr_cnfg_ded_present; + bool sec_cnfg_ho_present; +}LIBLTE_RRC_CONNECTION_RECONFIGURATION_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_rrc_connection_reconfiguration_msg(LIBLTE_RRC_CONNECTION_RECONFIGURATION_STRUCT *con_reconfig, + LIBLTE_BIT_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_rrc_connection_reconfiguration_msg(LIBLTE_BIT_MSG_STRUCT *msg, + LIBLTE_RRC_CONNECTION_RECONFIGURATION_STRUCT *con_reconfig); + +/********************************************************************* + Message Name: RN Reconfiguration Complete + + Description: Used to confirm the successful completion of an RN + reconfiguration + + Document Reference: 36.331 v10.0.0 Section 6.2.2 +*********************************************************************/ +// Defines +// Enums +// Structs +typedef struct{ + uint8 rrc_transaction_id; +}LIBLTE_RRC_RN_RECONFIGURATION_COMPLETE_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_rn_reconfiguration_complete_msg(LIBLTE_RRC_RN_RECONFIGURATION_COMPLETE_STRUCT *rn_reconfig_complete, + LIBLTE_BIT_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_rn_reconfiguration_complete_msg(LIBLTE_BIT_MSG_STRUCT *msg, + LIBLTE_RRC_RN_RECONFIGURATION_COMPLETE_STRUCT *rn_reconfig_complete); + +/********************************************************************* + Message Name: RN Reconfiguration + + Description: Modifies the RRC connection between the RN and the + E-UTRAN + + Document Reference: 36.331 v10.0.0 Section 6.2.2 +*********************************************************************/ +// Defines +// Enums +// Structs +typedef struct{ + // FIXME +}LIBLTE_RRC_RN_RECONFIGURATION_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_rn_reconfiguration_msg(LIBLTE_RRC_RN_RECONFIGURATION_STRUCT *rn_reconfig, + LIBLTE_BIT_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_rn_reconfiguration_msg(LIBLTE_BIT_MSG_STRUCT *msg, + LIBLTE_RRC_RN_RECONFIGURATION_STRUCT *rn_reconfig); + +/********************************************************************* + Message Name: Proximity Indication + + Description: Used to indicate that the UE is entering or leaving + the proximity of one or more cells whose CSG IDs are + in the UEs CSG whitelist + + Document Reference: 36.331 v10.0.0 Section 6.2.2 +*********************************************************************/ +// Defines +// Enums +typedef enum{ + LIBLTE_RRC_PROXIMITY_INDICATION_TYPE_ENTERING = 0, + LIBLTE_RRC_PROXIMITY_INDICATION_TYPE_LEAVING, + LIBLTE_RRC_PROXIMITY_INDICATION_TYPE_N_ITEMS, +}LIBLTE_RRC_PROXIMITY_INDICATION_TYPE_ENUM; +static const char liblte_rrc_proximity_indication_type_text[LIBLTE_RRC_PROXIMITY_INDICATION_TYPE_N_ITEMS][20] = {"Entering", "Leaving"}; +typedef enum{ + LIBLTE_RRC_PROXIMITY_INDICATION_CARRIER_FREQ_TYPE_EUTRA = 0, + LIBLTE_RRC_PROXIMITY_INDICATION_CARRIER_FREQ_TYPE_UTRA, + LIBLTE_RRC_PROXIMITY_INDICATION_CARRIER_FREQ_TYPE_N_ITEMS, +}LIBLTE_RRC_PROXIMITY_INDICATION_CARRIER_FREQ_TYPE_ENUM; +static const char liblte_rrc_proximity_indication_carrier_freq_type_text[LIBLTE_RRC_PROXIMITY_INDICATION_CARRIER_FREQ_TYPE_N_ITEMS][20] = {"EUTRA", "UTRA"}; +// Structs +typedef struct{ + LIBLTE_RRC_PROXIMITY_INDICATION_TYPE_ENUM type; + LIBLTE_RRC_PROXIMITY_INDICATION_CARRIER_FREQ_TYPE_ENUM carrier_freq_type; + uint16 carrier_freq; +}LIBLTE_RRC_PROXIMITY_INDICATION_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_proximity_indication_msg(LIBLTE_RRC_PROXIMITY_INDICATION_STRUCT *proximity_ind, + LIBLTE_BIT_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_proximity_indication_msg(LIBLTE_BIT_MSG_STRUCT *msg, + LIBLTE_RRC_PROXIMITY_INDICATION_STRUCT *proximity_ind); + +/********************************************************************* + Message Name: Paging + + Description: Used for the notification of one or more UEs + + Document Reference: 36.331 v10.0.0 Section 6.2.2 +*********************************************************************/ +// Defines +#define LIBLTE_RRC_MAX_PAGE_REC 16 +// Enums +typedef enum{ + LIBLTE_RRC_PAGING_UE_IDENTITY_TYPE_S_TMSI = 0, + LIBLTE_RRC_PAGING_UE_IDENTITY_TYPE_IMSI, + LIBLTE_RRC_PAGING_UE_IDENTITY_TYPE_N_ITEMS, +}LIBLTE_RRC_PAGING_UE_IDENTITY_TYPE_ENUM; +static const char liblte_rrc_paging_ue_identity_type_text[LIBLTE_RRC_PAGING_UE_IDENTITY_TYPE_N_ITEMS][20] = {"S-TMSI", "IMSI"}; +typedef enum{ + LIBLTE_RRC_CN_DOMAIN_PS = 0, + LIBLTE_RRC_CN_DOMAIN_CS, + LIBLTE_RRC_CN_DOMAIN_N_ITEMS, +}LIBLTE_RRC_CN_DOMAIN_ENUM; +static const char liblte_rrc_cn_domain_text[LIBLTE_RRC_CN_DOMAIN_N_ITEMS][20] = {"PS", "CS"}; +typedef enum{ + LIBLTE_RRC_CMAS_INDICATION_R9_TRUE = 0, + LIBLTE_RRC_CMAS_INDICATION_R9_N_ITEMS, +}LIBLTE_RRC_CMAS_INDICATION_R9_ENUM; +static const char liblte_rrc_cmas_indication_r9_text[LIBLTE_RRC_CMAS_INDICATION_R9_N_ITEMS][20] = {"TRUE"}; +typedef enum{ + LIBLTE_RRC_SYSTEM_INFO_MODIFICATION_TRUE = 0, + LIBLTE_RRC_SYSTEM_INFO_MODIFICATION_N_ITEMS, +}LIBLTE_RRC_SYSTEM_INFO_MODIFICATION_ENUM; +static const char liblte_rrc_system_info_modification_text[LIBLTE_RRC_SYSTEM_INFO_MODIFICATION_N_ITEMS][20] = {"TRUE"}; +typedef enum{ + LIBLTE_RRC_ETWS_INDICATION_TRUE = 0, + LIBLTE_RRC_ETWS_INDICATION_N_ITEMS, +}LIBLTE_RRC_ETWS_INDICATION_ENUM; +static const char liblte_rrc_etws_indication_text[LIBLTE_RRC_ETWS_INDICATION_N_ITEMS][20] = {"TRUE"}; +// Structs +typedef struct{ + LIBLTE_RRC_S_TMSI_STRUCT s_tmsi; + LIBLTE_RRC_PAGING_UE_IDENTITY_TYPE_ENUM ue_identity_type; + uint32 imsi_size; + uint8 imsi[21]; +}LIBLTE_RRC_PAGING_UE_IDENTITY_STRUCT; +typedef struct{ + LIBLTE_RRC_PAGING_UE_IDENTITY_STRUCT ue_identity; + LIBLTE_RRC_CN_DOMAIN_ENUM cn_domain; +}LIBLTE_RRC_PAGING_RECORD_STRUCT; +typedef struct{ + LIBLTE_RRC_CMAS_INDICATION_R9_ENUM cmas_ind_r9; + bool cmas_ind_present; + bool non_crit_ext_present; +}LIBLTE_RRC_PAGING_V920_IES_STRUCT; +typedef struct{ + LIBLTE_RRC_PAGING_V920_IES_STRUCT non_crit_ext; + uint8 late_non_crit_ext; + bool late_non_crit_ext_present; + bool non_crit_ext_present; +}LIBLTE_RRC_PAGING_V890_IES_STRUCT; +typedef struct{ + LIBLTE_RRC_PAGING_RECORD_STRUCT paging_record_list[LIBLTE_RRC_MAX_PAGE_REC]; + LIBLTE_RRC_PAGING_V890_IES_STRUCT non_crit_ext; + LIBLTE_RRC_SYSTEM_INFO_MODIFICATION_ENUM system_info_modification; + LIBLTE_RRC_ETWS_INDICATION_ENUM etws_indication; + uint32 paging_record_list_size; + bool system_info_modification_present; + bool etws_indication_present; + bool non_crit_ext_present; +}LIBLTE_RRC_PAGING_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_paging_msg(LIBLTE_RRC_PAGING_STRUCT *page, + LIBLTE_BIT_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_paging_msg(LIBLTE_BIT_MSG_STRUCT *msg, + LIBLTE_RRC_PAGING_STRUCT *page); + +/********************************************************************* + Message Name: Mobility From EUTRA Command + + Description: Used to command handover or a cell change from E-UTRA + to another RAT, or enhanced CS fallback to CDMA2000 + 1xRTT + + Document Reference: 36.331 v10.0.0 Section 6.2.2 +*********************************************************************/ +// Defines +// Enums +// Structs +typedef struct{ + // FIXME +}LIBLTE_RRC_MOBILITY_FROM_EUTRA_COMMAND_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_mobility_from_eutra_command_msg(LIBLTE_RRC_MOBILITY_FROM_EUTRA_COMMAND_STRUCT *mobility_from_eutra_cmd, + LIBLTE_BIT_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_mobility_from_eutra_command_msg(LIBLTE_BIT_MSG_STRUCT *msg, + LIBLTE_RRC_MOBILITY_FROM_EUTRA_COMMAND_STRUCT *mobility_from_eutra_cmd); + +/********************************************************************* + Message Name: Measurement Report + + Description: Used for the indication of measurement results + + Document Reference: 36.331 v10.0.0 Section 6.2.2 +*********************************************************************/ +// Defines +// Enums +// Structs +typedef struct{ + // FIXME +}LIBLTE_RRC_MEASUREMENT_REPORT_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_measurement_report_msg(LIBLTE_RRC_MEASUREMENT_REPORT_STRUCT *meas_report, + LIBLTE_BIT_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_measurement_report_msg(LIBLTE_BIT_MSG_STRUCT *msg, + LIBLTE_RRC_MEASUREMENT_REPORT_STRUCT *meas_report); + +/********************************************************************* + Message Name: MBSFN Area Configuration + + Description: Contains the MBMS control information applicable for + an MBSFN area + + Document Reference: 36.331 v10.0.0 Section 6.2.2 +*********************************************************************/ +// Defines +// Enums +// Structs +// Functions +// FIXME + +/********************************************************************* + Message Name: Master Information Block + + Description: Includes the system information transmitted on BCH + + Document Reference: 36.331 v10.0.0 Section 6.2.2 +*********************************************************************/ +// Inlined with BCCH BCH Message + +/********************************************************************* + Message Name: Logged Measurements Configuration + + Description: Used by E-UTRAN to configure the UE to perform + logging of measurement results while in RRC_IDLE + + Document Reference: 36.331 v10.0.0 Section 6.2.2 +*********************************************************************/ +// Defines +// Enums +// Structs +typedef struct{ + // FIXME +}LIBLTE_RRC_LOGGED_MEASUREMENTS_CONFIGURATION_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_logged_measurements_configuration_msg(LIBLTE_RRC_LOGGED_MEASUREMENTS_CONFIGURATION_STRUCT *logged_measurements_config, + LIBLTE_BIT_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_logged_measurements_configuration_msg(LIBLTE_BIT_MSG_STRUCT *msg, + LIBLTE_RRC_LOGGED_MEASUREMENTS_CONFIGURATION_STRUCT *logged_measurements_config); + +/********************************************************************* + Message Name: Handover From EUTRA Preparation Request (CDMA2000) + + Description: Used to trigger the handover preparation procedure + with a CDMA2000 RAT + + Document Reference: 36.331 v10.0.0 Section 6.2.2 +*********************************************************************/ +// Defines +// Enums +// Structs +typedef struct{ + // FIXME +}LIBLTE_RRC_HANDOVER_FROM_EUTRA_PREPARATION_REQUEST_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_handover_from_eutra_preparation_request_msg(LIBLTE_RRC_HANDOVER_FROM_EUTRA_PREPARATION_REQUEST_STRUCT *handover_from_eutra_prep_req, + LIBLTE_BIT_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_handover_from_eutra_preparation_request_msg(LIBLTE_BIT_MSG_STRUCT *msg, + LIBLTE_RRC_HANDOVER_FROM_EUTRA_PREPARATION_REQUEST_STRUCT *handover_from_eutra_prep_req); + +/********************************************************************* + Message Name: DL Information Transfer + + Description: Used for the downlink transfer of dedicated NAS + information + + Document Reference: 36.331 v10.0.0 Section 6.2.2 +*********************************************************************/ +// Defines +// Enums +typedef enum{ + LIBLTE_RRC_DL_INFORMATION_TRANSFER_TYPE_NAS = 0, + LIBLTE_RRC_DL_INFORMATION_TRANSFER_TYPE_CDMA2000_1XRTT, + LIBLTE_RRC_DL_INFORMATION_TRANSFER_TYPE_CDMA2000_HRPD, + LIBLTE_RRC_DL_INFORMATION_TRANSFER_TYPE_N_ITEMS, +}LIBLTE_RRC_DL_INFORMATION_TRANSFER_TYPE_ENUM; +static const char liblte_rrc_dl_information_transfer_type_text[LIBLTE_RRC_DL_INFORMATION_TRANSFER_TYPE_N_ITEMS][20] = {"NAS", + "CDMA2000-1XRTT", + "CDMA2000-HRPD"}; +// Structs +typedef struct{ + LIBLTE_SIMPLE_BYTE_MSG_STRUCT dedicated_info; + LIBLTE_RRC_DL_INFORMATION_TRANSFER_TYPE_ENUM dedicated_info_type; + uint8 rrc_transaction_id; +}LIBLTE_RRC_DL_INFORMATION_TRANSFER_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_dl_information_transfer_msg(LIBLTE_RRC_DL_INFORMATION_TRANSFER_STRUCT *dl_info_transfer, + LIBLTE_BIT_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_dl_information_transfer_msg(LIBLTE_BIT_MSG_STRUCT *msg, + LIBLTE_RRC_DL_INFORMATION_TRANSFER_STRUCT *dl_info_transfer); + +/********************************************************************* + Message Name: CSFB Parameters Response CDMA2000 + + Description: Used to provide the CDMA2000 1xRTT parameters to the + UE so the UE can register with the CDMA2000 1xRTT + network to support CSFB to CDMA2000 1xRTT + + Document Reference: 36.331 v10.0.0 Section 6.2.2 +*********************************************************************/ +// Defines +// Enums +// Structs +typedef struct{ + // FIXME +}LIBLTE_RRC_CSFB_PARAMETERS_RESPONSE_CDMA2000_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_csfb_parameters_response_cdma2000_msg(LIBLTE_RRC_CSFB_PARAMETERS_RESPONSE_CDMA2000_STRUCT *csfb_params_resp_cdma2000, + LIBLTE_BIT_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_csfb_parameters_response_cdma2000_msg(LIBLTE_BIT_MSG_STRUCT *msg, + LIBLTE_RRC_CSFB_PARAMETERS_RESPONSE_CDMA2000_STRUCT *csfb_params_resp_cdma2000); + +/********************************************************************* + Message Name: CSFB Parameters Request CDMA2000 + + Description: Used by the UE to obtain the CDMA2000 1xRTT + parameters from the network + + Document Reference: 36.331 v10.0.0 Section 6.2.2 +*********************************************************************/ +// Defines +// Enums +// Structs +typedef struct{ +}LIBLTE_RRC_CSFB_PARAMETERS_REQUEST_CDMA2000_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_csfb_parameters_request_cdma2000_msg(LIBLTE_RRC_CSFB_PARAMETERS_REQUEST_CDMA2000_STRUCT *csfb_params_req_cdma2000, + LIBLTE_BIT_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_csfb_parameters_request_cdma2000_msg(LIBLTE_BIT_MSG_STRUCT *msg, + LIBLTE_RRC_CSFB_PARAMETERS_REQUEST_CDMA2000_STRUCT *csfb_params_req_cdma2000); + +/********************************************************************* + Message Name: Counter Check Response + + Description: Used by the UE to respond to a Counter Check message + + Document Reference: 36.331 v10.0.0 Section 6.2.2 +*********************************************************************/ +// Defines +// Enums +// Structs +typedef struct{ + // FIXME +}LIBLTE_RRC_COUNTER_CHECK_RESPONSE_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_counter_check_response_msg(LIBLTE_RRC_COUNTER_CHECK_RESPONSE_STRUCT *counter_check_resp, + LIBLTE_BIT_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_counter_check_response_msg(LIBLTE_BIT_MSG_STRUCT *msg, + LIBLTE_RRC_COUNTER_CHECK_RESPONSE_STRUCT *counter_check_resp); + +/********************************************************************* + Message Name: Counter Check + + Description: Used by the E-UTRAN to indicate the current COUNT MSB + values associated to each DRB and to request the UE + to compare these to its COUNT MSB values and to + report the comparison results to E-UTRAN + + Document Reference: 36.331 v10.0.0 Section 6.2.2 +*********************************************************************/ +// Defines +// Enums +// Structs +typedef struct{ + // FIXME +}LIBLTE_RRC_COUNTER_CHECK_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_counter_check_msg(LIBLTE_RRC_COUNTER_CHECK_STRUCT *counter_check, + LIBLTE_BIT_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_counter_check_msg(LIBLTE_BIT_MSG_STRUCT *msg, + LIBLTE_RRC_COUNTER_CHECK_STRUCT *counter_check); + +/********************************************************************* + Message Name: BCCH BCH Message + + Description: Contains the set of RRC messages that may be sent + from the E-UTRAN to the UE via BCH on the BCCH + logical channel + + Document Reference: 36.331 v10.0.0 Sections 6.2.1 and 6.2.2 +*********************************************************************/ +// Defines +// Enums +typedef enum{ + LIBLTE_RRC_DL_BANDWIDTH_6 = 0, + LIBLTE_RRC_DL_BANDWIDTH_15, + LIBLTE_RRC_DL_BANDWIDTH_25, + LIBLTE_RRC_DL_BANDWIDTH_50, + LIBLTE_RRC_DL_BANDWIDTH_75, + LIBLTE_RRC_DL_BANDWIDTH_100, + LIBLTE_RRC_DL_BANDWIDTH_N_ITEMS, +}LIBLTE_RRC_DL_BANDWIDTH_ENUM; +static const char liblte_rrc_dl_bandwidth_text[LIBLTE_RRC_DL_BANDWIDTH_N_ITEMS][20] = {"1.4", "3", "5", "10", + "15", "20"}; +static const double liblte_rrc_dl_bandwidth_num[LIBLTE_RRC_DL_BANDWIDTH_N_ITEMS] = {1.4, 3, 5, 10, 15, 20}; +// Structs +typedef struct{ + LIBLTE_RRC_PHICH_CONFIG_STRUCT phich_config; + LIBLTE_RRC_DL_BANDWIDTH_ENUM dl_bw; + uint8 sfn_div_4; +}LIBLTE_RRC_MIB_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_bcch_bch_msg(LIBLTE_RRC_MIB_STRUCT *mib, + LIBLTE_BIT_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_bcch_bch_msg(LIBLTE_BIT_MSG_STRUCT *msg, + LIBLTE_RRC_MIB_STRUCT *mib); + +/********************************************************************* + Message Name: BCCH DLSCH Message + + Description: Contains the set of RRC messages that may be sent + from the E-UTRAN to the UE via DLSCH on the BCCH + logical channel + + Document Reference: 36.331 v10.0.0 Section 6.2.1 +*********************************************************************/ +// Defines +// Enums +// Structs +typedef LIBLTE_RRC_SYS_INFO_MSG_STRUCT LIBLTE_RRC_BCCH_DLSCH_MSG_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_bcch_dlsch_msg(LIBLTE_RRC_BCCH_DLSCH_MSG_STRUCT *bcch_dlsch_msg, + LIBLTE_BIT_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_bcch_dlsch_msg(LIBLTE_BIT_MSG_STRUCT *msg, + LIBLTE_RRC_BCCH_DLSCH_MSG_STRUCT *bcch_dlsch_msg); + +/********************************************************************* + Message Name: MCCH Message + + Description: Contains the set of RRC messages that may be sent + from the E-UTRAN to the UE on the MCCH logical + channel + + Document Reference: 36.331 v10.0.0 Section 6.2.1 +*********************************************************************/ +// Defines +// Enums +// Structs +// Functions +// FIXME + +/********************************************************************* + Message Name: PCCH Message + + Description: Contains the set of RRC messages that may be sent + from the E-UTRAN to the UE on the PCCH logical + channel + + Document Reference: 36.331 v10.0.0 Section 6.2.1 +*********************************************************************/ +// Defines +// Enums +// Structs +typedef LIBLTE_RRC_PAGING_STRUCT LIBLTE_RRC_PCCH_MSG_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_pcch_msg(LIBLTE_RRC_PCCH_MSG_STRUCT *pcch_msg, + LIBLTE_BIT_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_pcch_msg(LIBLTE_BIT_MSG_STRUCT *msg, + LIBLTE_RRC_PCCH_MSG_STRUCT *pcch_msg); + +/********************************************************************* + Message Name: DL CCCH Message + + Description: Contains the set of RRC messages that may be sent + from the E-UTRAN to the UE on the CCCH logical + channel + + Document Reference: 36.331 v10.0.0 Section 6.2.1 +*********************************************************************/ +// Defines +// Enums +typedef enum{ + LIBLTE_RRC_DL_CCCH_MSG_TYPE_RRC_CON_REEST = 0, + LIBLTE_RRC_DL_CCCH_MSG_TYPE_RRC_CON_REEST_REJ, + LIBLTE_RRC_DL_CCCH_MSG_TYPE_RRC_CON_REJ, + LIBLTE_RRC_DL_CCCH_MSG_TYPE_RRC_CON_SETUP, + LIBLTE_RRC_DL_CCCH_MSG_TYPE_N_ITEMS, +}LIBLTE_RRC_DL_CCCH_MSG_TYPE_ENUM; +static const char liblte_rrc_dl_ccch_msg_type_text[LIBLTE_RRC_DL_CCCH_MSG_TYPE_N_ITEMS][100] = {"RRC Connection Reestablishment", + "RRC Connection Reestablishment Reject", + "RRC Connection Reject", + "RRC Connection Setup"}; +// Structs +typedef union{ + LIBLTE_RRC_CONNECTION_REESTABLISHMENT_STRUCT rrc_con_reest; + LIBLTE_RRC_CONNECTION_REESTABLISHMENT_REJECT_STRUCT rrc_con_reest_rej; + LIBLTE_RRC_CONNECTION_REJECT_STRUCT rrc_con_rej; + LIBLTE_RRC_CONNECTION_SETUP_STRUCT rrc_con_setup; +}LIBLTE_RRC_DL_CCCH_MSG_TYPE_UNION; +typedef struct{ + LIBLTE_RRC_DL_CCCH_MSG_TYPE_UNION msg; + LIBLTE_RRC_DL_CCCH_MSG_TYPE_ENUM msg_type; +}LIBLTE_RRC_DL_CCCH_MSG_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_dl_ccch_msg(LIBLTE_RRC_DL_CCCH_MSG_STRUCT *dl_ccch_msg, + LIBLTE_BIT_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_dl_ccch_msg(LIBLTE_BIT_MSG_STRUCT *msg, + LIBLTE_RRC_DL_CCCH_MSG_STRUCT *dl_ccch_msg); + +/********************************************************************* + Message Name: DL DCCH Message + + Description: Contains the set of RRC messages that may be sent + from the E-UTRAN to the UE on the DCCH logical + channel + + Document Reference: 36.331 v10.0.0 Section 6.2.1 +*********************************************************************/ +// Defines +// Enums +typedef enum{ + LIBLTE_RRC_DL_DCCH_MSG_TYPE_CSFB_PARAMS_RESP_CDMA2000 = 0, + LIBLTE_RRC_DL_DCCH_MSG_TYPE_DL_INFO_TRANSFER, + LIBLTE_RRC_DL_DCCH_MSG_TYPE_HANDOVER_FROM_EUTRA_PREP_REQ, + LIBLTE_RRC_DL_DCCH_MSG_TYPE_MOBILITY_FROM_EUTRA_COMMAND, + LIBLTE_RRC_DL_DCCH_MSG_TYPE_RRC_CON_RECONFIG, + LIBLTE_RRC_DL_DCCH_MSG_TYPE_RRC_CON_RELEASE, + LIBLTE_RRC_DL_DCCH_MSG_TYPE_SECURITY_MODE_COMMAND, + LIBLTE_RRC_DL_DCCH_MSG_TYPE_UE_CAPABILITY_ENQUIRY, + LIBLTE_RRC_DL_DCCH_MSG_TYPE_COUNTER_CHECK, + LIBLTE_RRC_DL_DCCH_MSG_TYPE_UE_INFO_REQ, + LIBLTE_RRC_DL_DCCH_MSG_TYPE_LOGGED_MEASUREMENTS_CONFIG, + LIBLTE_RRC_DL_DCCH_MSG_TYPE_RN_RECONFIG, + LIBLTE_RRC_DL_DCCH_MSG_TYPE_N_ITEMS, +}LIBLTE_RRC_DL_DCCH_MSG_TYPE_ENUM; +static const char liblte_rrc_dl_dcch_msg_type_text[LIBLTE_RRC_DL_DCCH_MSG_TYPE_N_ITEMS][100] = {"CSFB Parameters Response CDMA2000", + "DL Information Transfer", + "Handover From EUTRA Preparation Request", + "Mobility From EUTRA Command", + "RRC Connection Reconfiguration", + "RRC Connection Release", + "Security Mode Command", + "UE Capability Enquiry", + "Counter Check", + "UE Information Request", + "Logged Measurements Configuration", + "RN Reconfiguration"}; +// Structs +typedef union{ + LIBLTE_RRC_CSFB_PARAMETERS_RESPONSE_CDMA2000_STRUCT csfb_params_resp_cdma2000; + LIBLTE_RRC_DL_INFORMATION_TRANSFER_STRUCT dl_info_transfer; + LIBLTE_RRC_HANDOVER_FROM_EUTRA_PREPARATION_REQUEST_STRUCT handover_from_eutra_prep_req; + LIBLTE_RRC_MOBILITY_FROM_EUTRA_COMMAND_STRUCT mobility_from_eutra_cmd; + LIBLTE_RRC_CONNECTION_RECONFIGURATION_STRUCT rrc_con_reconfig; + LIBLTE_RRC_CONNECTION_RELEASE_STRUCT rrc_con_release; + LIBLTE_RRC_SECURITY_MODE_COMMAND_STRUCT security_mode_cmd; + LIBLTE_RRC_UE_CAPABILITY_ENQUIRY_STRUCT ue_cap_enquiry; + LIBLTE_RRC_COUNTER_CHECK_STRUCT counter_check; + LIBLTE_RRC_UE_INFORMATION_REQUEST_STRUCT ue_info_req; + LIBLTE_RRC_LOGGED_MEASUREMENTS_CONFIGURATION_STRUCT logged_measurements_config; + LIBLTE_RRC_RN_RECONFIGURATION_STRUCT rn_reconfig; +}LIBLTE_RRC_DL_DCCH_MSG_TYPE_UNION; +typedef struct{ + LIBLTE_RRC_DL_DCCH_MSG_TYPE_UNION msg; + LIBLTE_RRC_DL_DCCH_MSG_TYPE_ENUM msg_type; +}LIBLTE_RRC_DL_DCCH_MSG_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_dl_dcch_msg(LIBLTE_RRC_DL_DCCH_MSG_STRUCT *dl_dcch_msg, + LIBLTE_BIT_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_dl_dcch_msg(LIBLTE_BIT_MSG_STRUCT *msg, + LIBLTE_RRC_DL_DCCH_MSG_STRUCT *dl_dcch_msg); + +/********************************************************************* + Message Name: UL CCCH Message + + Description: Contains the set of RRC messages that may be sent + from the UE to the E-UTRAN on the CCCH logical + channel + + Document Reference: 36.331 v10.0.0 Section 6.2.1 +*********************************************************************/ +// Defines +// Enums +typedef enum{ + LIBLTE_RRC_UL_CCCH_MSG_TYPE_RRC_CON_REEST_REQ = 0, + LIBLTE_RRC_UL_CCCH_MSG_TYPE_RRC_CON_REQ, + LIBLTE_RRC_UL_CCCH_MSG_TYPE_N_ITEMS, +}LIBLTE_RRC_UL_CCCH_MSG_TYPE_ENUM; +static const char liblte_rrc_ul_ccch_msg_type_text[LIBLTE_RRC_UL_CCCH_MSG_TYPE_N_ITEMS][100] = {"RRC Connection Reestablishment Request", + "RRC Connection Request"}; +// Structs +typedef union{ + LIBLTE_RRC_CONNECTION_REESTABLISHMENT_REQUEST_STRUCT rrc_con_reest_req; + LIBLTE_RRC_CONNECTION_REQUEST_STRUCT rrc_con_req; +}LIBLTE_RRC_UL_CCCH_MSG_TYPE_UNION; +typedef struct{ + LIBLTE_RRC_UL_CCCH_MSG_TYPE_UNION msg; + LIBLTE_RRC_UL_CCCH_MSG_TYPE_ENUM msg_type; +}LIBLTE_RRC_UL_CCCH_MSG_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_ul_ccch_msg(LIBLTE_RRC_UL_CCCH_MSG_STRUCT *ul_ccch_msg, + LIBLTE_BIT_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_ul_ccch_msg(LIBLTE_BIT_MSG_STRUCT *msg, + LIBLTE_RRC_UL_CCCH_MSG_STRUCT *ul_ccch_msg); + +/********************************************************************* + Message Name: UL DCCH Message + + Description: Contains the set of RRC messages that may be sent + from the UE to the E-UTRAN on the DCCH logical + channel + + Document Reference: 36.331 v10.0.0 Section 6.2.1 +*********************************************************************/ +// Defines +// Enums +typedef enum{ + LIBLTE_RRC_UL_DCCH_MSG_TYPE_CSFB_PARAMS_REQ_CDMA2000 = 0, + LIBLTE_RRC_UL_DCCH_MSG_TYPE_MEASUREMENT_REPORT, + LIBLTE_RRC_UL_DCCH_MSG_TYPE_RRC_CON_RECONFIG_COMPLETE, + LIBLTE_RRC_UL_DCCH_MSG_TYPE_RRC_CON_REEST_COMPLETE, + LIBLTE_RRC_UL_DCCH_MSG_TYPE_RRC_CON_SETUP_COMPLETE, + LIBLTE_RRC_UL_DCCH_MSG_TYPE_SECURITY_MODE_COMPLETE, + LIBLTE_RRC_UL_DCCH_MSG_TYPE_SECURITY_MODE_FAILURE, + LIBLTE_RRC_UL_DCCH_MSG_TYPE_UE_CAPABILITY_INFO, + LIBLTE_RRC_UL_DCCH_MSG_TYPE_UL_HANDOVER_PREP_TRANSFER, + LIBLTE_RRC_UL_DCCH_MSG_TYPE_UL_INFO_TRANSFER, + LIBLTE_RRC_UL_DCCH_MSG_TYPE_COUNTER_CHECK_RESP, + LIBLTE_RRC_UL_DCCH_MSG_TYPE_UE_INFO_RESP, + LIBLTE_RRC_UL_DCCH_MSG_TYPE_PROXIMITY_IND, + LIBLTE_RRC_UL_DCCH_MSG_TYPE_RN_RECONFIG_COMPLETE, + LIBLTE_RRC_UL_DCCH_MSG_TYPE_SPARE2, + LIBLTE_RRC_UL_DCCH_MSG_TYPE_SPARE1, + LIBLTE_RRC_UL_DCCH_MSG_TYPE_N_ITEMS, +}LIBLTE_RRC_UL_DCCH_MSG_TYPE_ENUM; +static const char liblte_rrc_ul_dcch_msg_type_text[LIBLTE_RRC_UL_DCCH_MSG_TYPE_N_ITEMS][100] = {"CSFB Parameters Request CDMA2000", + "Measurement Report", + "RRC Connection Reconfiguration Complete", + "RRC Connection Reestablishment Complete", + "RRC Connection Setup Complete", + "Security Mode Complete", + "Security Mode Failure", + "UE Capability Information", + "UL Handover Preparation Transfer", + "UL Information Transfer", + "Counter Check Response", + "UE Information Response", + "Proximity Indication", + "RN Reconfiguration Complete", + "SPARE", + "SPARE"}; +// Structs +typedef union{ + LIBLTE_RRC_CSFB_PARAMETERS_REQUEST_CDMA2000_STRUCT csfb_params_req_cdma2000; + LIBLTE_RRC_MEASUREMENT_REPORT_STRUCT measurement_report; + LIBLTE_RRC_CONNECTION_RECONFIGURATION_COMPLETE_STRUCT rrc_con_reconfig_complete; + LIBLTE_RRC_CONNECTION_REESTABLISHMENT_COMPLETE_STRUCT rrc_con_reest_complete; + LIBLTE_RRC_CONNECTION_SETUP_COMPLETE_STRUCT rrc_con_setup_complete; + LIBLTE_RRC_SECURITY_MODE_COMPLETE_STRUCT security_mode_complete; + LIBLTE_RRC_SECURITY_MODE_FAILURE_STRUCT security_mode_failure; + LIBLTE_RRC_UE_CAPABILITY_INFORMATION_STRUCT ue_capability_info; + LIBLTE_RRC_UL_HANDOVER_PREPARATION_TRANSFER_STRUCT ul_handover_prep_transfer; + LIBLTE_RRC_UL_INFORMATION_TRANSFER_STRUCT ul_info_transfer; + LIBLTE_RRC_COUNTER_CHECK_RESPONSE_STRUCT counter_check_resp; + LIBLTE_RRC_UE_INFORMATION_RESPONSE_STRUCT ue_info_resp; + LIBLTE_RRC_PROXIMITY_INDICATION_STRUCT proximity_ind; + LIBLTE_RRC_RN_RECONFIGURATION_COMPLETE_STRUCT rn_reconfig_complete; +}LIBLTE_RRC_UL_DCCH_MSG_TYPE_UNION; +typedef struct{ + LIBLTE_RRC_UL_DCCH_MSG_TYPE_UNION msg; + LIBLTE_RRC_UL_DCCH_MSG_TYPE_ENUM msg_type; +}LIBLTE_RRC_UL_DCCH_MSG_STRUCT; +// Functions +LIBLTE_ERROR_ENUM liblte_rrc_pack_ul_dcch_msg(LIBLTE_RRC_UL_DCCH_MSG_STRUCT *ul_dcch_msg, + LIBLTE_BIT_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_ul_dcch_msg(LIBLTE_BIT_MSG_STRUCT *msg, + LIBLTE_RRC_UL_DCCH_MSG_STRUCT *ul_dcch_msg); + +#endif /* __LIBLTE_RRC_H__ */ diff --git a/lib/include/srslte/asn1/liblte_s1ap.h b/lib/include/srslte/asn1/liblte_s1ap.h new file mode 100644 index 000000000..077ddac66 --- /dev/null +++ b/lib/include/srslte/asn1/liblte_s1ap.h @@ -0,0 +1,10355 @@ +/******************************************************************************* +/* +/* Copyright 2016 Software Radio Systems Limited +/* +********************************************************************************/ + +#ifndef LIBLTE_S1AP_H +#define LIBLTE_S1AP_H + +/******************************************************************************* +/* Warnings/Todos +********************************************************************************/ +// Extensions are not yet handled correctly +// Dynamic Sequence Of types have max 32 elements to reduce memory footprint +// Container Lists are not yet handled correctly e.g. E-RAB-IE-ContainerList + +/******************************************************************************* +/* INCLUDES +********************************************************************************/ + +#include "liblte_common.h" + +/******************************************************************************* + LOGGING +*******************************************************************************/ + +typedef void (*log_handler_t)(void *ctx, char *str); + +void liblte_log_register_handler(void *ctx, log_handler_t handler); + + +/******************************************************************************* +/* MAX defines +********************************************************************************/ +#define LIBLTE_S1AP_MAXPRIVATEIES 65535 +#define LIBLTE_S1AP_MAXPROTOCOLIES 65535 +#define LIBLTE_S1AP_MAXNOOFE_RABS 256 +#define LIBLTE_S1AP_MAXNOOFTACS 256 +#define LIBLTE_S1AP_MAXNOOFBPLMNS 6 +#define LIBLTE_S1AP_MAXNOOFEPLMNS 15 +#define LIBLTE_S1AP_MAXNOOFFORBLACS 4096 +#define LIBLTE_S1AP_MAXNOOFINDIVIDUALS1CONNECTIONSTORESET 256 +#define LIBLTE_S1AP_MAXNOOFTAIFORWARNING 65535 +#define LIBLTE_S1AP_MAXNOOFEMERGENCYAREAID 65535 +#define LIBLTE_S1AP_MAXNOOFCELLINEAI 65535 +#define LIBLTE_S1AP_MAXNOOFENBX2EXTTLAS 16 +#define LIBLTE_S1AP_MAXNOOFRATS 8 +#define LIBLTE_S1AP_MAXNOOFMMECS 256 +#define LIBLTE_S1AP_MAXNOOFTAFORMDT 8 +#define LIBLTE_S1AP_MAXNOOFCELLSFORRESTART 256 +#define LIBLTE_S1AP_MAXNOOFRESTARTEMERGENCYAREAIDS 256 +#define LIBLTE_S1AP_MAXNOOFCSGS 256 +#define LIBLTE_S1AP_MAXNOOFERRORS 256 +#define LIBLTE_S1AP_MAXNOOFEPLMNSPLUSONE 16 +#define LIBLTE_S1AP_MAXNOOFCELLS 16 +#define LIBLTE_S1AP_MAXNOOFCELLINTAI 65535 +#define LIBLTE_S1AP_MAXNOOFENBX2GTPTLAS 16 +#define LIBLTE_S1AP_MAXNOOFCELLIDFORMDT 32 +#define LIBLTE_S1AP_MAXNOOFRESTARTTAIS 2048 +#define LIBLTE_S1AP_MAXPROTOCOLEXTENSIONS 65535 +#define LIBLTE_S1AP_MAXNOOFPLMNSPERMME 32 +#define LIBLTE_S1AP_MAXNOOFCELLID 65535 +#define LIBLTE_S1AP_MAXNOOFGROUPIDS 65535 +#define LIBLTE_S1AP_MAXNOOFTAIS 256 +#define LIBLTE_S1AP_MAXNOOFENBX2TLAS 2 +#define LIBLTE_S1AP_MAXNOOFMDTPLMNS 16 +#define LIBLTE_S1AP_MAXNOOFFORBTACS 4096 + +/******************************************************************************* +/* Elementary Procedures +********************************************************************************/ +typedef enum{ + LIBLTE_S1AP_PROC_ID_HANDOVERPREPARATION = 0, + LIBLTE_S1AP_PROC_ID_HANDOVERRESOURCEALLOCATION = 1, + LIBLTE_S1AP_PROC_ID_HANDOVERNOTIFICATION = 2, + LIBLTE_S1AP_PROC_ID_PATHSWITCHREQUEST = 3, + LIBLTE_S1AP_PROC_ID_HANDOVERCANCEL = 4, + LIBLTE_S1AP_PROC_ID_E_RABSETUP = 5, + LIBLTE_S1AP_PROC_ID_E_RABMODIFY = 6, + LIBLTE_S1AP_PROC_ID_E_RABRELEASE = 7, + LIBLTE_S1AP_PROC_ID_E_RABRELEASEINDICATION = 8, + LIBLTE_S1AP_PROC_ID_INITIALCONTEXTSETUP = 9, + LIBLTE_S1AP_PROC_ID_PAGING = 10, + LIBLTE_S1AP_PROC_ID_DOWNLINKNASTRANSPORT = 11, + LIBLTE_S1AP_PROC_ID_INITIALUEMESSAGE = 12, + LIBLTE_S1AP_PROC_ID_UPLINKNASTRANSPORT = 13, + LIBLTE_S1AP_PROC_ID_RESET = 14, + LIBLTE_S1AP_PROC_ID_ERRORINDICATION = 15, + LIBLTE_S1AP_PROC_ID_NASNONDELIVERYINDICATION = 16, + LIBLTE_S1AP_PROC_ID_S1SETUP = 17, + LIBLTE_S1AP_PROC_ID_UECONTEXTRELEASEREQUEST = 18, + LIBLTE_S1AP_PROC_ID_DOWNLINKS1CDMA2000TUNNELING = 19, + LIBLTE_S1AP_PROC_ID_UPLINKS1CDMA2000TUNNELING = 20, + LIBLTE_S1AP_PROC_ID_UECONTEXTMODIFICATION = 21, + LIBLTE_S1AP_PROC_ID_UECAPABILITYINFOINDICATION = 22, + LIBLTE_S1AP_PROC_ID_UECONTEXTRELEASE = 23, + LIBLTE_S1AP_PROC_ID_ENBSTATUSTRANSFER = 24, + LIBLTE_S1AP_PROC_ID_MMESTATUSTRANSFER = 25, + LIBLTE_S1AP_PROC_ID_DEACTIVATETRACE = 26, + LIBLTE_S1AP_PROC_ID_TRACESTART = 27, + LIBLTE_S1AP_PROC_ID_TRACEFAILUREINDICATION = 28, + LIBLTE_S1AP_PROC_ID_ENBCONFIGURATIONUPDATE = 29, + LIBLTE_S1AP_PROC_ID_MMECONFIGURATIONUPDATE = 30, + LIBLTE_S1AP_PROC_ID_LOCATIONREPORTINGCONTROL = 31, + LIBLTE_S1AP_PROC_ID_LOCATIONREPORTINGFAILUREINDICATION = 32, + LIBLTE_S1AP_PROC_ID_LOCATIONREPORT = 33, + LIBLTE_S1AP_PROC_ID_OVERLOADSTART = 34, + LIBLTE_S1AP_PROC_ID_OVERLOADSTOP = 35, + LIBLTE_S1AP_PROC_ID_WRITEREPLACEWARNING = 36, + LIBLTE_S1AP_PROC_ID_ENBDIRECTINFORMATIONTRANSFER = 37, + LIBLTE_S1AP_PROC_ID_MMEDIRECTINFORMATIONTRANSFER = 38, + LIBLTE_S1AP_PROC_ID_PRIVATEMESSAGE = 39, + LIBLTE_S1AP_PROC_ID_ENBCONFIGURATIONTRANSFER = 40, + LIBLTE_S1AP_PROC_ID_MMECONFIGURATIONTRANSFER = 41, + LIBLTE_S1AP_PROC_ID_CELLTRAFFICTRACE = 42, + LIBLTE_S1AP_PROC_ID_KILL = 43, + LIBLTE_S1AP_PROC_ID_DOWNLINKUEASSOCIATEDLPPATRANSPORT = 44, + LIBLTE_S1AP_PROC_ID_UPLINKUEASSOCIATEDLPPATRANSPORT = 45, + LIBLTE_S1AP_PROC_ID_DOWNLINKNONUEASSOCIATEDLPPATRANSPORT = 46, + LIBLTE_S1AP_PROC_ID_UPLINKNONUEASSOCIATEDLPPATRANSPORT = 47, + LIBLTE_S1AP_PROC_ID_UERADIOCAPABILITYMATCH = 48, + LIBLTE_S1AP_PROC_ID_PWSRESTARTINDICATION = 49, + LIBLTE_S1AP_PROC_N_ITEMS, +}LIBLTE_S1AP_PROC_ENUM; +static const char liblte_s1ap_proc_text[LIBLTE_S1AP_PROC_N_ITEMS][64] = { + "id-HandoverPreparation", + "id-HandoverResourceAllocation", + "id-HandoverNotification", + "id-PathSwitchRequest", + "id-HandoverCancel", + "id-E-RABSetup", + "id-E-RABModify", + "id-E-RABRelease", + "id-E-RABReleaseIndication", + "id-InitialContextSetup", + "id-Paging", + "id-downlinkNASTransport", + "id-initialUEMessage", + "id-uplinkNASTransport", + "id-Reset", + "id-ErrorIndication", + "id-NASNonDeliveryIndication", + "id-S1Setup", + "id-UEContextReleaseRequest", + "id-DownlinkS1cdma2000tunneling", + "id-UplinkS1cdma2000tunneling", + "id-UEContextModification", + "id-UECapabilityInfoIndication", + "id-UEContextRelease", + "id-eNBStatusTransfer", + "id-MMEStatusTransfer", + "id-DeactivateTrace", + "id-TraceStart", + "id-TraceFailureIndication", + "id-ENBConfigurationUpdate", + "id-MMEConfigurationUpdate", + "id-LocationReportingControl", + "id-LocationReportingFailureIndication", + "id-LocationReport", + "id-OverloadStart", + "id-OverloadStop", + "id-WriteReplaceWarning", + "id-eNBDirectInformationTransfer", + "id-MMEDirectInformationTransfer", + "id-PrivateMessage", + "id-eNBConfigurationTransfer", + "id-MMEConfigurationTransfer", + "id-CellTrafficTrace", + "id-Kill", + "id-downlinkUEAssociatedLPPaTransport", + "id-uplinkUEAssociatedLPPaTransport", + "id-downlinkNonUEAssociatedLPPaTransport", + "id-uplinkNonUEAssociatedLPPaTransport", + "id-UERadioCapabilityMatch", + "id-PWSRestartIndication", +}; + + + +/******************************************************************************* +/* ProtocolIE Ids +********************************************************************************/ +typedef enum{ + LIBLTE_S1AP_IE_ID_MME_UE_S1AP_ID = 0, + LIBLTE_S1AP_IE_ID_HANDOVERTYPE = 1, + LIBLTE_S1AP_IE_ID_CAUSE = 2, + LIBLTE_S1AP_IE_ID_SOURCEID = 3, + LIBLTE_S1AP_IE_ID_TARGETID = 4, + LIBLTE_S1AP_IE_ID_SPARE5 = 5, + LIBLTE_S1AP_IE_ID_SPARE6 = 6, + LIBLTE_S1AP_IE_ID_SPARE7 = 7, + LIBLTE_S1AP_IE_ID_ENB_UE_S1AP_ID = 8, + LIBLTE_S1AP_IE_ID_SPARE9 = 9, + LIBLTE_S1AP_IE_ID_SPARE10 = 10, + LIBLTE_S1AP_IE_ID_SPARE11 = 11, + LIBLTE_S1AP_IE_ID_E_RABSUBJECTTODATAFORWARDINGLIST = 12, + LIBLTE_S1AP_IE_ID_E_RABTORELEASELISTHOCMD = 13, + LIBLTE_S1AP_IE_ID_E_RABDATAFORWARDINGITEM = 14, + LIBLTE_S1AP_IE_ID_E_RABRELEASEITEMBEARERRELCOMP = 15, + LIBLTE_S1AP_IE_ID_E_RABTOBESETUPLISTBEARERSUREQ = 16, + LIBLTE_S1AP_IE_ID_E_RABTOBESETUPITEMBEARERSUREQ = 17, + LIBLTE_S1AP_IE_ID_E_RABADMITTEDLIST = 18, + LIBLTE_S1AP_IE_ID_E_RABFAILEDTOSETUPLISTHOREQACK = 19, + LIBLTE_S1AP_IE_ID_E_RABADMITTEDITEM = 20, + LIBLTE_S1AP_IE_ID_E_RABFAILEDTOSETUPITEMHOREQACK = 21, + LIBLTE_S1AP_IE_ID_E_RABTOBESWITCHEDDLLIST = 22, + LIBLTE_S1AP_IE_ID_E_RABTOBESWITCHEDDLITEM = 23, + LIBLTE_S1AP_IE_ID_E_RABTOBESETUPLISTCTXTSUREQ = 24, + LIBLTE_S1AP_IE_ID_TRACEACTIVATION = 25, + LIBLTE_S1AP_IE_ID_NAS_PDU = 26, + LIBLTE_S1AP_IE_ID_E_RABTOBESETUPITEMHOREQ = 27, + LIBLTE_S1AP_IE_ID_E_RABSETUPLISTBEARERSURES = 28, + LIBLTE_S1AP_IE_ID_E_RABFAILEDTOSETUPLISTBEARERSURES = 29, + LIBLTE_S1AP_IE_ID_E_RABTOBEMODIFIEDLISTBEARERMODREQ = 30, + LIBLTE_S1AP_IE_ID_E_RABMODIFYLISTBEARERMODRES = 31, + LIBLTE_S1AP_IE_ID_E_RABFAILEDTOMODIFYLIST = 32, + LIBLTE_S1AP_IE_ID_E_RABTOBERELEASEDLIST = 33, + LIBLTE_S1AP_IE_ID_E_RABFAILEDTORELEASELIST = 34, + LIBLTE_S1AP_IE_ID_E_RABITEM = 35, + LIBLTE_S1AP_IE_ID_E_RABTOBEMODIFIEDITEMBEARERMODREQ = 36, + LIBLTE_S1AP_IE_ID_E_RABMODIFYITEMBEARERMODRES = 37, + LIBLTE_S1AP_IE_ID_E_RABRELEASEITEM = 38, + LIBLTE_S1AP_IE_ID_E_RABSETUPITEMBEARERSURES = 39, + LIBLTE_S1AP_IE_ID_SECURITYCONTEXT = 40, + LIBLTE_S1AP_IE_ID_HANDOVERRESTRICTIONLIST = 41, + LIBLTE_S1AP_IE_ID_SPARE42 = 42, + LIBLTE_S1AP_IE_ID_UEPAGINGID = 43, + LIBLTE_S1AP_IE_ID_PAGINGDRX = 44, + LIBLTE_S1AP_IE_ID_SPARE45 = 45, + LIBLTE_S1AP_IE_ID_TAILIST = 46, + LIBLTE_S1AP_IE_ID_TAIITEM = 47, + LIBLTE_S1AP_IE_ID_E_RABFAILEDTOSETUPLISTCTXTSURES = 48, + LIBLTE_S1AP_IE_ID_E_RABRELEASEITEMHOCMD = 49, + LIBLTE_S1AP_IE_ID_E_RABSETUPITEMCTXTSURES = 50, + LIBLTE_S1AP_IE_ID_E_RABSETUPLISTCTXTSURES = 51, + LIBLTE_S1AP_IE_ID_E_RABTOBESETUPITEMCTXTSUREQ = 52, + LIBLTE_S1AP_IE_ID_E_RABTOBESETUPLISTHOREQ = 53, + LIBLTE_S1AP_IE_ID_SPARE54 = 54, + LIBLTE_S1AP_IE_ID_GERANTOLTEHOINFORMATIONRES = 55, + LIBLTE_S1AP_IE_ID_SPARE56 = 56, + LIBLTE_S1AP_IE_ID_UTRANTOLTEHOINFORMATIONRES = 57, + LIBLTE_S1AP_IE_ID_CRITICALITYDIAGNOSTICS = 58, + LIBLTE_S1AP_IE_ID_GLOBAL_ENB_ID = 59, + LIBLTE_S1AP_IE_ID_ENBNAME = 60, + LIBLTE_S1AP_IE_ID_MMENAME = 61, + LIBLTE_S1AP_IE_ID_SPARE62 = 62, + LIBLTE_S1AP_IE_ID_SERVEDPLMNS = 63, + LIBLTE_S1AP_IE_ID_SUPPORTEDTAS = 64, + LIBLTE_S1AP_IE_ID_TIMETOWAIT = 65, + LIBLTE_S1AP_IE_ID_UEAGGREGATEMAXIMUMBITRATE = 66, + LIBLTE_S1AP_IE_ID_TAI = 67, + LIBLTE_S1AP_IE_ID_SPARE68 = 68, + LIBLTE_S1AP_IE_ID_E_RABRELEASELISTBEARERRELCOMP = 69, + LIBLTE_S1AP_IE_ID_CDMA2000PDU = 70, + LIBLTE_S1AP_IE_ID_CDMA2000RATTYPE = 71, + LIBLTE_S1AP_IE_ID_CDMA2000SECTORID = 72, + LIBLTE_S1AP_IE_ID_SECURITYKEY = 73, + LIBLTE_S1AP_IE_ID_UERADIOCAPABILITY = 74, + LIBLTE_S1AP_IE_ID_GUMMEI_ID = 75, + LIBLTE_S1AP_IE_ID_SPARE76 = 76, + LIBLTE_S1AP_IE_ID_SPARE77 = 77, + LIBLTE_S1AP_IE_ID_E_RABINFORMATIONLISTITEM = 78, + LIBLTE_S1AP_IE_ID_DIRECT_FORWARDING_PATH_AVAILABILITY = 79, + LIBLTE_S1AP_IE_ID_UEIDENTITYINDEXVALUE = 80, + LIBLTE_S1AP_IE_ID_SPARE81 = 81, + LIBLTE_S1AP_IE_ID_SPARE82 = 82, + LIBLTE_S1AP_IE_ID_CDMA2000HOSTATUS = 83, + LIBLTE_S1AP_IE_ID_CDMA2000HOREQUIREDINDICATION = 84, + LIBLTE_S1AP_IE_ID_SPARE85 = 85, + LIBLTE_S1AP_IE_ID_E_UTRAN_TRACE_ID = 86, + LIBLTE_S1AP_IE_ID_RELATIVEMMECAPACITY = 87, + LIBLTE_S1AP_IE_ID_SOURCEMME_UE_S1AP_ID = 88, + LIBLTE_S1AP_IE_ID_BEARERS_SUBJECTTOSTATUSTRANSFER_ITEM = 89, + LIBLTE_S1AP_IE_ID_ENB_STATUSTRANSFER_TRANSPARENTCONTAINER = 90, + LIBLTE_S1AP_IE_ID_UE_ASSOCIATEDLOGICALS1_CONNECTIONITEM = 91, + LIBLTE_S1AP_IE_ID_RESETTYPE = 92, + LIBLTE_S1AP_IE_ID_UE_ASSOCIATEDLOGICALS1_CONNECTIONLISTRESACK = 93, + LIBLTE_S1AP_IE_ID_E_RABTOBESWITCHEDULITEM = 94, + LIBLTE_S1AP_IE_ID_E_RABTOBESWITCHEDULLIST = 95, + LIBLTE_S1AP_IE_ID_S_TMSI = 96, + LIBLTE_S1AP_IE_ID_CDMA2000ONEXRAND = 97, + LIBLTE_S1AP_IE_ID_REQUESTTYPE = 98, + LIBLTE_S1AP_IE_ID_UE_S1AP_IDS = 99, + LIBLTE_S1AP_IE_ID_EUTRAN_CGI = 100, + LIBLTE_S1AP_IE_ID_OVERLOADRESPONSE = 101, + LIBLTE_S1AP_IE_ID_CDMA2000ONEXSRVCCINFO = 102, + LIBLTE_S1AP_IE_ID_E_RABFAILEDTOBERELEASEDLIST = 103, + LIBLTE_S1AP_IE_ID_SOURCE_TOTARGET_TRANSPARENTCONTAINER = 104, + LIBLTE_S1AP_IE_ID_SERVEDGUMMEIS = 105, + LIBLTE_S1AP_IE_ID_SUBSCRIBERPROFILEIDFORRFP = 106, + LIBLTE_S1AP_IE_ID_UESECURITYCAPABILITIES = 107, + LIBLTE_S1AP_IE_ID_CSFALLBACKINDICATOR = 108, + LIBLTE_S1AP_IE_ID_CNDOMAIN = 109, + LIBLTE_S1AP_IE_ID_E_RABRELEASEDLIST = 110, + LIBLTE_S1AP_IE_ID_MESSAGEIDENTIFIER = 111, + LIBLTE_S1AP_IE_ID_SERIALNUMBER = 112, + LIBLTE_S1AP_IE_ID_WARNINGAREALIST = 113, + LIBLTE_S1AP_IE_ID_REPETITIONPERIOD = 114, + LIBLTE_S1AP_IE_ID_NUMBEROFBROADCASTREQUEST = 115, + LIBLTE_S1AP_IE_ID_WARNINGTYPE = 116, + LIBLTE_S1AP_IE_ID_WARNINGSECURITYINFO = 117, + LIBLTE_S1AP_IE_ID_DATACODINGSCHEME = 118, + LIBLTE_S1AP_IE_ID_WARNINGMESSAGECONTENTS = 119, + LIBLTE_S1AP_IE_ID_BROADCASTCOMPLETEDAREALIST = 120, + LIBLTE_S1AP_IE_ID_INTER_SYSTEMINFORMATIONTRANSFERTYPEEDT = 121, + LIBLTE_S1AP_IE_ID_INTER_SYSTEMINFORMATIONTRANSFERTYPEMDT = 122, + LIBLTE_S1AP_IE_ID_TARGET_TOSOURCE_TRANSPARENTCONTAINER = 123, + LIBLTE_S1AP_IE_ID_SRVCCOPERATIONPOSSIBLE = 124, + LIBLTE_S1AP_IE_ID_SRVCCHOINDICATION = 125, + LIBLTE_S1AP_IE_ID_NAS_DOWNLINKCOUNT = 126, + LIBLTE_S1AP_IE_ID_CSG_ID = 127, + LIBLTE_S1AP_IE_ID_CSG_IDLIST = 128, + LIBLTE_S1AP_IE_ID_SONCONFIGURATIONTRANSFERECT = 129, + LIBLTE_S1AP_IE_ID_SONCONFIGURATIONTRANSFERMCT = 130, + LIBLTE_S1AP_IE_ID_TRACECOLLECTIONENTITYIPADDRESS = 131, + LIBLTE_S1AP_IE_ID_MSCLASSMARK2 = 132, + LIBLTE_S1AP_IE_ID_MSCLASSMARK3 = 133, + LIBLTE_S1AP_IE_ID_RRC_ESTABLISHMENT_CAUSE = 134, + LIBLTE_S1AP_IE_ID_NASSECURITYPARAMETERSFROME_UTRAN = 135, + LIBLTE_S1AP_IE_ID_NASSECURITYPARAMETERSTOE_UTRAN = 136, + LIBLTE_S1AP_IE_ID_DEFAULTPAGINGDRX = 137, + LIBLTE_S1AP_IE_ID_SOURCE_TOTARGET_TRANSPARENTCONTAINER_SECONDARY = 138, + LIBLTE_S1AP_IE_ID_TARGET_TOSOURCE_TRANSPARENTCONTAINER_SECONDARY = 139, + LIBLTE_S1AP_IE_ID_EUTRANROUNDTRIPDELAYESTIMATIONINFO = 140, + LIBLTE_S1AP_IE_ID_BROADCASTCANCELLEDAREALIST = 141, + LIBLTE_S1AP_IE_ID_CONCURRENTWARNINGMESSAGEINDICATOR = 142, + LIBLTE_S1AP_IE_ID_DATA_FORWARDING_NOT_POSSIBLE = 143, + LIBLTE_S1AP_IE_ID_EXTENDEDREPETITIONPERIOD = 144, + LIBLTE_S1AP_IE_ID_CELLACCESSMODE = 145, + LIBLTE_S1AP_IE_ID_CSGMEMBERSHIPSTATUS = 146, + LIBLTE_S1AP_IE_ID_LPPA_PDU = 147, + LIBLTE_S1AP_IE_ID_ROUTING_ID = 148, + LIBLTE_S1AP_IE_ID_TIME_SYNCHRONIZATION_INFO = 149, + LIBLTE_S1AP_IE_ID_PS_SERVICENOTAVAILABLE = 150, + LIBLTE_S1AP_IE_ID_PAGINGPRIORITY = 151, + LIBLTE_S1AP_IE_ID_X2TNLCONFIGURATIONINFO = 152, + LIBLTE_S1AP_IE_ID_ENBX2EXTENDEDTRANSPORTLAYERADDRESSES = 153, + LIBLTE_S1AP_IE_ID_GUMMEILIST = 154, + LIBLTE_S1AP_IE_ID_GW_TRANSPORTLAYERADDRESS = 155, + LIBLTE_S1AP_IE_ID_CORRELATION_ID = 156, + LIBLTE_S1AP_IE_ID_SOURCEMME_GUMMEI = 157, + LIBLTE_S1AP_IE_ID_MME_UE_S1AP_ID_2 = 158, + LIBLTE_S1AP_IE_ID_REGISTEREDLAI = 159, + LIBLTE_S1AP_IE_ID_RELAYNODE_INDICATOR = 160, + LIBLTE_S1AP_IE_ID_TRAFFICLOADREDUCTIONINDICATION = 161, + LIBLTE_S1AP_IE_ID_MDTCONFIGURATION = 162, + LIBLTE_S1AP_IE_ID_MMERELAYSUPPORTINDICATOR = 163, + LIBLTE_S1AP_IE_ID_GWCONTEXTRELEASEINDICATION = 164, + LIBLTE_S1AP_IE_ID_MANAGEMENTBASEDMDTALLOWED = 165, + LIBLTE_S1AP_IE_ID_PRIVACYINDICATOR = 166, + LIBLTE_S1AP_IE_ID_TIME_UE_STAYEDINCELL_ENHANCEDGRANULARITY = 167, + LIBLTE_S1AP_IE_ID_HO_CAUSE = 168, + LIBLTE_S1AP_IE_ID_VOICESUPPORTMATCHINDICATOR = 169, + LIBLTE_S1AP_IE_ID_GUMMEITYPE = 170, + LIBLTE_S1AP_IE_ID_M3CONFIGURATION = 171, + LIBLTE_S1AP_IE_ID_M4CONFIGURATION = 172, + LIBLTE_S1AP_IE_ID_M5CONFIGURATION = 173, + LIBLTE_S1AP_IE_ID_MDT_LOCATION_INFO = 174, + LIBLTE_S1AP_IE_ID_MOBILITYINFORMATION = 175, + LIBLTE_S1AP_IE_ID_TUNNEL_INFORMATION_FOR_BBF = 176, + LIBLTE_S1AP_IE_ID_MANAGEMENTBASEDMDTPLMNLIST = 177, + LIBLTE_S1AP_IE_ID_SIGNALLINGBASEDMDTPLMNLIST = 178, + LIBLTE_S1AP_IE_ID_ULCOUNTVALUEEXTENDED = 179, + LIBLTE_S1AP_IE_ID_DLCOUNTVALUEEXTENDED = 180, + LIBLTE_S1AP_IE_ID_RECEIVESTATUSOFULPDCPSDUSEXTENDED = 181, + LIBLTE_S1AP_IE_ID_ECGILISTFORRESTART = 182, + LIBLTE_S1AP_IE_ID_SIPTO_CORRELATION_ID = 183, + LIBLTE_S1AP_IE_ID_SIPTO_L_GW_TRANSPORTLAYERADDRESS = 184, + LIBLTE_S1AP_IE_ID_TRANSPORTINFORMATION = 185, + LIBLTE_S1AP_IE_ID_LHN_ID = 186, + LIBLTE_S1AP_IE_ID_ADDITIONALCSFALLBACKINDICATOR = 187, + LIBLTE_S1AP_IE_ID_TAILISTFORRESTART = 188, + LIBLTE_S1AP_IE_ID_USERLOCATIONINFORMATION = 189, + LIBLTE_S1AP_IE_ID_EMERGENCYAREAIDLISTFORRESTART = 190, + LIBLTE_S1AP_IE_ID_KILLALLWARNINGMESSAGES = 191, + LIBLTE_S1AP_IE_N_ITEMS, +}LIBLTE_S1AP_IE_ENUM; +static const char liblte_s1ap_ie_text[LIBLTE_S1AP_IE_N_ITEMS][64] = { + "id-MME-UE-S1AP-ID", + "id-HandoverType", + "id-Cause", + "id-SourceID", + "id-TargetID", + "id-spare5", + "id-spare6", + "id-spare7", + "id-eNB-UE-S1AP-ID", + "id-spare9", + "id-spare10", + "id-spare11", + "id-E-RABSubjecttoDataForwardingList", + "id-E-RABtoReleaseListHOCmd", + "id-E-RABDataForwardingItem", + "id-E-RABReleaseItemBearerRelComp", + "id-E-RABToBeSetupListBearerSUReq", + "id-E-RABToBeSetupItemBearerSUReq", + "id-E-RABAdmittedList", + "id-E-RABFailedToSetupListHOReqAck", + "id-E-RABAdmittedItem", + "id-E-RABFailedtoSetupItemHOReqAck", + "id-E-RABToBeSwitchedDLList", + "id-E-RABToBeSwitchedDLItem", + "id-E-RABToBeSetupListCtxtSUReq", + "id-TraceActivation", + "id-NAS-PDU", + "id-E-RABToBeSetupItemHOReq", + "id-E-RABSetupListBearerSURes", + "id-E-RABFailedToSetupListBearerSURes", + "id-E-RABToBeModifiedListBearerModReq", + "id-E-RABModifyListBearerModRes", + "id-E-RABFailedToModifyList", + "id-E-RABToBeReleasedList", + "id-E-RABFailedToReleaseList", + "id-E-RABItem", + "id-E-RABToBeModifiedItemBearerModReq", + "id-E-RABModifyItemBearerModRes", + "id-E-RABReleaseItem", + "id-E-RABSetupItemBearerSURes", + "id-SecurityContext", + "id-HandoverRestrictionList", + "id-spare42", + "id-UEPagingID", + "id-pagingDRX", + "id-spare45", + "id-TAIList", + "id-TAIItem", + "id-E-RABFailedToSetupListCtxtSURes", + "id-E-RABReleaseItemHOCmd", + "id-E-RABSetupItemCtxtSURes", + "id-E-RABSetupListCtxtSURes", + "id-E-RABToBeSetupItemCtxtSUReq", + "id-E-RABToBeSetupListHOReq", + "id-spare54", + "id-GERANtoLTEHOInformationRes", + "id-spare56", + "id-UTRANtoLTEHOInformationRes", + "id-CriticalityDiagnostics", + "id-Global-ENB-ID", + "id-eNBname", + "id-MMEname", + "id-spare62", + "id-ServedPLMNs", + "id-SupportedTAs", + "id-TimeToWait", + "id-uEaggregateMaximumBitrate", + "id-TAI", + "id-spare68", + "id-E-RABReleaseListBearerRelComp", + "id-cdma2000PDU", + "id-cdma2000RATType", + "id-cdma2000SectorID", + "id-SecurityKey", + "id-UERadioCapability", + "id-GUMMEI-ID", + "id-spare76", + "id-spare77", + "id-E-RABInformationListItem", + "id-Direct-Forwarding-Path-Availability", + "id-UEIdentityIndexValue", + "id-spare81", + "id-spare82", + "id-cdma2000HOStatus", + "id-cdma2000HORequiredIndication", + "id-spare85", + "id-E-UTRAN-Trace-ID", + "id-RelativeMMECapacity", + "id-SourceMME-UE-S1AP-ID", + "id-Bearers-SubjectToStatusTransfer-Item", + "id-eNB-StatusTransfer-TransparentContainer", + "id-UE-associatedLogicalS1-ConnectionItem", + "id-ResetType", + "id-UE-associatedLogicalS1-ConnectionListResAck", + "id-E-RABToBeSwitchedULItem", + "id-E-RABToBeSwitchedULList", + "id-S-TMSI", + "id-cdma2000OneXRAND", + "id-RequestType", + "id-UE-S1AP-IDs", + "id-EUTRAN-CGI", + "id-OverloadResponse", + "id-cdma2000OneXSRVCCInfo", + "id-E-RABFailedToBeReleasedList", + "id-Source-ToTarget-TransparentContainer", + "id-ServedGUMMEIs", + "id-SubscriberProfileIDforRFP", + "id-UESecurityCapabilities", + "id-CSFallbackIndicator", + "id-CNDomain", + "id-E-RABReleasedList", + "id-MessageIdentifier", + "id-SerialNumber", + "id-WarningAreaList", + "id-RepetitionPeriod", + "id-NumberofBroadcastRequest", + "id-WarningType", + "id-WarningSecurityInfo", + "id-DataCodingScheme", + "id-WarningMessageContents", + "id-BroadcastCompletedAreaList", + "id-Inter-SystemInformationTransferTypeEDT", + "id-Inter-SystemInformationTransferTypeMDT", + "id-Target-ToSource-TransparentContainer", + "id-SRVCCOperationPossible", + "id-SRVCCHOIndication", + "id-NAS-DownlinkCount", + "id-CSG-Id", + "id-CSG-IdList", + "id-SONConfigurationTransferECT", + "id-SONConfigurationTransferMCT", + "id-TraceCollectionEntityIPAddress", + "id-MSClassmark2", + "id-MSClassmark3", + "id-RRC-Establishment-Cause", + "id-NASSecurityParametersfromE-UTRAN", + "id-NASSecurityParameterstoE-UTRAN", + "id-DefaultPagingDRX", + "id-Source-ToTarget-TransparentContainer-Secondary", + "id-Target-ToSource-TransparentContainer-Secondary", + "id-EUTRANRoundTripDelayEstimationInfo", + "id-BroadcastCancelledAreaList", + "id-ConcurrentWarningMessageIndicator", + "id-Data-Forwarding-Not-Possible", + "id-ExtendedRepetitionPeriod", + "id-CellAccessMode", + "id-CSGMembershipStatus", + "id-LPPa-PDU", + "id-Routing-ID", + "id-Time-Synchronization-Info", + "id-PS-ServiceNotAvailable", + "id-PagingPriority", + "id-x2TNLConfigurationInfo", + "id-eNBX2ExtendedTransportLayerAddresses", + "id-GUMMEIList", + "id-GW-TransportLayerAddress", + "id-Correlation-ID", + "id-SourceMME-GUMMEI", + "id-MME-UE-S1AP-ID-2", + "id-RegisteredLAI", + "id-RelayNode-Indicator", + "id-TrafficLoadReductionIndication", + "id-MDTConfiguration", + "id-MMERelaySupportIndicator", + "id-GWContextReleaseIndication", + "id-ManagementBasedMDTAllowed", + "id-PrivacyIndicator", + "id-Time-UE-StayedInCell-EnhancedGranularity", + "id-HO-Cause", + "id-VoiceSupportMatchIndicator", + "id-GUMMEIType", + "id-M3Configuration", + "id-M4Configuration", + "id-M5Configuration", + "id-MDT-Location-Info", + "id-MobilityInformation", + "id-Tunnel-Information-for-BBF", + "id-ManagementBasedMDTPLMNList", + "id-SignallingBasedMDTPLMNList", + "id-ULCOUNTValueExtended", + "id-DLCOUNTValueExtended", + "id-ReceiveStatusOfULPDCPSDUsExtended", + "id-ECGIListForRestart", + "id-SIPTO-Correlation-ID", + "id-SIPTO-L-GW-TransportLayerAddress", + "id-TransportInformation", + "id-LHN-ID", + "id-AdditionalCSFallbackIndicator", + "id-TAIListForRestart", + "id-UserLocationInformation", + "id-EmergencyAreaIDListForRestart", + "id-KillAllWarningMessages", +}; + + +/******************************************************************************* +/* ProtocolIE Criticality ENUMERATED +********************************************************************************/ +typedef enum{ + LIBLTE_S1AP_CRITICALITY_REJECT, + LIBLTE_S1AP_CRITICALITY_IGNORE, + LIBLTE_S1AP_CRITICALITY_NOTIFY, + LIBLTE_S1AP_CRITICALITY_N_ITEMS, +}LIBLTE_S1AP_CRITICALITY_ENUM; +static const char liblte_s1ap_criticality_text[LIBLTE_S1AP_CRITICALITY_N_ITEMS][80] = { + "reject", + "ignore", + "notify", +}; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_criticality( + LIBLTE_S1AP_CRITICALITY_ENUM *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_criticality( + uint8_t **ptr, + LIBLTE_S1AP_CRITICALITY_ENUM *ie); + +/******************************************************************************* +/* ProtocolIE local INTEGER +********************************************************************************/ +typedef struct{ +uint16_t local; +}LIBLTE_S1AP_LOCAL_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_local( + LIBLTE_S1AP_LOCAL_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_local( + uint8_t **ptr, + LIBLTE_S1AP_LOCAL_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE PrivateIE_ID CHOICE +********************************************************************************/ +typedef enum{ + LIBLTE_S1AP_PRIVATEIE_ID_CHOICE_LOCAL, + LIBLTE_S1AP_PRIVATEIE_ID_CHOICE_GLOBAL, + LIBLTE_S1AP_PRIVATEIE_ID_CHOICE_N_ITEMS, +}LIBLTE_S1AP_PRIVATEIE_ID_CHOICE_ENUM; +static const char liblte_s1ap_privateie_id_choice_text[LIBLTE_S1AP_PRIVATEIE_ID_CHOICE_N_ITEMS][50] = { + "local", + "global", +}; + +typedef union{ + LIBLTE_S1AP_LOCAL_STRUCT local; + LIBLTE_ASN1_OID_STRUCT global; +}LIBLTE_S1AP_PRIVATEIE_ID_CHOICE_UNION; + +typedef struct{ + LIBLTE_S1AP_PRIVATEIE_ID_CHOICE_UNION choice; + LIBLTE_S1AP_PRIVATEIE_ID_CHOICE_ENUM choice_type; +}LIBLTE_S1AP_PRIVATEIE_ID_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_privateie_id( + LIBLTE_S1AP_PRIVATEIE_ID_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_privateie_id( + uint8_t **ptr, + LIBLTE_S1AP_PRIVATEIE_ID_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE ProtocolExtensionID INTEGER +********************************************************************************/ +typedef struct{ +uint16_t ProtocolExtensionID; +}LIBLTE_S1AP_PROTOCOLEXTENSIONID_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_protocolextensionid( + LIBLTE_S1AP_PROTOCOLEXTENSIONID_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_protocolextensionid( + uint8_t **ptr, + LIBLTE_S1AP_PROTOCOLEXTENSIONID_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE TriggeringMessage ENUMERATED +********************************************************************************/ +typedef enum{ + LIBLTE_S1AP_TRIGGERINGMESSAGE_INITIATING_MESSAGE, + LIBLTE_S1AP_TRIGGERINGMESSAGE_SUCCESSFUL_OUTCOME, + LIBLTE_S1AP_TRIGGERINGMESSAGE_UNSUCCESSFULL_OUTCOME, + LIBLTE_S1AP_TRIGGERINGMESSAGE_N_ITEMS, +}LIBLTE_S1AP_TRIGGERINGMESSAGE_ENUM; +static const char liblte_s1ap_triggeringmessage_text[LIBLTE_S1AP_TRIGGERINGMESSAGE_N_ITEMS][80] = { + "initiating-message", + "successful-outcome", + "unsuccessfull-outcome", +}; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_triggeringmessage( + LIBLTE_S1AP_TRIGGERINGMESSAGE_ENUM *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_triggeringmessage( + uint8_t **ptr, + LIBLTE_S1AP_TRIGGERINGMESSAGE_ENUM *ie); + +/******************************************************************************* +/* ProtocolIE Presence ENUMERATED +********************************************************************************/ +typedef enum{ + LIBLTE_S1AP_PRESENCE_OPTIONAL, + LIBLTE_S1AP_PRESENCE_CONDITIONAL, + LIBLTE_S1AP_PRESENCE_MANDATORY, + LIBLTE_S1AP_PRESENCE_N_ITEMS, +}LIBLTE_S1AP_PRESENCE_ENUM; +static const char liblte_s1ap_presence_text[LIBLTE_S1AP_PRESENCE_N_ITEMS][80] = { + "optional", + "conditional", + "mandatory", +}; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_presence( + LIBLTE_S1AP_PRESENCE_ENUM *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_presence( + uint8_t **ptr, + LIBLTE_S1AP_PRESENCE_ENUM *ie); + +/******************************************************************************* +/* ProtocolIE ProtocolIE_ID INTEGER +********************************************************************************/ +typedef struct{ +uint16_t ProtocolIE_ID; +}LIBLTE_S1AP_PROTOCOLIE_ID_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_protocolie_id( + LIBLTE_S1AP_PROTOCOLIE_ID_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_protocolie_id( + uint8_t **ptr, + LIBLTE_S1AP_PROTOCOLIE_ID_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE ProcedureCode INTEGER +********************************************************************************/ +typedef struct{ +uint8_t ProcedureCode; +}LIBLTE_S1AP_PROCEDURECODE_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_procedurecode( + LIBLTE_S1AP_PROCEDURECODE_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_procedurecode( + uint8_t **ptr, + LIBLTE_S1AP_PROCEDURECODE_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE ProtocolIE_Field SEQUENCE +********************************************************************************/ +typedef struct{ + LIBLTE_S1AP_PROTOCOLIE_ID_STRUCT id; + LIBLTE_S1AP_CRITICALITY_ENUM criticality; + LIBLTE_ASN1_OPEN_TYPE_STRUCT value; +}LIBLTE_S1AP_PROTOCOLIE_FIELD_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_protocolie_field( + LIBLTE_S1AP_PROTOCOLIE_FIELD_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_protocolie_field( + uint8_t **ptr, + LIBLTE_S1AP_PROTOCOLIE_FIELD_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE ProtocolExtensionField SEQUENCE +********************************************************************************/ +typedef struct{ + LIBLTE_S1AP_PROTOCOLEXTENSIONID_STRUCT id; + LIBLTE_S1AP_CRITICALITY_ENUM criticality; + LIBLTE_ASN1_OPEN_TYPE_STRUCT extensionValue; +}LIBLTE_S1AP_PROTOCOLEXTENSIONFIELD_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_protocolextensionfield( + LIBLTE_S1AP_PROTOCOLEXTENSIONFIELD_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_protocolextensionfield( + uint8_t **ptr, + LIBLTE_S1AP_PROTOCOLEXTENSIONFIELD_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE ProtocolIE_FieldPair SEQUENCE +********************************************************************************/ +typedef struct{ + LIBLTE_S1AP_PROTOCOLIE_ID_STRUCT id; + LIBLTE_S1AP_CRITICALITY_ENUM firstCriticality; + LIBLTE_ASN1_OPEN_TYPE_STRUCT firstValue; + LIBLTE_S1AP_CRITICALITY_ENUM secondCriticality; + LIBLTE_ASN1_OPEN_TYPE_STRUCT secondValue; +}LIBLTE_S1AP_PROTOCOLIE_FIELDPAIR_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_protocolie_fieldpair( + LIBLTE_S1AP_PROTOCOLIE_FIELDPAIR_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_protocolie_fieldpair( + uint8_t **ptr, + LIBLTE_S1AP_PROTOCOLIE_FIELDPAIR_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE ProtocolExtensionContainer DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:65535 +typedef struct{ + uint32_t len; + LIBLTE_S1AP_PROTOCOLEXTENSIONFIELD_STRUCT buffer[32]; //WARNING: Artificial limit to reduce memory footprint +}LIBLTE_S1AP_PROTOCOLEXTENSIONCONTAINER_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_protocolextensioncontainer( + LIBLTE_S1AP_PROTOCOLEXTENSIONCONTAINER_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_protocolextensioncontainer( + uint8_t **ptr, + LIBLTE_S1AP_PROTOCOLEXTENSIONCONTAINER_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE ProtocolIE_ContainerPair DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:0, ub:65535 +typedef struct{ + uint32_t len; + LIBLTE_S1AP_PROTOCOLIE_FIELDPAIR_STRUCT buffer[32]; //WARNING: Artificial limit to reduce memory footprint +}LIBLTE_S1AP_PROTOCOLIE_CONTAINERPAIR_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_protocolie_containerpair( + LIBLTE_S1AP_PROTOCOLIE_CONTAINERPAIR_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_protocolie_containerpair( + uint8_t **ptr, + LIBLTE_S1AP_PROTOCOLIE_CONTAINERPAIR_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE ProtocolIE_ContainerPairList DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:None, ub:None +typedef struct{ + uint32_t len; + LIBLTE_S1AP_PROTOCOLIE_CONTAINERPAIR_STRUCT buffer[32]; //WARNING: Artificial limit to reduce memory footprint +}LIBLTE_S1AP_PROTOCOLIE_CONTAINERPAIRLIST_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_protocolie_containerpairlist( + LIBLTE_S1AP_PROTOCOLIE_CONTAINERPAIRLIST_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_protocolie_containerpairlist( + uint8_t **ptr, + LIBLTE_S1AP_PROTOCOLIE_CONTAINERPAIRLIST_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE PrivateIE_Field SEQUENCE +********************************************************************************/ +typedef struct{ + LIBLTE_S1AP_PRIVATEIE_ID_STRUCT id; + LIBLTE_S1AP_CRITICALITY_ENUM criticality; + LIBLTE_ASN1_OPEN_TYPE_STRUCT value; +}LIBLTE_S1AP_PRIVATEIE_FIELD_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_privateie_field( + LIBLTE_S1AP_PRIVATEIE_FIELD_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_privateie_field( + uint8_t **ptr, + LIBLTE_S1AP_PRIVATEIE_FIELD_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE ProtocolIE_SingleContainer SEQUENCE +********************************************************************************/ +typedef struct{ + LIBLTE_S1AP_PROTOCOLIE_ID_STRUCT id; + LIBLTE_S1AP_CRITICALITY_ENUM criticality; + LIBLTE_ASN1_OPEN_TYPE_STRUCT value; +}LIBLTE_S1AP_PROTOCOLIE_SINGLECONTAINER_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_protocolie_singlecontainer( + LIBLTE_S1AP_PROTOCOLIE_SINGLECONTAINER_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_protocolie_singlecontainer( + uint8_t **ptr, + LIBLTE_S1AP_PROTOCOLIE_SINGLECONTAINER_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE PrivateIE_Container DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:65535 +typedef struct{ + uint32_t len; + LIBLTE_S1AP_PRIVATEIE_FIELD_STRUCT buffer[32]; //WARNING: Artificial limit to reduce memory footprint +}LIBLTE_S1AP_PRIVATEIE_CONTAINER_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_privateie_container( + LIBLTE_S1AP_PRIVATEIE_CONTAINER_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_privateie_container( + uint8_t **ptr, + LIBLTE_S1AP_PRIVATEIE_CONTAINER_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE BitRate INTEGER +********************************************************************************/ +typedef struct{ +uint32_t BitRate; +}LIBLTE_S1AP_BITRATE_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_bitrate( + LIBLTE_S1AP_BITRATE_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_bitrate( + uint8_t **ptr, + LIBLTE_S1AP_BITRATE_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE CauseMisc ENUMERATED +********************************************************************************/ +typedef enum{ + LIBLTE_S1AP_CAUSEMISC_CONTROL_PROCESSING_OVERLOAD, + LIBLTE_S1AP_CAUSEMISC_NOT_ENOUGH_USER_PLANE_PROCESSING_RESOURCES, + LIBLTE_S1AP_CAUSEMISC_HARDWARE_FAILURE, + LIBLTE_S1AP_CAUSEMISC_OM_INTERVENTION, + LIBLTE_S1AP_CAUSEMISC_UNSPECIFIED, + LIBLTE_S1AP_CAUSEMISC_UNKNOWN_PLMN, + LIBLTE_S1AP_CAUSEMISC_N_ITEMS, +}LIBLTE_S1AP_CAUSEMISC_ENUM; +static const char liblte_s1ap_causemisc_text[LIBLTE_S1AP_CAUSEMISC_N_ITEMS][80] = { + "control-processing-overload", + "not-enough-user-plane-processing-resources", + "hardware-failure", + "om-intervention", + "unspecified", + "unknown-PLMN", +}; + +typedef struct{ + bool ext; + LIBLTE_S1AP_CAUSEMISC_ENUM e; +}LIBLTE_S1AP_CAUSEMISC_ENUM_EXT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_causemisc( + LIBLTE_S1AP_CAUSEMISC_ENUM_EXT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_causemisc( + uint8_t **ptr, + LIBLTE_S1AP_CAUSEMISC_ENUM_EXT *ie); + +/******************************************************************************* +/* ProtocolIE CauseRadioNetwork ENUMERATED +********************************************************************************/ +typedef enum{ + LIBLTE_S1AP_CAUSERADIONETWORK_UNSPECIFIED, + LIBLTE_S1AP_CAUSERADIONETWORK_TX2RELOCOVERALL_EXPIRY, + LIBLTE_S1AP_CAUSERADIONETWORK_SUCCESSFUL_HANDOVER, + LIBLTE_S1AP_CAUSERADIONETWORK_RELEASE_DUE_TO_EUTRAN_GENERATED_REASON, + LIBLTE_S1AP_CAUSERADIONETWORK_HANDOVER_CANCELLED, + LIBLTE_S1AP_CAUSERADIONETWORK_PARTIAL_HANDOVER, + LIBLTE_S1AP_CAUSERADIONETWORK_HO_FAILURE_IN_TARGET_EPC_ENB_OR_TARGET_SYSTEM, + LIBLTE_S1AP_CAUSERADIONETWORK_HO_TARGET_NOT_ALLOWED, + LIBLTE_S1AP_CAUSERADIONETWORK_TS1RELOCOVERALL_EXPIRY, + LIBLTE_S1AP_CAUSERADIONETWORK_TS1RELOCPREP_EXPIRY, + LIBLTE_S1AP_CAUSERADIONETWORK_CELL_NOT_AVAILABLE, + LIBLTE_S1AP_CAUSERADIONETWORK_UNKNOWN_TARGETID, + LIBLTE_S1AP_CAUSERADIONETWORK_NO_RADIO_RESOURCES_AVAILABLE_IN_TARGET_CELL, + LIBLTE_S1AP_CAUSERADIONETWORK_UNKNOWN_MME_UE_S1AP_ID, + LIBLTE_S1AP_CAUSERADIONETWORK_UNKNOWN_ENB_UE_S1AP_ID, + LIBLTE_S1AP_CAUSERADIONETWORK_UNKNOWN_PAIR_UE_S1AP_ID, + LIBLTE_S1AP_CAUSERADIONETWORK_HANDOVER_DESIRABLE_FOR_RADIO_REASON, + LIBLTE_S1AP_CAUSERADIONETWORK_TIME_CRITICAL_HANDOVER, + LIBLTE_S1AP_CAUSERADIONETWORK_RESOURCE_OPTIMISATION_HANDOVER, + LIBLTE_S1AP_CAUSERADIONETWORK_REDUCE_LOAD_IN_SERVING_CELL, + LIBLTE_S1AP_CAUSERADIONETWORK_USER_INACTIVITY, + LIBLTE_S1AP_CAUSERADIONETWORK_RADIO_CONNECTION_WITH_UE_LOST, + LIBLTE_S1AP_CAUSERADIONETWORK_LOAD_BALANCING_TAU_REQUIRED, + LIBLTE_S1AP_CAUSERADIONETWORK_CS_FALLBACK_TRIGGERED, + LIBLTE_S1AP_CAUSERADIONETWORK_UE_NOT_AVAILABLE_FOR_PS_SERVICE, + LIBLTE_S1AP_CAUSERADIONETWORK_RADIO_RESOURCES_NOT_AVAILABLE, + LIBLTE_S1AP_CAUSERADIONETWORK_FAILURE_IN_RADIO_INTERFACE_PROCEDURE, + LIBLTE_S1AP_CAUSERADIONETWORK_INVALID_QOS_COMBINATION, + LIBLTE_S1AP_CAUSERADIONETWORK_INTERRAT_REDIRECTION, + LIBLTE_S1AP_CAUSERADIONETWORK_INTERACTION_WITH_OTHER_PROCEDURE, + LIBLTE_S1AP_CAUSERADIONETWORK_UNKNOWN_E_RAB_ID, + LIBLTE_S1AP_CAUSERADIONETWORK_MULTIPLE_E_RAB_ID_INSTANCES, + LIBLTE_S1AP_CAUSERADIONETWORK_ENCRYPTION_AND_OR_INTEGRITY_PROTECTION_ALGORITHMS_NOT_SUPPORTED, + LIBLTE_S1AP_CAUSERADIONETWORK_S1_INTRA_SYSTEM_HANDOVER_TRIGGERED, + LIBLTE_S1AP_CAUSERADIONETWORK_S1_INTER_SYSTEM_HANDOVER_TRIGGERED, + LIBLTE_S1AP_CAUSERADIONETWORK_X2_HANDOVER_TRIGGERED, + LIBLTE_S1AP_CAUSERADIONETWORK_REDIRECTION_TOWARDS_1XRTT, + LIBLTE_S1AP_CAUSERADIONETWORK_NOT_SUPPORTED_QCI_VALUE, + LIBLTE_S1AP_CAUSERADIONETWORK_INVALID_CSG_ID, + LIBLTE_S1AP_CAUSERADIONETWORK_N_ITEMS, +}LIBLTE_S1AP_CAUSERADIONETWORK_ENUM; +static const char liblte_s1ap_causeradionetwork_text[LIBLTE_S1AP_CAUSERADIONETWORK_N_ITEMS][80] = { + "unspecified", + "tx2relocoverall-expiry", + "successful-handover", + "release-due-to-eutran-generated-reason", + "handover-cancelled", + "partial-handover", + "ho-failure-in-target-EPC-eNB-or-target-system", + "ho-target-not-allowed", + "tS1relocoverall-expiry", + "tS1relocprep-expiry", + "cell-not-available", + "unknown-targetID", + "no-radio-resources-available-in-target-cell", + "unknown-mme-ue-s1ap-id", + "unknown-enb-ue-s1ap-id", + "unknown-pair-ue-s1ap-id", + "handover-desirable-for-radio-reason", + "time-critical-handover", + "resource-optimisation-handover", + "reduce-load-in-serving-cell", + "user-inactivity", + "radio-connection-with-ue-lost", + "load-balancing-tau-required", + "cs-fallback-triggered", + "ue-not-available-for-ps-service", + "radio-resources-not-available", + "failure-in-radio-interface-procedure", + "invalid-qos-combination", + "interrat-redirection", + "interaction-with-other-procedure", + "unknown-E-RAB-ID", + "multiple-E-RAB-ID-instances", + "encryption-and-or-integrity-protection-algorithms-not-supported", + "s1-intra-system-handover-triggered", + "s1-inter-system-handover-triggered", + "x2-handover-triggered", + "redirection-towards-1xRTT", + "not-supported-QCI-value", + "invalid-CSG-Id", +}; + +typedef struct{ + bool ext; + LIBLTE_S1AP_CAUSERADIONETWORK_ENUM e; +}LIBLTE_S1AP_CAUSERADIONETWORK_ENUM_EXT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_causeradionetwork( + LIBLTE_S1AP_CAUSERADIONETWORK_ENUM_EXT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_causeradionetwork( + uint8_t **ptr, + LIBLTE_S1AP_CAUSERADIONETWORK_ENUM_EXT *ie); + +/******************************************************************************* +/* ProtocolIE CauseNas ENUMERATED +********************************************************************************/ +typedef enum{ + LIBLTE_S1AP_CAUSENAS_NORMAL_RELEASE, + LIBLTE_S1AP_CAUSENAS_AUTHENTICATION_FAILURE, + LIBLTE_S1AP_CAUSENAS_DETACH, + LIBLTE_S1AP_CAUSENAS_UNSPECIFIED, + LIBLTE_S1AP_CAUSENAS_CSG_SUBSCRIPTION_EXPIRY, + LIBLTE_S1AP_CAUSENAS_N_ITEMS, +}LIBLTE_S1AP_CAUSENAS_ENUM; +static const char liblte_s1ap_causenas_text[LIBLTE_S1AP_CAUSENAS_N_ITEMS][80] = { + "normal-release", + "authentication-failure", + "detach", + "unspecified", + "csg-subscription-expiry", +}; + +typedef struct{ + bool ext; + LIBLTE_S1AP_CAUSENAS_ENUM e; +}LIBLTE_S1AP_CAUSENAS_ENUM_EXT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_causenas( + LIBLTE_S1AP_CAUSENAS_ENUM_EXT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_causenas( + uint8_t **ptr, + LIBLTE_S1AP_CAUSENAS_ENUM_EXT *ie); + +/******************************************************************************* +/* ProtocolIE CellIdentity STATIC BIT STRING +********************************************************************************/ +#define LIBLTE_S1AP_CELLIDENTITY_BIT_STRING_LEN 28 +typedef struct{ + uint8_t buffer[28]; +}LIBLTE_S1AP_CELLIDENTITY_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_cellidentity( + LIBLTE_S1AP_CELLIDENTITY_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_cellidentity( + uint8_t **ptr, + LIBLTE_S1AP_CELLIDENTITY_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE Cdma2000PDU DYNAMIC OCTET STRING +********************************************************************************/ +// lb:0, ub:16318 +typedef struct{ + uint32_t n_octets; + uint8_t buffer[16318]; +}LIBLTE_S1AP_CDMA2000PDU_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_cdma2000pdu( + LIBLTE_S1AP_CDMA2000PDU_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_cdma2000pdu( + uint8_t **ptr, + LIBLTE_S1AP_CDMA2000PDU_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE Cdma2000SectorID DYNAMIC OCTET STRING +********************************************************************************/ +// lb:0, ub:16318 +typedef struct{ + uint32_t n_octets; + uint8_t buffer[16318]; +}LIBLTE_S1AP_CDMA2000SECTORID_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_cdma2000sectorid( + LIBLTE_S1AP_CDMA2000SECTORID_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_cdma2000sectorid( + uint8_t **ptr, + LIBLTE_S1AP_CDMA2000SECTORID_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE Cdma2000HORequiredIndication ENUMERATED +********************************************************************************/ +typedef enum{ + LIBLTE_S1AP_CDMA2000HOREQUIREDINDICATION_TRUE, + LIBLTE_S1AP_CDMA2000HOREQUIREDINDICATION_N_ITEMS, +}LIBLTE_S1AP_CDMA2000HOREQUIREDINDICATION_ENUM; +static const char liblte_s1ap_cdma2000horequiredindication_text[LIBLTE_S1AP_CDMA2000HOREQUIREDINDICATION_N_ITEMS][80] = { + "true", +}; + +typedef struct{ + bool ext; + LIBLTE_S1AP_CDMA2000HOREQUIREDINDICATION_ENUM e; +}LIBLTE_S1AP_CDMA2000HOREQUIREDINDICATION_ENUM_EXT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_cdma2000horequiredindication( + LIBLTE_S1AP_CDMA2000HOREQUIREDINDICATION_ENUM_EXT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_cdma2000horequiredindication( + uint8_t **ptr, + LIBLTE_S1AP_CDMA2000HOREQUIREDINDICATION_ENUM_EXT *ie); + +/******************************************************************************* +/* ProtocolIE Cdma2000OneXMSI DYNAMIC OCTET STRING +********************************************************************************/ +// lb:0, ub:16318 +typedef struct{ + uint32_t n_octets; + uint8_t buffer[16318]; +}LIBLTE_S1AP_CDMA2000ONEXMSI_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_cdma2000onexmsi( + LIBLTE_S1AP_CDMA2000ONEXMSI_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_cdma2000onexmsi( + uint8_t **ptr, + LIBLTE_S1AP_CDMA2000ONEXMSI_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE Cdma2000OneXRAND DYNAMIC OCTET STRING +********************************************************************************/ +// lb:0, ub:16318 +typedef struct{ + uint32_t n_octets; + uint8_t buffer[16318]; +}LIBLTE_S1AP_CDMA2000ONEXRAND_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_cdma2000onexrand( + LIBLTE_S1AP_CDMA2000ONEXRAND_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_cdma2000onexrand( + uint8_t **ptr, + LIBLTE_S1AP_CDMA2000ONEXRAND_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE CNDomain ENUMERATED +********************************************************************************/ +typedef enum{ + LIBLTE_S1AP_CNDOMAIN_PS, + LIBLTE_S1AP_CNDOMAIN_CS, + LIBLTE_S1AP_CNDOMAIN_N_ITEMS, +}LIBLTE_S1AP_CNDOMAIN_ENUM; +static const char liblte_s1ap_cndomain_text[LIBLTE_S1AP_CNDOMAIN_N_ITEMS][80] = { + "ps", + "cs", +}; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_cndomain( + LIBLTE_S1AP_CNDOMAIN_ENUM *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_cndomain( + uint8_t **ptr, + LIBLTE_S1AP_CNDOMAIN_ENUM *ie); + +/******************************************************************************* +/* ProtocolIE Correlation_ID STATIC OCTET STRING +********************************************************************************/ +#define LIBLTE_S1AP_CORRELATION_ID_OCTET_STRING_LEN 4 +typedef struct{ + uint8_t buffer[4]; +}LIBLTE_S1AP_CORRELATION_ID_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_correlation_id( + LIBLTE_S1AP_CORRELATION_ID_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_correlation_id( + uint8_t **ptr, + LIBLTE_S1AP_CORRELATION_ID_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE AdditionalCSFallbackIndicator ENUMERATED +********************************************************************************/ +typedef enum{ + LIBLTE_S1AP_ADDITIONALCSFALLBACKINDICATOR_NO_RESTRICTION, + LIBLTE_S1AP_ADDITIONALCSFALLBACKINDICATOR_RESTRICTION, + LIBLTE_S1AP_ADDITIONALCSFALLBACKINDICATOR_N_ITEMS, +}LIBLTE_S1AP_ADDITIONALCSFALLBACKINDICATOR_ENUM; +static const char liblte_s1ap_additionalcsfallbackindicator_text[LIBLTE_S1AP_ADDITIONALCSFALLBACKINDICATOR_N_ITEMS][80] = { + "no-restriction", + "restriction", +}; + +typedef struct{ + bool ext; + LIBLTE_S1AP_ADDITIONALCSFALLBACKINDICATOR_ENUM e; +}LIBLTE_S1AP_ADDITIONALCSFALLBACKINDICATOR_ENUM_EXT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_additionalcsfallbackindicator( + LIBLTE_S1AP_ADDITIONALCSFALLBACKINDICATOR_ENUM_EXT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_additionalcsfallbackindicator( + uint8_t **ptr, + LIBLTE_S1AP_ADDITIONALCSFALLBACKINDICATOR_ENUM_EXT *ie); + +/******************************************************************************* +/* ProtocolIE DL_Forwarding ENUMERATED +********************************************************************************/ +typedef enum{ + LIBLTE_S1AP_DL_FORWARDING_DL_FORWARDING_PROPOSED, + LIBLTE_S1AP_DL_FORWARDING_N_ITEMS, +}LIBLTE_S1AP_DL_FORWARDING_ENUM; +static const char liblte_s1ap_dl_forwarding_text[LIBLTE_S1AP_DL_FORWARDING_N_ITEMS][80] = { + "dL-Forwarding-proposed", +}; + +typedef struct{ + bool ext; + LIBLTE_S1AP_DL_FORWARDING_ENUM e; +}LIBLTE_S1AP_DL_FORWARDING_ENUM_EXT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_dl_forwarding( + LIBLTE_S1AP_DL_FORWARDING_ENUM_EXT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_dl_forwarding( + uint8_t **ptr, + LIBLTE_S1AP_DL_FORWARDING_ENUM_EXT *ie); + +/******************************************************************************* +/* ProtocolIE Data_Forwarding_Not_Possible ENUMERATED +********************************************************************************/ +typedef enum{ + LIBLTE_S1AP_DATA_FORWARDING_NOT_POSSIBLE_DATA_FORWARDING_NOT_POSSIBLE, + LIBLTE_S1AP_DATA_FORWARDING_NOT_POSSIBLE_N_ITEMS, +}LIBLTE_S1AP_DATA_FORWARDING_NOT_POSSIBLE_ENUM; +static const char liblte_s1ap_data_forwarding_not_possible_text[LIBLTE_S1AP_DATA_FORWARDING_NOT_POSSIBLE_N_ITEMS][80] = { + "data-Forwarding-not-Possible", +}; + +typedef struct{ + bool ext; + LIBLTE_S1AP_DATA_FORWARDING_NOT_POSSIBLE_ENUM e; +}LIBLTE_S1AP_DATA_FORWARDING_NOT_POSSIBLE_ENUM_EXT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_data_forwarding_not_possible( + LIBLTE_S1AP_DATA_FORWARDING_NOT_POSSIBLE_ENUM_EXT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_data_forwarding_not_possible( + uint8_t **ptr, + LIBLTE_S1AP_DATA_FORWARDING_NOT_POSSIBLE_ENUM_EXT *ie); + +/******************************************************************************* +/* ProtocolIE EmergencyAreaID STATIC OCTET STRING +********************************************************************************/ +#define LIBLTE_S1AP_EMERGENCYAREAID_OCTET_STRING_LEN 3 +typedef struct{ + uint8_t buffer[3]; +}LIBLTE_S1AP_EMERGENCYAREAID_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_emergencyareaid( + LIBLTE_S1AP_EMERGENCYAREAID_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_emergencyareaid( + uint8_t **ptr, + LIBLTE_S1AP_EMERGENCYAREAID_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE macroENB_ID STATIC BIT STRING +********************************************************************************/ +#define LIBLTE_S1AP_MACROENB_ID_BIT_STRING_LEN 20 +typedef struct{ + uint8_t buffer[20]; +}LIBLTE_S1AP_MACROENB_ID_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_macroenb_id( + LIBLTE_S1AP_MACROENB_ID_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_macroenb_id( + uint8_t **ptr, + LIBLTE_S1AP_MACROENB_ID_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE homeENB_ID STATIC BIT STRING +********************************************************************************/ +#define LIBLTE_S1AP_HOMEENB_ID_BIT_STRING_LEN 28 +typedef struct{ + uint8_t buffer[28]; +}LIBLTE_S1AP_HOMEENB_ID_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_homeenb_id( + LIBLTE_S1AP_HOMEENB_ID_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_homeenb_id( + uint8_t **ptr, + LIBLTE_S1AP_HOMEENB_ID_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE ENB_ID CHOICE +********************************************************************************/ +typedef enum{ + LIBLTE_S1AP_ENB_ID_CHOICE_MACROENB_ID, + LIBLTE_S1AP_ENB_ID_CHOICE_HOMEENB_ID, + LIBLTE_S1AP_ENB_ID_CHOICE_N_ITEMS, +}LIBLTE_S1AP_ENB_ID_CHOICE_ENUM; +static const char liblte_s1ap_enb_id_choice_text[LIBLTE_S1AP_ENB_ID_CHOICE_N_ITEMS][50] = { + "macroENB_ID", + "homeENB_ID", +}; + +typedef union{ + LIBLTE_S1AP_MACROENB_ID_STRUCT macroENB_ID; + LIBLTE_S1AP_HOMEENB_ID_STRUCT homeENB_ID; +}LIBLTE_S1AP_ENB_ID_CHOICE_UNION; + +typedef struct{ + bool ext; + LIBLTE_S1AP_ENB_ID_CHOICE_UNION choice; + LIBLTE_S1AP_ENB_ID_CHOICE_ENUM choice_type; +}LIBLTE_S1AP_ENB_ID_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_enb_id( + LIBLTE_S1AP_ENB_ID_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_enb_id( + uint8_t **ptr, + LIBLTE_S1AP_ENB_ID_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE ENBname PrintableString +********************************************************************************/ +typedef struct{ + bool ext; + uint32_t n_octets; + uint8_t buffer[150]; +}LIBLTE_S1AP_ENBNAME_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_enbname( + LIBLTE_S1AP_ENBNAME_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_enbname( + uint8_t **ptr, + LIBLTE_S1AP_ENBNAME_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE EncryptionAlgorithms STATIC BIT STRING +********************************************************************************/ +#define LIBLTE_S1AP_ENCRYPTIONALGORITHMS_BIT_STRING_LEN 16 +typedef struct{ + bool ext; + uint8_t buffer[16]; +}LIBLTE_S1AP_ENCRYPTIONALGORITHMS_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_encryptionalgorithms( + LIBLTE_S1AP_ENCRYPTIONALGORITHMS_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_encryptionalgorithms( + uint8_t **ptr, + LIBLTE_S1AP_ENCRYPTIONALGORITHMS_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE EventType ENUMERATED +********************************************************************************/ +typedef enum{ + LIBLTE_S1AP_EVENTTYPE_DIRECT, + LIBLTE_S1AP_EVENTTYPE_CHANGE_OF_SERVE_CELL, + LIBLTE_S1AP_EVENTTYPE_STOP_CHANGE_OF_SERVE_CELL, + LIBLTE_S1AP_EVENTTYPE_N_ITEMS, +}LIBLTE_S1AP_EVENTTYPE_ENUM; +static const char liblte_s1ap_eventtype_text[LIBLTE_S1AP_EVENTTYPE_N_ITEMS][80] = { + "direct", + "change-of-serve-cell", + "stop-change-of-serve-cell", +}; + +typedef struct{ + bool ext; + LIBLTE_S1AP_EVENTTYPE_ENUM e; +}LIBLTE_S1AP_EVENTTYPE_ENUM_EXT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_eventtype( + LIBLTE_S1AP_EVENTTYPE_ENUM_EXT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_eventtype( + uint8_t **ptr, + LIBLTE_S1AP_EVENTTYPE_ENUM_EXT *ie); + +/******************************************************************************* +/* ProtocolIE ExtendedRNC_ID INTEGER +********************************************************************************/ +typedef struct{ +uint16_t ExtendedRNC_ID; +}LIBLTE_S1AP_EXTENDEDRNC_ID_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_extendedrnc_id( + LIBLTE_S1AP_EXTENDEDRNC_ID_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_extendedrnc_id( + uint8_t **ptr, + LIBLTE_S1AP_EXTENDEDRNC_ID_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE ForbiddenInterRATs ENUMERATED +********************************************************************************/ +typedef enum{ + LIBLTE_S1AP_FORBIDDENINTERRATS_ALL, + LIBLTE_S1AP_FORBIDDENINTERRATS_GERAN, + LIBLTE_S1AP_FORBIDDENINTERRATS_UTRAN, + LIBLTE_S1AP_FORBIDDENINTERRATS_CDMA2000, + LIBLTE_S1AP_FORBIDDENINTERRATS_GERANANDUTRAN, + LIBLTE_S1AP_FORBIDDENINTERRATS_CDMA2000ANDUTRAN, + LIBLTE_S1AP_FORBIDDENINTERRATS_N_ITEMS, +}LIBLTE_S1AP_FORBIDDENINTERRATS_ENUM; +static const char liblte_s1ap_forbiddeninterrats_text[LIBLTE_S1AP_FORBIDDENINTERRATS_N_ITEMS][80] = { + "all", + "geran", + "utran", + "cdma2000", + "geranandutran", + "cdma2000andutran", +}; + +typedef struct{ + bool ext; + LIBLTE_S1AP_FORBIDDENINTERRATS_ENUM e; +}LIBLTE_S1AP_FORBIDDENINTERRATS_ENUM_EXT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_forbiddeninterrats( + LIBLTE_S1AP_FORBIDDENINTERRATS_ENUM_EXT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_forbiddeninterrats( + uint8_t **ptr, + LIBLTE_S1AP_FORBIDDENINTERRATS_ENUM_EXT *ie); + +/******************************************************************************* +/* ProtocolIE GWContextReleaseIndication ENUMERATED +********************************************************************************/ +typedef enum{ + LIBLTE_S1AP_GWCONTEXTRELEASEINDICATION_TRUE, + LIBLTE_S1AP_GWCONTEXTRELEASEINDICATION_N_ITEMS, +}LIBLTE_S1AP_GWCONTEXTRELEASEINDICATION_ENUM; +static const char liblte_s1ap_gwcontextreleaseindication_text[LIBLTE_S1AP_GWCONTEXTRELEASEINDICATION_N_ITEMS][80] = { + "true", +}; + +typedef struct{ + bool ext; + LIBLTE_S1AP_GWCONTEXTRELEASEINDICATION_ENUM e; +}LIBLTE_S1AP_GWCONTEXTRELEASEINDICATION_ENUM_EXT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_gwcontextreleaseindication( + LIBLTE_S1AP_GWCONTEXTRELEASEINDICATION_ENUM_EXT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_gwcontextreleaseindication( + uint8_t **ptr, + LIBLTE_S1AP_GWCONTEXTRELEASEINDICATION_ENUM_EXT *ie); + +/******************************************************************************* +/* ProtocolIE HFN INTEGER +********************************************************************************/ +typedef struct{ +uint32_t HFN; +}LIBLTE_S1AP_HFN_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_hfn( + LIBLTE_S1AP_HFN_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_hfn( + uint8_t **ptr, + LIBLTE_S1AP_HFN_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE IMSI DYNAMIC OCTET STRING +********************************************************************************/ +// lb:3, ub:8 +typedef struct{ + uint32_t n_octets; + uint8_t buffer[8]; +}LIBLTE_S1AP_IMSI_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_imsi( + LIBLTE_S1AP_IMSI_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_imsi( + uint8_t **ptr, + LIBLTE_S1AP_IMSI_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE InterfacesToTrace STATIC BIT STRING +********************************************************************************/ +#define LIBLTE_S1AP_INTERFACESTOTRACE_BIT_STRING_LEN 8 +typedef struct{ + uint8_t buffer[8]; +}LIBLTE_S1AP_INTERFACESTOTRACE_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_interfacestotrace( + LIBLTE_S1AP_INTERFACESTOTRACE_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_interfacestotrace( + uint8_t **ptr, + LIBLTE_S1AP_INTERFACESTOTRACE_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE LAC STATIC OCTET STRING +********************************************************************************/ +#define LIBLTE_S1AP_LAC_OCTET_STRING_LEN 2 +typedef struct{ + uint8_t buffer[2]; +}LIBLTE_S1AP_LAC_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_lac( + LIBLTE_S1AP_LAC_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_lac( + uint8_t **ptr, + LIBLTE_S1AP_LAC_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE LastVisitedUTRANCellInformation DYNAMIC OCTET STRING +********************************************************************************/ +// lb:0, ub:16318 +typedef struct{ + uint32_t n_octets; + uint8_t buffer[16318]; +}LIBLTE_S1AP_LASTVISITEDUTRANCELLINFORMATION_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_lastvisitedutrancellinformation( + LIBLTE_S1AP_LASTVISITEDUTRANCELLINFORMATION_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_lastvisitedutrancellinformation( + uint8_t **ptr, + LIBLTE_S1AP_LASTVISITEDUTRANCELLINFORMATION_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE L3_Information DYNAMIC OCTET STRING +********************************************************************************/ +// lb:0, ub:16318 +typedef struct{ + uint32_t n_octets; + uint8_t buffer[16318]; +}LIBLTE_S1AP_L3_INFORMATION_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_l3_information( + LIBLTE_S1AP_L3_INFORMATION_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_l3_information( + uint8_t **ptr, + LIBLTE_S1AP_L3_INFORMATION_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE LHN_ID DYNAMIC OCTET STRING +********************************************************************************/ +// lb:32, ub:256 +typedef struct{ + uint32_t n_octets; + uint8_t buffer[256]; +}LIBLTE_S1AP_LHN_ID_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_lhn_id( + LIBLTE_S1AP_LHN_ID_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_lhn_id( + uint8_t **ptr, + LIBLTE_S1AP_LHN_ID_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE LoggingDuration ENUMERATED +********************************************************************************/ +typedef enum{ + LIBLTE_S1AP_LOGGINGDURATION_M10, + LIBLTE_S1AP_LOGGINGDURATION_M20, + LIBLTE_S1AP_LOGGINGDURATION_M40, + LIBLTE_S1AP_LOGGINGDURATION_M60, + LIBLTE_S1AP_LOGGINGDURATION_M90, + LIBLTE_S1AP_LOGGINGDURATION_M120, + LIBLTE_S1AP_LOGGINGDURATION_N_ITEMS, +}LIBLTE_S1AP_LOGGINGDURATION_ENUM; +static const char liblte_s1ap_loggingduration_text[LIBLTE_S1AP_LOGGINGDURATION_N_ITEMS][80] = { + "m10", + "m20", + "m40", + "m60", + "m90", + "m120", +}; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_loggingduration( + LIBLTE_S1AP_LOGGINGDURATION_ENUM *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_loggingduration( + uint8_t **ptr, + LIBLTE_S1AP_LOGGINGDURATION_ENUM *ie); + +/******************************************************************************* +/* ProtocolIE MDT_Activation ENUMERATED +********************************************************************************/ +typedef enum{ + LIBLTE_S1AP_MDT_ACTIVATION_IMMEDIATE_MDT_ONLY, + LIBLTE_S1AP_MDT_ACTIVATION_IMMEDIATE_MDT_AND_TRACE, + LIBLTE_S1AP_MDT_ACTIVATION_LOGGED_MDT_ONLY, + LIBLTE_S1AP_MDT_ACTIVATION_N_ITEMS, +}LIBLTE_S1AP_MDT_ACTIVATION_ENUM; +static const char liblte_s1ap_mdt_activation_text[LIBLTE_S1AP_MDT_ACTIVATION_N_ITEMS][80] = { + "immediate-MDT-only", + "immediate-MDT-and-Trace", + "logged-MDT-only", +}; + +typedef struct{ + bool ext; + LIBLTE_S1AP_MDT_ACTIVATION_ENUM e; +}LIBLTE_S1AP_MDT_ACTIVATION_ENUM_EXT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_mdt_activation( + LIBLTE_S1AP_MDT_ACTIVATION_ENUM_EXT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_mdt_activation( + uint8_t **ptr, + LIBLTE_S1AP_MDT_ACTIVATION_ENUM_EXT *ie); + +/******************************************************************************* +/* ProtocolIE ManagementBasedMDTAllowed ENUMERATED +********************************************************************************/ +typedef enum{ + LIBLTE_S1AP_MANAGEMENTBASEDMDTALLOWED_ALLOWED, + LIBLTE_S1AP_MANAGEMENTBASEDMDTALLOWED_N_ITEMS, +}LIBLTE_S1AP_MANAGEMENTBASEDMDTALLOWED_ENUM; +static const char liblte_s1ap_managementbasedmdtallowed_text[LIBLTE_S1AP_MANAGEMENTBASEDMDTALLOWED_N_ITEMS][80] = { + "allowed", +}; + +typedef struct{ + bool ext; + LIBLTE_S1AP_MANAGEMENTBASEDMDTALLOWED_ENUM e; +}LIBLTE_S1AP_MANAGEMENTBASEDMDTALLOWED_ENUM_EXT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_managementbasedmdtallowed( + LIBLTE_S1AP_MANAGEMENTBASEDMDTALLOWED_ENUM_EXT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_managementbasedmdtallowed( + uint8_t **ptr, + LIBLTE_S1AP_MANAGEMENTBASEDMDTALLOWED_ENUM_EXT *ie); + +/******************************************************************************* +/* ProtocolIE PrivacyIndicator ENUMERATED +********************************************************************************/ +typedef enum{ + LIBLTE_S1AP_PRIVACYINDICATOR_IMMEDIATE_MDT, + LIBLTE_S1AP_PRIVACYINDICATOR_LOGGED_MDT, + LIBLTE_S1AP_PRIVACYINDICATOR_N_ITEMS, +}LIBLTE_S1AP_PRIVACYINDICATOR_ENUM; +static const char liblte_s1ap_privacyindicator_text[LIBLTE_S1AP_PRIVACYINDICATOR_N_ITEMS][80] = { + "immediate-MDT", + "logged-MDT", +}; + +typedef struct{ + bool ext; + LIBLTE_S1AP_PRIVACYINDICATOR_ENUM e; +}LIBLTE_S1AP_PRIVACYINDICATOR_ENUM_EXT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_privacyindicator( + LIBLTE_S1AP_PRIVACYINDICATOR_ENUM_EXT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_privacyindicator( + uint8_t **ptr, + LIBLTE_S1AP_PRIVACYINDICATOR_ENUM_EXT *ie); + +/******************************************************************************* +/* ProtocolIE MeasurementsToActivate STATIC BIT STRING +********************************************************************************/ +#define LIBLTE_S1AP_MEASUREMENTSTOACTIVATE_BIT_STRING_LEN 8 +typedef struct{ + uint8_t buffer[8]; +}LIBLTE_S1AP_MEASUREMENTSTOACTIVATE_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_measurementstoactivate( + LIBLTE_S1AP_MEASUREMENTSTOACTIVATE_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_measurementstoactivate( + uint8_t **ptr, + LIBLTE_S1AP_MEASUREMENTSTOACTIVATE_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE MessageIdentifier STATIC BIT STRING +********************************************************************************/ +#define LIBLTE_S1AP_MESSAGEIDENTIFIER_BIT_STRING_LEN 16 +typedef struct{ + uint8_t buffer[16]; +}LIBLTE_S1AP_MESSAGEIDENTIFIER_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_messageidentifier( + LIBLTE_S1AP_MESSAGEIDENTIFIER_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_messageidentifier( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGEIDENTIFIER_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE MMEname PrintableString +********************************************************************************/ +typedef struct{ + bool ext; + uint32_t n_octets; + uint8_t buffer[150]; +}LIBLTE_S1AP_MMENAME_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_mmename( + LIBLTE_S1AP_MMENAME_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_mmename( + uint8_t **ptr, + LIBLTE_S1AP_MMENAME_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE MME_Group_ID STATIC OCTET STRING +********************************************************************************/ +#define LIBLTE_S1AP_MME_GROUP_ID_OCTET_STRING_LEN 2 +typedef struct{ + uint8_t buffer[2]; +}LIBLTE_S1AP_MME_GROUP_ID_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_mme_group_id( + LIBLTE_S1AP_MME_GROUP_ID_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_mme_group_id( + uint8_t **ptr, + LIBLTE_S1AP_MME_GROUP_ID_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE MME_UE_S1AP_ID INTEGER +********************************************************************************/ +typedef struct{ +uint32_t MME_UE_S1AP_ID; +}LIBLTE_S1AP_MME_UE_S1AP_ID_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_mme_ue_s1ap_id( + LIBLTE_S1AP_MME_UE_S1AP_ID_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_mme_ue_s1ap_id( + uint8_t **ptr, + LIBLTE_S1AP_MME_UE_S1AP_ID_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE MSClassmark2 DYNAMIC OCTET STRING +********************************************************************************/ +// lb:0, ub:16318 +typedef struct{ + uint32_t n_octets; + uint8_t buffer[16318]; +}LIBLTE_S1AP_MSCLASSMARK2_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_msclassmark2( + LIBLTE_S1AP_MSCLASSMARK2_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_msclassmark2( + uint8_t **ptr, + LIBLTE_S1AP_MSCLASSMARK2_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE NAS_PDU DYNAMIC OCTET STRING +********************************************************************************/ +// lb:0, ub:16318 +typedef struct{ + uint32_t n_octets; + uint8_t buffer[16318]; +}LIBLTE_S1AP_NAS_PDU_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_nas_pdu( + LIBLTE_S1AP_NAS_PDU_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_nas_pdu( + uint8_t **ptr, + LIBLTE_S1AP_NAS_PDU_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE NASSecurityParameterstoE_UTRAN DYNAMIC OCTET STRING +********************************************************************************/ +// lb:0, ub:16318 +typedef struct{ + uint32_t n_octets; + uint8_t buffer[16318]; +}LIBLTE_S1AP_NASSECURITYPARAMETERSTOE_UTRAN_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_nassecurityparameterstoe_utran( + LIBLTE_S1AP_NASSECURITYPARAMETERSTOE_UTRAN_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_nassecurityparameterstoe_utran( + uint8_t **ptr, + LIBLTE_S1AP_NASSECURITYPARAMETERSTOE_UTRAN_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE NumberOfBroadcasts INTEGER +********************************************************************************/ +typedef struct{ +uint16_t NumberOfBroadcasts; +}LIBLTE_S1AP_NUMBEROFBROADCASTS_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_numberofbroadcasts( + LIBLTE_S1AP_NUMBEROFBROADCASTS_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_numberofbroadcasts( + uint8_t **ptr, + LIBLTE_S1AP_NUMBEROFBROADCASTS_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE OverloadAction ENUMERATED +********************************************************************************/ +typedef enum{ + LIBLTE_S1AP_OVERLOADACTION_REJECT_NON_EMERGENCY_MO_DT, + LIBLTE_S1AP_OVERLOADACTION_REJECT_RRC_CR_SIGNALLING, + LIBLTE_S1AP_OVERLOADACTION_PERMIT_EMERGENCY_SESSIONS_AND_MOBILE_TERMINATED_SERVICES_ONLY, + LIBLTE_S1AP_OVERLOADACTION_PERMIT_HIGH_PRIORITY_SESSIONS_AND_MOBILE_TERMINATED_SERVICES_ONLY, + LIBLTE_S1AP_OVERLOADACTION_REJECT_DELAY_TOLERANT_ACCESS, + LIBLTE_S1AP_OVERLOADACTION_N_ITEMS, +}LIBLTE_S1AP_OVERLOADACTION_ENUM; +static const char liblte_s1ap_overloadaction_text[LIBLTE_S1AP_OVERLOADACTION_N_ITEMS][80] = { + "reject-non-emergency-mo-dt", + "reject-rrc-cr-signalling", + "permit-emergency-sessions-and-mobile-terminated-services-only", + "permit-high-priority-sessions-and-mobile-terminated-services-only", + "reject-delay-tolerant-access", +}; + +typedef struct{ + bool ext; + LIBLTE_S1AP_OVERLOADACTION_ENUM e; +}LIBLTE_S1AP_OVERLOADACTION_ENUM_EXT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_overloadaction( + LIBLTE_S1AP_OVERLOADACTION_ENUM_EXT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_overloadaction( + uint8_t **ptr, + LIBLTE_S1AP_OVERLOADACTION_ENUM_EXT *ie); + +/******************************************************************************* +/* ProtocolIE PagingDRX ENUMERATED +********************************************************************************/ +typedef enum{ + LIBLTE_S1AP_PAGINGDRX_V32, + LIBLTE_S1AP_PAGINGDRX_V64, + LIBLTE_S1AP_PAGINGDRX_V128, + LIBLTE_S1AP_PAGINGDRX_V256, + LIBLTE_S1AP_PAGINGDRX_N_ITEMS, +}LIBLTE_S1AP_PAGINGDRX_ENUM; +static const char liblte_s1ap_pagingdrx_text[LIBLTE_S1AP_PAGINGDRX_N_ITEMS][80] = { + "v32", + "v64", + "v128", + "v256", +}; + +typedef struct{ + bool ext; + LIBLTE_S1AP_PAGINGDRX_ENUM e; +}LIBLTE_S1AP_PAGINGDRX_ENUM_EXT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_pagingdrx( + LIBLTE_S1AP_PAGINGDRX_ENUM_EXT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_pagingdrx( + uint8_t **ptr, + LIBLTE_S1AP_PAGINGDRX_ENUM_EXT *ie); + +/******************************************************************************* +/* ProtocolIE PDCP_SN INTEGER +********************************************************************************/ +typedef struct{ +uint16_t PDCP_SN; +}LIBLTE_S1AP_PDCP_SN_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_pdcp_sn( + LIBLTE_S1AP_PDCP_SN_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_pdcp_sn( + uint8_t **ptr, + LIBLTE_S1AP_PDCP_SN_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE Port_Number STATIC OCTET STRING +********************************************************************************/ +#define LIBLTE_S1AP_PORT_NUMBER_OCTET_STRING_LEN 2 +typedef struct{ + uint8_t buffer[2]; +}LIBLTE_S1AP_PORT_NUMBER_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_port_number( + LIBLTE_S1AP_PORT_NUMBER_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_port_number( + uint8_t **ptr, + LIBLTE_S1AP_PORT_NUMBER_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE Pre_emptionVulnerability ENUMERATED +********************************************************************************/ +typedef enum{ + LIBLTE_S1AP_PRE_EMPTIONVULNERABILITY_NOT_PRE_EMPTABLE, + LIBLTE_S1AP_PRE_EMPTIONVULNERABILITY_PRE_EMPTABLE, + LIBLTE_S1AP_PRE_EMPTIONVULNERABILITY_N_ITEMS, +}LIBLTE_S1AP_PRE_EMPTIONVULNERABILITY_ENUM; +static const char liblte_s1ap_pre_emptionvulnerability_text[LIBLTE_S1AP_PRE_EMPTIONVULNERABILITY_N_ITEMS][80] = { + "not-pre-emptable", + "pre-emptable", +}; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_pre_emptionvulnerability( + LIBLTE_S1AP_PRE_EMPTIONVULNERABILITY_ENUM *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_pre_emptionvulnerability( + uint8_t **ptr, + LIBLTE_S1AP_PRE_EMPTIONVULNERABILITY_ENUM *ie); + +/******************************************************************************* +/* ProtocolIE PS_ServiceNotAvailable ENUMERATED +********************************************************************************/ +typedef enum{ + LIBLTE_S1AP_PS_SERVICENOTAVAILABLE_PS_SERVICE_NOT_AVAILABLE, + LIBLTE_S1AP_PS_SERVICENOTAVAILABLE_N_ITEMS, +}LIBLTE_S1AP_PS_SERVICENOTAVAILABLE_ENUM; +static const char liblte_s1ap_ps_servicenotavailable_text[LIBLTE_S1AP_PS_SERVICENOTAVAILABLE_N_ITEMS][80] = { + "ps-service-not-available", +}; + +typedef struct{ + bool ext; + LIBLTE_S1AP_PS_SERVICENOTAVAILABLE_ENUM e; +}LIBLTE_S1AP_PS_SERVICENOTAVAILABLE_ENUM_EXT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_ps_servicenotavailable( + LIBLTE_S1AP_PS_SERVICENOTAVAILABLE_ENUM_EXT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_ps_servicenotavailable( + uint8_t **ptr, + LIBLTE_S1AP_PS_SERVICENOTAVAILABLE_ENUM_EXT *ie); + +/******************************************************************************* +/* ProtocolIE ReceiveStatusofULPDCPSDUs STATIC BIT STRING +********************************************************************************/ +#define LIBLTE_S1AP_RECEIVESTATUSOFULPDCPSDUS_BIT_STRING_LEN 4096 +typedef struct{ + uint8_t buffer[4096]; +}LIBLTE_S1AP_RECEIVESTATUSOFULPDCPSDUS_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_receivestatusofulpdcpsdus( + LIBLTE_S1AP_RECEIVESTATUSOFULPDCPSDUS_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_receivestatusofulpdcpsdus( + uint8_t **ptr, + LIBLTE_S1AP_RECEIVESTATUSOFULPDCPSDUS_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE RelativeMMECapacity INTEGER +********************************************************************************/ +typedef struct{ +uint8_t RelativeMMECapacity; +}LIBLTE_S1AP_RELATIVEMMECAPACITY_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_relativemmecapacity( + LIBLTE_S1AP_RELATIVEMMECAPACITY_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_relativemmecapacity( + uint8_t **ptr, + LIBLTE_S1AP_RELATIVEMMECAPACITY_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE RAC STATIC OCTET STRING +********************************************************************************/ +#define LIBLTE_S1AP_RAC_OCTET_STRING_LEN 1 +typedef struct{ + uint8_t buffer[1]; +}LIBLTE_S1AP_RAC_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_rac( + LIBLTE_S1AP_RAC_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_rac( + uint8_t **ptr, + LIBLTE_S1AP_RAC_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE ReportIntervalMDT ENUMERATED +********************************************************************************/ +typedef enum{ + LIBLTE_S1AP_REPORTINTERVALMDT_MS120, + LIBLTE_S1AP_REPORTINTERVALMDT_MS240, + LIBLTE_S1AP_REPORTINTERVALMDT_MS480, + LIBLTE_S1AP_REPORTINTERVALMDT_MS640, + LIBLTE_S1AP_REPORTINTERVALMDT_MS1024, + LIBLTE_S1AP_REPORTINTERVALMDT_MS2048, + LIBLTE_S1AP_REPORTINTERVALMDT_MS5120, + LIBLTE_S1AP_REPORTINTERVALMDT_MS10240, + LIBLTE_S1AP_REPORTINTERVALMDT_MIN1, + LIBLTE_S1AP_REPORTINTERVALMDT_MIN6, + LIBLTE_S1AP_REPORTINTERVALMDT_MIN12, + LIBLTE_S1AP_REPORTINTERVALMDT_MIN30, + LIBLTE_S1AP_REPORTINTERVALMDT_MIN60, + LIBLTE_S1AP_REPORTINTERVALMDT_N_ITEMS, +}LIBLTE_S1AP_REPORTINTERVALMDT_ENUM; +static const char liblte_s1ap_reportintervalmdt_text[LIBLTE_S1AP_REPORTINTERVALMDT_N_ITEMS][80] = { + "ms120", + "ms240", + "ms480", + "ms640", + "ms1024", + "ms2048", + "ms5120", + "ms10240", + "min1", + "min6", + "min12", + "min30", + "min60", +}; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_reportintervalmdt( + LIBLTE_S1AP_REPORTINTERVALMDT_ENUM *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_reportintervalmdt( + uint8_t **ptr, + LIBLTE_S1AP_REPORTINTERVALMDT_ENUM *ie); + +/******************************************************************************* +/* ProtocolIE ReportArea ENUMERATED +********************************************************************************/ +typedef enum{ + LIBLTE_S1AP_REPORTAREA_ECGI, + LIBLTE_S1AP_REPORTAREA_N_ITEMS, +}LIBLTE_S1AP_REPORTAREA_ENUM; +static const char liblte_s1ap_reportarea_text[LIBLTE_S1AP_REPORTAREA_N_ITEMS][80] = { + "ecgi", +}; + +typedef struct{ + bool ext; + LIBLTE_S1AP_REPORTAREA_ENUM e; +}LIBLTE_S1AP_REPORTAREA_ENUM_EXT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_reportarea( + LIBLTE_S1AP_REPORTAREA_ENUM_EXT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_reportarea( + uint8_t **ptr, + LIBLTE_S1AP_REPORTAREA_ENUM_EXT *ie); + +/******************************************************************************* +/* ProtocolIE RNC_ID INTEGER +********************************************************************************/ +typedef struct{ +uint16_t RNC_ID; +}LIBLTE_S1AP_RNC_ID_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_rnc_id( + LIBLTE_S1AP_RNC_ID_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_rnc_id( + uint8_t **ptr, + LIBLTE_S1AP_RNC_ID_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE RRC_Establishment_Cause ENUMERATED +********************************************************************************/ +typedef enum{ + LIBLTE_S1AP_RRC_ESTABLISHMENT_CAUSE_EMERGENCY, + LIBLTE_S1AP_RRC_ESTABLISHMENT_CAUSE_HIGHPRIORITYACCESS, + LIBLTE_S1AP_RRC_ESTABLISHMENT_CAUSE_MT_ACCESS, + LIBLTE_S1AP_RRC_ESTABLISHMENT_CAUSE_MO_SIGNALLING, + LIBLTE_S1AP_RRC_ESTABLISHMENT_CAUSE_MO_DATA, + LIBLTE_S1AP_RRC_ESTABLISHMENT_CAUSE_DELAY_TOLERANTACCESS, + LIBLTE_S1AP_RRC_ESTABLISHMENT_CAUSE_N_ITEMS, +}LIBLTE_S1AP_RRC_ESTABLISHMENT_CAUSE_ENUM; +static const char liblte_s1ap_rrc_establishment_cause_text[LIBLTE_S1AP_RRC_ESTABLISHMENT_CAUSE_N_ITEMS][80] = { + "emergency", + "highPriorityAccess", + "mt-Access", + "mo-Signalling", + "mo-Data", + "delay-TolerantAccess", +}; + +typedef struct{ + bool ext; + LIBLTE_S1AP_RRC_ESTABLISHMENT_CAUSE_ENUM e; +}LIBLTE_S1AP_RRC_ESTABLISHMENT_CAUSE_ENUM_EXT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_rrc_establishment_cause( + LIBLTE_S1AP_RRC_ESTABLISHMENT_CAUSE_ENUM_EXT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_rrc_establishment_cause( + uint8_t **ptr, + LIBLTE_S1AP_RRC_ESTABLISHMENT_CAUSE_ENUM_EXT *ie); + +/******************************************************************************* +/* ProtocolIE Routing_ID INTEGER +********************************************************************************/ +typedef struct{ +uint8_t Routing_ID; +}LIBLTE_S1AP_ROUTING_ID_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_routing_id( + LIBLTE_S1AP_ROUTING_ID_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_routing_id( + uint8_t **ptr, + LIBLTE_S1AP_ROUTING_ID_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE SONInformationRequest ENUMERATED +********************************************************************************/ +typedef enum{ + LIBLTE_S1AP_SONINFORMATIONREQUEST_X2TNL_CONFIGURATION_INFO, + LIBLTE_S1AP_SONINFORMATIONREQUEST_TIME_SYNCHRONIZATION_INFO, + LIBLTE_S1AP_SONINFORMATIONREQUEST_N_ITEMS, +}LIBLTE_S1AP_SONINFORMATIONREQUEST_ENUM; +static const char liblte_s1ap_soninformationrequest_text[LIBLTE_S1AP_SONINFORMATIONREQUEST_N_ITEMS][80] = { + "x2TNL-Configuration-Info", + "time-Synchronization-Info", +}; + +typedef struct{ + bool ext; + LIBLTE_S1AP_SONINFORMATIONREQUEST_ENUM e; +}LIBLTE_S1AP_SONINFORMATIONREQUEST_ENUM_EXT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_soninformationrequest( + LIBLTE_S1AP_SONINFORMATIONREQUEST_ENUM_EXT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_soninformationrequest( + uint8_t **ptr, + LIBLTE_S1AP_SONINFORMATIONREQUEST_ENUM_EXT *ie); + +/******************************************************************************* +/* ProtocolIE Source_ToTarget_TransparentContainer DYNAMIC OCTET STRING +********************************************************************************/ +// lb:0, ub:16318 +typedef struct{ + uint32_t n_octets; + uint8_t buffer[16318]; +}LIBLTE_S1AP_SOURCE_TOTARGET_TRANSPARENTCONTAINER_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_source_totarget_transparentcontainer( + LIBLTE_S1AP_SOURCE_TOTARGET_TRANSPARENTCONTAINER_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_source_totarget_transparentcontainer( + uint8_t **ptr, + LIBLTE_S1AP_SOURCE_TOTARGET_TRANSPARENTCONTAINER_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE SRVCCHOIndication ENUMERATED +********************************************************************************/ +typedef enum{ + LIBLTE_S1AP_SRVCCHOINDICATION_PSANDCS, + LIBLTE_S1AP_SRVCCHOINDICATION_CSONLY, + LIBLTE_S1AP_SRVCCHOINDICATION_N_ITEMS, +}LIBLTE_S1AP_SRVCCHOINDICATION_ENUM; +static const char liblte_s1ap_srvcchoindication_text[LIBLTE_S1AP_SRVCCHOINDICATION_N_ITEMS][80] = { + "pSandCS", + "cSonly", +}; + +typedef struct{ + bool ext; + LIBLTE_S1AP_SRVCCHOINDICATION_ENUM e; +}LIBLTE_S1AP_SRVCCHOINDICATION_ENUM_EXT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_srvcchoindication( + LIBLTE_S1AP_SRVCCHOINDICATION_ENUM_EXT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_srvcchoindication( + uint8_t **ptr, + LIBLTE_S1AP_SRVCCHOINDICATION_ENUM_EXT *ie); + +/******************************************************************************* +/* ProtocolIE SourceRNC_ToTargetRNC_TransparentContainer DYNAMIC OCTET STRING +********************************************************************************/ +// lb:0, ub:16318 +typedef struct{ + uint32_t n_octets; + uint8_t buffer[16318]; +}LIBLTE_S1AP_SOURCERNC_TOTARGETRNC_TRANSPARENTCONTAINER_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_sourcernc_totargetrnc_transparentcontainer( + LIBLTE_S1AP_SOURCERNC_TOTARGETRNC_TRANSPARENTCONTAINER_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_sourcernc_totargetrnc_transparentcontainer( + uint8_t **ptr, + LIBLTE_S1AP_SOURCERNC_TOTARGETRNC_TRANSPARENTCONTAINER_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE SubscriberProfileIDforRFP INTEGER +********************************************************************************/ +typedef struct{ +uint8_t SubscriberProfileIDforRFP; +}LIBLTE_S1AP_SUBSCRIBERPROFILEIDFORRFP_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_subscriberprofileidforrfp( + LIBLTE_S1AP_SUBSCRIBERPROFILEIDFORRFP_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_subscriberprofileidforrfp( + uint8_t **ptr, + LIBLTE_S1AP_SUBSCRIBERPROFILEIDFORRFP_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE SynchronizationStatus ENUMERATED +********************************************************************************/ +typedef enum{ + LIBLTE_S1AP_SYNCHRONIZATIONSTATUS_SYNCHRONOUS, + LIBLTE_S1AP_SYNCHRONIZATIONSTATUS_ASYNCHRONOUS, + LIBLTE_S1AP_SYNCHRONIZATIONSTATUS_N_ITEMS, +}LIBLTE_S1AP_SYNCHRONIZATIONSTATUS_ENUM; +static const char liblte_s1ap_synchronizationstatus_text[LIBLTE_S1AP_SYNCHRONIZATIONSTATUS_N_ITEMS][80] = { + "synchronous", + "asynchronous", +}; + +typedef struct{ + bool ext; + LIBLTE_S1AP_SYNCHRONIZATIONSTATUS_ENUM e; +}LIBLTE_S1AP_SYNCHRONIZATIONSTATUS_ENUM_EXT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_synchronizationstatus( + LIBLTE_S1AP_SYNCHRONIZATIONSTATUS_ENUM_EXT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_synchronizationstatus( + uint8_t **ptr, + LIBLTE_S1AP_SYNCHRONIZATIONSTATUS_ENUM_EXT *ie); + +/******************************************************************************* +/* ProtocolIE TargetRNC_ToSourceRNC_TransparentContainer DYNAMIC OCTET STRING +********************************************************************************/ +// lb:0, ub:16318 +typedef struct{ + uint32_t n_octets; + uint8_t buffer[16318]; +}LIBLTE_S1AP_TARGETRNC_TOSOURCERNC_TRANSPARENTCONTAINER_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_targetrnc_tosourcernc_transparentcontainer( + LIBLTE_S1AP_TARGETRNC_TOSOURCERNC_TRANSPARENTCONTAINER_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_targetrnc_tosourcernc_transparentcontainer( + uint8_t **ptr, + LIBLTE_S1AP_TARGETRNC_TOSOURCERNC_TRANSPARENTCONTAINER_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE Threshold_RSRQ INTEGER +********************************************************************************/ +typedef struct{ +uint8_t Threshold_RSRQ; +}LIBLTE_S1AP_THRESHOLD_RSRQ_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_threshold_rsrq( + LIBLTE_S1AP_THRESHOLD_RSRQ_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_threshold_rsrq( + uint8_t **ptr, + LIBLTE_S1AP_THRESHOLD_RSRQ_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE Time_UE_StayedInCell INTEGER +********************************************************************************/ +typedef struct{ +uint16_t Time_UE_StayedInCell; +}LIBLTE_S1AP_TIME_UE_STAYEDINCELL_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_time_ue_stayedincell( + LIBLTE_S1AP_TIME_UE_STAYEDINCELL_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_time_ue_stayedincell( + uint8_t **ptr, + LIBLTE_S1AP_TIME_UE_STAYEDINCELL_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE TransportLayerAddress DYNAMIC BIT STRING +********************************************************************************/ +// lb:1, ub:160 +typedef struct{ + bool ext; + uint32_t n_bits; + uint8_t buffer[160]; +}LIBLTE_S1AP_TRANSPORTLAYERADDRESS_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_transportlayeraddress( + LIBLTE_S1AP_TRANSPORTLAYERADDRESS_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_transportlayeraddress( + uint8_t **ptr, + LIBLTE_S1AP_TRANSPORTLAYERADDRESS_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE TraceDepth ENUMERATED +********************************************************************************/ +typedef enum{ + LIBLTE_S1AP_TRACEDEPTH_MINIMUM, + LIBLTE_S1AP_TRACEDEPTH_MEDIUM, + LIBLTE_S1AP_TRACEDEPTH_MAXIMUM, + LIBLTE_S1AP_TRACEDEPTH_MINIMUMWITHOUTVENDORSPECIFICEXTENSION, + LIBLTE_S1AP_TRACEDEPTH_MEDIUMWITHOUTVENDORSPECIFICEXTENSION, + LIBLTE_S1AP_TRACEDEPTH_MAXIMUMWITHOUTVENDORSPECIFICEXTENSION, + LIBLTE_S1AP_TRACEDEPTH_N_ITEMS, +}LIBLTE_S1AP_TRACEDEPTH_ENUM; +static const char liblte_s1ap_tracedepth_text[LIBLTE_S1AP_TRACEDEPTH_N_ITEMS][80] = { + "minimum", + "medium", + "maximum", + "minimumWithoutVendorSpecificExtension", + "mediumWithoutVendorSpecificExtension", + "maximumWithoutVendorSpecificExtension", +}; + +typedef struct{ + bool ext; + LIBLTE_S1AP_TRACEDEPTH_ENUM e; +}LIBLTE_S1AP_TRACEDEPTH_ENUM_EXT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_tracedepth( + LIBLTE_S1AP_TRACEDEPTH_ENUM_EXT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_tracedepth( + uint8_t **ptr, + LIBLTE_S1AP_TRACEDEPTH_ENUM_EXT *ie); + +/******************************************************************************* +/* ProtocolIE TrafficLoadReductionIndication INTEGER +********************************************************************************/ +typedef struct{ +uint8_t TrafficLoadReductionIndication; +}LIBLTE_S1AP_TRAFFICLOADREDUCTIONINDICATION_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_trafficloadreductionindication( + LIBLTE_S1AP_TRAFFICLOADREDUCTIONINDICATION_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_trafficloadreductionindication( + uint8_t **ptr, + LIBLTE_S1AP_TRAFFICLOADREDUCTIONINDICATION_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE UERadioCapability DYNAMIC OCTET STRING +********************************************************************************/ +// lb:0, ub:16318 +typedef struct{ + uint32_t n_octets; + uint8_t buffer[16318]; +}LIBLTE_S1AP_UERADIOCAPABILITY_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_ueradiocapability( + LIBLTE_S1AP_UERADIOCAPABILITY_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_ueradiocapability( + uint8_t **ptr, + LIBLTE_S1AP_UERADIOCAPABILITY_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE WarningType STATIC OCTET STRING +********************************************************************************/ +#define LIBLTE_S1AP_WARNINGTYPE_OCTET_STRING_LEN 2 +typedef struct{ + uint8_t buffer[2]; +}LIBLTE_S1AP_WARNINGTYPE_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_warningtype( + LIBLTE_S1AP_WARNINGTYPE_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_warningtype( + uint8_t **ptr, + LIBLTE_S1AP_WARNINGTYPE_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE WarningMessageContents DYNAMIC OCTET STRING +********************************************************************************/ +// lb:1, ub:9600 +typedef struct{ + uint32_t n_octets; + uint8_t buffer[9600]; +}LIBLTE_S1AP_WARNINGMESSAGECONTENTS_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_warningmessagecontents( + LIBLTE_S1AP_WARNINGMESSAGECONTENTS_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_warningmessagecontents( + uint8_t **ptr, + LIBLTE_S1AP_WARNINGMESSAGECONTENTS_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE CauseProtocol ENUMERATED +********************************************************************************/ +typedef enum{ + LIBLTE_S1AP_CAUSEPROTOCOL_TRANSFER_SYNTAX_ERROR, + LIBLTE_S1AP_CAUSEPROTOCOL_ABSTRACT_SYNTAX_ERROR_REJECT, + LIBLTE_S1AP_CAUSEPROTOCOL_ABSTRACT_SYNTAX_ERROR_IGNORE_AND_NOTIFY, + LIBLTE_S1AP_CAUSEPROTOCOL_MESSAGE_NOT_COMPATIBLE_WITH_RECEIVER_STATE, + LIBLTE_S1AP_CAUSEPROTOCOL_SEMANTIC_ERROR, + LIBLTE_S1AP_CAUSEPROTOCOL_ABSTRACT_SYNTAX_ERROR_FALSELY_CONSTRUCTED_MESSAGE, + LIBLTE_S1AP_CAUSEPROTOCOL_UNSPECIFIED, + LIBLTE_S1AP_CAUSEPROTOCOL_N_ITEMS, +}LIBLTE_S1AP_CAUSEPROTOCOL_ENUM; +static const char liblte_s1ap_causeprotocol_text[LIBLTE_S1AP_CAUSEPROTOCOL_N_ITEMS][80] = { + "transfer-syntax-error", + "abstract-syntax-error-reject", + "abstract-syntax-error-ignore-and-notify", + "message-not-compatible-with-receiver-state", + "semantic-error", + "abstract-syntax-error-falsely-constructed-message", + "unspecified", +}; + +typedef struct{ + bool ext; + LIBLTE_S1AP_CAUSEPROTOCOL_ENUM e; +}LIBLTE_S1AP_CAUSEPROTOCOL_ENUM_EXT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_causeprotocol( + LIBLTE_S1AP_CAUSEPROTOCOL_ENUM_EXT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_causeprotocol( + uint8_t **ptr, + LIBLTE_S1AP_CAUSEPROTOCOL_ENUM_EXT *ie); + +/******************************************************************************* +/* ProtocolIE CellAccessMode ENUMERATED +********************************************************************************/ +typedef enum{ + LIBLTE_S1AP_CELLACCESSMODE_HYBRID, + LIBLTE_S1AP_CELLACCESSMODE_N_ITEMS, +}LIBLTE_S1AP_CELLACCESSMODE_ENUM; +static const char liblte_s1ap_cellaccessmode_text[LIBLTE_S1AP_CELLACCESSMODE_N_ITEMS][80] = { + "hybrid", +}; + +typedef struct{ + bool ext; + LIBLTE_S1AP_CELLACCESSMODE_ENUM e; +}LIBLTE_S1AP_CELLACCESSMODE_ENUM_EXT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_cellaccessmode( + LIBLTE_S1AP_CELLACCESSMODE_ENUM_EXT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_cellaccessmode( + uint8_t **ptr, + LIBLTE_S1AP_CELLACCESSMODE_ENUM_EXT *ie); + +/******************************************************************************* +/* ProtocolIE Cdma2000RATType ENUMERATED +********************************************************************************/ +typedef enum{ + LIBLTE_S1AP_CDMA2000RATTYPE_HRPD, + LIBLTE_S1AP_CDMA2000RATTYPE_ONEXRTT, + LIBLTE_S1AP_CDMA2000RATTYPE_N_ITEMS, +}LIBLTE_S1AP_CDMA2000RATTYPE_ENUM; +static const char liblte_s1ap_cdma2000rattype_text[LIBLTE_S1AP_CDMA2000RATTYPE_N_ITEMS][80] = { + "hRPD", + "onexRTT", +}; + +typedef struct{ + bool ext; + LIBLTE_S1AP_CDMA2000RATTYPE_ENUM e; +}LIBLTE_S1AP_CDMA2000RATTYPE_ENUM_EXT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_cdma2000rattype( + LIBLTE_S1AP_CDMA2000RATTYPE_ENUM_EXT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_cdma2000rattype( + uint8_t **ptr, + LIBLTE_S1AP_CDMA2000RATTYPE_ENUM_EXT *ie); + +/******************************************************************************* +/* ProtocolIE Cdma2000OneXMEID DYNAMIC OCTET STRING +********************************************************************************/ +// lb:0, ub:16318 +typedef struct{ + uint32_t n_octets; + uint8_t buffer[16318]; +}LIBLTE_S1AP_CDMA2000ONEXMEID_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_cdma2000onexmeid( + LIBLTE_S1AP_CDMA2000ONEXMEID_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_cdma2000onexmeid( + uint8_t **ptr, + LIBLTE_S1AP_CDMA2000ONEXMEID_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE Cell_Size ENUMERATED +********************************************************************************/ +typedef enum{ + LIBLTE_S1AP_CELL_SIZE_VERYSMALL, + LIBLTE_S1AP_CELL_SIZE_SMALL, + LIBLTE_S1AP_CELL_SIZE_MEDIUM, + LIBLTE_S1AP_CELL_SIZE_LARGE, + LIBLTE_S1AP_CELL_SIZE_N_ITEMS, +}LIBLTE_S1AP_CELL_SIZE_ENUM; +static const char liblte_s1ap_cell_size_text[LIBLTE_S1AP_CELL_SIZE_N_ITEMS][80] = { + "verysmall", + "small", + "medium", + "large", +}; + +typedef struct{ + bool ext; + LIBLTE_S1AP_CELL_SIZE_ENUM e; +}LIBLTE_S1AP_CELL_SIZE_ENUM_EXT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_cell_size( + LIBLTE_S1AP_CELL_SIZE_ENUM_EXT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_cell_size( + uint8_t **ptr, + LIBLTE_S1AP_CELL_SIZE_ENUM_EXT *ie); + +/******************************************************************************* +/* ProtocolIE CI STATIC OCTET STRING +********************************************************************************/ +#define LIBLTE_S1AP_CI_OCTET_STRING_LEN 2 +typedef struct{ + uint8_t buffer[2]; +}LIBLTE_S1AP_CI_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_ci( + LIBLTE_S1AP_CI_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_ci( + uint8_t **ptr, + LIBLTE_S1AP_CI_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE CSFallbackIndicator ENUMERATED +********************************************************************************/ +typedef enum{ + LIBLTE_S1AP_CSFALLBACKINDICATOR_CS_FALLBACK_REQUIRED, + LIBLTE_S1AP_CSFALLBACKINDICATOR_CS_FALLBACK_HIGH_PRIORITY, + LIBLTE_S1AP_CSFALLBACKINDICATOR_N_ITEMS, +}LIBLTE_S1AP_CSFALLBACKINDICATOR_ENUM; +static const char liblte_s1ap_csfallbackindicator_text[LIBLTE_S1AP_CSFALLBACKINDICATOR_N_ITEMS][80] = { + "cs-fallback-required", + "cs-fallback-high-priority", +}; + +typedef struct{ + bool ext; + LIBLTE_S1AP_CSFALLBACKINDICATOR_ENUM e; +}LIBLTE_S1AP_CSFALLBACKINDICATOR_ENUM_EXT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_csfallbackindicator( + LIBLTE_S1AP_CSFALLBACKINDICATOR_ENUM_EXT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_csfallbackindicator( + uint8_t **ptr, + LIBLTE_S1AP_CSFALLBACKINDICATOR_ENUM_EXT *ie); + +/******************************************************************************* +/* ProtocolIE CSGMembershipStatus ENUMERATED +********************************************************************************/ +typedef enum{ + LIBLTE_S1AP_CSGMEMBERSHIPSTATUS_MEMBER, + LIBLTE_S1AP_CSGMEMBERSHIPSTATUS_NOT_MEMBER, + LIBLTE_S1AP_CSGMEMBERSHIPSTATUS_N_ITEMS, +}LIBLTE_S1AP_CSGMEMBERSHIPSTATUS_ENUM; +static const char liblte_s1ap_csgmembershipstatus_text[LIBLTE_S1AP_CSGMEMBERSHIPSTATUS_N_ITEMS][80] = { + "member", + "not-member", +}; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_csgmembershipstatus( + LIBLTE_S1AP_CSGMEMBERSHIPSTATUS_ENUM *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_csgmembershipstatus( + uint8_t **ptr, + LIBLTE_S1AP_CSGMEMBERSHIPSTATUS_ENUM *ie); + +/******************************************************************************* +/* ProtocolIE DataCodingScheme STATIC BIT STRING +********************************************************************************/ +#define LIBLTE_S1AP_DATACODINGSCHEME_BIT_STRING_LEN 8 +typedef struct{ + uint8_t buffer[8]; +}LIBLTE_S1AP_DATACODINGSCHEME_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_datacodingscheme( + LIBLTE_S1AP_DATACODINGSCHEME_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_datacodingscheme( + uint8_t **ptr, + LIBLTE_S1AP_DATACODINGSCHEME_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE EmergencyAreaIDList DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:65535 +typedef struct{ + uint32_t len; + LIBLTE_S1AP_EMERGENCYAREAID_STRUCT buffer[32]; //WARNING: Artificial limit to reduce memory footprint +}LIBLTE_S1AP_EMERGENCYAREAIDLIST_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_emergencyareaidlist( + LIBLTE_S1AP_EMERGENCYAREAIDLIST_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_emergencyareaidlist( + uint8_t **ptr, + LIBLTE_S1AP_EMERGENCYAREAIDLIST_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE EmergencyAreaIDListForRestart DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:256 +typedef struct{ + uint32_t len; + LIBLTE_S1AP_EMERGENCYAREAID_STRUCT buffer[32]; //WARNING: Artificial limit to reduce memory footprint +}LIBLTE_S1AP_EMERGENCYAREAIDLISTFORRESTART_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_emergencyareaidlistforrestart( + LIBLTE_S1AP_EMERGENCYAREAIDLISTFORRESTART_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_emergencyareaidlistforrestart( + uint8_t **ptr, + LIBLTE_S1AP_EMERGENCYAREAIDLISTFORRESTART_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE ENB_UE_S1AP_ID INTEGER +********************************************************************************/ +typedef struct{ +uint32_t ENB_UE_S1AP_ID; +}LIBLTE_S1AP_ENB_UE_S1AP_ID_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_enb_ue_s1ap_id( + LIBLTE_S1AP_ENB_UE_S1AP_ID_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_enb_ue_s1ap_id( + uint8_t **ptr, + LIBLTE_S1AP_ENB_UE_S1AP_ID_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE E_RAB_ID INTEGER +********************************************************************************/ +typedef struct{ + bool ext; +uint8_t E_RAB_ID; +}LIBLTE_S1AP_E_RAB_ID_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rab_id( + LIBLTE_S1AP_E_RAB_ID_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rab_id( + uint8_t **ptr, + LIBLTE_S1AP_E_RAB_ID_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE E_RABInformationListItem SEQUENCE +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_E_RAB_ID_STRUCT e_RAB_ID; + LIBLTE_S1AP_DL_FORWARDING_ENUM_EXT dL_Forwarding; + bool dL_Forwarding_present; + LIBLTE_S1AP_PROTOCOLEXTENSIONCONTAINER_STRUCT iE_Extensions; + bool iE_Extensions_present; +}LIBLTE_S1AP_E_RABINFORMATIONLISTITEM_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabinformationlistitem( + LIBLTE_S1AP_E_RABINFORMATIONLISTITEM_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabinformationlistitem( + uint8_t **ptr, + LIBLTE_S1AP_E_RABINFORMATIONLISTITEM_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE EUTRANRoundTripDelayEstimationInfo INTEGER +********************************************************************************/ +typedef struct{ +uint16_t EUTRANRoundTripDelayEstimationInfo; +}LIBLTE_S1AP_EUTRANROUNDTRIPDELAYESTIMATIONINFO_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_eutranroundtripdelayestimationinfo( + LIBLTE_S1AP_EUTRANROUNDTRIPDELAYESTIMATIONINFO_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_eutranroundtripdelayestimationinfo( + uint8_t **ptr, + LIBLTE_S1AP_EUTRANROUNDTRIPDELAYESTIMATIONINFO_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE ForbiddenLACs DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:4096 +typedef struct{ + uint32_t len; + LIBLTE_S1AP_LAC_STRUCT buffer[32]; //WARNING: Artificial limit to reduce memory footprint +}LIBLTE_S1AP_FORBIDDENLACS_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_forbiddenlacs( + LIBLTE_S1AP_FORBIDDENLACS_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_forbiddenlacs( + uint8_t **ptr, + LIBLTE_S1AP_FORBIDDENLACS_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE GTP_TEID STATIC OCTET STRING +********************************************************************************/ +#define LIBLTE_S1AP_GTP_TEID_OCTET_STRING_LEN 4 +typedef struct{ + uint8_t buffer[4]; +}LIBLTE_S1AP_GTP_TEID_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_gtp_teid( + LIBLTE_S1AP_GTP_TEID_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_gtp_teid( + uint8_t **ptr, + LIBLTE_S1AP_GTP_TEID_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE GUMMEIType ENUMERATED +********************************************************************************/ +typedef enum{ + LIBLTE_S1AP_GUMMEITYPE_NATIVE, + LIBLTE_S1AP_GUMMEITYPE_MAPPED, + LIBLTE_S1AP_GUMMEITYPE_N_ITEMS, +}LIBLTE_S1AP_GUMMEITYPE_ENUM; +static const char liblte_s1ap_gummeitype_text[LIBLTE_S1AP_GUMMEITYPE_N_ITEMS][80] = { + "native", + "mapped", +}; + +typedef struct{ + bool ext; + LIBLTE_S1AP_GUMMEITYPE_ENUM e; +}LIBLTE_S1AP_GUMMEITYPE_ENUM_EXT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_gummeitype( + LIBLTE_S1AP_GUMMEITYPE_ENUM_EXT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_gummeitype( + uint8_t **ptr, + LIBLTE_S1AP_GUMMEITYPE_ENUM_EXT *ie); + +/******************************************************************************* +/* ProtocolIE HandoverType ENUMERATED +********************************************************************************/ +typedef enum{ + LIBLTE_S1AP_HANDOVERTYPE_INTRALTE, + LIBLTE_S1AP_HANDOVERTYPE_LTETOUTRAN, + LIBLTE_S1AP_HANDOVERTYPE_LTETOGERAN, + LIBLTE_S1AP_HANDOVERTYPE_UTRANTOLTE, + LIBLTE_S1AP_HANDOVERTYPE_GERANTOLTE, + LIBLTE_S1AP_HANDOVERTYPE_N_ITEMS, +}LIBLTE_S1AP_HANDOVERTYPE_ENUM; +static const char liblte_s1ap_handovertype_text[LIBLTE_S1AP_HANDOVERTYPE_N_ITEMS][80] = { + "intralte", + "ltetoutran", + "ltetogeran", + "utrantolte", + "gerantolte", +}; + +typedef struct{ + bool ext; + LIBLTE_S1AP_HANDOVERTYPE_ENUM e; +}LIBLTE_S1AP_HANDOVERTYPE_ENUM_EXT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_handovertype( + LIBLTE_S1AP_HANDOVERTYPE_ENUM_EXT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_handovertype( + uint8_t **ptr, + LIBLTE_S1AP_HANDOVERTYPE_ENUM_EXT *ie); + +/******************************************************************************* +/* ProtocolIE IntegrityProtectionAlgorithms STATIC BIT STRING +********************************************************************************/ +#define LIBLTE_S1AP_INTEGRITYPROTECTIONALGORITHMS_BIT_STRING_LEN 16 +typedef struct{ + bool ext; + uint8_t buffer[16]; +}LIBLTE_S1AP_INTEGRITYPROTECTIONALGORITHMS_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_integrityprotectionalgorithms( + LIBLTE_S1AP_INTEGRITYPROTECTIONALGORITHMS_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_integrityprotectionalgorithms( + uint8_t **ptr, + LIBLTE_S1AP_INTEGRITYPROTECTIONALGORITHMS_STRUCT *ie); + +//TODO: Type undefined NULL + +/******************************************************************************* +/* ProtocolIE LastVisitedGERANCellInformation CHOICE +********************************************************************************/ +typedef enum{ + LIBLTE_S1AP_LASTVISITEDGERANCELLINFORMATION_CHOICE_UNDEFINED, + LIBLTE_S1AP_LASTVISITEDGERANCELLINFORMATION_CHOICE_N_ITEMS, +}LIBLTE_S1AP_LASTVISITEDGERANCELLINFORMATION_CHOICE_ENUM; +static const char liblte_s1ap_lastvisitedgerancellinformation_choice_text[LIBLTE_S1AP_LASTVISITEDGERANCELLINFORMATION_CHOICE_N_ITEMS][50] = { + "undefined", +}; + +typedef union{ + //TODO: NULL undefined; +}LIBLTE_S1AP_LASTVISITEDGERANCELLINFORMATION_CHOICE_UNION; + +typedef struct{ + bool ext; + LIBLTE_S1AP_LASTVISITEDGERANCELLINFORMATION_CHOICE_UNION choice; + LIBLTE_S1AP_LASTVISITEDGERANCELLINFORMATION_CHOICE_ENUM choice_type; +}LIBLTE_S1AP_LASTVISITEDGERANCELLINFORMATION_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_lastvisitedgerancellinformation( + LIBLTE_S1AP_LASTVISITEDGERANCELLINFORMATION_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_lastvisitedgerancellinformation( + uint8_t **ptr, + LIBLTE_S1AP_LASTVISITEDGERANCELLINFORMATION_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE Links_to_log ENUMERATED +********************************************************************************/ +typedef enum{ + LIBLTE_S1AP_LINKS_TO_LOG_UPLINK, + LIBLTE_S1AP_LINKS_TO_LOG_DOWNLINK, + LIBLTE_S1AP_LINKS_TO_LOG_BOTH_UPLINK_AND_DOWNLINK, + LIBLTE_S1AP_LINKS_TO_LOG_N_ITEMS, +}LIBLTE_S1AP_LINKS_TO_LOG_ENUM; +static const char liblte_s1ap_links_to_log_text[LIBLTE_S1AP_LINKS_TO_LOG_N_ITEMS][80] = { + "uplink", + "downlink", + "both-uplink-and-downlink", +}; + +typedef struct{ + bool ext; + LIBLTE_S1AP_LINKS_TO_LOG_ENUM e; +}LIBLTE_S1AP_LINKS_TO_LOG_ENUM_EXT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_links_to_log( + LIBLTE_S1AP_LINKS_TO_LOG_ENUM_EXT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_links_to_log( + uint8_t **ptr, + LIBLTE_S1AP_LINKS_TO_LOG_ENUM_EXT *ie); + +/******************************************************************************* +/* ProtocolIE LoggingInterval ENUMERATED +********************************************************************************/ +typedef enum{ + LIBLTE_S1AP_LOGGINGINTERVAL_MS128, + LIBLTE_S1AP_LOGGINGINTERVAL_MS256, + LIBLTE_S1AP_LOGGINGINTERVAL_MS512, + LIBLTE_S1AP_LOGGINGINTERVAL_MS1024, + LIBLTE_S1AP_LOGGINGINTERVAL_MS2048, + LIBLTE_S1AP_LOGGINGINTERVAL_MS3072, + LIBLTE_S1AP_LOGGINGINTERVAL_MS4096, + LIBLTE_S1AP_LOGGINGINTERVAL_MS6144, + LIBLTE_S1AP_LOGGINGINTERVAL_N_ITEMS, +}LIBLTE_S1AP_LOGGINGINTERVAL_ENUM; +static const char liblte_s1ap_logginginterval_text[LIBLTE_S1AP_LOGGINGINTERVAL_N_ITEMS][80] = { + "ms128", + "ms256", + "ms512", + "ms1024", + "ms2048", + "ms3072", + "ms4096", + "ms6144", +}; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_logginginterval( + LIBLTE_S1AP_LOGGINGINTERVAL_ENUM *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_logginginterval( + uint8_t **ptr, + LIBLTE_S1AP_LOGGINGINTERVAL_ENUM *ie); + +/******************************************************************************* +/* ProtocolIE M3period ENUMERATED +********************************************************************************/ +typedef enum{ + LIBLTE_S1AP_M3PERIOD_MS100, + LIBLTE_S1AP_M3PERIOD_MS1000, + LIBLTE_S1AP_M3PERIOD_MS10000, + LIBLTE_S1AP_M3PERIOD_N_ITEMS, +}LIBLTE_S1AP_M3PERIOD_ENUM; +static const char liblte_s1ap_m3period_text[LIBLTE_S1AP_M3PERIOD_N_ITEMS][80] = { + "ms100", + "ms1000", + "ms10000", +}; + +typedef struct{ + bool ext; + LIBLTE_S1AP_M3PERIOD_ENUM e; +}LIBLTE_S1AP_M3PERIOD_ENUM_EXT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_m3period( + LIBLTE_S1AP_M3PERIOD_ENUM_EXT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_m3period( + uint8_t **ptr, + LIBLTE_S1AP_M3PERIOD_ENUM_EXT *ie); + +/******************************************************************************* +/* ProtocolIE M4period ENUMERATED +********************************************************************************/ +typedef enum{ + LIBLTE_S1AP_M4PERIOD_MS1024, + LIBLTE_S1AP_M4PERIOD_MS2048, + LIBLTE_S1AP_M4PERIOD_MS5120, + LIBLTE_S1AP_M4PERIOD_MS10240, + LIBLTE_S1AP_M4PERIOD_MIN1, + LIBLTE_S1AP_M4PERIOD_N_ITEMS, +}LIBLTE_S1AP_M4PERIOD_ENUM; +static const char liblte_s1ap_m4period_text[LIBLTE_S1AP_M4PERIOD_N_ITEMS][80] = { + "ms1024", + "ms2048", + "ms5120", + "ms10240", + "min1", +}; + +typedef struct{ + bool ext; + LIBLTE_S1AP_M4PERIOD_ENUM e; +}LIBLTE_S1AP_M4PERIOD_ENUM_EXT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_m4period( + LIBLTE_S1AP_M4PERIOD_ENUM_EXT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_m4period( + uint8_t **ptr, + LIBLTE_S1AP_M4PERIOD_ENUM_EXT *ie); + +/******************************************************************************* +/* ProtocolIE M5period ENUMERATED +********************************************************************************/ +typedef enum{ + LIBLTE_S1AP_M5PERIOD_MS1024, + LIBLTE_S1AP_M5PERIOD_MS2048, + LIBLTE_S1AP_M5PERIOD_MS5120, + LIBLTE_S1AP_M5PERIOD_MS10240, + LIBLTE_S1AP_M5PERIOD_MIN1, + LIBLTE_S1AP_M5PERIOD_N_ITEMS, +}LIBLTE_S1AP_M5PERIOD_ENUM; +static const char liblte_s1ap_m5period_text[LIBLTE_S1AP_M5PERIOD_N_ITEMS][80] = { + "ms1024", + "ms2048", + "ms5120", + "ms10240", + "min1", +}; + +typedef struct{ + bool ext; + LIBLTE_S1AP_M5PERIOD_ENUM e; +}LIBLTE_S1AP_M5PERIOD_ENUM_EXT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_m5period( + LIBLTE_S1AP_M5PERIOD_ENUM_EXT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_m5period( + uint8_t **ptr, + LIBLTE_S1AP_M5PERIOD_ENUM_EXT *ie); + +/******************************************************************************* +/* ProtocolIE MobilityInformation STATIC BIT STRING +********************************************************************************/ +#define LIBLTE_S1AP_MOBILITYINFORMATION_BIT_STRING_LEN 32 +typedef struct{ + uint8_t buffer[32]; +}LIBLTE_S1AP_MOBILITYINFORMATION_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_mobilityinformation( + LIBLTE_S1AP_MOBILITYINFORMATION_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_mobilityinformation( + uint8_t **ptr, + LIBLTE_S1AP_MOBILITYINFORMATION_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE MME_Code STATIC OCTET STRING +********************************************************************************/ +#define LIBLTE_S1AP_MME_CODE_OCTET_STRING_LEN 1 +typedef struct{ + uint8_t buffer[1]; +}LIBLTE_S1AP_MME_CODE_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_mme_code( + LIBLTE_S1AP_MME_CODE_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_mme_code( + uint8_t **ptr, + LIBLTE_S1AP_MME_CODE_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE MSClassmark3 DYNAMIC OCTET STRING +********************************************************************************/ +// lb:0, ub:16318 +typedef struct{ + uint32_t n_octets; + uint8_t buffer[16318]; +}LIBLTE_S1AP_MSCLASSMARK3_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_msclassmark3( + LIBLTE_S1AP_MSCLASSMARK3_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_msclassmark3( + uint8_t **ptr, + LIBLTE_S1AP_MSCLASSMARK3_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE NumberofBroadcastRequest INTEGER +********************************************************************************/ +typedef struct{ +uint16_t NumberofBroadcastRequest; +}LIBLTE_S1AP_NUMBEROFBROADCASTREQUEST_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_numberofbroadcastrequest( + LIBLTE_S1AP_NUMBEROFBROADCASTREQUEST_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_numberofbroadcastrequest( + uint8_t **ptr, + LIBLTE_S1AP_NUMBEROFBROADCASTREQUEST_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE OverloadResponse CHOICE +********************************************************************************/ +typedef enum{ + LIBLTE_S1AP_OVERLOADRESPONSE_CHOICE_OVERLOADACTION, + LIBLTE_S1AP_OVERLOADRESPONSE_CHOICE_N_ITEMS, +}LIBLTE_S1AP_OVERLOADRESPONSE_CHOICE_ENUM; +static const char liblte_s1ap_overloadresponse_choice_text[LIBLTE_S1AP_OVERLOADRESPONSE_CHOICE_N_ITEMS][50] = { + "overloadAction", +}; + +typedef union{ + LIBLTE_S1AP_OVERLOADACTION_ENUM_EXT overloadAction; +}LIBLTE_S1AP_OVERLOADRESPONSE_CHOICE_UNION; + +typedef struct{ + bool ext; + LIBLTE_S1AP_OVERLOADRESPONSE_CHOICE_UNION choice; + LIBLTE_S1AP_OVERLOADRESPONSE_CHOICE_ENUM choice_type; +}LIBLTE_S1AP_OVERLOADRESPONSE_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_overloadresponse( + LIBLTE_S1AP_OVERLOADRESPONSE_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_overloadresponse( + uint8_t **ptr, + LIBLTE_S1AP_OVERLOADRESPONSE_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE PDCP_SNExtended INTEGER +********************************************************************************/ +typedef struct{ +uint16_t PDCP_SNExtended; +}LIBLTE_S1AP_PDCP_SNEXTENDED_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_pdcp_snextended( + LIBLTE_S1AP_PDCP_SNEXTENDED_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_pdcp_snextended( + uint8_t **ptr, + LIBLTE_S1AP_PDCP_SNEXTENDED_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE Pre_emptionCapability ENUMERATED +********************************************************************************/ +typedef enum{ + LIBLTE_S1AP_PRE_EMPTIONCAPABILITY_SHALL_NOT_TRIGGER_PRE_EMPTION, + LIBLTE_S1AP_PRE_EMPTIONCAPABILITY_MAY_TRIGGER_PRE_EMPTION, + LIBLTE_S1AP_PRE_EMPTIONCAPABILITY_N_ITEMS, +}LIBLTE_S1AP_PRE_EMPTIONCAPABILITY_ENUM; +static const char liblte_s1ap_pre_emptioncapability_text[LIBLTE_S1AP_PRE_EMPTIONCAPABILITY_N_ITEMS][80] = { + "shall-not-trigger-pre-emption", + "may-trigger-pre-emption", +}; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_pre_emptioncapability( + LIBLTE_S1AP_PRE_EMPTIONCAPABILITY_ENUM *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_pre_emptioncapability( + uint8_t **ptr, + LIBLTE_S1AP_PRE_EMPTIONCAPABILITY_ENUM *ie); + +/******************************************************************************* +/* ProtocolIE QCI INTEGER +********************************************************************************/ +typedef struct{ +uint8_t QCI; +}LIBLTE_S1AP_QCI_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_qci( + LIBLTE_S1AP_QCI_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_qci( + uint8_t **ptr, + LIBLTE_S1AP_QCI_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE RelayNode_Indicator ENUMERATED +********************************************************************************/ +typedef enum{ + LIBLTE_S1AP_RELAYNODE_INDICATOR_TRUE, + LIBLTE_S1AP_RELAYNODE_INDICATOR_N_ITEMS, +}LIBLTE_S1AP_RELAYNODE_INDICATOR_ENUM; +static const char liblte_s1ap_relaynode_indicator_text[LIBLTE_S1AP_RELAYNODE_INDICATOR_N_ITEMS][80] = { + "true", +}; + +typedef struct{ + bool ext; + LIBLTE_S1AP_RELAYNODE_INDICATOR_ENUM e; +}LIBLTE_S1AP_RELAYNODE_INDICATOR_ENUM_EXT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_relaynode_indicator( + LIBLTE_S1AP_RELAYNODE_INDICATOR_ENUM_EXT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_relaynode_indicator( + uint8_t **ptr, + LIBLTE_S1AP_RELAYNODE_INDICATOR_ENUM_EXT *ie); + +/******************************************************************************* +/* ProtocolIE M1ReportingTrigger ENUMERATED +********************************************************************************/ +typedef enum{ + LIBLTE_S1AP_M1REPORTINGTRIGGER_PERIODIC, + LIBLTE_S1AP_M1REPORTINGTRIGGER_A2EVENTTRIGGERED, + LIBLTE_S1AP_M1REPORTINGTRIGGER_A2EVENTTRIGGERED_PERIODIC, + LIBLTE_S1AP_M1REPORTINGTRIGGER_N_ITEMS, +}LIBLTE_S1AP_M1REPORTINGTRIGGER_ENUM; +static const char liblte_s1ap_m1reportingtrigger_text[LIBLTE_S1AP_M1REPORTINGTRIGGER_N_ITEMS][80] = { + "periodic", + "a2eventtriggered", + "a2eventtriggered-periodic", +}; + +typedef struct{ + bool ext; + LIBLTE_S1AP_M1REPORTINGTRIGGER_ENUM e; +}LIBLTE_S1AP_M1REPORTINGTRIGGER_ENUM_EXT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_m1reportingtrigger( + LIBLTE_S1AP_M1REPORTINGTRIGGER_ENUM_EXT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_m1reportingtrigger( + uint8_t **ptr, + LIBLTE_S1AP_M1REPORTINGTRIGGER_ENUM_EXT *ie); + +/******************************************************************************* +/* ProtocolIE RIMInformation DYNAMIC OCTET STRING +********************************************************************************/ +// lb:0, ub:16318 +typedef struct{ + uint32_t n_octets; + uint8_t buffer[16318]; +}LIBLTE_S1AP_RIMINFORMATION_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_riminformation( + LIBLTE_S1AP_RIMINFORMATION_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_riminformation( + uint8_t **ptr, + LIBLTE_S1AP_RIMINFORMATION_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE RepetitionPeriod INTEGER +********************************************************************************/ +typedef struct{ +uint16_t RepetitionPeriod; +}LIBLTE_S1AP_REPETITIONPERIOD_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_repetitionperiod( + LIBLTE_S1AP_REPETITIONPERIOD_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_repetitionperiod( + uint8_t **ptr, + LIBLTE_S1AP_REPETITIONPERIOD_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE SecurityKey STATIC BIT STRING +********************************************************************************/ +#define LIBLTE_S1AP_SECURITYKEY_BIT_STRING_LEN 256 +typedef struct{ + uint8_t buffer[256]; +}LIBLTE_S1AP_SECURITYKEY_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_securitykey( + LIBLTE_S1AP_SECURITYKEY_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_securitykey( + uint8_t **ptr, + LIBLTE_S1AP_SECURITYKEY_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE SerialNumber STATIC BIT STRING +********************************************************************************/ +#define LIBLTE_S1AP_SERIALNUMBER_BIT_STRING_LEN 16 +typedef struct{ + uint8_t buffer[16]; +}LIBLTE_S1AP_SERIALNUMBER_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_serialnumber( + LIBLTE_S1AP_SERIALNUMBER_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_serialnumber( + uint8_t **ptr, + LIBLTE_S1AP_SERIALNUMBER_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE SourceBSS_ToTargetBSS_TransparentContainer DYNAMIC OCTET STRING +********************************************************************************/ +// lb:0, ub:16318 +typedef struct{ + uint32_t n_octets; + uint8_t buffer[16318]; +}LIBLTE_S1AP_SOURCEBSS_TOTARGETBSS_TRANSPARENTCONTAINER_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_sourcebss_totargetbss_transparentcontainer( + LIBLTE_S1AP_SOURCEBSS_TOTARGETBSS_TRANSPARENTCONTAINER_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_sourcebss_totargetbss_transparentcontainer( + uint8_t **ptr, + LIBLTE_S1AP_SOURCEBSS_TOTARGETBSS_TRANSPARENTCONTAINER_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE SRVCCOperationPossible ENUMERATED +********************************************************************************/ +typedef enum{ + LIBLTE_S1AP_SRVCCOPERATIONPOSSIBLE_POSSIBLE, + LIBLTE_S1AP_SRVCCOPERATIONPOSSIBLE_N_ITEMS, +}LIBLTE_S1AP_SRVCCOPERATIONPOSSIBLE_ENUM; +static const char liblte_s1ap_srvccoperationpossible_text[LIBLTE_S1AP_SRVCCOPERATIONPOSSIBLE_N_ITEMS][80] = { + "possible", +}; + +typedef struct{ + bool ext; + LIBLTE_S1AP_SRVCCOPERATIONPOSSIBLE_ENUM e; +}LIBLTE_S1AP_SRVCCOPERATIONPOSSIBLE_ENUM_EXT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_srvccoperationpossible( + LIBLTE_S1AP_SRVCCOPERATIONPOSSIBLE_ENUM_EXT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_srvccoperationpossible( + uint8_t **ptr, + LIBLTE_S1AP_SRVCCOPERATIONPOSSIBLE_ENUM_EXT *ie); + +/******************************************************************************* +/* ProtocolIE ServedGroupIDs DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:65535 +typedef struct{ + uint32_t len; + LIBLTE_S1AP_MME_GROUP_ID_STRUCT buffer[32]; //WARNING: Artificial limit to reduce memory footprint +}LIBLTE_S1AP_SERVEDGROUPIDS_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_servedgroupids( + LIBLTE_S1AP_SERVEDGROUPIDS_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_servedgroupids( + uint8_t **ptr, + LIBLTE_S1AP_SERVEDGROUPIDS_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE StratumLevel INTEGER +********************************************************************************/ +typedef struct{ + bool ext; +uint8_t StratumLevel; +}LIBLTE_S1AP_STRATUMLEVEL_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_stratumlevel( + LIBLTE_S1AP_STRATUMLEVEL_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_stratumlevel( + uint8_t **ptr, + LIBLTE_S1AP_STRATUMLEVEL_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE TAC STATIC OCTET STRING +********************************************************************************/ +#define LIBLTE_S1AP_TAC_OCTET_STRING_LEN 2 +typedef struct{ + uint8_t buffer[2]; +}LIBLTE_S1AP_TAC_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_tac( + LIBLTE_S1AP_TAC_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_tac( + uint8_t **ptr, + LIBLTE_S1AP_TAC_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE TAListforMDT DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:8 +typedef struct{ + uint32_t len; + LIBLTE_S1AP_TAC_STRUCT buffer[32]; //WARNING: Artificial limit to reduce memory footprint +}LIBLTE_S1AP_TALISTFORMDT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_talistformdt( + LIBLTE_S1AP_TALISTFORMDT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_talistformdt( + uint8_t **ptr, + LIBLTE_S1AP_TALISTFORMDT_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE TBCD_STRING STATIC OCTET STRING +********************************************************************************/ +#define LIBLTE_S1AP_TBCD_STRING_OCTET_STRING_LEN 3 +typedef struct{ + uint8_t buffer[3]; +}LIBLTE_S1AP_TBCD_STRING_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_tbcd_string( + LIBLTE_S1AP_TBCD_STRING_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_tbcd_string( + uint8_t **ptr, + LIBLTE_S1AP_TBCD_STRING_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE Target_ToSource_TransparentContainer DYNAMIC OCTET STRING +********************************************************************************/ +// lb:0, ub:16318 +typedef struct{ + uint32_t n_octets; + uint8_t buffer[16318]; +}LIBLTE_S1AP_TARGET_TOSOURCE_TRANSPARENTCONTAINER_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_target_tosource_transparentcontainer( + LIBLTE_S1AP_TARGET_TOSOURCE_TRANSPARENTCONTAINER_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_target_tosource_transparentcontainer( + uint8_t **ptr, + LIBLTE_S1AP_TARGET_TOSOURCE_TRANSPARENTCONTAINER_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE Threshold_RSRP INTEGER +********************************************************************************/ +typedef struct{ +uint8_t Threshold_RSRP; +}LIBLTE_S1AP_THRESHOLD_RSRP_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_threshold_rsrp( + LIBLTE_S1AP_THRESHOLD_RSRP_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_threshold_rsrp( + uint8_t **ptr, + LIBLTE_S1AP_THRESHOLD_RSRP_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE Time_UE_StayedInCell_EnhancedGranularity INTEGER +********************************************************************************/ +typedef struct{ +uint16_t Time_UE_StayedInCell_EnhancedGranularity; +}LIBLTE_S1AP_TIME_UE_STAYEDINCELL_ENHANCEDGRANULARITY_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_time_ue_stayedincell_enhancedgranularity( + LIBLTE_S1AP_TIME_UE_STAYEDINCELL_ENHANCEDGRANULARITY_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_time_ue_stayedincell_enhancedgranularity( + uint8_t **ptr, + LIBLTE_S1AP_TIME_UE_STAYEDINCELL_ENHANCEDGRANULARITY_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE E_UTRAN_Trace_ID STATIC OCTET STRING +********************************************************************************/ +#define LIBLTE_S1AP_E_UTRAN_TRACE_ID_OCTET_STRING_LEN 8 +typedef struct{ + uint8_t buffer[8]; +}LIBLTE_S1AP_E_UTRAN_TRACE_ID_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_utran_trace_id( + LIBLTE_S1AP_E_UTRAN_TRACE_ID_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_utran_trace_id( + uint8_t **ptr, + LIBLTE_S1AP_E_UTRAN_TRACE_ID_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE TypeOfError ENUMERATED +********************************************************************************/ +typedef enum{ + LIBLTE_S1AP_TYPEOFERROR_NOT_UNDERSTOOD, + LIBLTE_S1AP_TYPEOFERROR_MISSING, + LIBLTE_S1AP_TYPEOFERROR_N_ITEMS, +}LIBLTE_S1AP_TYPEOFERROR_ENUM; +static const char liblte_s1ap_typeoferror_text[LIBLTE_S1AP_TYPEOFERROR_N_ITEMS][80] = { + "not-understood", + "missing", +}; + +typedef struct{ + bool ext; + LIBLTE_S1AP_TYPEOFERROR_ENUM e; +}LIBLTE_S1AP_TYPEOFERROR_ENUM_EXT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_typeoferror( + LIBLTE_S1AP_TYPEOFERROR_ENUM_EXT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_typeoferror( + uint8_t **ptr, + LIBLTE_S1AP_TYPEOFERROR_ENUM_EXT *ie); + +/******************************************************************************* +/* ProtocolIE UEAggregateMaximumBitrate SEQUENCE +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_BITRATE_STRUCT uEaggregateMaximumBitRateDL; + LIBLTE_S1AP_BITRATE_STRUCT uEaggregateMaximumBitRateUL; + LIBLTE_S1AP_PROTOCOLEXTENSIONCONTAINER_STRUCT iE_Extensions; + bool iE_Extensions_present; +}LIBLTE_S1AP_UEAGGREGATEMAXIMUMBITRATE_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_ueaggregatemaximumbitrate( + LIBLTE_S1AP_UEAGGREGATEMAXIMUMBITRATE_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_ueaggregatemaximumbitrate( + uint8_t **ptr, + LIBLTE_S1AP_UEAGGREGATEMAXIMUMBITRATE_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE UE_S1AP_ID_pair SEQUENCE +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_MME_UE_S1AP_ID_STRUCT mME_UE_S1AP_ID; + LIBLTE_S1AP_ENB_UE_S1AP_ID_STRUCT eNB_UE_S1AP_ID; + LIBLTE_S1AP_PROTOCOLEXTENSIONCONTAINER_STRUCT iE_Extensions; + bool iE_Extensions_present; +}LIBLTE_S1AP_UE_S1AP_ID_PAIR_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_ue_s1ap_id_pair( + LIBLTE_S1AP_UE_S1AP_ID_PAIR_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_ue_s1ap_id_pair( + uint8_t **ptr, + LIBLTE_S1AP_UE_S1AP_ID_PAIR_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE UEIdentityIndexValue STATIC BIT STRING +********************************************************************************/ +#define LIBLTE_S1AP_UEIDENTITYINDEXVALUE_BIT_STRING_LEN 10 +typedef struct{ + uint8_t buffer[10]; +}LIBLTE_S1AP_UEIDENTITYINDEXVALUE_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_ueidentityindexvalue( + LIBLTE_S1AP_UEIDENTITYINDEXVALUE_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_ueidentityindexvalue( + uint8_t **ptr, + LIBLTE_S1AP_UEIDENTITYINDEXVALUE_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE UESecurityCapabilities SEQUENCE +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_ENCRYPTIONALGORITHMS_STRUCT encryptionAlgorithms; + LIBLTE_S1AP_INTEGRITYPROTECTIONALGORITHMS_STRUCT integrityProtectionAlgorithms; + LIBLTE_S1AP_PROTOCOLEXTENSIONCONTAINER_STRUCT iE_Extensions; + bool iE_Extensions_present; +}LIBLTE_S1AP_UESECURITYCAPABILITIES_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_uesecuritycapabilities( + LIBLTE_S1AP_UESECURITYCAPABILITIES_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_uesecuritycapabilities( + uint8_t **ptr, + LIBLTE_S1AP_UESECURITYCAPABILITIES_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE VoiceSupportMatchIndicator ENUMERATED +********************************************************************************/ +typedef enum{ + LIBLTE_S1AP_VOICESUPPORTMATCHINDICATOR_SUPPORTED, + LIBLTE_S1AP_VOICESUPPORTMATCHINDICATOR_NOT_SUPPORTED, + LIBLTE_S1AP_VOICESUPPORTMATCHINDICATOR_N_ITEMS, +}LIBLTE_S1AP_VOICESUPPORTMATCHINDICATOR_ENUM; +static const char liblte_s1ap_voicesupportmatchindicator_text[LIBLTE_S1AP_VOICESUPPORTMATCHINDICATOR_N_ITEMS][80] = { + "supported", + "not-supported", +}; + +typedef struct{ + bool ext; + LIBLTE_S1AP_VOICESUPPORTMATCHINDICATOR_ENUM e; +}LIBLTE_S1AP_VOICESUPPORTMATCHINDICATOR_ENUM_EXT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_voicesupportmatchindicator( + LIBLTE_S1AP_VOICESUPPORTMATCHINDICATOR_ENUM_EXT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_voicesupportmatchindicator( + uint8_t **ptr, + LIBLTE_S1AP_VOICESUPPORTMATCHINDICATOR_ENUM_EXT *ie); + +/******************************************************************************* +/* ProtocolIE WarningSecurityInfo STATIC OCTET STRING +********************************************************************************/ +#define LIBLTE_S1AP_WARNINGSECURITYINFO_OCTET_STRING_LEN 50 +typedef struct{ + uint8_t buffer[50]; +}LIBLTE_S1AP_WARNINGSECURITYINFO_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_warningsecurityinfo( + LIBLTE_S1AP_WARNINGSECURITYINFO_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_warningsecurityinfo( + uint8_t **ptr, + LIBLTE_S1AP_WARNINGSECURITYINFO_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE ENBX2GTPTLAs DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:16 +typedef struct{ + uint32_t len; + LIBLTE_S1AP_TRANSPORTLAYERADDRESS_STRUCT buffer[32]; //WARNING: Artificial limit to reduce memory footprint +}LIBLTE_S1AP_ENBX2GTPTLAS_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_enbx2gtptlas( + LIBLTE_S1AP_ENBX2GTPTLAS_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_enbx2gtptlas( + uint8_t **ptr, + LIBLTE_S1AP_ENBX2GTPTLAS_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE CauseTransport ENUMERATED +********************************************************************************/ +typedef enum{ + LIBLTE_S1AP_CAUSETRANSPORT_TRANSPORT_RESOURCE_UNAVAILABLE, + LIBLTE_S1AP_CAUSETRANSPORT_UNSPECIFIED, + LIBLTE_S1AP_CAUSETRANSPORT_N_ITEMS, +}LIBLTE_S1AP_CAUSETRANSPORT_ENUM; +static const char liblte_s1ap_causetransport_text[LIBLTE_S1AP_CAUSETRANSPORT_N_ITEMS][80] = { + "transport-resource-unavailable", + "unspecified", +}; + +typedef struct{ + bool ext; + LIBLTE_S1AP_CAUSETRANSPORT_ENUM e; +}LIBLTE_S1AP_CAUSETRANSPORT_ENUM_EXT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_causetransport( + LIBLTE_S1AP_CAUSETRANSPORT_ENUM_EXT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_causetransport( + uint8_t **ptr, + LIBLTE_S1AP_CAUSETRANSPORT_ENUM_EXT *ie); + +/******************************************************************************* +/* ProtocolIE Cdma2000HOStatus ENUMERATED +********************************************************************************/ +typedef enum{ + LIBLTE_S1AP_CDMA2000HOSTATUS_HOSUCCESS, + LIBLTE_S1AP_CDMA2000HOSTATUS_HOFAILURE, + LIBLTE_S1AP_CDMA2000HOSTATUS_N_ITEMS, +}LIBLTE_S1AP_CDMA2000HOSTATUS_ENUM; +static const char liblte_s1ap_cdma2000hostatus_text[LIBLTE_S1AP_CDMA2000HOSTATUS_N_ITEMS][80] = { + "hOSuccess", + "hOFailure", +}; + +typedef struct{ + bool ext; + LIBLTE_S1AP_CDMA2000HOSTATUS_ENUM e; +}LIBLTE_S1AP_CDMA2000HOSTATUS_ENUM_EXT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_cdma2000hostatus( + LIBLTE_S1AP_CDMA2000HOSTATUS_ENUM_EXT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_cdma2000hostatus( + uint8_t **ptr, + LIBLTE_S1AP_CDMA2000HOSTATUS_ENUM_EXT *ie); + +/******************************************************************************* +/* ProtocolIE Cdma2000OneXPilot DYNAMIC OCTET STRING +********************************************************************************/ +// lb:0, ub:16318 +typedef struct{ + uint32_t n_octets; + uint8_t buffer[16318]; +}LIBLTE_S1AP_CDMA2000ONEXPILOT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_cdma2000onexpilot( + LIBLTE_S1AP_CDMA2000ONEXPILOT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_cdma2000onexpilot( + uint8_t **ptr, + LIBLTE_S1AP_CDMA2000ONEXPILOT_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE ConcurrentWarningMessageIndicator ENUMERATED +********************************************************************************/ +typedef enum{ + LIBLTE_S1AP_CONCURRENTWARNINGMESSAGEINDICATOR_TRUE, + LIBLTE_S1AP_CONCURRENTWARNINGMESSAGEINDICATOR_N_ITEMS, +}LIBLTE_S1AP_CONCURRENTWARNINGMESSAGEINDICATOR_ENUM; +static const char liblte_s1ap_concurrentwarningmessageindicator_text[LIBLTE_S1AP_CONCURRENTWARNINGMESSAGEINDICATOR_N_ITEMS][80] = { + "true", +}; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_concurrentwarningmessageindicator( + LIBLTE_S1AP_CONCURRENTWARNINGMESSAGEINDICATOR_ENUM *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_concurrentwarningmessageindicator( + uint8_t **ptr, + LIBLTE_S1AP_CONCURRENTWARNINGMESSAGEINDICATOR_ENUM *ie); + +/******************************************************************************* +/* ProtocolIE COUNTvalue SEQUENCE +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_PDCP_SN_STRUCT pDCP_SN; + LIBLTE_S1AP_HFN_STRUCT hFN; + LIBLTE_S1AP_PROTOCOLEXTENSIONCONTAINER_STRUCT iE_Extensions; + bool iE_Extensions_present; +}LIBLTE_S1AP_COUNTVALUE_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_countvalue( + LIBLTE_S1AP_COUNTVALUE_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_countvalue( + uint8_t **ptr, + LIBLTE_S1AP_COUNTVALUE_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE CriticalityDiagnostics_IE_Item SEQUENCE +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_CRITICALITY_ENUM iECriticality; + LIBLTE_S1AP_PROTOCOLIE_ID_STRUCT iE_ID; + LIBLTE_S1AP_TYPEOFERROR_ENUM_EXT typeOfError; + LIBLTE_S1AP_PROTOCOLEXTENSIONCONTAINER_STRUCT iE_Extensions; + bool iE_Extensions_present; +}LIBLTE_S1AP_CRITICALITYDIAGNOSTICS_IE_ITEM_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_criticalitydiagnostics_ie_item( + LIBLTE_S1AP_CRITICALITYDIAGNOSTICS_IE_ITEM_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_criticalitydiagnostics_ie_item( + uint8_t **ptr, + LIBLTE_S1AP_CRITICALITYDIAGNOSTICS_IE_ITEM_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE ENBX2TLAs DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:2 +typedef struct{ + uint32_t len; + LIBLTE_S1AP_TRANSPORTLAYERADDRESS_STRUCT buffer[32]; //WARNING: Artificial limit to reduce memory footprint +}LIBLTE_S1AP_ENBX2TLAS_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_enbx2tlas( + LIBLTE_S1AP_ENBX2TLAS_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_enbx2tlas( + uint8_t **ptr, + LIBLTE_S1AP_ENBX2TLAS_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE ExtendedRepetitionPeriod INTEGER +********************************************************************************/ +typedef struct{ +uint32_t ExtendedRepetitionPeriod; +}LIBLTE_S1AP_EXTENDEDREPETITIONPERIOD_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_extendedrepetitionperiod( + LIBLTE_S1AP_EXTENDEDREPETITIONPERIOD_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_extendedrepetitionperiod( + uint8_t **ptr, + LIBLTE_S1AP_EXTENDEDREPETITIONPERIOD_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE ForbiddenTACs DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:4096 +typedef struct{ + uint32_t len; + LIBLTE_S1AP_TAC_STRUCT buffer[32]; //WARNING: Artificial limit to reduce memory footprint +}LIBLTE_S1AP_FORBIDDENTACS_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_forbiddentacs( + LIBLTE_S1AP_FORBIDDENTACS_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_forbiddentacs( + uint8_t **ptr, + LIBLTE_S1AP_FORBIDDENTACS_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE GBR_QosInformation SEQUENCE +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_BITRATE_STRUCT e_RAB_MaximumBitrateDL; + LIBLTE_S1AP_BITRATE_STRUCT e_RAB_MaximumBitrateUL; + LIBLTE_S1AP_BITRATE_STRUCT e_RAB_GuaranteedBitrateDL; + LIBLTE_S1AP_BITRATE_STRUCT e_RAB_GuaranteedBitrateUL; + LIBLTE_S1AP_PROTOCOLEXTENSIONCONTAINER_STRUCT iE_Extensions; + bool iE_Extensions_present; +}LIBLTE_S1AP_GBR_QOSINFORMATION_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_gbr_qosinformation( + LIBLTE_S1AP_GBR_QOSINFORMATION_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_gbr_qosinformation( + uint8_t **ptr, + LIBLTE_S1AP_GBR_QOSINFORMATION_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE HFNModified INTEGER +********************************************************************************/ +typedef struct{ +uint32_t HFNModified; +}LIBLTE_S1AP_HFNMODIFIED_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_hfnmodified( + LIBLTE_S1AP_HFNMODIFIED_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_hfnmodified( + uint8_t **ptr, + LIBLTE_S1AP_HFNMODIFIED_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE KillAllWarningMessages ENUMERATED +********************************************************************************/ +typedef enum{ + LIBLTE_S1AP_KILLALLWARNINGMESSAGES_TRUE, + LIBLTE_S1AP_KILLALLWARNINGMESSAGES_N_ITEMS, +}LIBLTE_S1AP_KILLALLWARNINGMESSAGES_ENUM; +static const char liblte_s1ap_killallwarningmessages_text[LIBLTE_S1AP_KILLALLWARNINGMESSAGES_N_ITEMS][80] = { + "true", +}; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_killallwarningmessages( + LIBLTE_S1AP_KILLALLWARNINGMESSAGES_ENUM *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_killallwarningmessages( + uint8_t **ptr, + LIBLTE_S1AP_KILLALLWARNINGMESSAGES_ENUM *ie); + +/******************************************************************************* +/* ProtocolIE LPPa_PDU DYNAMIC OCTET STRING +********************************************************************************/ +// lb:0, ub:16318 +typedef struct{ + uint32_t n_octets; + uint8_t buffer[16318]; +}LIBLTE_S1AP_LPPA_PDU_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_lppa_pdu( + LIBLTE_S1AP_LPPA_PDU_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_lppa_pdu( + uint8_t **ptr, + LIBLTE_S1AP_LPPA_PDU_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE M3Configuration SEQUENCE +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_M3PERIOD_ENUM_EXT m3period; + LIBLTE_S1AP_PROTOCOLEXTENSIONCONTAINER_STRUCT iE_Extensions; + bool iE_Extensions_present; +}LIBLTE_S1AP_M3CONFIGURATION_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_m3configuration( + LIBLTE_S1AP_M3CONFIGURATION_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_m3configuration( + uint8_t **ptr, + LIBLTE_S1AP_M3CONFIGURATION_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE M5Configuration SEQUENCE +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_M5PERIOD_ENUM_EXT m5period; + LIBLTE_S1AP_LINKS_TO_LOG_ENUM_EXT m5_links_to_log; + LIBLTE_S1AP_PROTOCOLEXTENSIONCONTAINER_STRUCT iE_Extensions; + bool iE_Extensions_present; +}LIBLTE_S1AP_M5CONFIGURATION_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_m5configuration( + LIBLTE_S1AP_M5CONFIGURATION_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_m5configuration( + uint8_t **ptr, + LIBLTE_S1AP_M5CONFIGURATION_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE MeasurementThresholdA2 CHOICE +********************************************************************************/ +typedef enum{ + LIBLTE_S1AP_MEASUREMENTTHRESHOLDA2_CHOICE_THRESHOLD_RSRP, + LIBLTE_S1AP_MEASUREMENTTHRESHOLDA2_CHOICE_THRESHOLD_RSRQ, + LIBLTE_S1AP_MEASUREMENTTHRESHOLDA2_CHOICE_N_ITEMS, +}LIBLTE_S1AP_MEASUREMENTTHRESHOLDA2_CHOICE_ENUM; +static const char liblte_s1ap_measurementthresholda2_choice_text[LIBLTE_S1AP_MEASUREMENTTHRESHOLDA2_CHOICE_N_ITEMS][50] = { + "threshold_RSRP", + "threshold_RSRQ", +}; + +typedef union{ + LIBLTE_S1AP_THRESHOLD_RSRP_STRUCT threshold_RSRP; + LIBLTE_S1AP_THRESHOLD_RSRQ_STRUCT threshold_RSRQ; +}LIBLTE_S1AP_MEASUREMENTTHRESHOLDA2_CHOICE_UNION; + +typedef struct{ + bool ext; + LIBLTE_S1AP_MEASUREMENTTHRESHOLDA2_CHOICE_UNION choice; + LIBLTE_S1AP_MEASUREMENTTHRESHOLDA2_CHOICE_ENUM choice_type; +}LIBLTE_S1AP_MEASUREMENTTHRESHOLDA2_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_measurementthresholda2( + LIBLTE_S1AP_MEASUREMENTTHRESHOLDA2_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_measurementthresholda2( + uint8_t **ptr, + LIBLTE_S1AP_MEASUREMENTTHRESHOLDA2_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE M_TMSI STATIC OCTET STRING +********************************************************************************/ +#define LIBLTE_S1AP_M_TMSI_OCTET_STRING_LEN 4 +typedef struct{ + uint8_t buffer[4]; +}LIBLTE_S1AP_M_TMSI_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_m_tmsi( + LIBLTE_S1AP_M_TMSI_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_m_tmsi( + uint8_t **ptr, + LIBLTE_S1AP_M_TMSI_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE OldBSS_ToNewBSS_Information DYNAMIC OCTET STRING +********************************************************************************/ +// lb:0, ub:16318 +typedef struct{ + uint32_t n_octets; + uint8_t buffer[16318]; +}LIBLTE_S1AP_OLDBSS_TONEWBSS_INFORMATION_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_oldbss_tonewbss_information( + LIBLTE_S1AP_OLDBSS_TONEWBSS_INFORMATION_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_oldbss_tonewbss_information( + uint8_t **ptr, + LIBLTE_S1AP_OLDBSS_TONEWBSS_INFORMATION_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE PLMNidentity STATIC OCTET STRING +********************************************************************************/ +#define LIBLTE_S1AP_PLMNIDENTITY_OCTET_STRING_LEN 3 +typedef struct{ + uint8_t buffer[3]; +}LIBLTE_S1AP_PLMNIDENTITY_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_plmnidentity( + LIBLTE_S1AP_PLMNIDENTITY_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_plmnidentity( + uint8_t **ptr, + LIBLTE_S1AP_PLMNIDENTITY_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE ReceiveStatusOfULPDCPSDUsExtended DYNAMIC BIT STRING +********************************************************************************/ +// lb:1, ub:16384 +typedef struct{ + uint32_t n_bits; + uint8_t buffer[16384]; +}LIBLTE_S1AP_RECEIVESTATUSOFULPDCPSDUSEXTENDED_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_receivestatusofulpdcpsdusextended( + LIBLTE_S1AP_RECEIVESTATUSOFULPDCPSDUSEXTENDED_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_receivestatusofulpdcpsdusextended( + uint8_t **ptr, + LIBLTE_S1AP_RECEIVESTATUSOFULPDCPSDUSEXTENDED_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE RequestType SEQUENCE +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_EVENTTYPE_ENUM_EXT eventType; + LIBLTE_S1AP_REPORTAREA_ENUM_EXT reportArea; + LIBLTE_S1AP_PROTOCOLEXTENSIONCONTAINER_STRUCT iE_Extensions; + bool iE_Extensions_present; +}LIBLTE_S1AP_REQUESTTYPE_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_requesttype( + LIBLTE_S1AP_REQUESTTYPE_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_requesttype( + uint8_t **ptr, + LIBLTE_S1AP_REQUESTTYPE_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE RRC_Container DYNAMIC OCTET STRING +********************************************************************************/ +// lb:0, ub:16318 +typedef struct{ + uint32_t n_octets; + uint8_t buffer[16318]; +}LIBLTE_S1AP_RRC_CONTAINER_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_rrc_container( + LIBLTE_S1AP_RRC_CONTAINER_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_rrc_container( + uint8_t **ptr, + LIBLTE_S1AP_RRC_CONTAINER_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE nextHopChainingCount INTEGER +********************************************************************************/ +typedef struct{ +uint8_t nextHopChainingCount; +}LIBLTE_S1AP_NEXTHOPCHAININGCOUNT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_nexthopchainingcount( + LIBLTE_S1AP_NEXTHOPCHAININGCOUNT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_nexthopchainingcount( + uint8_t **ptr, + LIBLTE_S1AP_NEXTHOPCHAININGCOUNT_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE SecurityContext SEQUENCE +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_NEXTHOPCHAININGCOUNT_STRUCT nextHopChainingCount; + LIBLTE_S1AP_SECURITYKEY_STRUCT nextHopParameter; + LIBLTE_S1AP_PROTOCOLEXTENSIONCONTAINER_STRUCT iE_Extensions; + bool iE_Extensions_present; +}LIBLTE_S1AP_SECURITYCONTEXT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_securitycontext( + LIBLTE_S1AP_SECURITYCONTEXT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_securitycontext( + uint8_t **ptr, + LIBLTE_S1AP_SECURITYCONTEXT_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE ServedMMECs DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:256 +typedef struct{ + uint32_t len; + LIBLTE_S1AP_MME_CODE_STRUCT buffer[32]; //WARNING: Artificial limit to reduce memory footprint +}LIBLTE_S1AP_SERVEDMMECS_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_servedmmecs( + LIBLTE_S1AP_SERVEDMMECS_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_servedmmecs( + uint8_t **ptr, + LIBLTE_S1AP_SERVEDMMECS_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE TimeSynchronizationInfo SEQUENCE +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_STRATUMLEVEL_STRUCT stratumLevel; + LIBLTE_S1AP_SYNCHRONIZATIONSTATUS_ENUM_EXT synchronizationStatus; + LIBLTE_S1AP_PROTOCOLEXTENSIONCONTAINER_STRUCT iE_Extensions; + bool iE_Extensions_present; +}LIBLTE_S1AP_TIMESYNCHRONIZATIONINFO_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_timesynchronizationinfo( + LIBLTE_S1AP_TIMESYNCHRONIZATIONINFO_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_timesynchronizationinfo( + uint8_t **ptr, + LIBLTE_S1AP_TIMESYNCHRONIZATIONINFO_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE TAI SEQUENCE +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_TBCD_STRING_STRUCT pLMNidentity; + LIBLTE_S1AP_TAC_STRUCT tAC; + LIBLTE_S1AP_PROTOCOLEXTENSIONCONTAINER_STRUCT iE_Extensions; + bool iE_Extensions_present; +}LIBLTE_S1AP_TAI_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_tai( + LIBLTE_S1AP_TAI_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_tai( + uint8_t **ptr, + LIBLTE_S1AP_TAI_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE TABasedMDT SEQUENCE +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_TALISTFORMDT_STRUCT tAListforMDT; + LIBLTE_S1AP_PROTOCOLEXTENSIONCONTAINER_STRUCT iE_Extensions; + bool iE_Extensions_present; +}LIBLTE_S1AP_TABASEDMDT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_tabasedmdt( + LIBLTE_S1AP_TABASEDMDT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_tabasedmdt( + uint8_t **ptr, + LIBLTE_S1AP_TABASEDMDT_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE TargeteNB_ToSourceeNB_TransparentContainer SEQUENCE +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_RRC_CONTAINER_STRUCT rRC_Container; + LIBLTE_S1AP_PROTOCOLEXTENSIONCONTAINER_STRUCT iE_Extensions; + bool iE_Extensions_present; +}LIBLTE_S1AP_TARGETENB_TOSOURCEENB_TRANSPARENTCONTAINER_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_targetenb_tosourceenb_transparentcontainer( + LIBLTE_S1AP_TARGETENB_TOSOURCEENB_TRANSPARENTCONTAINER_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_targetenb_tosourceenb_transparentcontainer( + uint8_t **ptr, + LIBLTE_S1AP_TARGETENB_TOSOURCEENB_TRANSPARENTCONTAINER_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE M1ThresholdEventA2 SEQUENCE +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_MEASUREMENTTHRESHOLDA2_STRUCT measurementThreshold; + LIBLTE_S1AP_PROTOCOLEXTENSIONCONTAINER_STRUCT iE_Extensions; + bool iE_Extensions_present; +}LIBLTE_S1AP_M1THRESHOLDEVENTA2_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_m1thresholdeventa2( + LIBLTE_S1AP_M1THRESHOLDEVENTA2_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_m1thresholdeventa2( + uint8_t **ptr, + LIBLTE_S1AP_M1THRESHOLDEVENTA2_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE TransportInformation SEQUENCE +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_TRANSPORTLAYERADDRESS_STRUCT transportLayerAddress; + LIBLTE_S1AP_GTP_TEID_STRUCT uL_GTP_TEID; +}LIBLTE_S1AP_TRANSPORTINFORMATION_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_transportinformation( + LIBLTE_S1AP_TRANSPORTINFORMATION_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_transportinformation( + uint8_t **ptr, + LIBLTE_S1AP_TRANSPORTINFORMATION_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE TunnelInformation SEQUENCE +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_TRANSPORTLAYERADDRESS_STRUCT transportLayerAddress; + LIBLTE_S1AP_PORT_NUMBER_STRUCT uDP_Port_Number; + bool uDP_Port_Number_present; + LIBLTE_S1AP_PROTOCOLEXTENSIONCONTAINER_STRUCT iE_Extensions; + bool iE_Extensions_present; +}LIBLTE_S1AP_TUNNELINFORMATION_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_tunnelinformation( + LIBLTE_S1AP_TUNNELINFORMATION_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_tunnelinformation( + uint8_t **ptr, + LIBLTE_S1AP_TUNNELINFORMATION_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE UE_S1AP_IDs CHOICE +********************************************************************************/ +typedef enum{ + LIBLTE_S1AP_UE_S1AP_IDS_CHOICE_UE_S1AP_ID_PAIR, + LIBLTE_S1AP_UE_S1AP_IDS_CHOICE_MME_UE_S1AP_ID, + LIBLTE_S1AP_UE_S1AP_IDS_CHOICE_N_ITEMS, +}LIBLTE_S1AP_UE_S1AP_IDS_CHOICE_ENUM; +static const char liblte_s1ap_ue_s1ap_ids_choice_text[LIBLTE_S1AP_UE_S1AP_IDS_CHOICE_N_ITEMS][50] = { + "uE_S1AP_ID_pair", + "mME_UE_S1AP_ID", +}; + +typedef union{ + LIBLTE_S1AP_UE_S1AP_ID_PAIR_STRUCT uE_S1AP_ID_pair; + LIBLTE_S1AP_MME_UE_S1AP_ID_STRUCT mME_UE_S1AP_ID; +}LIBLTE_S1AP_UE_S1AP_IDS_CHOICE_UNION; + +typedef struct{ + bool ext; + LIBLTE_S1AP_UE_S1AP_IDS_CHOICE_UNION choice; + LIBLTE_S1AP_UE_S1AP_IDS_CHOICE_ENUM choice_type; +}LIBLTE_S1AP_UE_S1AP_IDS_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_ue_s1ap_ids( + LIBLTE_S1AP_UE_S1AP_IDS_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_ue_s1ap_ids( + uint8_t **ptr, + LIBLTE_S1AP_UE_S1AP_IDS_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE ENBX2ExtTLA SEQUENCE +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_TRANSPORTLAYERADDRESS_STRUCT iPsecTLA; + bool iPsecTLA_present; + LIBLTE_S1AP_ENBX2GTPTLAS_STRUCT gTPTLAa; + bool gTPTLAa_present; + LIBLTE_S1AP_PROTOCOLEXTENSIONCONTAINER_STRUCT iE_Extensions; + bool iE_Extensions_present; +}LIBLTE_S1AP_ENBX2EXTTLA_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_enbx2exttla( + LIBLTE_S1AP_ENBX2EXTTLA_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_enbx2exttla( + uint8_t **ptr, + LIBLTE_S1AP_ENBX2EXTTLA_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE BPLMNs DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:6 +typedef struct{ + uint32_t len; + LIBLTE_S1AP_TBCD_STRING_STRUCT buffer[32]; //WARNING: Artificial limit to reduce memory footprint +}LIBLTE_S1AP_BPLMNS_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_bplmns( + LIBLTE_S1AP_BPLMNS_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_bplmns( + uint8_t **ptr, + LIBLTE_S1AP_BPLMNS_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE Cause CHOICE +********************************************************************************/ +typedef enum{ + LIBLTE_S1AP_CAUSE_CHOICE_RADIONETWORK, + LIBLTE_S1AP_CAUSE_CHOICE_TRANSPORT, + LIBLTE_S1AP_CAUSE_CHOICE_NAS, + LIBLTE_S1AP_CAUSE_CHOICE_PROTOCOL, + LIBLTE_S1AP_CAUSE_CHOICE_MISC, + LIBLTE_S1AP_CAUSE_CHOICE_N_ITEMS, +}LIBLTE_S1AP_CAUSE_CHOICE_ENUM; +static const char liblte_s1ap_cause_choice_text[LIBLTE_S1AP_CAUSE_CHOICE_N_ITEMS][50] = { + "radioNetwork", + "transport", + "nas", + "protocol", + "misc", +}; + +typedef union{ + LIBLTE_S1AP_CAUSERADIONETWORK_ENUM_EXT radioNetwork; + LIBLTE_S1AP_CAUSETRANSPORT_ENUM_EXT transport; + LIBLTE_S1AP_CAUSENAS_ENUM_EXT nas; + LIBLTE_S1AP_CAUSEPROTOCOL_ENUM_EXT protocol; + LIBLTE_S1AP_CAUSEMISC_ENUM_EXT misc; +}LIBLTE_S1AP_CAUSE_CHOICE_UNION; + +typedef struct{ + bool ext; + LIBLTE_S1AP_CAUSE_CHOICE_UNION choice; + LIBLTE_S1AP_CAUSE_CHOICE_ENUM choice_type; +}LIBLTE_S1AP_CAUSE_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_cause( + LIBLTE_S1AP_CAUSE_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_cause( + uint8_t **ptr, + LIBLTE_S1AP_CAUSE_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE Cdma2000OneXSRVCCInfo SEQUENCE +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_CDMA2000ONEXMEID_STRUCT cdma2000OneXMEID; + LIBLTE_S1AP_CDMA2000ONEXMSI_STRUCT cdma2000OneXMSI; + LIBLTE_S1AP_CDMA2000ONEXPILOT_STRUCT cdma2000OneXPilot; + LIBLTE_S1AP_PROTOCOLEXTENSIONCONTAINER_STRUCT iE_Extensions; + bool iE_Extensions_present; +}LIBLTE_S1AP_CDMA2000ONEXSRVCCINFO_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_cdma2000onexsrvccinfo( + LIBLTE_S1AP_CDMA2000ONEXSRVCCINFO_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_cdma2000onexsrvccinfo( + uint8_t **ptr, + LIBLTE_S1AP_CDMA2000ONEXSRVCCINFO_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE CGI SEQUENCE +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_TBCD_STRING_STRUCT pLMNidentity; + LIBLTE_S1AP_LAC_STRUCT lAC; + LIBLTE_S1AP_CI_STRUCT cI; + LIBLTE_S1AP_RAC_STRUCT rAC; + bool rAC_present; + LIBLTE_S1AP_PROTOCOLEXTENSIONCONTAINER_STRUCT iE_Extensions; + bool iE_Extensions_present; +}LIBLTE_S1AP_CGI_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_cgi( + LIBLTE_S1AP_CGI_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_cgi( + uint8_t **ptr, + LIBLTE_S1AP_CGI_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE COUNTValueExtended SEQUENCE +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_PDCP_SNEXTENDED_STRUCT pDCP_SNExtended; + LIBLTE_S1AP_HFNMODIFIED_STRUCT hFNModified; + LIBLTE_S1AP_PROTOCOLEXTENSIONCONTAINER_STRUCT iE_Extensions; + bool iE_Extensions_present; +}LIBLTE_S1AP_COUNTVALUEEXTENDED_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_countvalueextended( + LIBLTE_S1AP_COUNTVALUEEXTENDED_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_countvalueextended( + uint8_t **ptr, + LIBLTE_S1AP_COUNTVALUEEXTENDED_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE CriticalityDiagnostics_IE_List DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:256 +typedef struct{ + uint32_t len; + LIBLTE_S1AP_CRITICALITYDIAGNOSTICS_IE_ITEM_STRUCT buffer[32]; //WARNING: Artificial limit to reduce memory footprint +}LIBLTE_S1AP_CRITICALITYDIAGNOSTICS_IE_LIST_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_criticalitydiagnostics_ie_list( + LIBLTE_S1AP_CRITICALITYDIAGNOSTICS_IE_LIST_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_criticalitydiagnostics_ie_list( + uint8_t **ptr, + LIBLTE_S1AP_CRITICALITYDIAGNOSTICS_IE_LIST_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE Global_ENB_ID SEQUENCE +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_TBCD_STRING_STRUCT pLMNidentity; + LIBLTE_S1AP_ENB_ID_STRUCT eNB_ID; + LIBLTE_S1AP_PROTOCOLEXTENSIONCONTAINER_STRUCT iE_Extensions; + bool iE_Extensions_present; +}LIBLTE_S1AP_GLOBAL_ENB_ID_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_global_enb_id( + LIBLTE_S1AP_GLOBAL_ENB_ID_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_global_enb_id( + uint8_t **ptr, + LIBLTE_S1AP_GLOBAL_ENB_ID_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE EPLMNs DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:15 +typedef struct{ + uint32_t len; + LIBLTE_S1AP_TBCD_STRING_STRUCT buffer[32]; //WARNING: Artificial limit to reduce memory footprint +}LIBLTE_S1AP_EPLMNS_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_eplmns( + LIBLTE_S1AP_EPLMNS_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_eplmns( + uint8_t **ptr, + LIBLTE_S1AP_EPLMNS_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE E_RABItem SEQUENCE +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_E_RAB_ID_STRUCT e_RAB_ID; + LIBLTE_S1AP_CAUSE_STRUCT cause; + LIBLTE_S1AP_PROTOCOLEXTENSIONCONTAINER_STRUCT iE_Extensions; + bool iE_Extensions_present; +}LIBLTE_S1AP_E_RABITEM_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabitem( + LIBLTE_S1AP_E_RABITEM_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabitem( + uint8_t **ptr, + LIBLTE_S1AP_E_RABITEM_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE EUTRAN_CGI SEQUENCE +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_TBCD_STRING_STRUCT pLMNidentity; + LIBLTE_S1AP_CELLIDENTITY_STRUCT cell_ID; + LIBLTE_S1AP_PROTOCOLEXTENSIONCONTAINER_STRUCT iE_Extensions; + bool iE_Extensions_present; +}LIBLTE_S1AP_EUTRAN_CGI_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_eutran_cgi( + LIBLTE_S1AP_EUTRAN_CGI_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_eutran_cgi( + uint8_t **ptr, + LIBLTE_S1AP_EUTRAN_CGI_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE ForbiddenTAs_Item SEQUENCE +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_TBCD_STRING_STRUCT pLMN_Identity; + LIBLTE_S1AP_FORBIDDENTACS_STRUCT forbiddenTACs; + LIBLTE_S1AP_PROTOCOLEXTENSIONCONTAINER_STRUCT iE_Extensions; + bool iE_Extensions_present; +}LIBLTE_S1AP_FORBIDDENTAS_ITEM_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_forbiddentas_item( + LIBLTE_S1AP_FORBIDDENTAS_ITEM_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_forbiddentas_item( + uint8_t **ptr, + LIBLTE_S1AP_FORBIDDENTAS_ITEM_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE ForbiddenLAs_Item SEQUENCE +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_TBCD_STRING_STRUCT pLMN_Identity; + LIBLTE_S1AP_FORBIDDENLACS_STRUCT forbiddenLACs; + LIBLTE_S1AP_PROTOCOLEXTENSIONCONTAINER_STRUCT iE_Extensions; + bool iE_Extensions_present; +}LIBLTE_S1AP_FORBIDDENLAS_ITEM_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_forbiddenlas_item( + LIBLTE_S1AP_FORBIDDENLAS_ITEM_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_forbiddenlas_item( + uint8_t **ptr, + LIBLTE_S1AP_FORBIDDENLAS_ITEM_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE LAI SEQUENCE +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_TBCD_STRING_STRUCT pLMNidentity; + LIBLTE_S1AP_LAC_STRUCT lAC; + LIBLTE_S1AP_PROTOCOLEXTENSIONCONTAINER_STRUCT iE_Extensions; + bool iE_Extensions_present; +}LIBLTE_S1AP_LAI_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_lai( + LIBLTE_S1AP_LAI_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_lai( + uint8_t **ptr, + LIBLTE_S1AP_LAI_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE M4Configuration SEQUENCE +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_M4PERIOD_ENUM_EXT m4period; + LIBLTE_S1AP_LINKS_TO_LOG_ENUM_EXT m4_links_to_log; + LIBLTE_S1AP_PROTOCOLEXTENSIONCONTAINER_STRUCT iE_Extensions; + bool iE_Extensions_present; +}LIBLTE_S1AP_M4CONFIGURATION_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_m4configuration( + LIBLTE_S1AP_M4CONFIGURATION_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_m4configuration( + uint8_t **ptr, + LIBLTE_S1AP_M4CONFIGURATION_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE MDTPLMNList DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:16 +typedef struct{ + uint32_t len; + LIBLTE_S1AP_TBCD_STRING_STRUCT buffer[32]; //WARNING: Artificial limit to reduce memory footprint +}LIBLTE_S1AP_MDTPLMNLIST_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_mdtplmnlist( + LIBLTE_S1AP_MDTPLMNLIST_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_mdtplmnlist( + uint8_t **ptr, + LIBLTE_S1AP_MDTPLMNLIST_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE MMERelaySupportIndicator ENUMERATED +********************************************************************************/ +typedef enum{ + LIBLTE_S1AP_MMERELAYSUPPORTINDICATOR_TRUE, + LIBLTE_S1AP_MMERELAYSUPPORTINDICATOR_N_ITEMS, +}LIBLTE_S1AP_MMERELAYSUPPORTINDICATOR_ENUM; +static const char liblte_s1ap_mmerelaysupportindicator_text[LIBLTE_S1AP_MMERELAYSUPPORTINDICATOR_N_ITEMS][80] = { + "true", +}; + +typedef struct{ + bool ext; + LIBLTE_S1AP_MMERELAYSUPPORTINDICATOR_ENUM e; +}LIBLTE_S1AP_MMERELAYSUPPORTINDICATOR_ENUM_EXT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_mmerelaysupportindicator( + LIBLTE_S1AP_MMERELAYSUPPORTINDICATOR_ENUM_EXT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_mmerelaysupportindicator( + uint8_t **ptr, + LIBLTE_S1AP_MMERELAYSUPPORTINDICATOR_ENUM_EXT *ie); + +/******************************************************************************* +/* ProtocolIE PagingPriority ENUMERATED +********************************************************************************/ +typedef enum{ + LIBLTE_S1AP_PAGINGPRIORITY_PRIOLEVEL1, + LIBLTE_S1AP_PAGINGPRIORITY_PRIOLEVEL2, + LIBLTE_S1AP_PAGINGPRIORITY_PRIOLEVEL3, + LIBLTE_S1AP_PAGINGPRIORITY_PRIOLEVEL4, + LIBLTE_S1AP_PAGINGPRIORITY_PRIOLEVEL5, + LIBLTE_S1AP_PAGINGPRIORITY_PRIOLEVEL6, + LIBLTE_S1AP_PAGINGPRIORITY_PRIOLEVEL7, + LIBLTE_S1AP_PAGINGPRIORITY_PRIOLEVEL8, + LIBLTE_S1AP_PAGINGPRIORITY_N_ITEMS, +}LIBLTE_S1AP_PAGINGPRIORITY_ENUM; +static const char liblte_s1ap_pagingpriority_text[LIBLTE_S1AP_PAGINGPRIORITY_N_ITEMS][80] = { + "priolevel1", + "priolevel2", + "priolevel3", + "priolevel4", + "priolevel5", + "priolevel6", + "priolevel7", + "priolevel8", +}; + +typedef struct{ + bool ext; + LIBLTE_S1AP_PAGINGPRIORITY_ENUM e; +}LIBLTE_S1AP_PAGINGPRIORITY_ENUM_EXT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_pagingpriority( + LIBLTE_S1AP_PAGINGPRIORITY_ENUM_EXT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_pagingpriority( + uint8_t **ptr, + LIBLTE_S1AP_PAGINGPRIORITY_ENUM_EXT *ie); + +/******************************************************************************* +/* ProtocolIE PriorityLevel INTEGER +********************************************************************************/ +typedef struct{ +uint8_t PriorityLevel; +}LIBLTE_S1AP_PRIORITYLEVEL_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_prioritylevel( + LIBLTE_S1AP_PRIORITYLEVEL_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_prioritylevel( + uint8_t **ptr, + LIBLTE_S1AP_PRIORITYLEVEL_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE ECGIListForRestart DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:256 +typedef struct{ + uint32_t len; + LIBLTE_S1AP_EUTRAN_CGI_STRUCT buffer[32]; //WARNING: Artificial limit to reduce memory footprint +}LIBLTE_S1AP_ECGILISTFORRESTART_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_ecgilistforrestart( + LIBLTE_S1AP_ECGILISTFORRESTART_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_ecgilistforrestart( + uint8_t **ptr, + LIBLTE_S1AP_ECGILISTFORRESTART_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE SourceeNB_ID SEQUENCE +********************************************************************************/ +typedef struct{ + LIBLTE_S1AP_GLOBAL_ENB_ID_STRUCT global_ENB_ID; + LIBLTE_S1AP_TAI_STRUCT selected_TAI; + LIBLTE_S1AP_PROTOCOLEXTENSIONCONTAINER_STRUCT iE_Extensions; + bool iE_Extensions_present; +}LIBLTE_S1AP_SOURCEENB_ID_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_sourceenb_id( + LIBLTE_S1AP_SOURCEENB_ID_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_sourceenb_id( + uint8_t **ptr, + LIBLTE_S1AP_SOURCEENB_ID_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE ServedPLMNs DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:32 +typedef struct{ + uint32_t len; + LIBLTE_S1AP_TBCD_STRING_STRUCT buffer[32]; //WARNING: Artificial limit to reduce memory footprint +}LIBLTE_S1AP_SERVEDPLMNS_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_servedplmns( + LIBLTE_S1AP_SERVEDPLMNS_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_servedplmns( + uint8_t **ptr, + LIBLTE_S1AP_SERVEDPLMNS_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE SupportedTAs_Item SEQUENCE +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_TAC_STRUCT tAC; + LIBLTE_S1AP_BPLMNS_STRUCT broadcastPLMNs; + LIBLTE_S1AP_PROTOCOLEXTENSIONCONTAINER_STRUCT iE_Extensions; + bool iE_Extensions_present; +}LIBLTE_S1AP_SUPPORTEDTAS_ITEM_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_supportedtas_item( + LIBLTE_S1AP_SUPPORTEDTAS_ITEM_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_supportedtas_item( + uint8_t **ptr, + LIBLTE_S1AP_SUPPORTEDTAS_ITEM_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE TAIListforMDT DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:8 +typedef struct{ + uint32_t len; + LIBLTE_S1AP_TAI_STRUCT buffer[32]; //WARNING: Artificial limit to reduce memory footprint +}LIBLTE_S1AP_TAILISTFORMDT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_tailistformdt( + LIBLTE_S1AP_TAILISTFORMDT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_tailistformdt( + uint8_t **ptr, + LIBLTE_S1AP_TAILISTFORMDT_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE CompletedCellinTAI_Item SEQUENCE +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_EUTRAN_CGI_STRUCT eCGI; + LIBLTE_S1AP_PROTOCOLEXTENSIONCONTAINER_STRUCT iE_Extensions; + bool iE_Extensions_present; +}LIBLTE_S1AP_COMPLETEDCELLINTAI_ITEM_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_completedcellintai_item( + LIBLTE_S1AP_COMPLETEDCELLINTAI_ITEM_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_completedcellintai_item( + uint8_t **ptr, + LIBLTE_S1AP_COMPLETEDCELLINTAI_ITEM_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE TargeteNB_ID SEQUENCE +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_GLOBAL_ENB_ID_STRUCT global_ENB_ID; + LIBLTE_S1AP_TAI_STRUCT selected_TAI; + LIBLTE_S1AP_PROTOCOLEXTENSIONCONTAINER_STRUCT iE_Extensions; + bool iE_Extensions_present; +}LIBLTE_S1AP_TARGETENB_ID_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_targetenb_id( + LIBLTE_S1AP_TARGETENB_ID_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_targetenb_id( + uint8_t **ptr, + LIBLTE_S1AP_TARGETENB_ID_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE TargetBSS_ToSourceBSS_TransparentContainer DYNAMIC OCTET STRING +********************************************************************************/ +// lb:0, ub:16318 +typedef struct{ + uint32_t n_octets; + uint8_t buffer[16318]; +}LIBLTE_S1AP_TARGETBSS_TOSOURCEBSS_TRANSPARENTCONTAINER_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_targetbss_tosourcebss_transparentcontainer( + LIBLTE_S1AP_TARGETBSS_TOSOURCEBSS_TRANSPARENTCONTAINER_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_targetbss_tosourcebss_transparentcontainer( + uint8_t **ptr, + LIBLTE_S1AP_TARGETBSS_TOSOURCEBSS_TRANSPARENTCONTAINER_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE TAIListForRestart DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:2048 +typedef struct{ + uint32_t len; + LIBLTE_S1AP_TAI_STRUCT buffer[32]; //WARNING: Artificial limit to reduce memory footprint +}LIBLTE_S1AP_TAILISTFORRESTART_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_tailistforrestart( + LIBLTE_S1AP_TAILISTFORRESTART_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_tailistforrestart( + uint8_t **ptr, + LIBLTE_S1AP_TAILISTFORRESTART_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE UserLocationInformation SEQUENCE +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_EUTRAN_CGI_STRUCT eutran_cgi; + LIBLTE_S1AP_TAI_STRUCT tai; + LIBLTE_S1AP_PROTOCOLEXTENSIONCONTAINER_STRUCT iE_Extensions; + bool iE_Extensions_present; +}LIBLTE_S1AP_USERLOCATIONINFORMATION_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_userlocationinformation( + LIBLTE_S1AP_USERLOCATIONINFORMATION_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_userlocationinformation( + uint8_t **ptr, + LIBLTE_S1AP_USERLOCATIONINFORMATION_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE ENBX2ExtTLAs DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:16 +typedef struct{ + uint32_t len; + LIBLTE_S1AP_ENBX2EXTTLA_STRUCT buffer[32]; //WARNING: Artificial limit to reduce memory footprint +}LIBLTE_S1AP_ENBX2EXTTLAS_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_enbx2exttlas( + LIBLTE_S1AP_ENBX2EXTTLAS_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_enbx2exttlas( + uint8_t **ptr, + LIBLTE_S1AP_ENBX2EXTTLAS_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE AllocationAndRetentionPriority SEQUENCE +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_PRIORITYLEVEL_STRUCT priorityLevel; + LIBLTE_S1AP_PRE_EMPTIONCAPABILITY_ENUM pre_emptionCapability; + LIBLTE_S1AP_PRE_EMPTIONVULNERABILITY_ENUM pre_emptionVulnerability; + LIBLTE_S1AP_PROTOCOLEXTENSIONCONTAINER_STRUCT iE_Extensions; + bool iE_Extensions_present; +}LIBLTE_S1AP_ALLOCATIONANDRETENTIONPRIORITY_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_allocationandretentionpriority( + LIBLTE_S1AP_ALLOCATIONANDRETENTIONPRIORITY_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_allocationandretentionpriority( + uint8_t **ptr, + LIBLTE_S1AP_ALLOCATIONANDRETENTIONPRIORITY_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE CancelledCellinEAI_Item SEQUENCE +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_EUTRAN_CGI_STRUCT eCGI; + LIBLTE_S1AP_NUMBEROFBROADCASTS_STRUCT numberOfBroadcasts; + LIBLTE_S1AP_PROTOCOLEXTENSIONCONTAINER_STRUCT iE_Extensions; + bool iE_Extensions_present; +}LIBLTE_S1AP_CANCELLEDCELLINEAI_ITEM_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_cancelledcellineai_item( + LIBLTE_S1AP_CANCELLEDCELLINEAI_ITEM_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_cancelledcellineai_item( + uint8_t **ptr, + LIBLTE_S1AP_CANCELLEDCELLINEAI_ITEM_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE CancelledCellinTAI_Item SEQUENCE +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_EUTRAN_CGI_STRUCT eCGI; + LIBLTE_S1AP_NUMBEROFBROADCASTS_STRUCT numberOfBroadcasts; + LIBLTE_S1AP_PROTOCOLEXTENSIONCONTAINER_STRUCT iE_Extensions; + bool iE_Extensions_present; +}LIBLTE_S1AP_CANCELLEDCELLINTAI_ITEM_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_cancelledcellintai_item( + LIBLTE_S1AP_CANCELLEDCELLINTAI_ITEM_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_cancelledcellintai_item( + uint8_t **ptr, + LIBLTE_S1AP_CANCELLEDCELLINTAI_ITEM_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE CellID_Broadcast_Item SEQUENCE +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_EUTRAN_CGI_STRUCT eCGI; + LIBLTE_S1AP_PROTOCOLEXTENSIONCONTAINER_STRUCT iE_Extensions; + bool iE_Extensions_present; +}LIBLTE_S1AP_CELLID_BROADCAST_ITEM_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_cellid_broadcast_item( + LIBLTE_S1AP_CELLID_BROADCAST_ITEM_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_cellid_broadcast_item( + uint8_t **ptr, + LIBLTE_S1AP_CELLID_BROADCAST_ITEM_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE CellID_Cancelled_Item SEQUENCE +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_EUTRAN_CGI_STRUCT eCGI; + LIBLTE_S1AP_NUMBEROFBROADCASTS_STRUCT numberOfBroadcasts; + LIBLTE_S1AP_PROTOCOLEXTENSIONCONTAINER_STRUCT iE_Extensions; + bool iE_Extensions_present; +}LIBLTE_S1AP_CELLID_CANCELLED_ITEM_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_cellid_cancelled_item( + LIBLTE_S1AP_CELLID_CANCELLED_ITEM_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_cellid_cancelled_item( + uint8_t **ptr, + LIBLTE_S1AP_CELLID_CANCELLED_ITEM_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE CellIdListforMDT DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:32 +typedef struct{ + uint32_t len; + LIBLTE_S1AP_EUTRAN_CGI_STRUCT buffer[32]; //WARNING: Artificial limit to reduce memory footprint +}LIBLTE_S1AP_CELLIDLISTFORMDT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_cellidlistformdt( + LIBLTE_S1AP_CELLIDLISTFORMDT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_cellidlistformdt( + uint8_t **ptr, + LIBLTE_S1AP_CELLIDLISTFORMDT_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE CSG_Id STATIC BIT STRING +********************************************************************************/ +#define LIBLTE_S1AP_CSG_ID_BIT_STRING_LEN 27 +typedef struct{ + uint8_t buffer[27]; +}LIBLTE_S1AP_CSG_ID_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_csg_id( + LIBLTE_S1AP_CSG_ID_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_csg_id( + uint8_t **ptr, + LIBLTE_S1AP_CSG_ID_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE CSG_IdList_Item SEQUENCE +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_CSG_ID_STRUCT cSG_Id; + LIBLTE_S1AP_PROTOCOLEXTENSIONCONTAINER_STRUCT iE_Extensions; + bool iE_Extensions_present; +}LIBLTE_S1AP_CSG_IDLIST_ITEM_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_csg_idlist_item( + LIBLTE_S1AP_CSG_IDLIST_ITEM_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_csg_idlist_item( + uint8_t **ptr, + LIBLTE_S1AP_CSG_IDLIST_ITEM_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE Direct_Forwarding_Path_Availability ENUMERATED +********************************************************************************/ +typedef enum{ + LIBLTE_S1AP_DIRECT_FORWARDING_PATH_AVAILABILITY_DIRECTPATHAVAILABLE, + LIBLTE_S1AP_DIRECT_FORWARDING_PATH_AVAILABILITY_N_ITEMS, +}LIBLTE_S1AP_DIRECT_FORWARDING_PATH_AVAILABILITY_ENUM; +static const char liblte_s1ap_direct_forwarding_path_availability_text[LIBLTE_S1AP_DIRECT_FORWARDING_PATH_AVAILABILITY_N_ITEMS][80] = { + "directPathAvailable", +}; + +typedef struct{ + bool ext; + LIBLTE_S1AP_DIRECT_FORWARDING_PATH_AVAILABILITY_ENUM e; +}LIBLTE_S1AP_DIRECT_FORWARDING_PATH_AVAILABILITY_ENUM_EXT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_direct_forwarding_path_availability( + LIBLTE_S1AP_DIRECT_FORWARDING_PATH_AVAILABILITY_ENUM_EXT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_direct_forwarding_path_availability( + uint8_t **ptr, + LIBLTE_S1AP_DIRECT_FORWARDING_PATH_AVAILABILITY_ENUM_EXT *ie); + +/******************************************************************************* +/* ProtocolIE CompletedCellinEAI_Item SEQUENCE +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_EUTRAN_CGI_STRUCT eCGI; + LIBLTE_S1AP_PROTOCOLEXTENSIONCONTAINER_STRUCT iE_Extensions; + bool iE_Extensions_present; +}LIBLTE_S1AP_COMPLETEDCELLINEAI_ITEM_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_completedcellineai_item( + LIBLTE_S1AP_COMPLETEDCELLINEAI_ITEM_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_completedcellineai_item( + uint8_t **ptr, + LIBLTE_S1AP_COMPLETEDCELLINEAI_ITEM_STRUCT *ie); + +/******************************************************************************* +/* Protocol Container List E_RABInformationList DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:256 +typedef struct{ + uint32_t len; + LIBLTE_S1AP_E_RABINFORMATIONLISTITEM_STRUCT buffer[32]; //WARNING: Artificial limit to reduce memory footprint +}LIBLTE_S1AP_E_RABINFORMATIONLIST_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabinformationlist( + LIBLTE_S1AP_E_RABINFORMATIONLIST_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabinformationlist( + uint8_t **ptr, + LIBLTE_S1AP_E_RABINFORMATIONLIST_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE ForbiddenTAs DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:16 +typedef struct{ + uint32_t len; + LIBLTE_S1AP_FORBIDDENTAS_ITEM_STRUCT buffer[32]; //WARNING: Artificial limit to reduce memory footprint +}LIBLTE_S1AP_FORBIDDENTAS_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_forbiddentas( + LIBLTE_S1AP_FORBIDDENTAS_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_forbiddentas( + uint8_t **ptr, + LIBLTE_S1AP_FORBIDDENTAS_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE GUMMEI SEQUENCE +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_TBCD_STRING_STRUCT pLMN_Identity; + LIBLTE_S1AP_MME_GROUP_ID_STRUCT mME_Group_ID; + LIBLTE_S1AP_MME_CODE_STRUCT mME_Code; + LIBLTE_S1AP_PROTOCOLEXTENSIONCONTAINER_STRUCT iE_Extensions; + bool iE_Extensions_present; +}LIBLTE_S1AP_GUMMEI_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_gummei( + LIBLTE_S1AP_GUMMEI_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_gummei( + uint8_t **ptr, + LIBLTE_S1AP_GUMMEI_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE LoggedMDT SEQUENCE +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_LOGGINGINTERVAL_ENUM loggingInterval; + LIBLTE_S1AP_LOGGINGDURATION_ENUM loggingDuration; + LIBLTE_S1AP_PROTOCOLEXTENSIONCONTAINER_STRUCT iE_Extensions; + bool iE_Extensions_present; +}LIBLTE_S1AP_LOGGEDMDT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_loggedmdt( + LIBLTE_S1AP_LOGGEDMDT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_loggedmdt( + uint8_t **ptr, + LIBLTE_S1AP_LOGGEDMDT_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE NASSecurityParametersfromE_UTRAN DYNAMIC OCTET STRING +********************************************************************************/ +// lb:0, ub:16318 +typedef struct{ + uint32_t n_octets; + uint8_t buffer[16318]; +}LIBLTE_S1AP_NASSECURITYPARAMETERSFROME_UTRAN_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_nassecurityparametersfrome_utran( + LIBLTE_S1AP_NASSECURITYPARAMETERSFROME_UTRAN_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_nassecurityparametersfrome_utran( + uint8_t **ptr, + LIBLTE_S1AP_NASSECURITYPARAMETERSFROME_UTRAN_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE ReportAmountMDT ENUMERATED +********************************************************************************/ +typedef enum{ + LIBLTE_S1AP_REPORTAMOUNTMDT_R1, + LIBLTE_S1AP_REPORTAMOUNTMDT_R2, + LIBLTE_S1AP_REPORTAMOUNTMDT_R4, + LIBLTE_S1AP_REPORTAMOUNTMDT_R8, + LIBLTE_S1AP_REPORTAMOUNTMDT_R16, + LIBLTE_S1AP_REPORTAMOUNTMDT_R32, + LIBLTE_S1AP_REPORTAMOUNTMDT_R64, + LIBLTE_S1AP_REPORTAMOUNTMDT_RINFINITY, + LIBLTE_S1AP_REPORTAMOUNTMDT_N_ITEMS, +}LIBLTE_S1AP_REPORTAMOUNTMDT_ENUM; +static const char liblte_s1ap_reportamountmdt_text[LIBLTE_S1AP_REPORTAMOUNTMDT_N_ITEMS][80] = { + "r1", + "r2", + "r4", + "r8", + "r16", + "r32", + "r64", + "rinfinity", +}; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_reportamountmdt( + LIBLTE_S1AP_REPORTAMOUNTMDT_ENUM *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_reportamountmdt( + uint8_t **ptr, + LIBLTE_S1AP_REPORTAMOUNTMDT_ENUM *ie); + +/******************************************************************************* +/* ProtocolIE ServedGUMMEIsItem SEQUENCE +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_SERVEDPLMNS_STRUCT servedPLMNs; + LIBLTE_S1AP_SERVEDGROUPIDS_STRUCT servedGroupIDs; + LIBLTE_S1AP_SERVEDMMECS_STRUCT servedMMECs; + LIBLTE_S1AP_PROTOCOLEXTENSIONCONTAINER_STRUCT iE_Extensions; + bool iE_Extensions_present; +}LIBLTE_S1AP_SERVEDGUMMEISITEM_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_servedgummeisitem( + LIBLTE_S1AP_SERVEDGUMMEISITEM_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_servedgummeisitem( + uint8_t **ptr, + LIBLTE_S1AP_SERVEDGUMMEISITEM_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE S_TMSI SEQUENCE +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_MME_CODE_STRUCT mMEC; + LIBLTE_S1AP_M_TMSI_STRUCT m_TMSI; + LIBLTE_S1AP_PROTOCOLEXTENSIONCONTAINER_STRUCT iE_Extensions; + bool iE_Extensions_present; +}LIBLTE_S1AP_S_TMSI_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_s_tmsi( + LIBLTE_S1AP_S_TMSI_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_s_tmsi( + uint8_t **ptr, + LIBLTE_S1AP_S_TMSI_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE TAIListforWarning DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:65535 +typedef struct{ + uint32_t len; + LIBLTE_S1AP_TAI_STRUCT buffer[32]; //WARNING: Artificial limit to reduce memory footprint +}LIBLTE_S1AP_TAILISTFORWARNING_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_tailistforwarning( + LIBLTE_S1AP_TAILISTFORWARNING_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_tailistforwarning( + uint8_t **ptr, + LIBLTE_S1AP_TAILISTFORWARNING_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE CompletedCellinTAI DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:65535 +typedef struct{ + uint32_t len; + LIBLTE_S1AP_COMPLETEDCELLINTAI_ITEM_STRUCT buffer[32]; //WARNING: Artificial limit to reduce memory footprint +}LIBLTE_S1AP_COMPLETEDCELLINTAI_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_completedcellintai( + LIBLTE_S1AP_COMPLETEDCELLINTAI_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_completedcellintai( + uint8_t **ptr, + LIBLTE_S1AP_COMPLETEDCELLINTAI_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE TargetRNC_ID SEQUENCE +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_LAI_STRUCT lAI; + LIBLTE_S1AP_RAC_STRUCT rAC; + bool rAC_present; + LIBLTE_S1AP_RNC_ID_STRUCT rNC_ID; + LIBLTE_S1AP_EXTENDEDRNC_ID_STRUCT extendedRNC_ID; + bool extendedRNC_ID_present; + LIBLTE_S1AP_PROTOCOLEXTENSIONCONTAINER_STRUCT iE_Extensions; + bool iE_Extensions_present; +}LIBLTE_S1AP_TARGETRNC_ID_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_targetrnc_id( + LIBLTE_S1AP_TARGETRNC_ID_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_targetrnc_id( + uint8_t **ptr, + LIBLTE_S1AP_TARGETRNC_ID_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE UE_associatedLogicalS1_ConnectionItem SEQUENCE +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_MME_UE_S1AP_ID_STRUCT mME_UE_S1AP_ID; + bool mME_UE_S1AP_ID_present; + LIBLTE_S1AP_ENB_UE_S1AP_ID_STRUCT eNB_UE_S1AP_ID; + bool eNB_UE_S1AP_ID_present; + LIBLTE_S1AP_PROTOCOLEXTENSIONCONTAINER_STRUCT iE_Extensions; + bool iE_Extensions_present; +}LIBLTE_S1AP_UE_ASSOCIATEDLOGICALS1_CONNECTIONITEM_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_ue_associatedlogicals1_connectionitem( + LIBLTE_S1AP_UE_ASSOCIATEDLOGICALS1_CONNECTIONITEM_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_ue_associatedlogicals1_connectionitem( + uint8_t **ptr, + LIBLTE_S1AP_UE_ASSOCIATEDLOGICALS1_CONNECTIONITEM_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE UEPagingID CHOICE +********************************************************************************/ +typedef enum{ + LIBLTE_S1AP_UEPAGINGID_CHOICE_S_TMSI, + LIBLTE_S1AP_UEPAGINGID_CHOICE_IMSI, + LIBLTE_S1AP_UEPAGINGID_CHOICE_N_ITEMS, +}LIBLTE_S1AP_UEPAGINGID_CHOICE_ENUM; +static const char liblte_s1ap_uepagingid_choice_text[LIBLTE_S1AP_UEPAGINGID_CHOICE_N_ITEMS][50] = { + "s_TMSI", + "iMSI", +}; + +typedef union{ + LIBLTE_S1AP_S_TMSI_STRUCT s_TMSI; + LIBLTE_S1AP_IMSI_STRUCT iMSI; +}LIBLTE_S1AP_UEPAGINGID_CHOICE_UNION; + +typedef struct{ + bool ext; + LIBLTE_S1AP_UEPAGINGID_CHOICE_UNION choice; + LIBLTE_S1AP_UEPAGINGID_CHOICE_ENUM choice_type; +}LIBLTE_S1AP_UEPAGINGID_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_uepagingid( + LIBLTE_S1AP_UEPAGINGID_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_uepagingid( + uint8_t **ptr, + LIBLTE_S1AP_UEPAGINGID_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE Bearers_SubjectToStatusTransfer_Item SEQUENCE +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_E_RAB_ID_STRUCT e_RAB_ID; + LIBLTE_S1AP_COUNTVALUE_STRUCT uL_COUNTvalue; + LIBLTE_S1AP_COUNTVALUE_STRUCT dL_COUNTvalue; + LIBLTE_S1AP_RECEIVESTATUSOFULPDCPSDUS_STRUCT receiveStatusofULPDCPSDUs; + bool receiveStatusofULPDCPSDUs_present; + LIBLTE_S1AP_PROTOCOLEXTENSIONCONTAINER_STRUCT iE_Extensions; + bool iE_Extensions_present; +}LIBLTE_S1AP_BEARERS_SUBJECTTOSTATUSTRANSFER_ITEM_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_bearers_subjecttostatustransfer_item( + LIBLTE_S1AP_BEARERS_SUBJECTTOSTATUSTRANSFER_ITEM_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_bearers_subjecttostatustransfer_item( + uint8_t **ptr, + LIBLTE_S1AP_BEARERS_SUBJECTTOSTATUSTRANSFER_ITEM_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE CancelledCellinEAI DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:65535 +typedef struct{ + uint32_t len; + LIBLTE_S1AP_CANCELLEDCELLINEAI_ITEM_STRUCT buffer[32]; //WARNING: Artificial limit to reduce memory footprint +}LIBLTE_S1AP_CANCELLEDCELLINEAI_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_cancelledcellineai( + LIBLTE_S1AP_CANCELLEDCELLINEAI_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_cancelledcellineai( + uint8_t **ptr, + LIBLTE_S1AP_CANCELLEDCELLINEAI_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE CellID_Broadcast DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:65535 +typedef struct{ + uint32_t len; + LIBLTE_S1AP_CELLID_BROADCAST_ITEM_STRUCT buffer[32]; //WARNING: Artificial limit to reduce memory footprint +}LIBLTE_S1AP_CELLID_BROADCAST_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_cellid_broadcast( + LIBLTE_S1AP_CELLID_BROADCAST_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_cellid_broadcast( + uint8_t **ptr, + LIBLTE_S1AP_CELLID_BROADCAST_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE CellBasedMDT SEQUENCE +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_CELLIDLISTFORMDT_STRUCT cellIdListforMDT; + LIBLTE_S1AP_PROTOCOLEXTENSIONCONTAINER_STRUCT iE_Extensions; + bool iE_Extensions_present; +}LIBLTE_S1AP_CELLBASEDMDT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_cellbasedmdt( + LIBLTE_S1AP_CELLBASEDMDT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_cellbasedmdt( + uint8_t **ptr, + LIBLTE_S1AP_CELLBASEDMDT_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE CSG_IdList DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:256 +typedef struct{ + uint32_t len; + LIBLTE_S1AP_CSG_IDLIST_ITEM_STRUCT buffer[32]; //WARNING: Artificial limit to reduce memory footprint +}LIBLTE_S1AP_CSG_IDLIST_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_csg_idlist( + LIBLTE_S1AP_CSG_IDLIST_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_csg_idlist( + uint8_t **ptr, + LIBLTE_S1AP_CSG_IDLIST_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE ECGIList DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:65535 +typedef struct{ + uint32_t len; + LIBLTE_S1AP_EUTRAN_CGI_STRUCT buffer[32]; //WARNING: Artificial limit to reduce memory footprint +}LIBLTE_S1AP_ECGILIST_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_ecgilist( + LIBLTE_S1AP_ECGILIST_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_ecgilist( + uint8_t **ptr, + LIBLTE_S1AP_ECGILIST_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE EmergencyAreaID_Cancelled_Item SEQUENCE +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_EMERGENCYAREAID_STRUCT emergencyAreaID; + LIBLTE_S1AP_CANCELLEDCELLINEAI_STRUCT cancelledCellinEAI; + LIBLTE_S1AP_PROTOCOLEXTENSIONCONTAINER_STRUCT iE_Extensions; + bool iE_Extensions_present; +}LIBLTE_S1AP_EMERGENCYAREAID_CANCELLED_ITEM_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_emergencyareaid_cancelled_item( + LIBLTE_S1AP_EMERGENCYAREAID_CANCELLED_ITEM_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_emergencyareaid_cancelled_item( + uint8_t **ptr, + LIBLTE_S1AP_EMERGENCYAREAID_CANCELLED_ITEM_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE GERAN_Cell_ID SEQUENCE +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_LAI_STRUCT lAI; + LIBLTE_S1AP_RAC_STRUCT rAC; + LIBLTE_S1AP_CI_STRUCT cI; + LIBLTE_S1AP_PROTOCOLEXTENSIONCONTAINER_STRUCT iE_Extensions; + bool iE_Extensions_present; +}LIBLTE_S1AP_GERAN_CELL_ID_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_geran_cell_id( + LIBLTE_S1AP_GERAN_CELL_ID_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_geran_cell_id( + uint8_t **ptr, + LIBLTE_S1AP_GERAN_CELL_ID_STRUCT *ie); + +/******************************************************************************* +/* Protocol Container List E_RABList DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:256 +typedef struct{ + uint32_t len; + LIBLTE_S1AP_E_RABITEM_STRUCT buffer[32]; //WARNING: Artificial limit to reduce memory footprint +}LIBLTE_S1AP_E_RABLIST_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rablist( + LIBLTE_S1AP_E_RABLIST_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rablist( + uint8_t **ptr, + LIBLTE_S1AP_E_RABLIST_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE ForbiddenLAs DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:16 +typedef struct{ + uint32_t len; + LIBLTE_S1AP_FORBIDDENLAS_ITEM_STRUCT buffer[32]; //WARNING: Artificial limit to reduce memory footprint +}LIBLTE_S1AP_FORBIDDENLAS_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_forbiddenlas( + LIBLTE_S1AP_FORBIDDENLAS_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_forbiddenlas( + uint8_t **ptr, + LIBLTE_S1AP_FORBIDDENLAS_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE MDT_Location_Info STATIC BIT STRING +********************************************************************************/ +#define LIBLTE_S1AP_MDT_LOCATION_INFO_BIT_STRING_LEN 8 +typedef struct{ + uint8_t buffer[8]; +}LIBLTE_S1AP_MDT_LOCATION_INFO_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_mdt_location_info( + LIBLTE_S1AP_MDT_LOCATION_INFO_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_mdt_location_info( + uint8_t **ptr, + LIBLTE_S1AP_MDT_LOCATION_INFO_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE M1PeriodicReporting SEQUENCE +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_REPORTINTERVALMDT_ENUM reportInterval; + LIBLTE_S1AP_REPORTAMOUNTMDT_ENUM reportAmount; + LIBLTE_S1AP_PROTOCOLEXTENSIONCONTAINER_STRUCT iE_Extensions; + bool iE_Extensions_present; +}LIBLTE_S1AP_M1PERIODICREPORTING_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_m1periodicreporting( + LIBLTE_S1AP_M1PERIODICREPORTING_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_m1periodicreporting( + uint8_t **ptr, + LIBLTE_S1AP_M1PERIODICREPORTING_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE eHRPD_Sector_ID DYNAMIC OCTET STRING +********************************************************************************/ +// lb:0, ub:16318 +typedef struct{ + uint32_t n_octets; + uint8_t buffer[16318]; +}LIBLTE_S1AP_EHRPD_SECTOR_ID_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_ehrpd_sector_id( + LIBLTE_S1AP_EHRPD_SECTOR_ID_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_ehrpd_sector_id( + uint8_t **ptr, + LIBLTE_S1AP_EHRPD_SECTOR_ID_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE RIMRoutingAddress CHOICE +********************************************************************************/ +typedef enum{ + LIBLTE_S1AP_RIMROUTINGADDRESS_CHOICE_GERAN_CELL_ID, + LIBLTE_S1AP_RIMROUTINGADDRESS_CHOICE_TARGETRNC_ID, + LIBLTE_S1AP_RIMROUTINGADDRESS_CHOICE_EHRPD_SECTOR_ID, + LIBLTE_S1AP_RIMROUTINGADDRESS_CHOICE_N_ITEMS, +}LIBLTE_S1AP_RIMROUTINGADDRESS_CHOICE_ENUM; +static const char liblte_s1ap_rimroutingaddress_choice_text[LIBLTE_S1AP_RIMROUTINGADDRESS_CHOICE_N_ITEMS][50] = { + "gERAN_Cell_ID", + "targetRNC_ID", + "eHRPD_Sector_ID", +}; + +typedef union{ + LIBLTE_S1AP_GERAN_CELL_ID_STRUCT gERAN_Cell_ID; + LIBLTE_S1AP_TARGETRNC_ID_STRUCT targetRNC_ID; + LIBLTE_S1AP_EHRPD_SECTOR_ID_STRUCT eHRPD_Sector_ID; +}LIBLTE_S1AP_RIMROUTINGADDRESS_CHOICE_UNION; + +typedef struct{ + bool ext; + LIBLTE_S1AP_RIMROUTINGADDRESS_CHOICE_UNION choice; + LIBLTE_S1AP_RIMROUTINGADDRESS_CHOICE_ENUM choice_type; +}LIBLTE_S1AP_RIMROUTINGADDRESS_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_rimroutingaddress( + LIBLTE_S1AP_RIMROUTINGADDRESS_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_rimroutingaddress( + uint8_t **ptr, + LIBLTE_S1AP_RIMROUTINGADDRESS_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE ServedGUMMEIs DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:8 +typedef struct{ + uint32_t len; + LIBLTE_S1AP_SERVEDGUMMEISITEM_STRUCT buffer[32]; //WARNING: Artificial limit to reduce memory footprint +}LIBLTE_S1AP_SERVEDGUMMEIS_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_servedgummeis( + LIBLTE_S1AP_SERVEDGUMMEIS_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_servedgummeis( + uint8_t **ptr, + LIBLTE_S1AP_SERVEDGUMMEIS_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE TAIBasedMDT SEQUENCE +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_TAILISTFORMDT_STRUCT tAIListforMDT; + LIBLTE_S1AP_PROTOCOLEXTENSIONCONTAINER_STRUCT iE_Extensions; + bool iE_Extensions_present; +}LIBLTE_S1AP_TAIBASEDMDT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_taibasedmdt( + LIBLTE_S1AP_TAIBASEDMDT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_taibasedmdt( + uint8_t **ptr, + LIBLTE_S1AP_TAIBASEDMDT_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE TAI_Broadcast_Item SEQUENCE +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_TAI_STRUCT tAI; + LIBLTE_S1AP_COMPLETEDCELLINTAI_STRUCT completedCellinTAI; + LIBLTE_S1AP_PROTOCOLEXTENSIONCONTAINER_STRUCT iE_Extensions; + bool iE_Extensions_present; +}LIBLTE_S1AP_TAI_BROADCAST_ITEM_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_tai_broadcast_item( + LIBLTE_S1AP_TAI_BROADCAST_ITEM_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_tai_broadcast_item( + uint8_t **ptr, + LIBLTE_S1AP_TAI_BROADCAST_ITEM_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE TargetID CHOICE +********************************************************************************/ +typedef enum{ + LIBLTE_S1AP_TARGETID_CHOICE_TARGETENB_ID, + LIBLTE_S1AP_TARGETID_CHOICE_TARGETRNC_ID, + LIBLTE_S1AP_TARGETID_CHOICE_CGI, + LIBLTE_S1AP_TARGETID_CHOICE_N_ITEMS, +}LIBLTE_S1AP_TARGETID_CHOICE_ENUM; +static const char liblte_s1ap_targetid_choice_text[LIBLTE_S1AP_TARGETID_CHOICE_N_ITEMS][50] = { + "targeteNB_ID", + "targetRNC_ID", + "cGI", +}; + +typedef union{ + LIBLTE_S1AP_TARGETENB_ID_STRUCT targeteNB_ID; + LIBLTE_S1AP_TARGETRNC_ID_STRUCT targetRNC_ID; + LIBLTE_S1AP_CGI_STRUCT cGI; +}LIBLTE_S1AP_TARGETID_CHOICE_UNION; + +typedef struct{ + bool ext; + LIBLTE_S1AP_TARGETID_CHOICE_UNION choice; + LIBLTE_S1AP_TARGETID_CHOICE_ENUM choice_type; +}LIBLTE_S1AP_TARGETID_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_targetid( + LIBLTE_S1AP_TARGETID_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_targetid( + uint8_t **ptr, + LIBLTE_S1AP_TARGETID_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE WarningAreaList CHOICE +********************************************************************************/ +typedef enum{ + LIBLTE_S1AP_WARNINGAREALIST_CHOICE_CELLIDLIST, + LIBLTE_S1AP_WARNINGAREALIST_CHOICE_TRACKINGAREALISTFORWARNING, + LIBLTE_S1AP_WARNINGAREALIST_CHOICE_EMERGENCYAREAIDLIST, + LIBLTE_S1AP_WARNINGAREALIST_CHOICE_N_ITEMS, +}LIBLTE_S1AP_WARNINGAREALIST_CHOICE_ENUM; +static const char liblte_s1ap_warningarealist_choice_text[LIBLTE_S1AP_WARNINGAREALIST_CHOICE_N_ITEMS][50] = { + "cellIDList", + "trackingAreaListforWarning", + "emergencyAreaIDList", +}; + +typedef union{ + LIBLTE_S1AP_ECGILIST_STRUCT cellIDList; + LIBLTE_S1AP_TAILISTFORWARNING_STRUCT trackingAreaListforWarning; + LIBLTE_S1AP_EMERGENCYAREAIDLIST_STRUCT emergencyAreaIDList; +}LIBLTE_S1AP_WARNINGAREALIST_CHOICE_UNION; + +typedef struct{ + bool ext; + LIBLTE_S1AP_WARNINGAREALIST_CHOICE_UNION choice; + LIBLTE_S1AP_WARNINGAREALIST_CHOICE_ENUM choice_type; +}LIBLTE_S1AP_WARNINGAREALIST_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_warningarealist( + LIBLTE_S1AP_WARNINGAREALIST_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_warningarealist( + uint8_t **ptr, + LIBLTE_S1AP_WARNINGAREALIST_STRUCT *ie); + +//TODO: Type pLMNWide NULL + +/******************************************************************************* +/* ProtocolIE AreaScopeOfMDT CHOICE +********************************************************************************/ +typedef enum{ + LIBLTE_S1AP_AREASCOPEOFMDT_CHOICE_CELLBASED, + LIBLTE_S1AP_AREASCOPEOFMDT_CHOICE_TABASED, + LIBLTE_S1AP_AREASCOPEOFMDT_CHOICE_PLMNWIDE, + LIBLTE_S1AP_AREASCOPEOFMDT_CHOICE_TAIBASED, + LIBLTE_S1AP_AREASCOPEOFMDT_CHOICE_N_ITEMS, +}LIBLTE_S1AP_AREASCOPEOFMDT_CHOICE_ENUM; +static const char liblte_s1ap_areascopeofmdt_choice_text[LIBLTE_S1AP_AREASCOPEOFMDT_CHOICE_N_ITEMS][50] = { + "cellBased", + "tABased", + "pLMNWide", + "tAIBased", +}; + +typedef union{ + LIBLTE_S1AP_CELLBASEDMDT_STRUCT cellBased; + LIBLTE_S1AP_TABASEDMDT_STRUCT tABased; + //TODO: NULL pLMNWide; + LIBLTE_S1AP_TAIBASEDMDT_STRUCT tAIBased; +}LIBLTE_S1AP_AREASCOPEOFMDT_CHOICE_UNION; + +typedef struct{ + bool ext; + LIBLTE_S1AP_AREASCOPEOFMDT_CHOICE_UNION choice; + LIBLTE_S1AP_AREASCOPEOFMDT_CHOICE_ENUM choice_type; +}LIBLTE_S1AP_AREASCOPEOFMDT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_areascopeofmdt( + LIBLTE_S1AP_AREASCOPEOFMDT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_areascopeofmdt( + uint8_t **ptr, + LIBLTE_S1AP_AREASCOPEOFMDT_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE CancelledCellinTAI DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:65535 +typedef struct{ + uint32_t len; + LIBLTE_S1AP_CANCELLEDCELLINTAI_ITEM_STRUCT buffer[32]; //WARNING: Artificial limit to reduce memory footprint +}LIBLTE_S1AP_CANCELLEDCELLINTAI_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_cancelledcellintai( + LIBLTE_S1AP_CANCELLEDCELLINTAI_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_cancelledcellintai( + uint8_t **ptr, + LIBLTE_S1AP_CANCELLEDCELLINTAI_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE CellType SEQUENCE +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_CELL_SIZE_ENUM_EXT cell_Size; + LIBLTE_S1AP_PROTOCOLEXTENSIONCONTAINER_STRUCT iE_Extensions; + bool iE_Extensions_present; +}LIBLTE_S1AP_CELLTYPE_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_celltype( + LIBLTE_S1AP_CELLTYPE_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_celltype( + uint8_t **ptr, + LIBLTE_S1AP_CELLTYPE_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE EmergencyAreaID_Cancelled DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:65535 +typedef struct{ + uint32_t len; + LIBLTE_S1AP_EMERGENCYAREAID_CANCELLED_ITEM_STRUCT buffer[32]; //WARNING: Artificial limit to reduce memory footprint +}LIBLTE_S1AP_EMERGENCYAREAID_CANCELLED_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_emergencyareaid_cancelled( + LIBLTE_S1AP_EMERGENCYAREAID_CANCELLED_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_emergencyareaid_cancelled( + uint8_t **ptr, + LIBLTE_S1AP_EMERGENCYAREAID_CANCELLED_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE GUMMEIList DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:256 +typedef struct{ + uint32_t len; + LIBLTE_S1AP_GUMMEI_STRUCT buffer[32]; //WARNING: Artificial limit to reduce memory footprint +}LIBLTE_S1AP_GUMMEILIST_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_gummeilist( + LIBLTE_S1AP_GUMMEILIST_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_gummeilist( + uint8_t **ptr, + LIBLTE_S1AP_GUMMEILIST_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE E_RABLevelQoSParameters SEQUENCE +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_QCI_STRUCT qCI; + LIBLTE_S1AP_ALLOCATIONANDRETENTIONPRIORITY_STRUCT allocationRetentionPriority; + LIBLTE_S1AP_GBR_QOSINFORMATION_STRUCT gbrQosInformation; + bool gbrQosInformation_present; + LIBLTE_S1AP_PROTOCOLEXTENSIONCONTAINER_STRUCT iE_Extensions; + bool iE_Extensions_present; +}LIBLTE_S1AP_E_RABLEVELQOSPARAMETERS_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rablevelqosparameters( + LIBLTE_S1AP_E_RABLEVELQOSPARAMETERS_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rablevelqosparameters( + uint8_t **ptr, + LIBLTE_S1AP_E_RABLEVELQOSPARAMETERS_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE LastVisitedEUTRANCellInformation SEQUENCE +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_EUTRAN_CGI_STRUCT global_Cell_ID; + LIBLTE_S1AP_CELLTYPE_STRUCT cellType; + LIBLTE_S1AP_TIME_UE_STAYEDINCELL_STRUCT time_UE_StayedInCell; + LIBLTE_S1AP_PROTOCOLEXTENSIONCONTAINER_STRUCT iE_Extensions; + bool iE_Extensions_present; +}LIBLTE_S1AP_LASTVISITEDEUTRANCELLINFORMATION_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_lastvisitedeutrancellinformation( + LIBLTE_S1AP_LASTVISITEDEUTRANCELLINFORMATION_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_lastvisitedeutrancellinformation( + uint8_t **ptr, + LIBLTE_S1AP_LASTVISITEDEUTRANCELLINFORMATION_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE RIMTransfer SEQUENCE +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_RIMINFORMATION_STRUCT rIMInformation; + LIBLTE_S1AP_RIMROUTINGADDRESS_STRUCT rIMRoutingAddress; + bool rIMRoutingAddress_present; + LIBLTE_S1AP_PROTOCOLEXTENSIONCONTAINER_STRUCT iE_Extensions; + bool iE_Extensions_present; +}LIBLTE_S1AP_RIMTRANSFER_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_rimtransfer( + LIBLTE_S1AP_RIMTRANSFER_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_rimtransfer( + uint8_t **ptr, + LIBLTE_S1AP_RIMTRANSFER_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE SupportedTAs DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:256 +typedef struct{ + uint32_t len; + LIBLTE_S1AP_SUPPORTEDTAS_ITEM_STRUCT buffer[32]; //WARNING: Artificial limit to reduce memory footprint +}LIBLTE_S1AP_SUPPORTEDTAS_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_supportedtas( + LIBLTE_S1AP_SUPPORTEDTAS_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_supportedtas( + uint8_t **ptr, + LIBLTE_S1AP_SUPPORTEDTAS_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE TAI_Cancelled_Item SEQUENCE +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_TAI_STRUCT tAI; + LIBLTE_S1AP_CANCELLEDCELLINTAI_STRUCT cancelledCellinTAI; + LIBLTE_S1AP_PROTOCOLEXTENSIONCONTAINER_STRUCT iE_Extensions; + bool iE_Extensions_present; +}LIBLTE_S1AP_TAI_CANCELLED_ITEM_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_tai_cancelled_item( + LIBLTE_S1AP_TAI_CANCELLED_ITEM_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_tai_cancelled_item( + uint8_t **ptr, + LIBLTE_S1AP_TAI_CANCELLED_ITEM_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE X2TNLConfigurationInfo SEQUENCE +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_ENBX2TLAS_STRUCT eNBX2TransportLayerAddresses; + LIBLTE_S1AP_PROTOCOLEXTENSIONCONTAINER_STRUCT iE_Extensions; + bool iE_Extensions_present; +}LIBLTE_S1AP_X2TNLCONFIGURATIONINFO_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_x2tnlconfigurationinfo( + LIBLTE_S1AP_X2TNLCONFIGURATIONINFO_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_x2tnlconfigurationinfo( + uint8_t **ptr, + LIBLTE_S1AP_X2TNLCONFIGURATIONINFO_STRUCT *ie); + +/******************************************************************************* +/* Protocol Container List Bearers_SubjectToStatusTransferList DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:256 +typedef struct{ + uint32_t len; + LIBLTE_S1AP_BEARERS_SUBJECTTOSTATUSTRANSFER_ITEM_STRUCT buffer[32]; //WARNING: Artificial limit to reduce memory footprint +}LIBLTE_S1AP_BEARERS_SUBJECTTOSTATUSTRANSFERLIST_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_bearers_subjecttostatustransferlist( + LIBLTE_S1AP_BEARERS_SUBJECTTOSTATUSTRANSFERLIST_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_bearers_subjecttostatustransferlist( + uint8_t **ptr, + LIBLTE_S1AP_BEARERS_SUBJECTTOSTATUSTRANSFERLIST_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE CellID_Cancelled DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:65535 +typedef struct{ + uint32_t len; + LIBLTE_S1AP_CELLID_CANCELLED_ITEM_STRUCT buffer[32]; //WARNING: Artificial limit to reduce memory footprint +}LIBLTE_S1AP_CELLID_CANCELLED_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_cellid_cancelled( + LIBLTE_S1AP_CELLID_CANCELLED_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_cellid_cancelled( + uint8_t **ptr, + LIBLTE_S1AP_CELLID_CANCELLED_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE CompletedCellinEAI DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:65535 +typedef struct{ + uint32_t len; + LIBLTE_S1AP_COMPLETEDCELLINEAI_ITEM_STRUCT buffer[32]; //WARNING: Artificial limit to reduce memory footprint +}LIBLTE_S1AP_COMPLETEDCELLINEAI_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_completedcellineai( + LIBLTE_S1AP_COMPLETEDCELLINEAI_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_completedcellineai( + uint8_t **ptr, + LIBLTE_S1AP_COMPLETEDCELLINEAI_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE HandoverRestrictionList SEQUENCE +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_TBCD_STRING_STRUCT servingPLMN; + LIBLTE_S1AP_EPLMNS_STRUCT equivalentPLMNs; + bool equivalentPLMNs_present; + LIBLTE_S1AP_FORBIDDENTAS_STRUCT forbiddenTAs; + bool forbiddenTAs_present; + LIBLTE_S1AP_FORBIDDENLAS_STRUCT forbiddenLAs; + bool forbiddenLAs_present; + LIBLTE_S1AP_FORBIDDENINTERRATS_ENUM_EXT forbiddenInterRATs; + bool forbiddenInterRATs_present; + LIBLTE_S1AP_PROTOCOLEXTENSIONCONTAINER_STRUCT iE_Extensions; + bool iE_Extensions_present; +}LIBLTE_S1AP_HANDOVERRESTRICTIONLIST_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_handoverrestrictionlist( + LIBLTE_S1AP_HANDOVERRESTRICTIONLIST_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_handoverrestrictionlist( + uint8_t **ptr, + LIBLTE_S1AP_HANDOVERRESTRICTIONLIST_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE LastVisitedCell_Item CHOICE +********************************************************************************/ +typedef enum{ + LIBLTE_S1AP_LASTVISITEDCELL_ITEM_CHOICE_E_UTRAN_CELL, + LIBLTE_S1AP_LASTVISITEDCELL_ITEM_CHOICE_UTRAN_CELL, + LIBLTE_S1AP_LASTVISITEDCELL_ITEM_CHOICE_GERAN_CELL, + LIBLTE_S1AP_LASTVISITEDCELL_ITEM_CHOICE_N_ITEMS, +}LIBLTE_S1AP_LASTVISITEDCELL_ITEM_CHOICE_ENUM; +static const char liblte_s1ap_lastvisitedcell_item_choice_text[LIBLTE_S1AP_LASTVISITEDCELL_ITEM_CHOICE_N_ITEMS][50] = { + "e_UTRAN_Cell", + "uTRAN_Cell", + "gERAN_Cell", +}; + +typedef union{ + LIBLTE_S1AP_LASTVISITEDEUTRANCELLINFORMATION_STRUCT e_UTRAN_Cell; + LIBLTE_S1AP_LASTVISITEDUTRANCELLINFORMATION_STRUCT uTRAN_Cell; + LIBLTE_S1AP_LASTVISITEDGERANCELLINFORMATION_STRUCT gERAN_Cell; +}LIBLTE_S1AP_LASTVISITEDCELL_ITEM_CHOICE_UNION; + +typedef struct{ + bool ext; + LIBLTE_S1AP_LASTVISITEDCELL_ITEM_CHOICE_UNION choice; + LIBLTE_S1AP_LASTVISITEDCELL_ITEM_CHOICE_ENUM choice_type; +}LIBLTE_S1AP_LASTVISITEDCELL_ITEM_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_lastvisitedcell_item( + LIBLTE_S1AP_LASTVISITEDCELL_ITEM_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_lastvisitedcell_item( + uint8_t **ptr, + LIBLTE_S1AP_LASTVISITEDCELL_ITEM_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE SONInformationReply SEQUENCE +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_X2TNLCONFIGURATIONINFO_STRUCT x2TNLConfigurationInfo; + bool x2TNLConfigurationInfo_present; + LIBLTE_S1AP_PROTOCOLEXTENSIONCONTAINER_STRUCT iE_Extensions; + bool iE_Extensions_present; +}LIBLTE_S1AP_SONINFORMATIONREPLY_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_soninformationreply( + LIBLTE_S1AP_SONINFORMATIONREPLY_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_soninformationreply( + uint8_t **ptr, + LIBLTE_S1AP_SONINFORMATIONREPLY_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE TAI_Broadcast DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:65535 +typedef struct{ + uint32_t len; + LIBLTE_S1AP_TAI_BROADCAST_ITEM_STRUCT buffer[32]; //WARNING: Artificial limit to reduce memory footprint +}LIBLTE_S1AP_TAI_BROADCAST_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_tai_broadcast( + LIBLTE_S1AP_TAI_BROADCAST_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_tai_broadcast( + uint8_t **ptr, + LIBLTE_S1AP_TAI_BROADCAST_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE TimeToWait ENUMERATED +********************************************************************************/ +typedef enum{ + LIBLTE_S1AP_TIMETOWAIT_V1S, + LIBLTE_S1AP_TIMETOWAIT_V2S, + LIBLTE_S1AP_TIMETOWAIT_V5S, + LIBLTE_S1AP_TIMETOWAIT_V10S, + LIBLTE_S1AP_TIMETOWAIT_V20S, + LIBLTE_S1AP_TIMETOWAIT_V60S, + LIBLTE_S1AP_TIMETOWAIT_N_ITEMS, +}LIBLTE_S1AP_TIMETOWAIT_ENUM; +static const char liblte_s1ap_timetowait_text[LIBLTE_S1AP_TIMETOWAIT_N_ITEMS][80] = { + "v1s", + "v2s", + "v5s", + "v10s", + "v20s", + "v60s", +}; + +typedef struct{ + bool ext; + LIBLTE_S1AP_TIMETOWAIT_ENUM e; +}LIBLTE_S1AP_TIMETOWAIT_ENUM_EXT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_timetowait( + LIBLTE_S1AP_TIMETOWAIT_ENUM_EXT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_timetowait( + uint8_t **ptr, + LIBLTE_S1AP_TIMETOWAIT_ENUM_EXT *ie); + +/******************************************************************************* +/* ProtocolIE UE_HistoryInformation DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:16 +typedef struct{ + uint32_t len; + LIBLTE_S1AP_LASTVISITEDCELL_ITEM_STRUCT buffer[32]; //WARNING: Artificial limit to reduce memory footprint +}LIBLTE_S1AP_UE_HISTORYINFORMATION_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_ue_historyinformation( + LIBLTE_S1AP_UE_HISTORYINFORMATION_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_ue_historyinformation( + uint8_t **ptr, + LIBLTE_S1AP_UE_HISTORYINFORMATION_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE CriticalityDiagnostics SEQUENCE +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_PROCEDURECODE_STRUCT procedureCode; + bool procedureCode_present; + LIBLTE_S1AP_TRIGGERINGMESSAGE_ENUM triggeringMessage; + bool triggeringMessage_present; + LIBLTE_S1AP_CRITICALITY_ENUM procedureCriticality; + bool procedureCriticality_present; + LIBLTE_S1AP_CRITICALITYDIAGNOSTICS_IE_LIST_STRUCT iEsCriticalityDiagnostics; + bool iEsCriticalityDiagnostics_present; + LIBLTE_S1AP_PROTOCOLEXTENSIONCONTAINER_STRUCT iE_Extensions; + bool iE_Extensions_present; +}LIBLTE_S1AP_CRITICALITYDIAGNOSTICS_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_criticalitydiagnostics( + LIBLTE_S1AP_CRITICALITYDIAGNOSTICS_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_criticalitydiagnostics( + uint8_t **ptr, + LIBLTE_S1AP_CRITICALITYDIAGNOSTICS_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE EmergencyAreaID_Broadcast_Item SEQUENCE +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_EMERGENCYAREAID_STRUCT emergencyAreaID; + LIBLTE_S1AP_COMPLETEDCELLINEAI_STRUCT completedCellinEAI; + LIBLTE_S1AP_PROTOCOLEXTENSIONCONTAINER_STRUCT iE_Extensions; + bool iE_Extensions_present; +}LIBLTE_S1AP_EMERGENCYAREAID_BROADCAST_ITEM_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_emergencyareaid_broadcast_item( + LIBLTE_S1AP_EMERGENCYAREAID_BROADCAST_ITEM_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_emergencyareaid_broadcast_item( + uint8_t **ptr, + LIBLTE_S1AP_EMERGENCYAREAID_BROADCAST_ITEM_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE ImmediateMDT SEQUENCE +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_MEASUREMENTSTOACTIVATE_STRUCT measurementsToActivate; + LIBLTE_S1AP_M1REPORTINGTRIGGER_ENUM_EXT m1reportingTrigger; + LIBLTE_S1AP_M1THRESHOLDEVENTA2_STRUCT m1thresholdeventA2; + bool m1thresholdeventA2_present; + LIBLTE_S1AP_M1PERIODICREPORTING_STRUCT m1periodicReporting; + bool m1periodicReporting_present; + LIBLTE_S1AP_PROTOCOLEXTENSIONCONTAINER_STRUCT iE_Extensions; + bool iE_Extensions_present; +}LIBLTE_S1AP_IMMEDIATEMDT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_immediatemdt( + LIBLTE_S1AP_IMMEDIATEMDT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_immediatemdt( + uint8_t **ptr, + LIBLTE_S1AP_IMMEDIATEMDT_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE MDTMode CHOICE +********************************************************************************/ +typedef enum{ + LIBLTE_S1AP_MDTMODE_CHOICE_IMMEDIATEMDT, + LIBLTE_S1AP_MDTMODE_CHOICE_LOGGEDMDT, + LIBLTE_S1AP_MDTMODE_CHOICE_N_ITEMS, +}LIBLTE_S1AP_MDTMODE_CHOICE_ENUM; +static const char liblte_s1ap_mdtmode_choice_text[LIBLTE_S1AP_MDTMODE_CHOICE_N_ITEMS][50] = { + "immediateMDT", + "loggedMDT", +}; + +typedef union{ + LIBLTE_S1AP_IMMEDIATEMDT_STRUCT immediateMDT; + LIBLTE_S1AP_LOGGEDMDT_STRUCT loggedMDT; +}LIBLTE_S1AP_MDTMODE_CHOICE_UNION; + +typedef struct{ + bool ext; + LIBLTE_S1AP_MDTMODE_CHOICE_UNION choice; + LIBLTE_S1AP_MDTMODE_CHOICE_ENUM choice_type; +}LIBLTE_S1AP_MDTMODE_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_mdtmode( + LIBLTE_S1AP_MDTMODE_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_mdtmode( + uint8_t **ptr, + LIBLTE_S1AP_MDTMODE_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE SourceeNB_ToTargeteNB_TransparentContainer SEQUENCE +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_RRC_CONTAINER_STRUCT rRC_Container; + LIBLTE_S1AP_E_RABINFORMATIONLIST_STRUCT e_RABInformationList; + bool e_RABInformationList_present; + LIBLTE_S1AP_EUTRAN_CGI_STRUCT targetCell_ID; + LIBLTE_S1AP_SUBSCRIBERPROFILEIDFORRFP_STRUCT subscriberProfileIDforRFP; + bool subscriberProfileIDforRFP_present; + LIBLTE_S1AP_UE_HISTORYINFORMATION_STRUCT uE_HistoryInformation; + LIBLTE_S1AP_PROTOCOLEXTENSIONCONTAINER_STRUCT iE_Extensions; + bool iE_Extensions_present; +}LIBLTE_S1AP_SOURCEENB_TOTARGETENB_TRANSPARENTCONTAINER_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_sourceenb_totargetenb_transparentcontainer( + LIBLTE_S1AP_SOURCEENB_TOTARGETENB_TRANSPARENTCONTAINER_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_sourceenb_totargetenb_transparentcontainer( + uint8_t **ptr, + LIBLTE_S1AP_SOURCEENB_TOTARGETENB_TRANSPARENTCONTAINER_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE EmergencyAreaID_Broadcast DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:65535 +typedef struct{ + uint32_t len; + LIBLTE_S1AP_EMERGENCYAREAID_BROADCAST_ITEM_STRUCT buffer[32]; //WARNING: Artificial limit to reduce memory footprint +}LIBLTE_S1AP_EMERGENCYAREAID_BROADCAST_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_emergencyareaid_broadcast( + LIBLTE_S1AP_EMERGENCYAREAID_BROADCAST_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_emergencyareaid_broadcast( + uint8_t **ptr, + LIBLTE_S1AP_EMERGENCYAREAID_BROADCAST_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE MDT_Configuration SEQUENCE +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_MDT_ACTIVATION_ENUM_EXT mdt_Activation; + LIBLTE_S1AP_AREASCOPEOFMDT_STRUCT areaScopeOfMDT; + LIBLTE_S1AP_MDTMODE_STRUCT mDTMode; + LIBLTE_S1AP_PROTOCOLEXTENSIONCONTAINER_STRUCT iE_Extensions; + bool iE_Extensions_present; +}LIBLTE_S1AP_MDT_CONFIGURATION_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_mdt_configuration( + LIBLTE_S1AP_MDT_CONFIGURATION_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_mdt_configuration( + uint8_t **ptr, + LIBLTE_S1AP_MDT_CONFIGURATION_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE TAI_Cancelled DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:65535 +typedef struct{ + uint32_t len; + LIBLTE_S1AP_TAI_CANCELLED_ITEM_STRUCT buffer[32]; //WARNING: Artificial limit to reduce memory footprint +}LIBLTE_S1AP_TAI_CANCELLED_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_tai_cancelled( + LIBLTE_S1AP_TAI_CANCELLED_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_tai_cancelled( + uint8_t **ptr, + LIBLTE_S1AP_TAI_CANCELLED_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE BroadcastCancelledAreaList CHOICE +********************************************************************************/ +typedef enum{ + LIBLTE_S1AP_BROADCASTCANCELLEDAREALIST_CHOICE_CELLID_CANCELLED, + LIBLTE_S1AP_BROADCASTCANCELLEDAREALIST_CHOICE_TAI_CANCELLED, + LIBLTE_S1AP_BROADCASTCANCELLEDAREALIST_CHOICE_EMERGENCYAREAID_CANCELLED, + LIBLTE_S1AP_BROADCASTCANCELLEDAREALIST_CHOICE_N_ITEMS, +}LIBLTE_S1AP_BROADCASTCANCELLEDAREALIST_CHOICE_ENUM; +static const char liblte_s1ap_broadcastcancelledarealist_choice_text[LIBLTE_S1AP_BROADCASTCANCELLEDAREALIST_CHOICE_N_ITEMS][50] = { + "cellID_Cancelled", + "tAI_Cancelled", + "emergencyAreaID_Cancelled", +}; + +typedef union{ + LIBLTE_S1AP_CELLID_CANCELLED_STRUCT cellID_Cancelled; + LIBLTE_S1AP_TAI_CANCELLED_STRUCT tAI_Cancelled; + LIBLTE_S1AP_EMERGENCYAREAID_CANCELLED_STRUCT emergencyAreaID_Cancelled; +}LIBLTE_S1AP_BROADCASTCANCELLEDAREALIST_CHOICE_UNION; + +typedef struct{ + bool ext; + LIBLTE_S1AP_BROADCASTCANCELLEDAREALIST_CHOICE_UNION choice; + LIBLTE_S1AP_BROADCASTCANCELLEDAREALIST_CHOICE_ENUM choice_type; +}LIBLTE_S1AP_BROADCASTCANCELLEDAREALIST_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_broadcastcancelledarealist( + LIBLTE_S1AP_BROADCASTCANCELLEDAREALIST_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_broadcastcancelledarealist( + uint8_t **ptr, + LIBLTE_S1AP_BROADCASTCANCELLEDAREALIST_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE ENB_StatusTransfer_TransparentContainer SEQUENCE +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_BEARERS_SUBJECTTOSTATUSTRANSFERLIST_STRUCT bearers_SubjectToStatusTransferList; + LIBLTE_S1AP_PROTOCOLEXTENSIONCONTAINER_STRUCT iE_Extensions; + bool iE_Extensions_present; +}LIBLTE_S1AP_ENB_STATUSTRANSFER_TRANSPARENTCONTAINER_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_enb_statustransfer_transparentcontainer( + LIBLTE_S1AP_ENB_STATUSTRANSFER_TRANSPARENTCONTAINER_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_enb_statustransfer_transparentcontainer( + uint8_t **ptr, + LIBLTE_S1AP_ENB_STATUSTRANSFER_TRANSPARENTCONTAINER_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE TraceActivation SEQUENCE +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_E_UTRAN_TRACE_ID_STRUCT e_UTRAN_Trace_ID; + LIBLTE_S1AP_INTERFACESTOTRACE_STRUCT interfacesToTrace; + LIBLTE_S1AP_TRACEDEPTH_ENUM_EXT traceDepth; + LIBLTE_S1AP_TRANSPORTLAYERADDRESS_STRUCT traceCollectionEntityIPAddress; + LIBLTE_S1AP_PROTOCOLEXTENSIONCONTAINER_STRUCT iE_Extensions; + bool iE_Extensions_present; +}LIBLTE_S1AP_TRACEACTIVATION_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_traceactivation( + LIBLTE_S1AP_TRACEACTIVATION_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_traceactivation( + uint8_t **ptr, + LIBLTE_S1AP_TRACEACTIVATION_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE BroadcastCompletedAreaList CHOICE +********************************************************************************/ +typedef enum{ + LIBLTE_S1AP_BROADCASTCOMPLETEDAREALIST_CHOICE_CELLID_BROADCAST, + LIBLTE_S1AP_BROADCASTCOMPLETEDAREALIST_CHOICE_TAI_BROADCAST, + LIBLTE_S1AP_BROADCASTCOMPLETEDAREALIST_CHOICE_EMERGENCYAREAID_BROADCAST, + LIBLTE_S1AP_BROADCASTCOMPLETEDAREALIST_CHOICE_N_ITEMS, +}LIBLTE_S1AP_BROADCASTCOMPLETEDAREALIST_CHOICE_ENUM; +static const char liblte_s1ap_broadcastcompletedarealist_choice_text[LIBLTE_S1AP_BROADCASTCOMPLETEDAREALIST_CHOICE_N_ITEMS][50] = { + "cellID_Broadcast", + "tAI_Broadcast", + "emergencyAreaID_Broadcast", +}; + +typedef union{ + LIBLTE_S1AP_CELLID_BROADCAST_STRUCT cellID_Broadcast; + LIBLTE_S1AP_TAI_BROADCAST_STRUCT tAI_Broadcast; + LIBLTE_S1AP_EMERGENCYAREAID_BROADCAST_STRUCT emergencyAreaID_Broadcast; +}LIBLTE_S1AP_BROADCASTCOMPLETEDAREALIST_CHOICE_UNION; + +typedef struct{ + bool ext; + LIBLTE_S1AP_BROADCASTCOMPLETEDAREALIST_CHOICE_UNION choice; + LIBLTE_S1AP_BROADCASTCOMPLETEDAREALIST_CHOICE_ENUM choice_type; +}LIBLTE_S1AP_BROADCASTCOMPLETEDAREALIST_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_broadcastcompletedarealist( + LIBLTE_S1AP_BROADCASTCOMPLETEDAREALIST_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_broadcastcompletedarealist( + uint8_t **ptr, + LIBLTE_S1AP_BROADCASTCOMPLETEDAREALIST_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE SONInformation CHOICE +********************************************************************************/ +typedef enum{ + LIBLTE_S1AP_SONINFORMATION_CHOICE_SONINFORMATIONREQUEST, + LIBLTE_S1AP_SONINFORMATION_CHOICE_SONINFORMATIONREPLY, + LIBLTE_S1AP_SONINFORMATION_CHOICE_N_ITEMS, +}LIBLTE_S1AP_SONINFORMATION_CHOICE_ENUM; +static const char liblte_s1ap_soninformation_choice_text[LIBLTE_S1AP_SONINFORMATION_CHOICE_N_ITEMS][50] = { + "sONInformationRequest", + "sONInformationReply", +}; + +typedef union{ + LIBLTE_S1AP_SONINFORMATIONREQUEST_ENUM_EXT sONInformationRequest; + LIBLTE_S1AP_SONINFORMATIONREPLY_STRUCT sONInformationReply; +}LIBLTE_S1AP_SONINFORMATION_CHOICE_UNION; + +typedef struct{ + bool ext; + LIBLTE_S1AP_SONINFORMATION_CHOICE_UNION choice; + LIBLTE_S1AP_SONINFORMATION_CHOICE_ENUM choice_type; +}LIBLTE_S1AP_SONINFORMATION_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_soninformation( + LIBLTE_S1AP_SONINFORMATION_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_soninformation( + uint8_t **ptr, + LIBLTE_S1AP_SONINFORMATION_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE SONConfigurationTransfer SEQUENCE +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_TARGETENB_ID_STRUCT targeteNB_ID; + LIBLTE_S1AP_SOURCEENB_ID_STRUCT sourceeNB_ID; + LIBLTE_S1AP_SONINFORMATION_STRUCT sONInformation; + LIBLTE_S1AP_PROTOCOLEXTENSIONCONTAINER_STRUCT iE_Extensions; + bool iE_Extensions_present; +}LIBLTE_S1AP_SONCONFIGURATIONTRANSFER_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_sonconfigurationtransfer( + LIBLTE_S1AP_SONCONFIGURATIONTRANSFER_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_sonconfigurationtransfer( + uint8_t **ptr, + LIBLTE_S1AP_SONCONFIGURATIONTRANSFER_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE ResetAll ENUMERATED +********************************************************************************/ +typedef enum{ + LIBLTE_S1AP_RESETALL_RESET_ALL, + LIBLTE_S1AP_RESETALL_N_ITEMS, +}LIBLTE_S1AP_RESETALL_ENUM; +static const char liblte_s1ap_resetall_text[LIBLTE_S1AP_RESETALL_N_ITEMS][80] = { + "reset-all", +}; + +typedef struct{ + bool ext; + LIBLTE_S1AP_RESETALL_ENUM e; +}LIBLTE_S1AP_RESETALL_ENUM_EXT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_resetall( + LIBLTE_S1AP_RESETALL_ENUM_EXT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_resetall( + uint8_t **ptr, + LIBLTE_S1AP_RESETALL_ENUM_EXT *ie); + +/******************************************************************************* +/* ProtocolIE Inter_SystemInformationTransferType CHOICE +********************************************************************************/ +typedef enum{ + LIBLTE_S1AP_INTER_SYSTEMINFORMATIONTRANSFERTYPE_CHOICE_RIMTRANSFER, + LIBLTE_S1AP_INTER_SYSTEMINFORMATIONTRANSFERTYPE_CHOICE_N_ITEMS, +}LIBLTE_S1AP_INTER_SYSTEMINFORMATIONTRANSFERTYPE_CHOICE_ENUM; +static const char liblte_s1ap_inter_systeminformationtransfertype_choice_text[LIBLTE_S1AP_INTER_SYSTEMINFORMATIONTRANSFERTYPE_CHOICE_N_ITEMS][50] = { + "rIMTransfer", +}; + +typedef union{ + LIBLTE_S1AP_RIMTRANSFER_STRUCT rIMTransfer; +}LIBLTE_S1AP_INTER_SYSTEMINFORMATIONTRANSFERTYPE_CHOICE_UNION; + +typedef struct{ + bool ext; + LIBLTE_S1AP_INTER_SYSTEMINFORMATIONTRANSFERTYPE_CHOICE_UNION choice; + LIBLTE_S1AP_INTER_SYSTEMINFORMATIONTRANSFERTYPE_CHOICE_ENUM choice_type; +}LIBLTE_S1AP_INTER_SYSTEMINFORMATIONTRANSFERTYPE_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_inter_systeminformationtransfertype( + LIBLTE_S1AP_INTER_SYSTEMINFORMATIONTRANSFERTYPE_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_inter_systeminformationtransfertype( + uint8_t **ptr, + LIBLTE_S1AP_INTER_SYSTEMINFORMATIONTRANSFERTYPE_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE E_RAB_IE_ContainerPairList DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:256 +typedef struct{ + uint32_t len; + LIBLTE_S1AP_PROTOCOLIE_CONTAINERPAIR_STRUCT buffer[32]; //WARNING: Artificial limit to reduce memory footprint +}LIBLTE_S1AP_E_RAB_IE_CONTAINERPAIRLIST_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rab_ie_containerpairlist( + LIBLTE_S1AP_E_RAB_IE_CONTAINERPAIRLIST_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rab_ie_containerpairlist( + uint8_t **ptr, + LIBLTE_S1AP_E_RAB_IE_CONTAINERPAIRLIST_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE E_RABDataForwardingItem SEQUENCE +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_E_RAB_ID_STRUCT e_RAB_ID; + LIBLTE_S1AP_TRANSPORTLAYERADDRESS_STRUCT dL_transportLayerAddress; + bool dL_transportLayerAddress_present; + LIBLTE_S1AP_GTP_TEID_STRUCT dL_gTP_TEID; + bool dL_gTP_TEID_present; + LIBLTE_S1AP_TRANSPORTLAYERADDRESS_STRUCT uL_TransportLayerAddress; + bool uL_TransportLayerAddress_present; + LIBLTE_S1AP_GTP_TEID_STRUCT uL_GTP_TEID; + bool uL_GTP_TEID_present; + LIBLTE_S1AP_PROTOCOLEXTENSIONCONTAINER_STRUCT iE_Extensions; + bool iE_Extensions_present; +}LIBLTE_S1AP_E_RABDATAFORWARDINGITEM_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabdataforwardingitem( + LIBLTE_S1AP_E_RABDATAFORWARDINGITEM_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabdataforwardingitem( + uint8_t **ptr, + LIBLTE_S1AP_E_RABDATAFORWARDINGITEM_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE E_RABToBeSetupItemHOReq SEQUENCE +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_E_RAB_ID_STRUCT e_RAB_ID; + LIBLTE_S1AP_TRANSPORTLAYERADDRESS_STRUCT transportLayerAddress; + LIBLTE_S1AP_GTP_TEID_STRUCT gTP_TEID; + LIBLTE_S1AP_E_RABLEVELQOSPARAMETERS_STRUCT e_RABlevelQosParameters; + LIBLTE_S1AP_PROTOCOLEXTENSIONCONTAINER_STRUCT iE_Extensions; + bool iE_Extensions_present; +}LIBLTE_S1AP_E_RABTOBESETUPITEMHOREQ_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabtobesetupitemhoreq( + LIBLTE_S1AP_E_RABTOBESETUPITEMHOREQ_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabtobesetupitemhoreq( + uint8_t **ptr, + LIBLTE_S1AP_E_RABTOBESETUPITEMHOREQ_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE E_RABAdmittedItem SEQUENCE +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_E_RAB_ID_STRUCT e_RAB_ID; + LIBLTE_S1AP_TRANSPORTLAYERADDRESS_STRUCT transportLayerAddress; + LIBLTE_S1AP_GTP_TEID_STRUCT gTP_TEID; + LIBLTE_S1AP_TRANSPORTLAYERADDRESS_STRUCT dL_transportLayerAddress; + bool dL_transportLayerAddress_present; + LIBLTE_S1AP_GTP_TEID_STRUCT dL_gTP_TEID; + bool dL_gTP_TEID_present; + LIBLTE_S1AP_TRANSPORTLAYERADDRESS_STRUCT uL_TransportLayerAddress; + bool uL_TransportLayerAddress_present; + LIBLTE_S1AP_GTP_TEID_STRUCT uL_GTP_TEID; + bool uL_GTP_TEID_present; + LIBLTE_S1AP_PROTOCOLEXTENSIONCONTAINER_STRUCT iE_Extensions; + bool iE_Extensions_present; +}LIBLTE_S1AP_E_RABADMITTEDITEM_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabadmitteditem( + LIBLTE_S1AP_E_RABADMITTEDITEM_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabadmitteditem( + uint8_t **ptr, + LIBLTE_S1AP_E_RABADMITTEDITEM_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE E_RABFailedToSetupItemHOReqAck SEQUENCE +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_E_RAB_ID_STRUCT e_RAB_ID; + LIBLTE_S1AP_CAUSE_STRUCT cause; + LIBLTE_S1AP_PROTOCOLEXTENSIONCONTAINER_STRUCT iE_Extensions; + bool iE_Extensions_present; +}LIBLTE_S1AP_E_RABFAILEDTOSETUPITEMHOREQACK_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabfailedtosetupitemhoreqack( + LIBLTE_S1AP_E_RABFAILEDTOSETUPITEMHOREQACK_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabfailedtosetupitemhoreqack( + uint8_t **ptr, + LIBLTE_S1AP_E_RABFAILEDTOSETUPITEMHOREQACK_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE E_RABToBeSwitchedDLItem SEQUENCE +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_E_RAB_ID_STRUCT e_RAB_ID; + LIBLTE_S1AP_TRANSPORTLAYERADDRESS_STRUCT transportLayerAddress; + LIBLTE_S1AP_GTP_TEID_STRUCT gTP_TEID; + LIBLTE_S1AP_PROTOCOLEXTENSIONCONTAINER_STRUCT iE_Extensions; + bool iE_Extensions_present; +}LIBLTE_S1AP_E_RABTOBESWITCHEDDLITEM_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabtobeswitcheddlitem( + LIBLTE_S1AP_E_RABTOBESWITCHEDDLITEM_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabtobeswitcheddlitem( + uint8_t **ptr, + LIBLTE_S1AP_E_RABTOBESWITCHEDDLITEM_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE E_RABToBeSwitchedULItem SEQUENCE +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_E_RAB_ID_STRUCT e_RAB_ID; + LIBLTE_S1AP_TRANSPORTLAYERADDRESS_STRUCT transportLayerAddress; + LIBLTE_S1AP_GTP_TEID_STRUCT gTP_TEID; + LIBLTE_S1AP_PROTOCOLEXTENSIONCONTAINER_STRUCT iE_Extensions; + bool iE_Extensions_present; +}LIBLTE_S1AP_E_RABTOBESWITCHEDULITEM_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabtobeswitchedulitem( + LIBLTE_S1AP_E_RABTOBESWITCHEDULITEM_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabtobeswitchedulitem( + uint8_t **ptr, + LIBLTE_S1AP_E_RABTOBESWITCHEDULITEM_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE E_RABToBeSetupItemBearerSUReq SEQUENCE +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_E_RAB_ID_STRUCT e_RAB_ID; + LIBLTE_S1AP_E_RABLEVELQOSPARAMETERS_STRUCT e_RABlevelQoSParameters; + LIBLTE_S1AP_TRANSPORTLAYERADDRESS_STRUCT transportLayerAddress; + LIBLTE_S1AP_GTP_TEID_STRUCT gTP_TEID; + LIBLTE_S1AP_NAS_PDU_STRUCT nAS_PDU; + LIBLTE_S1AP_PROTOCOLEXTENSIONCONTAINER_STRUCT iE_Extensions; + bool iE_Extensions_present; +}LIBLTE_S1AP_E_RABTOBESETUPITEMBEARERSUREQ_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabtobesetupitembearersureq( + LIBLTE_S1AP_E_RABTOBESETUPITEMBEARERSUREQ_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabtobesetupitembearersureq( + uint8_t **ptr, + LIBLTE_S1AP_E_RABTOBESETUPITEMBEARERSUREQ_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE E_RABSetupItemBearerSURes SEQUENCE +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_E_RAB_ID_STRUCT e_RAB_ID; + LIBLTE_S1AP_TRANSPORTLAYERADDRESS_STRUCT transportLayerAddress; + LIBLTE_S1AP_GTP_TEID_STRUCT gTP_TEID; + LIBLTE_S1AP_PROTOCOLEXTENSIONCONTAINER_STRUCT iE_Extensions; + bool iE_Extensions_present; +}LIBLTE_S1AP_E_RABSETUPITEMBEARERSURES_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabsetupitembearersures( + LIBLTE_S1AP_E_RABSETUPITEMBEARERSURES_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabsetupitembearersures( + uint8_t **ptr, + LIBLTE_S1AP_E_RABSETUPITEMBEARERSURES_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE E_RABToBeModifiedItemBearerModReq SEQUENCE +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_E_RAB_ID_STRUCT e_RAB_ID; + LIBLTE_S1AP_E_RABLEVELQOSPARAMETERS_STRUCT e_RABLevelQoSParameters; + LIBLTE_S1AP_NAS_PDU_STRUCT nAS_PDU; + LIBLTE_S1AP_PROTOCOLEXTENSIONCONTAINER_STRUCT iE_Extensions; + bool iE_Extensions_present; +}LIBLTE_S1AP_E_RABTOBEMODIFIEDITEMBEARERMODREQ_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabtobemodifieditembearermodreq( + LIBLTE_S1AP_E_RABTOBEMODIFIEDITEMBEARERMODREQ_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabtobemodifieditembearermodreq( + uint8_t **ptr, + LIBLTE_S1AP_E_RABTOBEMODIFIEDITEMBEARERMODREQ_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE E_RABModifyItemBearerModRes SEQUENCE +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_E_RAB_ID_STRUCT e_RAB_ID; + LIBLTE_S1AP_PROTOCOLEXTENSIONCONTAINER_STRUCT iE_Extensions; + bool iE_Extensions_present; +}LIBLTE_S1AP_E_RABMODIFYITEMBEARERMODRES_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabmodifyitembearermodres( + LIBLTE_S1AP_E_RABMODIFYITEMBEARERMODRES_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabmodifyitembearermodres( + uint8_t **ptr, + LIBLTE_S1AP_E_RABMODIFYITEMBEARERMODRES_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE E_RABReleaseItemBearerRelComp SEQUENCE +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_E_RAB_ID_STRUCT e_RAB_ID; + LIBLTE_S1AP_PROTOCOLEXTENSIONCONTAINER_STRUCT iE_Extensions; + bool iE_Extensions_present; +}LIBLTE_S1AP_E_RABRELEASEITEMBEARERRELCOMP_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabreleaseitembearerrelcomp( + LIBLTE_S1AP_E_RABRELEASEITEMBEARERRELCOMP_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabreleaseitembearerrelcomp( + uint8_t **ptr, + LIBLTE_S1AP_E_RABRELEASEITEMBEARERRELCOMP_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE E_RABToBeSetupItemCtxtSUReq SEQUENCE +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_E_RAB_ID_STRUCT e_RAB_ID; + LIBLTE_S1AP_E_RABLEVELQOSPARAMETERS_STRUCT e_RABlevelQoSParameters; + LIBLTE_S1AP_TRANSPORTLAYERADDRESS_STRUCT transportLayerAddress; + LIBLTE_S1AP_GTP_TEID_STRUCT gTP_TEID; + LIBLTE_S1AP_NAS_PDU_STRUCT nAS_PDU; + bool nAS_PDU_present; + LIBLTE_S1AP_PROTOCOLEXTENSIONCONTAINER_STRUCT iE_Extensions; + bool iE_Extensions_present; +}LIBLTE_S1AP_E_RABTOBESETUPITEMCTXTSUREQ_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabtobesetupitemctxtsureq( + LIBLTE_S1AP_E_RABTOBESETUPITEMCTXTSUREQ_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabtobesetupitemctxtsureq( + uint8_t **ptr, + LIBLTE_S1AP_E_RABTOBESETUPITEMCTXTSUREQ_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE E_RABSetupItemCtxtSURes SEQUENCE +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_E_RAB_ID_STRUCT e_RAB_ID; + LIBLTE_S1AP_TRANSPORTLAYERADDRESS_STRUCT transportLayerAddress; + LIBLTE_S1AP_GTP_TEID_STRUCT gTP_TEID; + LIBLTE_S1AP_PROTOCOLEXTENSIONCONTAINER_STRUCT iE_Extensions; + bool iE_Extensions_present; +}LIBLTE_S1AP_E_RABSETUPITEMCTXTSURES_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabsetupitemctxtsures( + LIBLTE_S1AP_E_RABSETUPITEMCTXTSURES_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabsetupitemctxtsures( + uint8_t **ptr, + LIBLTE_S1AP_E_RABSETUPITEMCTXTSURES_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE TAIItem SEQUENCE +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_TAI_STRUCT tAI; + LIBLTE_S1AP_PROTOCOLEXTENSIONCONTAINER_STRUCT iE_Extensions; + bool iE_Extensions_present; +}LIBLTE_S1AP_TAIITEM_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_taiitem( + LIBLTE_S1AP_TAIITEM_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_taiitem( + uint8_t **ptr, + LIBLTE_S1AP_TAIITEM_STRUCT *ie); + +/******************************************************************************* +/* Protocol Container List UE_associatedLogicalS1_ConnectionListRes DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:256 +typedef struct{ + uint32_t len; + LIBLTE_S1AP_UE_ASSOCIATEDLOGICALS1_CONNECTIONITEM_STRUCT buffer[32]; //WARNING: Artificial limit to reduce memory footprint +}LIBLTE_S1AP_UE_ASSOCIATEDLOGICALS1_CONNECTIONLISTRES_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_ue_associatedlogicals1_connectionlistres( + LIBLTE_S1AP_UE_ASSOCIATEDLOGICALS1_CONNECTIONLISTRES_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_ue_associatedlogicals1_connectionlistres( + uint8_t **ptr, + LIBLTE_S1AP_UE_ASSOCIATEDLOGICALS1_CONNECTIONLISTRES_STRUCT *ie); + +/******************************************************************************* +/* Protocol Container List UE_associatedLogicalS1_ConnectionListResAck DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:256 +typedef struct{ + uint32_t len; + LIBLTE_S1AP_UE_ASSOCIATEDLOGICALS1_CONNECTIONITEM_STRUCT buffer[32]; //WARNING: Artificial limit to reduce memory footprint +}LIBLTE_S1AP_UE_ASSOCIATEDLOGICALS1_CONNECTIONLISTRESACK_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_ue_associatedlogicals1_connectionlistresack( + LIBLTE_S1AP_UE_ASSOCIATEDLOGICALS1_CONNECTIONLISTRESACK_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_ue_associatedlogicals1_connectionlistresack( + uint8_t **ptr, + LIBLTE_S1AP_UE_ASSOCIATEDLOGICALS1_CONNECTIONLISTRESACK_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE PrivateMessage SEQUENCE +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_PRIVATEIE_CONTAINER_STRUCT privateIEs; +}LIBLTE_S1AP_PRIVATEMESSAGE_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_privatemessage( + LIBLTE_S1AP_PRIVATEMESSAGE_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_privatemessage( + uint8_t **ptr, + LIBLTE_S1AP_PRIVATEMESSAGE_STRUCT *ie); + +/******************************************************************************* +/* ProtocolIE ResetType CHOICE +********************************************************************************/ +typedef enum{ + LIBLTE_S1AP_RESETTYPE_CHOICE_S1_INTERFACE, + LIBLTE_S1AP_RESETTYPE_CHOICE_PARTOFS1_INTERFACE, + LIBLTE_S1AP_RESETTYPE_CHOICE_N_ITEMS, +}LIBLTE_S1AP_RESETTYPE_CHOICE_ENUM; +static const char liblte_s1ap_resettype_choice_text[LIBLTE_S1AP_RESETTYPE_CHOICE_N_ITEMS][50] = { + "s1_Interface", + "partOfS1_Interface", +}; + +typedef union{ + LIBLTE_S1AP_RESETALL_ENUM_EXT s1_Interface; + LIBLTE_S1AP_UE_ASSOCIATEDLOGICALS1_CONNECTIONLISTRES_STRUCT partOfS1_Interface; +}LIBLTE_S1AP_RESETTYPE_CHOICE_UNION; + +typedef struct{ + bool ext; + LIBLTE_S1AP_RESETTYPE_CHOICE_UNION choice; + LIBLTE_S1AP_RESETTYPE_CHOICE_ENUM choice_type; +}LIBLTE_S1AP_RESETTYPE_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_resettype( + LIBLTE_S1AP_RESETTYPE_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_resettype( + uint8_t **ptr, + LIBLTE_S1AP_RESETTYPE_STRUCT *ie); + +/******************************************************************************* +/* Protocol Container List E_RABSubjecttoDataForwardingList DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:256 +typedef struct{ + uint32_t len; + LIBLTE_S1AP_E_RABDATAFORWARDINGITEM_STRUCT buffer[32]; //WARNING: Artificial limit to reduce memory footprint +}LIBLTE_S1AP_E_RABSUBJECTTODATAFORWARDINGLIST_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabsubjecttodataforwardinglist( + LIBLTE_S1AP_E_RABSUBJECTTODATAFORWARDINGLIST_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabsubjecttodataforwardinglist( + uint8_t **ptr, + LIBLTE_S1AP_E_RABSUBJECTTODATAFORWARDINGLIST_STRUCT *ie); + +/******************************************************************************* +/* Protocol Container List E_RABToBeSetupListHOReq DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:256 +typedef struct{ + uint32_t len; + LIBLTE_S1AP_E_RABTOBESETUPITEMHOREQ_STRUCT buffer[32]; //WARNING: Artificial limit to reduce memory footprint +}LIBLTE_S1AP_E_RABTOBESETUPLISTHOREQ_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabtobesetuplisthoreq( + LIBLTE_S1AP_E_RABTOBESETUPLISTHOREQ_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabtobesetuplisthoreq( + uint8_t **ptr, + LIBLTE_S1AP_E_RABTOBESETUPLISTHOREQ_STRUCT *ie); + +/******************************************************************************* +/* Protocol Container List E_RABAdmittedList DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:256 +typedef struct{ + uint32_t len; + LIBLTE_S1AP_E_RABADMITTEDITEM_STRUCT buffer[32]; //WARNING: Artificial limit to reduce memory footprint +}LIBLTE_S1AP_E_RABADMITTEDLIST_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabadmittedlist( + LIBLTE_S1AP_E_RABADMITTEDLIST_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabadmittedlist( + uint8_t **ptr, + LIBLTE_S1AP_E_RABADMITTEDLIST_STRUCT *ie); + +/******************************************************************************* +/* Protocol Container List E_RABToBeSwitchedDLList DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:256 +typedef struct{ + uint32_t len; + LIBLTE_S1AP_E_RABTOBESWITCHEDDLITEM_STRUCT buffer[32]; //WARNING: Artificial limit to reduce memory footprint +}LIBLTE_S1AP_E_RABTOBESWITCHEDDLLIST_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabtobeswitcheddllist( + LIBLTE_S1AP_E_RABTOBESWITCHEDDLLIST_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabtobeswitcheddllist( + uint8_t **ptr, + LIBLTE_S1AP_E_RABTOBESWITCHEDDLLIST_STRUCT *ie); + +/******************************************************************************* +/* Protocol Container List E_RABToBeSwitchedULList DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:256 +typedef struct{ + uint32_t len; + LIBLTE_S1AP_E_RABTOBESWITCHEDULITEM_STRUCT buffer[32]; //WARNING: Artificial limit to reduce memory footprint +}LIBLTE_S1AP_E_RABTOBESWITCHEDULLIST_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabtobeswitchedullist( + LIBLTE_S1AP_E_RABTOBESWITCHEDULLIST_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabtobeswitchedullist( + uint8_t **ptr, + LIBLTE_S1AP_E_RABTOBESWITCHEDULLIST_STRUCT *ie); + +/******************************************************************************* +/* Protocol Container List E_RABToBeSetupListBearerSUReq DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:256 +typedef struct{ + uint32_t len; + LIBLTE_S1AP_E_RABTOBESETUPITEMBEARERSUREQ_STRUCT buffer[32]; //WARNING: Artificial limit to reduce memory footprint +}LIBLTE_S1AP_E_RABTOBESETUPLISTBEARERSUREQ_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabtobesetuplistbearersureq( + LIBLTE_S1AP_E_RABTOBESETUPLISTBEARERSUREQ_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabtobesetuplistbearersureq( + uint8_t **ptr, + LIBLTE_S1AP_E_RABTOBESETUPLISTBEARERSUREQ_STRUCT *ie); + +/******************************************************************************* +/* Protocol Container List E_RABSetupListBearerSURes DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:256 +typedef struct{ + uint32_t len; + LIBLTE_S1AP_E_RABSETUPITEMBEARERSURES_STRUCT buffer[32]; //WARNING: Artificial limit to reduce memory footprint +}LIBLTE_S1AP_E_RABSETUPLISTBEARERSURES_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabsetuplistbearersures( + LIBLTE_S1AP_E_RABSETUPLISTBEARERSURES_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabsetuplistbearersures( + uint8_t **ptr, + LIBLTE_S1AP_E_RABSETUPLISTBEARERSURES_STRUCT *ie); + +/******************************************************************************* +/* Protocol Container List E_RABToBeModifiedListBearerModReq DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:256 +typedef struct{ + uint32_t len; + LIBLTE_S1AP_E_RABTOBEMODIFIEDITEMBEARERMODREQ_STRUCT buffer[32]; //WARNING: Artificial limit to reduce memory footprint +}LIBLTE_S1AP_E_RABTOBEMODIFIEDLISTBEARERMODREQ_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabtobemodifiedlistbearermodreq( + LIBLTE_S1AP_E_RABTOBEMODIFIEDLISTBEARERMODREQ_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabtobemodifiedlistbearermodreq( + uint8_t **ptr, + LIBLTE_S1AP_E_RABTOBEMODIFIEDLISTBEARERMODREQ_STRUCT *ie); + +/******************************************************************************* +/* Protocol Container List E_RABModifyListBearerModRes DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:256 +typedef struct{ + uint32_t len; + LIBLTE_S1AP_E_RABMODIFYITEMBEARERMODRES_STRUCT buffer[32]; //WARNING: Artificial limit to reduce memory footprint +}LIBLTE_S1AP_E_RABMODIFYLISTBEARERMODRES_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabmodifylistbearermodres( + LIBLTE_S1AP_E_RABMODIFYLISTBEARERMODRES_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabmodifylistbearermodres( + uint8_t **ptr, + LIBLTE_S1AP_E_RABMODIFYLISTBEARERMODRES_STRUCT *ie); + +/******************************************************************************* +/* Protocol Container List E_RABReleaseListBearerRelComp DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:256 +typedef struct{ + uint32_t len; + LIBLTE_S1AP_E_RABRELEASEITEMBEARERRELCOMP_STRUCT buffer[32]; //WARNING: Artificial limit to reduce memory footprint +}LIBLTE_S1AP_E_RABRELEASELISTBEARERRELCOMP_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabreleaselistbearerrelcomp( + LIBLTE_S1AP_E_RABRELEASELISTBEARERRELCOMP_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabreleaselistbearerrelcomp( + uint8_t **ptr, + LIBLTE_S1AP_E_RABRELEASELISTBEARERRELCOMP_STRUCT *ie); + +/******************************************************************************* +/* Protocol Container List E_RABToBeSetupListCtxtSUReq DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:256 +typedef struct{ + uint32_t len; + LIBLTE_S1AP_E_RABTOBESETUPITEMCTXTSUREQ_STRUCT buffer[32]; //WARNING: Artificial limit to reduce memory footprint +}LIBLTE_S1AP_E_RABTOBESETUPLISTCTXTSUREQ_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabtobesetuplistctxtsureq( + LIBLTE_S1AP_E_RABTOBESETUPLISTCTXTSUREQ_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabtobesetuplistctxtsureq( + uint8_t **ptr, + LIBLTE_S1AP_E_RABTOBESETUPLISTCTXTSUREQ_STRUCT *ie); + +/******************************************************************************* +/* Protocol Container List E_RABSetupListCtxtSURes DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:256 +typedef struct{ + uint32_t len; + LIBLTE_S1AP_E_RABSETUPITEMCTXTSURES_STRUCT buffer[32]; //WARNING: Artificial limit to reduce memory footprint +}LIBLTE_S1AP_E_RABSETUPLISTCTXTSURES_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabsetuplistctxtsures( + LIBLTE_S1AP_E_RABSETUPLISTCTXTSURES_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabsetuplistctxtsures( + uint8_t **ptr, + LIBLTE_S1AP_E_RABSETUPLISTCTXTSURES_STRUCT *ie); + +/******************************************************************************* +/* Protocol Container List TAIList DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:256 +typedef struct{ + uint32_t len; + LIBLTE_S1AP_TAIITEM_STRUCT buffer[32]; //WARNING: Artificial limit to reduce memory footprint +}LIBLTE_S1AP_TAILIST_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_tailist( + LIBLTE_S1AP_TAILIST_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_tailist( + uint8_t **ptr, + LIBLTE_S1AP_TAILIST_STRUCT *ie); + +/******************************************************************************* +/* Protocol Container List E_RABFailedtoSetupListHOReqAck DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:256 +typedef struct{ + uint32_t len; + LIBLTE_S1AP_E_RABFAILEDTOSETUPITEMHOREQACK_STRUCT buffer[32]; //WARNING: Artificial limit to reduce memory footprint +}LIBLTE_S1AP_E_RABFAILEDTOSETUPLISTHOREQACK_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabfailedtosetuplisthoreqack( + LIBLTE_S1AP_E_RABFAILEDTOSETUPLISTHOREQACK_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabfailedtosetuplisthoreqack( + uint8_t **ptr, + LIBLTE_S1AP_E_RABFAILEDTOSETUPLISTHOREQACK_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message AllocationAndRetentionPriority_Ext STRUCT +********************************************************************************/ +typedef struct{ + bool ext; +}LIBLTE_S1AP_MESSAGE_ALLOCATIONANDRETENTIONPRIORITY_EXT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_allocationandretentionpriority_ext( + LIBLTE_S1AP_MESSAGE_ALLOCATIONANDRETENTIONPRIORITY_EXT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_allocationandretentionpriority_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_ALLOCATIONANDRETENTIONPRIORITY_EXT_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message CancelledCellinEAI_Item_Ext STRUCT +********************************************************************************/ +typedef struct{ + bool ext; +}LIBLTE_S1AP_MESSAGE_CANCELLEDCELLINEAI_ITEM_EXT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_cancelledcellineai_item_ext( + LIBLTE_S1AP_MESSAGE_CANCELLEDCELLINEAI_ITEM_EXT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_cancelledcellineai_item_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_CANCELLEDCELLINEAI_ITEM_EXT_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message CancelledCellinTAI_Item_Ext STRUCT +********************************************************************************/ +typedef struct{ + bool ext; +}LIBLTE_S1AP_MESSAGE_CANCELLEDCELLINTAI_ITEM_EXT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_cancelledcellintai_item_ext( + LIBLTE_S1AP_MESSAGE_CANCELLEDCELLINTAI_ITEM_EXT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_cancelledcellintai_item_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_CANCELLEDCELLINTAI_ITEM_EXT_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message CellID_Broadcast_Item_Ext STRUCT +********************************************************************************/ +typedef struct{ + bool ext; +}LIBLTE_S1AP_MESSAGE_CELLID_BROADCAST_ITEM_EXT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_cellid_broadcast_item_ext( + LIBLTE_S1AP_MESSAGE_CELLID_BROADCAST_ITEM_EXT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_cellid_broadcast_item_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_CELLID_BROADCAST_ITEM_EXT_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message CellID_Cancelled_Item_Ext STRUCT +********************************************************************************/ +typedef struct{ + bool ext; +}LIBLTE_S1AP_MESSAGE_CELLID_CANCELLED_ITEM_EXT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_cellid_cancelled_item_ext( + LIBLTE_S1AP_MESSAGE_CELLID_CANCELLED_ITEM_EXT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_cellid_cancelled_item_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_CELLID_CANCELLED_ITEM_EXT_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message CellBasedMDT_Ext STRUCT +********************************************************************************/ +typedef struct{ + bool ext; +}LIBLTE_S1AP_MESSAGE_CELLBASEDMDT_EXT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_cellbasedmdt_ext( + LIBLTE_S1AP_MESSAGE_CELLBASEDMDT_EXT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_cellbasedmdt_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_CELLBASEDMDT_EXT_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message Cdma2000OneXSRVCCInfo_Ext STRUCT +********************************************************************************/ +typedef struct{ + bool ext; +}LIBLTE_S1AP_MESSAGE_CDMA2000ONEXSRVCCINFO_EXT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_cdma2000onexsrvccinfo_ext( + LIBLTE_S1AP_MESSAGE_CDMA2000ONEXSRVCCINFO_EXT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_cdma2000onexsrvccinfo_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_CDMA2000ONEXSRVCCINFO_EXT_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message CellType_Ext STRUCT +********************************************************************************/ +typedef struct{ + bool ext; +}LIBLTE_S1AP_MESSAGE_CELLTYPE_EXT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_celltype_ext( + LIBLTE_S1AP_MESSAGE_CELLTYPE_EXT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_celltype_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_CELLTYPE_EXT_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message CGI_Ext STRUCT +********************************************************************************/ +typedef struct{ + bool ext; +}LIBLTE_S1AP_MESSAGE_CGI_EXT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_cgi_ext( + LIBLTE_S1AP_MESSAGE_CGI_EXT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_cgi_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_CGI_EXT_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message CSG_IdList_Item_Ext STRUCT +********************************************************************************/ +typedef struct{ + bool ext; +}LIBLTE_S1AP_MESSAGE_CSG_IDLIST_ITEM_EXT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_csg_idlist_item_ext( + LIBLTE_S1AP_MESSAGE_CSG_IDLIST_ITEM_EXT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_csg_idlist_item_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_CSG_IDLIST_ITEM_EXT_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message COUNTvalue_Ext STRUCT +********************************************************************************/ +typedef struct{ + bool ext; +}LIBLTE_S1AP_MESSAGE_COUNTVALUE_EXT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_countvalue_ext( + LIBLTE_S1AP_MESSAGE_COUNTVALUE_EXT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_countvalue_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_COUNTVALUE_EXT_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message COUNTValueExtended_Ext STRUCT +********************************************************************************/ +typedef struct{ + bool ext; +}LIBLTE_S1AP_MESSAGE_COUNTVALUEEXTENDED_EXT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_countvalueextended_ext( + LIBLTE_S1AP_MESSAGE_COUNTVALUEEXTENDED_EXT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_countvalueextended_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_COUNTVALUEEXTENDED_EXT_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message CriticalityDiagnostics_Ext STRUCT +********************************************************************************/ +typedef struct{ + bool ext; +}LIBLTE_S1AP_MESSAGE_CRITICALITYDIAGNOSTICS_EXT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_criticalitydiagnostics_ext( + LIBLTE_S1AP_MESSAGE_CRITICALITYDIAGNOSTICS_EXT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_criticalitydiagnostics_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_CRITICALITYDIAGNOSTICS_EXT_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message CriticalityDiagnostics_IE_Item_Ext STRUCT +********************************************************************************/ +typedef struct{ + bool ext; +}LIBLTE_S1AP_MESSAGE_CRITICALITYDIAGNOSTICS_IE_ITEM_EXT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_criticalitydiagnostics_ie_item_ext( + LIBLTE_S1AP_MESSAGE_CRITICALITYDIAGNOSTICS_IE_ITEM_EXT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_criticalitydiagnostics_ie_item_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_CRITICALITYDIAGNOSTICS_IE_ITEM_EXT_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message EmergencyAreaID_Broadcast_Item_Ext STRUCT +********************************************************************************/ +typedef struct{ + bool ext; +}LIBLTE_S1AP_MESSAGE_EMERGENCYAREAID_BROADCAST_ITEM_EXT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_emergencyareaid_broadcast_item_ext( + LIBLTE_S1AP_MESSAGE_EMERGENCYAREAID_BROADCAST_ITEM_EXT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_emergencyareaid_broadcast_item_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_EMERGENCYAREAID_BROADCAST_ITEM_EXT_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message EmergencyAreaID_Cancelled_Item_Ext STRUCT +********************************************************************************/ +typedef struct{ + bool ext; +}LIBLTE_S1AP_MESSAGE_EMERGENCYAREAID_CANCELLED_ITEM_EXT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_emergencyareaid_cancelled_item_ext( + LIBLTE_S1AP_MESSAGE_EMERGENCYAREAID_CANCELLED_ITEM_EXT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_emergencyareaid_cancelled_item_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_EMERGENCYAREAID_CANCELLED_ITEM_EXT_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message CompletedCellinEAI_Item_Ext STRUCT +********************************************************************************/ +typedef struct{ + bool ext; +}LIBLTE_S1AP_MESSAGE_COMPLETEDCELLINEAI_ITEM_EXT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_completedcellineai_item_ext( + LIBLTE_S1AP_MESSAGE_COMPLETEDCELLINEAI_ITEM_EXT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_completedcellineai_item_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_COMPLETEDCELLINEAI_ITEM_EXT_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message GERAN_Cell_ID_Ext STRUCT +********************************************************************************/ +typedef struct{ + bool ext; +}LIBLTE_S1AP_MESSAGE_GERAN_CELL_ID_EXT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_geran_cell_id_ext( + LIBLTE_S1AP_MESSAGE_GERAN_CELL_ID_EXT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_geran_cell_id_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_GERAN_CELL_ID_EXT_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message GlobalENB_ID_Ext STRUCT +********************************************************************************/ +typedef struct{ + bool ext; +}LIBLTE_S1AP_MESSAGE_GLOBALENB_ID_EXT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_globalenb_id_ext( + LIBLTE_S1AP_MESSAGE_GLOBALENB_ID_EXT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_globalenb_id_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_GLOBALENB_ID_EXT_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message ENB_StatusTransfer_TransparentContainer_Ext STRUCT +********************************************************************************/ +typedef struct{ + bool ext; +}LIBLTE_S1AP_MESSAGE_ENB_STATUSTRANSFER_TRANSPARENTCONTAINER_EXT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_enb_statustransfer_transparentcontainer_ext( + LIBLTE_S1AP_MESSAGE_ENB_STATUSTRANSFER_TRANSPARENTCONTAINER_EXT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_enb_statustransfer_transparentcontainer_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_ENB_STATUSTRANSFER_TRANSPARENTCONTAINER_EXT_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message E_RABInformationListItem_Ext STRUCT +********************************************************************************/ +typedef struct{ + bool ext; +}LIBLTE_S1AP_MESSAGE_E_RABINFORMATIONLISTITEM_EXT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabinformationlistitem_ext( + LIBLTE_S1AP_MESSAGE_E_RABINFORMATIONLISTITEM_EXT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabinformationlistitem_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_E_RABINFORMATIONLISTITEM_EXT_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message E_RABItem_Ext STRUCT +********************************************************************************/ +typedef struct{ + bool ext; +}LIBLTE_S1AP_MESSAGE_E_RABITEM_EXT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabitem_ext( + LIBLTE_S1AP_MESSAGE_E_RABITEM_EXT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabitem_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_E_RABITEM_EXT_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message E_RABQoSParameters_Ext STRUCT +********************************************************************************/ +typedef struct{ + bool ext; +}LIBLTE_S1AP_MESSAGE_E_RABQOSPARAMETERS_EXT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabqosparameters_ext( + LIBLTE_S1AP_MESSAGE_E_RABQOSPARAMETERS_EXT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabqosparameters_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_E_RABQOSPARAMETERS_EXT_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message EUTRAN_CGI_Ext STRUCT +********************************************************************************/ +typedef struct{ + bool ext; +}LIBLTE_S1AP_MESSAGE_EUTRAN_CGI_EXT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_eutran_cgi_ext( + LIBLTE_S1AP_MESSAGE_EUTRAN_CGI_EXT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_eutran_cgi_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_EUTRAN_CGI_EXT_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message ForbiddenTAs_Item_Ext STRUCT +********************************************************************************/ +typedef struct{ + bool ext; +}LIBLTE_S1AP_MESSAGE_FORBIDDENTAS_ITEM_EXT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_forbiddentas_item_ext( + LIBLTE_S1AP_MESSAGE_FORBIDDENTAS_ITEM_EXT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_forbiddentas_item_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_FORBIDDENTAS_ITEM_EXT_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message ForbiddenLAs_Item_Ext STRUCT +********************************************************************************/ +typedef struct{ + bool ext; +}LIBLTE_S1AP_MESSAGE_FORBIDDENLAS_ITEM_EXT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_forbiddenlas_item_ext( + LIBLTE_S1AP_MESSAGE_FORBIDDENLAS_ITEM_EXT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_forbiddenlas_item_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_FORBIDDENLAS_ITEM_EXT_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message GBR_QosInformation_Ext STRUCT +********************************************************************************/ +typedef struct{ + bool ext; +}LIBLTE_S1AP_MESSAGE_GBR_QOSINFORMATION_EXT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_gbr_qosinformation_ext( + LIBLTE_S1AP_MESSAGE_GBR_QOSINFORMATION_EXT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_gbr_qosinformation_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_GBR_QOSINFORMATION_EXT_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message GUMMEI_Ext STRUCT +********************************************************************************/ +typedef struct{ + bool ext; +}LIBLTE_S1AP_MESSAGE_GUMMEI_EXT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_gummei_ext( + LIBLTE_S1AP_MESSAGE_GUMMEI_EXT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_gummei_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_GUMMEI_EXT_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message HandoverRestrictionList_Ext STRUCT +********************************************************************************/ +typedef struct{ + bool ext; +}LIBLTE_S1AP_MESSAGE_HANDOVERRESTRICTIONLIST_EXT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_handoverrestrictionlist_ext( + LIBLTE_S1AP_MESSAGE_HANDOVERRESTRICTIONLIST_EXT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_handoverrestrictionlist_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_HANDOVERRESTRICTIONLIST_EXT_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message LAI_Ext STRUCT +********************************************************************************/ +typedef struct{ + bool ext; +}LIBLTE_S1AP_MESSAGE_LAI_EXT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_lai_ext( + LIBLTE_S1AP_MESSAGE_LAI_EXT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_lai_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_LAI_EXT_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message LoggedMDT_Ext STRUCT +********************************************************************************/ +typedef struct{ + bool ext; +}LIBLTE_S1AP_MESSAGE_LOGGEDMDT_EXT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_loggedmdt_ext( + LIBLTE_S1AP_MESSAGE_LOGGEDMDT_EXT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_loggedmdt_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_LOGGEDMDT_EXT_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message M3Configuration_Ext STRUCT +********************************************************************************/ +typedef struct{ + bool ext; +}LIBLTE_S1AP_MESSAGE_M3CONFIGURATION_EXT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_m3configuration_ext( + LIBLTE_S1AP_MESSAGE_M3CONFIGURATION_EXT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_m3configuration_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_M3CONFIGURATION_EXT_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message M4Configuration_Ext STRUCT +********************************************************************************/ +typedef struct{ + bool ext; +}LIBLTE_S1AP_MESSAGE_M4CONFIGURATION_EXT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_m4configuration_ext( + LIBLTE_S1AP_MESSAGE_M4CONFIGURATION_EXT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_m4configuration_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_M4CONFIGURATION_EXT_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message M5Configuration_Ext STRUCT +********************************************************************************/ +typedef struct{ + bool ext; +}LIBLTE_S1AP_MESSAGE_M5CONFIGURATION_EXT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_m5configuration_ext( + LIBLTE_S1AP_MESSAGE_M5CONFIGURATION_EXT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_m5configuration_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_M5CONFIGURATION_EXT_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message M1PeriodicReporting_Ext STRUCT +********************************************************************************/ +typedef struct{ + bool ext; +}LIBLTE_S1AP_MESSAGE_M1PERIODICREPORTING_EXT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_m1periodicreporting_ext( + LIBLTE_S1AP_MESSAGE_M1PERIODICREPORTING_EXT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_m1periodicreporting_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_M1PERIODICREPORTING_EXT_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message RequestType_Ext STRUCT +********************************************************************************/ +typedef struct{ + bool ext; +}LIBLTE_S1AP_MESSAGE_REQUESTTYPE_EXT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_requesttype_ext( + LIBLTE_S1AP_MESSAGE_REQUESTTYPE_EXT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_requesttype_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_REQUESTTYPE_EXT_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message RIMTransfer_Ext STRUCT +********************************************************************************/ +typedef struct{ + bool ext; +}LIBLTE_S1AP_MESSAGE_RIMTRANSFER_EXT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_rimtransfer_ext( + LIBLTE_S1AP_MESSAGE_RIMTRANSFER_EXT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_rimtransfer_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_RIMTRANSFER_EXT_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message SecurityContext_Ext STRUCT +********************************************************************************/ +typedef struct{ + bool ext; +}LIBLTE_S1AP_MESSAGE_SECURITYCONTEXT_EXT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_securitycontext_ext( + LIBLTE_S1AP_MESSAGE_SECURITYCONTEXT_EXT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_securitycontext_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_SECURITYCONTEXT_EXT_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message SourceeNB_ID_Ext STRUCT +********************************************************************************/ +typedef struct{ + bool ext; +}LIBLTE_S1AP_MESSAGE_SOURCEENB_ID_EXT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_sourceenb_id_ext( + LIBLTE_S1AP_MESSAGE_SOURCEENB_ID_EXT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_sourceenb_id_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_SOURCEENB_ID_EXT_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message ServedGUMMEIsItem_Ext STRUCT +********************************************************************************/ +typedef struct{ + bool ext; +}LIBLTE_S1AP_MESSAGE_SERVEDGUMMEISITEM_EXT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_servedgummeisitem_ext( + LIBLTE_S1AP_MESSAGE_SERVEDGUMMEISITEM_EXT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_servedgummeisitem_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_SERVEDGUMMEISITEM_EXT_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message SupportedTAs_Item_Ext STRUCT +********************************************************************************/ +typedef struct{ + bool ext; +}LIBLTE_S1AP_MESSAGE_SUPPORTEDTAS_ITEM_EXT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_supportedtas_item_ext( + LIBLTE_S1AP_MESSAGE_SUPPORTEDTAS_ITEM_EXT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_supportedtas_item_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_SUPPORTEDTAS_ITEM_EXT_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message TimeSynchronizationInfo_Ext STRUCT +********************************************************************************/ +typedef struct{ + bool ext; +}LIBLTE_S1AP_MESSAGE_TIMESYNCHRONIZATIONINFO_EXT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_timesynchronizationinfo_ext( + LIBLTE_S1AP_MESSAGE_TIMESYNCHRONIZATIONINFO_EXT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_timesynchronizationinfo_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_TIMESYNCHRONIZATIONINFO_EXT_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message S_TMSI_Ext STRUCT +********************************************************************************/ +typedef struct{ + bool ext; +}LIBLTE_S1AP_MESSAGE_S_TMSI_EXT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_s_tmsi_ext( + LIBLTE_S1AP_MESSAGE_S_TMSI_EXT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_s_tmsi_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_S_TMSI_EXT_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message TAIBasedMDT_Ext STRUCT +********************************************************************************/ +typedef struct{ + bool ext; +}LIBLTE_S1AP_MESSAGE_TAIBASEDMDT_EXT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_taibasedmdt_ext( + LIBLTE_S1AP_MESSAGE_TAIBASEDMDT_EXT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_taibasedmdt_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_TAIBASEDMDT_EXT_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message TAI_Ext STRUCT +********************************************************************************/ +typedef struct{ + bool ext; +}LIBLTE_S1AP_MESSAGE_TAI_EXT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_tai_ext( + LIBLTE_S1AP_MESSAGE_TAI_EXT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_tai_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_TAI_EXT_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message TAI_Broadcast_Item_Ext STRUCT +********************************************************************************/ +typedef struct{ + bool ext; +}LIBLTE_S1AP_MESSAGE_TAI_BROADCAST_ITEM_EXT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_tai_broadcast_item_ext( + LIBLTE_S1AP_MESSAGE_TAI_BROADCAST_ITEM_EXT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_tai_broadcast_item_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_TAI_BROADCAST_ITEM_EXT_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message TAI_Cancelled_Item_Ext STRUCT +********************************************************************************/ +typedef struct{ + bool ext; +}LIBLTE_S1AP_MESSAGE_TAI_CANCELLED_ITEM_EXT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_tai_cancelled_item_ext( + LIBLTE_S1AP_MESSAGE_TAI_CANCELLED_ITEM_EXT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_tai_cancelled_item_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_TAI_CANCELLED_ITEM_EXT_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message TABasedMDT_Ext STRUCT +********************************************************************************/ +typedef struct{ + bool ext; +}LIBLTE_S1AP_MESSAGE_TABASEDMDT_EXT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_tabasedmdt_ext( + LIBLTE_S1AP_MESSAGE_TABASEDMDT_EXT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_tabasedmdt_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_TABASEDMDT_EXT_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message CompletedCellinTAI_Item_Ext STRUCT +********************************************************************************/ +typedef struct{ + bool ext; +}LIBLTE_S1AP_MESSAGE_COMPLETEDCELLINTAI_ITEM_EXT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_completedcellintai_item_ext( + LIBLTE_S1AP_MESSAGE_COMPLETEDCELLINTAI_ITEM_EXT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_completedcellintai_item_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_COMPLETEDCELLINTAI_ITEM_EXT_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message TargeteNB_ID_Ext STRUCT +********************************************************************************/ +typedef struct{ + bool ext; +}LIBLTE_S1AP_MESSAGE_TARGETENB_ID_EXT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_targetenb_id_ext( + LIBLTE_S1AP_MESSAGE_TARGETENB_ID_EXT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_targetenb_id_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_TARGETENB_ID_EXT_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message TargetRNC_ID_Ext STRUCT +********************************************************************************/ +typedef struct{ + bool ext; +}LIBLTE_S1AP_MESSAGE_TARGETRNC_ID_EXT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_targetrnc_id_ext( + LIBLTE_S1AP_MESSAGE_TARGETRNC_ID_EXT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_targetrnc_id_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_TARGETRNC_ID_EXT_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message TargeteNB_ToSourceeNB_TransparentContainer_Ext STRUCT +********************************************************************************/ +typedef struct{ + bool ext; +}LIBLTE_S1AP_MESSAGE_TARGETENB_TOSOURCEENB_TRANSPARENTCONTAINER_EXT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_targetenb_tosourceenb_transparentcontainer_ext( + LIBLTE_S1AP_MESSAGE_TARGETENB_TOSOURCEENB_TRANSPARENTCONTAINER_EXT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_targetenb_tosourceenb_transparentcontainer_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_TARGETENB_TOSOURCEENB_TRANSPARENTCONTAINER_EXT_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message M1ThresholdEventA2_Ext STRUCT +********************************************************************************/ +typedef struct{ + bool ext; +}LIBLTE_S1AP_MESSAGE_M1THRESHOLDEVENTA2_EXT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_m1thresholdeventa2_ext( + LIBLTE_S1AP_MESSAGE_M1THRESHOLDEVENTA2_EXT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_m1thresholdeventa2_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_M1THRESHOLDEVENTA2_EXT_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message Tunnel_Information_Ext STRUCT +********************************************************************************/ +typedef struct{ + bool ext; +}LIBLTE_S1AP_MESSAGE_TUNNEL_INFORMATION_EXT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_tunnel_information_ext( + LIBLTE_S1AP_MESSAGE_TUNNEL_INFORMATION_EXT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_tunnel_information_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_TUNNEL_INFORMATION_EXT_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message UEAggregate_MaximumBitrates_Ext STRUCT +********************************************************************************/ +typedef struct{ + bool ext; +}LIBLTE_S1AP_MESSAGE_UEAGGREGATE_MAXIMUMBITRATES_EXT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_ueaggregate_maximumbitrates_ext( + LIBLTE_S1AP_MESSAGE_UEAGGREGATE_MAXIMUMBITRATES_EXT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_ueaggregate_maximumbitrates_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_UEAGGREGATE_MAXIMUMBITRATES_EXT_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message UE_S1AP_ID_pair_Ext STRUCT +********************************************************************************/ +typedef struct{ + bool ext; +}LIBLTE_S1AP_MESSAGE_UE_S1AP_ID_PAIR_EXT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_ue_s1ap_id_pair_ext( + LIBLTE_S1AP_MESSAGE_UE_S1AP_ID_PAIR_EXT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_ue_s1ap_id_pair_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_UE_S1AP_ID_PAIR_EXT_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message UE_associatedLogicalS1_ConnectionItemExt STRUCT +********************************************************************************/ +typedef struct{ + bool ext; +}LIBLTE_S1AP_MESSAGE_UE_ASSOCIATEDLOGICALS1_CONNECTIONITEMEXT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_ue_associatedlogicals1_connectionitemext( + LIBLTE_S1AP_MESSAGE_UE_ASSOCIATEDLOGICALS1_CONNECTIONITEMEXT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_ue_associatedlogicals1_connectionitemext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_UE_ASSOCIATEDLOGICALS1_CONNECTIONITEMEXT_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message UESecurityCapabilities_Ext STRUCT +********************************************************************************/ +typedef struct{ + bool ext; +}LIBLTE_S1AP_MESSAGE_UESECURITYCAPABILITIES_EXT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_uesecuritycapabilities_ext( + LIBLTE_S1AP_MESSAGE_UESECURITYCAPABILITIES_EXT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_uesecuritycapabilities_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_UESECURITYCAPABILITIES_EXT_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message UserLocationInformation_Ext STRUCT +********************************************************************************/ +typedef struct{ + bool ext; +}LIBLTE_S1AP_MESSAGE_USERLOCATIONINFORMATION_EXT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_userlocationinformation_ext( + LIBLTE_S1AP_MESSAGE_USERLOCATIONINFORMATION_EXT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_userlocationinformation_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_USERLOCATIONINFORMATION_EXT_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message ENBX2ExtTLA_Ext STRUCT +********************************************************************************/ +typedef struct{ + bool ext; +}LIBLTE_S1AP_MESSAGE_ENBX2EXTTLA_EXT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_enbx2exttla_ext( + LIBLTE_S1AP_MESSAGE_ENBX2EXTTLA_EXT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_enbx2exttla_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_ENBX2EXTTLA_EXT_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message SourceeNB_ToTargeteNB_TransparentContainer_Ext STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_MOBILITYINFORMATION_STRUCT MobilityInformation; + bool MobilityInformation_present; +}LIBLTE_S1AP_MESSAGE_SOURCEENB_TOTARGETENB_TRANSPARENTCONTAINER_EXT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_sourceenb_totargetenb_transparentcontainer_ext( + LIBLTE_S1AP_MESSAGE_SOURCEENB_TOTARGETENB_TRANSPARENTCONTAINER_EXT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_sourceenb_totargetenb_transparentcontainer_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_SOURCEENB_TOTARGETENB_TRANSPARENTCONTAINER_EXT_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message E_RABInformationList STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_E_RABINFORMATIONLISTITEM_STRUCT E_RABInformationListItem; +}LIBLTE_S1AP_MESSAGE_E_RABINFORMATIONLIST_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabinformationlist( + LIBLTE_S1AP_MESSAGE_E_RABINFORMATIONLIST_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabinformationlist( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_E_RABINFORMATIONLIST_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message LastVisitedEUTRANCellInformation_Ext STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_TIME_UE_STAYEDINCELL_ENHANCEDGRANULARITY_STRUCT Time_UE_StayedInCell_EnhancedGranularity; + bool Time_UE_StayedInCell_EnhancedGranularity_present; + LIBLTE_S1AP_CAUSE_STRUCT HO_Cause; + bool HO_Cause_present; +}LIBLTE_S1AP_MESSAGE_LASTVISITEDEUTRANCELLINFORMATION_EXT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_lastvisitedeutrancellinformation_ext( + LIBLTE_S1AP_MESSAGE_LASTVISITEDEUTRANCELLINFORMATION_EXT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_lastvisitedeutrancellinformation_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_LASTVISITEDEUTRANCELLINFORMATION_EXT_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message SONInformationReply_Ext STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_TIMESYNCHRONIZATIONINFO_STRUCT Time_Synchronization_Info; + bool Time_Synchronization_Info_present; +}LIBLTE_S1AP_MESSAGE_SONINFORMATIONREPLY_EXT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_soninformationreply_ext( + LIBLTE_S1AP_MESSAGE_SONINFORMATIONREPLY_EXT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_soninformationreply_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_SONINFORMATIONREPLY_EXT_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message Bearers_SubjectToStatusTransfer_ItemExt STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_COUNTVALUEEXTENDED_STRUCT ULCOUNTValueExtended; + bool ULCOUNTValueExtended_present; + LIBLTE_S1AP_COUNTVALUEEXTENDED_STRUCT DLCOUNTValueExtended; + bool DLCOUNTValueExtended_present; + LIBLTE_S1AP_RECEIVESTATUSOFULPDCPSDUSEXTENDED_STRUCT ReceiveStatusOfULPDCPSDUsExtended; + bool ReceiveStatusOfULPDCPSDUsExtended_present; +}LIBLTE_S1AP_MESSAGE_BEARERS_SUBJECTTOSTATUSTRANSFER_ITEMEXT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_bearers_subjecttostatustransfer_itemext( + LIBLTE_S1AP_MESSAGE_BEARERS_SUBJECTTOSTATUSTRANSFER_ITEMEXT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_bearers_subjecttostatustransfer_itemext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_BEARERS_SUBJECTTOSTATUSTRANSFER_ITEMEXT_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message E_RABItem STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_E_RABITEM_STRUCT E_RABItem; +}LIBLTE_S1AP_MESSAGE_E_RABITEM_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabitem( + LIBLTE_S1AP_MESSAGE_E_RABITEM_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabitem( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_E_RABITEM_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message MDT_Configuration_Ext STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_MDTPLMNLIST_STRUCT SignallingBasedMDTPLMNList; + bool SignallingBasedMDTPLMNList_present; +}LIBLTE_S1AP_MESSAGE_MDT_CONFIGURATION_EXT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_mdt_configuration_ext( + LIBLTE_S1AP_MESSAGE_MDT_CONFIGURATION_EXT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_mdt_configuration_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_MDT_CONFIGURATION_EXT_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message X2TNLConfigurationInfo_Ext STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_ENBX2EXTTLAS_STRUCT eNBX2ExtendedTransportLayerAddresses; + bool eNBX2ExtendedTransportLayerAddresses_present; +}LIBLTE_S1AP_MESSAGE_X2TNLCONFIGURATIONINFO_EXT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_x2tnlconfigurationinfo_ext( + LIBLTE_S1AP_MESSAGE_X2TNLCONFIGURATIONINFO_EXT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_x2tnlconfigurationinfo_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_X2TNLCONFIGURATIONINFO_EXT_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message Bearers_SubjectToStatusTransfer_Item STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_BEARERS_SUBJECTTOSTATUSTRANSFER_ITEM_STRUCT Bearers_SubjectToStatusTransfer_Item; +}LIBLTE_S1AP_MESSAGE_BEARERS_SUBJECTTOSTATUSTRANSFER_ITEM_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_bearers_subjecttostatustransfer_item( + LIBLTE_S1AP_MESSAGE_BEARERS_SUBJECTTOSTATUSTRANSFER_ITEM_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_bearers_subjecttostatustransfer_item( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_BEARERS_SUBJECTTOSTATUSTRANSFER_ITEM_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message ImmediateMDT_Ext STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_M3CONFIGURATION_STRUCT M3Configuration; + bool M3Configuration_present; + LIBLTE_S1AP_M4CONFIGURATION_STRUCT M4Configuration; + bool M4Configuration_present; + LIBLTE_S1AP_M5CONFIGURATION_STRUCT M5Configuration; + bool M5Configuration_present; + LIBLTE_S1AP_MDT_LOCATION_INFO_STRUCT MDT_Location_Info; + bool MDT_Location_Info_present; +}LIBLTE_S1AP_MESSAGE_IMMEDIATEMDT_EXT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_immediatemdt_ext( + LIBLTE_S1AP_MESSAGE_IMMEDIATEMDT_EXT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_immediatemdt_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_IMMEDIATEMDT_EXT_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message SONConfigurationTransfer_Ext STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_X2TNLCONFIGURATIONINFO_STRUCT x2TNLConfigurationInfo; + bool x2TNLConfigurationInfo_present; +}LIBLTE_S1AP_MESSAGE_SONCONFIGURATIONTRANSFER_EXT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_sonconfigurationtransfer_ext( + LIBLTE_S1AP_MESSAGE_SONCONFIGURATIONTRANSFER_EXT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_sonconfigurationtransfer_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_SONCONFIGURATIONTRANSFER_EXT_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message TraceActivation_Ext STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_MDT_CONFIGURATION_STRUCT MDTConfiguration; + bool MDTConfiguration_present; +}LIBLTE_S1AP_MESSAGE_TRACEACTIVATION_EXT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_traceactivation_ext( + LIBLTE_S1AP_MESSAGE_TRACEACTIVATION_EXT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_traceactivation_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_TRACEACTIVATION_EXT_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message HandoverRequired STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_MME_UE_S1AP_ID_STRUCT MME_UE_S1AP_ID; + LIBLTE_S1AP_ENB_UE_S1AP_ID_STRUCT eNB_UE_S1AP_ID; + LIBLTE_S1AP_HANDOVERTYPE_ENUM_EXT HandoverType; + LIBLTE_S1AP_CAUSE_STRUCT Cause; + LIBLTE_S1AP_TARGETID_STRUCT TargetID; + LIBLTE_S1AP_DIRECT_FORWARDING_PATH_AVAILABILITY_ENUM_EXT Direct_Forwarding_Path_Availability; + bool Direct_Forwarding_Path_Availability_present; + LIBLTE_S1AP_SRVCCHOINDICATION_ENUM_EXT SRVCCHOIndication; + bool SRVCCHOIndication_present; + LIBLTE_S1AP_SOURCE_TOTARGET_TRANSPARENTCONTAINER_STRUCT Source_ToTarget_TransparentContainer; + LIBLTE_S1AP_SOURCE_TOTARGET_TRANSPARENTCONTAINER_STRUCT Source_ToTarget_TransparentContainer_Secondary; + bool Source_ToTarget_TransparentContainer_Secondary_present; + LIBLTE_S1AP_MSCLASSMARK2_STRUCT MSClassmark2; + bool MSClassmark2_present; + LIBLTE_S1AP_MSCLASSMARK3_STRUCT MSClassmark3; + bool MSClassmark3_present; + LIBLTE_S1AP_CSG_ID_STRUCT CSG_Id; + bool CSG_Id_present; + LIBLTE_S1AP_CELLACCESSMODE_ENUM_EXT CellAccessMode; + bool CellAccessMode_present; + LIBLTE_S1AP_PS_SERVICENOTAVAILABLE_ENUM_EXT PS_ServiceNotAvailable; + bool PS_ServiceNotAvailable_present; +}LIBLTE_S1AP_MESSAGE_HANDOVERREQUIRED_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_handoverrequired( + LIBLTE_S1AP_MESSAGE_HANDOVERREQUIRED_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_handoverrequired( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_HANDOVERREQUIRED_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message E_RABDataForwardingItem_Ext STRUCT +********************************************************************************/ +typedef struct{ + bool ext; +}LIBLTE_S1AP_MESSAGE_E_RABDATAFORWARDINGITEM_EXT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabdataforwardingitem_ext( + LIBLTE_S1AP_MESSAGE_E_RABDATAFORWARDINGITEM_EXT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabdataforwardingitem_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_E_RABDATAFORWARDINGITEM_EXT_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message HandoverPreparationFailure STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_MME_UE_S1AP_ID_STRUCT MME_UE_S1AP_ID; + LIBLTE_S1AP_ENB_UE_S1AP_ID_STRUCT eNB_UE_S1AP_ID; + LIBLTE_S1AP_CAUSE_STRUCT Cause; + LIBLTE_S1AP_CRITICALITYDIAGNOSTICS_STRUCT CriticalityDiagnostics; + bool CriticalityDiagnostics_present; +}LIBLTE_S1AP_MESSAGE_HANDOVERPREPARATIONFAILURE_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_handoverpreparationfailure( + LIBLTE_S1AP_MESSAGE_HANDOVERPREPARATIONFAILURE_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_handoverpreparationfailure( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_HANDOVERPREPARATIONFAILURE_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message E_RABToBeSetupItemHOReq_Ext STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_DATA_FORWARDING_NOT_POSSIBLE_ENUM_EXT Data_Forwarding_Not_Possible; + bool Data_Forwarding_Not_Possible_present; +}LIBLTE_S1AP_MESSAGE_E_RABTOBESETUPITEMHOREQ_EXT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabtobesetupitemhoreq_ext( + LIBLTE_S1AP_MESSAGE_E_RABTOBESETUPITEMHOREQ_EXT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabtobesetupitemhoreq_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_E_RABTOBESETUPITEMHOREQ_EXT_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message E_RABAdmittedItem_Ext STRUCT +********************************************************************************/ +typedef struct{ + bool ext; +}LIBLTE_S1AP_MESSAGE_E_RABADMITTEDITEM_EXT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabadmitteditem_ext( + LIBLTE_S1AP_MESSAGE_E_RABADMITTEDITEM_EXT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabadmitteditem_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_E_RABADMITTEDITEM_EXT_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message E_RABFailedToSetupItemHOReqAckExt STRUCT +********************************************************************************/ +typedef struct{ + bool ext; +}LIBLTE_S1AP_MESSAGE_E_RABFAILEDTOSETUPITEMHOREQACKEXT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabfailedtosetupitemhoreqackext( + LIBLTE_S1AP_MESSAGE_E_RABFAILEDTOSETUPITEMHOREQACKEXT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabfailedtosetupitemhoreqackext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_E_RABFAILEDTOSETUPITEMHOREQACKEXT_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message HandoverFailure STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_MME_UE_S1AP_ID_STRUCT MME_UE_S1AP_ID; + LIBLTE_S1AP_CAUSE_STRUCT Cause; + LIBLTE_S1AP_CRITICALITYDIAGNOSTICS_STRUCT CriticalityDiagnostics; + bool CriticalityDiagnostics_present; +}LIBLTE_S1AP_MESSAGE_HANDOVERFAILURE_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_handoverfailure( + LIBLTE_S1AP_MESSAGE_HANDOVERFAILURE_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_handoverfailure( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_HANDOVERFAILURE_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message HandoverNotify STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_MME_UE_S1AP_ID_STRUCT MME_UE_S1AP_ID; + LIBLTE_S1AP_ENB_UE_S1AP_ID_STRUCT eNB_UE_S1AP_ID; + LIBLTE_S1AP_EUTRAN_CGI_STRUCT EUTRAN_CGI; + LIBLTE_S1AP_TAI_STRUCT TAI; + LIBLTE_S1AP_TUNNELINFORMATION_STRUCT Tunnel_Information_for_BBF; + bool Tunnel_Information_for_BBF_present; + LIBLTE_S1AP_LHN_ID_STRUCT LHN_ID; + bool LHN_ID_present; +}LIBLTE_S1AP_MESSAGE_HANDOVERNOTIFY_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_handovernotify( + LIBLTE_S1AP_MESSAGE_HANDOVERNOTIFY_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_handovernotify( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_HANDOVERNOTIFY_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message E_RABToBeSwitchedDLItem_Ext STRUCT +********************************************************************************/ +typedef struct{ + bool ext; +}LIBLTE_S1AP_MESSAGE_E_RABTOBESWITCHEDDLITEM_EXT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabtobeswitcheddlitem_ext( + LIBLTE_S1AP_MESSAGE_E_RABTOBESWITCHEDDLITEM_EXT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabtobeswitcheddlitem_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_E_RABTOBESWITCHEDDLITEM_EXT_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message E_RABToBeSwitchedULItem_Ext STRUCT +********************************************************************************/ +typedef struct{ + bool ext; +}LIBLTE_S1AP_MESSAGE_E_RABTOBESWITCHEDULITEM_EXT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabtobeswitchedulitem_ext( + LIBLTE_S1AP_MESSAGE_E_RABTOBESWITCHEDULITEM_EXT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabtobeswitchedulitem_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_E_RABTOBESWITCHEDULITEM_EXT_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message PathSwitchRequestFailure STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_MME_UE_S1AP_ID_STRUCT MME_UE_S1AP_ID; + LIBLTE_S1AP_ENB_UE_S1AP_ID_STRUCT eNB_UE_S1AP_ID; + LIBLTE_S1AP_CAUSE_STRUCT Cause; + LIBLTE_S1AP_CRITICALITYDIAGNOSTICS_STRUCT CriticalityDiagnostics; + bool CriticalityDiagnostics_present; +}LIBLTE_S1AP_MESSAGE_PATHSWITCHREQUESTFAILURE_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_pathswitchrequestfailure( + LIBLTE_S1AP_MESSAGE_PATHSWITCHREQUESTFAILURE_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_pathswitchrequestfailure( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_PATHSWITCHREQUESTFAILURE_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message HandoverCancel STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_MME_UE_S1AP_ID_STRUCT MME_UE_S1AP_ID; + LIBLTE_S1AP_ENB_UE_S1AP_ID_STRUCT eNB_UE_S1AP_ID; + LIBLTE_S1AP_CAUSE_STRUCT Cause; +}LIBLTE_S1AP_MESSAGE_HANDOVERCANCEL_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_handovercancel( + LIBLTE_S1AP_MESSAGE_HANDOVERCANCEL_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_handovercancel( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_HANDOVERCANCEL_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message HandoverCancelAcknowledge STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_MME_UE_S1AP_ID_STRUCT MME_UE_S1AP_ID; + LIBLTE_S1AP_ENB_UE_S1AP_ID_STRUCT eNB_UE_S1AP_ID; + LIBLTE_S1AP_CRITICALITYDIAGNOSTICS_STRUCT CriticalityDiagnostics; + bool CriticalityDiagnostics_present; +}LIBLTE_S1AP_MESSAGE_HANDOVERCANCELACKNOWLEDGE_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_handovercancelacknowledge( + LIBLTE_S1AP_MESSAGE_HANDOVERCANCELACKNOWLEDGE_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_handovercancelacknowledge( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_HANDOVERCANCELACKNOWLEDGE_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message E_RABToBeSetupItemBearerSUReqExt STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_CORRELATION_ID_STRUCT Correlation_ID; + bool Correlation_ID_present; + LIBLTE_S1AP_CORRELATION_ID_STRUCT SIPTO_Correlation_ID; + bool SIPTO_Correlation_ID_present; +}LIBLTE_S1AP_MESSAGE_E_RABTOBESETUPITEMBEARERSUREQEXT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabtobesetupitembearersureqext( + LIBLTE_S1AP_MESSAGE_E_RABTOBESETUPITEMBEARERSUREQEXT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabtobesetupitembearersureqext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_E_RABTOBESETUPITEMBEARERSUREQEXT_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message E_RABSetupItemBearerSUResExt STRUCT +********************************************************************************/ +typedef struct{ + bool ext; +}LIBLTE_S1AP_MESSAGE_E_RABSETUPITEMBEARERSURESEXT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabsetupitembearersuresext( + LIBLTE_S1AP_MESSAGE_E_RABSETUPITEMBEARERSURESEXT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabsetupitembearersuresext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_E_RABSETUPITEMBEARERSURESEXT_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message E_RABToBeModifyItemBearerModReqExt STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_TRANSPORTINFORMATION_STRUCT TransportInformation; + bool TransportInformation_present; +}LIBLTE_S1AP_MESSAGE_E_RABTOBEMODIFYITEMBEARERMODREQEXT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabtobemodifyitembearermodreqext( + LIBLTE_S1AP_MESSAGE_E_RABTOBEMODIFYITEMBEARERMODREQEXT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabtobemodifyitembearermodreqext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_E_RABTOBEMODIFYITEMBEARERMODREQEXT_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message E_RABModifyItemBearerModResExt STRUCT +********************************************************************************/ +typedef struct{ + bool ext; +}LIBLTE_S1AP_MESSAGE_E_RABMODIFYITEMBEARERMODRESEXT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabmodifyitembearermodresext( + LIBLTE_S1AP_MESSAGE_E_RABMODIFYITEMBEARERMODRESEXT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabmodifyitembearermodresext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_E_RABMODIFYITEMBEARERMODRESEXT_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message E_RABReleaseCommand STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_MME_UE_S1AP_ID_STRUCT MME_UE_S1AP_ID; + LIBLTE_S1AP_ENB_UE_S1AP_ID_STRUCT eNB_UE_S1AP_ID; + LIBLTE_S1AP_UEAGGREGATEMAXIMUMBITRATE_STRUCT uEaggregateMaximumBitrate; + bool uEaggregateMaximumBitrate_present; + LIBLTE_S1AP_E_RABLIST_STRUCT E_RABToBeReleasedList; + LIBLTE_S1AP_NAS_PDU_STRUCT NAS_PDU; + bool NAS_PDU_present; +}LIBLTE_S1AP_MESSAGE_E_RABRELEASECOMMAND_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabreleasecommand( + LIBLTE_S1AP_MESSAGE_E_RABRELEASECOMMAND_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabreleasecommand( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_E_RABRELEASECOMMAND_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message E_RABReleaseItemBearerRelCompExt STRUCT +********************************************************************************/ +typedef struct{ + bool ext; +}LIBLTE_S1AP_MESSAGE_E_RABRELEASEITEMBEARERRELCOMPEXT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabreleaseitembearerrelcompext( + LIBLTE_S1AP_MESSAGE_E_RABRELEASEITEMBEARERRELCOMPEXT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabreleaseitembearerrelcompext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_E_RABRELEASEITEMBEARERRELCOMPEXT_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message E_RABReleaseIndication STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_MME_UE_S1AP_ID_STRUCT MME_UE_S1AP_ID; + LIBLTE_S1AP_ENB_UE_S1AP_ID_STRUCT eNB_UE_S1AP_ID; + LIBLTE_S1AP_E_RABLIST_STRUCT E_RABReleasedList; + LIBLTE_S1AP_USERLOCATIONINFORMATION_STRUCT UserLocationInformation; + bool UserLocationInformation_present; +}LIBLTE_S1AP_MESSAGE_E_RABRELEASEINDICATION_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabreleaseindication( + LIBLTE_S1AP_MESSAGE_E_RABRELEASEINDICATION_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabreleaseindication( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_E_RABRELEASEINDICATION_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message E_RABToBeSetupItemCtxtSUReqExt STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_CORRELATION_ID_STRUCT Correlation_ID; + bool Correlation_ID_present; + LIBLTE_S1AP_CORRELATION_ID_STRUCT SIPTO_Correlation_ID; + bool SIPTO_Correlation_ID_present; +}LIBLTE_S1AP_MESSAGE_E_RABTOBESETUPITEMCTXTSUREQEXT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabtobesetupitemctxtsureqext( + LIBLTE_S1AP_MESSAGE_E_RABTOBESETUPITEMCTXTSUREQEXT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabtobesetupitemctxtsureqext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_E_RABTOBESETUPITEMCTXTSUREQEXT_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message E_RABSetupItemCtxtSUResExt STRUCT +********************************************************************************/ +typedef struct{ + bool ext; +}LIBLTE_S1AP_MESSAGE_E_RABSETUPITEMCTXTSURESEXT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabsetupitemctxtsuresext( + LIBLTE_S1AP_MESSAGE_E_RABSETUPITEMCTXTSURESEXT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabsetupitemctxtsuresext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_E_RABSETUPITEMCTXTSURESEXT_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message InitialContextSetupFailure STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_MME_UE_S1AP_ID_STRUCT MME_UE_S1AP_ID; + LIBLTE_S1AP_ENB_UE_S1AP_ID_STRUCT eNB_UE_S1AP_ID; + LIBLTE_S1AP_CAUSE_STRUCT Cause; + LIBLTE_S1AP_CRITICALITYDIAGNOSTICS_STRUCT CriticalityDiagnostics; + bool CriticalityDiagnostics_present; +}LIBLTE_S1AP_MESSAGE_INITIALCONTEXTSETUPFAILURE_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_initialcontextsetupfailure( + LIBLTE_S1AP_MESSAGE_INITIALCONTEXTSETUPFAILURE_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_initialcontextsetupfailure( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_INITIALCONTEXTSETUPFAILURE_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message TAIItemExt STRUCT +********************************************************************************/ +typedef struct{ + bool ext; +}LIBLTE_S1AP_MESSAGE_TAIITEMEXT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_taiitemext( + LIBLTE_S1AP_MESSAGE_TAIITEMEXT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_taiitemext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_TAIITEMEXT_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message UEContextReleaseRequest STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_MME_UE_S1AP_ID_STRUCT MME_UE_S1AP_ID; + LIBLTE_S1AP_ENB_UE_S1AP_ID_STRUCT eNB_UE_S1AP_ID; + LIBLTE_S1AP_CAUSE_STRUCT Cause; + LIBLTE_S1AP_GWCONTEXTRELEASEINDICATION_ENUM_EXT GWContextReleaseIndication; + bool GWContextReleaseIndication_present; +}LIBLTE_S1AP_MESSAGE_UECONTEXTRELEASEREQUEST_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_uecontextreleaserequest( + LIBLTE_S1AP_MESSAGE_UECONTEXTRELEASEREQUEST_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_uecontextreleaserequest( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_UECONTEXTRELEASEREQUEST_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message UEContextReleaseCommand STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_UE_S1AP_IDS_STRUCT UE_S1AP_IDs; + LIBLTE_S1AP_CAUSE_STRUCT Cause; +}LIBLTE_S1AP_MESSAGE_UECONTEXTRELEASECOMMAND_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_uecontextreleasecommand( + LIBLTE_S1AP_MESSAGE_UECONTEXTRELEASECOMMAND_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_uecontextreleasecommand( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_UECONTEXTRELEASECOMMAND_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message UEContextReleaseComplete STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_MME_UE_S1AP_ID_STRUCT MME_UE_S1AP_ID; + LIBLTE_S1AP_ENB_UE_S1AP_ID_STRUCT eNB_UE_S1AP_ID; + LIBLTE_S1AP_CRITICALITYDIAGNOSTICS_STRUCT CriticalityDiagnostics; + bool CriticalityDiagnostics_present; + LIBLTE_S1AP_USERLOCATIONINFORMATION_STRUCT UserLocationInformation; + bool UserLocationInformation_present; +}LIBLTE_S1AP_MESSAGE_UECONTEXTRELEASECOMPLETE_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_uecontextreleasecomplete( + LIBLTE_S1AP_MESSAGE_UECONTEXTRELEASECOMPLETE_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_uecontextreleasecomplete( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_UECONTEXTRELEASECOMPLETE_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message UEContextModificationRequest STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_MME_UE_S1AP_ID_STRUCT MME_UE_S1AP_ID; + LIBLTE_S1AP_ENB_UE_S1AP_ID_STRUCT eNB_UE_S1AP_ID; + LIBLTE_S1AP_SECURITYKEY_STRUCT SecurityKey; + bool SecurityKey_present; + LIBLTE_S1AP_SUBSCRIBERPROFILEIDFORRFP_STRUCT SubscriberProfileIDforRFP; + bool SubscriberProfileIDforRFP_present; + LIBLTE_S1AP_UEAGGREGATEMAXIMUMBITRATE_STRUCT uEaggregateMaximumBitrate; + bool uEaggregateMaximumBitrate_present; + LIBLTE_S1AP_CSFALLBACKINDICATOR_ENUM_EXT CSFallbackIndicator; + bool CSFallbackIndicator_present; + LIBLTE_S1AP_UESECURITYCAPABILITIES_STRUCT UESecurityCapabilities; + bool UESecurityCapabilities_present; + LIBLTE_S1AP_CSGMEMBERSHIPSTATUS_ENUM CSGMembershipStatus; + bool CSGMembershipStatus_present; + LIBLTE_S1AP_LAI_STRUCT RegisteredLAI; + bool RegisteredLAI_present; + LIBLTE_S1AP_ADDITIONALCSFALLBACKINDICATOR_ENUM_EXT AdditionalCSFallbackIndicator; + bool AdditionalCSFallbackIndicator_present; +}LIBLTE_S1AP_MESSAGE_UECONTEXTMODIFICATIONREQUEST_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_uecontextmodificationrequest( + LIBLTE_S1AP_MESSAGE_UECONTEXTMODIFICATIONREQUEST_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_uecontextmodificationrequest( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_UECONTEXTMODIFICATIONREQUEST_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message UEContextModificationResponse STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_MME_UE_S1AP_ID_STRUCT MME_UE_S1AP_ID; + LIBLTE_S1AP_ENB_UE_S1AP_ID_STRUCT eNB_UE_S1AP_ID; + LIBLTE_S1AP_CRITICALITYDIAGNOSTICS_STRUCT CriticalityDiagnostics; + bool CriticalityDiagnostics_present; +}LIBLTE_S1AP_MESSAGE_UECONTEXTMODIFICATIONRESPONSE_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_uecontextmodificationresponse( + LIBLTE_S1AP_MESSAGE_UECONTEXTMODIFICATIONRESPONSE_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_uecontextmodificationresponse( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_UECONTEXTMODIFICATIONRESPONSE_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message UEContextModificationFailure STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_MME_UE_S1AP_ID_STRUCT MME_UE_S1AP_ID; + LIBLTE_S1AP_ENB_UE_S1AP_ID_STRUCT eNB_UE_S1AP_ID; + LIBLTE_S1AP_CAUSE_STRUCT Cause; + LIBLTE_S1AP_CRITICALITYDIAGNOSTICS_STRUCT CriticalityDiagnostics; + bool CriticalityDiagnostics_present; +}LIBLTE_S1AP_MESSAGE_UECONTEXTMODIFICATIONFAILURE_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_uecontextmodificationfailure( + LIBLTE_S1AP_MESSAGE_UECONTEXTMODIFICATIONFAILURE_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_uecontextmodificationfailure( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_UECONTEXTMODIFICATIONFAILURE_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message UERadioCapabilityMatchRequest STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_MME_UE_S1AP_ID_STRUCT MME_UE_S1AP_ID; + LIBLTE_S1AP_ENB_UE_S1AP_ID_STRUCT eNB_UE_S1AP_ID; + LIBLTE_S1AP_UERADIOCAPABILITY_STRUCT UERadioCapability; + bool UERadioCapability_present; +}LIBLTE_S1AP_MESSAGE_UERADIOCAPABILITYMATCHREQUEST_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_ueradiocapabilitymatchrequest( + LIBLTE_S1AP_MESSAGE_UERADIOCAPABILITYMATCHREQUEST_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_ueradiocapabilitymatchrequest( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_UERADIOCAPABILITYMATCHREQUEST_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message UERadioCapabilityMatchResponse STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_MME_UE_S1AP_ID_STRUCT MME_UE_S1AP_ID; + LIBLTE_S1AP_ENB_UE_S1AP_ID_STRUCT eNB_UE_S1AP_ID; + LIBLTE_S1AP_VOICESUPPORTMATCHINDICATOR_ENUM_EXT VoiceSupportMatchIndicator; + LIBLTE_S1AP_CRITICALITYDIAGNOSTICS_STRUCT CriticalityDiagnostics; + bool CriticalityDiagnostics_present; +}LIBLTE_S1AP_MESSAGE_UERADIOCAPABILITYMATCHRESPONSE_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_ueradiocapabilitymatchresponse( + LIBLTE_S1AP_MESSAGE_UERADIOCAPABILITYMATCHRESPONSE_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_ueradiocapabilitymatchresponse( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_UERADIOCAPABILITYMATCHRESPONSE_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message DownlinkNASTransport STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_MME_UE_S1AP_ID_STRUCT MME_UE_S1AP_ID; + LIBLTE_S1AP_ENB_UE_S1AP_ID_STRUCT eNB_UE_S1AP_ID; + LIBLTE_S1AP_NAS_PDU_STRUCT NAS_PDU; + LIBLTE_S1AP_HANDOVERRESTRICTIONLIST_STRUCT HandoverRestrictionList; + bool HandoverRestrictionList_present; + LIBLTE_S1AP_SUBSCRIBERPROFILEIDFORRFP_STRUCT SubscriberProfileIDforRFP; + bool SubscriberProfileIDforRFP_present; +}LIBLTE_S1AP_MESSAGE_DOWNLINKNASTRANSPORT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_downlinknastransport( + LIBLTE_S1AP_MESSAGE_DOWNLINKNASTRANSPORT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_downlinknastransport( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_DOWNLINKNASTRANSPORT_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message InitialUEMessage STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_ENB_UE_S1AP_ID_STRUCT eNB_UE_S1AP_ID; + LIBLTE_S1AP_NAS_PDU_STRUCT NAS_PDU; + LIBLTE_S1AP_TAI_STRUCT TAI; + LIBLTE_S1AP_EUTRAN_CGI_STRUCT EUTRAN_CGI; + LIBLTE_S1AP_RRC_ESTABLISHMENT_CAUSE_ENUM_EXT RRC_Establishment_Cause; + LIBLTE_S1AP_S_TMSI_STRUCT S_TMSI; + bool S_TMSI_present; + LIBLTE_S1AP_CSG_ID_STRUCT CSG_Id; + bool CSG_Id_present; + LIBLTE_S1AP_GUMMEI_STRUCT GUMMEI_ID; + bool GUMMEI_ID_present; + LIBLTE_S1AP_CELLACCESSMODE_ENUM_EXT CellAccessMode; + bool CellAccessMode_present; + LIBLTE_S1AP_TRANSPORTLAYERADDRESS_STRUCT GW_TransportLayerAddress; + bool GW_TransportLayerAddress_present; + LIBLTE_S1AP_RELAYNODE_INDICATOR_ENUM_EXT RelayNode_Indicator; + bool RelayNode_Indicator_present; + LIBLTE_S1AP_GUMMEITYPE_ENUM_EXT GUMMEIType; + bool GUMMEIType_present; + LIBLTE_S1AP_TUNNELINFORMATION_STRUCT Tunnel_Information_for_BBF; + bool Tunnel_Information_for_BBF_present; + LIBLTE_S1AP_TRANSPORTLAYERADDRESS_STRUCT SIPTO_L_GW_TransportLayerAddress; + bool SIPTO_L_GW_TransportLayerAddress_present; + LIBLTE_S1AP_LHN_ID_STRUCT LHN_ID; + bool LHN_ID_present; +}LIBLTE_S1AP_MESSAGE_INITIALUEMESSAGE_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_initialuemessage( + LIBLTE_S1AP_MESSAGE_INITIALUEMESSAGE_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_initialuemessage( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_INITIALUEMESSAGE_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message UplinkNASTransport STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_MME_UE_S1AP_ID_STRUCT MME_UE_S1AP_ID; + LIBLTE_S1AP_ENB_UE_S1AP_ID_STRUCT eNB_UE_S1AP_ID; + LIBLTE_S1AP_NAS_PDU_STRUCT NAS_PDU; + LIBLTE_S1AP_EUTRAN_CGI_STRUCT EUTRAN_CGI; + LIBLTE_S1AP_TAI_STRUCT TAI; + LIBLTE_S1AP_TRANSPORTLAYERADDRESS_STRUCT GW_TransportLayerAddress; + bool GW_TransportLayerAddress_present; + LIBLTE_S1AP_TRANSPORTLAYERADDRESS_STRUCT SIPTO_L_GW_TransportLayerAddress; + bool SIPTO_L_GW_TransportLayerAddress_present; + LIBLTE_S1AP_LHN_ID_STRUCT LHN_ID; + bool LHN_ID_present; +}LIBLTE_S1AP_MESSAGE_UPLINKNASTRANSPORT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_uplinknastransport( + LIBLTE_S1AP_MESSAGE_UPLINKNASTRANSPORT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_uplinknastransport( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_UPLINKNASTRANSPORT_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message NASNonDeliveryIndication STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_MME_UE_S1AP_ID_STRUCT MME_UE_S1AP_ID; + LIBLTE_S1AP_ENB_UE_S1AP_ID_STRUCT eNB_UE_S1AP_ID; + LIBLTE_S1AP_NAS_PDU_STRUCT NAS_PDU; + LIBLTE_S1AP_CAUSE_STRUCT Cause; +}LIBLTE_S1AP_MESSAGE_NASNONDELIVERYINDICATION_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_nasnondeliveryindication( + LIBLTE_S1AP_MESSAGE_NASNONDELIVERYINDICATION_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_nasnondeliveryindication( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_NASNONDELIVERYINDICATION_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message UE_associatedLogicalS1_ConnectionItem STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_UE_ASSOCIATEDLOGICALS1_CONNECTIONITEM_STRUCT UE_associatedLogicalS1_ConnectionItem; +}LIBLTE_S1AP_MESSAGE_UE_ASSOCIATEDLOGICALS1_CONNECTIONITEM_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_ue_associatedlogicals1_connectionitem( + LIBLTE_S1AP_MESSAGE_UE_ASSOCIATEDLOGICALS1_CONNECTIONITEM_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_ue_associatedlogicals1_connectionitem( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_UE_ASSOCIATEDLOGICALS1_CONNECTIONITEM_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message UE_associatedLogicalS1_ConnectionItemRes STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_UE_ASSOCIATEDLOGICALS1_CONNECTIONITEM_STRUCT UE_associatedLogicalS1_ConnectionItem; +}LIBLTE_S1AP_MESSAGE_UE_ASSOCIATEDLOGICALS1_CONNECTIONITEMRES_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_ue_associatedlogicals1_connectionitemres( + LIBLTE_S1AP_MESSAGE_UE_ASSOCIATEDLOGICALS1_CONNECTIONITEMRES_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_ue_associatedlogicals1_connectionitemres( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_UE_ASSOCIATEDLOGICALS1_CONNECTIONITEMRES_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message ErrorIndication STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_MME_UE_S1AP_ID_STRUCT MME_UE_S1AP_ID; + bool MME_UE_S1AP_ID_present; + LIBLTE_S1AP_ENB_UE_S1AP_ID_STRUCT eNB_UE_S1AP_ID; + bool eNB_UE_S1AP_ID_present; + LIBLTE_S1AP_CAUSE_STRUCT Cause; + bool Cause_present; + LIBLTE_S1AP_CRITICALITYDIAGNOSTICS_STRUCT CriticalityDiagnostics; + bool CriticalityDiagnostics_present; +}LIBLTE_S1AP_MESSAGE_ERRORINDICATION_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_errorindication( + LIBLTE_S1AP_MESSAGE_ERRORINDICATION_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_errorindication( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_ERRORINDICATION_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message S1SetupRequest STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_GLOBAL_ENB_ID_STRUCT Global_ENB_ID; + LIBLTE_S1AP_ENBNAME_STRUCT eNBname; + bool eNBname_present; + LIBLTE_S1AP_SUPPORTEDTAS_STRUCT SupportedTAs; + LIBLTE_S1AP_PAGINGDRX_ENUM_EXT DefaultPagingDRX; + LIBLTE_S1AP_CSG_IDLIST_STRUCT CSG_IdList; + bool CSG_IdList_present; +}LIBLTE_S1AP_MESSAGE_S1SETUPREQUEST_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_s1setuprequest( + LIBLTE_S1AP_MESSAGE_S1SETUPREQUEST_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_s1setuprequest( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_S1SETUPREQUEST_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message S1SetupResponse STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_MMENAME_STRUCT MMEname; + bool MMEname_present; + LIBLTE_S1AP_SERVEDGUMMEIS_STRUCT ServedGUMMEIs; + LIBLTE_S1AP_RELATIVEMMECAPACITY_STRUCT RelativeMMECapacity; + LIBLTE_S1AP_MMERELAYSUPPORTINDICATOR_ENUM_EXT MMERelaySupportIndicator; + bool MMERelaySupportIndicator_present; + LIBLTE_S1AP_CRITICALITYDIAGNOSTICS_STRUCT CriticalityDiagnostics; + bool CriticalityDiagnostics_present; +}LIBLTE_S1AP_MESSAGE_S1SETUPRESPONSE_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_s1setupresponse( + LIBLTE_S1AP_MESSAGE_S1SETUPRESPONSE_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_s1setupresponse( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_S1SETUPRESPONSE_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message S1SetupFailure STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_CAUSE_STRUCT Cause; + LIBLTE_S1AP_TIMETOWAIT_ENUM_EXT TimeToWait; + bool TimeToWait_present; + LIBLTE_S1AP_CRITICALITYDIAGNOSTICS_STRUCT CriticalityDiagnostics; + bool CriticalityDiagnostics_present; +}LIBLTE_S1AP_MESSAGE_S1SETUPFAILURE_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_s1setupfailure( + LIBLTE_S1AP_MESSAGE_S1SETUPFAILURE_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_s1setupfailure( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_S1SETUPFAILURE_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message ENBConfigurationUpdate STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_ENBNAME_STRUCT eNBname; + bool eNBname_present; + LIBLTE_S1AP_SUPPORTEDTAS_STRUCT SupportedTAs; + bool SupportedTAs_present; + LIBLTE_S1AP_CSG_IDLIST_STRUCT CSG_IdList; + bool CSG_IdList_present; + LIBLTE_S1AP_PAGINGDRX_ENUM_EXT DefaultPagingDRX; + bool DefaultPagingDRX_present; +}LIBLTE_S1AP_MESSAGE_ENBCONFIGURATIONUPDATE_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_enbconfigurationupdate( + LIBLTE_S1AP_MESSAGE_ENBCONFIGURATIONUPDATE_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_enbconfigurationupdate( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_ENBCONFIGURATIONUPDATE_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message ENBConfigurationUpdateAcknowledge STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_CRITICALITYDIAGNOSTICS_STRUCT CriticalityDiagnostics; + bool CriticalityDiagnostics_present; +}LIBLTE_S1AP_MESSAGE_ENBCONFIGURATIONUPDATEACKNOWLEDGE_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_enbconfigurationupdateacknowledge( + LIBLTE_S1AP_MESSAGE_ENBCONFIGURATIONUPDATEACKNOWLEDGE_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_enbconfigurationupdateacknowledge( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_ENBCONFIGURATIONUPDATEACKNOWLEDGE_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message ENBConfigurationUpdateFailure STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_CAUSE_STRUCT Cause; + LIBLTE_S1AP_TIMETOWAIT_ENUM_EXT TimeToWait; + bool TimeToWait_present; + LIBLTE_S1AP_CRITICALITYDIAGNOSTICS_STRUCT CriticalityDiagnostics; + bool CriticalityDiagnostics_present; +}LIBLTE_S1AP_MESSAGE_ENBCONFIGURATIONUPDATEFAILURE_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_enbconfigurationupdatefailure( + LIBLTE_S1AP_MESSAGE_ENBCONFIGURATIONUPDATEFAILURE_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_enbconfigurationupdatefailure( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_ENBCONFIGURATIONUPDATEFAILURE_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message MMEConfigurationUpdate STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_MMENAME_STRUCT MMEname; + bool MMEname_present; + LIBLTE_S1AP_SERVEDGUMMEIS_STRUCT ServedGUMMEIs; + bool ServedGUMMEIs_present; + LIBLTE_S1AP_RELATIVEMMECAPACITY_STRUCT RelativeMMECapacity; + bool RelativeMMECapacity_present; +}LIBLTE_S1AP_MESSAGE_MMECONFIGURATIONUPDATE_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_mmeconfigurationupdate( + LIBLTE_S1AP_MESSAGE_MMECONFIGURATIONUPDATE_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_mmeconfigurationupdate( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_MMECONFIGURATIONUPDATE_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message MMEConfigurationUpdateAcknowledge STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_CRITICALITYDIAGNOSTICS_STRUCT CriticalityDiagnostics; + bool CriticalityDiagnostics_present; +}LIBLTE_S1AP_MESSAGE_MMECONFIGURATIONUPDATEACKNOWLEDGE_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_mmeconfigurationupdateacknowledge( + LIBLTE_S1AP_MESSAGE_MMECONFIGURATIONUPDATEACKNOWLEDGE_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_mmeconfigurationupdateacknowledge( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_MMECONFIGURATIONUPDATEACKNOWLEDGE_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message MMEConfigurationUpdateFailure STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_CAUSE_STRUCT Cause; + LIBLTE_S1AP_TIMETOWAIT_ENUM_EXT TimeToWait; + bool TimeToWait_present; + LIBLTE_S1AP_CRITICALITYDIAGNOSTICS_STRUCT CriticalityDiagnostics; + bool CriticalityDiagnostics_present; +}LIBLTE_S1AP_MESSAGE_MMECONFIGURATIONUPDATEFAILURE_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_mmeconfigurationupdatefailure( + LIBLTE_S1AP_MESSAGE_MMECONFIGURATIONUPDATEFAILURE_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_mmeconfigurationupdatefailure( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_MMECONFIGURATIONUPDATEFAILURE_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message UplinkS1cdma2000tunneling STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_MME_UE_S1AP_ID_STRUCT MME_UE_S1AP_ID; + LIBLTE_S1AP_ENB_UE_S1AP_ID_STRUCT eNB_UE_S1AP_ID; + LIBLTE_S1AP_CDMA2000RATTYPE_ENUM_EXT cdma2000RATType; + LIBLTE_S1AP_CDMA2000SECTORID_STRUCT cdma2000SectorID; + LIBLTE_S1AP_CDMA2000HOREQUIREDINDICATION_ENUM_EXT cdma2000HORequiredIndication; + bool cdma2000HORequiredIndication_present; + LIBLTE_S1AP_CDMA2000ONEXSRVCCINFO_STRUCT cdma2000OneXSRVCCInfo; + bool cdma2000OneXSRVCCInfo_present; + LIBLTE_S1AP_CDMA2000ONEXRAND_STRUCT cdma2000OneXRAND; + bool cdma2000OneXRAND_present; + LIBLTE_S1AP_CDMA2000PDU_STRUCT cdma2000PDU; + LIBLTE_S1AP_EUTRANROUNDTRIPDELAYESTIMATIONINFO_STRUCT EUTRANRoundTripDelayEstimationInfo; + bool EUTRANRoundTripDelayEstimationInfo_present; +}LIBLTE_S1AP_MESSAGE_UPLINKS1CDMA2000TUNNELING_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_uplinks1cdma2000tunneling( + LIBLTE_S1AP_MESSAGE_UPLINKS1CDMA2000TUNNELING_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_uplinks1cdma2000tunneling( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_UPLINKS1CDMA2000TUNNELING_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message UECapabilityInfoIndication STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_MME_UE_S1AP_ID_STRUCT MME_UE_S1AP_ID; + LIBLTE_S1AP_ENB_UE_S1AP_ID_STRUCT eNB_UE_S1AP_ID; + LIBLTE_S1AP_UERADIOCAPABILITY_STRUCT UERadioCapability; +}LIBLTE_S1AP_MESSAGE_UECAPABILITYINFOINDICATION_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_uecapabilityinfoindication( + LIBLTE_S1AP_MESSAGE_UECAPABILITYINFOINDICATION_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_uecapabilityinfoindication( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_UECAPABILITYINFOINDICATION_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message ENBStatusTransfer STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_MME_UE_S1AP_ID_STRUCT MME_UE_S1AP_ID; + LIBLTE_S1AP_ENB_UE_S1AP_ID_STRUCT eNB_UE_S1AP_ID; + LIBLTE_S1AP_ENB_STATUSTRANSFER_TRANSPARENTCONTAINER_STRUCT eNB_StatusTransfer_TransparentContainer; +}LIBLTE_S1AP_MESSAGE_ENBSTATUSTRANSFER_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_enbstatustransfer( + LIBLTE_S1AP_MESSAGE_ENBSTATUSTRANSFER_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_enbstatustransfer( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_ENBSTATUSTRANSFER_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message MMEStatusTransfer STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_MME_UE_S1AP_ID_STRUCT MME_UE_S1AP_ID; + LIBLTE_S1AP_ENB_UE_S1AP_ID_STRUCT eNB_UE_S1AP_ID; + LIBLTE_S1AP_ENB_STATUSTRANSFER_TRANSPARENTCONTAINER_STRUCT eNB_StatusTransfer_TransparentContainer; +}LIBLTE_S1AP_MESSAGE_MMESTATUSTRANSFER_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_mmestatustransfer( + LIBLTE_S1AP_MESSAGE_MMESTATUSTRANSFER_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_mmestatustransfer( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_MMESTATUSTRANSFER_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message TraceStart STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_MME_UE_S1AP_ID_STRUCT MME_UE_S1AP_ID; + LIBLTE_S1AP_ENB_UE_S1AP_ID_STRUCT eNB_UE_S1AP_ID; + LIBLTE_S1AP_TRACEACTIVATION_STRUCT TraceActivation; +}LIBLTE_S1AP_MESSAGE_TRACESTART_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_tracestart( + LIBLTE_S1AP_MESSAGE_TRACESTART_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_tracestart( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_TRACESTART_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message TraceFailureIndication STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_MME_UE_S1AP_ID_STRUCT MME_UE_S1AP_ID; + LIBLTE_S1AP_ENB_UE_S1AP_ID_STRUCT eNB_UE_S1AP_ID; + LIBLTE_S1AP_E_UTRAN_TRACE_ID_STRUCT E_UTRAN_Trace_ID; + LIBLTE_S1AP_CAUSE_STRUCT Cause; +}LIBLTE_S1AP_MESSAGE_TRACEFAILUREINDICATION_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_tracefailureindication( + LIBLTE_S1AP_MESSAGE_TRACEFAILUREINDICATION_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_tracefailureindication( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_TRACEFAILUREINDICATION_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message DeactivateTrace STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_MME_UE_S1AP_ID_STRUCT MME_UE_S1AP_ID; + LIBLTE_S1AP_ENB_UE_S1AP_ID_STRUCT eNB_UE_S1AP_ID; + LIBLTE_S1AP_E_UTRAN_TRACE_ID_STRUCT E_UTRAN_Trace_ID; +}LIBLTE_S1AP_MESSAGE_DEACTIVATETRACE_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_deactivatetrace( + LIBLTE_S1AP_MESSAGE_DEACTIVATETRACE_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_deactivatetrace( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_DEACTIVATETRACE_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message CellTrafficTrace STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_MME_UE_S1AP_ID_STRUCT MME_UE_S1AP_ID; + LIBLTE_S1AP_ENB_UE_S1AP_ID_STRUCT eNB_UE_S1AP_ID; + LIBLTE_S1AP_E_UTRAN_TRACE_ID_STRUCT E_UTRAN_Trace_ID; + LIBLTE_S1AP_EUTRAN_CGI_STRUCT EUTRAN_CGI; + LIBLTE_S1AP_TRANSPORTLAYERADDRESS_STRUCT TraceCollectionEntityIPAddress; + LIBLTE_S1AP_PRIVACYINDICATOR_ENUM_EXT PrivacyIndicator; + bool PrivacyIndicator_present; +}LIBLTE_S1AP_MESSAGE_CELLTRAFFICTRACE_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_celltraffictrace( + LIBLTE_S1AP_MESSAGE_CELLTRAFFICTRACE_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_celltraffictrace( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_CELLTRAFFICTRACE_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message LocationReportingControl STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_MME_UE_S1AP_ID_STRUCT MME_UE_S1AP_ID; + LIBLTE_S1AP_ENB_UE_S1AP_ID_STRUCT eNB_UE_S1AP_ID; + LIBLTE_S1AP_REQUESTTYPE_STRUCT RequestType; +}LIBLTE_S1AP_MESSAGE_LOCATIONREPORTINGCONTROL_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_locationreportingcontrol( + LIBLTE_S1AP_MESSAGE_LOCATIONREPORTINGCONTROL_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_locationreportingcontrol( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_LOCATIONREPORTINGCONTROL_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message LocationReportingFailureIndication STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_MME_UE_S1AP_ID_STRUCT MME_UE_S1AP_ID; + LIBLTE_S1AP_ENB_UE_S1AP_ID_STRUCT eNB_UE_S1AP_ID; + LIBLTE_S1AP_CAUSE_STRUCT Cause; +}LIBLTE_S1AP_MESSAGE_LOCATIONREPORTINGFAILUREINDICATION_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_locationreportingfailureindication( + LIBLTE_S1AP_MESSAGE_LOCATIONREPORTINGFAILUREINDICATION_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_locationreportingfailureindication( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_LOCATIONREPORTINGFAILUREINDICATION_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message LocationReport STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_MME_UE_S1AP_ID_STRUCT MME_UE_S1AP_ID; + LIBLTE_S1AP_ENB_UE_S1AP_ID_STRUCT eNB_UE_S1AP_ID; + LIBLTE_S1AP_EUTRAN_CGI_STRUCT EUTRAN_CGI; + LIBLTE_S1AP_TAI_STRUCT TAI; + LIBLTE_S1AP_REQUESTTYPE_STRUCT RequestType; +}LIBLTE_S1AP_MESSAGE_LOCATIONREPORT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_locationreport( + LIBLTE_S1AP_MESSAGE_LOCATIONREPORT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_locationreport( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_LOCATIONREPORT_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message OverloadStart STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_OVERLOADRESPONSE_STRUCT OverloadResponse; + LIBLTE_S1AP_GUMMEILIST_STRUCT GUMMEIList; + bool GUMMEIList_present; + LIBLTE_S1AP_TRAFFICLOADREDUCTIONINDICATION_STRUCT TrafficLoadReductionIndication; + bool TrafficLoadReductionIndication_present; +}LIBLTE_S1AP_MESSAGE_OVERLOADSTART_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_overloadstart( + LIBLTE_S1AP_MESSAGE_OVERLOADSTART_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_overloadstart( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_OVERLOADSTART_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message OverloadStop STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_GUMMEILIST_STRUCT GUMMEIList; + bool GUMMEIList_present; +}LIBLTE_S1AP_MESSAGE_OVERLOADSTOP_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_overloadstop( + LIBLTE_S1AP_MESSAGE_OVERLOADSTOP_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_overloadstop( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_OVERLOADSTOP_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message WriteReplaceWarningRequest STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_MESSAGEIDENTIFIER_STRUCT MessageIdentifier; + LIBLTE_S1AP_SERIALNUMBER_STRUCT SerialNumber; + LIBLTE_S1AP_WARNINGAREALIST_STRUCT WarningAreaList; + bool WarningAreaList_present; + LIBLTE_S1AP_REPETITIONPERIOD_STRUCT RepetitionPeriod; + LIBLTE_S1AP_EXTENDEDREPETITIONPERIOD_STRUCT ExtendedRepetitionPeriod; + bool ExtendedRepetitionPeriod_present; + LIBLTE_S1AP_NUMBEROFBROADCASTREQUEST_STRUCT NumberofBroadcastRequest; + LIBLTE_S1AP_WARNINGTYPE_STRUCT WarningType; + bool WarningType_present; + LIBLTE_S1AP_WARNINGSECURITYINFO_STRUCT WarningSecurityInfo; + bool WarningSecurityInfo_present; + LIBLTE_S1AP_DATACODINGSCHEME_STRUCT DataCodingScheme; + bool DataCodingScheme_present; + LIBLTE_S1AP_WARNINGMESSAGECONTENTS_STRUCT WarningMessageContents; + bool WarningMessageContents_present; + LIBLTE_S1AP_CONCURRENTWARNINGMESSAGEINDICATOR_ENUM ConcurrentWarningMessageIndicator; + bool ConcurrentWarningMessageIndicator_present; +}LIBLTE_S1AP_MESSAGE_WRITEREPLACEWARNINGREQUEST_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_writereplacewarningrequest( + LIBLTE_S1AP_MESSAGE_WRITEREPLACEWARNINGREQUEST_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_writereplacewarningrequest( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_WRITEREPLACEWARNINGREQUEST_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message WriteReplaceWarningResponse STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_MESSAGEIDENTIFIER_STRUCT MessageIdentifier; + LIBLTE_S1AP_SERIALNUMBER_STRUCT SerialNumber; + LIBLTE_S1AP_BROADCASTCOMPLETEDAREALIST_STRUCT BroadcastCompletedAreaList; + bool BroadcastCompletedAreaList_present; + LIBLTE_S1AP_CRITICALITYDIAGNOSTICS_STRUCT CriticalityDiagnostics; + bool CriticalityDiagnostics_present; +}LIBLTE_S1AP_MESSAGE_WRITEREPLACEWARNINGRESPONSE_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_writereplacewarningresponse( + LIBLTE_S1AP_MESSAGE_WRITEREPLACEWARNINGRESPONSE_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_writereplacewarningresponse( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_WRITEREPLACEWARNINGRESPONSE_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message MMEDirectInformationTransfer STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_INTER_SYSTEMINFORMATIONTRANSFERTYPE_STRUCT Inter_SystemInformationTransferTypeMDT; +}LIBLTE_S1AP_MESSAGE_MMEDIRECTINFORMATIONTRANSFER_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_mmedirectinformationtransfer( + LIBLTE_S1AP_MESSAGE_MMEDIRECTINFORMATIONTRANSFER_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_mmedirectinformationtransfer( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_MMEDIRECTINFORMATIONTRANSFER_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message ENBConfigurationTransfer STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_SONCONFIGURATIONTRANSFER_STRUCT SONConfigurationTransferECT; + bool SONConfigurationTransferECT_present; +}LIBLTE_S1AP_MESSAGE_ENBCONFIGURATIONTRANSFER_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_enbconfigurationtransfer( + LIBLTE_S1AP_MESSAGE_ENBCONFIGURATIONTRANSFER_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_enbconfigurationtransfer( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_ENBCONFIGURATIONTRANSFER_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message MMEConfigurationTransfer STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_SONCONFIGURATIONTRANSFER_STRUCT SONConfigurationTransferMCT; + bool SONConfigurationTransferMCT_present; +}LIBLTE_S1AP_MESSAGE_MMECONFIGURATIONTRANSFER_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_mmeconfigurationtransfer( + LIBLTE_S1AP_MESSAGE_MMECONFIGURATIONTRANSFER_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_mmeconfigurationtransfer( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_MMECONFIGURATIONTRANSFER_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message PrivateMessage STRUCT +********************************************************************************/ +typedef struct{ + bool ext; +}LIBLTE_S1AP_MESSAGE_PRIVATEMESSAGE_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_privatemessage( + LIBLTE_S1AP_MESSAGE_PRIVATEMESSAGE_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_privatemessage( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_PRIVATEMESSAGE_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message KillRequest STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_MESSAGEIDENTIFIER_STRUCT MessageIdentifier; + LIBLTE_S1AP_SERIALNUMBER_STRUCT SerialNumber; + LIBLTE_S1AP_WARNINGAREALIST_STRUCT WarningAreaList; + bool WarningAreaList_present; + LIBLTE_S1AP_KILLALLWARNINGMESSAGES_ENUM KillAllWarningMessages; + bool KillAllWarningMessages_present; +}LIBLTE_S1AP_MESSAGE_KILLREQUEST_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_killrequest( + LIBLTE_S1AP_MESSAGE_KILLREQUEST_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_killrequest( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_KILLREQUEST_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message KillResponse STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_MESSAGEIDENTIFIER_STRUCT MessageIdentifier; + LIBLTE_S1AP_SERIALNUMBER_STRUCT SerialNumber; + LIBLTE_S1AP_BROADCASTCANCELLEDAREALIST_STRUCT BroadcastCancelledAreaList; + bool BroadcastCancelledAreaList_present; + LIBLTE_S1AP_CRITICALITYDIAGNOSTICS_STRUCT CriticalityDiagnostics; + bool CriticalityDiagnostics_present; +}LIBLTE_S1AP_MESSAGE_KILLRESPONSE_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_killresponse( + LIBLTE_S1AP_MESSAGE_KILLRESPONSE_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_killresponse( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_KILLRESPONSE_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message PWSRestartIndication STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_ECGILISTFORRESTART_STRUCT ECGIListForRestart; + LIBLTE_S1AP_GLOBAL_ENB_ID_STRUCT Global_ENB_ID; + LIBLTE_S1AP_TAILISTFORRESTART_STRUCT TAIListForRestart; + LIBLTE_S1AP_EMERGENCYAREAIDLISTFORRESTART_STRUCT EmergencyAreaIDListForRestart; + bool EmergencyAreaIDListForRestart_present; +}LIBLTE_S1AP_MESSAGE_PWSRESTARTINDICATION_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_pwsrestartindication( + LIBLTE_S1AP_MESSAGE_PWSRESTARTINDICATION_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_pwsrestartindication( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_PWSRESTARTINDICATION_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message DownlinkUEAssociatedLPPaTransport STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_MME_UE_S1AP_ID_STRUCT MME_UE_S1AP_ID; + LIBLTE_S1AP_ENB_UE_S1AP_ID_STRUCT eNB_UE_S1AP_ID; + LIBLTE_S1AP_ROUTING_ID_STRUCT Routing_ID; + LIBLTE_S1AP_LPPA_PDU_STRUCT LPPa_PDU; +}LIBLTE_S1AP_MESSAGE_DOWNLINKUEASSOCIATEDLPPATRANSPORT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_downlinkueassociatedlppatransport( + LIBLTE_S1AP_MESSAGE_DOWNLINKUEASSOCIATEDLPPATRANSPORT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_downlinkueassociatedlppatransport( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_DOWNLINKUEASSOCIATEDLPPATRANSPORT_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message UplinkUEAssociatedLPPaTransport STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_MME_UE_S1AP_ID_STRUCT MME_UE_S1AP_ID; + LIBLTE_S1AP_ENB_UE_S1AP_ID_STRUCT eNB_UE_S1AP_ID; + LIBLTE_S1AP_ROUTING_ID_STRUCT Routing_ID; + LIBLTE_S1AP_LPPA_PDU_STRUCT LPPa_PDU; +}LIBLTE_S1AP_MESSAGE_UPLINKUEASSOCIATEDLPPATRANSPORT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_uplinkueassociatedlppatransport( + LIBLTE_S1AP_MESSAGE_UPLINKUEASSOCIATEDLPPATRANSPORT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_uplinkueassociatedlppatransport( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_UPLINKUEASSOCIATEDLPPATRANSPORT_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message DownlinkNonUEAssociatedLPPaTransport STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_ROUTING_ID_STRUCT Routing_ID; + LIBLTE_S1AP_LPPA_PDU_STRUCT LPPa_PDU; +}LIBLTE_S1AP_MESSAGE_DOWNLINKNONUEASSOCIATEDLPPATRANSPORT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_downlinknonueassociatedlppatransport( + LIBLTE_S1AP_MESSAGE_DOWNLINKNONUEASSOCIATEDLPPATRANSPORT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_downlinknonueassociatedlppatransport( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_DOWNLINKNONUEASSOCIATEDLPPATRANSPORT_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message UplinkNonUEAssociatedLPPaTransport STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_ROUTING_ID_STRUCT Routing_ID; + LIBLTE_S1AP_LPPA_PDU_STRUCT LPPa_PDU; +}LIBLTE_S1AP_MESSAGE_UPLINKNONUEASSOCIATEDLPPATRANSPORT_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_uplinknonueassociatedlppatransport( + LIBLTE_S1AP_MESSAGE_UPLINKNONUEASSOCIATEDLPPATRANSPORT_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_uplinknonueassociatedlppatransport( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_UPLINKNONUEASSOCIATEDLPPATRANSPORT_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message ENBDirectInformationTransfer STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_INTER_SYSTEMINFORMATIONTRANSFERTYPE_STRUCT Inter_SystemInformationTransferTypeEDT; +}LIBLTE_S1AP_MESSAGE_ENBDIRECTINFORMATIONTRANSFER_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_enbdirectinformationtransfer( + LIBLTE_S1AP_MESSAGE_ENBDIRECTINFORMATIONTRANSFER_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_enbdirectinformationtransfer( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_ENBDIRECTINFORMATIONTRANSFER_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message E_RABDataForwardingItem STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_E_RABDATAFORWARDINGITEM_STRUCT E_RABDataForwardingItem; +}LIBLTE_S1AP_MESSAGE_E_RABDATAFORWARDINGITEM_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabdataforwardingitem( + LIBLTE_S1AP_MESSAGE_E_RABDATAFORWARDINGITEM_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabdataforwardingitem( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_E_RABDATAFORWARDINGITEM_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message E_RABToBeSetupItemHOReq STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_E_RABTOBESETUPITEMHOREQ_STRUCT E_RABToBeSetupItemHOReq; +}LIBLTE_S1AP_MESSAGE_E_RABTOBESETUPITEMHOREQ_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabtobesetupitemhoreq( + LIBLTE_S1AP_MESSAGE_E_RABTOBESETUPITEMHOREQ_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabtobesetupitemhoreq( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_E_RABTOBESETUPITEMHOREQ_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message E_RABAdmittedItem STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_E_RABADMITTEDITEM_STRUCT E_RABAdmittedItem; +}LIBLTE_S1AP_MESSAGE_E_RABADMITTEDITEM_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabadmitteditem( + LIBLTE_S1AP_MESSAGE_E_RABADMITTEDITEM_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabadmitteditem( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_E_RABADMITTEDITEM_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message E_RABFailedtoSetupItemHOReqAck STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_E_RABFAILEDTOSETUPITEMHOREQACK_STRUCT E_RABFailedtoSetupItemHOReqAck; +}LIBLTE_S1AP_MESSAGE_E_RABFAILEDTOSETUPITEMHOREQACK_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabfailedtosetupitemhoreqack( + LIBLTE_S1AP_MESSAGE_E_RABFAILEDTOSETUPITEMHOREQACK_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabfailedtosetupitemhoreqack( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_E_RABFAILEDTOSETUPITEMHOREQACK_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message E_RABToBeSwitchedDLItem STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_E_RABTOBESWITCHEDDLITEM_STRUCT E_RABToBeSwitchedDLItem; +}LIBLTE_S1AP_MESSAGE_E_RABTOBESWITCHEDDLITEM_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabtobeswitcheddlitem( + LIBLTE_S1AP_MESSAGE_E_RABTOBESWITCHEDDLITEM_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabtobeswitcheddlitem( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_E_RABTOBESWITCHEDDLITEM_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message E_RABToBeSwitchedULItem STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_E_RABTOBESWITCHEDULITEM_STRUCT E_RABToBeSwitchedULItem; +}LIBLTE_S1AP_MESSAGE_E_RABTOBESWITCHEDULITEM_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabtobeswitchedulitem( + LIBLTE_S1AP_MESSAGE_E_RABTOBESWITCHEDULITEM_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabtobeswitchedulitem( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_E_RABTOBESWITCHEDULITEM_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message E_RABToBeSetupItemBearerSUReq STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_E_RABTOBESETUPITEMBEARERSUREQ_STRUCT E_RABToBeSetupItemBearerSUReq; +}LIBLTE_S1AP_MESSAGE_E_RABTOBESETUPITEMBEARERSUREQ_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabtobesetupitembearersureq( + LIBLTE_S1AP_MESSAGE_E_RABTOBESETUPITEMBEARERSUREQ_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabtobesetupitembearersureq( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_E_RABTOBESETUPITEMBEARERSUREQ_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message E_RABSetupItemBearerSURes STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_E_RABSETUPITEMBEARERSURES_STRUCT E_RABSetupItemBearerSURes; +}LIBLTE_S1AP_MESSAGE_E_RABSETUPITEMBEARERSURES_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabsetupitembearersures( + LIBLTE_S1AP_MESSAGE_E_RABSETUPITEMBEARERSURES_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabsetupitembearersures( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_E_RABSETUPITEMBEARERSURES_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message E_RABToBeModifiedItemBearerModReq STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_E_RABTOBEMODIFIEDITEMBEARERMODREQ_STRUCT E_RABToBeModifiedItemBearerModReq; +}LIBLTE_S1AP_MESSAGE_E_RABTOBEMODIFIEDITEMBEARERMODREQ_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabtobemodifieditembearermodreq( + LIBLTE_S1AP_MESSAGE_E_RABTOBEMODIFIEDITEMBEARERMODREQ_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabtobemodifieditembearermodreq( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_E_RABTOBEMODIFIEDITEMBEARERMODREQ_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message E_RABModifyItemBearerModRes STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_E_RABMODIFYITEMBEARERMODRES_STRUCT E_RABModifyItemBearerModRes; +}LIBLTE_S1AP_MESSAGE_E_RABMODIFYITEMBEARERMODRES_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabmodifyitembearermodres( + LIBLTE_S1AP_MESSAGE_E_RABMODIFYITEMBEARERMODRES_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabmodifyitembearermodres( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_E_RABMODIFYITEMBEARERMODRES_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message E_RABReleaseItemBearerRelComp STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_E_RABRELEASEITEMBEARERRELCOMP_STRUCT E_RABReleaseItemBearerRelComp; +}LIBLTE_S1AP_MESSAGE_E_RABRELEASEITEMBEARERRELCOMP_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabreleaseitembearerrelcomp( + LIBLTE_S1AP_MESSAGE_E_RABRELEASEITEMBEARERRELCOMP_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabreleaseitembearerrelcomp( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_E_RABRELEASEITEMBEARERRELCOMP_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message E_RABToBeSetupItemCtxtSUReq STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_E_RABTOBESETUPITEMCTXTSUREQ_STRUCT E_RABToBeSetupItemCtxtSUReq; +}LIBLTE_S1AP_MESSAGE_E_RABTOBESETUPITEMCTXTSUREQ_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabtobesetupitemctxtsureq( + LIBLTE_S1AP_MESSAGE_E_RABTOBESETUPITEMCTXTSUREQ_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabtobesetupitemctxtsureq( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_E_RABTOBESETUPITEMCTXTSUREQ_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message E_RABSetupItemCtxtSURes STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_E_RABSETUPITEMCTXTSURES_STRUCT E_RABSetupItemCtxtSURes; +}LIBLTE_S1AP_MESSAGE_E_RABSETUPITEMCTXTSURES_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabsetupitemctxtsures( + LIBLTE_S1AP_MESSAGE_E_RABSETUPITEMCTXTSURES_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabsetupitemctxtsures( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_E_RABSETUPITEMCTXTSURES_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message TAIItem STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_TAIITEM_STRUCT TAIItem; +}LIBLTE_S1AP_MESSAGE_TAIITEM_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_taiitem( + LIBLTE_S1AP_MESSAGE_TAIITEM_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_taiitem( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_TAIITEM_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message ResetAcknowledge STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_UE_ASSOCIATEDLOGICALS1_CONNECTIONLISTRESACK_STRUCT UE_associatedLogicalS1_ConnectionListResAck; + bool UE_associatedLogicalS1_ConnectionListResAck_present; + LIBLTE_S1AP_CRITICALITYDIAGNOSTICS_STRUCT CriticalityDiagnostics; + bool CriticalityDiagnostics_present; +}LIBLTE_S1AP_MESSAGE_RESETACKNOWLEDGE_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_resetacknowledge( + LIBLTE_S1AP_MESSAGE_RESETACKNOWLEDGE_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_resetacknowledge( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_RESETACKNOWLEDGE_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message Reset STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_CAUSE_STRUCT Cause; + LIBLTE_S1AP_RESETTYPE_STRUCT ResetType; +}LIBLTE_S1AP_MESSAGE_RESET_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_reset( + LIBLTE_S1AP_MESSAGE_RESET_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_reset( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_RESET_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message DownlinkS1cdma2000tunneling STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_MME_UE_S1AP_ID_STRUCT MME_UE_S1AP_ID; + LIBLTE_S1AP_ENB_UE_S1AP_ID_STRUCT eNB_UE_S1AP_ID; + LIBLTE_S1AP_E_RABSUBJECTTODATAFORWARDINGLIST_STRUCT E_RABSubjecttoDataForwardingList; + bool E_RABSubjecttoDataForwardingList_present; + LIBLTE_S1AP_CDMA2000HOSTATUS_ENUM_EXT cdma2000HOStatus; + bool cdma2000HOStatus_present; + LIBLTE_S1AP_CDMA2000RATTYPE_ENUM_EXT cdma2000RATType; + LIBLTE_S1AP_CDMA2000PDU_STRUCT cdma2000PDU; +}LIBLTE_S1AP_MESSAGE_DOWNLINKS1CDMA2000TUNNELING_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_downlinks1cdma2000tunneling( + LIBLTE_S1AP_MESSAGE_DOWNLINKS1CDMA2000TUNNELING_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_downlinks1cdma2000tunneling( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_DOWNLINKS1CDMA2000TUNNELING_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message HandoverCommand STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_MME_UE_S1AP_ID_STRUCT MME_UE_S1AP_ID; + LIBLTE_S1AP_ENB_UE_S1AP_ID_STRUCT eNB_UE_S1AP_ID; + LIBLTE_S1AP_HANDOVERTYPE_ENUM_EXT HandoverType; + LIBLTE_S1AP_NASSECURITYPARAMETERSFROME_UTRAN_STRUCT NASSecurityParametersfromE_UTRAN; + bool NASSecurityParametersfromE_UTRAN_present; + LIBLTE_S1AP_E_RABSUBJECTTODATAFORWARDINGLIST_STRUCT E_RABSubjecttoDataForwardingList; + bool E_RABSubjecttoDataForwardingList_present; + LIBLTE_S1AP_E_RABLIST_STRUCT E_RABtoReleaseListHOCmd; + bool E_RABtoReleaseListHOCmd_present; + LIBLTE_S1AP_TARGET_TOSOURCE_TRANSPARENTCONTAINER_STRUCT Target_ToSource_TransparentContainer; + LIBLTE_S1AP_TARGET_TOSOURCE_TRANSPARENTCONTAINER_STRUCT Target_ToSource_TransparentContainer_Secondary; + bool Target_ToSource_TransparentContainer_Secondary_present; + LIBLTE_S1AP_CRITICALITYDIAGNOSTICS_STRUCT CriticalityDiagnostics; + bool CriticalityDiagnostics_present; +}LIBLTE_S1AP_MESSAGE_HANDOVERCOMMAND_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_handovercommand( + LIBLTE_S1AP_MESSAGE_HANDOVERCOMMAND_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_handovercommand( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_HANDOVERCOMMAND_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message HandoverRequest STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_MME_UE_S1AP_ID_STRUCT MME_UE_S1AP_ID; + LIBLTE_S1AP_HANDOVERTYPE_ENUM_EXT HandoverType; + LIBLTE_S1AP_CAUSE_STRUCT Cause; + LIBLTE_S1AP_UEAGGREGATEMAXIMUMBITRATE_STRUCT uEaggregateMaximumBitrate; + LIBLTE_S1AP_E_RABTOBESETUPLISTHOREQ_STRUCT E_RABToBeSetupListHOReq; + LIBLTE_S1AP_SOURCE_TOTARGET_TRANSPARENTCONTAINER_STRUCT Source_ToTarget_TransparentContainer; + LIBLTE_S1AP_UESECURITYCAPABILITIES_STRUCT UESecurityCapabilities; + LIBLTE_S1AP_HANDOVERRESTRICTIONLIST_STRUCT HandoverRestrictionList; + bool HandoverRestrictionList_present; + LIBLTE_S1AP_TRACEACTIVATION_STRUCT TraceActivation; + bool TraceActivation_present; + LIBLTE_S1AP_REQUESTTYPE_STRUCT RequestType; + bool RequestType_present; + LIBLTE_S1AP_SRVCCOPERATIONPOSSIBLE_ENUM_EXT SRVCCOperationPossible; + bool SRVCCOperationPossible_present; + LIBLTE_S1AP_SECURITYCONTEXT_STRUCT SecurityContext; + LIBLTE_S1AP_NASSECURITYPARAMETERSTOE_UTRAN_STRUCT NASSecurityParameterstoE_UTRAN; + bool NASSecurityParameterstoE_UTRAN_present; + LIBLTE_S1AP_CSG_ID_STRUCT CSG_Id; + bool CSG_Id_present; + LIBLTE_S1AP_CSGMEMBERSHIPSTATUS_ENUM CSGMembershipStatus; + bool CSGMembershipStatus_present; + LIBLTE_S1AP_GUMMEI_STRUCT GUMMEI_ID; + bool GUMMEI_ID_present; + LIBLTE_S1AP_MME_UE_S1AP_ID_STRUCT MME_UE_S1AP_ID_2; + bool MME_UE_S1AP_ID_2_present; + LIBLTE_S1AP_MANAGEMENTBASEDMDTALLOWED_ENUM_EXT ManagementBasedMDTAllowed; + bool ManagementBasedMDTAllowed_present; + LIBLTE_S1AP_MDTPLMNLIST_STRUCT ManagementBasedMDTPLMNList; + bool ManagementBasedMDTPLMNList_present; +}LIBLTE_S1AP_MESSAGE_HANDOVERREQUEST_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_handoverrequest( + LIBLTE_S1AP_MESSAGE_HANDOVERREQUEST_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_handoverrequest( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_HANDOVERREQUEST_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message PathSwitchRequest STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_ENB_UE_S1AP_ID_STRUCT eNB_UE_S1AP_ID; + LIBLTE_S1AP_E_RABTOBESWITCHEDDLLIST_STRUCT E_RABToBeSwitchedDLList; + LIBLTE_S1AP_MME_UE_S1AP_ID_STRUCT SourceMME_UE_S1AP_ID; + LIBLTE_S1AP_EUTRAN_CGI_STRUCT EUTRAN_CGI; + LIBLTE_S1AP_TAI_STRUCT TAI; + LIBLTE_S1AP_UESECURITYCAPABILITIES_STRUCT UESecurityCapabilities; + LIBLTE_S1AP_CSG_ID_STRUCT CSG_Id; + bool CSG_Id_present; + LIBLTE_S1AP_CELLACCESSMODE_ENUM_EXT CellAccessMode; + bool CellAccessMode_present; + LIBLTE_S1AP_GUMMEI_STRUCT SourceMME_GUMMEI; + bool SourceMME_GUMMEI_present; + LIBLTE_S1AP_CSGMEMBERSHIPSTATUS_ENUM CSGMembershipStatus; + bool CSGMembershipStatus_present; + LIBLTE_S1AP_TUNNELINFORMATION_STRUCT Tunnel_Information_for_BBF; + bool Tunnel_Information_for_BBF_present; + LIBLTE_S1AP_LHN_ID_STRUCT LHN_ID; + bool LHN_ID_present; +}LIBLTE_S1AP_MESSAGE_PATHSWITCHREQUEST_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_pathswitchrequest( + LIBLTE_S1AP_MESSAGE_PATHSWITCHREQUEST_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_pathswitchrequest( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_PATHSWITCHREQUEST_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message PathSwitchRequestAcknowledge STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_MME_UE_S1AP_ID_STRUCT MME_UE_S1AP_ID; + LIBLTE_S1AP_ENB_UE_S1AP_ID_STRUCT eNB_UE_S1AP_ID; + LIBLTE_S1AP_UEAGGREGATEMAXIMUMBITRATE_STRUCT uEaggregateMaximumBitrate; + bool uEaggregateMaximumBitrate_present; + LIBLTE_S1AP_E_RABTOBESWITCHEDULLIST_STRUCT E_RABToBeSwitchedULList; + bool E_RABToBeSwitchedULList_present; + LIBLTE_S1AP_E_RABLIST_STRUCT E_RABToBeReleasedList; + bool E_RABToBeReleasedList_present; + LIBLTE_S1AP_SECURITYCONTEXT_STRUCT SecurityContext; + LIBLTE_S1AP_CRITICALITYDIAGNOSTICS_STRUCT CriticalityDiagnostics; + bool CriticalityDiagnostics_present; + LIBLTE_S1AP_MME_UE_S1AP_ID_STRUCT MME_UE_S1AP_ID_2; + bool MME_UE_S1AP_ID_2_present; + LIBLTE_S1AP_CSGMEMBERSHIPSTATUS_ENUM CSGMembershipStatus; + bool CSGMembershipStatus_present; +}LIBLTE_S1AP_MESSAGE_PATHSWITCHREQUESTACKNOWLEDGE_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_pathswitchrequestacknowledge( + LIBLTE_S1AP_MESSAGE_PATHSWITCHREQUESTACKNOWLEDGE_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_pathswitchrequestacknowledge( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_PATHSWITCHREQUESTACKNOWLEDGE_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message E_RABSetupRequest STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_MME_UE_S1AP_ID_STRUCT MME_UE_S1AP_ID; + LIBLTE_S1AP_ENB_UE_S1AP_ID_STRUCT eNB_UE_S1AP_ID; + LIBLTE_S1AP_UEAGGREGATEMAXIMUMBITRATE_STRUCT uEaggregateMaximumBitrate; + bool uEaggregateMaximumBitrate_present; + LIBLTE_S1AP_E_RABTOBESETUPLISTBEARERSUREQ_STRUCT E_RABToBeSetupListBearerSUReq; +}LIBLTE_S1AP_MESSAGE_E_RABSETUPREQUEST_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabsetuprequest( + LIBLTE_S1AP_MESSAGE_E_RABSETUPREQUEST_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabsetuprequest( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_E_RABSETUPREQUEST_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message E_RABSetupResponse STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_MME_UE_S1AP_ID_STRUCT MME_UE_S1AP_ID; + LIBLTE_S1AP_ENB_UE_S1AP_ID_STRUCT eNB_UE_S1AP_ID; + LIBLTE_S1AP_E_RABSETUPLISTBEARERSURES_STRUCT E_RABSetupListBearerSURes; + bool E_RABSetupListBearerSURes_present; + LIBLTE_S1AP_E_RABLIST_STRUCT E_RABFailedToSetupListBearerSURes; + bool E_RABFailedToSetupListBearerSURes_present; + LIBLTE_S1AP_CRITICALITYDIAGNOSTICS_STRUCT CriticalityDiagnostics; + bool CriticalityDiagnostics_present; +}LIBLTE_S1AP_MESSAGE_E_RABSETUPRESPONSE_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabsetupresponse( + LIBLTE_S1AP_MESSAGE_E_RABSETUPRESPONSE_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabsetupresponse( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_E_RABSETUPRESPONSE_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message E_RABModifyRequest STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_MME_UE_S1AP_ID_STRUCT MME_UE_S1AP_ID; + LIBLTE_S1AP_ENB_UE_S1AP_ID_STRUCT eNB_UE_S1AP_ID; + LIBLTE_S1AP_UEAGGREGATEMAXIMUMBITRATE_STRUCT uEaggregateMaximumBitrate; + bool uEaggregateMaximumBitrate_present; + LIBLTE_S1AP_E_RABTOBEMODIFIEDLISTBEARERMODREQ_STRUCT E_RABToBeModifiedListBearerModReq; +}LIBLTE_S1AP_MESSAGE_E_RABMODIFYREQUEST_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabmodifyrequest( + LIBLTE_S1AP_MESSAGE_E_RABMODIFYREQUEST_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabmodifyrequest( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_E_RABMODIFYREQUEST_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message E_RABModifyResponse STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_MME_UE_S1AP_ID_STRUCT MME_UE_S1AP_ID; + LIBLTE_S1AP_ENB_UE_S1AP_ID_STRUCT eNB_UE_S1AP_ID; + LIBLTE_S1AP_E_RABMODIFYLISTBEARERMODRES_STRUCT E_RABModifyListBearerModRes; + bool E_RABModifyListBearerModRes_present; + LIBLTE_S1AP_E_RABLIST_STRUCT E_RABFailedToModifyList; + bool E_RABFailedToModifyList_present; + LIBLTE_S1AP_CRITICALITYDIAGNOSTICS_STRUCT CriticalityDiagnostics; + bool CriticalityDiagnostics_present; +}LIBLTE_S1AP_MESSAGE_E_RABMODIFYRESPONSE_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabmodifyresponse( + LIBLTE_S1AP_MESSAGE_E_RABMODIFYRESPONSE_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabmodifyresponse( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_E_RABMODIFYRESPONSE_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message E_RABReleaseResponse STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_MME_UE_S1AP_ID_STRUCT MME_UE_S1AP_ID; + LIBLTE_S1AP_ENB_UE_S1AP_ID_STRUCT eNB_UE_S1AP_ID; + LIBLTE_S1AP_E_RABRELEASELISTBEARERRELCOMP_STRUCT E_RABReleaseListBearerRelComp; + bool E_RABReleaseListBearerRelComp_present; + LIBLTE_S1AP_E_RABLIST_STRUCT E_RABFailedToReleaseList; + bool E_RABFailedToReleaseList_present; + LIBLTE_S1AP_CRITICALITYDIAGNOSTICS_STRUCT CriticalityDiagnostics; + bool CriticalityDiagnostics_present; + LIBLTE_S1AP_USERLOCATIONINFORMATION_STRUCT UserLocationInformation; + bool UserLocationInformation_present; +}LIBLTE_S1AP_MESSAGE_E_RABRELEASERESPONSE_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabreleaseresponse( + LIBLTE_S1AP_MESSAGE_E_RABRELEASERESPONSE_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabreleaseresponse( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_E_RABRELEASERESPONSE_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message InitialContextSetupRequest STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_MME_UE_S1AP_ID_STRUCT MME_UE_S1AP_ID; + LIBLTE_S1AP_ENB_UE_S1AP_ID_STRUCT eNB_UE_S1AP_ID; + LIBLTE_S1AP_UEAGGREGATEMAXIMUMBITRATE_STRUCT uEaggregateMaximumBitrate; + LIBLTE_S1AP_E_RABTOBESETUPLISTCTXTSUREQ_STRUCT E_RABToBeSetupListCtxtSUReq; + LIBLTE_S1AP_UESECURITYCAPABILITIES_STRUCT UESecurityCapabilities; + LIBLTE_S1AP_SECURITYKEY_STRUCT SecurityKey; + LIBLTE_S1AP_TRACEACTIVATION_STRUCT TraceActivation; + bool TraceActivation_present; + LIBLTE_S1AP_HANDOVERRESTRICTIONLIST_STRUCT HandoverRestrictionList; + bool HandoverRestrictionList_present; + LIBLTE_S1AP_UERADIOCAPABILITY_STRUCT UERadioCapability; + bool UERadioCapability_present; + LIBLTE_S1AP_SUBSCRIBERPROFILEIDFORRFP_STRUCT SubscriberProfileIDforRFP; + bool SubscriberProfileIDforRFP_present; + LIBLTE_S1AP_CSFALLBACKINDICATOR_ENUM_EXT CSFallbackIndicator; + bool CSFallbackIndicator_present; + LIBLTE_S1AP_SRVCCOPERATIONPOSSIBLE_ENUM_EXT SRVCCOperationPossible; + bool SRVCCOperationPossible_present; + LIBLTE_S1AP_CSGMEMBERSHIPSTATUS_ENUM CSGMembershipStatus; + bool CSGMembershipStatus_present; + LIBLTE_S1AP_LAI_STRUCT RegisteredLAI; + bool RegisteredLAI_present; + LIBLTE_S1AP_GUMMEI_STRUCT GUMMEI_ID; + bool GUMMEI_ID_present; + LIBLTE_S1AP_MME_UE_S1AP_ID_STRUCT MME_UE_S1AP_ID_2; + bool MME_UE_S1AP_ID_2_present; + LIBLTE_S1AP_MANAGEMENTBASEDMDTALLOWED_ENUM_EXT ManagementBasedMDTAllowed; + bool ManagementBasedMDTAllowed_present; + LIBLTE_S1AP_MDTPLMNLIST_STRUCT ManagementBasedMDTPLMNList; + bool ManagementBasedMDTPLMNList_present; + LIBLTE_S1AP_ADDITIONALCSFALLBACKINDICATOR_ENUM_EXT AdditionalCSFallbackIndicator; + bool AdditionalCSFallbackIndicator_present; +}LIBLTE_S1AP_MESSAGE_INITIALCONTEXTSETUPREQUEST_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_initialcontextsetuprequest( + LIBLTE_S1AP_MESSAGE_INITIALCONTEXTSETUPREQUEST_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_initialcontextsetuprequest( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_INITIALCONTEXTSETUPREQUEST_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message InitialContextSetupResponse STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_MME_UE_S1AP_ID_STRUCT MME_UE_S1AP_ID; + LIBLTE_S1AP_ENB_UE_S1AP_ID_STRUCT eNB_UE_S1AP_ID; + LIBLTE_S1AP_E_RABSETUPLISTCTXTSURES_STRUCT E_RABSetupListCtxtSURes; + LIBLTE_S1AP_E_RABLIST_STRUCT E_RABFailedToSetupListCtxtSURes; + bool E_RABFailedToSetupListCtxtSURes_present; + LIBLTE_S1AP_CRITICALITYDIAGNOSTICS_STRUCT CriticalityDiagnostics; + bool CriticalityDiagnostics_present; +}LIBLTE_S1AP_MESSAGE_INITIALCONTEXTSETUPRESPONSE_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_initialcontextsetupresponse( + LIBLTE_S1AP_MESSAGE_INITIALCONTEXTSETUPRESPONSE_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_initialcontextsetupresponse( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_INITIALCONTEXTSETUPRESPONSE_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message Paging STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_UEIDENTITYINDEXVALUE_STRUCT UEIdentityIndexValue; + LIBLTE_S1AP_UEPAGINGID_STRUCT UEPagingID; + LIBLTE_S1AP_PAGINGDRX_ENUM_EXT pagingDRX; + bool pagingDRX_present; + LIBLTE_S1AP_CNDOMAIN_ENUM CNDomain; + LIBLTE_S1AP_TAILIST_STRUCT TAIList; + LIBLTE_S1AP_CSG_IDLIST_STRUCT CSG_IdList; + bool CSG_IdList_present; + LIBLTE_S1AP_PAGINGPRIORITY_ENUM_EXT PagingPriority; + bool PagingPriority_present; +}LIBLTE_S1AP_MESSAGE_PAGING_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_paging( + LIBLTE_S1AP_MESSAGE_PAGING_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_paging( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_PAGING_STRUCT *ie); + +/******************************************************************************* +/* Protocol Message HandoverRequestAcknowledge STRUCT +********************************************************************************/ +typedef struct{ + bool ext; + LIBLTE_S1AP_MME_UE_S1AP_ID_STRUCT MME_UE_S1AP_ID; + LIBLTE_S1AP_ENB_UE_S1AP_ID_STRUCT eNB_UE_S1AP_ID; + LIBLTE_S1AP_E_RABADMITTEDLIST_STRUCT E_RABAdmittedList; + LIBLTE_S1AP_E_RABFAILEDTOSETUPLISTHOREQACK_STRUCT E_RABFailedToSetupListHOReqAck; + bool E_RABFailedToSetupListHOReqAck_present; + LIBLTE_S1AP_TARGET_TOSOURCE_TRANSPARENTCONTAINER_STRUCT Target_ToSource_TransparentContainer; + LIBLTE_S1AP_CSG_ID_STRUCT CSG_Id; + bool CSG_Id_present; + LIBLTE_S1AP_CRITICALITYDIAGNOSTICS_STRUCT CriticalityDiagnostics; + bool CriticalityDiagnostics_present; + LIBLTE_S1AP_CELLACCESSMODE_ENUM_EXT CellAccessMode; + bool CellAccessMode_present; +}LIBLTE_S1AP_MESSAGE_HANDOVERREQUESTACKNOWLEDGE_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_handoverrequestacknowledge( + LIBLTE_S1AP_MESSAGE_HANDOVERREQUESTACKNOWLEDGE_STRUCT *ie, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_handoverrequestacknowledge( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_HANDOVERREQUESTACKNOWLEDGE_STRUCT *ie); + +/******************************************************************************* +/* Procedure code criticality lookups +********************************************************************************/ +static const LIBLTE_S1AP_CRITICALITY_ENUM liblte_s1ap_procedure_criticality[50] = { + LIBLTE_S1AP_CRITICALITY_REJECT, + LIBLTE_S1AP_CRITICALITY_REJECT, + LIBLTE_S1AP_CRITICALITY_IGNORE, + LIBLTE_S1AP_CRITICALITY_REJECT, + LIBLTE_S1AP_CRITICALITY_REJECT, + LIBLTE_S1AP_CRITICALITY_REJECT, + LIBLTE_S1AP_CRITICALITY_REJECT, + LIBLTE_S1AP_CRITICALITY_REJECT, + LIBLTE_S1AP_CRITICALITY_IGNORE, + LIBLTE_S1AP_CRITICALITY_REJECT, + LIBLTE_S1AP_CRITICALITY_IGNORE, + LIBLTE_S1AP_CRITICALITY_IGNORE, + LIBLTE_S1AP_CRITICALITY_IGNORE, + LIBLTE_S1AP_CRITICALITY_IGNORE, + LIBLTE_S1AP_CRITICALITY_REJECT, + LIBLTE_S1AP_CRITICALITY_IGNORE, + LIBLTE_S1AP_CRITICALITY_IGNORE, + LIBLTE_S1AP_CRITICALITY_REJECT, + LIBLTE_S1AP_CRITICALITY_IGNORE, + LIBLTE_S1AP_CRITICALITY_IGNORE, + LIBLTE_S1AP_CRITICALITY_IGNORE, + LIBLTE_S1AP_CRITICALITY_REJECT, + LIBLTE_S1AP_CRITICALITY_IGNORE, + LIBLTE_S1AP_CRITICALITY_REJECT, + LIBLTE_S1AP_CRITICALITY_IGNORE, + LIBLTE_S1AP_CRITICALITY_IGNORE, + LIBLTE_S1AP_CRITICALITY_IGNORE, + LIBLTE_S1AP_CRITICALITY_IGNORE, + LIBLTE_S1AP_CRITICALITY_IGNORE, + LIBLTE_S1AP_CRITICALITY_REJECT, + LIBLTE_S1AP_CRITICALITY_REJECT, + LIBLTE_S1AP_CRITICALITY_IGNORE, + LIBLTE_S1AP_CRITICALITY_IGNORE, + LIBLTE_S1AP_CRITICALITY_IGNORE, + LIBLTE_S1AP_CRITICALITY_IGNORE, + LIBLTE_S1AP_CRITICALITY_REJECT, + LIBLTE_S1AP_CRITICALITY_REJECT, + LIBLTE_S1AP_CRITICALITY_IGNORE, + LIBLTE_S1AP_CRITICALITY_IGNORE, + LIBLTE_S1AP_CRITICALITY_IGNORE, + LIBLTE_S1AP_CRITICALITY_IGNORE, + LIBLTE_S1AP_CRITICALITY_IGNORE, + LIBLTE_S1AP_CRITICALITY_IGNORE, + LIBLTE_S1AP_CRITICALITY_REJECT, + LIBLTE_S1AP_CRITICALITY_IGNORE, + LIBLTE_S1AP_CRITICALITY_IGNORE, + LIBLTE_S1AP_CRITICALITY_IGNORE, + LIBLTE_S1AP_CRITICALITY_IGNORE, + LIBLTE_S1AP_CRITICALITY_REJECT, + LIBLTE_S1AP_CRITICALITY_IGNORE, +}; + +/******************************************************************************* +/* ProtocolIE-Field +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_protocolie_header( + uint32_t len, + uint32_t ie_id, + LIBLTE_S1AP_CRITICALITY_ENUM crit, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_protocolie_header( + uint8_t **ptr, + uint32_t *ie_id, + LIBLTE_S1AP_CRITICALITY_ENUM *crit, + uint32_t *len); + +/******************************************************************************* +/* InitiatingMessage CHOICE +********************************************************************************/ +typedef enum{ + LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_LOCATIONREPORTINGCONTROL, + LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_DOWNLINKS1CDMA2000TUNNELING, + LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_S1SETUPREQUEST, + LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_UECAPABILITYINFOINDICATION, + LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_LOCATIONREPORT, + LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_UPLINKNONUEASSOCIATEDLPPATRANSPORT, + LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_UPLINKS1CDMA2000TUNNELING, + LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_MMECONFIGURATIONTRANSFER, + LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_TRACESTART, + LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_HANDOVERCANCEL, + LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_UERADIOCAPABILITYMATCHREQUEST, + LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_DOWNLINKNASTRANSPORT, + LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_INITIALCONTEXTSETUPREQUEST, + LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_HANDOVERREQUIRED, + LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_MMEDIRECTINFORMATIONTRANSFER, + LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_TRACEFAILUREINDICATION, + LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_MMECONFIGURATIONUPDATE, + LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_WRITEREPLACEWARNINGREQUEST, + LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_ENBDIRECTINFORMATIONTRANSFER, + LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_DOWNLINKUEASSOCIATEDLPPATRANSPORT, + LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_E_RABRELEASECOMMAND, + LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_NASNONDELIVERYINDICATION, + LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_ENBCONFIGURATIONUPDATE, + LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_UPLINKUEASSOCIATEDLPPATRANSPORT, + LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_INITIALUEMESSAGE, + LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_E_RABMODIFYREQUEST, + LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_UECONTEXTMODIFICATIONREQUEST, + LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_E_RABSETUPREQUEST, + LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_RESET, + LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_OVERLOADSTART, + LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_E_RABRELEASEINDICATION, + LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_LOCATIONREPORTINGFAILUREINDICATION, + LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_DEACTIVATETRACE, + LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_PATHSWITCHREQUEST, + LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_HANDOVERREQUEST, + LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_DOWNLINKNONUEASSOCIATEDLPPATRANSPORT, + LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_OVERLOADSTOP, + LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_PAGING, + LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_HANDOVERNOTIFY, + LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_PWSRESTARTINDICATION, + LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_UECONTEXTRELEASEREQUEST, + LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_UPLINKNASTRANSPORT, + LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_ENBCONFIGURATIONTRANSFER, + LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_MMESTATUSTRANSFER, + LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_CELLTRAFFICTRACE, + LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_UECONTEXTRELEASECOMMAND, + LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_KILLREQUEST, + LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_PRIVATEMESSAGE, + LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_ENBSTATUSTRANSFER, + LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_ERRORINDICATION, + LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_N_ITEMS, +}LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_ENUM; +static const char liblte_s1ap_initiatingmessage_choice_text[LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_N_ITEMS][50] = { + "LocationReportingControl", + "DownlinkS1cdma2000tunneling", + "S1SetupRequest", + "UECapabilityInfoIndication", + "LocationReport", + "UplinkNonUEAssociatedLPPaTransport", + "UplinkS1cdma2000tunneling", + "MMEConfigurationTransfer", + "TraceStart", + "HandoverCancel", + "UERadioCapabilityMatchRequest", + "DownlinkNASTransport", + "InitialContextSetupRequest", + "HandoverRequired", + "MMEDirectInformationTransfer", + "TraceFailureIndication", + "MMEConfigurationUpdate", + "WriteReplaceWarningRequest", + "ENBDirectInformationTransfer", + "DownlinkUEAssociatedLPPaTransport", + "E-RABReleaseCommand", + "NASNonDeliveryIndication", + "ENBConfigurationUpdate", + "UplinkUEAssociatedLPPaTransport", + "InitialUEMessage", + "E-RABModifyRequest", + "UEContextModificationRequest", + "E-RABSetupRequest", + "Reset", + "OverloadStart", + "E-RABReleaseIndication", + "LocationReportingFailureIndication", + "DeactivateTrace", + "PathSwitchRequest", + "HandoverRequest", + "DownlinkNonUEAssociatedLPPaTransport", + "OverloadStop", + "Paging", + "HandoverNotify", + "PWSRestartIndication", + "UEContextReleaseRequest", + "UplinkNASTransport", + "ENBConfigurationTransfer", + "MMEStatusTransfer", + "CellTrafficTrace", + "UEContextReleaseCommand", + "KillRequest", + "PrivateMessage", + "ENBStatusTransfer", + "ErrorIndication", +}; + +typedef union{ + LIBLTE_S1AP_MESSAGE_LOCATIONREPORTINGCONTROL_STRUCT LocationReportingControl; + LIBLTE_S1AP_MESSAGE_DOWNLINKS1CDMA2000TUNNELING_STRUCT DownlinkS1cdma2000tunneling; + LIBLTE_S1AP_MESSAGE_S1SETUPREQUEST_STRUCT S1SetupRequest; + LIBLTE_S1AP_MESSAGE_UECAPABILITYINFOINDICATION_STRUCT UECapabilityInfoIndication; + LIBLTE_S1AP_MESSAGE_LOCATIONREPORT_STRUCT LocationReport; + LIBLTE_S1AP_MESSAGE_UPLINKNONUEASSOCIATEDLPPATRANSPORT_STRUCT UplinkNonUEAssociatedLPPaTransport; + LIBLTE_S1AP_MESSAGE_UPLINKS1CDMA2000TUNNELING_STRUCT UplinkS1cdma2000tunneling; + LIBLTE_S1AP_MESSAGE_MMECONFIGURATIONTRANSFER_STRUCT MMEConfigurationTransfer; + LIBLTE_S1AP_MESSAGE_TRACESTART_STRUCT TraceStart; + LIBLTE_S1AP_MESSAGE_HANDOVERCANCEL_STRUCT HandoverCancel; + LIBLTE_S1AP_MESSAGE_UERADIOCAPABILITYMATCHREQUEST_STRUCT UERadioCapabilityMatchRequest; + LIBLTE_S1AP_MESSAGE_DOWNLINKNASTRANSPORT_STRUCT DownlinkNASTransport; + LIBLTE_S1AP_MESSAGE_INITIALCONTEXTSETUPREQUEST_STRUCT InitialContextSetupRequest; + LIBLTE_S1AP_MESSAGE_HANDOVERREQUIRED_STRUCT HandoverRequired; + LIBLTE_S1AP_MESSAGE_MMEDIRECTINFORMATIONTRANSFER_STRUCT MMEDirectInformationTransfer; + LIBLTE_S1AP_MESSAGE_TRACEFAILUREINDICATION_STRUCT TraceFailureIndication; + LIBLTE_S1AP_MESSAGE_MMECONFIGURATIONUPDATE_STRUCT MMEConfigurationUpdate; + LIBLTE_S1AP_MESSAGE_WRITEREPLACEWARNINGREQUEST_STRUCT WriteReplaceWarningRequest; + LIBLTE_S1AP_MESSAGE_ENBDIRECTINFORMATIONTRANSFER_STRUCT ENBDirectInformationTransfer; + LIBLTE_S1AP_MESSAGE_DOWNLINKUEASSOCIATEDLPPATRANSPORT_STRUCT DownlinkUEAssociatedLPPaTransport; + LIBLTE_S1AP_MESSAGE_E_RABRELEASECOMMAND_STRUCT E_RABReleaseCommand; + LIBLTE_S1AP_MESSAGE_NASNONDELIVERYINDICATION_STRUCT NASNonDeliveryIndication; + LIBLTE_S1AP_MESSAGE_ENBCONFIGURATIONUPDATE_STRUCT ENBConfigurationUpdate; + LIBLTE_S1AP_MESSAGE_UPLINKUEASSOCIATEDLPPATRANSPORT_STRUCT UplinkUEAssociatedLPPaTransport; + LIBLTE_S1AP_MESSAGE_INITIALUEMESSAGE_STRUCT InitialUEMessage; + LIBLTE_S1AP_MESSAGE_E_RABMODIFYREQUEST_STRUCT E_RABModifyRequest; + LIBLTE_S1AP_MESSAGE_UECONTEXTMODIFICATIONREQUEST_STRUCT UEContextModificationRequest; + LIBLTE_S1AP_MESSAGE_E_RABSETUPREQUEST_STRUCT E_RABSetupRequest; + LIBLTE_S1AP_MESSAGE_RESET_STRUCT Reset; + LIBLTE_S1AP_MESSAGE_OVERLOADSTART_STRUCT OverloadStart; + LIBLTE_S1AP_MESSAGE_E_RABRELEASEINDICATION_STRUCT E_RABReleaseIndication; + LIBLTE_S1AP_MESSAGE_LOCATIONREPORTINGFAILUREINDICATION_STRUCT LocationReportingFailureIndication; + LIBLTE_S1AP_MESSAGE_DEACTIVATETRACE_STRUCT DeactivateTrace; + LIBLTE_S1AP_MESSAGE_PATHSWITCHREQUEST_STRUCT PathSwitchRequest; + LIBLTE_S1AP_MESSAGE_HANDOVERREQUEST_STRUCT HandoverRequest; + LIBLTE_S1AP_MESSAGE_DOWNLINKNONUEASSOCIATEDLPPATRANSPORT_STRUCT DownlinkNonUEAssociatedLPPaTransport; + LIBLTE_S1AP_MESSAGE_OVERLOADSTOP_STRUCT OverloadStop; + LIBLTE_S1AP_MESSAGE_PAGING_STRUCT Paging; + LIBLTE_S1AP_MESSAGE_HANDOVERNOTIFY_STRUCT HandoverNotify; + LIBLTE_S1AP_MESSAGE_PWSRESTARTINDICATION_STRUCT PWSRestartIndication; + LIBLTE_S1AP_MESSAGE_UECONTEXTRELEASEREQUEST_STRUCT UEContextReleaseRequest; + LIBLTE_S1AP_MESSAGE_UPLINKNASTRANSPORT_STRUCT UplinkNASTransport; + LIBLTE_S1AP_MESSAGE_ENBCONFIGURATIONTRANSFER_STRUCT ENBConfigurationTransfer; + LIBLTE_S1AP_MESSAGE_MMESTATUSTRANSFER_STRUCT MMEStatusTransfer; + LIBLTE_S1AP_MESSAGE_CELLTRAFFICTRACE_STRUCT CellTrafficTrace; + LIBLTE_S1AP_MESSAGE_UECONTEXTRELEASECOMMAND_STRUCT UEContextReleaseCommand; + LIBLTE_S1AP_MESSAGE_KILLREQUEST_STRUCT KillRequest; + LIBLTE_S1AP_MESSAGE_PRIVATEMESSAGE_STRUCT PrivateMessage; + LIBLTE_S1AP_MESSAGE_ENBSTATUSTRANSFER_STRUCT ENBStatusTransfer; + LIBLTE_S1AP_MESSAGE_ERRORINDICATION_STRUCT ErrorIndication; +}LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_UNION; + +typedef struct{ + uint8_t procedureCode; + LIBLTE_S1AP_CRITICALITY_ENUM criticality; + LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_UNION choice; + LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_ENUM choice_type; +}LIBLTE_S1AP_INITIATINGMESSAGE_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_initiatingmessage( + LIBLTE_S1AP_INITIATINGMESSAGE_STRUCT *msg, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_initiatingmessage( + uint8_t **ptr, + LIBLTE_S1AP_INITIATINGMESSAGE_STRUCT *msg); + +/******************************************************************************* +/* UnsuccessfulOutcome CHOICE +********************************************************************************/ +typedef enum{ + LIBLTE_S1AP_UNSUCCESSFULOUTCOME_CHOICE_S1SETUPFAILURE, + LIBLTE_S1AP_UNSUCCESSFULOUTCOME_CHOICE_PATHSWITCHREQUESTFAILURE, + LIBLTE_S1AP_UNSUCCESSFULOUTCOME_CHOICE_UECONTEXTMODIFICATIONFAILURE, + LIBLTE_S1AP_UNSUCCESSFULOUTCOME_CHOICE_INITIALCONTEXTSETUPFAILURE, + LIBLTE_S1AP_UNSUCCESSFULOUTCOME_CHOICE_ENBCONFIGURATIONUPDATEFAILURE, + LIBLTE_S1AP_UNSUCCESSFULOUTCOME_CHOICE_HANDOVERPREPARATIONFAILURE, + LIBLTE_S1AP_UNSUCCESSFULOUTCOME_CHOICE_HANDOVERFAILURE, + LIBLTE_S1AP_UNSUCCESSFULOUTCOME_CHOICE_MMECONFIGURATIONUPDATEFAILURE, + LIBLTE_S1AP_UNSUCCESSFULOUTCOME_CHOICE_N_ITEMS, +}LIBLTE_S1AP_UNSUCCESSFULOUTCOME_CHOICE_ENUM; +static const char liblte_s1ap_unsuccessfuloutcome_choice_text[LIBLTE_S1AP_UNSUCCESSFULOUTCOME_CHOICE_N_ITEMS][50] = { + "S1SetupFailure", + "PathSwitchRequestFailure", + "UEContextModificationFailure", + "InitialContextSetupFailure", + "ENBConfigurationUpdateFailure", + "HandoverPreparationFailure", + "HandoverFailure", + "MMEConfigurationUpdateFailure", +}; + +typedef union{ + LIBLTE_S1AP_MESSAGE_S1SETUPFAILURE_STRUCT S1SetupFailure; + LIBLTE_S1AP_MESSAGE_PATHSWITCHREQUESTFAILURE_STRUCT PathSwitchRequestFailure; + LIBLTE_S1AP_MESSAGE_UECONTEXTMODIFICATIONFAILURE_STRUCT UEContextModificationFailure; + LIBLTE_S1AP_MESSAGE_INITIALCONTEXTSETUPFAILURE_STRUCT InitialContextSetupFailure; + LIBLTE_S1AP_MESSAGE_ENBCONFIGURATIONUPDATEFAILURE_STRUCT ENBConfigurationUpdateFailure; + LIBLTE_S1AP_MESSAGE_HANDOVERPREPARATIONFAILURE_STRUCT HandoverPreparationFailure; + LIBLTE_S1AP_MESSAGE_HANDOVERFAILURE_STRUCT HandoverFailure; + LIBLTE_S1AP_MESSAGE_MMECONFIGURATIONUPDATEFAILURE_STRUCT MMEConfigurationUpdateFailure; +}LIBLTE_S1AP_UNSUCCESSFULOUTCOME_CHOICE_UNION; + +typedef struct{ + uint8_t procedureCode; + LIBLTE_S1AP_CRITICALITY_ENUM criticality; + LIBLTE_S1AP_UNSUCCESSFULOUTCOME_CHOICE_UNION choice; + LIBLTE_S1AP_UNSUCCESSFULOUTCOME_CHOICE_ENUM choice_type; +}LIBLTE_S1AP_UNSUCCESSFULOUTCOME_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_unsuccessfuloutcome( + LIBLTE_S1AP_UNSUCCESSFULOUTCOME_STRUCT *msg, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_unsuccessfuloutcome( + uint8_t **ptr, + LIBLTE_S1AP_UNSUCCESSFULOUTCOME_STRUCT *msg); + +/******************************************************************************* +/* SuccessfulOutcome CHOICE +********************************************************************************/ +typedef enum{ + LIBLTE_S1AP_SUCCESSFULOUTCOME_CHOICE_HANDOVERREQUESTACKNOWLEDGE, + LIBLTE_S1AP_SUCCESSFULOUTCOME_CHOICE_UECONTEXTRELEASECOMPLETE, + LIBLTE_S1AP_SUCCESSFULOUTCOME_CHOICE_UERADIOCAPABILITYMATCHRESPONSE, + LIBLTE_S1AP_SUCCESSFULOUTCOME_CHOICE_INITIALCONTEXTSETUPRESPONSE, + LIBLTE_S1AP_SUCCESSFULOUTCOME_CHOICE_E_RABSETUPRESPONSE, + LIBLTE_S1AP_SUCCESSFULOUTCOME_CHOICE_PATHSWITCHREQUESTACKNOWLEDGE, + LIBLTE_S1AP_SUCCESSFULOUTCOME_CHOICE_MMECONFIGURATIONUPDATEACKNOWLEDGE, + LIBLTE_S1AP_SUCCESSFULOUTCOME_CHOICE_RESETACKNOWLEDGE, + LIBLTE_S1AP_SUCCESSFULOUTCOME_CHOICE_ENBCONFIGURATIONUPDATEACKNOWLEDGE, + LIBLTE_S1AP_SUCCESSFULOUTCOME_CHOICE_E_RABMODIFYRESPONSE, + LIBLTE_S1AP_SUCCESSFULOUTCOME_CHOICE_WRITEREPLACEWARNINGRESPONSE, + LIBLTE_S1AP_SUCCESSFULOUTCOME_CHOICE_S1SETUPRESPONSE, + LIBLTE_S1AP_SUCCESSFULOUTCOME_CHOICE_KILLRESPONSE, + LIBLTE_S1AP_SUCCESSFULOUTCOME_CHOICE_UECONTEXTMODIFICATIONRESPONSE, + LIBLTE_S1AP_SUCCESSFULOUTCOME_CHOICE_HANDOVERCOMMAND, + LIBLTE_S1AP_SUCCESSFULOUTCOME_CHOICE_HANDOVERCANCELACKNOWLEDGE, + LIBLTE_S1AP_SUCCESSFULOUTCOME_CHOICE_E_RABRELEASERESPONSE, + LIBLTE_S1AP_SUCCESSFULOUTCOME_CHOICE_N_ITEMS, +}LIBLTE_S1AP_SUCCESSFULOUTCOME_CHOICE_ENUM; +static const char liblte_s1ap_successfuloutcome_choice_text[LIBLTE_S1AP_SUCCESSFULOUTCOME_CHOICE_N_ITEMS][50] = { + "HandoverRequestAcknowledge", + "UEContextReleaseComplete", + "UERadioCapabilityMatchResponse", + "InitialContextSetupResponse", + "E-RABSetupResponse", + "PathSwitchRequestAcknowledge", + "MMEConfigurationUpdateAcknowledge", + "ResetAcknowledge", + "ENBConfigurationUpdateAcknowledge", + "E-RABModifyResponse", + "WriteReplaceWarningResponse", + "S1SetupResponse", + "KillResponse", + "UEContextModificationResponse", + "HandoverCommand", + "HandoverCancelAcknowledge", + "E-RABReleaseResponse", +}; + +typedef union{ + LIBLTE_S1AP_MESSAGE_HANDOVERREQUESTACKNOWLEDGE_STRUCT HandoverRequestAcknowledge; + LIBLTE_S1AP_MESSAGE_UECONTEXTRELEASECOMPLETE_STRUCT UEContextReleaseComplete; + LIBLTE_S1AP_MESSAGE_UERADIOCAPABILITYMATCHRESPONSE_STRUCT UERadioCapabilityMatchResponse; + LIBLTE_S1AP_MESSAGE_INITIALCONTEXTSETUPRESPONSE_STRUCT InitialContextSetupResponse; + LIBLTE_S1AP_MESSAGE_E_RABSETUPRESPONSE_STRUCT E_RABSetupResponse; + LIBLTE_S1AP_MESSAGE_PATHSWITCHREQUESTACKNOWLEDGE_STRUCT PathSwitchRequestAcknowledge; + LIBLTE_S1AP_MESSAGE_MMECONFIGURATIONUPDATEACKNOWLEDGE_STRUCT MMEConfigurationUpdateAcknowledge; + LIBLTE_S1AP_MESSAGE_RESETACKNOWLEDGE_STRUCT ResetAcknowledge; + LIBLTE_S1AP_MESSAGE_ENBCONFIGURATIONUPDATEACKNOWLEDGE_STRUCT ENBConfigurationUpdateAcknowledge; + LIBLTE_S1AP_MESSAGE_E_RABMODIFYRESPONSE_STRUCT E_RABModifyResponse; + LIBLTE_S1AP_MESSAGE_WRITEREPLACEWARNINGRESPONSE_STRUCT WriteReplaceWarningResponse; + LIBLTE_S1AP_MESSAGE_S1SETUPRESPONSE_STRUCT S1SetupResponse; + LIBLTE_S1AP_MESSAGE_KILLRESPONSE_STRUCT KillResponse; + LIBLTE_S1AP_MESSAGE_UECONTEXTMODIFICATIONRESPONSE_STRUCT UEContextModificationResponse; + LIBLTE_S1AP_MESSAGE_HANDOVERCOMMAND_STRUCT HandoverCommand; + LIBLTE_S1AP_MESSAGE_HANDOVERCANCELACKNOWLEDGE_STRUCT HandoverCancelAcknowledge; + LIBLTE_S1AP_MESSAGE_E_RABRELEASERESPONSE_STRUCT E_RABReleaseResponse; +}LIBLTE_S1AP_SUCCESSFULOUTCOME_CHOICE_UNION; + +typedef struct{ + uint8_t procedureCode; + LIBLTE_S1AP_CRITICALITY_ENUM criticality; + LIBLTE_S1AP_SUCCESSFULOUTCOME_CHOICE_UNION choice; + LIBLTE_S1AP_SUCCESSFULOUTCOME_CHOICE_ENUM choice_type; +}LIBLTE_S1AP_SUCCESSFULOUTCOME_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_successfuloutcome( + LIBLTE_S1AP_SUCCESSFULOUTCOME_STRUCT *msg, + uint8_t **ptr); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_successfuloutcome( + uint8_t **ptr, + LIBLTE_S1AP_SUCCESSFULOUTCOME_STRUCT *msg); + +/******************************************************************************* +/* S1AP_PDU CHOICE +********************************************************************************/ +typedef enum{ + LIBLTE_S1AP_S1AP_PDU_CHOICE_INITIATINGMESSAGE, + LIBLTE_S1AP_S1AP_PDU_CHOICE_SUCCESSFULOUTCOME, + LIBLTE_S1AP_S1AP_PDU_CHOICE_UNSUCCESSFULOUTCOME, + LIBLTE_S1AP_S1AP_PDU_CHOICE_N_ITEMS, +}LIBLTE_S1AP_S1AP_PDU_CHOICE_ENUM; +static const char liblte_s1ap_s1ap_pdu_choice_text[LIBLTE_S1AP_S1AP_PDU_CHOICE_N_ITEMS][50] = { + "initiatingMessage", + "successfulOutcome", + "unsuccessfulOutcome", +}; + +typedef union{ + LIBLTE_S1AP_INITIATINGMESSAGE_STRUCT initiatingMessage; + LIBLTE_S1AP_SUCCESSFULOUTCOME_STRUCT successfulOutcome; + LIBLTE_S1AP_UNSUCCESSFULOUTCOME_STRUCT unsuccessfulOutcome; +}LIBLTE_S1AP_S1AP_PDU_CHOICE_UNION; + +typedef struct{ + bool ext; + LIBLTE_S1AP_S1AP_PDU_CHOICE_UNION choice; + LIBLTE_S1AP_S1AP_PDU_CHOICE_ENUM choice_type; +}LIBLTE_S1AP_S1AP_PDU_STRUCT; + +LIBLTE_ERROR_ENUM liblte_s1ap_pack_s1ap_pdu( + LIBLTE_S1AP_S1AP_PDU_STRUCT *s1ap_pdu, + LIBLTE_BYTE_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_s1ap_pdu( + LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_S1AP_S1AP_PDU_STRUCT *s1ap_pdu); +#endif // LIBLTE_S1AP_H diff --git a/lib/include/srslte/common/bcd_helpers.h b/lib/include/srslte/common/bcd_helpers.h new file mode 100644 index 000000000..d44a66483 --- /dev/null +++ b/lib/include/srslte/common/bcd_helpers.h @@ -0,0 +1,118 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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 BCD_HELPERS +#define BCD_HELPERS + +#include +#include +#include + +namespace srslte { + +/****************************************************************************** + * Convert between string and BCD-coded MCC. + * Digits are represented by 4-bit nibbles. Unused nibbles are filled with 0xF. + * MCC 001 results in 0xF001 + *****************************************************************************/ +inline bool string_to_mcc(std::string str, uint16_t *mcc) +{ + uint32_t len = str.size(); + if(len != 3) { + return false; + } + if(!isdigit(str[0]) || !isdigit(str[1]) || !isdigit(str[2])) { + return false; + } + *mcc = 0xF000; + *mcc |= ((uint8_t)(str[0]-'0') << 8); + *mcc |= ((uint8_t)(str[1]-'0') << 4); + *mcc |= ((uint8_t)(str[2]-'0')); + return true; +} + +inline bool mcc_to_string(uint16_t mcc, std::string *str) +{ + if((mcc & 0xF000) != 0xF000) { + return false; + } + *str = ""; + *str += ((mcc & 0x0F00) >> 8) + '0'; + *str += ((mcc & 0x00F0) >> 4) + '0'; + *str += (mcc & 0x000F) + '0'; + return true; +} + +/****************************************************************************** + * Convert between string and BCD-coded MNC. + * Digits are represented by 4-bit nibbles. Unused nibbles are filled with 0xF. + * MNC 001 results in 0xF001 + * MNC 01 results in 0xFF01 + *****************************************************************************/ +inline bool string_to_mnc(std::string str, uint16_t *mnc) +{ + uint32_t len = str.size(); + if(len != 3 && len != 2) { + return false; + } + if(len == 3) { + if(!isdigit(str[0]) || !isdigit(str[1]) || !isdigit(str[2])) { + return false; + } + *mnc = 0xF000; + *mnc |= ((uint8_t)(str[0]-'0') << 8); + *mnc |= ((uint8_t)(str[1]-'0') << 4); + *mnc |= ((uint8_t)(str[2]-'0')); + } + if(len == 2) { + if(!isdigit(str[0]) || !isdigit(str[1])) { + return false; + } + *mnc = 0xFF00; + *mnc |= ((uint8_t)(str[0]-'0') << 4); + *mnc |= ((uint8_t)(str[1]-'0')); + } + + return true; +} + +inline bool mnc_to_string(uint16_t mnc, std::string *str) +{ + if((mnc & 0xF000) != 0xF000) { + return false; + } + *str = ""; + if((mnc & 0xFF00) != 0xFF00) { + *str += ((mnc & 0x0F00) >> 8) + '0'; + } + *str += ((mnc & 0x00F0) >> 4) + '0'; + *str += (mnc & 0x000F) + '0'; + return true; +} + +} // namespace srslte + +#endif // BCD_HELPERS diff --git a/lib/include/srslte/common/block_queue.h b/lib/include/srslte/common/block_queue.h new file mode 100644 index 000000000..b4b312b60 --- /dev/null +++ b/lib/include/srslte/common/block_queue.h @@ -0,0 +1,97 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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 BLOCK_QUEUE +#define BLOCK_QUEUE + +#include +#include +#include +#include +#include +namespace srslte { + +template +class block_queue { + +public: + block_queue() { + pthread_mutex_init(&mutex, NULL); + pthread_cond_init(&cvar, NULL); + } + void push(const myobj& value) { + pthread_mutex_lock(&mutex); + q.push(value); + pthread_cond_signal(&cvar); + pthread_mutex_unlock(&mutex); + } + + bool try_pop(myobj *value) { + pthread_mutex_lock(&mutex); + if (q.empty()) { + pthread_mutex_unlock(&mutex); + return false; + } + if (value) { + *value = q.front(); + q.pop(); + } + pthread_mutex_unlock(&mutex); + return true; + } + + myobj wait_pop() { // blocking pop + pthread_mutex_lock(&mutex); + while(q.empty()) { + pthread_cond_wait(&cvar, &mutex); + } + myobj value = q.front(); + q.pop(); + pthread_mutex_unlock(&mutex); + return value; + } + + bool empty() const { // queue is empty? + pthread_mutex_lock(&mutex); + bool ret = q.empty(); + pthread_mutex_unlock(&mutex); + return ret; + } + + void clear() { // remove all items + myobj item; + while (try_pop(item)); + } + +private: + std::queue q; + pthread_mutex_t mutex; + pthread_cond_t cvar; +}; + +} + +#endif \ No newline at end of file diff --git a/lib/include/srslte/common/buffer_pool.h b/lib/include/srslte/common/buffer_pool.h new file mode 100644 index 000000000..eec35b79a --- /dev/null +++ b/lib/include/srslte/common/buffer_pool.h @@ -0,0 +1,169 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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 BUFFER_POOL_H +#define BUFFER_POOL_H + +#include +#include +#include +#include + +/******************************************************************************* + INCLUDES +*******************************************************************************/ + +#include "srslte/common/common.h" + +namespace srslte { + +/****************************************************************************** + * Buffer pool + * + * Preallocates a large number of buffer_t and provides allocate and + * deallocate functions. Provides quick object creation and deletion as well + * as object reuse. + * Singleton class of byte_buffer_t (but other pools of different type can be created) + *****************************************************************************/ + +template +class buffer_pool{ +public: + + // non-static methods + buffer_pool(uint32_t nof_buffers = POOL_SIZE) + { + pthread_mutex_init(&mutex, NULL); + for(uint32_t i=0;idebug_name)?used[i]->debug_name:"Undefined"); + } + } + + + buffer_t* allocate(const char *debug_name = NULL) + { + pthread_mutex_lock(&mutex); + buffer_t* b = NULL; + + if(available.size() > 0) + { + b = available.top(); + used.push_back(b); + available.pop(); + + if (available.size() < capacity/20) { + printf("Warning buffer pool capacity is %f %%\n", (float) available.size()/capacity); + } +#ifdef SRSLTE_BUFFER_POOL_LOG_ENABLED + if (debug_name) { + strncpy(b->debug_name, debug_name, SRSLTE_BUFFER_POOL_LOG_NAME_LEN); + b->debug_name[SRSLTE_BUFFER_POOL_LOG_NAME_LEN-1] = 0; + } +#endif + + } else { + printf("Error - buffer pool is empty\n"); + +#ifdef SRSLTE_BUFFER_POOL_LOG_ENABLED + print_all_buffers(); +#endif + } + + pthread_mutex_unlock(&mutex); + return b; + } + + bool deallocate(buffer_t *b) + { + bool ret = false; + pthread_mutex_lock(&mutex); + typename std::vector::iterator elem = std::find(used.begin(), used.end(), b); + if (elem != used.end()) { + used.erase(elem); + available.push(b); + ret = true; + } else { + printf("Error deallocating from buffer pool: buffer not created in this pool.\n"); + } + pthread_mutex_unlock(&mutex); + return ret; + } + + +private: + static const int POOL_SIZE = 2048; + std::stack available; + std::vector used; + pthread_mutex_t mutex; + uint32_t capacity; +}; + + +class byte_buffer_pool { +public: + // Singleton static methods + static byte_buffer_pool *instance; + static byte_buffer_pool* get_instance(void); + static void cleanup(void); + byte_buffer_pool() { + pool = new buffer_pool; + } + ~byte_buffer_pool() { + delete pool; + } + byte_buffer_t* allocate(const char *debug_name = NULL) { + return pool->allocate(debug_name); + } + void deallocate(byte_buffer_t *b) { + b->reset(); + pool->deallocate(b); + } +private: + buffer_pool *pool; +}; + + +} // namespace srsue + +#endif // BUFFER_POOL_H diff --git a/lib/include/srslte/common/common.h b/lib/include/srslte/common/common.h new file mode 100644 index 000000000..5f13ab214 --- /dev/null +++ b/lib/include/srslte/common/common.h @@ -0,0 +1,250 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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 COMMON_H +#define COMMON_H + +/******************************************************************************* + INCLUDES +*******************************************************************************/ + +#include +#include + +/******************************************************************************* + DEFINES +*******************************************************************************/ + +#define SRSLTE_UE_CATEGORY 4 + +#define SRSLTE_N_SRB 3 +#define SRSLTE_N_DRB 8 +#define SRSLTE_N_RADIO_BEARERS 11 + +// Cat 3 UE - Max number of DL-SCH transport block bits received within a TTI +// 3GPP 36.306 Table 4.1.1 +#define SRSLTE_MAX_BUFFER_SIZE_BITS 102048 +#define SRSLTE_MAX_BUFFER_SIZE_BYTES 12756 +#define SRSLTE_BUFFER_HEADER_OFFSET 1024 + +#define SRSLTE_BUFFER_POOL_LOG_ENABLED + +#ifdef SRSLTE_BUFFER_POOL_LOG_ENABLED +#define pool_allocate (pool->allocate(__FUNCTION__)) +#define SRSLTE_BUFFER_POOL_LOG_NAME_LEN 128 +#else +#define pool_allocate (pool->allocate()) +#endif + +#include "srslte/srslte.h" + +/******************************************************************************* + TYPEDEFS +*******************************************************************************/ + +namespace srslte { + +typedef enum{ + ERROR_NONE = 0, + ERROR_INVALID_PARAMS, + ERROR_INVALID_COMMAND, + ERROR_OUT_OF_BOUNDS, + ERROR_CANT_START, + ERROR_ALREADY_STARTED, + ERROR_N_ITEMS, +}error_t; +static const char error_text[ERROR_N_ITEMS][20] = { "None", + "Invalid parameters", + "Invalid command", + "Out of bounds", + "Can't start", + "Already started"}; + +typedef enum{ + RB_ID_SRB0 = 0, + RB_ID_SRB1, + RB_ID_SRB2, + RB_ID_DRB1, + RB_ID_DRB2, + RB_ID_DRB3, + RB_ID_DRB4, + RB_ID_DRB5, + RB_ID_DRB6, + RB_ID_DRB7, + RB_ID_DRB8, + RB_ID_N_ITEMS, +}rb_id_t; +static const char rb_id_text[RB_ID_N_ITEMS][20] = { "SRB0", + "SRB1", + "SRB2", + "DRB1", + "DRB2", + "DRB3", + "DRB4", + "DRB5", + "DRB6", + "DRB7", + "DRB8"}; + +/****************************************************************************** + * Byte and Bit buffers + * + * Generic buffers with headroom to accommodate packet headers and custom + * copy constructors & assignment operators for quick copying. Byte buffer + * holds a next pointer to support linked lists. + *****************************************************************************/ +class byte_buffer_t{ +public: + uint32_t N_bytes; + uint8_t buffer[SRSLTE_MAX_BUFFER_SIZE_BYTES]; + uint8_t *msg; +#ifdef SRSLTE_BUFFER_POOL_LOG_ENABLED + char debug_name[SRSLTE_BUFFER_POOL_LOG_NAME_LEN]; +#endif + + byte_buffer_t():N_bytes(0) + { + timestamp_is_set = false; + msg = &buffer[SRSLTE_BUFFER_HEADER_OFFSET]; + next = NULL; +#ifdef SRSLTE_BUFFER_POOL_LOG_ENABLED + debug_name[0] = 0; +#endif + } + byte_buffer_t(const byte_buffer_t& buf) + { + N_bytes = buf.N_bytes; + memcpy(msg, buf.msg, N_bytes); + } + byte_buffer_t & operator= (const byte_buffer_t & buf) + { + // avoid self assignment + if (&buf == this) + return *this; + N_bytes = buf.N_bytes; + memcpy(msg, buf.msg, N_bytes); + return *this; + } + void reset() + { + msg = &buffer[SRSLTE_BUFFER_HEADER_OFFSET]; + N_bytes = 0; + timestamp_is_set = false; + } + uint32_t get_headroom() + { + return msg-buffer; + } + long get_latency_us() + { + if(!timestamp_is_set) + return 0; + gettimeofday(×tamp[2], NULL); + get_time_interval(timestamp); + return timestamp[0].tv_usec; + } + + void set_timestamp() + { + gettimeofday(×tamp[1], NULL); + timestamp_is_set = true; + } + +private: + + + void get_time_interval(struct timeval * tdata) { + + tdata[0].tv_sec = tdata[2].tv_sec - tdata[1].tv_sec; + tdata[0].tv_usec = tdata[2].tv_usec - tdata[1].tv_usec; + if (tdata[0].tv_usec < 0) { + tdata[0].tv_sec--; + tdata[0].tv_usec += 1000000; + } + } + + + struct timeval timestamp[3]; + bool timestamp_is_set; + byte_buffer_t *next; +}; + +struct bit_buffer_t{ + uint32_t N_bits; + uint8_t buffer[SRSLTE_MAX_BUFFER_SIZE_BITS]; + uint8_t *msg; +#ifdef SRSLTE_BUFFER_POOL_LOG_ENABLED + char debug_name[128]; +#endif + + bit_buffer_t():N_bits(0) + { + msg = &buffer[SRSLTE_BUFFER_HEADER_OFFSET]; + } + bit_buffer_t(const bit_buffer_t& buf){ + N_bits = buf.N_bits; + memcpy(msg, buf.msg, N_bits); + } + bit_buffer_t & operator= (const bit_buffer_t & buf){ + // avoid self assignment + if (&buf == this) + return *this; + N_bits = buf.N_bits; + memcpy(msg, buf.msg, N_bits); + return *this; + } + void reset() + { + msg = &buffer[SRSLTE_BUFFER_HEADER_OFFSET]; + N_bits = 0; + timestamp_is_set = false; + } + uint32_t get_headroom() + { + return msg-buffer; + } + long get_latency_us() + { + if(!timestamp_is_set) + return 0; + gettimeofday(×tamp[2], NULL); + return timestamp[0].tv_usec; + } + void set_timestamp() + { + gettimeofday(×tamp[1], NULL); + timestamp_is_set = true; + } + +private: + struct timeval timestamp[3]; + bool timestamp_is_set; + +}; + +} // namespace srsue + +#endif // COMMON_H diff --git a/lib/include/srslte/common/config.h b/lib/include/srslte/common/config.h new file mode 100644 index 000000000..3231355fa --- /dev/null +++ b/lib/include/srslte/common/config.h @@ -0,0 +1,57 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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 CONFIG_H +#define CONFIG_H + +// Generic helper definitions for shared library support +#if defined _WIN32 || defined __CYGWIN__ + #define SRSAPPS_IMPORT __declspec(dllimport) + #define SRSAPPS_EXPORT __declspec(dllexport) + #define SRSAPPS_LOCAL +#else + #if __GNUC__ >= 4 + #define SRSAPPS_IMPORT __attribute__ ((visibility ("default"))) + #define SRSAPPS_EXPORT __attribute__ ((visibility ("default"))) + #else + #define SRSAPPS_IMPORT + #define SRSAPPS_EXPORT + #define SRSAPPS_LOCAL + #endif +#endif + +// Define SRSAPPS_API +// is used for the public API symbols. +#ifdef SRSAPPS_DLL_EXPORTS // defined if we are building the SRSAPPS DLL (instead of using it) + #define SRSAPPS_EXPORT +#else + #define SRSAPPS_IMPORT +#endif + +// cf_t definition +typedef _Complex float cf_t; + +#endif // CONFIG_H diff --git a/lib/include/srslte/common/interfaces_common.h b/lib/include/srslte/common/interfaces_common.h new file mode 100644 index 000000000..76025a64f --- /dev/null +++ b/lib/include/srslte/common/interfaces_common.h @@ -0,0 +1,52 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2017 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of srsLTE. + * + * srsUE 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. + * + * srsUE 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 INTERFACE_COMMON_H +#define INTERFACE_COMMON_H + +#include "srslte/common/timers.h" + +namespace srslte { + +class mac_interface_timers +{ +public: + /* Timer services with ms resolution. + * timer_id must be lower than MAC_NOF_UPPER_TIMERS + */ + virtual timers::timer* get(uint32_t timer_id) = 0; + virtual uint32_t get_unique_id() = 0; +}; + +class read_pdu_interface +{ +public: + virtual int read_pdu(uint32_t lcid, uint8_t *payload, uint32_t requested_bytes) = 0; +}; + +} + +#endif diff --git a/lib/include/srslte/common/liblte_security.h b/lib/include/srslte/common/liblte_security.h new file mode 100644 index 000000000..b49f7211b --- /dev/null +++ b/lib/include/srslte/common/liblte_security.h @@ -0,0 +1,270 @@ +/******************************************************************************* + + Copyright 2014 Ben Wojtowicz + + This program 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. + + This program 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. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + +******************************************************************************* + + File: liblte_security.h + + Description: Contains all the definitions for the LTE security algorithm + library. + + Revision History + ---------- ------------- -------------------------------------------- + 08/03/2014 Ben Wojtowicz Created file. + 09/03/2014 Ben Wojtowicz Added key generation and EIA2. + +*******************************************************************************/ + +#ifndef __LIBLTE_SECURITY_H__ +#define __LIBLTE_SECURITY_H__ + +/******************************************************************************* + INCLUDES +*******************************************************************************/ + +#include "srslte/asn1/liblte_common.h" + +/******************************************************************************* + DEFINES +*******************************************************************************/ + + +/******************************************************************************* + TYPEDEFS +*******************************************************************************/ + + +/******************************************************************************* + DECLARATIONS +*******************************************************************************/ + +/********************************************************************* + Name: liblte_security_generate_k_asme + + Description: Generate the security key Kasme. + + Document Reference: 33.401 v10.0.0 Annex A.2 +*********************************************************************/ +// Defines +// Enums +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_security_generate_k_asme(uint8 *ck, + uint8 *ik, + uint8 *ak, + uint8 *sqn, + uint16 mcc, + uint16 mnc, + uint8 *k_asme); + +/********************************************************************* + Name: liblte_security_generate_k_enb + + Description: Generate the security key Kenb. + + Document Reference: 33.401 v10.0.0 Annex A.2 +*********************************************************************/ +// Defines +// Enums +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_security_generate_k_enb(uint8 *k_asme, + uint32 nas_count, + uint8 *k_enb); + +/********************************************************************* + Name: liblte_security_generate_k_nas + + Description: Generate the NAS security keys KNASenc and KNASint. + + Document Reference: 33.401 v10.0.0 Annex A.2 +*********************************************************************/ +// Defines +// Enums +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_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] = {"EEA0", + "128-EEA1", + "128-EEA2"}; +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_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] = {"EIA0", + "128-EIA1", + "128-EIA2"}; +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_security_generate_k_nas(uint8 *k_asme, + LIBLTE_SECURITY_CIPHERING_ALGORITHM_ID_ENUM enc_alg_id, + LIBLTE_SECURITY_INTEGRITY_ALGORITHM_ID_ENUM int_alg_id, + uint8 *k_nas_enc, + uint8 *k_nas_int); + +/********************************************************************* + Name: liblte_security_generate_k_rrc + + Description: Generate the RRC security keys KRRCenc and KRRCint. + + Document Reference: 33.401 v10.0.0 Annex A.2 +*********************************************************************/ +// Defines +// Enums +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_security_generate_k_rrc(uint8 *k_enb, + LIBLTE_SECURITY_CIPHERING_ALGORITHM_ID_ENUM enc_alg_id, + LIBLTE_SECURITY_INTEGRITY_ALGORITHM_ID_ENUM int_alg_id, + uint8 *k_rrc_enc, + uint8 *k_rrc_int); + +/********************************************************************* + Name: liblte_security_generate_k_up + + Description: Generate the user plane security keys KUPenc and + KUPint. + + Document Reference: 33.401 v10.0.0 Annex A.2 +*********************************************************************/ +// Defines +// Enums +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_security_generate_k_up(uint8 *k_enb, + LIBLTE_SECURITY_CIPHERING_ALGORITHM_ID_ENUM enc_alg_id, + LIBLTE_SECURITY_INTEGRITY_ALGORITHM_ID_ENUM int_alg_id, + uint8 *k_up_enc, + uint8 *k_up_int); + +/********************************************************************* + Name: liblte_security_128_eia2 + + Description: 128-bit integrity algorithm EIA2. + + Document Reference: 33.401 v10.0.0 Annex B.2.3 + 33.102 v10.0.0 Section 6.5.4 + RFC4493 +*********************************************************************/ +// Defines +#define LIBLTE_SECURITY_DIRECTION_UPLINK 0 +#define LIBLTE_SECURITY_DIRECTION_DOWNLINK 1 +// Enums +// Structs +// Functions +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); + +/********************************************************************* + Name: liblte_security_milenage_f1 + + Description: Milenage security function F1. Computes network + authentication code MAC-A from key K, random + challenge RAND, sequence number SQN, and + authentication management field AMF. + + Document Reference: 35.206 v10.0.0 Annex 3 +*********************************************************************/ +// Defines +// Enums +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_security_milenage_f1(uint8 *k, + uint8 *op, + uint8 *rand, + uint8 *sqn, + uint8 *amf, + uint8 *mac_a); + +/********************************************************************* + Name: liblte_security_milenage_f1_star + + Description: Milenage security function F1*. Computes resynch + authentication code MAC-S from key K, random + challenge RAND, sequence number SQN, and + authentication management field AMF. + + Document Reference: 35.206 v10.0.0 Annex 3 +*********************************************************************/ +// Defines +// Enums +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_security_milenage_f1_star(uint8 *k, + uint8 *op, + uint8 *rand, + uint8 *sqn, + uint8 *amf, + uint8 *mac_s); + +/********************************************************************* + Name: liblte_security_milenage_f2345 + + Description: Milenage security functions F2, F3, F4, and F5. + Computes response RES, confidentiality key CK, + integrity key IK, and anonymity key AK from random + challenge RAND. + + Document Reference: 35.206 v10.0.0 Annex 3 +*********************************************************************/ +// Defines +// Enums +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_security_milenage_f2345(uint8 *k, + uint8 *op, + uint8 *rand, + uint8 *res, + uint8 *ck, + uint8 *ik, + uint8 *ak); + +/********************************************************************* + Name: liblte_security_milenage_f5_star + + Description: Milenage security function F5*. Computes resynch + anonymity key AK from key K and random challenge + RAND. + + Document Reference: 35.206 v10.0.0 Annex 3 +*********************************************************************/ +// Defines +// Enums +// Structs +// Functions +LIBLTE_ERROR_ENUM liblte_security_milenage_f5_star(uint8 *k, + uint8 *op, + uint8 *rand, + uint8 *ak); + +#endif /* __LIBLTE_SECURITY_H__ */ diff --git a/lib/include/srslte/common/liblte_ssl.h b/lib/include/srslte/common/liblte_ssl.h new file mode 100644 index 000000000..886d557b1 --- /dev/null +++ b/lib/include/srslte/common/liblte_ssl.h @@ -0,0 +1,53 @@ +#ifndef __LIBLTE_SSL_H__ +#define __LIBLTE_SSL_H__ + +#ifdef HAVE_POLARSSL + +#include "polarssl/sha256.h" +#include "polarssl/aes.h" + +void sha256(const unsigned char *key, size_t keylen, + const unsigned char *input, size_t ilen, + unsigned char output[32], int is224 ) +{ + sha256_hmac(key, keylen, input, ilen, output, is224); +} + +#endif // HAVE_POLARSSL + +#ifdef HAVE_MBEDTLS + +#include "mbedtls/md.h" +#include "mbedtls/aes.h" + +typedef mbedtls_aes_context aes_context; + +#define AES_ENCRYPT 1 +#define AES_DECRYPT 0 + +int aes_setkey_enc( aes_context *ctx, const unsigned char *key, unsigned int keysize ) +{ + return mbedtls_aes_setkey_enc(ctx, key, keysize); +} + +int aes_crypt_ecb( aes_context *ctx, + int mode, + const unsigned char input[16], + unsigned char output[16] ) +{ + return mbedtls_aes_crypt_ecb(ctx, mode, input, output); +} + +void sha256(const unsigned char *key, size_t keylen, + const unsigned char *input, size_t ilen, + unsigned char output[32], int is224 ) +{ + mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), + key, keylen, + input, ilen, + output ); +} + +#endif // HAVE_MBEDTLS + +#endif // __LIBLTE_SSL_H__ diff --git a/lib/include/srslte/common/log.h b/lib/include/srslte/common/log.h new file mode 100644 index 000000000..9bec779df --- /dev/null +++ b/lib/include/srslte/common/log.h @@ -0,0 +1,127 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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: log.h + * + * Description: Abstract logging service + * + * Reference: + *****************************************************************************/ + +#ifndef LOG_H +#define LOG_H + +#include +#include + +namespace srslte { + +typedef enum { + LOG_LEVEL_NONE = 0, + LOG_LEVEL_ERROR, + LOG_LEVEL_WARNING, + LOG_LEVEL_INFO, + LOG_LEVEL_DEBUG, + LOG_LEVEL_N_ITEMS +} LOG_LEVEL_ENUM; +static const char log_level_text[LOG_LEVEL_N_ITEMS][16] = {"None ", + "Error ", + "Warning", + "Info ", + "Debug "}; + +class log +{ +public: + + log() { + service_name = ""; + tti = 0; + level = LOG_LEVEL_NONE; + hex_limit = 0; + } + + log(std::string service_name_) { + service_name = service_name_; + tti = 0; + level = LOG_LEVEL_NONE; + hex_limit = 0; + } + + // This function shall be called at the start of every tti for printing tti + void step(uint32_t tti_) { + tti = tti_; + } + uint32_t get_tti() { + return tti; + } + + void set_level(LOG_LEVEL_ENUM l) { + level = l; + } + LOG_LEVEL_ENUM get_level() { + return level; + } + + void set_hex_limit(int limit) { + hex_limit = limit; + } + int get_hex_limit() { + return hex_limit; + } + + // Pure virtual methods for logging + virtual void console(std::string message, ...) = 0; + virtual void error(std::string message, ...) = 0; + virtual void warning(std::string message, ...) = 0; + virtual void info(std::string message, ...) = 0; + virtual void debug(std::string message, ...) = 0; + + // Same with hex dump + virtual void error_hex(uint8_t *hex, int size, std::string message, ...){error("error_hex not implemented.\n");} + virtual void warning_hex(uint8_t *hex, int size, std::string message, ...){error("warning_hex not implemented.\n");} + virtual void info_hex(uint8_t *hex, int size, std::string message, ...){error("info_hex not implemented.\n");} + virtual void debug_hex(uint8_t *hex, int size, std::string message, ...){error("debug_hex not implemented.\n");} + + // Same with line and file info + virtual void error_line(std::string file, int line, std::string message, ...){error("error_line not implemented.\n");} + virtual void warning_line(std::string file, int line, std::string message, ...){error("warning_line not implemented.\n");} + virtual void info_line(std::string file, int line, std::string message, ...){error("info_line not implemented.\n");} + virtual void debug_line(std::string file, int line, std::string message, ...){error("debug_line not implemented.\n");} + +protected: + std::string get_service_name() { return service_name; } + uint32_t tti; + LOG_LEVEL_ENUM level; + int hex_limit; + std::string service_name; +}; + +} // namespace srslte + +#endif // LOG_H + diff --git a/lib/include/srslte/common/log_filter.h b/lib/include/srslte/common/log_filter.h new file mode 100644 index 000000000..c1ed1998a --- /dev/null +++ b/lib/include/srslte/common/log_filter.h @@ -0,0 +1,83 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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: log_filter.h + * Description: Log filter for a specific layer or element. + * Performs filtering based on log level, generates + * timestamped log strings and passes them to the + * common logger object. + *****************************************************************************/ + +#ifndef LOG_FILTER_H +#define LOG_FILTER_H + +#include +#include +#include "srslte/common/log.h" +#include "logger.h" + +namespace srslte { + +class log_filter : public srslte::log +{ +public: + + log_filter(); + log_filter(std::string layer, logger *logger_, bool tti=false); + + void init(std::string layer, logger *logger_, bool tti=false); + + void console(std::string message, ...); + void error(std::string message, ...); + void warning(std::string message, ...); + void info(std::string message, ...); + void debug(std::string message, ...); + + void error_hex(uint8_t *hex, int size, std::string message, ...); + void warning_hex(uint8_t *hex, int size, std::string message, ...); + void info_hex(uint8_t *hex, int size, std::string message, ...); + void debug_hex(uint8_t *hex, int size, std::string message, ...); + + void error_line(std::string file, int line, std::string message, ...); + void warning_line(std::string file, int line, std::string message, ...); + void info_line(std::string file, int line, std::string message, ...); + void debug_line(std::string file, int line, std::string message, ...); + +private: + logger *logger_h; + bool do_tti; + + void all_log(srslte::LOG_LEVEL_ENUM level, uint32_t tti, char *msg); + void all_log(srslte::LOG_LEVEL_ENUM level, uint32_t tti, char *msg, 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(); + std::string hex_string(uint8_t *hex, int size); +}; + +} // namespace srsue + +#endif // LOG_FILTER_H diff --git a/lib/include/srslte/common/log_stdout.h b/lib/include/srslte/common/log_stdout.h new file mode 100644 index 000000000..df1b5b5fb --- /dev/null +++ b/lib/include/srslte/common/log_stdout.h @@ -0,0 +1,82 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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: log_stout.h + * + * Description: Logging service through standard output. Inherits log interface + * + * Reference: + *****************************************************************************/ + +#ifndef LOGSTDOUT_H +#define LOGSTDOUT_H + +#include +#include +#include "srslte/common/log.h" + +namespace srslte { + +class log_stdout : public log +{ +public: + + log_stdout(std::string service_name_) : log(service_name_) { } + + void console(std::string message, ...); + void error(std::string message, ...); + void warning(std::string message, ...); + void info(std::string message, ...); + void debug(std::string message, ...); + + // Same with hex dump + void error_hex(uint8_t *hex, int size, std::string message, ...); + void warning_hex(uint8_t *hex, int size, std::string message, ...); + void info_hex(uint8_t *hex, int size, std::string message, ...); + void debug_hex(uint8_t *hex, int size, std::string message, ...); + + // Same with line and file info + void error_line(std::string file, int line, std::string message, ...); + void warning_line(std::string file, int line, std::string message, ...); + void info_line(std::string file, int line, std::string message, ...); + void debug_line(std::string file, int line, std::string message, ...); + +private: + void printlog(srslte::LOG_LEVEL_ENUM level, uint32_t tti, std::string file, int line, std::string message, va_list args); + void printlog(srslte::LOG_LEVEL_ENUM level, uint32_t tti, std::string message, va_list args); + + void all_log(srslte::LOG_LEVEL_ENUM level, uint32_t tti, char *msg); + void all_log(srslte::LOG_LEVEL_ENUM level, uint32_t tti, char *msg, 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(); + std::string hex_string(uint8_t *hex, int size); +}; + +} + +#endif + diff --git a/lib/include/srslte/common/logger.h b/lib/include/srslte/common/logger.h new file mode 100644 index 000000000..67a897824 --- /dev/null +++ b/lib/include/srslte/common/logger.h @@ -0,0 +1,74 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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: logger.h + * Description: Common log object. Maintains a queue of log messages + * and runs a thread to read messages and write to file. + * Multiple producers, single consumer. If full, producers + * increase queue size. If empty, consumer blocks. + *****************************************************************************/ + +#ifndef LOGGER_H +#define LOGGER_H + +#include +#include +#include +#include "srslte/common/threads.h" + +namespace srslte { + +typedef std::string* str_ptr; + +class logger : public thread +{ +public: + logger(); + logger(std::string file); + ~logger(); + void init(std::string file); + void log(const char *msg); + void log(str_ptr msg); + +private: + void run_thread(); + void flush(); + + FILE* logfile; + bool inited; + bool not_done; + std::string filename; + pthread_cond_t not_empty; + pthread_cond_t not_full; + pthread_mutex_t mutex; + pthread_t thread; + std::deque buffer; +}; + +} // namespace srsue + +#endif // LOGGER_H diff --git a/lib/include/srslte/common/mac_pcap.h b/lib/include/srslte/common/mac_pcap.h new file mode 100644 index 000000000..f441e1aed --- /dev/null +++ b/lib/include/srslte/common/mac_pcap.h @@ -0,0 +1,61 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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 MACPCAP_H +#define MACPCAP_H + +#include +#include "srslte/common/pcap.h" + +namespace srslte { + +class mac_pcap +{ +public: + mac_pcap() {enable_write=false; ue_id=0; pcap_file = NULL; }; + void enable(bool en); + void open(const char *filename, uint32_t ue_id = 0); + void close(); + void write_ul_crnti(uint8_t *pdu, uint32_t pdu_len_bytes, uint16_t crnti, uint32_t reTX, uint32_t tti); + void write_dl_crnti(uint8_t *pdu, uint32_t pdu_len_bytes, uint16_t crnti, bool crc_ok, uint32_t tti); + void write_dl_ranti(uint8_t *pdu, uint32_t pdu_len_bytes, uint16_t ranti, bool crc_ok, uint32_t tti); + + // SI and BCH only for DL + void write_dl_sirnti(uint8_t *pdu, uint32_t pdu_len_bytes, bool crc_ok, uint32_t tti); + void write_dl_bch(uint8_t *pdu, uint32_t pdu_len_bytes, bool crc_ok, uint32_t tti); + void write_dl_pch(uint8_t *pdu, uint32_t pdu_len_bytes, bool crc_ok, uint32_t tti); + +private: + bool enable_write; + FILE *pcap_file; + uint32_t ue_id; + void pack_and_write(uint8_t* pdu, uint32_t pdu_len_bytes, uint32_t reTX, bool crc_ok, uint32_t tti, + uint16_t crnti_, uint8_t direction, uint8_t rnti_type); +}; + +} // namespace srsue + +#endif // MACPCAP_H diff --git a/lib/include/srslte/common/metrics_hub.h b/lib/include/srslte/common/metrics_hub.h new file mode 100644 index 000000000..8443ef65a --- /dev/null +++ b/lib/include/srslte/common/metrics_hub.h @@ -0,0 +1,61 @@ + +/****************************************************************************** + * File: metrics_hub.h + * Description: Centralizes metrics interfaces to allow different metrics clients + * to get metrics + *****************************************************************************/ + +#ifndef METRICS_HUB_H +#define METRICS_HUB_H + +#include +#include "srslte/common/threads.h" + +namespace srslte { + +template +class metrics_interface +{ +public: + virtual bool get_metrics(metrics_t &m) = 0; +}; + +template +class metrics_listener +{ +public: + virtual void set_metrics(metrics_t &m) = 0; +}; + +template +class metrics_hub : public periodic_thread +{ +public: + bool init(metrics_interface *m_, float report_period_secs=1.0) { + m = m_; + start_periodic(report_period_secs*1e6); + } + void stop() { + thread_cancel(); + } + + void add_listener(metrics_listener *listener) { + listeners.push_back(listener); + } + +private: + void run_period() { + metrics_t metric; + m->get_metrics(metric); + for (int i=0;iset_metrics(metric); + } + } + metrics_interface *m; + std::vector*> listeners; + +}; + +} // namespace srslte + +#endif // METRICS_HUB_H diff --git a/lib/include/srslte/common/msg_queue.h b/lib/include/srslte/common/msg_queue.h new file mode 100644 index 000000000..bca4c5388 --- /dev/null +++ b/lib/include/srslte/common/msg_queue.h @@ -0,0 +1,152 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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: msg_queue.h + * Description: Thread-safe bounded circular buffer of srsue_byte_buffer pointers. + * Reference: + *****************************************************************************/ + +#ifndef MSG_QUEUE_H +#define MSG_QUEUE_H + +#include "srslte/common/common.h" +#include + +namespace srslte { + +class msg_queue +{ +public: + msg_queue(uint32_t capacity_ = 128) + :head(0) + ,tail(0) + ,unread(0) + ,unread_bytes(0) + ,capacity(capacity_) + { + buf = new byte_buffer_t*[capacity]; + pthread_mutex_init(&mutex, NULL); + pthread_cond_init(¬_empty, NULL); + pthread_cond_init(¬_full, NULL); + } + + ~msg_queue() + { + delete [] buf; + } + + void write(byte_buffer_t *msg) + { + pthread_mutex_lock(&mutex); + while(is_full()) { + pthread_cond_wait(¬_full, &mutex); + } + buf[head] = msg; + head = (head+1)%capacity; + unread++; + unread_bytes += msg->N_bytes; + + pthread_cond_signal(¬_empty); + pthread_mutex_unlock(&mutex); + } + + void read(byte_buffer_t **msg) + { + pthread_mutex_lock(&mutex); + while(is_empty()) { + pthread_cond_wait(¬_empty, &mutex); + } + *msg = buf[tail]; + tail = (tail+1)%capacity; + unread--; + unread_bytes -= (*msg)->N_bytes; + + pthread_cond_signal(¬_full); + pthread_mutex_unlock(&mutex); + } + + bool try_read(byte_buffer_t **msg) + { + pthread_mutex_lock(&mutex); + if(is_empty()) + { + pthread_mutex_unlock(&mutex); + return false; + }else{ + *msg = buf[tail]; + tail = (tail+1)%capacity; + unread--; + unread_bytes -= (*msg)->N_bytes; + pthread_cond_signal(¬_full); + pthread_mutex_unlock(&mutex); + return true; + } + } + + uint32_t size() + { + pthread_mutex_lock(&mutex); + uint32_t r = unread; + pthread_mutex_unlock(&mutex); + return r; + } + + uint32_t size_bytes() + { + pthread_mutex_lock(&mutex); + uint32_t r = unread_bytes; + pthread_mutex_unlock(&mutex); + return r; + } + + uint32_t size_tail_bytes() + { + pthread_mutex_lock(&mutex); + uint32_t r = buf[tail]->N_bytes; + pthread_mutex_unlock(&mutex); + return r; + } + +private: + bool is_empty() const { return unread == 0; } + bool is_full() const { return unread == capacity; } + + pthread_cond_t not_empty; + pthread_cond_t not_full; + pthread_mutex_t mutex; + byte_buffer_t **buf; + uint32_t capacity; + uint32_t unread; + uint32_t unread_bytes; + uint32_t head; + uint32_t tail; +}; + +} // namespace srsue + + +#endif // MSG_QUEUE_H diff --git a/lib/include/srslte/common/pcap.h b/lib/include/srslte/common/pcap.h new file mode 100644 index 000000000..d9937c060 --- /dev/null +++ b/lib/include/srslte/common/pcap.h @@ -0,0 +1,218 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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 UEPCAP_H +#define UEPCAP_H + +#include +#include +#include +#include + +#define MAC_LTE_DLT 147 + + +/* This structure gets written to the start of the file */ +typedef struct pcap_hdr_s { + unsigned int magic_number; /* magic number */ + unsigned short version_major; /* major version number */ + unsigned short version_minor; /* minor version number */ + unsigned int thiszone; /* GMT to local correction */ + unsigned int sigfigs; /* accuracy of timestamps */ + unsigned int snaplen; /* max length of captured packets, in octets */ + unsigned int network; /* data link type */ +} pcap_hdr_t; + +/* This structure precedes each packet */ +typedef struct pcaprec_hdr_s { + unsigned int ts_sec; /* timestamp seconds */ + unsigned int ts_usec; /* timestamp microseconds */ + unsigned int incl_len; /* number of octets of packet saved in file */ + unsigned int orig_len; /* actual length of packet */ +} pcaprec_hdr_t; + + +/* radioType */ +#define FDD_RADIO 1 +#define TDD_RADIO 2 + +/* Direction */ +#define DIRECTION_UPLINK 0 +#define DIRECTION_DOWNLINK 1 + +/* rntiType */ +#define NO_RNTI 0 /* Used for BCH-BCH */ +#define P_RNTI 1 +#define RA_RNTI 2 +#define C_RNTI 3 +#define SI_RNTI 4 +#define SPS_RNTI 5 +#define M_RNTI 6 + +#define MAC_LTE_START_STRING "mac-lte" + +#define MAC_LTE_RNTI_TAG 0x02 +/* 2 bytes, network order */ + +#define MAC_LTE_UEID_TAG 0x03 +/* 2 bytes, network order */ + +#define MAC_LTE_SUBFRAME_TAG 0x04 +/* 2 bytes, network order */ + +#define MAC_LTE_PREDFINED_DATA_TAG 0x05 +/* 1 byte */ + +#define MAC_LTE_RETX_TAG 0x06 +/* 1 byte */ + +#define MAC_LTE_CRC_STATUS_TAG 0x07 +/* 1 byte */ + +/* MAC PDU. Following this tag comes the actual MAC PDU (there is no length, the PDU + continues until the end of the frame) */ +#define MAC_LTE_PAYLOAD_TAG 0x01 + + +/* Context information for every MAC PDU that will be logged */ +typedef struct MAC_Context_Info_t { + unsigned short radioType; + unsigned char direction; + unsigned char rntiType; + unsigned short rnti; + unsigned short ueid; + unsigned char isRetx; + unsigned char crcStatusOK; + + unsigned short sysFrameNumber; + unsigned short subFrameNumber; + +} MAC_Context_Info_t; + + + + +/**************************************************************************/ +/* API functions for opening/writing/closing MAC-LTE PCAP files */ + +/* Open the file and write file header */ +inline FILE *MAC_LTE_PCAP_Open(const char *fileName) +{ + pcap_hdr_t file_header = + { + 0xa1b2c3d4, /* magic number */ + 2, 4, /* version number is 2.4 */ + 0, /* timezone */ + 0, /* sigfigs - apparently all tools do this */ + 65535, /* snaplen - this should be long enough */ + MAC_LTE_DLT /* Data Link Type (DLT). Set as unused value 147 for now */ + }; + + FILE *fd = fopen(fileName, "w"); + if (fd == NULL) { + printf("Failed to open file \"%s\" for writing\n", fileName); + return NULL; + } + + /* Write the file header */ + fwrite(&file_header, sizeof(pcap_hdr_t), 1, fd); + + return fd; +} + +/* Write an individual PDU (PCAP packet header + mac-context + mac-pdu) */ +inline int MAC_LTE_PCAP_WritePDU(FILE *fd, MAC_Context_Info_t *context, + const unsigned char *PDU, unsigned int length) +{ + pcaprec_hdr_t packet_header; + char context_header[256]; + int offset = 0; + unsigned short tmp16; + + /* Can't write if file wasn't successfully opened */ + if (fd == NULL) { + printf("Error: Can't write to empty file handle\n"); + return 0; + } + + /*****************************************************************/ + /* 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; + + /* Subframe number */ + context_header[offset++] = MAC_LTE_SUBFRAME_TAG; + tmp16 = htons(context->subFrameNumber); + memcpy(context_header+offset, &tmp16, 2); + offset += 2; + + /* CRC Status */ + context_header[offset++] = MAC_LTE_CRC_STATUS_TAG; + context_header[offset++] = context->crcStatusOK; + + /* Data tag immediately preceding PDU */ + context_header[offset++] = MAC_LTE_PAYLOAD_TAG; + + + /****************************************************************/ + /* PCAP Header */ + struct timeval t; + gettimeofday(&t, NULL); + 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; +} + +/* Close the PCAP file */ +inline void MAC_LTE_PCAP_Close(FILE *fd) +{ + if(fd) + fclose(fd); +} + +#endif /* UEPCAP_H */ \ No newline at end of file diff --git a/lib/include/srslte/common/pdu.h b/lib/include/srslte/common/pdu.h new file mode 100644 index 000000000..c3eb68ca7 --- /dev/null +++ b/lib/include/srslte/common/pdu.h @@ -0,0 +1,339 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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 MACPDU_H +#define MACPDU_H + +#include +#include "srslte/common/log.h" +#include "srslte/common/interfaces_common.h" +#include +#include + +/* MAC PDU Packing/Unpacking functions. Section 6 of 36.321 */ + + +namespace srslte { + +template +class pdu +{ +public: + + pdu(uint32_t max_subheaders_) : subheaders(max_subheaders_) { + max_subheaders = max_subheaders_; + nof_subheaders = 0; + cur_idx = -1; + pdu_len = 0; + rem_len = 0; + last_sdu_idx = -1; + pdu_is_ul = false; + buffer_tx = NULL; + total_sdu_len = 0; + } + + void fprint(FILE *stream) { + fprintf(stream, "Number of Subheaders: %d\n", nof_subheaders); + for (int i=0;i 0) { + nof_subheaders++; + next(); + return true; + } else { + return false; + } + } + + bool next() { + if (cur_idx < nof_subheaders - 1) { + cur_idx++; + return true; + } else { + return false; + } + } + + void del_subh() { + if (nof_subheaders > 0) { + nof_subheaders--; + } + if (cur_idx > 0) { + cur_idx--; + } + } + + SubH* get() { + if (cur_idx >= 0) { + return &subheaders[cur_idx]; + } else { + return NULL; + } + } + + bool is_ul() { + return pdu_is_ul; + } + + uint8_t* get_current_sdu_ptr() { + return &buffer_tx[total_sdu_len+sdu_offset_start]; + } + + void add_sdu(uint32_t sdu_sz) { + total_sdu_len += sdu_sz; + } + + // Section 6.1.2 + void parse_packet(uint8_t *ptr) { + uint8_t *init_ptr = ptr; + nof_subheaders = 0; + while(subheaders[nof_subheaders].read_subheader(&ptr)) { + nof_subheaders++; + } + nof_subheaders++; + for (int i=0;i subheaders; + uint32_t pdu_len; + uint32_t rem_len; + int cur_idx; + int nof_subheaders; + uint32_t max_subheaders; + bool pdu_is_ul; + uint8_t* buffer_tx; + uint32_t total_sdu_len; + uint32_t sdu_offset_start; + int last_sdu_idx; + +private: + + /* Prepares the PDU for parsing or writing by setting the number of subheaders to 0 and the pdu length */ + void init_(uint8_t *buffer_tx_ptr, uint32_t pdu_len_bytes, bool is_ulsch) { + nof_subheaders = 0; + pdu_len = pdu_len_bytes; + rem_len = pdu_len; + pdu_is_ul = is_ulsch; + buffer_tx = buffer_tx_ptr; + sdu_offset_start = max_subheaders*2 + 13; // Assuming worst-case 2 bytes per sdu subheader + all possible CE + total_sdu_len = 0; + last_sdu_idx = -1; + reset(); + for (uint32_t i=0;i +class subh +{ +public: + + virtual bool read_subheader(uint8_t** ptr) = 0; + virtual void read_payload(uint8_t **ptr) = 0; + virtual void write_subheader(uint8_t** ptr, bool is_last) = 0; + virtual void write_payload(uint8_t **ptr) = 0; + virtual void fprint(FILE *stream) = 0; + + pdu* parent; +private: + virtual void init() = 0; +}; + + + +class sch_subh : public subh +{ + +public: + + typedef enum { + PHR_REPORT = 26, + CRNTI = 27, + CON_RES_ID = 28, + TRUNC_BSR = 28, + TA_CMD = 29, + SHORT_BSR = 29, + DRX_CMD = 30, + LONG_BSR = 30, + PADDING = 31, + SDU = 0 + } cetype; + + // Size of MAC CEs + const static int MAC_CE_CONTRES_LEN = 6; + + // Reading functions + bool is_sdu(); + cetype ce_type(); + uint32_t size_plus_header(); + void set_payload_size(uint32_t size); + + bool read_subheader(uint8_t** ptr); + void read_payload(uint8_t **ptr); + uint32_t get_sdu_lcid(); + uint32_t get_payload_size(); + uint32_t get_header_size(bool is_last); + uint8_t* get_sdu_ptr(); + + uint16_t get_c_rnti(); + uint64_t get_con_res_id(); + uint8_t get_ta_cmd(); + float get_phr(); + int get_bsr(uint32_t buff_size[4]); + + // Writing functions + void write_subheader(uint8_t** ptr, bool is_last); + void write_payload(uint8_t **ptr); + int set_sdu(uint32_t lcid, uint32_t nof_bytes, uint8_t *payload); + int set_sdu(uint32_t lcid, uint32_t requested_bytes, read_pdu_interface *sdu_itf); + bool set_c_rnti(uint16_t crnti); + bool set_bsr(uint32_t buff_size[4], sch_subh::cetype format); + bool set_con_res_id(uint64_t con_res_id); + bool set_ta_cmd(uint8_t ta_cmd); + bool set_phr(float phr); + void set_padding(); + void set_padding(uint32_t padding_len); + + void init(); + void fprint(FILE *stream); + + +private: + static const int MAX_CE_PAYLOAD_LEN = 8; + uint32_t lcid; + int nof_bytes; + uint8_t* payload; + uint8_t w_payload_ce[8]; + bool F_bit; + uint32_t sizeof_ce(uint32_t lcid, bool is_ul); + static uint8_t buff_size_table(uint32_t buffer_size); + static uint8_t phr_report_table(float phr_value); +}; + +class sch_pdu : public pdu +{ +public: + + sch_pdu(uint32_t max_subh) : pdu(max_subh) {} + + void parse_packet(uint8_t *ptr); + uint8_t* write_packet(); + uint8_t* write_packet(srslte::log *log_h); + bool has_space_ce(uint32_t nbytes); + bool has_space_sdu(uint32_t nbytes); + int get_pdu_len(); + int rem_size(); + int get_sdu_space(); + + static uint32_t size_header_sdu(uint32_t nbytes); + bool update_space_ce(uint32_t nbytes); + bool update_space_sdu(uint32_t nbytes); + void fprint(FILE *stream); +}; + +class rar_subh : public subh +{ +public: + + static const uint32_t RAR_GRANT_LEN = 20; + + // Reading functions + bool read_subheader(uint8_t** ptr); + void read_payload(uint8_t** ptr); + uint32_t get_rapid(); + uint32_t get_ta_cmd(); + uint16_t get_temp_crnti(); + void get_sched_grant(uint8_t grant[RAR_GRANT_LEN]); + + // Writing functoins + void write_subheader(uint8_t** ptr, bool is_last); + void write_payload(uint8_t** ptr); + void set_rapid(uint32_t rapid); + void set_ta_cmd(uint32_t ta); + void set_temp_crnti(uint16_t temp_rnti); + void set_sched_grant(uint8_t grant[RAR_GRANT_LEN]); + + void init(); + void fprint(FILE *stream); + +private: + uint8_t grant[RAR_GRANT_LEN]; + uint32_t ta; + uint16_t temp_rnti; + uint32_t preamble; +}; + +class rar_pdu : public pdu +{ +public: + + rar_pdu(uint32_t max_rars = 16); + + void set_backoff(uint8_t bi); + bool has_backoff(); + uint8_t get_backoff(); + + bool write_packet(uint8_t* ptr); + void fprint(FILE *stream); + +private: + bool has_backoff_indicator; + uint8_t backoff_indicator; +}; + +} // namespace srsue + +#endif // MACPDU_H diff --git a/lib/include/srslte/common/pdu_queue.h b/lib/include/srslte/common/pdu_queue.h new file mode 100644 index 000000000..40e0f2dd2 --- /dev/null +++ b/lib/include/srslte/common/pdu_queue.h @@ -0,0 +1,85 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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 PDUPROC_H +#define PDUPROC_H + +#include "srslte/common/log.h" +#include "srslte/common/block_queue.h" +#include "srslte/common/buffer_pool.h" +#include "srslte/common/timers.h" +#include "srslte/common/pdu.h" + +/* Logical Channel Demultiplexing and MAC CE dissassemble */ + + +namespace srslte { + +class pdu_queue +{ +public: + class process_callback + { + public: + virtual void process_pdu(uint8_t *buff, uint32_t len, uint32_t tstamp) = 0; + }; + + pdu_queue(uint32_t pool_size = DEFAULT_POOL_SIZE) : pool(pool_size), callback(NULL), log_h(NULL) {} + void init(process_callback *callback, log* log_h_); + + uint8_t* request(uint32_t len); + void deallocate(uint8_t* pdu); + void push(uint8_t *ptr, uint32_t len, uint32_t tstamp = 0); + + bool process_pdus(); + +private: + const static int DEFAULT_POOL_SIZE = 64; // Number of PDU buffers in total + const static int MAX_PDU_LEN = 150*1024/8; // ~ 150 Mbps + + typedef struct { + uint8_t ptr[MAX_PDU_LEN]; + uint32_t len; + uint32_t tstamp; + #ifdef SRSLTE_BUFFER_POOL_LOG_ENABLED + char debug_name[128]; + #endif + + } pdu_t; + + block_queue pdu_q; + buffer_pool pool; + + process_callback *callback; + log *log_h; +}; + +} // namespace srslte + +#endif // PDUPROC_H + + + diff --git a/lib/include/srslte/common/security.h b/lib/include/srslte/common/security.h new file mode 100644 index 000000000..080f1848f --- /dev/null +++ b/lib/include/srslte/common/security.h @@ -0,0 +1,151 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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 SECURITY_H +#define SECURITY_H + +/****************************************************************************** + * Common security header - wraps ciphering/integrity check algorithms. + *****************************************************************************/ + + +#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"}; + + +/****************************************************************************** + * Key Generation + *****************************************************************************/ + +uint8_t security_generate_k_asme( uint8_t *ck, + uint8_t *ik, + uint8_t *ak, + uint8_t *sqn, + uint16_t mcc, + uint16_t mnc, + uint8_t *k_asme); + +uint8_t security_generate_k_enb( uint8_t *k_asme, + uint32_t nas_count, + uint8_t *k_enb); + +uint8_t security_generate_k_nas( uint8_t *k_asme, + CIPHERING_ALGORITHM_ID_ENUM enc_alg_id, + INTEGRITY_ALGORITHM_ID_ENUM int_alg_id, + uint8_t *k_nas_enc, + uint8_t *k_nas_int); + +uint8_t security_generate_k_rrc( uint8_t *k_enb, + CIPHERING_ALGORITHM_ID_ENUM enc_alg_id, + INTEGRITY_ALGORITHM_ID_ENUM int_alg_id, + uint8_t *k_rrc_enc, + uint8_t *k_rrc_int); + +uint8_t security_generate_k_up( uint8_t *k_enb, + CIPHERING_ALGORITHM_ID_ENUM enc_alg_id, + INTEGRITY_ALGORITHM_ID_ENUM int_alg_id, + uint8_t *k_up_enc, + uint8_t *k_up_int); + +/****************************************************************************** + * Integrity Protection + *****************************************************************************/ + +uint8_t security_128_eia1( uint8_t *key, + uint32_t count, + uint8_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, + uint8_t bearer, + uint8_t direction, + uint8_t *msg, + uint32_t msg_len, + uint8_t *mac); + +/****************************************************************************** + * Authentication + *****************************************************************************/ + +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 srsue + +#endif // SECURITY_H diff --git a/lib/include/srslte/common/snow_3g.h b/lib/include/srslte/common/snow_3g.h new file mode 100644 index 000000000..c20e6a626 --- /dev/null +++ b/lib/include/srslte/common/snow_3g.h @@ -0,0 +1,71 @@ +/*--------------------------------------------------------- +* snow_3g.h +* +* Adapted from ETSI/SAGE specifications: +* "Specification of the 3GPP Confidentiality and +* Integrity Algorithms UEA2 & UIA2. +* Document 1: UEA2 and UIA2 Specification" +* "Specification of the 3GPP Confidentiality +* and Integrity Algorithms UEA2 & UIA2. +* Document 2: SNOW 3G Specification" +*---------------------------------------------------------*/ + +#include +#include +#include +#include + +typedef unsigned char u8; +typedef unsigned int u32; +typedef unsigned long long u64; + +/* Initialization. +* Input k[4]: Four 32-bit words making up 128-bit key. +* Input IV[4]: Four 32-bit words making 128-bit initialization variable. +* Output: All the LFSRs and FSM are initialized for key generation. +* See Section 4.1. +*/ + +void snow3g_initialize(u32 k[4], u32 IV[4]); + +/* Generation of Keystream. +* input n: number of 32-bit words of keystream. +* input z: space for the generated keystream, assumes +* memory is allocated already. +* output: generated keystream which is filled in z +* See section 4.2. +*/ + +void snow3g_generate_keystream(u32 n, u32 *z); + +/* f8. +* Input key: 128 bit Confidentiality Key. +* Input count:32-bit Count, Frame dependent input. +* Input bearer: 5-bit Bearer identity (in the LSB side). +* Input dir:1 bit, direction of transmission. +* Input data: length number of bits, input bit stream. +* Input length: 32 bit Length, i.e., the number of bits to be encrypted or +* decrypted. +* Output data: Output bit stream. Assumes data is suitably memory +* allocated. +* Encrypts/decrypts blocks of data between 1 and 2^32 bits in length as +* defined in Section 3. +*/ + +void snow3g_f8( u8 *key, u32 count, u32 bearer, u32 dir, \ + u8 *data, u32 length ); + +/* f9. +* Input key: 128 bit Integrity Key. +* Input count:32-bit Count, Frame dependent input. +* Input fresh: 32-bit Random number. +* Input dir:1 bit, direction of transmission (in the LSB). +* Input data: length number of bits, input bit stream. +* Input length: 64 bit Length, i.e., the number of bits to be MAC'd. +* Output : 32 bit block used as MAC +* Generates 32-bit MAC using UIA2 algorithm as defined in Section 4. +*/ + +u8* snow3g_f9( u8* key, u32 count, u32 fresh, u32 dir, \ + u8 *data, u64 length); + diff --git a/lib/include/srslte/common/task_dispatcher.h b/lib/include/srslte/common/task_dispatcher.h new file mode 100644 index 000000000..5a86fc311 --- /dev/null +++ b/lib/include/srslte/common/task_dispatcher.h @@ -0,0 +1,61 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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: task_dispatcher.h + * Description: + * Reference: + *****************************************************************************/ + +#ifndef TASK_DISPATCHER_H +#define TASK_DISPATCHER_H + +#include +#include +#include +#include +#include "srslte/common/threads.h" + +namespace srslte { + +class task_dispatcher : public thread +{ +public: + task_dispatcher(uint32_t max_pending_tasks); + ~task_dispatcher(); + void push_task(uint32_t task_code); + virtual void run_task(uint32_t task_code) = 0; +private: + std::queue pending_tasks; + void run_thread(); + pthread_mutex_t mutex; + pthread_cond_t cvar; + bool running; +}; + +} // namespace srsue + +#endif // TASK_DISPATCHER_H diff --git a/lib/include/srslte/common/thread_pool.h b/lib/include/srslte/common/thread_pool.h new file mode 100644 index 000000000..812ee2433 --- /dev/null +++ b/lib/include/srslte/common/thread_pool.h @@ -0,0 +1,105 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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: thread_pool.h + * Description: Implements a pool of threads. Pending tasks to execute are + * identified by a pointer. + * Reference: + *****************************************************************************/ + +#ifndef THREAD_POOL_H +#define THREAD_POOL_H + +#include +#include +#include +#include + +#include "srslte/common/threads.h" + +namespace srslte { + +class thread_pool +{ +public: + + class worker : public thread + { + public: + void setup(uint32_t id, thread_pool *parent, uint32_t prio=0, uint32_t mask = 255); + void stop(); + uint32_t get_id(); + void release(); + protected: + virtual void work_imp() = 0; + private: + uint32_t my_id; + thread_pool *my_parent; + bool running; + void run_thread(); + void wait_to_start(); + void finished(); + }; + + + thread_pool(uint32_t nof_workers); + void init_worker(uint32_t id, worker*, uint32_t prio = 0, uint32_t mask = 255); + void stop(); + worker* wait_worker(); + worker* wait_worker(uint32_t tti); + worker* wait_worker_nb(uint32_t tti); + void start_worker(worker*); + void start_worker(uint32_t id); + worker* get_worker(uint32_t id); + uint32_t get_nof_workers(); + + +private: + + bool find_finished_worker(uint32_t tti, uint32_t *id); + + typedef enum { + IDLE, + START_WORK, + WORKER_READY, + WORKING + }worker_status; + + std::vector workers; + uint32_t nof_workers; + uint32_t max_workers; + bool running; + pthread_cond_t cvar_queue; + pthread_mutex_t mutex_queue; + std::vector status; + std::vector cvar; + std::vector mutex; + std::stack available_workers; +}; +} + +#endif diff --git a/lib/include/srslte/common/threads.h b/lib/include/srslte/common/threads.h new file mode 100644 index 000000000..a8807ba9b --- /dev/null +++ b/lib/include/srslte/common/threads.h @@ -0,0 +1,151 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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 +#include +#include +#include +#include + +#ifdef __cplusplus + extern "C" { +#endif // __cplusplus + + bool threads_new_rt(pthread_t *thread, void *(*start_routine) (void*), void *arg); + bool threads_new_rt_prio(pthread_t *thread, void *(*start_routine) (void*), void *arg, int prio_offset); + bool threads_new_rt_cpu(pthread_t *thread, void *(*start_routine) (void*), void *arg, int cpu, int prio_offset); + bool threads_new_rt_mask(pthread_t *thread, void *(*start_routine) (void*), void *arg, int mask, int prio_offset); + void threads_print_self(); + +#ifdef __cplusplus +} + +#ifndef THREADS_ +#define THREADS_ + +class thread +{ +public: + 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); + } + bool start_cpu_mask(int prio, int mask){ + return threads_new_rt_mask(&_thread, thread_function_entry, this, mask, prio); +} + void print_priority() { + threads_print_self(); + } + void wait_thread_finish() { + pthread_join(_thread, NULL); + } + void thread_cancel() { + pthread_cancel(_thread); + } +protected: + virtual void run_thread() = 0; +private: + static void *thread_function_entry(void *_this) { ((thread*) _this)->run_thread(); return NULL; } + pthread_t _thread; +}; + +class periodic_thread : public thread +{ +public: + void start_periodic(int period_us_, int priority = -1) { + period_us = period_us_; + start(priority); + } +protected: + virtual void run_period() = 0; +private: + int wakeups_missed; + int timer_fd; + int period_us; + void run_thread() { + if (make_periodic()) { + return; + } + while(1) { + run_period(); + wait_period(); + } + } + int make_periodic() { + int ret = -1; + unsigned int ns; + unsigned int sec; + struct itimerspec itval; + + /* Create the timer */ + ret = timerfd_create (CLOCK_MONOTONIC, 0); + wakeups_missed = 0; + timer_fd = ret; + if (ret > 0) { + /* Make the timer periodic */ + sec = period_us/1e6; + ns = (period_us - (sec * 1000000)) * 1000; + itval.it_interval.tv_sec = sec; + itval.it_interval.tv_nsec = ns; + itval.it_value.tv_sec = sec; + itval.it_value.tv_nsec = ns; + ret = timerfd_settime (timer_fd, 0, &itval, NULL); + if (ret < 0) { + perror("timerfd_settime"); + } + } else { + perror("timerfd_create"); + } + return ret; + } + void wait_period() { + unsigned long long missed; + int ret; + + /* Wait for the next timer event. If we have missed any the + number is written to "missed" */ + ret = read (timer_fd, &missed, sizeof (missed)); + if (ret == -1) + { + perror ("read timer"); + return; + } + + /* "missed" should always be >= 1, but just to be sure, check it is not 0 anyway */ + if (missed > 0) { + wakeups_missed += (missed - 1); + } + } +}; + + + +#endif // THREADS_ + +#endif // __cplusplus + diff --git a/lib/include/srslte/common/timeout.h b/lib/include/srslte/common/timeout.h new file mode 100644 index 000000000..2c9560729 --- /dev/null +++ b/lib/include/srslte/common/timeout.h @@ -0,0 +1,124 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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: timeout.h + * Description: Millisecond resolution timeouts. Uses a dedicated thread to + * call an optional callback function upon timeout expiry. + * Reference: + *****************************************************************************/ + +#ifndef TIMEOUT_H +#define TIMEOUT_H + +#include +#include +#include +#include +#include "srslte/srslte.h" + +namespace srslte { + +class timeout_callback +{ + public: + virtual void timeout_expired(uint32_t timeout_id) = 0; +}; + +class timeout +{ +public: + timeout():running(false),callback(NULL), thread(0), timeout_id(0) {} + ~timeout() + { + if(running && callback) + pthread_join(thread, NULL); + } + void start(int duration_msec_, uint32_t timeout_id_=0,timeout_callback *callback_=NULL) + { + if(duration_msec_ < 0) + return; + reset(); + gettimeofday(&start_time[1], NULL); + duration_msec = duration_msec_; + running = true; + timeout_id = timeout_id_; + callback = callback_; + if(callback) + pthread_create(&thread, NULL, &thread_start, this); + } + void reset() + { + if(callback) + pthread_cancel(thread); + running = false; + } + static void* thread_start(void *t_) + { + timeout *t = (timeout*)t_; + t->thread_func(); + return NULL; + } + void thread_func() + { + + // substract time elapsed until now from timer duration + gettimeofday(&start_time[2], NULL); + get_time_interval(start_time); + + int32_t usec = duration_msec*1000-start_time[0].tv_usec; + if(usec > 0) + usleep(usec); + if(callback && running) + callback->timeout_expired(timeout_id); + } + bool expired() + { + if(running) { + gettimeofday(&start_time[2], NULL); + get_time_interval(start_time); + return start_time[0].tv_usec > duration_msec*1000; + } else { + return false; + } + } + bool is_running() + { + return running; + } + +private: + struct timeval start_time[3]; + pthread_t thread; + uint32_t timeout_id; + timeout_callback *callback; + bool running; + int duration_msec; +}; + +} // namespace srsue + +#endif // TIMEOUT_H diff --git a/lib/include/srslte/common/timers.h b/lib/include/srslte/common/timers.h new file mode 100644 index 000000000..56e40e152 --- /dev/null +++ b/lib/include/srslte/common/timers.h @@ -0,0 +1,151 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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: timers.h + * Description: Manually incremented timers. Call a callback function upon + * expiry. + * Reference: + *****************************************************************************/ + +#ifndef TIMERS_H +#define TIMERS_H + +#include +#include +#include +#include + +namespace srslte { + +class timer_callback +{ + public: + virtual void timer_expired(uint32_t timer_id) = 0; +}; + +class timers +{ +public: + class timer + { + public: + timer(uint32_t id_=0) {id = id_; counter = 0; timeout = 0; running = false; callback = NULL; } + void set(timer_callback *callback_, uint32_t timeout_) { + callback = callback_; + timeout = timeout_; + reset(); + } + bool is_running() { + return (counter < timeout) && running; + } + bool is_expired() { + return callback && (counter >= timeout || !running); + } + uint32_t get_timeout() { + return timeout; + } + void reset() { + counter = 0; + } + void step() { + if (running) { + counter++; + if (is_expired()) { + running = false; + if (callback) { + callback->timer_expired(id); + } + } + } + } + void stop() { + running = false; + } + void run() { + running = true; + } + uint32_t id; + private: + timer_callback *callback; + uint32_t timeout; + uint32_t counter; + bool running; + }; + + timers(uint32_t nof_timers_) : timer_list(nof_timers_) { + nof_timers = nof_timers_; + next_timer = 0; + for (uint32_t i=0;istep(); + } + } + void stop_all() { + for (uint32_t i=0;istop(); + } + } + void run_all() { + for (uint32_t i=0;irun(); + } + } + void reset_all() { + for (uint32_t i=0;ireset(); + } + } + timer *get(uint32_t i) { + if (i < nof_timers) { + return &timer_list[i]; + } else { + printf("Error accessing invalid timer %d (Only %d timers available)\n", i, nof_timers); + return NULL; + } + } + uint32_t get_unique_id() { + if (next_timer == nof_timers){ + printf("No more unique timer ids (Only %d timers available)\n", nof_timers); + next_timer = 0; + } + return next_timer++; + } +private: + uint32_t nof_timers; + uint32_t next_timer; + std::vector timer_list; +}; + +} // namespace srslte + +#endif // TIMERS_H diff --git a/lib/include/srslte/common/trace.h b/lib/include/srslte/common/trace.h new file mode 100644 index 000000000..64d55e460 --- /dev/null +++ b/lib/include/srslte/common/trace.h @@ -0,0 +1,101 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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: trace.h + * Description: + * Reference: + *****************************************************************************/ + +#ifndef TRACE_H +#define TRACE_H + +#include +#include +#include + +namespace srslte { + +template +class trace +{ +public: + + trace(uint32_t nof_elems_) : tti(nof_elems_), data(nof_elems_) { + rpm=0; + nof_elems=nof_elems_; + wrapped = false; + }; + void push_cur_time_us(uint32_t cur_tti) { + struct timeval t; + gettimeofday(&t, NULL); + elemType us = t.tv_sec*1e6+t.tv_usec; + push(cur_tti, us); + } + void push(uint32_t value_tti, elemType value) { + tti[rpm] = value_tti; + data[rpm] = value; + rpm++; + if (rpm >= nof_elems) { + rpm = 0; + wrapped = true; + } + } + bool writeToBinary(std::string filename) { + FILE *f = fopen(filename.c_str(), "w"); + if (f != NULL) { + uint32_t st=wrapped?(rpm+1):0; + do { + writeToBinaryValue(f, st++); + if (st >= nof_elems) { + st=0; + } + } while(st!=rpm); + fclose(f); + return true; + } else { + perror("fopen"); + return false; + } + } + +private: + std::vector tti; + std::vector data; + uint32_t rpm; + uint32_t nof_elems; + bool wrapped; + + void writeToBinaryValue(FILE *f, uint32_t idx) { + fwrite(&tti[idx], 1, sizeof(uint32_t), f); + fwrite(&data[idx], 1, sizeof(elemType), f); + } + +}; + +} // namespace srslte + +#endif // TRACE_H diff --git a/lib/include/srslte/common/tti_sync.h b/lib/include/srslte/common/tti_sync.h new file mode 100644 index 000000000..23061ea2d --- /dev/null +++ b/lib/include/srslte/common/tti_sync.h @@ -0,0 +1,78 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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: tti_synch.h + * Description: Interface used for PHY-MAC synchronization + * (producer-consumer model). The consumer waits while its + * counter is lower than the producer counter. + * The PHY is the consumer. The MAC is the producer. + * Reference: + *****************************************************************************/ + +#ifndef TTISYNC_H +#define TTISYNC_H + +#include + +namespace srslte { + +class tti_sync +{ + public: + tti_sync(uint32_t modulus_) + { + modulus = modulus_; + increment = 1; + init_counters(0); + } + virtual void increase() = 0; + virtual void resync() = 0; + virtual uint32_t wait() = 0; + virtual void set_producer_cntr(uint32_t) = 0; + uint32_t get_producer_cntr() { return producer_cntr; } + uint32_t get_consumer_cntr() { return consumer_cntr; } + void set_increment(uint32_t increment_) { + increment = increment_; + } + protected: + void increase_producer() { producer_cntr = (producer_cntr + increment)%modulus; } + void increase_consumer() { consumer_cntr = (consumer_cntr + increment)%modulus; } + bool wait_condition() { return producer_cntr == consumer_cntr; } + void init_counters(uint32_t val) + { + consumer_cntr = val; + producer_cntr = val; + } + uint32_t increment; + uint32_t modulus; + uint32_t producer_cntr; + uint32_t consumer_cntr; +}; + +} // namespace srsue + +#endif // TTISYNC_H diff --git a/lib/include/srslte/common/tti_sync_cv.h b/lib/include/srslte/common/tti_sync_cv.h new file mode 100644 index 000000000..c04fa71f0 --- /dev/null +++ b/lib/include/srslte/common/tti_sync_cv.h @@ -0,0 +1,58 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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: tti_synch_cv.h + * Description: Implements tti_sync interface with condition variables. + * Reference: + *****************************************************************************/ + +#ifndef TTISYNC_CV_H +#define TTISYNC_CV_H + +#include +#include "srslte/common/tti_sync.h" + +namespace srslte { + +class tti_sync_cv : public tti_sync +{ + public: + tti_sync_cv(uint32_t modulus = 10240); + ~tti_sync_cv(); + void increase(); + uint32_t wait(); + void resync(); + void set_producer_cntr(uint32_t producer_cntr); + + private: + pthread_cond_t cond; + pthread_mutex_t mutex; +}; + +} // namespace srsue + +#endif // TTISYNC_CV_H diff --git a/srslte/include/srslte/config.h b/lib/include/srslte/config.h similarity index 100% rename from srslte/include/srslte/config.h rename to lib/include/srslte/config.h diff --git a/lib/include/srslte/interfaces/enb_interfaces.h b/lib/include/srslte/interfaces/enb_interfaces.h new file mode 100644 index 000000000..8806ded58 --- /dev/null +++ b/lib/include/srslte/interfaces/enb_interfaces.h @@ -0,0 +1,268 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2017 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of srsLTE. + * + * srsUE 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. + * + * srsUE 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/srslte.h" + +#include "srslte/common/common.h" +#include "srslte/common/security.h" +#include "srslte/interfaces/sched_interface.h" +#include "srslte/asn1/liblte_rrc.h" +#include "srslte/asn1/liblte_s1ap.h" + +#include + +#ifndef ENBINTERFACES_H +#define ENBINTERFACES_H + +namespace srsenb { + +/* Interface PHY -> MAC */ +class mac_interface_phy +{ +public: + const static int MAX_GRANTS = 64; + + typedef struct { + srslte_enb_dl_pdsch_t sched_grants[MAX_GRANTS]; + uint32_t nof_grants; + uint32_t cfi; + } dl_sched_t; + + typedef struct { + srslte_enb_ul_pusch_t sched_grants[MAX_GRANTS]; + srslte_enb_dl_phich_t phich[MAX_GRANTS]; + uint32_t nof_grants; + uint32_t nof_phich; + } ul_sched_t; + + + virtual int sr_detected(uint32_t tti, uint16_t rnti) = 0; + virtual int rach_detected(uint32_t tti, uint32_t preamble_idx, uint32_t time_adv) = 0; + + virtual int cqi_info(uint32_t tti, uint16_t rnti, uint32_t cqi_value) = 0; + virtual int snr_info(uint32_t tti, uint16_t rnti, float snr_db) = 0; + virtual int ack_info(uint32_t tti, uint16_t rnti, bool ack) = 0; + virtual int crc_info(uint32_t tti, uint16_t rnti, uint32_t nof_bytes, bool crc_res) = 0; + + virtual int get_dl_sched(uint32_t tti, dl_sched_t *dl_sched_res) = 0; + virtual int get_ul_sched(uint32_t tti, ul_sched_t *ul_sched_res) = 0; + + // Radio-Link status + virtual void rl_failure(uint16_t rnti) = 0; + virtual void rl_ok(uint16_t rnti) = 0; + + virtual void tti_clock() = 0; +}; + +/* Interface MAC -> PHY */ +class phy_interface_mac +{ +public: + + /* MAC adds/removes an RNTI to the list of active RNTIs */ + virtual int add_rnti(uint16_t rnti) = 0; + virtual void rem_rnti(uint16_t rnti) = 0; +}; + +/* Interface RRC -> PHY */ +class phy_interface_rrc +{ +public: + virtual void set_config_dedicated(uint16_t rnti, LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT* dedicated) = 0; + +}; + +class mac_interface_rrc +{ +public: + /* Provides cell configuration including SIB periodicity, etc. */ + virtual int cell_cfg(sched_interface::cell_cfg_t *cell_cfg) = 0; + virtual void reset() = 0; + + /* Manages UE configuration context */ + virtual int ue_cfg(uint16_t rnti, sched_interface::ue_cfg_t *cfg) = 0; + virtual int ue_rem(uint16_t rnti) = 0; + + /* Manages UE bearers and associated configuration */ + virtual int bearer_ue_cfg(uint16_t rnti, uint32_t lc_id, sched_interface::ue_bearer_cfg_t *cfg) = 0; + virtual int bearer_ue_rem(uint16_t rnti, uint32_t lc_id) = 0; + virtual void phy_config_enabled(uint16_t rnti, bool enabled) = 0; + +}; + +class mac_interface_rlc +{ +public: + virtual int rlc_buffer_state(uint16_t rnti, uint32_t lc_id, uint32_t tx_queue, uint32_t retx_queue) = 0; +}; + +//RLC interface for MAC +class rlc_interface_mac +{ +public: + + /* MAC calls RLC to get RLC segment of nof_bytes length. + * Segmentation happens in this function. RLC PDU is stored in payload. */ + virtual int read_pdu(uint16_t rnti, uint32_t lcid, uint8_t *payload, uint32_t nof_bytes) = 0; + + virtual void read_pdu_bcch_dlsch(uint32_t sib_index, uint8_t *payload) = 0; + virtual void read_pdu_pcch(uint8_t* payload, uint32_t buffer_size) = 0; + + /* MAC calls RLC to push an RLC PDU. This function is called from an independent MAC thread. + * PDU gets placed into the buffer and higher layer thread gets notified. */ + virtual void write_pdu(uint16_t rnti, uint32_t lcid, uint8_t *payload, uint32_t nof_bytes) = 0; + +}; + + +// RLC interface for PDCP +class rlc_interface_pdcp +{ +public: + /* PDCP calls RLC to push an RLC SDU. SDU gets placed into the RLC buffer and MAC pulls + * RLC PDUs according to TB size. */ + virtual void write_sdu(uint16_t rnti, uint32_t lcid, srslte::byte_buffer_t *sdu) = 0; +}; + +// RLC interface for RRC +class rlc_interface_rrc +{ +public: + virtual void reset(uint16_t rnti) = 0; + virtual void clear_buffer(uint16_t rnti) = 0; + virtual void add_user(uint16_t rnti) = 0; + virtual void rem_user(uint16_t rnti) = 0; + virtual void add_bearer(uint16_t rnti, uint32_t lcid) = 0; + virtual void add_bearer(uint16_t rnti, uint32_t lcid, LIBLTE_RRC_RLC_CONFIG_STRUCT *cnfg) = 0; +}; + +// PDCP interface for GTPU +class pdcp_interface_gtpu +{ +public: + virtual void write_sdu(uint16_t rnti, uint32_t lcid, srslte::byte_buffer_t *sdu) = 0; +}; + +// PDCP interface for RRC +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 write_sdu(uint16_t rnti, uint32_t lcid, srslte::byte_buffer_t *sdu) = 0; + virtual void add_bearer(uint16_t rnti, uint32_t lcid, LIBLTE_RRC_PDCP_CONFIG_STRUCT *cnfg=NULL) = 0; + virtual void config_security(uint16_t rnti, + uint32_t lcid, + uint8_t *k_rrc_enc_, + uint8_t *k_rrc_int_, + srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo_, + srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo_) = 0; +}; + +// PDCP interface for RLC +class pdcp_interface_rlc +{ +public: + /* RLC calls PDCP to push a PDCP PDU. */ + virtual void write_pdu(uint16_t rnti, uint32_t lcid, srslte::byte_buffer_t *sdu) = 0; +}; + +// RRC interface for RLC +class rrc_interface_rlc +{ +public: + virtual void read_pdu_bcch_dlsch(uint32_t sib_index, uint8_t *payload) = 0; + virtual void read_pdu_pcch(uint8_t *payload, uint32_t payload_size) = 0; + virtual void max_retx_attempted(uint16_t rnti) = 0; +}; + +// RRC interface for MAC +class rrc_interface_mac +{ +public: + /* Radio Link failure */ + virtual void rl_failure(uint16_t rnti) = 0; + virtual void add_user(uint16_t rnti) = 0; + virtual void upd_user(uint16_t new_rnti, uint16_t old_rnti) = 0; + virtual void set_activity_user(uint16_t rnti) = 0; + virtual bool is_paging_opportunity(uint32_t tti, uint32_t *payload_len) = 0; +}; + +// RRC interface for PDCP +class rrc_interface_pdcp +{ +public: + virtual void write_pdu(uint16_t rnti, uint32_t lcid, srslte::byte_buffer_t *pdu) = 0; +}; + +// RRC interface for S1AP +class rrc_interface_s1ap +{ +public: + virtual void write_dl_info(uint16_t rnti, srslte::byte_buffer_t *sdu) = 0; + virtual void release_complete(uint16_t rnti) = 0; + virtual bool setup_ue_ctxt(uint16_t rnti, LIBLTE_S1AP_MESSAGE_INITIALCONTEXTSETUPREQUEST_STRUCT *msg) = 0; + virtual bool setup_ue_erabs(uint16_t rnti, LIBLTE_S1AP_MESSAGE_E_RABSETUPREQUEST_STRUCT *msg) = 0; + virtual bool release_erabs(uint32_t rnti) = 0; + virtual void add_paging_id(uint32_t ueid, LIBLTE_S1AP_UEPAGINGID_STRUCT UEPagingID) = 0; +}; + +// GTPU interface for PDCP +class gtpu_interface_pdcp +{ +public: + virtual void write_pdu(uint16_t rnti, uint32_t lcid, srslte::byte_buffer_t *pdu) = 0; +}; + +// GTPU interface for RRC +class gtpu_interface_rrc +{ +public: + virtual void add_bearer(uint16_t rnti, uint32_t lcid, uint32_t teid_out, uint32_t *teid_in) = 0; + virtual void rem_bearer(uint16_t rnti, uint32_t lcid) = 0; + virtual void rem_user(uint16_t rnti) = 0; +}; + +// S1AP interface for RRC +class s1ap_interface_rrc +{ +public: + virtual void initial_ue(uint16_t rnti, srslte::byte_buffer_t *pdu) = 0; + virtual void initial_ue(uint16_t rnti, srslte::byte_buffer_t *pdu, uint32_t m_tmsi, uint8_t mmec) = 0; + virtual void write_pdu(uint16_t rnti, srslte::byte_buffer_t *pdu) = 0; + virtual bool user_exists(uint16_t rnti) = 0; + virtual void user_inactivity(uint16_t rnti) = 0; + virtual void release_eutran(uint16_t rnti) = 0; + virtual bool user_link_lost(uint16_t rnti) = 0; + virtual void ue_ctxt_setup_complete(uint16_t rnti, LIBLTE_S1AP_MESSAGE_INITIALCONTEXTSETUPRESPONSE_STRUCT *res) = 0; + virtual void ue_erab_setup_complete(uint16_t rnti, LIBLTE_S1AP_MESSAGE_E_RABSETUPRESPONSE_STRUCT *res) = 0; + // virtual void ue_capabilities(uint16_t rnti, LIBLTE_RRC_UE_EUTRA_CAPABILITY_STRUCT *caps) = 0; +}; + +} + +#endif diff --git a/lib/include/srslte/interfaces/enb_metrics_interface.h b/lib/include/srslte/interfaces/enb_metrics_interface.h new file mode 100644 index 000000000..6893b4c2f --- /dev/null +++ b/lib/include/srslte/interfaces/enb_metrics_interface.h @@ -0,0 +1,67 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2017 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of srsLTE. + * + * srsUE 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. + * + * srsUE 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 ENB_METRICS_INTERFACE_H +#define ENB_METRICS_INTERFACE_H + +#include + +#include "upper/common_enb.h" +#include "upper/s1ap_metrics.h" +#include "upper/rrc_metrics.h" +#include "srslte/upper/gw_metrics.h" +#include "srslte/upper/rlc_metrics.h" +#include "mac/mac_metrics.h" +#include "phy/phy_metrics.h" + +namespace srsenb { + +typedef struct { + uint32_t rf_o; + uint32_t rf_u; + uint32_t rf_l; + bool rf_error; +}rf_metrics_t; + +typedef struct { + rf_metrics_t rf; + phy_metrics_t phy[ENB_METRICS_MAX_USERS]; + mac_metrics_t mac[ENB_METRICS_MAX_USERS]; + rrc_metrics_t rrc; + s1ap_metrics_t s1ap; + bool running; +}enb_metrics_t; + +// ENB interface +class enb_metrics_interface +{ +public: + virtual bool get_metrics(enb_metrics_t &m) = 0; +}; + +} // namespace srsenb + +#endif // ENB_METRICS_INTERFACE_H diff --git a/lib/include/srslte/interfaces/sched_interface.h b/lib/include/srslte/interfaces/sched_interface.h new file mode 100644 index 000000000..63ab92121 --- /dev/null +++ b/lib/include/srslte/interfaces/sched_interface.h @@ -0,0 +1,247 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2017 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of srsLTE. + * + * srsUE 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. + * + * srsUE 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/srslte.h" + +#ifndef SCHED_INTERFACE_H +#define SCHED_INTERFACE_H + +namespace srsenb { + +class sched_interface +{ +public: + + const static int MAX_SIB_PAYLOAD_LEN = 2048; + const static int MAX_SIBS = 16; + const static int MAX_LC = 6; + const static int MAX_DATA_LIST = 32; + const static int MAX_RAR_LIST = 8; + const static int MAX_BC_LIST = 8; + const static int MAX_RLC_PDU_LIST = 8; + const static int MAX_PHICH_LIST = 8; + + typedef struct { + uint32_t len; + uint32_t period_rf; + } cell_cfg_sib_t; + + + typedef struct { + int pdsch_mcs; + int pdsch_max_mcs; + int pusch_mcs; + int pusch_max_mcs; + int nof_ctrl_symbols; + } sched_args_t; + + + typedef struct { + + // Main cell configuration (used to calculate DCI locations in scheduler) + srslte_cell_t cell; + + /* SIB configuration */ + cell_cfg_sib_t sibs[MAX_SIBS]; + uint32_t si_window_ms; + + /* pusch configuration */ + srslte_pusch_hopping_cfg_t pusch_hopping_cfg; + + /* prach configuration */ + uint32_t prach_config; + uint32_t prach_freq_offset; + uint32_t prach_rar_window; + uint32_t prach_contention_resolution_timer; + + uint32_t maxharq_msg3tx; + uint32_t n1pucch_an; + uint32_t delta_pucch_shift; + + uint32_t nrb_cqi; + uint32_t ncs_an; + + uint32_t srs_subframe_config; + uint32_t srs_subframe_offset; + uint32_t srs_bw_config; + + } cell_cfg_t; + + + typedef struct { + int priority; + int bsd; + int pbr; + enum {IDLE = 0, UL, DL, BOTH} direction; + } ue_bearer_cfg_t; + + typedef struct { + + bool continuous_pusch; + + /* ue capabilities, etc */ + + uint32_t maxharq_tx; + uint32_t aperiodic_cqi_period; // if 0 is periodic CQI + uint32_t beta_ack_index; + uint32_t beta_ri_index; + uint32_t beta_cqi_index; + + srslte_pucch_cfg_t pucch_cfg; + uint32_t n_pucch_cqi; + uint32_t sr_I; + uint32_t sr_N_pucch; + bool sr_enabled; + uint32_t cqi_pucch; + uint32_t cqi_idx; + bool cqi_enabled; + + ue_bearer_cfg_t ue_bearers[MAX_LC]; + + } ue_cfg_t; + + typedef struct { + uint32_t lcid; + uint32_t nbytes; + } dl_sched_pdu_t; + + typedef struct { + uint32_t rnti; + srslte_ra_dl_dci_t dci; + srslte_dci_location_t dci_location; + uint32_t tbs; + bool mac_ce_ta; + bool mac_ce_rnti; + uint32_t nof_pdu_elems; + dl_sched_pdu_t pdu[MAX_RLC_PDU_LIST]; + } dl_sched_data_t; + + typedef struct { + uint32_t rnti; + bool needs_pdcch; + uint32_t current_tx_nb; + uint32_t tbs; + srslte_ra_ul_dci_t dci; + srslte_dci_location_t dci_location; + } ul_sched_data_t; + + typedef struct { + uint32_t ra_id; + srslte_dci_rar_grant_t grant; + } dl_sched_rar_grant_t; + + typedef struct { + uint32_t rarnti; + uint32_t tbs; + srslte_ra_dl_dci_t dci; + srslte_dci_location_t dci_location; + uint32_t nof_grants; + dl_sched_rar_grant_t grants[MAX_RAR_LIST]; + } dl_sched_rar_t; + + typedef struct { + srslte_ra_dl_dci_t dci; + srslte_dci_location_t dci_location; + + enum bc_type { + BCCH, PCCH + } type; + + uint32_t index; + + uint32_t tbs; + + } dl_sched_bc_t; + + typedef struct { + uint32_t cfi; + uint32_t nof_data_elems; + uint32_t nof_rar_elems; + uint32_t nof_bc_elems; + dl_sched_data_t data[MAX_DATA_LIST]; + dl_sched_rar_t rar[MAX_RAR_LIST]; + dl_sched_bc_t bc[MAX_BC_LIST]; + } dl_sched_res_t; + + typedef struct { + uint16_t rnti; + enum phich_elem { + ACK, NACK + } phich; + } ul_sched_phich_t; + + typedef struct { + uint32_t nof_dci_elems; + uint32_t nof_phich_elems; + ul_sched_data_t pusch[MAX_DATA_LIST]; + ul_sched_phich_t phich[MAX_PHICH_LIST]; + } ul_sched_res_t; + + /******************* Scheduler Control ****************************/ + + /* Provides cell configuration including SIB periodicity, etc. */ + virtual int cell_cfg(cell_cfg_t *cell_cfg) = 0; + virtual int reset() = 0; + + /* Manages UE scheduling context */ + virtual int ue_cfg(uint16_t rnti, ue_cfg_t *cfg) = 0; + virtual int ue_rem(uint16_t rnti) = 0; + virtual bool ue_exists(uint16_t rnti) = 0; + + /* Manages UE bearers and associated configuration */ + virtual int bearer_ue_cfg(uint16_t rnti, uint32_t lc_id, ue_bearer_cfg_t *cfg) = 0; + virtual int bearer_ue_rem(uint16_t rnti, uint32_t lc_id) = 0; + + virtual uint32_t get_ul_buffer(uint16_t rnti) = 0; + virtual uint32_t get_dl_buffer(uint16_t rnti) = 0; + + /******************* Scheduling Interface ***********************/ + /* DL buffer status report */ + virtual int dl_rlc_buffer_state(uint16_t rnti, uint32_t lc_id, uint32_t tx_queue, uint32_t retx_queue) = 0; + virtual int dl_mac_buffer_state(uint16_t rnti, uint32_t ce_code) = 0; + + /* DL information */ + virtual int dl_ack_info(uint32_t tti, uint16_t rnti, bool ack) = 0; + virtual int dl_rach_info(uint32_t tti, uint32_t ra_id, uint16_t rnti, uint32_t estimated_size) = 0; + virtual int dl_cqi_info(uint32_t tti, uint16_t rnti, uint32_t cqi_value) = 0; + + /* UL information */ + virtual int ul_crc_info(uint32_t tti, uint16_t rnti, bool crc) = 0; + virtual int ul_sr_info(uint32_t tti, uint16_t rnti) = 0; + virtual int ul_bsr(uint16_t rnti, uint32_t lcid, uint32_t bsr) = 0; + virtual int ul_recv_len(uint16_t rnti, uint32_t lcid, uint32_t len) = 0; + virtual int ul_phr(uint16_t rnti, int phr) = 0; + virtual int ul_cqi_info(uint32_t tti, uint16_t rnti, uint32_t cqi, uint32_t ul_ch_code) = 0; + + /* Run Scheduler for this tti */ + virtual int dl_sched(uint32_t tti, dl_sched_res_t *sched_result) = 0; + virtual int ul_sched(uint32_t tti, ul_sched_res_t *sched_result) = 0; + +}; + +} + +#endif diff --git a/lib/include/srslte/interfaces/ue_interfaces.h b/lib/include/srslte/interfaces/ue_interfaces.h new file mode 100644 index 000000000..62b2a7ef7 --- /dev/null +++ b/lib/include/srslte/interfaces/ue_interfaces.h @@ -0,0 +1,481 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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: interfaces.h + * Description: Abstract base class interfaces provided by layers + * to other layers. + *****************************************************************************/ + +#ifndef INTERFACES_H +#define INTERFACES_H + +#include + +#include "srslte/asn1/liblte_rrc.h" +#include "srslte/common/interfaces_common.h" +#include "srslte/common/common.h" +#include "srslte/common/security.h" + +namespace srsue { + +// UE interface +class ue_interface +{ +}; + +// USIM interface for NAS +class usim_interface_nas +{ +public: + virtual void get_imsi_vec(uint8_t* imsi_, uint32_t n) = 0; + virtual void get_imei_vec(uint8_t* imei_, uint32_t n) = 0; + virtual void generate_authentication_response(uint8_t *rand, + uint8_t *autn_enb, + uint16_t mcc, + uint16_t mnc, + bool *net_valid, + uint8_t *res) = 0; + virtual void generate_nas_keys(uint8_t *k_nas_enc, + uint8_t *k_nas_int, + srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo, + srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo) = 0; +}; + +// USIM interface for RRC +class usim_interface_rrc +{ +public: + virtual void generate_as_keys(uint32_t count_ul, + uint8_t *k_rrc_enc, + uint8_t *k_rrc_int, + uint8_t *k_up_enc, + uint8_t *k_up_int, + srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo, + srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo) = 0; +}; + +// GW interface for NAS +class gw_interface_nas +{ +public: + virtual srslte::error_t setup_if_addr(uint32_t ip_addr, char *err_str) = 0; +}; + +// GW interface for PDCP +class gw_interface_pdcp +{ +public: + virtual void write_pdu(uint32_t lcid, srslte::byte_buffer_t *pdu) = 0; +}; + +// NAS interface for RRC +class nas_interface_rrc +{ +public: + virtual bool is_attached() = 0; + virtual void notify_connection_setup() = 0; + virtual void write_pdu(uint32_t lcid, srslte::byte_buffer_t *pdu) = 0; + virtual uint32_t get_ul_count() = 0; + virtual bool get_s_tmsi(LIBLTE_RRC_S_TMSI_STRUCT *s_tmsi) = 0; +}; + +// RRC interface for MAC +class rrc_interface_mac +{ +public: + virtual void release_pucch_srs() = 0; + virtual void ra_problem() = 0; +}; + +// RRC interface for PHY +class rrc_interface_phy +{ +public: + virtual void in_sync() = 0; + virtual void out_of_sync() = 0; +}; + +// RRC interface for NAS +class rrc_interface_nas +{ +public: + virtual void write_sdu(uint32_t lcid, srslte::byte_buffer_t *sdu) = 0; + virtual uint16_t get_mcc() = 0; + virtual uint16_t get_mnc() = 0; + virtual void enable_capabilities() = 0; +}; + +// RRC interface for GW +class rrc_interface_gw +{ +public: + virtual bool rrc_connected() = 0; + virtual void rrc_connect() = 0; + virtual bool have_drb() = 0; +}; + +// RRC interface for PDCP +class rrc_interface_pdcp +{ +public: + virtual void write_pdu(uint32_t lcid, srslte::byte_buffer_t *pdu) = 0; + virtual void write_pdu_bcch_bch(srslte::byte_buffer_t *pdu) = 0; + virtual void write_pdu_bcch_dlsch(srslte::byte_buffer_t *pdu) = 0; + virtual void write_pdu_pcch(srslte::byte_buffer_t *pdu) = 0; +}; + +// RRC interface for RLC +class rrc_interface_rlc +{ +public: + virtual void max_retx_attempted() = 0; +}; + +// PDCP interface for GW +class pdcp_interface_gw +{ +public: + virtual void write_sdu(uint32_t lcid, srslte::byte_buffer_t *sdu) = 0; +}; + +// PDCP interface for RRC +class pdcp_interface_rrc +{ +public: + virtual void reset() = 0; + virtual void write_sdu(uint32_t lcid, srslte::byte_buffer_t *sdu) = 0; + virtual void add_bearer(uint32_t lcid, LIBLTE_RRC_PDCP_CONFIG_STRUCT *cnfg=NULL) = 0; + virtual void config_security(uint32_t lcid, + uint8_t *k_rrc_enc_, + uint8_t *k_rrc_int_, + srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo_, + srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo_) = 0; +}; + +// PDCP interface for RLC +class pdcp_interface_rlc +{ +public: + /* RLC calls PDCP to push a PDCP PDU. */ + virtual void write_pdu(uint32_t lcid, srslte::byte_buffer_t *sdu) = 0; + virtual void write_pdu_bcch_bch(srslte::byte_buffer_t *sdu) = 0; + virtual void write_pdu_bcch_dlsch(srslte::byte_buffer_t *sdu) = 0; + virtual void write_pdu_pcch(srslte::byte_buffer_t *sdu) = 0; +}; + +// RLC interface for RRC +class rlc_interface_rrc +{ +public: + virtual void reset() = 0; + virtual void add_bearer(uint32_t lcid) = 0; + virtual void add_bearer(uint32_t lcid, LIBLTE_RRC_RLC_CONFIG_STRUCT *cnfg) = 0; +}; + +// RLC interface for PDCP +class rlc_interface_pdcp +{ +public: + /* PDCP calls RLC to push an RLC SDU. SDU gets placed into the RLC buffer and MAC pulls + * RLC PDUs according to TB size. */ + virtual void write_sdu(uint32_t lcid, srslte::byte_buffer_t *sdu) = 0; +}; + +//RLC interface for MAC +class rlc_interface_mac : public srslte::read_pdu_interface +{ +public: + /* MAC calls RLC to get buffer state for a logical channel. + * This function should return quickly. */ + virtual uint32_t get_buffer_state(uint32_t lcid) = 0; + virtual uint32_t get_total_buffer_state(uint32_t lcid) = 0; + + + const static int MAX_PDU_SEGMENTS = 20; + + /* MAC calls RLC to get RLC segment of nof_bytes length. + * Segmentation happens in this function. RLC PDU is stored in payload. */ + virtual int read_pdu(uint32_t lcid, uint8_t *payload, uint32_t nof_bytes) = 0; + + /* MAC calls RLC to push an RLC PDU. This function is called from an independent MAC thread. + * PDU gets placed into the buffer and higher layer thread gets notified. */ + virtual void write_pdu(uint32_t lcid, uint8_t *payload, uint32_t nof_bytes) = 0; + virtual void write_pdu_bcch_bch(uint8_t *payload, uint32_t nof_bytes) = 0; + virtual void write_pdu_bcch_dlsch(uint8_t *payload, uint32_t nof_bytes) = 0; + virtual void write_pdu_pcch(uint8_t *payload, uint32_t nof_bytes) = 0; +}; + + + +/** MAC interface + * + */ +/* Interface PHY -> MAC */ +class mac_interface_phy +{ +public: + + typedef struct { + uint32_t pid; + uint32_t tti; + uint32_t last_tti; + bool ndi; + bool last_ndi; + uint32_t n_bytes; + int rv; + uint16_t rnti; + bool is_from_rar; + bool is_sps_release; + bool has_cqi_request; + srslte_rnti_type_t rnti_type; + srslte_phy_grant_t phy_grant; + } mac_grant_t; + + typedef struct { + bool decode_enabled; + int rv; + uint16_t rnti; + bool generate_ack; + bool default_ack; + // If non-null, called after tb_decoded_ok to determine if ack needs to be sent + bool (*generate_ack_callback)(void*); + void *generate_ack_callback_arg; + uint8_t *payload_ptr; + srslte_softbuffer_rx_t *softbuffer; + srslte_phy_grant_t phy_grant; + } tb_action_dl_t; + + typedef struct { + bool tx_enabled; + bool expect_ack; + uint32_t rv; + uint16_t rnti; + uint32_t current_tx_nb; + srslte_softbuffer_tx_t *softbuffer; + srslte_phy_grant_t phy_grant; + uint8_t *payload_ptr; + } tb_action_ul_t; + + /* Indicate reception of UL grant. + * payload_ptr points to memory where MAC PDU must be written by MAC layer */ + virtual void new_grant_ul(mac_grant_t grant, tb_action_ul_t *action) = 0; + + /* Indicate reception of UL grant + HARQ information throught PHICH in the same TTI. */ + virtual void new_grant_ul_ack(mac_grant_t grant, bool ack, tb_action_ul_t *action) = 0; + + /* Indicate reception of HARQ information only through PHICH. */ + virtual void harq_recv(uint32_t tti, bool ack, tb_action_ul_t *action) = 0; + + /* Indicate reception of DL grant. */ + virtual void new_grant_dl(mac_grant_t grant, tb_action_dl_t *action) = 0; + + /* Indicate successfull decoding of PDSCH TB. */ + virtual void tb_decoded(bool ack, srslte_rnti_type_t rnti_type, uint32_t harq_pid) = 0; + + /* Indicate successfull decoding of BCH TB through PBCH */ + virtual void bch_decoded_ok(uint8_t *payload, uint32_t len) = 0; + + /* Indicate successfull decoding of PCH TB through PDSCH */ + virtual void pch_decoded_ok(uint32_t len) = 0; + + /* Function called every start of a subframe (TTI). Warning, this function is called + * from a high priority thread and should terminate asap + */ + virtual void tti_clock(uint32_t tti) = 0; + +}; + + +/* Interface RRC -> MAC */ +class mac_interface_rrc +{ +public: + + typedef struct { + LIBLTE_RRC_MAC_MAIN_CONFIG_STRUCT main; + LIBLTE_RRC_RACH_CONFIG_COMMON_STRUCT rach; + LIBLTE_RRC_SCHEDULING_REQUEST_CONFIG_STRUCT sr; + uint32_t prach_config_index; + } mac_cfg_t; + + + // Class to handle UE specific RNTIs between RRC and MAC + typedef struct { + uint16_t crnti; + uint16_t temp_rnti; + uint16_t tpc_rnti; + uint16_t sps_rnti; + uint64_t contention_id; + } ue_rnti_t; + + /* Instructs the MAC to start receiving BCCH */ + virtual void bcch_start_rx() = 0; + virtual void bcch_stop_rx() = 0; + virtual void bcch_start_rx(int si_window_start, int si_window_length) = 0; + + /* Instructs the MAC to start receiving PCCH */ + virtual void pcch_start_rx() = 0; + virtual void pcch_stop_rx() = 0; + + /* RRC configures a logical channel */ + virtual void setup_lcid(uint32_t lcid, uint32_t lcg, uint32_t priority, int PBR_x_tti, uint32_t BSD) = 0; + + virtual uint32_t get_current_tti() = 0; + + virtual void set_config(mac_cfg_t *mac_cfg) = 0; + virtual void set_config_main(LIBLTE_RRC_MAC_MAIN_CONFIG_STRUCT *main_cfg) = 0; + virtual void set_config_rach(LIBLTE_RRC_RACH_CONFIG_COMMON_STRUCT *rach_cfg, uint32_t prach_config_index) = 0; + virtual void set_config_sr(LIBLTE_RRC_SCHEDULING_REQUEST_CONFIG_STRUCT *sr_cfg) = 0; + virtual void get_config(mac_cfg_t *mac_cfg) = 0; + + virtual void get_rntis(ue_rnti_t *rntis) = 0; + virtual void set_contention_id(uint64_t uecri) = 0; + + + virtual void reconfiguration() = 0; + virtual void reset() = 0; +}; + + + + +/** PHY interface + * + */ + +typedef struct { + bool ul_pwr_ctrl_en; + float prach_gain; + int pdsch_max_its; + bool attach_enable_64qam; + int nof_phy_threads; + + int worker_cpu_mask; + int sync_cpu_affinity; + + uint32_t nof_rx_ant; + std::string equalizer_mode; + int cqi_max; + int cqi_fixed; + float snr_ema_coeff; + std::string snr_estim_alg; + bool cfo_integer_enabled; + float cfo_correct_tol_hz; + int time_correct_period; + bool sfo_correct_disable; + std::string sss_algorithm; + float estimator_fil_w; + bool rssi_sensor_enabled; +} phy_args_t; + +/* Interface MAC -> PHY */ +class phy_interface_mac +{ +public: + /* Configure PRACH using parameters written by RRC */ + virtual void configure_prach_params() = 0; + + /* Start synchronization with strongest cell in the current carrier frequency */ + virtual void sync_start() = 0; + virtual void sync_stop() = 0; + + /* Sets a C-RNTI allowing the PHY to pregenerate signals if necessary */ + virtual void set_crnti(uint16_t rnti) = 0; + + virtual void prach_send(uint32_t preamble_idx, int allowed_subframe, float target_power_dbm) = 0; + virtual int prach_tx_tti() = 0; + + /* Indicates the transmission of a SR signal in the next opportunity */ + virtual void sr_send() = 0; + virtual int sr_last_tx_tti() = 0; + + /* Time advance commands */ + virtual void set_timeadv_rar(uint32_t ta_cmd) = 0; + virtual void set_timeadv(uint32_t ta_cmd) = 0; + + /* Sets RAR grant payload */ + virtual void set_rar_grant(uint32_t tti, uint8_t grant_payload[SRSLTE_RAR_GRANT_LEN]) = 0; + + /* Instruct the PHY to decode PDCCH with the CRC scrambled with given RNTI */ + virtual void pdcch_ul_search(srslte_rnti_type_t rnti_type, uint16_t rnti, int tti_start = -1, int tti_end = -1) = 0; + virtual void pdcch_dl_search(srslte_rnti_type_t rnti_type, uint16_t rnti, int tti_start = -1, int tti_end = -1) = 0; + virtual void pdcch_ul_search_reset() = 0; + virtual void pdcch_dl_search_reset() = 0; + + virtual uint32_t get_current_tti() = 0; + + virtual float get_phr() = 0; + virtual float get_pathloss_db() = 0; + +}; + +class phy_interface_rrc +{ +public: + + typedef struct { + LIBLTE_RRC_PRACH_CONFIG_SIB_STRUCT prach_cnfg; + LIBLTE_RRC_PDSCH_CONFIG_COMMON_STRUCT pdsch_cnfg; + LIBLTE_RRC_PUSCH_CONFIG_COMMON_STRUCT pusch_cnfg; + LIBLTE_RRC_PHICH_CONFIG_STRUCT phich_cnfg; + LIBLTE_RRC_PUCCH_CONFIG_COMMON_STRUCT pucch_cnfg; + LIBLTE_RRC_SRS_UL_CONFIG_COMMON_STRUCT srs_ul_cnfg; + LIBLTE_RRC_UL_POWER_CONTROL_COMMON_STRUCT ul_pwr_ctrl; + LIBLTE_RRC_TDD_CONFIG_STRUCT tdd_cnfg; + LIBLTE_RRC_ANTENNA_PORTS_COUNT_ENUM ant_info; + } phy_cfg_common_t; + + typedef struct { + LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT dedicated; + phy_cfg_common_t common; + bool enable_64qam; + } phy_cfg_t; + + virtual void get_current_cell(srslte_cell_t *cell) = 0; + virtual void get_config(phy_cfg_t *phy_cfg) = 0; + virtual void set_config(phy_cfg_t *phy_cfg) = 0; + virtual void set_config_dedicated(LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT *dedicated) = 0; + virtual void set_config_common(phy_cfg_common_t *common) = 0; + virtual void set_config_tdd(LIBLTE_RRC_TDD_CONFIG_STRUCT *tdd) = 0; + virtual void set_config_64qam_en(bool enable) = 0; + + /* Is the PHY downlink synchronized? */ + virtual bool status_is_sync() = 0; + + /* Configure UL using parameters written with set_param() */ + virtual void configure_ul_params(bool pregen_disabled = false) = 0; + + virtual void reset() = 0; + + virtual void resync_sfn() = 0; + +}; + + +} // namespace srslte + +#endif // INTERFACES_H diff --git a/srslte/include/srslte/agc/agc.h b/lib/include/srslte/phy/agc/agc.h similarity index 100% rename from srslte/include/srslte/agc/agc.h rename to lib/include/srslte/phy/agc/agc.h diff --git a/srslte/include/srslte/ch_estimation/chest_common.h b/lib/include/srslte/phy/ch_estimation/chest_common.h similarity index 100% rename from srslte/include/srslte/ch_estimation/chest_common.h rename to lib/include/srslte/phy/ch_estimation/chest_common.h diff --git a/srslte/include/srslte/ch_estimation/chest_dl.h b/lib/include/srslte/phy/ch_estimation/chest_dl.h similarity index 95% rename from srslte/include/srslte/ch_estimation/chest_dl.h rename to lib/include/srslte/phy/ch_estimation/chest_dl.h index 110e3d509..a454f939c 100644 --- a/srslte/include/srslte/ch_estimation/chest_dl.h +++ b/lib/include/srslte/phy/ch_estimation/chest_dl.h @@ -45,11 +45,11 @@ #include "srslte/config.h" -#include "srslte/ch_estimation/chest_common.h" -#include "srslte/resampling/interp.h" -#include "srslte/ch_estimation/refsignal_dl.h" -#include "srslte/common/phy_common.h" -#include "srslte/sync/pss.h" +#include "srslte/phy/ch_estimation/chest_common.h" +#include "srslte/phy/resampling/interp.h" +#include "srslte/phy/ch_estimation/refsignal_dl.h" +#include "srslte/phy/common/phy_common.h" +#include "srslte/phy/sync/pss.h" typedef enum { diff --git a/srslte/include/srslte/ch_estimation/chest_ul.h b/lib/include/srslte/phy/ch_estimation/chest_ul.h similarity index 95% rename from srslte/include/srslte/ch_estimation/chest_ul.h rename to lib/include/srslte/phy/ch_estimation/chest_ul.h index 8f21cb6b3..1e505210c 100644 --- a/srslte/include/srslte/ch_estimation/chest_ul.h +++ b/lib/include/srslte/phy/ch_estimation/chest_ul.h @@ -43,10 +43,10 @@ #include "srslte/config.h" -#include "srslte/ch_estimation/chest_common.h" -#include "srslte/resampling/interp.h" -#include "srslte/ch_estimation/refsignal_ul.h" -#include "srslte/common/phy_common.h" +#include "srslte/phy/ch_estimation/chest_common.h" +#include "srslte/phy/resampling/interp.h" +#include "srslte/phy/ch_estimation/refsignal_ul.h" +#include "srslte/phy/common/phy_common.h" typedef struct { srslte_cell_t cell; diff --git a/srslte/include/srslte/ch_estimation/refsignal_dl.h b/lib/include/srslte/phy/ch_estimation/refsignal_dl.h similarity index 98% rename from srslte/include/srslte/ch_estimation/refsignal_dl.h rename to lib/include/srslte/phy/ch_estimation/refsignal_dl.h index bc0410b3d..3cdf7901e 100644 --- a/srslte/include/srslte/ch_estimation/refsignal_dl.h +++ b/lib/include/srslte/phy/ch_estimation/refsignal_dl.h @@ -36,7 +36,7 @@ #define SRSLTE_REFSIGNAL_DL_ #include "srslte/config.h" -#include "srslte/common/phy_common.h" +#include "srslte/phy/common/phy_common.h" // Number of references in a subframe: there are 2 symbols for port_id=0,1 x 2 slots x 2 refs per prb #define SRSLTE_REFSIGNAL_NUM_SF(nof_prb, port_id) (((port_id)<2?8:4)*(nof_prb)) diff --git a/srslte/include/srslte/ch_estimation/refsignal_ul.h b/lib/include/srslte/phy/ch_estimation/refsignal_ul.h similarity index 99% rename from srslte/include/srslte/ch_estimation/refsignal_ul.h rename to lib/include/srslte/phy/ch_estimation/refsignal_ul.h index 1c6814b63..72bfb5d94 100644 --- a/srslte/include/srslte/ch_estimation/refsignal_ul.h +++ b/lib/include/srslte/phy/ch_estimation/refsignal_ul.h @@ -36,8 +36,8 @@ #define SRSLTE_REFSIGNAL_UL_ #include "srslte/config.h" -#include "srslte/phch/pucch.h" -#include "srslte/common/phy_common.h" +#include "srslte/phy/phch/pucch.h" +#include "srslte/phy/common/phy_common.h" #define SRSLTE_NOF_GROUPS_U 30 #define SRSLTE_NOF_SEQUENCES_U 2 diff --git a/srslte/include/srslte/channel/ch_awgn.h b/lib/include/srslte/phy/channel/ch_awgn.h similarity index 100% rename from srslte/include/srslte/channel/ch_awgn.h rename to lib/include/srslte/phy/channel/ch_awgn.h diff --git a/srslte/include/srslte/common/phy_common.h b/lib/include/srslte/phy/common/phy_common.h similarity index 100% rename from srslte/include/srslte/common/phy_common.h rename to lib/include/srslte/phy/common/phy_common.h diff --git a/srslte/include/srslte/common/sequence.h b/lib/include/srslte/phy/common/sequence.h similarity index 98% rename from srslte/include/srslte/common/sequence.h rename to lib/include/srslte/phy/common/sequence.h index 291545cd2..dbeba5ff4 100644 --- a/srslte/include/srslte/common/sequence.h +++ b/lib/include/srslte/phy/common/sequence.h @@ -37,7 +37,7 @@ #define LTESEQ_ #include "srslte/config.h" -#include "srslte/common/phy_common.h" +#include "srslte/phy/common/phy_common.h" typedef struct SRSLTE_API { uint8_t *c; diff --git a/srslte/include/srslte/common/timestamp.h b/lib/include/srslte/phy/common/timestamp.h similarity index 100% rename from srslte/include/srslte/common/timestamp.h rename to lib/include/srslte/phy/common/timestamp.h diff --git a/srslte/include/srslte/dft/dft.h b/lib/include/srslte/phy/dft/dft.h similarity index 100% rename from srslte/include/srslte/dft/dft.h rename to lib/include/srslte/phy/dft/dft.h diff --git a/srslte/include/srslte/dft/dft_precoding.h b/lib/include/srslte/phy/dft/dft_precoding.h similarity index 97% rename from srslte/include/srslte/dft/dft_precoding.h rename to lib/include/srslte/phy/dft/dft_precoding.h index e860e5b7b..6e5c5dc40 100644 --- a/srslte/include/srslte/dft/dft_precoding.h +++ b/lib/include/srslte/phy/dft/dft_precoding.h @@ -37,8 +37,8 @@ #define DFTPREC_ #include "srslte/config.h" -#include "srslte/common/phy_common.h" -#include "srslte/dft/dft.h" +#include "srslte/phy/common/phy_common.h" +#include "srslte/phy/dft/dft.h" /* DFT-based Transform Precoding object */ typedef struct SRSLTE_API { diff --git a/srslte/include/srslte/dft/ofdm.h b/lib/include/srslte/phy/dft/ofdm.h similarity index 97% rename from srslte/include/srslte/dft/ofdm.h rename to lib/include/srslte/phy/dft/ofdm.h index a218fcc5b..990d7a8cc 100644 --- a/srslte/include/srslte/dft/ofdm.h +++ b/lib/include/srslte/phy/dft/ofdm.h @@ -41,8 +41,8 @@ #include #include "srslte/config.h" -#include "srslte/common/phy_common.h" -#include "srslte/dft/dft.h" +#include "srslte/phy/common/phy_common.h" +#include "srslte/phy/dft/dft.h" /* This is common for both directions */ typedef struct SRSLTE_API{ diff --git a/srslte/include/srslte/enb/enb_dl.h b/lib/include/srslte/phy/enb/enb_dl.h similarity index 89% rename from srslte/include/srslte/enb/enb_dl.h rename to lib/include/srslte/phy/enb/enb_dl.h index 560441c70..08cb5da4f 100644 --- a/srslte/include/srslte/enb/enb_dl.h +++ b/lib/include/srslte/phy/enb/enb_dl.h @@ -40,25 +40,25 @@ #include -#include "srslte/common/phy_common.h" -#include "srslte/dft/ofdm.h" -#include "srslte/sync/pss.h" -#include "srslte/sync/sss.h" -#include "srslte/ch_estimation/refsignal_dl.h" -#include "srslte/phch/dci.h" -#include "srslte/phch/pbch.h" -#include "srslte/phch/pcfich.h" -#include "srslte/phch/pdcch.h" -#include "srslte/phch/pdsch.h" -#include "srslte/phch/pdsch_cfg.h" -#include "srslte/phch/phich.h" -#include "srslte/phch/ra.h" -#include "srslte/phch/regs.h" +#include "srslte/phy/common/phy_common.h" +#include "srslte/phy/dft/ofdm.h" +#include "srslte/phy/sync/pss.h" +#include "srslte/phy/sync/sss.h" +#include "srslte/phy/ch_estimation/refsignal_dl.h" +#include "srslte/phy/phch/dci.h" +#include "srslte/phy/phch/pbch.h" +#include "srslte/phy/phch/pcfich.h" +#include "srslte/phy/phch/pdcch.h" +#include "srslte/phy/phch/pdsch.h" +#include "srslte/phy/phch/pdsch_cfg.h" +#include "srslte/phy/phch/phich.h" +#include "srslte/phy/phch/ra.h" +#include "srslte/phy/phch/regs.h" -#include "srslte/enb/enb_ul.h" +#include "srslte/phy/enb/enb_ul.h" -#include "srslte/utils/vector.h" -#include "srslte/utils/debug.h" +#include "srslte/phy/utils/vector.h" +#include "srslte/phy/utils/debug.h" #include "srslte/config.h" diff --git a/srslte/include/srslte/enb/enb_ul.h b/lib/include/srslte/phy/enb/enb_ul.h similarity index 93% rename from srslte/include/srslte/enb/enb_ul.h rename to lib/include/srslte/phy/enb/enb_ul.h index 6e426b81c..486566a1c 100644 --- a/srslte/include/srslte/enb/enb_ul.h +++ b/lib/include/srslte/phy/enb/enb_ul.h @@ -40,16 +40,16 @@ #include -#include "srslte/common/phy_common.h" -#include "srslte/dft/ofdm.h" -#include "srslte/ch_estimation/chest_ul.h" -#include "srslte/phch/prach.h" -#include "srslte/phch/pusch.h" -#include "srslte/phch/pusch_cfg.h" -#include "srslte/phch/ra.h" +#include "srslte/phy/common/phy_common.h" +#include "srslte/phy/dft/ofdm.h" +#include "srslte/phy/ch_estimation/chest_ul.h" +#include "srslte/phy/phch/prach.h" +#include "srslte/phy/phch/pusch.h" +#include "srslte/phy/phch/pusch_cfg.h" +#include "srslte/phy/phch/ra.h" -#include "srslte/utils/vector.h" -#include "srslte/utils/debug.h" +#include "srslte/phy/utils/vector.h" +#include "srslte/phy/utils/debug.h" #include "srslte/config.h" diff --git a/srslte/include/srslte/fec/cbsegm.h b/lib/include/srslte/phy/fec/cbsegm.h similarity index 100% rename from srslte/include/srslte/fec/cbsegm.h rename to lib/include/srslte/phy/fec/cbsegm.h diff --git a/srslte/include/srslte/fec/convcoder.h b/lib/include/srslte/phy/fec/convcoder.h similarity index 100% rename from srslte/include/srslte/fec/convcoder.h rename to lib/include/srslte/phy/fec/convcoder.h diff --git a/srslte/include/srslte/fec/crc.h b/lib/include/srslte/phy/fec/crc.h similarity index 100% rename from srslte/include/srslte/fec/crc.h rename to lib/include/srslte/phy/fec/crc.h diff --git a/srslte/include/srslte/fec/rm_conv.h b/lib/include/srslte/phy/fec/rm_conv.h similarity index 100% rename from srslte/include/srslte/fec/rm_conv.h rename to lib/include/srslte/phy/fec/rm_conv.h diff --git a/srslte/include/srslte/fec/rm_turbo.h b/lib/include/srslte/phy/fec/rm_turbo.h similarity index 100% rename from srslte/include/srslte/fec/rm_turbo.h rename to lib/include/srslte/phy/fec/rm_turbo.h diff --git a/srslte/include/srslte/fec/softbuffer.h b/lib/include/srslte/phy/fec/softbuffer.h similarity index 98% rename from srslte/include/srslte/fec/softbuffer.h rename to lib/include/srslte/phy/fec/softbuffer.h index 28e5de69c..a47cc7b96 100644 --- a/srslte/include/srslte/fec/softbuffer.h +++ b/lib/include/srslte/phy/fec/softbuffer.h @@ -37,7 +37,7 @@ #define SOFTBUFFER_ #include "srslte/config.h" -#include "srslte/common/phy_common.h" +#include "srslte/phy/common/phy_common.h" typedef struct SRSLTE_API { uint32_t max_cb; diff --git a/srslte/include/srslte/fec/tc_interl.h b/lib/include/srslte/phy/fec/tc_interl.h similarity index 100% rename from srslte/include/srslte/fec/tc_interl.h rename to lib/include/srslte/phy/fec/tc_interl.h diff --git a/srslte/include/srslte/fec/turbocoder.h b/lib/include/srslte/phy/fec/turbocoder.h similarity index 95% rename from srslte/include/srslte/fec/turbocoder.h rename to lib/include/srslte/phy/fec/turbocoder.h index 710a9f5fe..119e4f641 100644 --- a/srslte/include/srslte/fec/turbocoder.h +++ b/lib/include/srslte/phy/fec/turbocoder.h @@ -39,7 +39,7 @@ #define TURBOCODER_ #include "srslte/config.h" -#include "srslte/fec/tc_interl.h" +#include "srslte/phy/fec/tc_interl.h" #define SRSLTE_TCOD_MAX_LEN_CB_BYTES (6144/8) diff --git a/srslte/include/srslte/fec/turbodecoder.h b/lib/include/srslte/phy/fec/turbodecoder.h similarity index 92% rename from srslte/include/srslte/fec/turbodecoder.h rename to lib/include/srslte/phy/fec/turbodecoder.h index c887cba83..149841fad 100644 --- a/srslte/include/srslte/fec/turbodecoder.h +++ b/lib/include/srslte/phy/fec/turbodecoder.h @@ -40,8 +40,8 @@ #define TURBODECODER_ #include "srslte/config.h" -#include "srslte/fec/tc_interl.h" -#include "srslte/fec/cbsegm.h" +#include "srslte/phy/fec/tc_interl.h" +#include "srslte/phy/fec/cbsegm.h" #define SRSLTE_TCOD_RATE 3 #define SRSLTE_TCOD_TOTALTAIL 12 @@ -49,10 +49,10 @@ #define SRSLTE_TCOD_MAX_LEN_CB 6144 #define SRSLTE_TCOD_MAX_LEN_CODED (SRSLTE_TCOD_RATE*SRSLTE_TCOD_MAX_LEN_CB+SRSLTE_TCOD_TOTALTAIL) -#include "srslte/fec/turbodecoder_gen.h" +#include "srslte/phy/fec/turbodecoder_gen.h" #ifdef LV_HAVE_SSE -#include "srslte/fec/turbodecoder_sse.h" +#include "srslte/phy/fec/turbodecoder_sse.h" #endif typedef struct SRSLTE_API { diff --git a/srslte/include/srslte/fec/turbodecoder_gen.h b/lib/include/srslte/phy/fec/turbodecoder_gen.h similarity index 94% rename from srslte/include/srslte/fec/turbodecoder_gen.h rename to lib/include/srslte/phy/fec/turbodecoder_gen.h index a8a4e14cd..7f219201a 100644 --- a/srslte/include/srslte/fec/turbodecoder_gen.h +++ b/lib/include/srslte/phy/fec/turbodecoder_gen.h @@ -40,8 +40,8 @@ #define TURBODECODER_GEN_ #include "srslte/config.h" -#include "srslte/fec/tc_interl.h" -#include "srslte/fec/cbsegm.h" +#include "srslte/phy/fec/tc_interl.h" +#include "srslte/phy/fec/cbsegm.h" #define SRSLTE_TCOD_RATE 3 #define SRSLTE_TCOD_TOTALTAIL 12 diff --git a/srslte/include/srslte/fec/turbodecoder_sse.h b/lib/include/srslte/phy/fec/turbodecoder_sse.h similarity index 94% rename from srslte/include/srslte/fec/turbodecoder_sse.h rename to lib/include/srslte/phy/fec/turbodecoder_sse.h index 52cbc7333..8b9f24372 100644 --- a/srslte/include/srslte/fec/turbodecoder_sse.h +++ b/lib/include/srslte/phy/fec/turbodecoder_sse.h @@ -40,8 +40,8 @@ #define TURBODECODER_SSE_ #include "srslte/config.h" -#include "srslte/fec/tc_interl.h" -#include "srslte/fec/cbsegm.h" +#include "srslte/phy/fec/tc_interl.h" +#include "srslte/phy/fec/cbsegm.h" #define SRSLTE_TCOD_RATE 3 #define SRSLTE_TCOD_TOTALTAIL 12 diff --git a/srslte/include/srslte/fec/viterbi.h b/lib/include/srslte/phy/fec/viterbi.h similarity index 85% rename from srslte/include/srslte/fec/viterbi.h rename to lib/include/srslte/phy/fec/viterbi.h index 1707daf8b..d69750fb3 100644 --- a/srslte/include/srslte/fec/viterbi.h +++ b/lib/include/srslte/phy/fec/viterbi.h @@ -100,6 +100,18 @@ SRSLTE_API int srslte_viterbi_init_sse(srslte_viterbi_t *q, uint32_t max_frame_length, bool tail_bitting); +SRSLTE_API int srslte_viterbi_init_neon(srslte_viterbi_t *q, + srslte_viterbi_type_t type, + int poly[3], + uint32_t max_frame_length, + bool tail_bitting); + +SRSLTE_API int srslte_viterbi_init_avx2(srslte_viterbi_t *q, + srslte_viterbi_type_t type, + int poly[3], + uint32_t max_frame_length, + bool tail_bitting); + #endif diff --git a/srslte/include/srslte/io/binsource.h b/lib/include/srslte/phy/io/binsource.h similarity index 100% rename from srslte/include/srslte/io/binsource.h rename to lib/include/srslte/phy/io/binsource.h diff --git a/srslte/include/srslte/io/filesink.h b/lib/include/srslte/phy/io/filesink.h similarity index 98% rename from srslte/include/srslte/io/filesink.h rename to lib/include/srslte/phy/io/filesink.h index 106cba8c5..b8ca8db51 100644 --- a/srslte/include/srslte/io/filesink.h +++ b/lib/include/srslte/phy/io/filesink.h @@ -41,7 +41,7 @@ #include #include "srslte/config.h" -#include "srslte/io/format.h" +#include "srslte/phy/io/format.h" /* Low-level API */ typedef struct SRSLTE_API { diff --git a/srslte/include/srslte/io/filesource.h b/lib/include/srslte/phy/io/filesource.h similarity index 98% rename from srslte/include/srslte/io/filesource.h rename to lib/include/srslte/phy/io/filesource.h index e966dcbde..ee8bc080d 100644 --- a/srslte/include/srslte/io/filesource.h +++ b/lib/include/srslte/phy/io/filesource.h @@ -41,7 +41,7 @@ #include #include "srslte/config.h" -#include "srslte/io/format.h" +#include "srslte/phy/io/format.h" /* Low-level API */ typedef struct SRSLTE_API { diff --git a/srslte/include/srslte/io/format.h b/lib/include/srslte/phy/io/format.h similarity index 100% rename from srslte/include/srslte/io/format.h rename to lib/include/srslte/phy/io/format.h diff --git a/srslte/include/srslte/io/netsink.h b/lib/include/srslte/phy/io/netsink.h similarity index 100% rename from srslte/include/srslte/io/netsink.h rename to lib/include/srslte/phy/io/netsink.h diff --git a/srslte/include/srslte/io/netsource.h b/lib/include/srslte/phy/io/netsource.h similarity index 100% rename from srslte/include/srslte/io/netsource.h rename to lib/include/srslte/phy/io/netsource.h diff --git a/srslte/include/srslte/mimo/layermap.h b/lib/include/srslte/phy/mimo/layermap.h similarity index 98% rename from srslte/include/srslte/mimo/layermap.h rename to lib/include/srslte/phy/mimo/layermap.h index 998cf3fde..5daf51c14 100644 --- a/srslte/include/srslte/mimo/layermap.h +++ b/lib/include/srslte/phy/mimo/layermap.h @@ -38,7 +38,7 @@ #define LAYERMAP_H_ #include "srslte/config.h" -#include "srslte/common/phy_common.h" +#include "srslte/phy/common/phy_common.h" /* Generates the vector of layer-mapped symbols "x" based on the vector of data symbols "d" */ diff --git a/srslte/include/srslte/mimo/precoding.h b/lib/include/srslte/phy/mimo/precoding.h similarity index 99% rename from srslte/include/srslte/mimo/precoding.h rename to lib/include/srslte/phy/mimo/precoding.h index 0002daebb..62fad08ef 100644 --- a/srslte/include/srslte/mimo/precoding.h +++ b/lib/include/srslte/phy/mimo/precoding.h @@ -37,7 +37,7 @@ #define PRECODING_H_ #include "srslte/config.h" -#include "srslte/common/phy_common.h" +#include "srslte/phy/common/phy_common.h" /** The precoder takes as input nlayers vectors "x" from the * layer mapping and generates nports vectors "y" to be mapped onto diff --git a/srslte/include/srslte/modem/demod_hard.h b/lib/include/srslte/phy/modem/demod_hard.h similarity index 100% rename from srslte/include/srslte/modem/demod_hard.h rename to lib/include/srslte/phy/modem/demod_hard.h diff --git a/srslte/include/srslte/modem/demod_soft.h b/lib/include/srslte/phy/modem/demod_soft.h similarity index 100% rename from srslte/include/srslte/modem/demod_soft.h rename to lib/include/srslte/phy/modem/demod_soft.h diff --git a/srslte/include/srslte/modem/mod.h b/lib/include/srslte/phy/modem/mod.h similarity index 100% rename from srslte/include/srslte/modem/mod.h rename to lib/include/srslte/phy/modem/mod.h diff --git a/srslte/include/srslte/modem/modem_table.h b/lib/include/srslte/phy/modem/modem_table.h similarity index 98% rename from srslte/include/srslte/modem/modem_table.h rename to lib/include/srslte/phy/modem/modem_table.h index 576a7598f..20b0a0f88 100644 --- a/srslte/include/srslte/modem/modem_table.h +++ b/lib/include/srslte/phy/modem/modem_table.h @@ -40,7 +40,7 @@ #include #include -#include "srslte/common/phy_common.h" +#include "srslte/phy/common/phy_common.h" #include "srslte/config.h" typedef struct { diff --git a/srslte/include/srslte/phch/cqi.h b/lib/include/srslte/phy/phch/cqi.h similarity index 99% rename from srslte/include/srslte/phch/cqi.h rename to lib/include/srslte/phy/phch/cqi.h index 9a7b243be..f6857dfa0 100644 --- a/srslte/include/srslte/phch/cqi.h +++ b/lib/include/srslte/phy/phch/cqi.h @@ -38,7 +38,7 @@ #include #include "srslte/config.h" -#include "srslte/common/phy_common.h" +#include "srslte/phy/common/phy_common.h" #define SRSLTE_CQI_MAX_BITS 64 diff --git a/srslte/include/srslte/phch/dci.h b/lib/include/srslte/phy/phch/dci.h similarity index 98% rename from srslte/include/srslte/phch/dci.h rename to lib/include/srslte/phy/phch/dci.h index 1bc169f77..6976a6b24 100644 --- a/srslte/include/srslte/phch/dci.h +++ b/lib/include/srslte/phy/phch/dci.h @@ -40,8 +40,8 @@ #include #include "srslte/config.h" -#include "srslte/common/phy_common.h" -#include "srslte/phch/ra.h" +#include "srslte/phy/common/phy_common.h" +#include "srslte/phy/phch/ra.h" #define SRSLTE_DCI_MAX_BITS 128 diff --git a/srslte/include/srslte/phch/pbch.h b/lib/include/srslte/phy/phch/pbch.h similarity index 89% rename from srslte/include/srslte/phch/pbch.h rename to lib/include/srslte/phy/phch/pbch.h index e63f52f07..8489df05a 100644 --- a/srslte/include/srslte/phch/pbch.h +++ b/lib/include/srslte/phy/phch/pbch.h @@ -38,16 +38,16 @@ #define PBCH_ #include "srslte/config.h" -#include "srslte/common/phy_common.h" -#include "srslte/mimo/precoding.h" -#include "srslte/mimo/layermap.h" -#include "srslte/modem/mod.h" -#include "srslte/modem/demod_soft.h" -#include "srslte/scrambling/scrambling.h" -#include "srslte/fec/rm_conv.h" -#include "srslte/fec/convcoder.h" -#include "srslte/fec/viterbi.h" -#include "srslte/fec/crc.h" +#include "srslte/phy/common/phy_common.h" +#include "srslte/phy/mimo/precoding.h" +#include "srslte/phy/mimo/layermap.h" +#include "srslte/phy/modem/mod.h" +#include "srslte/phy/modem/demod_soft.h" +#include "srslte/phy/scrambling/scrambling.h" +#include "srslte/phy/fec/rm_conv.h" +#include "srslte/phy/fec/convcoder.h" +#include "srslte/phy/fec/viterbi.h" +#include "srslte/phy/fec/crc.h" #define SRSLTE_BCH_PAYLOAD_LEN 24 #define SRSLTE_BCH_PAYLOADCRC_LEN (SRSLTE_BCH_PAYLOAD_LEN+16) diff --git a/srslte/include/srslte/phch/pcfich.h b/lib/include/srslte/phy/phch/pcfich.h similarity index 92% rename from srslte/include/srslte/phch/pcfich.h rename to lib/include/srslte/phy/phch/pcfich.h index 91cbd5229..672caed2c 100644 --- a/srslte/include/srslte/phch/pcfich.h +++ b/lib/include/srslte/phy/phch/pcfich.h @@ -36,13 +36,13 @@ #define PCFICH_ #include "srslte/config.h" -#include "srslte/common/phy_common.h" -#include "srslte/mimo/precoding.h" -#include "srslte/mimo/layermap.h" -#include "srslte/modem/mod.h" -#include "srslte/modem/demod_soft.h" -#include "srslte/scrambling/scrambling.h" -#include "srslte/phch/regs.h" +#include "srslte/phy/common/phy_common.h" +#include "srslte/phy/mimo/precoding.h" +#include "srslte/phy/mimo/layermap.h" +#include "srslte/phy/modem/mod.h" +#include "srslte/phy/modem/demod_soft.h" +#include "srslte/phy/scrambling/scrambling.h" +#include "srslte/phy/phch/regs.h" #define PCFICH_CFI_LEN 32 #define PCFICH_RE PCFICH_CFI_LEN/2 diff --git a/srslte/include/srslte/phch/pdcch.h b/lib/include/srslte/phy/phch/pdcch.h similarity index 93% rename from srslte/include/srslte/phch/pdcch.h rename to lib/include/srslte/phy/phch/pdcch.h index a83bf6ffd..8d4aba790 100644 --- a/srslte/include/srslte/phch/pdcch.h +++ b/lib/include/srslte/phy/phch/pdcch.h @@ -36,18 +36,18 @@ #define PDCCH_ #include "srslte/config.h" -#include "srslte/common/phy_common.h" -#include "srslte/mimo/precoding.h" -#include "srslte/mimo/layermap.h" -#include "srslte/modem/mod.h" -#include "srslte/modem/demod_soft.h" -#include "srslte/scrambling/scrambling.h" -#include "srslte/fec/rm_conv.h" -#include "srslte/fec/convcoder.h" -#include "srslte/fec/viterbi.h" -#include "srslte/fec/crc.h" -#include "srslte/phch/dci.h" -#include "srslte/phch/regs.h" +#include "srslte/phy/common/phy_common.h" +#include "srslte/phy/mimo/precoding.h" +#include "srslte/phy/mimo/layermap.h" +#include "srslte/phy/modem/mod.h" +#include "srslte/phy/modem/demod_soft.h" +#include "srslte/phy/scrambling/scrambling.h" +#include "srslte/phy/fec/rm_conv.h" +#include "srslte/phy/fec/convcoder.h" +#include "srslte/phy/fec/viterbi.h" +#include "srslte/phy/fec/crc.h" +#include "srslte/phy/phch/dci.h" +#include "srslte/phy/phch/regs.h" diff --git a/srslte/include/srslte/phch/pdsch.h b/lib/include/srslte/phy/phch/pdsch.h similarity index 91% rename from srslte/include/srslte/phch/pdsch.h rename to lib/include/srslte/phy/phch/pdsch.h index 7e90973ed..7730d2fa1 100644 --- a/srslte/include/srslte/phch/pdsch.h +++ b/lib/include/srslte/phy/phch/pdsch.h @@ -36,16 +36,16 @@ #define PDSCH_ #include "srslte/config.h" -#include "srslte/common/phy_common.h" -#include "srslte/mimo/precoding.h" -#include "srslte/mimo/layermap.h" -#include "srslte/modem/mod.h" -#include "srslte/modem/demod_soft.h" -#include "srslte/scrambling/scrambling.h" -#include "srslte/phch/dci.h" -#include "srslte/phch/regs.h" -#include "srslte/phch/sch.h" -#include "srslte/phch/pdsch_cfg.h" +#include "srslte/phy/common/phy_common.h" +#include "srslte/phy/mimo/precoding.h" +#include "srslte/phy/mimo/layermap.h" +#include "srslte/phy/modem/mod.h" +#include "srslte/phy/modem/demod_soft.h" +#include "srslte/phy/scrambling/scrambling.h" +#include "srslte/phy/phch/dci.h" +#include "srslte/phy/phch/regs.h" +#include "srslte/phy/phch/sch.h" +#include "srslte/phy/phch/pdsch_cfg.h" typedef struct { srslte_sequence_t seq[SRSLTE_NSUBFRAMES_X_FRAME]; diff --git a/srslte/include/srslte/phch/pdsch_cfg.h b/lib/include/srslte/phy/phch/pdsch_cfg.h similarity index 92% rename from srslte/include/srslte/phch/pdsch_cfg.h rename to lib/include/srslte/phy/phch/pdsch_cfg.h index 07ece3a7b..2745470f8 100644 --- a/srslte/include/srslte/phch/pdsch_cfg.h +++ b/lib/include/srslte/phy/phch/pdsch_cfg.h @@ -35,9 +35,9 @@ #ifndef PDSCHCFG_ #define PDSCHCFG_ -#include "srslte/phch/ra.h" -#include "srslte/fec/softbuffer.h" -#include "srslte/fec/cbsegm.h" +#include "srslte/phy/phch/ra.h" +#include "srslte/phy/fec/softbuffer.h" +#include "srslte/phy/fec/cbsegm.h" typedef struct SRSLTE_API { srslte_cbsegm_t cb_segm; diff --git a/srslte/include/srslte/phch/phich.h b/lib/include/srslte/phy/phch/phich.h similarity index 95% rename from srslte/include/srslte/phch/phich.h rename to lib/include/srslte/phy/phch/phich.h index 2e477b41e..18454a2d5 100644 --- a/srslte/include/srslte/phch/phich.h +++ b/lib/include/srslte/phy/phch/phich.h @@ -36,12 +36,12 @@ #define PHICH_ #include "srslte/config.h" -#include "srslte/common/phy_common.h" -#include "srslte/mimo/precoding.h" -#include "srslte/mimo/layermap.h" -#include "srslte/modem/mod.h" -#include "srslte/modem/demod_soft.h" -#include "srslte/scrambling/scrambling.h" +#include "srslte/phy/common/phy_common.h" +#include "srslte/phy/mimo/precoding.h" +#include "srslte/phy/mimo/layermap.h" +#include "srslte/phy/modem/mod.h" +#include "srslte/phy/modem/demod_soft.h" +#include "srslte/phy/scrambling/scrambling.h" #include "regs.h" diff --git a/srslte/include/srslte/phch/prach.h b/lib/include/srslte/phy/phch/prach.h similarity index 98% rename from srslte/include/srslte/phch/prach.h rename to lib/include/srslte/phy/phch/prach.h index 69c79aea2..a08256a57 100644 --- a/srslte/include/srslte/phch/prach.h +++ b/lib/include/srslte/phy/phch/prach.h @@ -40,8 +40,8 @@ #include #include #include "srslte/config.h" -#include "srslte/dft/dft.h" -#include "srslte/common/phy_common.h" +#include "srslte/phy/dft/dft.h" +#include "srslte/phy/common/phy_common.h" /** Generation and detection of RACH signals for uplink. diff --git a/srslte/include/srslte/phch/pucch.h b/lib/include/srslte/phy/phch/pucch.h similarity index 97% rename from srslte/include/srslte/phch/pucch.h rename to lib/include/srslte/phy/phch/pucch.h index a91274441..3542dc53f 100644 --- a/srslte/include/srslte/phch/pucch.h +++ b/lib/include/srslte/phy/phch/pucch.h @@ -36,11 +36,11 @@ #define PUCCH_ #include "srslte/config.h" -#include "srslte/common/phy_common.h" -#include "srslte/common/sequence.h" -#include "srslte/modem/mod.h" -#include "srslte/phch/cqi.h" -#include "srslte/phch/uci.h" +#include "srslte/phy/common/phy_common.h" +#include "srslte/phy/common/sequence.h" +#include "srslte/phy/modem/mod.h" +#include "srslte/phy/phch/cqi.h" +#include "srslte/phy/phch/uci.h" #define SRSLTE_PUCCH_N_SEQ 12 #define SRSLTE_PUCCH2_NOF_BITS SRSLTE_UCI_CQI_CODED_PUCCH_B diff --git a/srslte/include/srslte/phch/pusch.h b/lib/include/srslte/phy/phch/pusch.h similarity index 89% rename from srslte/include/srslte/phch/pusch.h rename to lib/include/srslte/phy/phch/pusch.h index 25f4f40d8..bf04a4781 100644 --- a/srslte/include/srslte/phch/pusch.h +++ b/lib/include/srslte/phy/phch/pusch.h @@ -36,18 +36,18 @@ #define PUSCH_ #include "srslte/config.h" -#include "srslte/common/phy_common.h" -#include "srslte/mimo/precoding.h" -#include "srslte/mimo/layermap.h" -#include "srslte/modem/mod.h" -#include "srslte/modem/demod_soft.h" -#include "srslte/scrambling/scrambling.h" -#include "srslte/phch/regs.h" -#include "srslte/phch/dci.h" -#include "srslte/phch/sch.h" -#include "srslte/phch/pusch_cfg.h" -#include "srslte/dft/dft_precoding.h" -#include "srslte/ch_estimation/refsignal_ul.h" +#include "srslte/phy/common/phy_common.h" +#include "srslte/phy/mimo/precoding.h" +#include "srslte/phy/mimo/layermap.h" +#include "srslte/phy/modem/mod.h" +#include "srslte/phy/modem/demod_soft.h" +#include "srslte/phy/scrambling/scrambling.h" +#include "srslte/phy/phch/regs.h" +#include "srslte/phy/phch/dci.h" +#include "srslte/phy/phch/sch.h" +#include "srslte/phy/phch/pusch_cfg.h" +#include "srslte/phy/dft/dft_precoding.h" +#include "srslte/phy/ch_estimation/refsignal_ul.h" #define SRSLTE_PUSCH_MAX_TDEC_ITERS 5 diff --git a/srslte/include/srslte/phch/pusch_cfg.h b/lib/include/srslte/phy/phch/pusch_cfg.h similarity index 93% rename from srslte/include/srslte/phch/pusch_cfg.h rename to lib/include/srslte/phy/phch/pusch_cfg.h index eb9abe02d..5d743d94c 100644 --- a/srslte/include/srslte/phch/pusch_cfg.h +++ b/lib/include/srslte/phy/phch/pusch_cfg.h @@ -35,9 +35,9 @@ #ifndef PUSCHCFG_ #define PUSCHCFG_ -#include "srslte/phch/ra.h" -#include "srslte/fec/softbuffer.h" -#include "srslte/fec/cbsegm.h" +#include "srslte/phy/phch/ra.h" +#include "srslte/phy/fec/softbuffer.h" +#include "srslte/phy/fec/cbsegm.h" typedef struct SRSLTE_API { uint32_t I_offset_cqi; diff --git a/srslte/include/srslte/phch/ra.h b/lib/include/srslte/phy/phch/ra.h similarity index 99% rename from srslte/include/srslte/phch/ra.h rename to lib/include/srslte/phy/phch/ra.h index fb17703dd..cec2e6087 100644 --- a/srslte/include/srslte/phch/ra.h +++ b/lib/include/srslte/phy/phch/ra.h @@ -40,7 +40,7 @@ #include #include "srslte/config.h" -#include "srslte/common/phy_common.h" +#include "srslte/phy/common/phy_common.h" /************************************************** * Common structures used for Resource Allocation diff --git a/srslte/include/srslte/phch/regs.h b/lib/include/srslte/phy/phch/regs.h similarity index 99% rename from srslte/include/srslte/phch/regs.h rename to lib/include/srslte/phy/phch/regs.h index f7d5f91f1..9d5129e36 100644 --- a/srslte/include/srslte/phch/regs.h +++ b/lib/include/srslte/phy/phch/regs.h @@ -37,7 +37,7 @@ #include #include "srslte/config.h" -#include "srslte/common/phy_common.h" +#include "srslte/phy/common/phy_common.h" #define REGS_PHICH_NSYM 12 #define REGS_PHICH_REGS_X_GROUP 3 diff --git a/srslte/include/srslte/phch/sch.h b/lib/include/srslte/phy/phch/sch.h similarity index 94% rename from srslte/include/srslte/phch/sch.h rename to lib/include/srslte/phy/phch/sch.h index 7c365120b..4ef0b3070 100644 --- a/srslte/include/srslte/phch/sch.h +++ b/lib/include/srslte/phy/phch/sch.h @@ -36,14 +36,14 @@ #define SCH_ #include "srslte/config.h" -#include "srslte/common/phy_common.h" -#include "srslte/fec/rm_turbo.h" -#include "srslte/fec/turbocoder.h" -#include "srslte/fec/turbodecoder.h" -#include "srslte/fec/crc.h" -#include "srslte/phch/pdsch_cfg.h" -#include "srslte/phch/pusch_cfg.h" -#include "srslte/phch/uci.h" +#include "srslte/phy/common/phy_common.h" +#include "srslte/phy/fec/rm_turbo.h" +#include "srslte/phy/fec/turbocoder.h" +#include "srslte/phy/fec/turbodecoder.h" +#include "srslte/phy/fec/crc.h" +#include "srslte/phy/phch/pdsch_cfg.h" +#include "srslte/phy/phch/pusch_cfg.h" +#include "srslte/phy/phch/uci.h" #ifndef SRSLTE_RX_NULL #define SRSLTE_RX_NULL 10000 diff --git a/srslte/include/srslte/phch/uci.h b/lib/include/srslte/phy/phch/uci.h similarity index 96% rename from srslte/include/srslte/phch/uci.h rename to lib/include/srslte/phy/phch/uci.h index fa916c283..bad87866e 100644 --- a/srslte/include/srslte/phch/uci.h +++ b/lib/include/srslte/phy/phch/uci.h @@ -36,11 +36,11 @@ #define UCI_ #include "srslte/config.h" -#include "srslte/common/phy_common.h" -#include "srslte/phch/pusch_cfg.h" -#include "srslte/fec/crc.h" -#include "srslte/fec/viterbi.h" -#include "srslte/phch/cqi.h" +#include "srslte/phy/common/phy_common.h" +#include "srslte/phy/phch/pusch_cfg.h" +#include "srslte/phy/fec/crc.h" +#include "srslte/phy/fec/viterbi.h" +#include "srslte/phy/phch/cqi.h" #define SRSLTE_UCI_MAX_CQI_LEN_PUSCH 512 #define SRSLTE_UCI_MAX_CQI_LEN_PUCCH 13 diff --git a/srslte/include/srslte/resampling/decim.h b/lib/include/srslte/phy/resampling/decim.h similarity index 100% rename from srslte/include/srslte/resampling/decim.h rename to lib/include/srslte/phy/resampling/decim.h diff --git a/srslte/include/srslte/resampling/interp.h b/lib/include/srslte/phy/resampling/interp.h similarity index 100% rename from srslte/include/srslte/resampling/interp.h rename to lib/include/srslte/phy/resampling/interp.h diff --git a/srslte/include/srslte/resampling/resample_arb.h b/lib/include/srslte/phy/resampling/resample_arb.h similarity index 100% rename from srslte/include/srslte/resampling/resample_arb.h rename to lib/include/srslte/phy/resampling/resample_arb.h diff --git a/srslte/include/srslte/rf/rf.h b/lib/include/srslte/phy/rf/rf.h similarity index 100% rename from srslte/include/srslte/rf/rf.h rename to lib/include/srslte/phy/rf/rf.h diff --git a/srslte/include/srslte/rf/rf_utils.h b/lib/include/srslte/phy/rf/rf_utils.h similarity index 98% rename from srslte/include/srslte/rf/rf_utils.h rename to lib/include/srslte/phy/rf/rf_utils.h index c5f55a6c1..7dddb20f4 100644 --- a/srslte/include/srslte/rf/rf_utils.h +++ b/lib/include/srslte/phy/rf/rf_utils.h @@ -26,7 +26,7 @@ #include "srslte/srslte.h" -#include "srslte/rf/rf.h" +#include "srslte/phy/rf/rf.h" typedef struct SRSLTE_API { uint32_t max_frames_pbch; // timeout in number of 5ms frames for MIB decoding diff --git a/srslte/include/srslte/scrambling/scrambling.h b/lib/include/srslte/phy/scrambling/scrambling.h similarity index 97% rename from srslte/include/srslte/scrambling/scrambling.h rename to lib/include/srslte/phy/scrambling/scrambling.h index 4e1fe40e6..4fa74790a 100644 --- a/srslte/include/srslte/scrambling/scrambling.h +++ b/lib/include/srslte/phy/scrambling/scrambling.h @@ -36,8 +36,8 @@ #define SCRAMBLING_ #include "srslte/config.h" -#include "srslte/common/sequence.h" -#include "srslte/common/phy_common.h" +#include "srslte/phy/common/sequence.h" +#include "srslte/phy/common/phy_common.h" /* Scrambling has no state */ SRSLTE_API void srslte_scrambling_b(srslte_sequence_t *s, diff --git a/srslte/include/srslte/sync/cfo.h b/lib/include/srslte/phy/sync/cfo.h similarity index 98% rename from srslte/include/srslte/sync/cfo.h rename to lib/include/srslte/phy/sync/cfo.h index b2cbce644..642e81fc4 100644 --- a/srslte/include/srslte/sync/cfo.h +++ b/lib/include/srslte/phy/sync/cfo.h @@ -38,7 +38,7 @@ #include #include "srslte/config.h" -#include "srslte/utils/cexptab.h" +#include "srslte/phy/utils/cexptab.h" /** If the frequency is changed more than the tolerance, a new table is generated */ #define SRSLTE_CFO_TOLERANCE 0.00001 diff --git a/srslte/include/srslte/sync/cp.h b/lib/include/srslte/phy/sync/cp.h similarity index 100% rename from srslte/include/srslte/sync/cp.h rename to lib/include/srslte/phy/sync/cp.h diff --git a/srslte/include/srslte/sync/pss.h b/lib/include/srslte/phy/sync/pss.h similarity index 90% rename from srslte/include/srslte/sync/pss.h rename to lib/include/srslte/phy/sync/pss.h index 0c7830792..f18c5b6af 100644 --- a/srslte/include/srslte/sync/pss.h +++ b/lib/include/srslte/phy/sync/pss.h @@ -49,8 +49,9 @@ #include #include "srslte/config.h" -#include "srslte/common/phy_common.h" -#include "srslte/utils/convolution.h" +#include "srslte/phy/common/phy_common.h" +#include "srslte/phy/utils/convolution.h" +#include "srslte/phy/utils/filter.h" #define CONVOLUTION_FFT @@ -74,13 +75,17 @@ typedef struct SRSLTE_API { #ifdef CONVOLUTION_FFT srslte_conv_fft_cc_t conv_fft; -#endif + srslte_filt_cc_t filter; +#endif + int decimate; uint32_t frame_size; uint32_t N_id_2; uint32_t fft_size; - + cf_t *pss_signal_freq_full[3]; + cf_t *pss_signal_time[3]; + cf_t pss_signal_freq[3][SRSLTE_PSS_LEN]; // One sequence for each N_id_2 cf_t *tmp_input; cf_t *conv_output; @@ -102,6 +107,12 @@ SRSLTE_API int srslte_pss_synch_init_fft_offset(srslte_pss_synch_t *q, uint32_t fft_size, int cfo_i); +SRSLTE_API int srslte_pss_synch_init_fft_offset_decim(srslte_pss_synch_t *q, + uint32_t frame_size, + uint32_t fft_size, + int cfo_i, + int decimate); + SRSLTE_API int srslte_pss_synch_init(srslte_pss_synch_t *q, uint32_t frame_size); diff --git a/srslte/include/srslte/sync/sfo.h b/lib/include/srslte/phy/sync/sfo.h similarity index 100% rename from srslte/include/srslte/sync/sfo.h rename to lib/include/srslte/phy/sync/sfo.h diff --git a/srslte/include/srslte/sync/sss.h b/lib/include/srslte/phy/sync/sss.h similarity index 98% rename from srslte/include/srslte/sync/sss.h rename to lib/include/srslte/phy/sync/sss.h index 2d9ac5c4e..aca57e860 100644 --- a/srslte/include/srslte/sync/sss.h +++ b/lib/include/srslte/phy/sync/sss.h @@ -40,8 +40,8 @@ #include #include "srslte/config.h" -#include "srslte/common/phy_common.h" -#include "srslte/dft/dft.h" +#include "srslte/phy/common/phy_common.h" +#include "srslte/phy/dft/dft.h" #define SRSLTE_SSS_N 31 diff --git a/srslte/include/srslte/sync/sync.h b/lib/include/srslte/phy/sync/sync.h similarity index 94% rename from srslte/include/srslte/sync/sync.h rename to lib/include/srslte/phy/sync/sync.h index 364baed19..ab22d64fc 100644 --- a/srslte/include/srslte/sync/sync.h +++ b/lib/include/srslte/phy/sync/sync.h @@ -49,10 +49,10 @@ #include #include "srslte/config.h" -#include "srslte/sync/pss.h" -#include "srslte/sync/sss.h" -#include "srslte/sync/cfo.h" -#include "srslte/sync/cp.h" +#include "srslte/phy/sync/pss.h" +#include "srslte/phy/sync/sss.h" +#include "srslte/phy/sync/cfo.h" +#include "srslte/phy/sync/cp.h" #define SRSLTE_SYNC_FFT_SZ_MIN 64 #define SRSLTE_SYNC_FFT_SZ_MAX 2048 @@ -65,7 +65,7 @@ typedef struct SRSLTE_API { srslte_sss_synch_t sss; srslte_cp_synch_t cp_synch; cf_t *cfo_i_corr[2]; - + int decimate; float threshold; float peak_value; uint32_t N_id_2; @@ -112,6 +112,13 @@ SRSLTE_API int srslte_sync_init(srslte_sync_t *q, uint32_t max_offset, uint32_t fft_size); +SRSLTE_API int srslte_sync_init_decim(srslte_sync_t *q, + uint32_t frame_size, + uint32_t max_offset, + uint32_t fft_size, + int decimate); + + SRSLTE_API void srslte_sync_free(srslte_sync_t *q); SRSLTE_API void srslte_sync_reset(srslte_sync_t *q); diff --git a/srslte/include/srslte/ue/ue_cell_search.h b/lib/include/srslte/phy/ue/ue_cell_search.h similarity index 94% rename from srslte/include/srslte/ue/ue_cell_search.h rename to lib/include/srslte/phy/ue/ue_cell_search.h index 628683f09..bcabe1728 100644 --- a/srslte/include/srslte/ue/ue_cell_search.h +++ b/lib/include/srslte/phy/ue/ue_cell_search.h @@ -46,12 +46,12 @@ #include #include "srslte/config.h" -#include "srslte/ue/ue_sync.h" -#include "srslte/ue/ue_mib.h" -#include "srslte/sync/cfo.h" -#include "srslte/ch_estimation/chest_dl.h" -#include "srslte/phch/pbch.h" -#include "srslte/dft/ofdm.h" +#include "srslte/phy/ue/ue_sync.h" +#include "srslte/phy/ue/ue_mib.h" +#include "srslte/phy/sync/cfo.h" +#include "srslte/phy/ch_estimation/chest_dl.h" +#include "srslte/phy/phch/pbch.h" +#include "srslte/phy/dft/ofdm.h" #define SRSLTE_CS_NOF_PRB 6 #define SRSLTE_CS_SAMP_FREQ 1920000.0 diff --git a/srslte/include/srslte/ue/ue_dl.h b/lib/include/srslte/phy/ue/ue_dl.h similarity index 93% rename from srslte/include/srslte/ue/ue_dl.h rename to lib/include/srslte/phy/ue/ue_dl.h index a32794aa2..7c3f83320 100644 --- a/srslte/include/srslte/ue/ue_dl.h +++ b/lib/include/srslte/phy/ue/ue_dl.h @@ -40,23 +40,23 @@ #include -#include "srslte/ch_estimation/chest_dl.h" -#include "srslte/dft/ofdm.h" -#include "srslte/common/phy_common.h" +#include "srslte/phy/ch_estimation/chest_dl.h" +#include "srslte/phy/dft/ofdm.h" +#include "srslte/phy/common/phy_common.h" -#include "srslte/phch/dci.h" -#include "srslte/phch/pcfich.h" -#include "srslte/phch/pdcch.h" -#include "srslte/phch/pdsch.h" -#include "srslte/phch/pdsch_cfg.h" -#include "srslte/phch/phich.h" -#include "srslte/phch/ra.h" -#include "srslte/phch/regs.h" +#include "srslte/phy/phch/dci.h" +#include "srslte/phy/phch/pcfich.h" +#include "srslte/phy/phch/pdcch.h" +#include "srslte/phy/phch/pdsch.h" +#include "srslte/phy/phch/pdsch_cfg.h" +#include "srslte/phy/phch/phich.h" +#include "srslte/phy/phch/ra.h" +#include "srslte/phy/phch/regs.h" -#include "srslte/sync/cfo.h" +#include "srslte/phy/sync/cfo.h" -#include "srslte/utils/vector.h" -#include "srslte/utils/debug.h" +#include "srslte/phy/utils/vector.h" +#include "srslte/phy/utils/debug.h" #include "srslte/config.h" diff --git a/srslte/include/srslte/ue/ue_mib.h b/lib/include/srslte/phy/ue/ue_mib.h similarity index 96% rename from srslte/include/srslte/ue/ue_mib.h rename to lib/include/srslte/phy/ue/ue_mib.h index 202b6ee7f..abefa014f 100644 --- a/srslte/include/srslte/ue/ue_mib.h +++ b/lib/include/srslte/phy/ue/ue_mib.h @@ -49,11 +49,11 @@ #include #include "srslte/config.h" -#include "srslte/ue/ue_sync.h" -#include "srslte/sync/cfo.h" -#include "srslte/ch_estimation/chest_dl.h" -#include "srslte/phch/pbch.h" -#include "srslte/dft/ofdm.h" +#include "srslte/phy/ue/ue_sync.h" +#include "srslte/phy/sync/cfo.h" +#include "srslte/phy/ch_estimation/chest_dl.h" +#include "srslte/phy/phch/pbch.h" +#include "srslte/phy/dft/ofdm.h" #define SRSLTE_UE_MIB_NOF_PRB 6 diff --git a/srslte/include/srslte/ue/ue_phy.h b/lib/include/srslte/phy/ue/ue_phy.h similarity index 99% rename from srslte/include/srslte/ue/ue_phy.h rename to lib/include/srslte/phy/ue/ue_phy.h index 8f760e127..369b96027 100644 --- a/srslte/include/srslte/ue/ue_phy.h +++ b/lib/include/srslte/phy/ue/ue_phy.h @@ -33,7 +33,7 @@ *****************************************************************************/ #include "srslte/srslte.h" -#include "srslte/utils/queue.h" +#include "srslte/phy/utils/queue.h" #ifndef UEPHY_H #define UEPHY_H diff --git a/srslte/include/srslte/ue/ue_sync.h b/lib/include/srslte/phy/ue/ue_sync.h similarity index 89% rename from srslte/include/srslte/ue/ue_sync.h rename to lib/include/srslte/phy/ue/ue_sync.h index 3764e4331..94d4f9136 100644 --- a/srslte/include/srslte/ue/ue_sync.h +++ b/lib/include/srslte/phy/ue/ue_sync.h @@ -52,14 +52,14 @@ #include #include "srslte/config.h" -#include "srslte/sync/sync.h" -#include "srslte/sync/cfo.h" -#include "srslte/agc/agc.h" -#include "srslte/ch_estimation/chest_dl.h" -#include "srslte/phch/pbch.h" -#include "srslte/dft/ofdm.h" -#include "srslte/common/timestamp.h" -#include "srslte/io/filesource.h" +#include "srslte/phy/sync/sync.h" +#include "srslte/phy/sync/cfo.h" +#include "srslte/phy/agc/agc.h" +#include "srslte/phy/ch_estimation/chest_dl.h" +#include "srslte/phy/phch/pbch.h" +#include "srslte/phy/dft/ofdm.h" +#include "srslte/phy/common/timestamp.h" +#include "srslte/phy/io/filesource.h" typedef enum SRSLTE_API { SF_FIND, SF_TRACK} srslte_ue_sync_state_t; @@ -73,7 +73,7 @@ typedef struct SRSLTE_API { srslte_agc_t agc; bool do_agc; uint32_t agc_period; - + int decimate; void *stream; void *stream_single; int (*recv_callback)(void*, cf_t*[SRSLTE_MAX_PORTS], uint32_t, srslte_timestamp_t*); @@ -135,6 +135,13 @@ SRSLTE_API int srslte_ue_sync_init_multi(srslte_ue_sync_t *q, uint32_t nof_rx_antennas, void *stream_handler); +SRSLTE_API int srslte_ue_sync_init_multi_decim(srslte_ue_sync_t *q, + srslte_cell_t cell, + int (recv_callback)(void*, cf_t*[SRSLTE_MAX_PORTS], uint32_t, srslte_timestamp_t*), + uint32_t nof_rx_antennas, + void *stream_handler, + int decimate); + SRSLTE_API int srslte_ue_sync_init_file(srslte_ue_sync_t *q, uint32_t nof_prb, char *file_name, diff --git a/srslte/include/srslte/ue/ue_ul.h b/lib/include/srslte/phy/ue/ue_ul.h similarity index 95% rename from srslte/include/srslte/ue/ue_ul.h rename to lib/include/srslte/phy/ue/ue_ul.h index 20642cdcc..2afa8068a 100644 --- a/srslte/include/srslte/ue/ue_ul.h +++ b/lib/include/srslte/phy/ue/ue_ul.h @@ -38,16 +38,16 @@ #ifndef UEUL_H #define UEUL_H -#include "srslte/common/phy_common.h" -#include "srslte/ch_estimation/chest_dl.h" -#include "srslte/dft/ofdm.h" -#include "srslte/ch_estimation/refsignal_ul.h" -#include "srslte/phch/pusch.h" -#include "srslte/phch/dci.h" -#include "srslte/phch/ra.h" -#include "srslte/sync/cfo.h" -#include "srslte/utils/vector.h" -#include "srslte/utils/debug.h" +#include "srslte/phy/common/phy_common.h" +#include "srslte/phy/ch_estimation/chest_dl.h" +#include "srslte/phy/dft/ofdm.h" +#include "srslte/phy/ch_estimation/refsignal_ul.h" +#include "srslte/phy/phch/pusch.h" +#include "srslte/phy/phch/dci.h" +#include "srslte/phy/phch/ra.h" +#include "srslte/phy/sync/cfo.h" +#include "srslte/phy/utils/vector.h" +#include "srslte/phy/utils/debug.h" #include "srslte/config.h" diff --git a/srslte/include/srslte/utils/bit.h b/lib/include/srslte/phy/utils/bit.h similarity index 100% rename from srslte/include/srslte/utils/bit.h rename to lib/include/srslte/phy/utils/bit.h diff --git a/srslte/include/srslte/utils/cexptab.h b/lib/include/srslte/phy/utils/cexptab.h similarity index 100% rename from srslte/include/srslte/utils/cexptab.h rename to lib/include/srslte/phy/utils/cexptab.h diff --git a/srslte/include/srslte/utils/convolution.h b/lib/include/srslte/phy/utils/convolution.h similarity index 88% rename from srslte/include/srslte/utils/convolution.h rename to lib/include/srslte/phy/utils/convolution.h index 93fba38f8..27ea7e590 100644 --- a/srslte/include/srslte/utils/convolution.h +++ b/lib/include/srslte/phy/utils/convolution.h @@ -36,7 +36,7 @@ #define CONVOLUTION_H_ #include "srslte/config.h" -#include "srslte/dft/dft.h" +#include "srslte/phy/dft/dft.h" typedef struct SRSLTE_API { cf_t *input_fft; @@ -49,12 +49,16 @@ typedef struct SRSLTE_API { srslte_dft_plan_t input_plan; srslte_dft_plan_t filter_plan; srslte_dft_plan_t output_plan; + //cf_t *pss_signal_time_fft[3]; // One sequence for each N_id_2 + //cf_t *pss_signal_time[3]; + }srslte_conv_fft_cc_t; SRSLTE_API int srslte_conv_fft_cc_init(srslte_conv_fft_cc_t *q, uint32_t input_len, uint32_t filter_len); + SRSLTE_API void srslte_conv_fft_cc_free(srslte_conv_fft_cc_t *q); SRSLTE_API uint32_t srslte_conv_fft_cc_run(srslte_conv_fft_cc_t *q, @@ -62,6 +66,11 @@ SRSLTE_API uint32_t srslte_conv_fft_cc_run(srslte_conv_fft_cc_t *q, cf_t *filter, cf_t *output); +SRSLTE_API uint32_t srslte_conv_fft_cc_run_opt(srslte_conv_fft_cc_t *q, + cf_t *input, + cf_t *filter_freq, + cf_t *output); + SRSLTE_API uint32_t srslte_conv_cc(cf_t *input, cf_t *filter, cf_t *output, diff --git a/srslte/include/srslte/utils/debug.h b/lib/include/srslte/phy/utils/debug.h similarity index 100% rename from srslte/include/srslte/utils/debug.h rename to lib/include/srslte/phy/utils/debug.h diff --git a/lib/include/srslte/phy/utils/filter.h b/lib/include/srslte/phy/utils/filter.h new file mode 100644 index 000000000..70e00363c --- /dev/null +++ b/lib/include/srslte/phy/utils/filter.h @@ -0,0 +1,60 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsLTE library. + * + * 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: debug.h + * + * Description: Debug output utilities. + * + * Reference: + *****************************************************************************/ + +#ifndef FILTER_H +#define FILTER_H +#include +#include +#include "srslte/config.h" +#include +#include "srslte/phy/utils/vector.h" +typedef struct SRSLTE_API{ + cf_t *filter_input; + cf_t *downsampled_input; + cf_t *filter_output; + bool is_decimator; + int factor; + int num_taps; + float *taps; + +}srslte_filt_cc_t; + +void srslte_filt_decim_cc_init(srslte_filt_cc_t *q, int factor, int order); + +void srslte_filt_decim_cc_free(srslte_filt_cc_t *q); + +void srslte_filt_decim_cc_execute(srslte_filt_cc_t *q, cf_t *input, cf_t *downsampled_input, cf_t *output, int size); + +void srslte_downsample_cc(cf_t *input, cf_t *output, int M, int size) ; +#endif // FILTER_H \ No newline at end of file diff --git a/srslte/include/srslte/utils/ringbuffer.h b/lib/include/srslte/phy/utils/ringbuffer.h similarity index 100% rename from srslte/include/srslte/utils/ringbuffer.h rename to lib/include/srslte/phy/utils/ringbuffer.h diff --git a/srslte/include/srslte/utils/vector.h b/lib/include/srslte/phy/utils/vector.h similarity index 100% rename from srslte/include/srslte/utils/vector.h rename to lib/include/srslte/phy/utils/vector.h diff --git a/lib/include/srslte/phy/utils/vector_simd.h b/lib/include/srslte/phy/utils/vector_simd.h new file mode 100644 index 000000000..5cea166b3 --- /dev/null +++ b/lib/include/srslte/phy/utils/vector_simd.h @@ -0,0 +1,82 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsLTE library. + * + * 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 VECTORSIMD_ +#define VECTORSIMD_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include "srslte/config.h" + +SRSLTE_API int srslte_vec_dot_prod_sss_sse(short *x, short *y, uint32_t len); + +SRSLTE_API int srslte_vec_dot_prod_sss_avx(short *x, short *y, uint32_t len); + + + +SRSLTE_API void srslte_vec_sum_sss_sse(short *x, short *y, short *z, uint32_t len); + +SRSLTE_API void srslte_vec_sum_sss_avx(short *x, short *y, short *z, uint32_t len); + + + +SRSLTE_API void srslte_vec_sub_sss_sse(short *x, short *y, short *z, uint32_t len); + +SRSLTE_API void srslte_vec_sub_sss_avx(short *x, short *y, short *z, uint32_t len); + + + + + +SRSLTE_API void srslte_vec_prod_sss_sse(short *x, short *y, short *z, uint32_t len); + +SRSLTE_API void srslte_vec_prod_sss_avx(short *x, short *y, short *z, uint32_t len); + + +SRSLTE_API void srslte_vec_sc_div2_sss_sse(short *x, int n_rightshift, short *z, uint32_t len); + +SRSLTE_API void srslte_vec_sc_div2_sss_avx(short *x, int k, short *z, uint32_t len); + + + + + +SRSLTE_API void srslte_vec_lut_sss_sse(short *x, unsigned short *lut, short *y, uint32_t len); + +SRSLTE_API void srslte_vec_convert_fi_sse(float *x, int16_t *z, float scale, uint32_t len); + + + +SRSLTE_API void srslte_vec_mult_scalar_cf_f_avx( cf_t *z,const cf_t *x,const float h,const uint32_t len); +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib/include/srslte/radio/radio.h b/lib/include/srslte/radio/radio.h new file mode 100644 index 000000000..849c1c0e9 --- /dev/null +++ b/lib/include/srslte/radio/radio.h @@ -0,0 +1,175 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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 + +#include "srslte/srslte.h" +#include "srslte/phy/rf/rf.h" +#include "srslte/common/trace.h" + +#ifndef RADIO_H +#define RADIO_H + +typedef struct { + float tx_corr_dc_gain; + float tx_corr_dc_phase; + float tx_corr_iq_i; + float tx_corr_iq_q; + float rx_corr_dc_gain; + float rx_corr_dc_phase; + float rx_corr_iq_i; + float rx_corr_iq_q; +}rf_cal_t; + + +namespace srslte { + +/* Interface to the RF frontend. + */ + class radio + { + public: + radio() : tr_local_time(1024*10), tr_usrp_time(1024*10), tr_tx_time(1024*10), tr_is_eob(1024*10) { + bzero(&rf_device, sizeof(srslte_rf_t)); + bzero(&end_of_burst_time, sizeof(srslte_timestamp_t)); + bzero(zeros, burst_preamble_max_samples*sizeof(cf_t)); + + sf_len = 0; + burst_preamble_sec = 0; + is_start_of_burst = false; + burst_preamble_samples = 0; + burst_preamble_time_rounded = 0; + + cur_tx_srate = 0; + tx_adv_sec = 0; + tx_adv_nsamples = 0; + tx_adv_auto = false; + tx_adv_negative = false; + tx_freq = 0; + rx_freq = 0; + trace_enabled = false; + tti = 0; + agc_enabled = false; + offset = 0; + + }; + + bool init(char *args = NULL, char *devname = NULL); + void stop(); + bool start_agc(bool tx_gain_same_rx); + + void set_burst_preamble(double preamble_us); + void set_tx_adv(int nsamples); + void set_tx_adv_neg(bool tx_adv_is_neg); + + void set_manual_calibration(rf_cal_t *calibration); + + void get_time(srslte_timestamp_t *now); + bool tx(void *buffer, uint32_t nof_samples, srslte_timestamp_t tx_time); + void tx_end(); + bool rx_now(void *buffer, uint32_t nof_samples, srslte_timestamp_t *rxd_time); + bool rx_at(void *buffer, uint32_t nof_samples, srslte_timestamp_t rx_time); + + void set_tx_gain(float gain); + void set_rx_gain(float gain); + void set_tx_rx_gain_offset(float offset); + double set_rx_gain_th(float gain); + + void set_tx_freq(float freq); + void set_rx_freq(float freq); + + float get_tx_freq(); + float get_rx_freq(); + + void set_master_clock_rate(float rate); + void set_tx_srate(float srate); + void set_rx_srate(float srate); + + float get_tx_gain(); + float get_rx_gain(); + + float get_max_tx_power(); + float set_tx_power(float power); + float get_rssi(); + bool has_rssi(); + + void start_trace(); + void write_trace(std::string filename); + void start_rx(); + void stop_rx(); + + void set_tti(uint32_t tti); + void tx_offset(int offset); + void set_tti_len(uint32_t sf_len); + uint32_t get_tti_len(); + + void register_error_handler(srslte_rf_error_handler_t h); + + protected: + + void save_trace(uint32_t is_eob, srslte_timestamp_t *usrp_time); + + srslte_rf_t rf_device; + + + const static uint32_t burst_preamble_max_samples = 30720000; // 30.72 MHz is maximum frequency + double burst_preamble_sec;// Start of burst preamble time (off->on RF transition time) + srslte_timestamp_t end_of_burst_time; + bool is_start_of_burst; + uint32_t burst_preamble_samples; + double burst_preamble_time_rounded; // preamble time rounded to sample time + cf_t zeros[burst_preamble_max_samples]; + double cur_tx_srate; + + double tx_adv_sec; // Transmission time advance to compensate for antenna->timestamp delay + int tx_adv_nsamples; // Transmision time advance in number of samples + + // Define default values for known radios + bool tx_adv_auto; + bool tx_adv_negative; + const static double uhd_default_burst_preamble_sec = 600*1e-6; + const static double uhd_default_tx_adv_samples = 98; + const static double uhd_default_tx_adv_offset_sec = 4*1e-6; + + const static double blade_default_burst_preamble_sec = 0.0; + const static double blade_default_tx_adv_samples = 27; + const static double blade_default_tx_adv_offset_sec = 1e-6; + + float tx_freq, rx_freq; + + trace tr_local_time; + trace tr_usrp_time; + trace tr_tx_time; + trace tr_is_eob; + bool trace_enabled; + uint32_t tti; + bool agc_enabled; + int offset; + uint32_t sf_len; + }; +} + +#endif diff --git a/lib/include/srslte/radio/radio_multi.h b/lib/include/srslte/radio/radio_multi.h new file mode 100644 index 000000000..d83237619 --- /dev/null +++ b/lib/include/srslte/radio/radio_multi.h @@ -0,0 +1,54 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2017 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of srsLTE. + * + * srsUE 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. + * + * srsUE 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 + +#include "srslte/srslte.h" +extern "C" { +#include "srslte/phy/rf/rf.h" +} +#include "srslte/common/trace.h" + +#include "srslte/radio/radio.h" + +#ifndef RADIO_MULTI_H +#define RADIO_MULTI_H + + +namespace srslte { + +/* Interface to the RF frontend. + */ + class radio_multi : public radio + { + public: + + bool init_multi(uint32_t nof_rx_antennas, char *args = NULL, char *devname = NULL); + bool rx_now(cf_t *buffer[SRSLTE_MAX_PORTS], uint32_t nof_samples, srslte_timestamp_t *rxd_time); + }; +} + +#endif diff --git a/lib/include/srslte/srslte.h b/lib/include/srslte/srslte.h new file mode 100644 index 000000000..f44f5325d --- /dev/null +++ b/lib/include/srslte/srslte.h @@ -0,0 +1,129 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsLTE library. + * + * 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 _LTE_ +#define _LTE_ + +#ifdef __cplusplus + extern "C" { +#endif + +#include +#include + +#include "srslte/config.h" +#include "srslte/version.h" + +#include "srslte/phy/utils/bit.h" +#include "srslte/phy/utils/convolution.h" +#include "srslte/phy/utils/debug.h" +#include "srslte/phy/utils/cexptab.h" +#include "srslte/phy/utils/vector.h" + +#include "srslte/phy/common/timestamp.h" +#include "srslte/phy/common/sequence.h" +#include "srslte/phy/common/phy_common.h" + +#include "srslte/phy/ch_estimation/chest_ul.h" +#include "srslte/phy/ch_estimation/chest_dl.h" +#include "srslte/phy/ch_estimation/refsignal_dl.h" +#include "srslte/phy/ch_estimation/refsignal_ul.h" + +#include "srslte/phy/resampling/interp.h" +#include "srslte/phy/resampling/decim.h" +#include "srslte/phy/resampling/resample_arb.h" + +#include "srslte/phy/channel/ch_awgn.h" + +#include "srslte/phy/fec/viterbi.h" +#include "srslte/phy/fec/convcoder.h" +#include "srslte/phy/fec/crc.h" +#include "srslte/phy/fec/tc_interl.h" +#include "srslte/phy/fec/turbocoder.h" +#include "srslte/phy/fec/turbodecoder.h" +#include "srslte/phy/fec/cbsegm.h" +#include "srslte/phy/fec/rm_conv.h" +#include "srslte/phy/fec/rm_turbo.h" + +#include "srslte/phy/dft/dft_precoding.h" +#include "srslte/phy/dft/ofdm.h" +#include "srslte/phy/dft/dft.h" + +#include "srslte/phy/io/binsource.h" +#include "srslte/phy/io/filesink.h" +#include "srslte/phy/io/filesource.h" +#include "srslte/phy/io/netsink.h" +#include "srslte/phy/io/netsource.h" + +#include "srslte/phy/modem/demod_hard.h" +#include "srslte/phy/modem/demod_soft.h" +#include "srslte/phy/modem/mod.h" +#include "srslte/phy/modem/modem_table.h" + +#include "srslte/phy/mimo/precoding.h" +#include "srslte/phy/mimo/layermap.h" + +#include "srslte/phy/phch/cqi.h" +#include "srslte/phy/phch/dci.h" +#include "srslte/phy/fec/softbuffer.h" +#include "srslte/phy/phch/pbch.h" +#include "srslte/phy/phch/pcfich.h" +#include "srslte/phy/phch/pdcch.h" +#include "srslte/phy/phch/pdsch.h" +#include "srslte/phy/phch/phich.h" +#include "srslte/phy/phch/pusch.h" +#include "srslte/phy/phch/pucch.h" +#include "srslte/phy/phch/prach.h" +#include "srslte/phy/phch/ra.h" +#include "srslte/phy/phch/regs.h" +#include "srslte/phy/phch/sch.h" +#include "srslte/phy/phch/uci.h" + +#include "srslte/phy/ue/ue_sync.h" +#include "srslte/phy/ue/ue_mib.h" +#include "srslte/phy/ue/ue_cell_search.h" +#include "srslte/phy/ue/ue_dl.h" +#include "srslte/phy/ue/ue_ul.h" + +#include "srslte/phy/enb/enb_dl.h" +#include "srslte/phy/enb/enb_ul.h" + +#include "srslte/phy/scrambling/scrambling.h" + +#include "srslte/phy/sync/pss.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 +} +#undef I // Fix complex.h #define I nastiness when using C++ +#endif + +#endif diff --git a/lib/include/srslte/upper/gw.h b/lib/include/srslte/upper/gw.h new file mode 100644 index 000000000..a01413829 --- /dev/null +++ b/lib/include/srslte/upper/gw.h @@ -0,0 +1,88 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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 GW_H +#define GW_H + +#include "srslte/common/buffer_pool.h" +#include "srslte/common/log.h" +#include "srslte/common/common.h" +#include "srslte/common/msg_queue.h" +#include "srslte/interfaces/ue_interfaces.h" +#include "srslte/common/threads.h" +#include "srslte/upper/gw_metrics.h" + +#include + +namespace srslte { + +class gw + :public srsue::gw_interface_pdcp + ,public srsue::gw_interface_nas + ,public thread +{ +public: + gw(); + void init(srsue::pdcp_interface_gw *pdcp_, srsue::rrc_interface_gw *rrc_, srsue::ue_interface *ue_, log *gw_log_); + void stop(); + + void get_metrics(gw_metrics_t &m); + + // PDCP interface + void write_pdu(uint32_t lcid, byte_buffer_t *pdu); + + // NAS interface + error_t setup_if_addr(uint32_t ip_addr, char *err_str); + +private: + + static const int GW_THREAD_PRIO = 7; + + srsue::pdcp_interface_gw *pdcp; + srsue::rrc_interface_gw *rrc; + srsue::ue_interface *ue; + + byte_buffer_pool *pool; + log *gw_log; + bool running; + bool run_enable; + int32 tun_fd; + struct ifreq ifr; + int32 sock; + bool if_up; + + long ul_tput_bytes; + long dl_tput_bytes; + struct timeval metrics_time[3]; + + void run_thread(); + error_t init_if(char *err_str); +}; + +} // namespace srsue + + +#endif // GW_H diff --git a/lib/include/srslte/upper/gw_metrics.h b/lib/include/srslte/upper/gw_metrics.h new file mode 100644 index 000000000..b5d8eaf23 --- /dev/null +++ b/lib/include/srslte/upper/gw_metrics.h @@ -0,0 +1,41 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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 UE_GW_METRICS_H +#define UE_GW_METRICS_H + + +namespace srslte { + +struct gw_metrics_t +{ + double dl_tput_mbps; + double ul_tput_mbps; +}; + +} // namespace srsue + +#endif // UE_GW_METRICS_H diff --git a/lib/include/srslte/upper/pdcp.h b/lib/include/srslte/upper/pdcp.h new file mode 100644 index 000000000..090f8f045 --- /dev/null +++ b/lib/include/srslte/upper/pdcp.h @@ -0,0 +1,84 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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 PDCP_H +#define PDCP_H + +#include "srslte/common/log.h" +#include "srslte/common/common.h" +#include "srslte/interfaces/ue_interfaces.h" +#include "srslte/upper/pdcp_entity.h" + +namespace srslte { + +class pdcp + :public srsue::pdcp_interface_gw + ,public srsue::pdcp_interface_rlc + ,public srsue::pdcp_interface_rrc +{ +public: + pdcp(); + virtual ~pdcp(){} + void init(srsue::rlc_interface_pdcp *rlc_, + srsue::rrc_interface_pdcp *rrc_, + srsue::gw_interface_pdcp *gw_, + log *pdcp_log_, + uint8_t direction_); + void stop(); + + // RRC interface + void reset(); + void write_sdu(uint32_t lcid, byte_buffer_t *sdu); + void add_bearer(uint32_t lcid, LIBLTE_RRC_PDCP_CONFIG_STRUCT *cnfg = NULL); + void config_security(uint32_t lcid, + uint8_t *k_rrc_enc, + uint8_t *k_rrc_int, + CIPHERING_ALGORITHM_ID_ENUM cipher_algo, + INTEGRITY_ALGORITHM_ID_ENUM integ_algo); + + // RLC interface + void write_pdu(uint32_t lcid, byte_buffer_t *sdu); + void write_pdu_bcch_bch(byte_buffer_t *sdu); + void write_pdu_bcch_dlsch(byte_buffer_t *sdu); + void write_pdu_pcch(byte_buffer_t *sdu); + +private: + log *pdcp_log; + pdcp_entity pdcp_array[SRSLTE_N_RADIO_BEARERS]; + + srsue::rlc_interface_pdcp *rlc; + srsue::rrc_interface_pdcp *rrc; + srsue::gw_interface_pdcp *gw; + + uint8_t direction; + + bool valid_lcid(uint32_t lcid); +}; + +} // namespace srsue + + +#endif // PDCP_H diff --git a/lib/include/srslte/upper/pdcp_entity.h b/lib/include/srslte/upper/pdcp_entity.h new file mode 100644 index 000000000..2c1c988a0 --- /dev/null +++ b/lib/include/srslte/upper/pdcp_entity.h @@ -0,0 +1,138 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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 PDCP_ENTITY_H +#define 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" + + +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(); + void init(srsue::rlc_interface_pdcp *rlc_, + srsue::rrc_interface_pdcp *rrc_, + srsue::gw_interface_pdcp *gw_, + srslte::log *log_, + uint32_t lcid_, + uint8_t direction_, + LIBLTE_RRC_PDCP_CONFIG_STRUCT *cnfg = NULL + ); + void reset(); + + bool is_active(); + + // RRC interface + void write_sdu(byte_buffer_t *sdu); + void config_security(uint8_t *k_rrc_enc_, + uint8_t *k_rrc_int_, + CIPHERING_ALGORITHM_ID_ENUM cipher_algo_, + INTEGRITY_ALGORITHM_ID_ENUM integ_algo_); + + // RLC interface + void write_pdu(byte_buffer_t *pdu); + +private: + byte_buffer_pool *pool; + srslte::log *log; + + srsue::rlc_interface_pdcp *rlc; + srsue::rrc_interface_pdcp *rrc; + srsue::gw_interface_pdcp *gw; + + bool active; + uint32_t lcid; + bool do_security; + u_int8_t direction; + + uint8_t sn_len; + // TODO: Support the following configurations + // bool do_rohc; + + uint32_t rx_count; + uint32_t tx_count; + uint8_t k_rrc_enc[32]; + uint8_t k_rrc_int[32]; + + CIPHERING_ALGORITHM_ID_ENUM cipher_algo; + INTEGRITY_ALGORITHM_ID_ENUM integ_algo; + + void integrity_generate(uint8_t *key_128, + uint32_t count, + uint8_t rb_id, + uint8_t direction, + uint8_t *msg, + uint32_t msg_len, + uint8_t *mac); + +}; + +/**************************************************************************** + * 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 srsue + + +#endif // PDCP_ENTITY_H diff --git a/lib/include/srslte/upper/rlc.h b/lib/include/srslte/upper/rlc.h new file mode 100644 index 000000000..9d7f7ff39 --- /dev/null +++ b/lib/include/srslte/upper/rlc.h @@ -0,0 +1,101 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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 RLC_H +#define RLC_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/msg_queue.h" +#include "srslte/upper/rlc_entity.h" +#include "srslte/upper/rlc_metrics.h" + +namespace srslte { + +/**************************************************************************** + * RLC Layer + * Ref: 3GPP TS 36.322 v10.0.0 + * Single interface for RLC layer - contains separate RLC entities for + * each bearer. + ***************************************************************************/ +class rlc + :public srsue::rlc_interface_mac + ,public srsue::rlc_interface_pdcp + ,public srsue::rlc_interface_rrc +{ +public: + rlc(); + virtual ~rlc() {} + void init(srsue::pdcp_interface_rlc *pdcp_, + srsue::rrc_interface_rlc *rrc_, + srsue::ue_interface *ue_, + log *rlc_log_, + mac_interface_timers *mac_timers_); + void stop(); + + void get_metrics(rlc_metrics_t &m); + + // PDCP interface + void write_sdu(uint32_t lcid, byte_buffer_t *sdu); + + // MAC interface + uint32_t get_buffer_state(uint32_t lcid); + uint32_t get_total_buffer_state(uint32_t lcid); + int read_pdu(uint32_t lcid, uint8_t *payload, uint32_t nof_bytes); + void write_pdu(uint32_t lcid, uint8_t *payload, uint32_t nof_bytes); + void write_pdu_bcch_bch(uint8_t *payload, uint32_t nof_bytes); + void write_pdu_bcch_dlsch(uint8_t *payload, uint32_t nof_bytes); + void write_pdu_pcch(uint8_t *payload, uint32_t nof_bytes); + + // RRC interface + void reset(); + void add_bearer(uint32_t lcid); + void add_bearer(uint32_t lcid, LIBLTE_RRC_RLC_CONFIG_STRUCT *cnfg); + +private: + void reset_metrics(); + + byte_buffer_pool *pool; + srslte::log *rlc_log; + srsue::pdcp_interface_rlc *pdcp; + srsue::rrc_interface_rlc *rrc; + srslte::mac_interface_timers *mac_timers; + srsue::ue_interface *ue; + srslte::rlc_entity rlc_array[SRSLTE_N_RADIO_BEARERS]; + + long ul_tput_bytes[SRSLTE_N_RADIO_BEARERS]; + long dl_tput_bytes[SRSLTE_N_RADIO_BEARERS]; + struct timeval metrics_time[3]; + + bool valid_lcid(uint32_t lcid); +}; + +} // namespace srsue + + +#endif // RLC_H diff --git a/lib/include/srslte/upper/rlc_am.h b/lib/include/srslte/upper/rlc_am.h new file mode 100644 index 000000000..5fcf31c94 --- /dev/null +++ b/lib/include/srslte/upper/rlc_am.h @@ -0,0 +1,228 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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 RLC_AM_H +#define RLC_AM_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/msg_queue.h" +#include "srslte/common/timeout.h" +#include "srslte/upper/rlc_common.h" +#include +#include +#include + +namespace srslte { + + + +struct rlc_amd_rx_pdu_t{ + rlc_amd_pdu_header_t header; + byte_buffer_t *buf; +}; + +struct rlc_amd_rx_pdu_segments_t{ + std::list segments; +}; + +struct rlc_amd_tx_pdu_t{ + rlc_amd_pdu_header_t header; + byte_buffer_t *buf; + uint32_t retx_count; + bool is_acked; +}; + +struct rlc_amd_retx_t{ + uint32_t sn; + bool is_segment; + uint32_t so_start; + uint32_t so_end; +}; + + +class rlc_am + :public rlc_common +{ +public: + rlc_am(); + void init(log *rlc_entity_log_, + uint32_t lcid_, + srsue::pdcp_interface_rlc *pdcp_, + srsue::rrc_interface_rlc *rrc_, + mac_interface_timers *mac_timers); + void configure(LIBLTE_RRC_RLC_CONFIG_STRUCT *cnfg); + void reset(); + void empty_queue(); + + rlc_mode_t get_mode(); + uint32_t get_bearer(); + + // PDCP interface + void write_sdu(byte_buffer_t *sdu); + + // MAC interface + uint32_t get_buffer_state(); + uint32_t get_total_buffer_state(); + int read_pdu(uint8_t *payload, uint32_t nof_bytes); + void write_pdu(uint8_t *payload, uint32_t nof_bytes); + +private: + + byte_buffer_pool *pool; + srslte::log *log; + uint32_t lcid; + srsue::pdcp_interface_rlc *pdcp; + srsue::rrc_interface_rlc *rrc; + + // TX SDU buffers + msg_queue tx_sdu_queue; + byte_buffer_t *tx_sdu; + + // PDU being resegmented + rlc_amd_tx_pdu_t tx_pdu_segments; + + // Tx and Rx windows + std::map tx_window; + std::deque retx_queue; + std::map rx_window; + std::map rx_segments; + + // RX SDU buffers + byte_buffer_t *rx_sdu; + + // Mutexes + pthread_mutex_t mutex; + + bool poll_received; + bool do_status; + rlc_status_pdu_t status; + + /**************************************************************************** + * Configurable parameters + * Ref: 3GPP TS 36.322 v10.0.0 Section 7 + ***************************************************************************/ + + // TX configs + int32_t t_poll_retx; // Poll retx timeout (ms) + int32_t poll_pdu; // Insert poll bit after this many PDUs + int32_t poll_byte; // Insert poll bit after this much data (KB) + uint32_t max_retx_thresh; // Max number of retx + + // RX configs + int32_t t_reordering; // Timer used by rx to detect PDU loss (ms) + int32_t t_status_prohibit; // Timer used by rx to prohibit tx of status PDU (ms) + + /**************************************************************************** + * State variables and counters + * Ref: 3GPP TS 36.322 v10.0.0 Section 7 + ***************************************************************************/ + + // Tx state variables + uint32_t vt_a; // ACK state. SN of next PDU in sequence to be ACKed. Low edge of tx window. + uint32_t vt_ms; // Max send state. High edge of tx window. vt_a + window_size. + uint32_t vt_s; // Send state. SN to be assigned for next PDU. + uint32_t poll_sn; // Poll send state. SN of most recent PDU txed with poll bit set. + + // Tx counters + uint32_t pdu_without_poll; + uint32_t byte_without_poll; + + // Rx state variables + uint32_t vr_r; // Receive state. SN following last in-sequence received PDU. Low edge of rx window + uint32_t vr_mr; // Max acceptable receive state. High edge of rx window. vr_r + window size. + uint32_t vr_x; // t_reordering state. SN following PDU which triggered t_reordering. + uint32_t vr_ms; // Max status tx state. Highest possible value of SN for ACK_SN in status PDU. + uint32_t vr_h; // Highest rx state. SN following PDU with highest SN among rxed PDUs. + + /**************************************************************************** + * Timers + * Ref: 3GPP TS 36.322 v10.0.0 Section 7 + ***************************************************************************/ + timeout poll_retx_timeout; + timeout reordering_timeout; + timeout status_prohibit_timeout; + + static const int reordering_timeout_id = 1; + + // Timer checks + bool status_prohibited(); + bool poll_retx(); + void check_reordering_timeout(); + + // Helpers + bool poll_required(); + + int prepare_status(); + int build_status_pdu(uint8_t *payload, uint32_t nof_bytes); + int build_retx_pdu(uint8_t *payload, uint32_t nof_bytes); + int build_segment(uint8_t *payload, uint32_t nof_bytes, rlc_amd_retx_t retx); + int build_data_pdu(uint8_t *payload, uint32_t nof_bytes); + + 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 handle_control_pdu(uint8_t *payload, uint32_t nof_bytes); + + void reassemble_rx_sdus(); + + bool inside_tx_window(uint16_t sn); + bool inside_rx_window(uint16_t sn); + void debug_state(); + + bool add_segment_and_check(rlc_amd_rx_pdu_segments_t *pdu, rlc_amd_rx_pdu_t *segment); + int required_buffer_size(rlc_amd_retx_t retx); + bool retx_queue_has_sn(uint32_t sn); +}; + +/**************************************************************************** + * Header pack/unpack helper functions + * Ref: 3GPP TS 36.322 v10.0.0 Section 6.2.1 + ***************************************************************************/ +void rlc_am_read_data_pdu_header(byte_buffer_t *pdu, rlc_amd_pdu_header_t *header); +void rlc_am_read_data_pdu_header(uint8_t **payload, uint32_t *nof_bytes, rlc_amd_pdu_header_t *header); +void rlc_am_write_data_pdu_header(rlc_amd_pdu_header_t *header, byte_buffer_t *pdu); +void rlc_am_write_data_pdu_header(rlc_amd_pdu_header_t *header, uint8_t **payload); +void rlc_am_read_status_pdu(byte_buffer_t *pdu, rlc_status_pdu_t *status); +void rlc_am_read_status_pdu(uint8_t *payload, uint32_t nof_bytes, rlc_status_pdu_t *status); +void rlc_am_write_status_pdu(rlc_status_pdu_t *status, byte_buffer_t *pdu ); +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_control_pdu(byte_buffer_t *pdu); +bool rlc_am_is_control_pdu(uint8_t *payload); +bool rlc_am_is_pdu_segment(uint8_t *payload); +std::string rlc_am_to_string(rlc_status_pdu_t *status); +bool rlc_am_start_aligned(uint8_t fi); +bool rlc_am_end_aligned(uint8_t fi); + +} // namespace srsue + + +#endif // RLC_AM_H diff --git a/lib/include/srslte/upper/rlc_common.h b/lib/include/srslte/upper/rlc_common.h new file mode 100644 index 000000000..0c545b60f --- /dev/null +++ b/lib/include/srslte/upper/rlc_common.h @@ -0,0 +1,184 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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 RLC_COMMON_H +#define RLC_COMMON_H + +namespace srslte { + +/**************************************************************************** + * Structs and Defines + * Ref: 3GPP TS 36.322 v10.0.0 + ***************************************************************************/ + +#define RLC_AM_WINDOW_SIZE 512 + +typedef enum{ + RLC_MODE_TM = 0, + RLC_MODE_UM, + RLC_MODE_AM, + RLC_MODE_N_ITEMS, +}rlc_mode_t; +static const char rlc_mode_text[RLC_MODE_N_ITEMS][20] = {"Transparent Mode", + "Unacknowledged Mode", + "Acknowledged Mode"}; + +typedef enum{ + RLC_FI_FIELD_START_AND_END_ALIGNED = 0, + RLC_FI_FIELD_NOT_END_ALIGNED, + RLC_FI_FIELD_NOT_START_ALIGNED, + RLC_FI_FIELD_NOT_START_OR_END_ALIGNED, + RLC_FI_FIELD_N_ITEMS, +}rlc_fi_field_t; +static const char rlc_fi_field_text[RLC_FI_FIELD_N_ITEMS][32] = {"Start and end aligned", + "Not end aligned", + "Not start aligned", + "Not start or end aligned"}; + +typedef enum{ + RLC_DC_FIELD_CONTROL_PDU = 0, + RLC_DC_FIELD_DATA_PDU, + RLC_DC_FIELD_N_ITEMS, +}rlc_dc_field_t; +static const char rlc_dc_field_text[RLC_DC_FIELD_N_ITEMS][20] = {"Control PDU", + "Data PDU"}; + +typedef enum{ + RLC_UMD_SN_SIZE_5_BITS = 0, + RLC_UMD_SN_SIZE_10_BITS, + RLC_UMD_SN_SIZE_N_ITEMS, +}rlc_umd_sn_size_t; +static const char rlc_umd_sn_size_text[RLC_UMD_SN_SIZE_N_ITEMS][20] = {"5 bits", "10 bits"}; +static const uint16_t rlc_umd_sn_size_num[RLC_UMD_SN_SIZE_N_ITEMS] = {5, 10}; + +// UMD PDU Header +typedef struct{ + uint8_t fi; // Framing info + rlc_umd_sn_size_t sn_size; // Sequence number size (5 or 10 bits) + uint16_t sn; // Sequence number + uint32_t N_li; // Number of length indicators + uint16_t li[RLC_AM_WINDOW_SIZE]; // Array of length indicators +}rlc_umd_pdu_header_t; + +// AMD PDU Header +struct rlc_amd_pdu_header_t{ + rlc_dc_field_t dc; // Data or control + uint8_t rf; // Resegmentation flag + uint8_t p; // Polling bit + uint8_t fi; // Framing info + uint16_t sn; // Sequence number + uint8_t lsf; // Last segment flag + uint16_t so; // Segment offset + uint32_t N_li; // Number of length indicators + uint16_t li[RLC_AM_WINDOW_SIZE]; // Array of length indicators + + rlc_amd_pdu_header_t(){ + dc = RLC_DC_FIELD_CONTROL_PDU; + rf = 0; + p = 0; + fi = 0; + sn = 0; + lsf = 0; + so = 0; + N_li=0; + for(int i=0;i +#include +#include + +namespace srslte { + +struct rlc_umd_pdu_t{ + rlc_umd_pdu_header_t header; + byte_buffer_t *buf; +}; + +class rlc_um + :public timer_callback + ,public rlc_common +{ +public: + rlc_um(); + + void init(log *rlc_entity_log_, + uint32_t lcid_, + srsue::pdcp_interface_rlc *pdcp_, + srsue::rrc_interface_rlc *rrc_, + mac_interface_timers *mac_timers_); + void configure(LIBLTE_RRC_RLC_CONFIG_STRUCT *cnfg); + void reset(); + void empty_queue(); + + rlc_mode_t get_mode(); + uint32_t get_bearer(); + + // PDCP interface + void write_sdu(byte_buffer_t *sdu); + + // MAC interface + uint32_t get_buffer_state(); + uint32_t get_total_buffer_state(); + int read_pdu(uint8_t *payload, uint32_t nof_bytes); + void write_pdu(uint8_t *payload, uint32_t nof_bytes); + + // Timeout callback interface + void timer_expired(uint32_t timeout_id); + + bool reordering_timeout_running(); + +private: + + byte_buffer_pool *pool; + srslte::log *log; + uint32_t lcid; + srsue::pdcp_interface_rlc *pdcp; + srsue::rrc_interface_rlc *rrc; + mac_interface_timers *mac_timers; + + // TX SDU buffers + msg_queue tx_sdu_queue; + byte_buffer_t *tx_sdu; + + // Rx window + std::map rx_window; + uint32_t rx_window_size; + uint32_t rx_mod; // Rx counter modulus + uint32_t tx_mod; // Tx counter modulus + + // RX SDU buffers + byte_buffer_t *rx_sdu; + uint32_t vr_ur_in_rx_sdu; + + // Mutexes + pthread_mutex_t mutex; + + /**************************************************************************** + * Configurable parameters + * Ref: 3GPP TS 36.322 v10.0.0 Section 7 + ***************************************************************************/ + + int32_t t_reordering; // Timer used by rx to detect PDU loss (ms) + rlc_umd_sn_size_t tx_sn_field_length; // Number of bits used for tx (UL) sequence number + rlc_umd_sn_size_t rx_sn_field_length; // Number of bits used for rx (DL) sequence number + + /**************************************************************************** + * State variables and counters + * Ref: 3GPP TS 36.322 v10.0.0 Section 7 + ***************************************************************************/ + + // Tx state variables + uint32_t vt_us; // Send state. SN to be assigned for next PDU. + + // Rx state variables + uint32_t vr_ur; // Receive state. SN of earliest PDU still considered for reordering. + uint32_t vr_ux; // t_reordering state. SN following PDU which triggered t_reordering. + uint32_t vr_uh; // Highest rx state. SN following PDU with highest SN among rxed PDUs. + + /**************************************************************************** + * Timers + * Ref: 3GPP TS 36.322 v10.0.0 Section 7 + ***************************************************************************/ + uint32_t reordering_timeout_id; + + bool pdu_lost; + + int build_data_pdu(uint8_t *payload, uint32_t nof_bytes); + void handle_data_pdu(uint8_t *payload, uint32_t nof_bytes); + void reassemble_rx_sdus(); + bool inside_reordering_window(uint16_t sn); + void debug_state(); +}; + +/**************************************************************************** + * Header pack/unpack helper functions + * Ref: 3GPP TS 36.322 v10.0.0 Section 6.2.1 + ***************************************************************************/ +void rlc_um_read_data_pdu_header(byte_buffer_t *pdu, rlc_umd_sn_size_t sn_size, rlc_umd_pdu_header_t *header); +void rlc_um_read_data_pdu_header(uint8_t *payload, uint32_t nof_bytes, rlc_umd_sn_size_t sn_size, rlc_umd_pdu_header_t *header); +void rlc_um_write_data_pdu_header(rlc_umd_pdu_header_t *header, byte_buffer_t *pdu); + +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 + + +#endif // RLC_UM_H diff --git a/srslte/include/srslte/version.h.in b/lib/include/srslte/version.h.in similarity index 100% rename from srslte/include/srslte/version.h.in rename to lib/include/srslte/version.h.in diff --git a/srslte/lib/common/CMakeLists.txt b/lib/src/CMakeLists.txt similarity index 77% rename from srslte/lib/common/CMakeLists.txt rename to lib/src/CMakeLists.txt index db4e6f49b..2c576f754 100644 --- a/srslte/lib/common/CMakeLists.txt +++ b/lib/src/CMakeLists.txt @@ -1,7 +1,7 @@ # -# Copyright 2013-2015 Software Radio Systems Limited +# Copyright 2013-2017 Software Radio Systems Limited # -# This file is part of the srsLTE library. +# 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 @@ -18,6 +18,8 @@ # and at http://www.gnu.org/licenses/. # -file(GLOB SOURCES "*.c") -add_library(srslte_common OBJECT ${SOURCES}) -SRSLTE_SET_PIC(srslte_common) +add_subdirectory(asn1) +add_subdirectory(common) +add_subdirectory(phy) +add_subdirectory(radio) +add_subdirectory(upper) diff --git a/lib/src/asn1/CMakeLists.txt b/lib/src/asn1/CMakeLists.txt new file mode 100644 index 000000000..aeed84602 --- /dev/null +++ b/lib/src/asn1/CMakeLists.txt @@ -0,0 +1,28 @@ +# +# Copyright 2013-2017 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/. +# + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-switch -Wno-unused-but-set-variable -Wno-unused-variable -Wno-return-type -Wno-sign-compare -Wno-reorder -Wno-parantheses") +add_library(srslte_asn1 SHARED + liblte_common.cc + liblte_rrc.cc + liblte_mme.cc + liblte_s1ap.cc +) +install(TARGETS srslte_asn1 DESTINATION ${LIBRARY_DIR}) diff --git a/lib/src/asn1/liblte_common.cc b/lib/src/asn1/liblte_common.cc new file mode 100644 index 000000000..0e618bf35 --- /dev/null +++ b/lib/src/asn1/liblte_common.cc @@ -0,0 +1,198 @@ +/******************************************************************************* + + Copyright 2014 Ben Wojtowicz + + This program 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. + + This program 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. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + +******************************************************************************* + + File: liblte_common.cc + + Description: Contains all the implementations for the LTE common library. + + Revision History + ---------- ------------- -------------------------------------------- + 08/03/2014 Ben Wojtowicz Created file. + 11/29/2014 Ben Wojtowicz Added liblte prefix to value_2_bits and + bits_2_value. + +*******************************************************************************/ + +/******************************************************************************* + INCLUDES +*******************************************************************************/ + +#include "srslte/asn1/liblte_common.h" + +/******************************************************************************* + DEFINES +*******************************************************************************/ + + +/******************************************************************************* + TYPEDEFS +*******************************************************************************/ + + +/******************************************************************************* + GLOBAL VARIABLES +*******************************************************************************/ + + +/******************************************************************************* + FUNCTIONS +*******************************************************************************/ + +/********************************************************************* + Name: liblte_value_2_bits + + Description: Converts a value to a bit string +*********************************************************************/ +void liblte_value_2_bits(uint32 value, + uint8 **bits, + uint32 N_bits) +{ + uint32 i; + + for(i=0; i> (N_bits-i-1)) & 0x1; + } + *bits += N_bits; +} + +/********************************************************************* + Name: liblte_bits_2_value + + Description: Converts a bit string to a value +*********************************************************************/ +uint32 liblte_bits_2_value(uint8 **bits, + uint32 N_bits) +{ + uint32 value = 0; + uint32 i; + + for(i=0; imsg; + uint32_t i; + + for(i=0; iN_bits/8; i++) + { + bytes->msg[i] = liblte_bits_2_value(&bit_ptr, 8); + } + bytes->N_bytes = bits->N_bits/8; + if(bits->N_bits%8 > 0) + { + bytes->msg[bytes->N_bytes] = liblte_bits_2_value(&bit_ptr, bits->N_bits%8); + bytes->N_bytes++; + } +} + +/********************************************************************* + Name: liblte_unpack + + Description: Unpack a byte array into a bit array +*********************************************************************/ +void liblte_unpack(LIBLTE_BYTE_MSG_STRUCT *bytes, + LIBLTE_BIT_MSG_STRUCT *bits) +{ + uint8_t *bit_ptr = bits->msg; + uint32_t i; + + for(i=0; iN_bytes; i++) + { + liblte_value_2_bits(bytes->msg[i], &bit_ptr, 8); + } + bits->N_bits = bytes->N_bytes*8; +} + +/********************************************************************* + Name: liblte_pack + + Description: Pack a bit array into a byte array +*********************************************************************/ +void liblte_pack(uint8_t *bits, uint32_t n_bits, uint8_t *bytes) +{ + uint8_t* bit_ptr = bits; + uint32_t i; + + for(i=0; i 0) + { + bytes[n_bits/8] = liblte_bits_2_value(&bit_ptr, n_bits%8); + } +} + +/********************************************************************* + Name: liblte_unpack + + Description: Unpack a byte array into a bit array +*********************************************************************/ +void liblte_unpack(uint8_t *bytes, uint32_t n_bytes, uint8_t *bits) +{ + uint8_t *bit_ptr = bits; + uint32_t i; + + for(i=0; i 0) + { + (*ptr)++; + } +} + +/********************************************************************* + Name: liblte_align_up_zero + + Description: Aligns a pointer to a multibyte boundary and zeros + bytes skipped +*********************************************************************/ +void liblte_align_up_zero(uint8_t **ptr, uint32_t align) +{ + while( (uint64_t)(*ptr) % align > 0) + { + **ptr = 0; + (*ptr)++; + } +} diff --git a/lib/src/asn1/liblte_mme.cc b/lib/src/asn1/liblte_mme.cc new file mode 100644 index 000000000..4447b001f --- /dev/null +++ b/lib/src/asn1/liblte_mme.cc @@ -0,0 +1,10954 @@ +/******************************************************************************* + + Copyright 2014-2015 Ben Wojtowicz + + This program 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. + + This program 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. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + +******************************************************************************* + + File: liblte_mme.cc + + Description: Contains all the implementations for the LTE Mobility + Management Entity library. + + Revision History + ---------- ------------- -------------------------------------------- + 06/15/2014 Ben Wojtowicz Created file. + 08/03/2014 Ben Wojtowicz Added more decoding/encoding. + 09/03/2014 Ben Wojtowicz Added more decoding/encoding and fixed MCC + and MNC packing. + 11/01/2014 Ben Wojtowicz Added more decoding/encoding. + 11/29/2014 Ben Wojtowicz Added more decoding/encoding. + 12/16/2014 Ben Wojtowicz Added more decoding/encoding. + 12/24/2014 Ben Wojtowicz Cleaned up the Time Zone and Time IE. + 02/15/2015 Ben Wojtowicz Added more decoding/encoding. + +*******************************************************************************/ + +/******************************************************************************* + INCLUDES +*******************************************************************************/ + +#include "srslte/asn1/liblte_mme.h" +#include "srslte/common/liblte_security.h" + +/******************************************************************************* + DEFINES +*******************************************************************************/ + + +/******************************************************************************* + TYPEDEFS +*******************************************************************************/ + + +/******************************************************************************* + GLOBAL VARIABLES +*******************************************************************************/ + + +/******************************************************************************* + INFORMATION ELEMENT FUNCTIONS +*******************************************************************************/ + +/********************************************************************* + IE Name: Additional Information + + Description: Provides additional information to upper layers in + relation to the generic NAS message transport + mechanism. + + Document Reference: 24.301 v10.2.0 Section 9.9.2.0 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_additional_information_ie(LIBLTE_MME_ADDITIONAL_INFORMATION_STRUCT *add_info, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint32 i; + + if(add_info != NULL && + ie_ptr != NULL) + { + (*ie_ptr)[0] = add_info->N_octets; + for(i=0; iN_octets; i++) + { + (*ie_ptr)[1+i] = add_info->info[i]; + } + *ie_ptr += add_info->N_octets + 1; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_additional_information_ie(uint8 **ie_ptr, + LIBLTE_MME_ADDITIONAL_INFORMATION_STRUCT *add_info) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint32 i; + + if(ie_ptr != NULL && + add_info != NULL) + { + add_info->N_octets = (*ie_ptr)[0]; + for(i=0; iN_octets; i++) + { + add_info->info[i] = (*ie_ptr)[1+i]; + } + *ie_ptr += add_info->N_octets + 1; + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Device Properties + + Description: Indicates if the UE is configured for NAS signalling + low priority. + + Document Reference: 24.301 v10.2.0 Section 9.9.2.0A + 24.008 v10.2.0 Section 10.5.7.8 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_device_properties_ie(LIBLTE_MME_DEVICE_PROPERTIES_ENUM device_props, + uint8 bit_offset, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL) + { + **ie_ptr |= device_props << bit_offset; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_device_properties_ie(uint8 **ie_ptr, + uint8 bit_offset, + LIBLTE_MME_DEVICE_PROPERTIES_ENUM *device_props) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + device_props != NULL) + { + *device_props = (LIBLTE_MME_DEVICE_PROPERTIES_ENUM)((**ie_ptr >> bit_offset) & 0x01); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: EPS Bearer Context Status + + Description: Indicates the state of each EPS bearer context that + can be identified by an EPS bearer identity. + + Document Reference: 24.301 v10.2.0 Section 9.9.2.1 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_eps_bearer_context_status_ie(LIBLTE_MME_EPS_BEARER_CONTEXT_STATUS_STRUCT *ebcs, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ebcs != NULL && + ie_ptr != NULL) + { + (*ie_ptr)[0] = 2; + (*ie_ptr)[1] = (ebcs->ebi[7] << 7); + (*ie_ptr)[1] |= (ebcs->ebi[6] << 6); + (*ie_ptr)[1] |= (ebcs->ebi[5] << 5); + (*ie_ptr)[2] = (ebcs->ebi[15] << 7); + (*ie_ptr)[2] |= (ebcs->ebi[14] << 6); + (*ie_ptr)[2] |= (ebcs->ebi[13] << 5); + (*ie_ptr)[2] |= (ebcs->ebi[12] << 4); + (*ie_ptr)[2] |= (ebcs->ebi[11] << 3); + (*ie_ptr)[2] |= (ebcs->ebi[10] << 2); + (*ie_ptr)[2] |= (ebcs->ebi[9] << 1); + (*ie_ptr)[2] |= ebcs->ebi[8]; + *ie_ptr += 3; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_eps_bearer_context_status_ie(uint8 **ie_ptr, + LIBLTE_MME_EPS_BEARER_CONTEXT_STATUS_STRUCT *ebcs) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + ebcs != NULL) + { + ebcs->ebi[5] = ((*ie_ptr)[1] >> 5) & 0x01; + ebcs->ebi[6] = ((*ie_ptr)[1] >> 6) & 0x01; + ebcs->ebi[7] = ((*ie_ptr)[1] >> 7) & 0x01; + ebcs->ebi[8] = (*ie_ptr)[2] & 0x01; + ebcs->ebi[9] = ((*ie_ptr)[2] >> 1) & 0x01; + ebcs->ebi[10] = ((*ie_ptr)[2] >> 2) & 0x01; + ebcs->ebi[11] = ((*ie_ptr)[2] >> 3) & 0x01; + ebcs->ebi[12] = ((*ie_ptr)[2] >> 4) & 0x01; + ebcs->ebi[13] = ((*ie_ptr)[2] >> 5) & 0x01; + ebcs->ebi[14] = ((*ie_ptr)[2] >> 6) & 0x01; + ebcs->ebi[15] = ((*ie_ptr)[2] >> 7) & 0x01; + *ie_ptr += 3; + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Location Area Identification + + Description: Provides an unambiguous identification of location + areas within the area covered by the 3GPP system. + + Document Reference: 24.301 v10.2.0 Section 9.9.2.2 + 24.008 v10.2.0 Section 10.5.1.3 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_location_area_id_ie(LIBLTE_MME_LOCATION_AREA_ID_STRUCT *lai, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(lai != NULL && + ie_ptr != NULL) + { + (*ie_ptr)[0] = (((lai->mcc/10) % 10) << 4) | ((lai->mcc/100) % 10); + if(lai->mnc < 100) + { + (*ie_ptr)[1] = 0xF0 | (lai->mcc % 10); + (*ie_ptr)[2] = ((lai->mnc % 10) << 4) | ((lai->mnc/10) % 10); + }else{ + (*ie_ptr)[1] = ((lai->mnc % 10) << 4) | (lai->mcc % 10); + (*ie_ptr)[2] = (((lai->mnc/10) % 10) << 4) | ((lai->mnc/100) % 10); + } + (*ie_ptr)[3] = (lai->lac >> 8) & 0xFF; + (*ie_ptr)[4] = lai->lac & 0xFF; + *ie_ptr += 5; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_location_area_id_ie(uint8 **ie_ptr, + LIBLTE_MME_LOCATION_AREA_ID_STRUCT *lai) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + lai != NULL) + { + lai->mcc = ((*ie_ptr)[0] & 0x0F)*100; + lai->mcc += (((*ie_ptr)[0] >> 4) & 0x0F)*10; + lai->mcc += (*ie_ptr)[1] & 0x0F; + if((((*ie_ptr)[1] >> 4) & 0x0F) == 0x0F) + { + lai->mnc = ((*ie_ptr)[2] & 0x0F)*10; + lai->mnc += ((*ie_ptr)[2] >> 4) & 0x0F; + }else{ + lai->mnc = ((*ie_ptr)[1] >> 4) & 0x0F; + lai->mnc += ((*ie_ptr)[2] & 0x0F)*100; + lai->mnc += (((*ie_ptr)[2] >> 4) & 0x0F)*10; + } + lai->lac = (*ie_ptr)[3] << 8; + lai->lac |= (*ie_ptr)[4]; + *ie_ptr += 5; + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Mobile Identity + + Description: Provides either the IMSI, TMSI/P-TMSI/M-TMSI, IMEI, + IMEISV, or TMGI, associated with the optional MBMS + session identity. + + Document Reference: 24.301 v10.2.0 Section 9.9.2.3 + 24.008 v10.2.0 Section 10.5.1.4 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_mobile_id_ie(LIBLTE_MME_MOBILE_ID_STRUCT *mobile_id, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *id; + uint32 i; + uint8 length; + bool odd = false; + + if(mobile_id != NULL && + ie_ptr != NULL) + { + if(LIBLTE_MME_MOBILE_ID_TYPE_IMSI == mobile_id->type_of_id) + { + id = mobile_id->imsi; + length = 8; + odd = true; + }else if(LIBLTE_MME_MOBILE_ID_TYPE_IMEI == mobile_id->type_of_id){ + id = mobile_id->imei; + length = 8; + odd = true; + }else if(LIBLTE_MME_MOBILE_ID_TYPE_IMEISV == mobile_id->type_of_id){ + id = mobile_id->imeisv; + length = 9; + odd = false; + }else{ + // FIXME: Not handling these IDs + return(err); + } + + // Length + **ie_ptr = length; + *ie_ptr += 1; + + // | Identity digit 1 | odd/even | Id type | + if(odd) + { + **ie_ptr = (id[0] << 4) | (1 << 3) | mobile_id->type_of_id; + }else{ + **ie_ptr = (id[0] << 4) | (0 << 3) | mobile_id->type_of_id; + } + *ie_ptr += 1; + + // | Identity digit p+1 | Identity digit p | + for(i=0; i<7; i++) + { + (*ie_ptr)[i] = (id[i*2+2] << 4) | id[i*2+1]; + } + *ie_ptr += 7; + if(!odd) + { + **ie_ptr = 0xF0 | id[15]; + *ie_ptr += 1; + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_mobile_id_ie(uint8 **ie_ptr, + LIBLTE_MME_MOBILE_ID_STRUCT *mobile_id) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *id; + uint32 length; + uint32 i; + bool odd = false; + + if(ie_ptr != NULL && + mobile_id != NULL) + { + length = **ie_ptr; + *ie_ptr += 1; + + mobile_id->type_of_id = **ie_ptr & 0x07; + + if(LIBLTE_MME_MOBILE_ID_TYPE_IMSI == mobile_id->type_of_id) + { + id = mobile_id->imsi; + odd = true; + }else if(LIBLTE_MME_MOBILE_ID_TYPE_IMEI == mobile_id->type_of_id){ + id = mobile_id->imei; + odd = true; + }else if(LIBLTE_MME_MOBILE_ID_TYPE_IMEISV == mobile_id->type_of_id){ + id = mobile_id->imeisv; + odd = false; + }else{ + // FIXME: Not handling these IDs + return(err); + } + + id[0] = **ie_ptr >> 4; + *ie_ptr += 1; + for(i=0; i<7; i++) + { + id[i*2+1] = (*ie_ptr)[i] & 0x0F; + id[i*2+2] = (*ie_ptr)[i] >> 4; + } + if(odd) + { + *ie_ptr += 7; + }else{ + id[i*2+1] = (*ie_ptr)[i] & 0xF; + *ie_ptr += 8; + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Mobile Station Classmark 2 + + Description: Provides the network with information concerning + aspects of both high and low priority of the UE. + + Document Reference: 24.301 v10.2.0 Section 9.9.2.4 + 24.008 v10.2.0 Section 10.5.1.6 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_mobile_station_classmark_2_ie(LIBLTE_MME_MOBILE_STATION_CLASSMARK_2_STRUCT *ms_cm2, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ms_cm2 != NULL && + ie_ptr != NULL) + { + (*ie_ptr)[0] = 3; + (*ie_ptr)[1] = (ms_cm2->rev_lev & 0x03) << 5; + (*ie_ptr)[1] |= ms_cm2->es_ind << 4; + (*ie_ptr)[1] |= ms_cm2->a5_1 << 3; + (*ie_ptr)[1] |= ms_cm2->rf_power_cap & 0x07; + (*ie_ptr)[2] = ms_cm2->ps_cap << 6; + (*ie_ptr)[2] |= (ms_cm2->ss_screen_ind & 0x03) << 4; + (*ie_ptr)[2] |= ms_cm2->sm_cap << 3; + (*ie_ptr)[2] |= ms_cm2->vbs << 2; + (*ie_ptr)[2] |= ms_cm2->vgcs << 1; + (*ie_ptr)[2] |= ms_cm2->fc; + (*ie_ptr)[3] = ms_cm2->cm3 << 7; + (*ie_ptr)[3] |= ms_cm2->lcsva_cap << 5; + (*ie_ptr)[3] |= ms_cm2->ucs2 << 4; + (*ie_ptr)[3] |= ms_cm2->solsa << 3; + (*ie_ptr)[3] |= ms_cm2->cmsp << 2; + (*ie_ptr)[3] |= ms_cm2->a5_3 << 1; + (*ie_ptr)[3] |= ms_cm2->a5_2; + *ie_ptr += 4; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_mobile_station_classmark_2_ie(uint8 **ie_ptr, + LIBLTE_MME_MOBILE_STATION_CLASSMARK_2_STRUCT *ms_cm2) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + ms_cm2 != NULL) + { + ms_cm2->rev_lev = (LIBLTE_MME_REVISION_LEVEL_ENUM)(((*ie_ptr)[1] >> 5) & 0x03); + ms_cm2->es_ind = ((*ie_ptr)[1] >> 4) & 0x01; + ms_cm2->a5_1 = ((*ie_ptr)[1] >> 3) & 0x01; + ms_cm2->rf_power_cap = (LIBLTE_MME_RF_POWER_CAPABILITY_ENUM)((*ie_ptr)[1] & 0x07); + ms_cm2->ps_cap = ((*ie_ptr)[2] >> 6) & 0x01; + ms_cm2->ss_screen_ind = (LIBLTE_MME_SS_SCREEN_INDICATOR_ENUM)(((*ie_ptr)[2] >> 4) & 0x03); + ms_cm2->sm_cap = ((*ie_ptr)[2] >> 3) & 0x01; + ms_cm2->vbs = ((*ie_ptr)[2] >> 2) & 0x01; + ms_cm2->vgcs = ((*ie_ptr)[2] >> 1) & 0x01; + ms_cm2->fc = (*ie_ptr)[2] & 0x01; + ms_cm2->cm3 = ((*ie_ptr)[3] >> 7) & 0x01; + ms_cm2->lcsva_cap = ((*ie_ptr)[3] >> 5) & 0x01; + ms_cm2->ucs2 = ((*ie_ptr)[3] >> 4) & 0x01; + ms_cm2->solsa = ((*ie_ptr)[3] >> 3) & 0x01; + ms_cm2->cmsp = ((*ie_ptr)[3] >> 2) & 0x01; + ms_cm2->a5_3 = ((*ie_ptr)[3] >> 1) & 0x01; + ms_cm2->a5_2 = (*ie_ptr)[3] & 0x01; + *ie_ptr += 4; + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Mobile Station Classmark 3 + + Description: Provides the network with information concerning + aspects of the UE. + + Document Reference: 24.301 v10.2.0 Section 9.9.2.5 + 24.008 v10.2.0 Section 10.5.1.7 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_mobile_station_classmark_3_ie(LIBLTE_MME_MOBILE_STATION_CLASSMARK_3_STRUCT *ms_cm3, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ms_cm3 != NULL && + ie_ptr != NULL) + { + // FIXME + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_mobile_station_classmark_3_ie(uint8 **ie_ptr, + LIBLTE_MME_MOBILE_STATION_CLASSMARK_3_STRUCT *ms_cm3) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + ms_cm3 != NULL) + { + // FIXME + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: NAS Security Parameters From E-UTRA + + Description: Provides the UE with information that enables the UE + to create a mapped UMTS security context. + + Document Reference: 24.301 v10.2.0 Section 9.9.2.6 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_nas_security_parameters_from_eutra_ie(uint8 dl_nas_count, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL) + { + (*ie_ptr)[0] = dl_nas_count & 0x0F; + *ie_ptr += 1; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_nas_security_parameters_from_eutra_ie(uint8 **ie_ptr, + uint8 *dl_nas_count) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + dl_nas_count != NULL) + { + *dl_nas_count = (*ie_ptr)[0]; + *ie_ptr += 1; + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: NAS Security Parameters To E-UTRA + + Description: Provides the UE with parameters that enables the UE + to create a mapped EPS security context and take + this context into use after inter-system handover to + S1 mode. + + Document Reference: 24.301 v10.2.0 Section 9.9.2.7 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_nas_security_parameters_to_eutra_ie(LIBLTE_MME_NAS_SECURITY_PARAMETERS_TO_EUTRA_STRUCT *sec_params, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(sec_params != NULL && + ie_ptr != NULL) + { + (*ie_ptr)[0] = (sec_params->nonce_mme >> 24) & 0xFF; + (*ie_ptr)[1] = (sec_params->nonce_mme >> 16) & 0xFF; + (*ie_ptr)[2] = (sec_params->nonce_mme >> 8) & 0xFF; + (*ie_ptr)[3] = sec_params->nonce_mme & 0xFF; + (*ie_ptr)[4] = (sec_params->eea & 0x07) << 4; + (*ie_ptr)[4] |= sec_params->eia & 0x07; + (*ie_ptr)[5] = (sec_params->tsc_flag & 0x01) << 3; + (*ie_ptr)[5] |= sec_params->nas_ksi & 0x07; + *ie_ptr += 6; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_nas_security_parameters_to_eutra_ie(uint8 **ie_ptr, + LIBLTE_MME_NAS_SECURITY_PARAMETERS_TO_EUTRA_STRUCT *sec_params) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + sec_params != NULL) + { + sec_params->nonce_mme = (*ie_ptr)[0] << 24; + sec_params->nonce_mme |= (*ie_ptr)[1] << 16; + sec_params->nonce_mme |= (*ie_ptr)[2] << 8; + sec_params->nonce_mme |= (*ie_ptr)[3]; + sec_params->eea = (LIBLTE_MME_TYPE_OF_CIPHERING_ALGORITHM_ENUM)(((*ie_ptr)[4] >> 4) & 0x07); + sec_params->eia = (LIBLTE_MME_TYPE_OF_INTEGRITY_ALGORITHM_ENUM)((*ie_ptr)[4] & 0x07); + sec_params->tsc_flag = (LIBLTE_MME_TYPE_OF_SECURITY_CONTEXT_FLAG_ENUM)(((*ie_ptr)[5] >> 3) & 0x01); + sec_params->nas_ksi = (*ie_ptr)[5] & 0x07; + *ie_ptr += 6; + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: PLMN List + + Description: Provides a list of PLMN codes to the UE. + + Document Reference: 24.301 v10.2.0 Section 9.9.2.8 + 24.008 v10.2.0 Section 10.5.1.13 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_plmn_list_ie(LIBLTE_MME_PLMN_LIST_STRUCT *plmn_list, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint32 i; + + if(plmn_list != NULL && + ie_ptr != NULL) + { + (*ie_ptr)[0] = plmn_list->N_plmns * 3; + for(i=0; iN_plmns; i++) + { + (*ie_ptr)[i*3+0] = (((plmn_list->mcc[i]/10) % 10) << 4) | ((plmn_list->mcc[i]/100) % 10); + if(plmn_list->mnc[i] < 100) + { + (*ie_ptr)[i*3+1] = 0xF0 | (plmn_list->mcc[i] % 10); + (*ie_ptr)[i*3+2] = ((plmn_list->mnc[i] % 10) << 4) | ((plmn_list->mnc[i]/10) % 10); + }else{ + (*ie_ptr)[i*3+1] = ((plmn_list->mnc[i] % 10) << 4) | (plmn_list->mcc[i] % 10); + (*ie_ptr)[i*3+2] = (((plmn_list->mnc[i]/10) % 10) << 4) | ((plmn_list->mnc[i]/100) % 10); + } + } + *ie_ptr += (plmn_list->N_plmns * 3) + 1; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_plmn_list_ie(uint8 **ie_ptr, + LIBLTE_MME_PLMN_LIST_STRUCT *plmn_list) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint32 i; + + if(ie_ptr != NULL && + plmn_list != NULL) + { + plmn_list->N_plmns = (*ie_ptr)[0] / 3; + for(i=0; iN_plmns; i++) + { + plmn_list->mcc[i] = ((*ie_ptr)[i*3+0] & 0x0F)*100; + plmn_list->mcc[i] += (((*ie_ptr)[i*3+0] >> 4) & 0x0F)*10; + plmn_list->mcc[i] += (*ie_ptr)[i*3+1] & 0x0F; + if((((*ie_ptr)[i*3+1] >> 4) & 0x0F) == 0x0F) + { + plmn_list->mnc[i] = ((*ie_ptr)[i*3+2] & 0x0F)*10; + plmn_list->mnc[i] += ((*ie_ptr)[i*3+2] >> 4) & 0x0F; + }else{ + plmn_list->mnc[i] = ((*ie_ptr)[i*3+1] >> 4) & 0x0F; + plmn_list->mnc[i] += ((*ie_ptr)[i*3+2] & 0x0F)*100; + plmn_list->mnc[i] += (((*ie_ptr)[i*3+2] >> 4) & 0x0F)*10; + } + } + *ie_ptr += (*ie_ptr)[0] + 1; + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Spare Half Octet + + Description: Used in the description of EMM and ESM messages when + an odd number of half octet type 1 information + elements are used. + + Document Reference: 24.301 v10.2.0 Section 9.9.2.9 +*********************************************************************/ + +/********************************************************************* + IE Name: Supported Codec List + + Description: Provides the network with information about the + speech codecs supported by the UE. + + Document Reference: 24.301 v10.2.0 Section 9.9.2.10 + 24.008 v10.2.0 Section 10.5.4.32 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_supported_codec_list_ie(LIBLTE_MME_SUPPORTED_CODEC_LIST_STRUCT *supported_codec_list, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint32 i; + + if(supported_codec_list != NULL && + ie_ptr != NULL) + { + (*ie_ptr)[0] = supported_codec_list->N_supported_codecs*4; + for(i=0; iN_supported_codecs; i++) + { + (*ie_ptr)[1+i*4+0] = supported_codec_list->supported_codec[i].sys_id; + (*ie_ptr)[1+i*4+1] = 2; + (*ie_ptr)[1+i*4+2] = (supported_codec_list->supported_codec[i].codec_bitmap >> 8) & 0xFF; + (*ie_ptr)[1+i*4+3] = supported_codec_list->supported_codec[i].codec_bitmap & 0xFF; + } + *ie_ptr += (supported_codec_list->N_supported_codecs*4) + 1; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_supported_codec_list_ie(uint8 **ie_ptr, + LIBLTE_MME_SUPPORTED_CODEC_LIST_STRUCT *supported_codec_list) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint32 i; + + if(ie_ptr != NULL && + supported_codec_list != NULL) + { + supported_codec_list->N_supported_codecs = ((*ie_ptr)[0]/4); + for(i=0; iN_supported_codecs; i++) + { + supported_codec_list->supported_codec[i].sys_id = (*ie_ptr)[1+i*4+0]; + supported_codec_list->supported_codec[i].codec_bitmap = (*ie_ptr)[1+i*4+2] << 8; + supported_codec_list->supported_codec[i].codec_bitmap |= (*ie_ptr)[1+i*4+3]; + } + *ie_ptr += (supported_codec_list->N_supported_codecs*4) + 1; + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Additional Update Result + + Description: Provides additional information about the result of + a combined attached procedure or a combined tracking + area updating procedure. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.0A +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_additional_update_result_ie(LIBLTE_MME_ADDITIONAL_UPDATE_RESULT_ENUM result, + uint8 bit_offset, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL) + { + **ie_ptr |= result << bit_offset; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_additional_update_result_ie(uint8 **ie_ptr, + uint8 bit_offset, + LIBLTE_MME_ADDITIONAL_UPDATE_RESULT_ENUM *result) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(result != NULL && + ie_ptr != NULL) + { + *result = (LIBLTE_MME_ADDITIONAL_UPDATE_RESULT_ENUM)((**ie_ptr >> bit_offset) & 0x03); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Additional Update Type + + Description: Provides additional information about the type of + request for a combined attach or a combined tracking + area updating procedure. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.0B +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_additional_update_type_ie(LIBLTE_MME_ADDITIONAL_UPDATE_TYPE_ENUM aut, + uint8 bit_offset, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL) + { + **ie_ptr |= aut << bit_offset; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_additional_update_type_ie(uint8 **ie_ptr, + uint8 bit_offset, + LIBLTE_MME_ADDITIONAL_UPDATE_TYPE_ENUM *aut) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + aut != NULL) + { + *aut = (LIBLTE_MME_ADDITIONAL_UPDATE_TYPE_ENUM)((**ie_ptr >> bit_offset) & 0x01); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Authentication Failure Parameter + + Description: Provides the network with the necessary information + to begin a re-authentication procedure in the case + of a 'Synch failure', following a UMTS or EPS + authentication challenge. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.1 + 24.008 v10.2.0 Section 10.5.3.2.2 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_authentication_failure_parameter_ie(uint8 *auth_fail_param, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint32 i; + + if(auth_fail_param != NULL && + ie_ptr != NULL) + { + (*ie_ptr)[0] = 14; + for(i=0; i<14; i++) + { + (*ie_ptr)[i+1] = auth_fail_param[i]; + } + *ie_ptr += 15; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_authentication_failure_parameter_ie(uint8 **ie_ptr, + uint8 *auth_fail_param) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint32 i; + + if(ie_ptr != NULL && + auth_fail_param != NULL) + { + for(i=0; i<14; i++) + { + auth_fail_param[i] = (*ie_ptr)[i+1]; + } + *ie_ptr += 15; + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Authentication Parameter AUTN + + Description: Provides the UE with a means of authenticating the + network. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.2 + 24.008 v10.2.0 Section 10.5.3.1.1 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_authentication_parameter_autn_ie(uint8 *autn, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint32 i; + + if(autn != NULL && + ie_ptr != NULL) + { + (*ie_ptr)[0] = 16; + for(i=0; i<16; i++) + { + (*ie_ptr)[i+1] = autn[i]; + } + *ie_ptr += 17; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_authentication_parameter_autn_ie(uint8 **ie_ptr, + uint8 *autn) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint32 i; + + if(ie_ptr != NULL && + autn != NULL) + { + for(i=0; i<16; i++) + { + autn[i] = (*ie_ptr)[i+1]; + } + *ie_ptr += 17; + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Authentication Parameter RAND + + Description: Provides the UE with a non-predictable number to be + used to calculate the authentication signature SRES + and the ciphering key Kc (for a GSM authentication + challenge), or the response RES and both the + ciphering key CK and the integrity key IK (for a + UMTS authentication challenge). + + Document Reference: 24.301 v10.2.0 Section 9.9.3.3 + 24.008 v10.2.0 Section 10.5.3.1 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_authentication_parameter_rand_ie(uint8 *rand_val, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint32 i; + + if(rand_val != NULL && + ie_ptr != NULL) + { + for(i=0; i<16; i++) + { + (*ie_ptr)[i] = rand_val[i]; + } + *ie_ptr += 16; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_authentication_parameter_rand_ie(uint8 **ie_ptr, + uint8 *rand_val) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint32 i; + + if(ie_ptr != NULL && + rand_val != NULL) + { + for(i=0; i<16; i++) + { + rand_val[i] = (*ie_ptr)[i]; + } + *ie_ptr += 16; + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Authentication Response Parameter + + Description: Provides the network with the authentication + response calculated in the USIM. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.4 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_authentication_response_parameter_ie(uint8 *res, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint32 i; + + if(res != NULL && + ie_ptr != NULL) + { + (*ie_ptr)[0] = 8; + for(i=0; i<8; i++) + { + (*ie_ptr)[i+1] = res[i]; + } + *ie_ptr += 9; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_authentication_response_parameter_ie(uint8 **ie_ptr, + uint8 *res) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint32 i; + + if(ie_ptr != NULL && + res != NULL) + { + for(i=0; i<(*ie_ptr)[0]; i++) + { + res[i] = (*ie_ptr)[i+1]; + } + *ie_ptr += (*ie_ptr)[0] + 1; + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Ciphering Key Sequence Number + + Description: Makes it possible for the network to identify the + ciphering key Kc which is stored in the UE without + invoking the authentication procedure. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.4A + 24.008 v10.2.0 Section 10.5.1.2 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_ciphering_key_sequence_number_ie(uint8 key_seq, + uint8 bit_offset, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL) + { + (*ie_ptr)[0] |= (key_seq & 0x07) << bit_offset; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_ciphering_key_sequence_number_ie(uint8 **ie_ptr, + uint8 bit_offset, + uint8 *key_seq) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + key_seq != NULL) + { + *key_seq = ((*ie_ptr)[0] >> bit_offset) & 0x07; + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: CSFB Response + + Description: Indicates whether the UE accepts or rejects a paging + for CS fallback. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.5 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_csfb_response_ie(uint8 csfb_resp, + uint8 bit_offset, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL) + { + (*ie_ptr)[0] |= (csfb_resp & 0x07) << bit_offset; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_csfb_response_ie(uint8 **ie_ptr, + uint8 bit_offset, + uint8 *csfb_resp) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + csfb_resp != NULL) + { + *csfb_resp = ((*ie_ptr)[0] & 0x07) >> bit_offset; + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Daylight Saving Time + + Description: Encodes the daylight saving time in steps of 1 hour. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.6 + 24.008 v10.2.0 Section 10.5.3.12 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_daylight_saving_time_ie(LIBLTE_MME_DAYLIGHT_SAVING_TIME_ENUM dst, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL) + { + (*ie_ptr)[0] = 1; + (*ie_ptr)[1] = dst & 0x03; + *ie_ptr += 2; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_daylight_saving_time_ie(uint8 **ie_ptr, + LIBLTE_MME_DAYLIGHT_SAVING_TIME_ENUM *dst) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + dst != NULL) + { + *dst = (LIBLTE_MME_DAYLIGHT_SAVING_TIME_ENUM)((*ie_ptr)[1] & 0x03); + *ie_ptr += 2; + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Detach Type + + Description: Indicates the type of detach. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.7 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_detach_type_ie(LIBLTE_MME_DETACH_TYPE_STRUCT *detach_type, + uint8 bit_offset, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(detach_type != NULL && + ie_ptr != NULL) + { + (*ie_ptr)[0] |= (detach_type->switch_off & 0x01) << (3 + bit_offset); + (*ie_ptr)[0] |= (detach_type->type_of_detach & 0x07) << bit_offset; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_detach_type_ie(uint8 **ie_ptr, + uint8 bit_offset, + LIBLTE_MME_DETACH_TYPE_STRUCT *detach_type) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + detach_type != NULL) + { + detach_type->switch_off = ((*ie_ptr)[0] >> (3 + bit_offset)) & 0x01; + detach_type->type_of_detach = ((*ie_ptr)[0] >> bit_offset) & 0x07; + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: DRX Parameter + + Description: Indicates whether the UE uses DRX mode or not. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.8 + 24.008 v10.2.0 Section 10.5.5.6 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_drx_parameter_ie(LIBLTE_MME_DRX_PARAMETER_STRUCT *drx_param, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(drx_param != NULL && + ie_ptr != NULL) + { + (*ie_ptr)[0] = drx_param->split_pg_cycle_code; + (*ie_ptr)[1] = (drx_param->drx_cycle_len_coeff_and_value & 0x0F) << 4; + (*ie_ptr)[1] |= (drx_param->split_on_ccch & 0x01) << 3; + (*ie_ptr)[1] |= drx_param->non_drx_timer & 0x07; + *ie_ptr += 2; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_drx_parameter_ie(uint8 **ie_ptr, + LIBLTE_MME_DRX_PARAMETER_STRUCT *drx_param) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + drx_param != NULL) + { + drx_param->split_pg_cycle_code = (*ie_ptr)[0]; + drx_param->drx_cycle_len_coeff_and_value = ((*ie_ptr)[1] >> 4) & 0x0F; + drx_param->split_on_ccch = ((*ie_ptr)[1] >> 3) & 0x01; + drx_param->non_drx_timer = (LIBLTE_MME_NON_DRX_TIMER_ENUM)((*ie_ptr)[1] & 0x07); + *ie_ptr += 2; + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: EMM Cause + + Description: Indicates the reason why an EMM request from the UE + is rejected by the network. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.9 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_emm_cause_ie(uint8 emm_cause, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL) + { + **ie_ptr = emm_cause; + *ie_ptr += 1; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_emm_cause_ie(uint8 **ie_ptr, + uint8 *emm_cause) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + emm_cause != NULL) + { + *emm_cause = **ie_ptr; + *ie_ptr += 1; + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: EPS Attach Result + + Description: Specifies the result of an attach procedure. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.10 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_eps_attach_result_ie(uint8 result, + uint8 bit_offset, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL) + { + **ie_ptr |= result << bit_offset; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_eps_attach_result_ie(uint8 **ie_ptr, + uint8 bit_offset, + uint8 *result) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + result != NULL) + { + *result = (**ie_ptr >> bit_offset) & 0x07; + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: EPS Attach Type + + Description: Indicates the type of the requested attach. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.11 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_eps_attach_type_ie(uint8 attach_type, + uint8 bit_offset, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL) + { + **ie_ptr |= attach_type << bit_offset; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_eps_attach_type_ie(uint8 **ie_ptr, + uint8 bit_offset, + uint8 *attach_type) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + attach_type != NULL) + { + *attach_type = (**ie_ptr >> bit_offset) & 0x07; + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: EPS Mobile Identity + + Description: Provides either the IMSI, the GUTI, or the IMEI. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.12 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_eps_mobile_id_ie(LIBLTE_MME_EPS_MOBILE_ID_STRUCT *eps_mobile_id, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *id; + uint32 i; + + if(eps_mobile_id != NULL && + ie_ptr != NULL) + { + if(LIBLTE_MME_EPS_MOBILE_ID_TYPE_GUTI == eps_mobile_id->type_of_id) + { + **ie_ptr = 11; + *ie_ptr += 1; + **ie_ptr = 0xF0 | eps_mobile_id->type_of_id; + *ie_ptr += 1; + **ie_ptr = (((eps_mobile_id->guti.mcc/10) % 10) << 4) | ((eps_mobile_id->guti.mcc/100) % 10); + *ie_ptr += 1; + if(eps_mobile_id->guti.mnc < 100) + { + **ie_ptr = 0xF0 | (eps_mobile_id->guti.mcc % 10); + *ie_ptr += 1; + **ie_ptr = ((eps_mobile_id->guti.mnc % 10) << 4) | ((eps_mobile_id->guti.mnc/10) % 10); + *ie_ptr += 1; + }else{ + **ie_ptr = ((eps_mobile_id->guti.mnc % 10) << 4) | (eps_mobile_id->guti.mcc % 10); + *ie_ptr += 1; + **ie_ptr = (((eps_mobile_id->guti.mnc/10) % 10) << 4) | ((eps_mobile_id->guti.mnc/100) % 10); + *ie_ptr += 1; + } + **ie_ptr = (eps_mobile_id->guti.mme_group_id >> 8) & 0x0F; + *ie_ptr += 1; + **ie_ptr = eps_mobile_id->guti.mme_group_id & 0x0F; + *ie_ptr += 1; + **ie_ptr = eps_mobile_id->guti.mme_code; + *ie_ptr += 1; + **ie_ptr = (eps_mobile_id->guti.m_tmsi >> 24) & 0xFF; + *ie_ptr += 1; + **ie_ptr = (eps_mobile_id->guti.m_tmsi >> 16) & 0xFF; + *ie_ptr += 1; + **ie_ptr = (eps_mobile_id->guti.m_tmsi >> 8) & 0xFF; + *ie_ptr += 1; + **ie_ptr = eps_mobile_id->guti.m_tmsi & 0xFF; + *ie_ptr += 1; + }else{ + if(LIBLTE_MME_EPS_MOBILE_ID_TYPE_IMSI == eps_mobile_id->type_of_id) + { + id = eps_mobile_id->imsi; + }else{ + id = eps_mobile_id->imei; + } + + **ie_ptr = 8; + *ie_ptr += 1; + **ie_ptr = (id[0] << 4) | (1 << 3) | eps_mobile_id->type_of_id; + *ie_ptr += 1; + for(i=0; i<7; i++) + { + **ie_ptr = (id[i*2+2] << 4) | id[i*2+1]; + *ie_ptr += 1; + } + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_eps_mobile_id_ie(uint8 **ie_ptr, + LIBLTE_MME_EPS_MOBILE_ID_STRUCT *eps_mobile_id) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *id; + uint32 length; + uint32 i; + + if(ie_ptr != NULL && + eps_mobile_id != NULL) + { + length = **ie_ptr; + *ie_ptr += 1; + + eps_mobile_id->type_of_id = **ie_ptr & 0x07; + + if(LIBLTE_MME_EPS_MOBILE_ID_TYPE_GUTI == eps_mobile_id->type_of_id) + { + *ie_ptr += 1; + eps_mobile_id->guti.mcc = (**ie_ptr & 0x0F)*100; + eps_mobile_id->guti.mcc += ((**ie_ptr >> 4) & 0x0F)*10; + *ie_ptr += 1; + eps_mobile_id->guti.mcc += **ie_ptr & 0x0F; + if(((**ie_ptr >> 4) & 0x0F) == 0x0F) + { + *ie_ptr += 1; + eps_mobile_id->guti.mnc = (**ie_ptr & 0x0F)*10; + eps_mobile_id->guti.mnc += (**ie_ptr >> 4) & 0x0F; + *ie_ptr += 1; + }else{ + eps_mobile_id->guti.mnc = (**ie_ptr >> 4) & 0x0F; + *ie_ptr += 1; + eps_mobile_id->guti.mnc += (**ie_ptr & 0x0F)*100; + eps_mobile_id->guti.mnc += ((**ie_ptr >> 4) & 0x0F)*10; + *ie_ptr += 1; + } + eps_mobile_id->guti.mme_group_id = **ie_ptr << 8; + *ie_ptr += 1; + eps_mobile_id->guti.mme_group_id |= **ie_ptr; + *ie_ptr += 1; + eps_mobile_id->guti.mme_code = **ie_ptr; + *ie_ptr += 1; + eps_mobile_id->guti.m_tmsi = **ie_ptr << 24; + *ie_ptr += 1; + eps_mobile_id->guti.m_tmsi |= **ie_ptr << 16; + *ie_ptr += 1; + eps_mobile_id->guti.m_tmsi |= **ie_ptr << 8; + *ie_ptr += 1; + eps_mobile_id->guti.m_tmsi |= **ie_ptr; + *ie_ptr += 1; + }else{ + if(LIBLTE_MME_EPS_MOBILE_ID_TYPE_IMSI == eps_mobile_id->type_of_id) + { + id = eps_mobile_id->imsi; + }else{ + id = eps_mobile_id->imei; + } + + id[0] = **ie_ptr >> 4; + *ie_ptr += 1; + for(i=0; i<7; i++) + { + id[i*2+1] = **ie_ptr & 0x0F; + id[i*2+2] = **ie_ptr >> 4; + *ie_ptr += 1; + } + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: EPS Network Feature Support + + Description: Indicates whether certain features are supported by + the network. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.12A +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_eps_network_feature_support_ie(LIBLTE_MME_EPS_NETWORK_FEATURE_SUPPORT_STRUCT *eps_nfs, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(eps_nfs != NULL && + ie_ptr != NULL) + { + (*ie_ptr)[0] = 1; + (*ie_ptr)[1] = eps_nfs->esrps << 5; + (*ie_ptr)[1] |= (eps_nfs->cs_lcs & 0x03) << 3; + (*ie_ptr)[1] |= eps_nfs->epc_lcs << 2; + (*ie_ptr)[1] |= eps_nfs->emc_bs << 1; + (*ie_ptr)[1] |= eps_nfs->ims_vops; + *ie_ptr += 2; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_eps_network_feature_support_ie(uint8 **ie_ptr, + LIBLTE_MME_EPS_NETWORK_FEATURE_SUPPORT_STRUCT *eps_nfs) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + eps_nfs != NULL) + { + eps_nfs->esrps = ((*ie_ptr)[1] >> 5) & 0x01; + eps_nfs->cs_lcs = (LIBLTE_MME_CS_LCS_ENUM)(((*ie_ptr)[1] >> 3) & 0x03); + eps_nfs->epc_lcs = ((*ie_ptr)[1] >> 2) & 0x01; + eps_nfs->emc_bs = ((*ie_ptr)[1] >> 1) & 0x01; + eps_nfs->ims_vops = (*ie_ptr)[1] & 0x01; + *ie_ptr += 2; + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: EPS Update Result + + Description: Specifies the result of the associated updating + procedure. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.13 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_eps_update_result_ie(uint8 eps_update_res, + uint8 bit_offset, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL) + { + (*ie_ptr)[0] |= (eps_update_res & 0x07) << bit_offset; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_eps_update_result_ie(uint8 **ie_ptr, + uint8 bit_offset, + uint8 *eps_update_res) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + eps_update_res != NULL) + { + *eps_update_res = ((*ie_ptr)[0] >> bit_offset) & 0x07; + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: EPS Update Type + + Description: Specifies the area the updating procedure is + associated with. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.14 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_eps_update_type_ie(LIBLTE_MME_EPS_UPDATE_TYPE_STRUCT *eps_update_type, + uint8 bit_offset, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(eps_update_type != NULL && + ie_ptr != NULL) + { + (*ie_ptr)[0] |= (eps_update_type->active_flag & 0x01) << (bit_offset + 3); + (*ie_ptr)[0] |= (eps_update_type->type & 0x07) << bit_offset; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_eps_update_type_ie(uint8 **ie_ptr, + uint8 bit_offset, + LIBLTE_MME_EPS_UPDATE_TYPE_STRUCT *eps_update_type) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + eps_update_type != NULL) + { + eps_update_type->active_flag = ((*ie_ptr)[0] >> (bit_offset + 3)) & 0x01; + eps_update_type->type = (LIBLTE_MME_EPS_UPDATE_TYPE_ENUM)(((*ie_ptr)[0] >> bit_offset) & 0x07); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: ESM Message Container + + Description: Enables piggybacked transfer of a single ESM message + within an EMM message. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.15 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_esm_message_container_ie(LIBLTE_BYTE_MSG_STRUCT *esm_msg, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint32 i; + + if(esm_msg != NULL && + ie_ptr != NULL) + { + (*ie_ptr)[0] = esm_msg->N_bytes >> 8; + (*ie_ptr)[1] = esm_msg->N_bytes & 0xFF; + for(i=0; iN_bytes; i++) + { + (*ie_ptr)[2+i] = esm_msg->msg[i]; + } + *ie_ptr += esm_msg->N_bytes + 2; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_esm_message_container_ie(uint8 **ie_ptr, + LIBLTE_BYTE_MSG_STRUCT *esm_msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint32 i; + + if(ie_ptr != NULL && + esm_msg != NULL) + { + esm_msg->N_bytes = (*ie_ptr)[0] << 8; + esm_msg->N_bytes |= (*ie_ptr)[1]; + for(i=0; iN_bytes; i++) + { + esm_msg->msg[i] = (*ie_ptr)[2+i]; + } + *ie_ptr += esm_msg->N_bytes + 2; + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: GPRS Timer + + Description: Specifies GPRS specific timer values. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.16 + 24.008 v10.2.0 Section 10.5.7.3 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_gprs_timer_ie(LIBLTE_MME_GPRS_TIMER_STRUCT *timer, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(timer != NULL && + ie_ptr != NULL) + { + **ie_ptr = ((timer->unit & 0x07) << 5) | (timer->value & 0x1F); + *ie_ptr += 1; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_gprs_timer_ie(uint8 **ie_ptr, + LIBLTE_MME_GPRS_TIMER_STRUCT *timer) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + timer != NULL) + { + timer->unit = **ie_ptr >> 5; + timer->value = **ie_ptr & 0x1F; + *ie_ptr += 1; + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: GPRS Timer 2 + + Description: Specifies GPRS specific timer values. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.16A + 24.008 v10.2.0 Section 10.5.7.4 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_gprs_timer_2_ie(uint8 value, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL) + { + **ie_ptr = 1; + *ie_ptr += 1; + **ie_ptr = value; + *ie_ptr += 1; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_gprs_timer_2_ie(uint8 **ie_ptr, + uint8 *value) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + value != NULL) + { + *ie_ptr += 1; + *value = **ie_ptr; + *ie_ptr += 1; + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: GPRS Timer 3 + + Description: Specifies GPRS specific timer values. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.16B + 24.008 v10.2.0 Section 10.5.7.4A +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_gprs_timer_3_ie(LIBLTE_MME_GPRS_TIMER_3_STRUCT *timer, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(timer != NULL && + ie_ptr != NULL) + { + (*ie_ptr)[0] = 1; + (*ie_ptr)[1] = ((timer->unit & 0x07) << 5) | (timer->value & 0x1F); + *ie_ptr += 2; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_gprs_timer_3_ie(uint8 **ie_ptr, + LIBLTE_MME_GPRS_TIMER_3_STRUCT *timer) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + timer != NULL) + { + timer->unit = (*ie_ptr)[1] >> 5; + timer->value = (*ie_ptr)[1] & 0x1F; + *ie_ptr += 2; + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Identity Type 2 + + Description: Specifies which identity is requested. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.17 + 24.008 v10.2.0 Section 10.5.5.9 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_identity_type_2_ie(uint8 id_type, + uint8 bit_offset, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL) + { + **ie_ptr |= id_type << bit_offset; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_identity_type_2_ie(uint8 **ie_ptr, + uint8 bit_offset, + uint8 *id_type) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + id_type != NULL) + { + *id_type = (**ie_ptr >> bit_offset) & 0x07; + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: IMEISV Request + + Description: Indicates that the IMEISV shall be included by the + UE in the authentication and ciphering response + message. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.18 + 24.008 v10.2.0 Section 10.5.5.10 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_imeisv_request_ie(LIBLTE_MME_IMEISV_REQUEST_ENUM imeisv_req, + uint8 bit_offset, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL) + { + **ie_ptr |= imeisv_req << bit_offset; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_imeisv_request_ie(uint8 **ie_ptr, + uint8 bit_offset, + LIBLTE_MME_IMEISV_REQUEST_ENUM *imeisv_req) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + imeisv_req != NULL) + { + *imeisv_req = (LIBLTE_MME_IMEISV_REQUEST_ENUM)((**ie_ptr >> bit_offset) & 0x07); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: KSI And Sequence Number + + Description: Provides the network with the key set identifier + (KSI) value of the current EPS security context and + the 5 least significant bits of the NAS COUNT value + applicable for the message including this information + element. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.19 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_ksi_and_sequence_number_ie(LIBLTE_MME_KSI_AND_SEQUENCE_NUMBER_STRUCT *ksi_and_seq_num, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ksi_and_seq_num != NULL && + ie_ptr != NULL) + { + (*ie_ptr)[0] = (ksi_and_seq_num->ksi & 0x07) << 5; + (*ie_ptr)[0] |= ksi_and_seq_num->seq_num & 0x1F; + *ie_ptr += 1; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_ksi_and_sequence_number_ie(uint8 **ie_ptr, + LIBLTE_MME_KSI_AND_SEQUENCE_NUMBER_STRUCT *ksi_and_seq_num) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + ksi_and_seq_num != NULL) + { + ksi_and_seq_num->ksi = ((*ie_ptr)[0] >> 5) & 0x07; + ksi_and_seq_num->seq_num = (*ie_ptr)[0] & 0x1F; + *ie_ptr += 1; + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: MS Network Capability + + Description: Provides the network with information concerning + aspects of the UE related to GPRS. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.20 + 24.008 v10.2.0 Section 10.5.5.12 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_ms_network_capability_ie(LIBLTE_MME_MS_NETWORK_CAPABILITY_STRUCT *ms_network_cap, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ms_network_cap != NULL && + ie_ptr != NULL) + { + (*ie_ptr)[0] = 3; + (*ie_ptr)[1] = ms_network_cap->gea[1] << 7; + (*ie_ptr)[1] |= ms_network_cap->sm_cap_ded << 6; + (*ie_ptr)[1] |= ms_network_cap->sm_cap_gprs << 5; + (*ie_ptr)[1] |= ms_network_cap->ucs2 << 4; + (*ie_ptr)[1] |= (ms_network_cap->ss_screening & 0x03) << 2; + (*ie_ptr)[1] |= ms_network_cap->solsa << 1; + (*ie_ptr)[1] |= ms_network_cap->revision; + (*ie_ptr)[2] = ms_network_cap->pfc << 7; + (*ie_ptr)[2] |= ms_network_cap->gea[2] << 6; + (*ie_ptr)[2] |= ms_network_cap->gea[3] << 5; + (*ie_ptr)[2] |= ms_network_cap->gea[4] << 4; + (*ie_ptr)[2] |= ms_network_cap->gea[5] << 3; + (*ie_ptr)[2] |= ms_network_cap->gea[6] << 2; + (*ie_ptr)[2] |= ms_network_cap->gea[7] << 1; + (*ie_ptr)[2] |= ms_network_cap->lcsva; + (*ie_ptr)[3] = ms_network_cap->ho_g2u_via_iu << 7; + (*ie_ptr)[3] |= ms_network_cap->ho_g2e_via_s1 << 6; + (*ie_ptr)[3] |= ms_network_cap->emm_comb << 5; + (*ie_ptr)[3] |= ms_network_cap->isr << 4; + (*ie_ptr)[3] |= ms_network_cap->srvcc << 3; + (*ie_ptr)[3] |= ms_network_cap->epc << 2; + (*ie_ptr)[3] |= ms_network_cap->nf << 1; + *ie_ptr += 4; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_ms_network_capability_ie(uint8 **ie_ptr, + LIBLTE_MME_MS_NETWORK_CAPABILITY_STRUCT *ms_network_cap) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + ms_network_cap != NULL) + { + ms_network_cap->gea[1] = ((*ie_ptr)[1] >> 7) & 0x01; + ms_network_cap->sm_cap_ded = ((*ie_ptr)[1] >> 6) & 0x01; + ms_network_cap->sm_cap_gprs = ((*ie_ptr)[1] >> 5) & 0x01; + ms_network_cap->ucs2 = ((*ie_ptr)[1] >> 4) & 0x01; + ms_network_cap->ss_screening = (LIBLTE_MME_SS_SCREENING_INDICATOR_ENUM)(((*ie_ptr)[1] >> 2) & 0x03); + ms_network_cap->solsa = ((*ie_ptr)[1] >> 1) & 0x01; + ms_network_cap->revision = (*ie_ptr)[1] & 0x01; + ms_network_cap->pfc = ((*ie_ptr)[2] >> 7) & 0x01; + ms_network_cap->gea[2] = ((*ie_ptr)[2] >> 6) & 0x01; + ms_network_cap->gea[3] = ((*ie_ptr)[2] >> 5) & 0x01; + ms_network_cap->gea[4] = ((*ie_ptr)[2] >> 4) & 0x01; + ms_network_cap->gea[5] = ((*ie_ptr)[2] >> 3) & 0x01; + ms_network_cap->gea[6] = ((*ie_ptr)[2] >> 2) & 0x01; + ms_network_cap->gea[7] = ((*ie_ptr)[2] >> 1) & 0x01; + ms_network_cap->lcsva = (*ie_ptr)[2] & 0x01; + ms_network_cap->ho_g2u_via_iu = ((*ie_ptr)[3] >> 7) & 0x01; + ms_network_cap->ho_g2e_via_s1 = ((*ie_ptr)[3] >> 6) & 0x01; + ms_network_cap->emm_comb = ((*ie_ptr)[3] >> 5) & 0x01; + ms_network_cap->isr = ((*ie_ptr)[3] >> 4) & 0x01; + ms_network_cap->srvcc = ((*ie_ptr)[3] >> 3) & 0x01; + ms_network_cap->epc = ((*ie_ptr)[3] >> 2) & 0x01; + ms_network_cap->nf = ((*ie_ptr)[3] >> 1) & 0x01; + *ie_ptr += (*ie_ptr)[0] + 1; + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: NAS Key Set Identifier + + Description: Provides the NAS key set identifier that is allocated + by the network. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.21 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_nas_key_set_id_ie(LIBLTE_MME_NAS_KEY_SET_ID_STRUCT *nas_ksi, + uint8 bit_offset, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(nas_ksi != NULL && + ie_ptr != NULL) + { + **ie_ptr |= nas_ksi->tsc_flag << (bit_offset + 3); + **ie_ptr |= nas_ksi->nas_ksi << bit_offset; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_nas_key_set_id_ie(uint8 **ie_ptr, + uint8 bit_offset, + LIBLTE_MME_NAS_KEY_SET_ID_STRUCT *nas_ksi) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + nas_ksi != NULL) + { + nas_ksi->tsc_flag = (LIBLTE_MME_TYPE_OF_SECURITY_CONTEXT_FLAG_ENUM)((**ie_ptr >> (bit_offset + 3)) & 0x01); + nas_ksi->nas_ksi = (**ie_ptr >> bit_offset) & 0x07; + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: NAS Message Container + + Description: Encapsulates the SMS messages transferred between + the UE and the network. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.22 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_nas_message_container_ie(LIBLTE_BYTE_MSG_STRUCT *nas_msg, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint32 i; + + if(nas_msg != NULL && + ie_ptr != NULL) + { + (*ie_ptr)[0] = nas_msg->N_bytes & 0xFF; + for(i=0; iN_bytes; i++) + { + (*ie_ptr)[1+i] = nas_msg->msg[i]; + } + *ie_ptr += nas_msg->N_bytes + 1; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_nas_message_container_ie(uint8 **ie_ptr, + LIBLTE_BYTE_MSG_STRUCT *nas_msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint32 i; + + if(ie_ptr != NULL && + nas_msg != NULL) + { + nas_msg->N_bytes = (*ie_ptr)[0]; + for(i=0; iN_bytes; i++) + { + nas_msg->msg[i] = (*ie_ptr)[1+i]; + } + *ie_ptr += nas_msg->N_bytes + 1; + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: NAS Security Algorithms + + Description: Indicates the algorithms to be used for ciphering + and integrity protection. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.23 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_nas_security_algorithms_ie(LIBLTE_MME_NAS_SECURITY_ALGORITHMS_STRUCT *nas_sec_algs, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(nas_sec_algs != NULL && + ie_ptr != NULL) + { + **ie_ptr = (nas_sec_algs->type_of_eea << 4) | (nas_sec_algs->type_of_eia); + *ie_ptr += 1; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_nas_security_algorithms_ie(uint8 **ie_ptr, + LIBLTE_MME_NAS_SECURITY_ALGORITHMS_STRUCT *nas_sec_algs) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + nas_sec_algs != NULL) + { + nas_sec_algs->type_of_eea = (LIBLTE_MME_TYPE_OF_CIPHERING_ALGORITHM_ENUM)((**ie_ptr >> 4) & 0x07); + nas_sec_algs->type_of_eia = (LIBLTE_MME_TYPE_OF_INTEGRITY_ALGORITHM_ENUM)(**ie_ptr & 0x07); + *ie_ptr += 1; + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Network Name + + Description: Passes a text string to the UE. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.24 + 24.008 v10.2.0 Section 10.5.3.5A +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_network_name_ie(LIBLTE_MME_NETWORK_NAME_STRUCT *net_name, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint32 i; + uint32 bit_offset; + uint32 byte_offset; + const char *char_str = net_name->name.c_str(); + + if(net_name != NULL && + ie_ptr != NULL) + { + bit_offset = 0; + byte_offset = 2; + for(i=0; iname.size(); i++) + { + if(char_str[i] == 0x0A || + char_str[i] == 0x0D || + (char_str[i] >= 0x20 && + char_str[i] <= 0x3F) || + (char_str[i] >= 0x41 && + char_str[i] <= 0x5A) || + (char_str[i] >= 0x61 && + char_str[i] <= 0x7A)) + { + switch(bit_offset) + { + case 0: + (*ie_ptr)[byte_offset] = char_str[i]; + bit_offset = 7; + break; + case 1: + (*ie_ptr)[byte_offset] |= (char_str[i] << 1); + bit_offset = 0; + byte_offset++; + break; + case 2: + (*ie_ptr)[byte_offset] |= ((char_str[i] << 2) & 0xFC); + byte_offset++; + (*ie_ptr)[byte_offset] = ((char_str[i] >> 6) & 0x01); + bit_offset = 1; + break; + case 3: + (*ie_ptr)[byte_offset] |= ((char_str[i] << 3) & 0xF8); + byte_offset++; + (*ie_ptr)[byte_offset] = ((char_str[i] >> 5) & 0x03); + bit_offset = 2; + break; + case 4: + (*ie_ptr)[byte_offset] |= ((char_str[i] << 4) & 0xF0); + byte_offset++; + (*ie_ptr)[byte_offset] = ((char_str[i] >> 4) & 0x07); + bit_offset = 3; + break; + case 5: + (*ie_ptr)[byte_offset] |= ((char_str[i] << 5) & 0xE0); + byte_offset++; + (*ie_ptr)[byte_offset] = ((char_str[i] >> 3) & 0x0F); + bit_offset = 4; + break; + case 6: + (*ie_ptr)[byte_offset] |= ((char_str[i] << 6) & 0xC0); + byte_offset++; + (*ie_ptr)[byte_offset] = ((char_str[i] >> 2) & 0x1F); + bit_offset = 5; + break; + case 7: + (*ie_ptr)[byte_offset] |= ((char_str[i] << 7) & 0x80); + byte_offset++; + (*ie_ptr)[byte_offset] = ((char_str[i] >> 1) & 0x3F); + bit_offset = 6; + break; + } + } + } + if(0 == bit_offset) + { + (*ie_ptr)[0] = byte_offset - 1; + (*ie_ptr)[1] = 0x80 | ((net_name->add_ci & 0x01) << 3); + *ie_ptr += byte_offset; + }else{ + (*ie_ptr)[0] = byte_offset; + (*ie_ptr)[1] = 0x80 | ((net_name->add_ci & 0x01) << 3) | ((8 - bit_offset) & 0x07); + *ie_ptr += byte_offset + 1; + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_network_name_ie(uint8 **ie_ptr, + LIBLTE_MME_NETWORK_NAME_STRUCT *net_name) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint32 i; + uint32 bit_offset; + uint32 byte_offset; + uint32 N_bytes; + uint8 spare_field; + char tmp_char; + + if(ie_ptr != NULL && + net_name != NULL) + { + net_name->add_ci = (LIBLTE_MME_ADD_CI_ENUM)(((*ie_ptr)[1] >> 3) & 0x01); + spare_field = (*ie_ptr)[1] & 0x07; + N_bytes = (*ie_ptr)[0]; + bit_offset = 0; + byte_offset = 2; + net_name->name = ""; + while(byte_offset < N_bytes) + { + switch(bit_offset) + { + case 0: + tmp_char = (*ie_ptr)[byte_offset] & 0x7F; + bit_offset = 7; + break; + case 1: + tmp_char = ((*ie_ptr)[byte_offset] >> 1) & 0x7F; + bit_offset = 0; + byte_offset++; + break; + case 2: + tmp_char = ((*ie_ptr)[byte_offset] >> 2) & 0x3F; + byte_offset++; + tmp_char |= ((*ie_ptr)[byte_offset] << 6) & 0x40; + bit_offset = 1; + break; + case 3: + tmp_char = ((*ie_ptr)[byte_offset] >> 3) & 0x1F; + byte_offset++; + tmp_char |= ((*ie_ptr)[byte_offset] << 5) & 0x60; + bit_offset = 2; + break; + case 4: + tmp_char = ((*ie_ptr)[byte_offset] >> 4) & 0x0F; + byte_offset++; + tmp_char |= ((*ie_ptr)[byte_offset] << 4) & 0x70; + bit_offset = 3; + break; + case 5: + tmp_char = ((*ie_ptr)[byte_offset] >> 5) & 0x07; + byte_offset++; + tmp_char |= ((*ie_ptr)[byte_offset] << 3) & 0x78; + bit_offset = 4; + break; + case 6: + tmp_char = ((*ie_ptr)[byte_offset] >> 6) & 0x03; + byte_offset++; + tmp_char |= ((*ie_ptr)[byte_offset] << 2) & 0x7C; + bit_offset = 5; + break; + case 7: + tmp_char = ((*ie_ptr)[byte_offset] >> 7) & 0x01; + byte_offset++; + tmp_char |= ((*ie_ptr)[byte_offset] << 1) & 0x7E; + bit_offset = 6; + break; + } + + if(tmp_char == 0x0A || + tmp_char == 0x0D || + (tmp_char >= 0x20 && + tmp_char <= 0x3F) || + (tmp_char >= 0x41 && + tmp_char <= 0x5A) || + (tmp_char >= 0x61 && + tmp_char <= 0x7A)) + { + net_name->name += tmp_char; + } + } + + if(0 == bit_offset || + (1 == bit_offset && + 0 == spare_field)) + { + if(0 == bit_offset) + { + tmp_char = (*ie_ptr)[byte_offset] & 0x7F; + }else{ + tmp_char = ((*ie_ptr)[byte_offset] >> 1) & 0x7F; + } + if(tmp_char == 0x0A || + tmp_char == 0x0D || + (tmp_char >= 0x20 && + tmp_char <= 0x3F) || + (tmp_char >= 0x41 && + tmp_char <= 0x5A) || + (tmp_char >= 0x61 && + tmp_char <= 0x7A)) + { + net_name->name += tmp_char; + } + } + + *ie_ptr += byte_offset + 1; + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Nonce + + Description: Transfers a 32-bit nonce value to support deriving + a new mapped EPS security context. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.25 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_nonce_ie(uint32 nonce, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL) + { + (*ie_ptr)[0] = (nonce >> 24) & 0xFF; + (*ie_ptr)[1] = (nonce >> 16) & 0xFF; + (*ie_ptr)[2] = (nonce >> 8) & 0xFF; + (*ie_ptr)[3] = nonce & 0xFF; + *ie_ptr += 4; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_nonce_ie(uint8 **ie_ptr, + uint32 *nonce) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + nonce != NULL) + { + *nonce = (*ie_ptr)[0] << 24; + *nonce |= (*ie_ptr)[1] << 16; + *nonce |= (*ie_ptr)[2] << 8; + *nonce |= (*ie_ptr)[3]; + *ie_ptr += 4; + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Paging Identity + + Description: Indicates the identity used for paging for non-EPS + services. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.25A +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_paging_identity_ie(uint8 paging_id, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL) + { + (*ie_ptr)[0] = paging_id & 0x01; + *ie_ptr += 1; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_paging_identity_ie(uint8 **ie_ptr, + uint8 *paging_id) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + paging_id != NULL) + { + *paging_id = (*ie_ptr)[0] & 0x01; + *ie_ptr += 1; + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: P-TMSI Signature + + Description: Identifies a GMM context of a UE. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.26 + 24.008 v10.2.0 Section 10.5.5.8 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_p_tmsi_signature_ie(uint32 p_tmsi_signature, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL) + { + (*ie_ptr)[0] = (p_tmsi_signature >> 24) & 0xFF; + (*ie_ptr)[1] = (p_tmsi_signature >> 16) & 0xFF; + (*ie_ptr)[2] = (p_tmsi_signature >> 8) & 0xFF; + (*ie_ptr)[3] = p_tmsi_signature & 0xFF; + *ie_ptr += 4; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_p_tmsi_signature_ie(uint8 **ie_ptr, + uint32 *p_tmsi_signature) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + p_tmsi_signature != NULL) + { + *p_tmsi_signature = (*ie_ptr)[0] << 24; + *p_tmsi_signature |= (*ie_ptr)[1] << 16; + *p_tmsi_signature |= (*ie_ptr)[2] << 8; + *p_tmsi_signature |= (*ie_ptr)[3]; + *ie_ptr += 4; + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Service Type + + Description: Specifies the purpose of the service request + procedure. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.27 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_service_type_ie(uint8 value, + uint8 bit_offset, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL) + { + (*ie_ptr)[0] |= (value & 0x0F) << bit_offset; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_service_type_ie(uint8 **ie_ptr, + uint8 bit_offset, + uint8 *value) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + value != NULL) + { + *value = ((*ie_ptr)[0] >> bit_offset) & 0x0F; + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Short MAC + + Description: Protects the integrity of a SERVICE REQUEST message. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.28 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_short_mac_ie(uint16 short_mac, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL) + { + (*ie_ptr)[0] = (short_mac >> 8) & 0xFF; + (*ie_ptr)[1] = short_mac & 0xFF; + *ie_ptr += 2; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_short_mac_ie(uint8 **ie_ptr, + uint16 *short_mac) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + short_mac != NULL) + { + *short_mac = (*ie_ptr)[0] << 8; + *short_mac |= (*ie_ptr)[1]; + *ie_ptr += 2; + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Time Zone + + Description: Encodes the offset between universal time and local + time in steps of 15 minutes. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.29 + 24.008 v10.2.0 Section 10.5.3.8 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_time_zone_ie(uint8 tz, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL) + { + (*ie_ptr)[0] = tz; + *ie_ptr += 1; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_time_zone_ie(uint8 **ie_ptr, + uint8 *tz) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + tz != NULL) + { + *tz = (*ie_ptr)[0]; + *ie_ptr += 1; + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Time Zone And Time + + Description: Encodes the offset between universal time and local + time in steps of 15 minutes and encodes the universal + time at which the IE may have been sent by the + network. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.30 + 24.008 v10.2.0 Section 10.5.3.9 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_time_zone_and_time_ie(LIBLTE_MME_TIME_ZONE_AND_TIME_STRUCT *ttz, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ttz != NULL && + ie_ptr != NULL) + { + (*ie_ptr)[0] = ((ttz->year % 10) << 4) | ((ttz->year % 100) / 10); + (*ie_ptr)[1] = ((ttz->month % 10) << 4) | (ttz->month / 10); + (*ie_ptr)[2] = ((ttz->day % 10) << 4) | (ttz->day / 10); + (*ie_ptr)[3] = ((ttz->hour % 10) << 4) | (ttz->hour / 10); + (*ie_ptr)[4] = ((ttz->minute % 10) << 4) | (ttz->minute / 10); + (*ie_ptr)[5] = ((ttz->second % 10) << 4) | (ttz->second / 10); + (*ie_ptr)[6] = ttz->tz; + *ie_ptr += 7; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_time_zone_and_time_ie(uint8 **ie_ptr, + LIBLTE_MME_TIME_ZONE_AND_TIME_STRUCT *ttz) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + ttz != NULL) + { + ttz->year = 2000 + (((*ie_ptr)[0] & 0x0F) * 10) + (((*ie_ptr)[0] >> 4) & 0x0F); + ttz->month = (((*ie_ptr)[1] & 0x0F) * 10) + (((*ie_ptr)[1] >> 4) & 0x0F); + ttz->day = (((*ie_ptr)[2] & 0x0F) * 10) + (((*ie_ptr)[2] >> 4) & 0x0F); + ttz->hour = (((*ie_ptr)[3] & 0x0F) * 10) + (((*ie_ptr)[3] >> 4) & 0x0F); + ttz->minute = (((*ie_ptr)[4] & 0x0F) * 10) + (((*ie_ptr)[4] >> 4) & 0x0F); + ttz->second = (((*ie_ptr)[5] & 0x0F) * 10) + (((*ie_ptr)[5] >> 4) & 0x0F); + ttz->tz = (*ie_ptr)[6]; + *ie_ptr += 7; + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: TMSI Status + + Description: Indicates whether a valid TMSI is available in the + UE or not. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.31 + 24.008 v10.2.0 Section 10.5.5.4 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_tmsi_status_ie(LIBLTE_MME_TMSI_STATUS_ENUM tmsi_status, + uint8 bit_offset, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL) + { + **ie_ptr |= tmsi_status << bit_offset; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_tmsi_status_ie(uint8 **ie_ptr, + uint8 bit_offset, + LIBLTE_MME_TMSI_STATUS_ENUM *tmsi_status) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + tmsi_status != NULL) + { + *tmsi_status = (LIBLTE_MME_TMSI_STATUS_ENUM)((**ie_ptr >> bit_offset) & 0x01); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Tracking Area Identity + + Description: Provides an unambiguous identification of tracking + areas within the area covered by the 3GPP system. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.32 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_tracking_area_id_ie(LIBLTE_MME_TRACKING_AREA_ID_STRUCT *tai, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(tai != NULL && + ie_ptr != NULL) + { + (*ie_ptr)[0] = (((tai->mcc/10) % 10) << 4) | ((tai->mcc/100) % 10); + if(tai->mnc < 100) + { + (*ie_ptr)[1] = 0xF0 | (tai->mcc % 10); + (*ie_ptr)[2] = ((tai->mnc % 10) << 4) | ((tai->mnc/10) % 10); + }else{ + (*ie_ptr)[1] = ((tai->mnc % 10) << 4) | (tai->mcc % 10); + (*ie_ptr)[2] = (((tai->mnc/10) % 10) << 4) | ((tai->mnc/100) % 10); + } + (*ie_ptr)[3] = (tai->tac >> 8) & 0xFF; + (*ie_ptr)[4] = tai->tac & 0xFF; + *ie_ptr += 5; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_tracking_area_id_ie(uint8 **ie_ptr, + LIBLTE_MME_TRACKING_AREA_ID_STRUCT *tai) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + tai != NULL) + { + tai->mcc = ((*ie_ptr)[0] & 0x0F)*100; + tai->mcc += (((*ie_ptr)[0] >> 4) & 0x0F)*10; + tai->mcc += (*ie_ptr)[1] & 0x0F; + if((((*ie_ptr)[1] >> 4) & 0x0F) == 0x0F) + { + tai->mnc = ((*ie_ptr)[2] & 0x0F)*10; + tai->mnc += ((*ie_ptr)[2] >> 4) & 0x0F; + }else{ + tai->mnc = ((*ie_ptr)[1] >> 4) & 0x0F; + tai->mnc += ((*ie_ptr)[2] & 0x0F)*100; + tai->mnc += (((*ie_ptr)[2] >> 4) & 0x0F)*10; + } + tai->tac = (*ie_ptr)[3] << 8; + tai->tac |= (*ie_ptr)[4]; + *ie_ptr += 5; + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Tracking Area Identity List + + Description: Transfers a list of tracking areas from the network + to the UE. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.33 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_tracking_area_identity_list_ie(LIBLTE_MME_TRACKING_AREA_IDENTITY_LIST_STRUCT *tai_list, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint32 i; + + if(tai_list != NULL && + ie_ptr != NULL) + { + (*ie_ptr)[0] = (tai_list->N_tais*5) + 1; + // FIXME: Support all types + if(1 == tai_list->N_tais) + { + (*ie_ptr)[1] = (LIBLTE_MME_TRACKING_AREA_IDENTITY_LIST_TYPE_ONE_PLMN_NON_CONSECUTIVE_TACS << 5) | ((tai_list->N_tais - 1) & 0x1F); + }else{ + (*ie_ptr)[1] = (LIBLTE_MME_TRACKING_AREA_IDENTITY_LIST_TYPE_DIFFERENT_PLMNS << 5) | ((tai_list->N_tais - 1) & 0x1F); + } + *ie_ptr += 2; + for(i=0; iN_tais; i++) + { + liblte_mme_pack_tracking_area_id_ie(&tai_list->tai[i], ie_ptr); + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_tracking_area_identity_list_ie(uint8 **ie_ptr, + LIBLTE_MME_TRACKING_AREA_IDENTITY_LIST_STRUCT *tai_list) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + LIBLTE_MME_TRACKING_AREA_IDENTITY_LIST_TYPE_ENUM type; + uint32 sent_length; + uint32 length; + uint32 i; + uint32 N_elems; + uint16 mcc; + uint16 mnc; + uint16 tac; + + if(ie_ptr != NULL && + tai_list != NULL) + { + sent_length = (*ie_ptr)[0] + 1; + length = 1; + tai_list->N_tais = 0; + while(length < sent_length) + { + type = (LIBLTE_MME_TRACKING_AREA_IDENTITY_LIST_TYPE_ENUM)(((*ie_ptr)[length] >> 5) & 0x03); + N_elems = (*ie_ptr)[length++] & 0x1F; + if(LIBLTE_MME_TRACKING_AREA_IDENTITY_LIST_TYPE_ONE_PLMN_NON_CONSECUTIVE_TACS == type) + { + mcc = ((*ie_ptr)[length] & 0x0F)*100; + mcc += (((*ie_ptr)[length++] >> 4) & 0x0F)*10; + mcc += (*ie_ptr)[length] & 0x0F; + if((((*ie_ptr)[length] >> 4) & 0x0F) == 0x0F) + { + length++; + mnc = ((*ie_ptr)[length] & 0x0F)*10; + mnc += ((*ie_ptr)[length++] >> 4) & 0x0F; + }else{ + mnc = ((*ie_ptr)[length++] >> 4) & 0x0F; + mnc += ((*ie_ptr)[length] & 0x0F)*100; + mnc += (((*ie_ptr)[length++] >> 4) & 0x0F)*10; + } + for(i=0; itai[tai_list->N_tais].mcc = mcc; + tai_list->tai[tai_list->N_tais].mnc = mnc; + tai_list->tai[tai_list->N_tais].tac = (*ie_ptr)[length++] << 8; + tai_list->tai[tai_list->N_tais].tac |= (*ie_ptr)[length++]; + tai_list->N_tais++; + } + }else if(LIBLTE_MME_TRACKING_AREA_IDENTITY_LIST_TYPE_ONE_PLMN_CONSECUTIVE_TACS == type){ + mcc = ((*ie_ptr)[length] & 0x0F)*100; + mcc += (((*ie_ptr)[length++] >> 4) & 0x0F)*10; + mcc += (*ie_ptr)[length] & 0x0F; + if((((*ie_ptr)[length] >> 4) & 0x0F) == 0x0F) + { + length++; + mnc = ((*ie_ptr)[length] & 0x0F)*10; + mnc += ((*ie_ptr)[length++] >> 4) & 0x0F; + }else{ + mnc = ((*ie_ptr)[length++] >> 4) & 0x0F; + mnc += ((*ie_ptr)[length] & 0x0F)*100; + mnc += (((*ie_ptr)[length++] >> 4) & 0x0F)*10; + } + tac = (*ie_ptr)[length++] << 8; + tac |= (*ie_ptr)[length++]; + for(i=0; itai[tai_list->N_tais].mcc = mcc; + tai_list->tai[tai_list->N_tais].mnc = mnc; + tai_list->tai[tai_list->N_tais].tac = tac + i; + tai_list->N_tais++; + } + }else{ + for(i=0; itai[tai_list->N_tais].mcc = ((*ie_ptr)[length] & 0x0F)*100; + tai_list->tai[tai_list->N_tais].mcc += (((*ie_ptr)[length++] >> 4) & 0x0F)*10; + tai_list->tai[tai_list->N_tais].mcc += (*ie_ptr)[length] & 0x0F; + if((((*ie_ptr)[length] >> 4) & 0x0F) == 0x0F) + { + length++; + tai_list->tai[tai_list->N_tais].mnc = ((*ie_ptr)[length] & 0x0F)*10; + tai_list->tai[tai_list->N_tais].mnc += ((*ie_ptr)[length++] >> 4) & 0x0F; + }else{ + tai_list->tai[tai_list->N_tais].mnc = ((*ie_ptr)[length++] >> 4) & 0x0F; + tai_list->tai[tai_list->N_tais].mnc += ((*ie_ptr)[length] & 0x0F)*100; + tai_list->tai[tai_list->N_tais].mnc += (((*ie_ptr)[length++] >> 4) & 0x0F)*10; + } + tai_list->tai[tai_list->N_tais].tac = (*ie_ptr)[length++] << 8; + tai_list->tai[tai_list->N_tais].tac |= (*ie_ptr)[length++]; + tai_list->N_tais++; + } + } + } + *ie_ptr += (*ie_ptr)[0] + 1; + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: UE Network Capability + + Description: Provides the network with information concerning + aspects of the UE related to EPS or interworking with + GPRS. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.34 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_ue_network_capability_ie(LIBLTE_MME_UE_NETWORK_CAPABILITY_STRUCT *ue_network_cap, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ue_network_cap != NULL && + ie_ptr != NULL) + { + if(ue_network_cap->uea_present && + (ue_network_cap->ucs2_present || + ue_network_cap->uia_present) && + (ue_network_cap->lpp_present || + ue_network_cap->lcs_present || + ue_network_cap->onexsrvcc_present || + ue_network_cap->nf_present)) + { + **ie_ptr = 5; + }else if(ue_network_cap->uea_present && + (ue_network_cap->ucs2_present || + ue_network_cap->uia_present)){ + **ie_ptr = 4; + }else if(ue_network_cap->uea_present){ + **ie_ptr = 3; + }else{ + **ie_ptr = 2; + } + *ie_ptr += 1; + **ie_ptr = ue_network_cap->eea[0] << 7; + **ie_ptr |= ue_network_cap->eea[1] << 6; + **ie_ptr |= ue_network_cap->eea[2] << 5; + **ie_ptr |= ue_network_cap->eea[3] << 4; + **ie_ptr |= ue_network_cap->eea[4] << 3; + **ie_ptr |= ue_network_cap->eea[5] << 2; + **ie_ptr |= ue_network_cap->eea[6] << 1; + **ie_ptr |= ue_network_cap->eea[7]; + *ie_ptr += 1; + **ie_ptr = ue_network_cap->eia[0] << 7; + **ie_ptr |= ue_network_cap->eia[1] << 6; + **ie_ptr |= ue_network_cap->eia[2] << 5; + **ie_ptr |= ue_network_cap->eia[3] << 4; + **ie_ptr |= ue_network_cap->eia[4] << 3; + **ie_ptr |= ue_network_cap->eia[5] << 2; + **ie_ptr |= ue_network_cap->eia[6] << 1; + **ie_ptr |= ue_network_cap->eia[7]; + *ie_ptr += 1; + if(ue_network_cap->uea_present) + { + **ie_ptr = ue_network_cap->uea[0] << 7; + **ie_ptr |= ue_network_cap->uea[1] << 6; + **ie_ptr |= ue_network_cap->uea[2] << 5; + **ie_ptr |= ue_network_cap->uea[3] << 4; + **ie_ptr |= ue_network_cap->uea[4] << 3; + **ie_ptr |= ue_network_cap->uea[5] << 2; + **ie_ptr |= ue_network_cap->uea[6] << 1; + **ie_ptr |= ue_network_cap->uea[7]; + *ie_ptr += 1; + } + if(ue_network_cap->ucs2_present || + ue_network_cap->uia_present) + { + **ie_ptr = ue_network_cap->ucs2 << 7; + **ie_ptr |= ue_network_cap->uia[1] << 6; + **ie_ptr |= ue_network_cap->uia[2] << 5; + **ie_ptr |= ue_network_cap->uia[3] << 4; + **ie_ptr |= ue_network_cap->uia[4] << 3; + **ie_ptr |= ue_network_cap->uia[5] << 2; + **ie_ptr |= ue_network_cap->uia[6] << 1; + **ie_ptr |= ue_network_cap->uia[7]; + *ie_ptr += 1; + } + if(ue_network_cap->lpp_present || + ue_network_cap->lcs_present || + ue_network_cap->onexsrvcc_present || + ue_network_cap->nf_present) + { + **ie_ptr = ue_network_cap->lpp << 3; + **ie_ptr |= ue_network_cap->lcs << 2; + **ie_ptr |= ue_network_cap->onexsrvcc << 1; + **ie_ptr |= ue_network_cap->nf; + *ie_ptr += 1; + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_ue_network_capability_ie(uint8 **ie_ptr, + LIBLTE_MME_UE_NETWORK_CAPABILITY_STRUCT *ue_network_cap) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint32 length; + + if(ie_ptr != NULL && + ue_network_cap != NULL) + { + length = **ie_ptr; + *ie_ptr += 1; + ue_network_cap->eea[0] = (**ie_ptr >> 7) & 0x01; + ue_network_cap->eea[1] = (**ie_ptr >> 6) & 0x01; + ue_network_cap->eea[2] = (**ie_ptr >> 5) & 0x01; + ue_network_cap->eea[3] = (**ie_ptr >> 4) & 0x01; + ue_network_cap->eea[4] = (**ie_ptr >> 3) & 0x01; + ue_network_cap->eea[5] = (**ie_ptr >> 2) & 0x01; + ue_network_cap->eea[6] = (**ie_ptr >> 1) & 0x01; + ue_network_cap->eea[7] = **ie_ptr & 0x01; + *ie_ptr += 1; + ue_network_cap->eia[0] = (**ie_ptr >> 7) & 0x01; + ue_network_cap->eia[1] = (**ie_ptr >> 6) & 0x01; + ue_network_cap->eia[2] = (**ie_ptr >> 5) & 0x01; + ue_network_cap->eia[3] = (**ie_ptr >> 4) & 0x01; + ue_network_cap->eia[4] = (**ie_ptr >> 3) & 0x01; + ue_network_cap->eia[5] = (**ie_ptr >> 2) & 0x01; + ue_network_cap->eia[6] = (**ie_ptr >> 1) & 0x01; + ue_network_cap->eia[7] = **ie_ptr & 0x01; + *ie_ptr += 1; + if(length > 2) + { + ue_network_cap->uea[0] = (**ie_ptr >> 7) & 0x01; + ue_network_cap->uea[1] = (**ie_ptr >> 6) & 0x01; + ue_network_cap->uea[2] = (**ie_ptr >> 5) & 0x01; + ue_network_cap->uea[3] = (**ie_ptr >> 4) & 0x01; + ue_network_cap->uea[4] = (**ie_ptr >> 3) & 0x01; + ue_network_cap->uea[5] = (**ie_ptr >> 2) & 0x01; + ue_network_cap->uea[6] = (**ie_ptr >> 1) & 0x01; + ue_network_cap->uea[7] = **ie_ptr & 0x01; + ue_network_cap->uea_present = true; + *ie_ptr += 1; + }else{ + ue_network_cap->uea_present = false; + } + if(length > 3) + { + ue_network_cap->ucs2 = (**ie_ptr >> 7) & 0x01; + ue_network_cap->ucs2_present = true; + ue_network_cap->uia[1] = (**ie_ptr >> 6) & 0x01; + ue_network_cap->uia[2] = (**ie_ptr >> 5) & 0x01; + ue_network_cap->uia[3] = (**ie_ptr >> 4) & 0x01; + ue_network_cap->uia[4] = (**ie_ptr >> 3) & 0x01; + ue_network_cap->uia[5] = (**ie_ptr >> 2) & 0x01; + ue_network_cap->uia[6] = (**ie_ptr >> 1) & 0x01; + ue_network_cap->uia[7] = **ie_ptr & 0x01; + ue_network_cap->uia_present = true; + *ie_ptr += 1; + }else{ + ue_network_cap->ucs2_present = false; + ue_network_cap->uia_present = false; + } + if(length > 4) + { + ue_network_cap->lpp = (**ie_ptr >> 3) & 0x01; + ue_network_cap->lpp_present = true; + ue_network_cap->lcs = (**ie_ptr >> 2) & 0x01; + ue_network_cap->lcs_present = true; + ue_network_cap->onexsrvcc = (**ie_ptr >> 1) & 0x01; + ue_network_cap->onexsrvcc_present = true; + ue_network_cap->nf = **ie_ptr >> 1; + ue_network_cap->nf_present = true; + *ie_ptr += 1; + }else{ + ue_network_cap->lpp_present = false; + ue_network_cap->lcs_present = false; + ue_network_cap->onexsrvcc_present = false; + ue_network_cap->nf_present = false; + } + if(length > 5) + { + *ie_ptr += length-5; + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: UE Radio Capability Update Needed + + Description: Indicates whether the MME shall delete the stored + UE radio capability information, if any. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.35 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_ue_radio_capability_update_needed_ie(uint8 urc_update, + uint8 bit_offset, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL) + { + (*ie_ptr)[0] |= (urc_update & 0x01) << bit_offset; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_ue_radio_capability_update_needed_ie(uint8 **ie_ptr, + uint8 bit_offset, + uint8 *urc_update) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + urc_update != NULL) + { + *urc_update = ((*ie_ptr)[0] >> bit_offset) & 0x01; + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: UE Security Capability + + Description: Indicates which security algorithms are supported by + the UE in S1 mode. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.36 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_ue_security_capabilities_ie(LIBLTE_MME_UE_SECURITY_CAPABILITIES_STRUCT *ue_sec_cap, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint32 idx; + + if(ue_sec_cap != NULL && + ie_ptr != NULL) + { + if(ue_sec_cap->uea_present && + ue_sec_cap->uia_present && + ue_sec_cap->gea_present) + { + (*ie_ptr)[0] = 5; + }else if(ue_sec_cap->uea_present && + ue_sec_cap->uia_present){ + (*ie_ptr)[0] = 4; + }else if(ue_sec_cap->uea_present){ + (*ie_ptr)[0] = 3; + }else{ + (*ie_ptr)[0] = 2; + } + idx = 1; + (*ie_ptr)[idx] = ue_sec_cap->eea[0] << 7; + (*ie_ptr)[idx] |= ue_sec_cap->eea[1] << 6; + (*ie_ptr)[idx] |= ue_sec_cap->eea[2] << 5; + (*ie_ptr)[idx] |= ue_sec_cap->eea[3] << 4; + (*ie_ptr)[idx] |= ue_sec_cap->eea[4] << 3; + (*ie_ptr)[idx] |= ue_sec_cap->eea[5] << 2; + (*ie_ptr)[idx] |= ue_sec_cap->eea[6] << 1; + (*ie_ptr)[idx] |= ue_sec_cap->eea[7]; + idx++; + (*ie_ptr)[idx] = ue_sec_cap->eia[0] << 7; + (*ie_ptr)[idx] |= ue_sec_cap->eia[1] << 6; + (*ie_ptr)[idx] |= ue_sec_cap->eia[2] << 5; + (*ie_ptr)[idx] |= ue_sec_cap->eia[3] << 4; + (*ie_ptr)[idx] |= ue_sec_cap->eia[4] << 3; + (*ie_ptr)[idx] |= ue_sec_cap->eia[5] << 2; + (*ie_ptr)[idx] |= ue_sec_cap->eia[6] << 1; + (*ie_ptr)[idx] |= ue_sec_cap->eia[7]; + idx++; + if(ue_sec_cap->uea_present) + { + (*ie_ptr)[idx] = ue_sec_cap->uea[0] << 7; + (*ie_ptr)[idx] |= ue_sec_cap->uea[1] << 6; + (*ie_ptr)[idx] |= ue_sec_cap->uea[2] << 5; + (*ie_ptr)[idx] |= ue_sec_cap->uea[3] << 4; + (*ie_ptr)[idx] |= ue_sec_cap->uea[4] << 3; + (*ie_ptr)[idx] |= ue_sec_cap->uea[5] << 2; + (*ie_ptr)[idx] |= ue_sec_cap->uea[6] << 1; + (*ie_ptr)[idx] |= ue_sec_cap->uea[7]; + idx++; + } + if(ue_sec_cap->uia_present) + { + (*ie_ptr)[idx] = ue_sec_cap->uia[1] << 6; + (*ie_ptr)[idx] |= ue_sec_cap->uia[2] << 5; + (*ie_ptr)[idx] |= ue_sec_cap->uia[3] << 4; + (*ie_ptr)[idx] |= ue_sec_cap->uia[4] << 3; + (*ie_ptr)[idx] |= ue_sec_cap->uia[5] << 2; + (*ie_ptr)[idx] |= ue_sec_cap->uia[6] << 1; + (*ie_ptr)[idx] |= ue_sec_cap->uia[7]; + idx++; + } + if(ue_sec_cap->gea_present) + { + (*ie_ptr)[idx] = ue_sec_cap->gea[1] << 6; + (*ie_ptr)[idx] |= ue_sec_cap->gea[2] << 5; + (*ie_ptr)[idx] |= ue_sec_cap->gea[3] << 4; + (*ie_ptr)[idx] |= ue_sec_cap->gea[4] << 3; + (*ie_ptr)[idx] |= ue_sec_cap->gea[5] << 2; + (*ie_ptr)[idx] |= ue_sec_cap->gea[6] << 1; + (*ie_ptr)[idx] |= ue_sec_cap->gea[7]; + idx++; + } + *ie_ptr += idx; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_ue_security_capabilities_ie(uint8 **ie_ptr, + LIBLTE_MME_UE_SECURITY_CAPABILITIES_STRUCT *ue_sec_cap) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint32 length; + + if(ie_ptr != NULL && + ue_sec_cap != NULL) + { + length = (*ie_ptr)[0]; + ue_sec_cap->eea[0] = ((*ie_ptr)[1] >> 7) & 0x01; + ue_sec_cap->eea[1] = ((*ie_ptr)[1] >> 6) & 0x01; + ue_sec_cap->eea[2] = ((*ie_ptr)[1] >> 5) & 0x01; + ue_sec_cap->eea[3] = ((*ie_ptr)[1] >> 4) & 0x01; + ue_sec_cap->eea[4] = ((*ie_ptr)[1] >> 3) & 0x01; + ue_sec_cap->eea[5] = ((*ie_ptr)[1] >> 2) & 0x01; + ue_sec_cap->eea[6] = ((*ie_ptr)[1] >> 1) & 0x01; + ue_sec_cap->eea[7] = (*ie_ptr)[1] & 0x01; + ue_sec_cap->eia[0] = ((*ie_ptr)[2] >> 7) & 0x01; + ue_sec_cap->eia[1] = ((*ie_ptr)[2] >> 6) & 0x01; + ue_sec_cap->eia[2] = ((*ie_ptr)[2] >> 5) & 0x01; + ue_sec_cap->eia[3] = ((*ie_ptr)[2] >> 4) & 0x01; + ue_sec_cap->eia[4] = ((*ie_ptr)[2] >> 3) & 0x01; + ue_sec_cap->eia[5] = ((*ie_ptr)[2] >> 2) & 0x01; + ue_sec_cap->eia[6] = ((*ie_ptr)[2] >> 1) & 0x01; + ue_sec_cap->eia[7] = (*ie_ptr)[2] & 0x01; + if(length > 2) + { + ue_sec_cap->uea[0] = ((*ie_ptr)[3] >> 7) & 0x01; + ue_sec_cap->uea[1] = ((*ie_ptr)[3] >> 6) & 0x01; + ue_sec_cap->uea[2] = ((*ie_ptr)[3] >> 5) & 0x01; + ue_sec_cap->uea[3] = ((*ie_ptr)[3] >> 4) & 0x01; + ue_sec_cap->uea[4] = ((*ie_ptr)[3] >> 3) & 0x01; + ue_sec_cap->uea[5] = ((*ie_ptr)[3] >> 2) & 0x01; + ue_sec_cap->uea[6] = ((*ie_ptr)[3] >> 1) & 0x01; + ue_sec_cap->uea[7] = (*ie_ptr)[3] & 0x01; + ue_sec_cap->uea_present = true; + }else{ + ue_sec_cap->uea_present = false; + } + if(length > 3) + { + ue_sec_cap->uia[1] = ((*ie_ptr)[4] >> 6) & 0x01; + ue_sec_cap->uia[2] = ((*ie_ptr)[4] >> 5) & 0x01; + ue_sec_cap->uia[3] = ((*ie_ptr)[4] >> 4) & 0x01; + ue_sec_cap->uia[4] = ((*ie_ptr)[4] >> 3) & 0x01; + ue_sec_cap->uia[5] = ((*ie_ptr)[4] >> 2) & 0x01; + ue_sec_cap->uia[6] = ((*ie_ptr)[4] >> 1) & 0x01; + ue_sec_cap->uia[7] = (*ie_ptr)[4] & 0x01; + ue_sec_cap->uia_present = true; + }else{ + ue_sec_cap->uia_present = false; + } + if(length > 4) + { + ue_sec_cap->gea[1] = ((*ie_ptr)[5] >> 6) & 0x01; + ue_sec_cap->gea[2] = ((*ie_ptr)[5] >> 5) & 0x01; + ue_sec_cap->gea[3] = ((*ie_ptr)[5] >> 4) & 0x01; + ue_sec_cap->gea[4] = ((*ie_ptr)[5] >> 3) & 0x01; + ue_sec_cap->gea[5] = ((*ie_ptr)[5] >> 2) & 0x01; + ue_sec_cap->gea[6] = ((*ie_ptr)[5] >> 1) & 0x01; + ue_sec_cap->gea[7] = (*ie_ptr)[5] & 0x01; + ue_sec_cap->gea_present = true; + }else{ + ue_sec_cap->gea_present = false; + } + *ie_ptr += length + 1; + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Emergency Number List + + Description: Encodes emergency number(s) for use within the + country (as indicated by MCC) where the IE is + received. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.37 + 24.008 v10.2.0 Section 10.5.3.13 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_emergency_number_list_ie(LIBLTE_MME_EMERGENCY_NUMBER_LIST_STRUCT *emerg_num_list, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint32 i; + uint32 j; + uint32 length; + + if(emerg_num_list != NULL && + ie_ptr != NULL) + { + length = 1; + for(i=0; iN_emerg_nums; i++) + { + if((emerg_num_list->emerg_num[i].N_emerg_num_digits % 2) == 0) + { + (*ie_ptr)[length++] = (emerg_num_list->emerg_num[i].N_emerg_num_digits/2) + 1; + (*ie_ptr)[length++] = emerg_num_list->emerg_num[i].emerg_service_cat; + for(j=0; jemerg_num[i].N_emerg_num_digits/2; j++) + { + (*ie_ptr)[length] = emerg_num_list->emerg_num[i].emerg_num[j*2+0]; + (*ie_ptr)[length++] |= emerg_num_list->emerg_num[i].emerg_num[j*2+1] << 4; + } + }else{ + (*ie_ptr)[length++] = (emerg_num_list->emerg_num[i].N_emerg_num_digits/2) + 2; + (*ie_ptr)[length++] = emerg_num_list->emerg_num[i].emerg_service_cat; + for(j=0; jemerg_num[i].N_emerg_num_digits/2; j++) + { + (*ie_ptr)[length] = emerg_num_list->emerg_num[i].emerg_num[j*2+0]; + (*ie_ptr)[length++] |= emerg_num_list->emerg_num[i].emerg_num[j*2+1] << 4; + } + (*ie_ptr)[length++] = 0xF0 | emerg_num_list->emerg_num[i].emerg_num[j*2]; + } + } + (*ie_ptr)[0] = length - 2; + *ie_ptr += length - 1; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_emergency_number_list_ie(uint8 **ie_ptr, + LIBLTE_MME_EMERGENCY_NUMBER_LIST_STRUCT *emerg_num_list) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint32 sent_length; + uint32 length; + uint32 idx; + uint32 i; + + if(ie_ptr != NULL && + emerg_num_list != NULL) + { + sent_length = (*ie_ptr)[0] + 1; + length = 1; + emerg_num_list->N_emerg_nums = 0; + while(length < sent_length) + { + idx = emerg_num_list->N_emerg_nums; + emerg_num_list->emerg_num[idx].N_emerg_num_digits = ((*ie_ptr)[length++] - 1) * 2; + emerg_num_list->emerg_num[idx].emerg_service_cat = (LIBLTE_MME_EMERGENCY_SERVICE_CATEGORY_ENUM)((*ie_ptr)[length++] & 0x1F); + for(i=0; iemerg_num[idx].N_emerg_num_digits/2; i++) + { + emerg_num_list->emerg_num[idx].emerg_num[i*2+0] = (*ie_ptr)[length] & 0x0F; + emerg_num_list->emerg_num[idx].emerg_num[i*2+1] = (*ie_ptr)[length++] >> 4; + } + // Added by Ismael: if i==0 this is negative + if (i > 0) { + if(emerg_num_list->emerg_num[idx].emerg_num[i*2-1] == 0x0F) + { + emerg_num_list->emerg_num[idx].N_emerg_num_digits--; + } + } + emerg_num_list->N_emerg_nums++; + } + *ie_ptr += (*ie_ptr)[0] + 1; + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: CLI + + Description: Conveys information about the calling line for a + terminated call to a CS fallback capable UE. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.38 +*********************************************************************/ +// FIXME + +/********************************************************************* + IE Name: SS Code + + Description: Conveys information related to a network initiated + supplementary service request to a CS fallback + capable UE. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.39 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_ss_code_ie(uint8 code, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL) + { + (*ie_ptr)[0] = code; + *ie_ptr += 1; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_ss_code_ie(uint8 **ie_ptr, + uint8 *code) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + code != NULL) + { + *code = (*ie_ptr)[0]; + *ie_ptr += 1; + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: LCS Indicator + + Description: Indicates that the origin of the message is due to a + LCS request and the type of this request to a CS + fallback capable UE. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.40 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_lcs_indicator_ie(uint8 lcs_ind, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL) + { + (*ie_ptr)[0] = lcs_ind; + *ie_ptr += 1; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_lcs_indicator_ie(uint8 **ie_ptr, + uint8 *lcs_ind) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + lcs_ind != NULL) + { + *lcs_ind = (*ie_ptr)[0]; + *ie_ptr += 1; + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: LCS Client Identity + + Description: Conveys information related to the client of a LCS + request for a CS fallback capable UE. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.41 +*********************************************************************/ +// FIXME + +/********************************************************************* + IE Name: Generic Message Container Type + + Description: Specifies the type of message contained in the + generic message container IE. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.42 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_generic_message_container_type_ie(uint8 msg_cont_type, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL) + { + (*ie_ptr)[0] = msg_cont_type; + *ie_ptr += 1; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_generic_message_container_type_ie(uint8 **ie_ptr, + uint8 *msg_cont_type) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + msg_cont_type != NULL) + { + *msg_cont_type = (*ie_ptr)[0]; + *ie_ptr += 1; + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Generic Message Container + + Description: Encapsulates the application message transferred + between the UE and the network. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.43 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_generic_message_container_ie(LIBLTE_BYTE_MSG_STRUCT *msg, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint32 i; + + if(msg != NULL && + ie_ptr != NULL) + { + (*ie_ptr)[0] = msg->N_bytes >> 8; + (*ie_ptr)[1] = msg->N_bytes & 0xFF; + for(i=0; iN_bytes; i++) + { + (*ie_ptr)[2+i] = msg->msg[i]; + } + *ie_ptr += msg->N_bytes + 2; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_generic_message_container_ie(uint8 **ie_ptr, + LIBLTE_BYTE_MSG_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint32 i; + + if(ie_ptr != NULL && + msg != NULL) + { + msg->N_bytes = (*ie_ptr)[0] << 8; + msg->N_bytes |= (*ie_ptr)[1]; + for(i=0; iN_bytes; i++) + { + msg->msg[i] = (*ie_ptr)[2+i]; + } + *ie_ptr += msg->N_bytes + 2; + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Voice Domain Preference and UE's Usage Setting + + Description: Provides the network with the UE's usage setting and + the voice domain preference for the E-UTRAN. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.44 + 24.008 v10.2.0 Section 10.5.5.28 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_voice_domain_pref_and_ue_usage_setting_ie(LIBLTE_MME_VOICE_DOMAIN_PREF_AND_UE_USAGE_SETTING_STRUCT *voice_domain_pref_and_ue_usage_setting, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(voice_domain_pref_and_ue_usage_setting != NULL && + ie_ptr != NULL) + { + **ie_ptr = 1; + *ie_ptr += 1; + **ie_ptr = voice_domain_pref_and_ue_usage_setting->ue_usage_setting << 2; + **ie_ptr |= voice_domain_pref_and_ue_usage_setting->voice_domain_pref; + *ie_ptr += 1; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_voice_domain_pref_and_ue_usage_setting_ie(uint8 **ie_ptr, + LIBLTE_MME_VOICE_DOMAIN_PREF_AND_UE_USAGE_SETTING_STRUCT *voice_domain_pref_and_ue_usage_setting) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + voice_domain_pref_and_ue_usage_setting != NULL) + { + *ie_ptr += 1; + voice_domain_pref_and_ue_usage_setting->ue_usage_setting = (LIBLTE_MME_UE_USAGE_SETTING_ENUM)((**ie_ptr >> 2) & 0x01); + voice_domain_pref_and_ue_usage_setting->voice_domain_pref = (LIBLTE_MME_VOICE_DOMAIN_PREF_ENUM)(**ie_ptr & 0x03); + *ie_ptr += 1; + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: GUTI Type + + Description: Indicates whether the GUTI included in the same + message in an information element of type EPS + mobility identity represents a native GUTI or a + mapped GUTI. + + Document Reference: 24.301 v10.2.0 Section 9.9.3.45 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_guti_type_ie(LIBLTE_MME_GUTI_TYPE_ENUM guti_type, + uint8 bit_offset, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL) + { + **ie_ptr |= guti_type << bit_offset; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_guti_type_ie(uint8 **ie_ptr, + uint8 bit_offset, + LIBLTE_MME_GUTI_TYPE_ENUM *guti_type) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + guti_type != NULL) + { + *guti_type = (LIBLTE_MME_GUTI_TYPE_ENUM)((**ie_ptr >> bit_offset) & 0x01); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Access Point Name + + Description: Identifies the packet data network to which the GPRS + user wishes to connect and notifies the access point + of the packet data network that wishes to connect to + the UE. + + Document Reference: 24.301 v10.2.0 Section 9.9.4.1 + 24.008 v10.2.0 Section 10.5.6.1 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_access_point_name_ie(LIBLTE_MME_ACCESS_POINT_NAME_STRUCT *apn, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + const char *apn_str; + uint32 i; + uint32 len_idx; + uint32 apn_idx; + uint32 label_len; + + if(apn != NULL && + ie_ptr != NULL) + { + apn_str = apn->apn.c_str(); + (*ie_ptr)[0] = apn->apn.length()+1; + len_idx = 0; + apn_idx = 0; + label_len = 0; + while(apn->apn.length() > apn_idx) + { + (*ie_ptr)[1+apn_idx+1] = (uint8)apn_str[apn_idx]; + apn_idx++; + label_len++; + + if(apn_str[apn_idx] == '.') + { + (*ie_ptr)[1+len_idx] = label_len; + label_len = 0; + len_idx = apn_idx+1; + apn_idx++; + } + } + (*ie_ptr)[1+len_idx] = label_len; + *ie_ptr += apn->apn.length() + 2; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_access_point_name_ie(uint8 **ie_ptr, + LIBLTE_MME_ACCESS_POINT_NAME_STRUCT *apn) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint32 i; + uint32 ie_idx; + uint32 label_len; + + if(ie_ptr != NULL && + apn != NULL) + { + apn->apn.clear(); + ie_idx = 0; + while(ie_idx < (*ie_ptr)[0]) + { + label_len = (*ie_ptr)[1+ie_idx]; + for(i=0; iapn += (char)((*ie_ptr)[1+ie_idx+i+1]); + } + ie_idx += label_len + 1; + if(ie_idx < (*ie_ptr)[0]) + { + apn->apn += '.'; + } + } + apn->apn += "\0"; + *ie_ptr += (*ie_ptr)[0] + 1; + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: APN Aggregate Maximum Bit Rate + + Description: Indicates the initial subscribed APN-AMBR when the + UE establishes a PDN connection or indicates the new + APN-AMBR if it is changed by the network. + + Document Reference: 24.301 v10.2.0 Section 9.9.4.2 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_apn_aggregate_maximum_bit_rate_ie(LIBLTE_MME_APN_AGGREGATE_MAXIMUM_BIT_RATE_STRUCT *apn_ambr, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(apn_ambr != NULL && + ie_ptr != NULL) + { + if(apn_ambr->ext_present && + apn_ambr->ext2_present) + { + (*ie_ptr)[0] = 6; + }else if(apn_ambr->ext_present){ + (*ie_ptr)[0] = 4; + }else{ + (*ie_ptr)[0] = 2; + } + (*ie_ptr)[1] = apn_ambr->apn_ambr_dl; + (*ie_ptr)[2] = apn_ambr->apn_ambr_ul; + if(apn_ambr->ext_present) + { + (*ie_ptr)[3] = apn_ambr->apn_ambr_dl_ext; + (*ie_ptr)[4] = apn_ambr->apn_ambr_ul_ext; + } + if(apn_ambr->ext2_present) + { + (*ie_ptr)[5] = apn_ambr->apn_ambr_dl_ext2; + (*ie_ptr)[6] = apn_ambr->apn_ambr_ul_ext2; + } + if(apn_ambr->ext_present && + apn_ambr->ext2_present) + { + *ie_ptr += 7; + }else if(apn_ambr->ext_present){ + *ie_ptr += 5; + }else{ + *ie_ptr += 3; + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_apn_aggregate_maximum_bit_rate_ie(uint8 **ie_ptr, + LIBLTE_MME_APN_AGGREGATE_MAXIMUM_BIT_RATE_STRUCT *apn_ambr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + apn_ambr != NULL) + { + if(6 == (*ie_ptr)[0]) + { + apn_ambr->ext_present = true; + apn_ambr->ext2_present = true; + }else if(4 == (*ie_ptr)[0]){ + apn_ambr->ext_present = true; + apn_ambr->ext2_present = false; + }else{ + apn_ambr->ext_present = false; + apn_ambr->ext2_present = false; + } + apn_ambr->apn_ambr_dl = (*ie_ptr)[1]; + apn_ambr->apn_ambr_ul = (*ie_ptr)[2]; + if(apn_ambr->ext_present) + { + apn_ambr->apn_ambr_dl_ext = (*ie_ptr)[3]; + apn_ambr->apn_ambr_ul_ext = (*ie_ptr)[4]; + } + if(apn_ambr->ext2_present) + { + apn_ambr->apn_ambr_dl_ext2 = (*ie_ptr)[5]; + apn_ambr->apn_ambr_ul_ext2 = (*ie_ptr)[6]; + } + if(apn_ambr->ext_present && + apn_ambr->ext2_present) + { + *ie_ptr += 7; + }else if(apn_ambr->ext_present){ + *ie_ptr += 5; + }else{ + *ie_ptr += 3; + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Connectivity Type + + Description: Specifies the type of connectivity selected by the + network for the PDN connection. + + Document Reference: 24.301 v10.2.0 Section 9.9.4.2A + 24.008 v10.2.0 Section 10.5.6.19 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_connectivity_type_ie(uint8 con_type, + uint8 bit_offset, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL) + { + (*ie_ptr)[0] |= con_type << bit_offset; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_connectivity_type_ie(uint8 **ie_ptr, + uint8 bit_offset, + uint8 *con_type) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + con_type != NULL) + { + *con_type = ((*ie_ptr)[0] >> bit_offset) & 0x0F; + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: EPS Quality Of Service + + Description: Specifies the QoS parameters for an EPS bearer + context. + + Document Reference: 24.301 v10.2.0 Section 9.9.4.3 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_eps_quality_of_service_ie(LIBLTE_MME_EPS_QUALITY_OF_SERVICE_STRUCT *qos, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(qos != NULL && + ie_ptr != NULL) + { + if(qos->br_present && + qos->br_ext_present) + { + (*ie_ptr)[0] = 9; + }else if(qos->br_present){ + (*ie_ptr)[0] = 5; + }else{ + (*ie_ptr)[0] = 1; + } + (*ie_ptr)[1] = qos->qci; + if(qos->br_present) + { + (*ie_ptr)[2] = qos->mbr_ul; + (*ie_ptr)[3] = qos->mbr_dl; + (*ie_ptr)[4] = qos->gbr_ul; + (*ie_ptr)[5] = qos->gbr_dl; + } + if(qos->br_ext_present) + { + (*ie_ptr)[6] = qos->mbr_ul_ext; + (*ie_ptr)[7] = qos->mbr_dl_ext; + (*ie_ptr)[8] = qos->gbr_ul_ext; + (*ie_ptr)[9] = qos->gbr_dl_ext; + } + if(qos->br_present && + qos->br_ext_present) + { + *ie_ptr += 10; + }else if(qos->br_present){ + *ie_ptr += 6; + }else{ + *ie_ptr += 2; + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_eps_quality_of_service_ie(uint8 **ie_ptr, + LIBLTE_MME_EPS_QUALITY_OF_SERVICE_STRUCT *qos) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + qos != NULL) + { + if((*ie_ptr)[0] == 1) + { + qos->br_present = false; + qos->br_ext_present = false; + }else if((*ie_ptr)[0] == 5){ + qos->br_present = true; + qos->br_ext_present = false; + }else{ + qos->br_present = true; + qos->br_ext_present = true; + } + qos->qci = (*ie_ptr)[1]; + if(qos->br_present) + { + qos->mbr_ul = (*ie_ptr)[2]; + qos->mbr_dl = (*ie_ptr)[3]; + qos->gbr_ul = (*ie_ptr)[4]; + qos->gbr_dl = (*ie_ptr)[5]; + } + if(qos->br_ext_present) + { + qos->mbr_ul_ext = (*ie_ptr)[6]; + qos->mbr_dl_ext = (*ie_ptr)[7]; + qos->gbr_ul_ext = (*ie_ptr)[8]; + qos->gbr_dl_ext = (*ie_ptr)[9]; + } + if(qos->br_present && + qos->br_ext_present) + { + *ie_ptr += 10; + }else if(qos->br_present){ + *ie_ptr += 6; + }else{ + *ie_ptr += 2; + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: ESM Cause + + Description: Indicates the reason why a session management request + is rejected. + + Document Reference: 24.301 v10.2.0 Section 9.9.4.4 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_esm_cause_ie(uint8 cause, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL) + { + (*ie_ptr)[0] = cause; + *ie_ptr += 1; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_esm_cause_ie(uint8 **ie_ptr, + uint8 *cause) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + cause != NULL) + { + *cause = (*ie_ptr)[0]; + *ie_ptr += 1; + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: ESM Information Transfer Flag + + Description: Indicates whether ESM information, i.e. protocol + configuration options or APN or both, is to be + transferred security protected. + + Document Reference: 24.301 v10.2.0 Section 9.9.4.5 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_esm_info_transfer_flag_ie(LIBLTE_MME_ESM_INFO_TRANSFER_FLAG_ENUM esm_info_transfer_flag, + uint8 bit_offset, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL) + { + **ie_ptr |= esm_info_transfer_flag << bit_offset; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_esm_info_transfer_flag_ie(uint8 **ie_ptr, + uint8 bit_offset, + LIBLTE_MME_ESM_INFO_TRANSFER_FLAG_ENUM *esm_info_transfer_flag) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + esm_info_transfer_flag != NULL) + { + *esm_info_transfer_flag = (LIBLTE_MME_ESM_INFO_TRANSFER_FLAG_ENUM)((**ie_ptr >> bit_offset) & 0x01); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Linked EPS Bearer Identity + + Description: Identifies the default bearer that is associated + with a dedicated EPS bearer or identifies the EPS + bearer (default or dedicated) with which one or more + packet filters specified in a traffic flow aggregate + are associated. + + Document Reference: 24.301 v10.2.0 Section 9.9.4.6 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_linked_eps_bearer_identity_ie(uint8 bearer_id, + uint8 bit_offset, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL) + { + (*ie_ptr)[0] |= (bearer_id & 0x0F) << bit_offset; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_linked_eps_bearer_identity_ie(uint8 **ie_ptr, + uint8 bit_offset, + uint8 *bearer_id) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + bearer_id != NULL) + { + *bearer_id = ((*ie_ptr)[0] >> bit_offset) & 0x0F; + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: LLC Service Access Point Identifier + + Description: Identifies the service access point that is used for + the GPRS data transfer at LLC layer. + + Document Reference: 24.301 v10.2.0 Section 9.9.4.7 + 24.008 v10.2.0 Section 10.5.6.9 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_llc_service_access_point_identifier_ie(uint8 llc_sapi, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL) + { + (*ie_ptr)[0] = llc_sapi; + *ie_ptr += 1; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_llc_service_access_point_identifier_ie(uint8 **ie_ptr, + uint8 *llc_sapi) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + llc_sapi != NULL) + { + *llc_sapi = (*ie_ptr)[0]; + *ie_ptr += 1; + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Notification Indicator + + Description: Informs the UE about an event which is relevant for + the upper layer using an EPS bearer context or + having requested a procedure transaction. + + Document Reference: 24.301 v10.2.0 Section 9.9.4.7A +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_notification_indicator_ie(uint8 notification_ind, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL) + { + (*ie_ptr)[0] = 1; + (*ie_ptr)[1] = notification_ind; + *ie_ptr += 2; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_notification_indicator_ie(uint8 **ie_ptr, + uint8 *notification_ind) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + notification_ind != NULL) + { + *notification_ind = (*ie_ptr)[1]; + *ie_ptr += 2; + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Packet Flow Identifier + + Description: Indicates the packet flow identifier for a packet + flow context. + + Document Reference: 24.301 v10.2.0 Section 9.9.4.8 + 24.008 v10.2.0 Section 10.5.6.11 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_packet_flow_identifier_ie(uint8 packet_flow_id, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL) + { + (*ie_ptr)[0] = 1; + (*ie_ptr)[1] = packet_flow_id; + *ie_ptr += 2; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_packet_flow_identifier_ie(uint8 **ie_ptr, + uint8 *packet_flow_id) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + packet_flow_id != NULL) + { + *packet_flow_id = (*ie_ptr)[1]; + *ie_ptr += (*ie_ptr)[0]; + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: PDN Address + + Description: Assigns an IPv4 address to the UE associated with a + packet data network and provides the UE with an + interface identifier to be used to build the IPv6 + link local address. + + Document Reference: 24.301 v10.2.0 Section 9.9.4.9 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_pdn_address_ie(LIBLTE_MME_PDN_ADDRESS_STRUCT *pdn_addr, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint32 i; + + if(pdn_addr != NULL && + ie_ptr != NULL) + { + (*ie_ptr)[1] = 0x00 | (pdn_addr->pdn_type & 0x07); + if(LIBLTE_MME_PDN_TYPE_IPV4 == pdn_addr->pdn_type) + { + for(i=0; i<4; i++) + { + (*ie_ptr)[2+i] = pdn_addr->addr[i]; + } + (*ie_ptr)[0] = 5; + *ie_ptr += 6; + }else if(LIBLTE_MME_PDN_TYPE_IPV6 == pdn_addr->pdn_type){ + for(i=0; i<8; i++) + { + (*ie_ptr)[2+i] = pdn_addr->addr[i]; + } + (*ie_ptr)[0] = 9; + *ie_ptr += 10; + }else{ + for(i=0; i<12; i++) + { + (*ie_ptr)[2+i] = pdn_addr->addr[i]; + } + (*ie_ptr)[0] = 13; + *ie_ptr += 14; + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_pdn_address_ie(uint8 **ie_ptr, + LIBLTE_MME_PDN_ADDRESS_STRUCT *pdn_addr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint32 i; + + if(ie_ptr != NULL && + pdn_addr != NULL) + { + pdn_addr->pdn_type = (*ie_ptr)[1] & 0x07; + if(LIBLTE_MME_PDN_TYPE_IPV4 == pdn_addr->pdn_type) + { + for(i=0; i<4; i++) + { + pdn_addr->addr[i] = (*ie_ptr)[2+i]; + } + }else if(LIBLTE_MME_PDN_TYPE_IPV6 == pdn_addr->pdn_type){ + for(i=0; i<8; i++) + { + pdn_addr->addr[i] = (*ie_ptr)[2+i]; + } + }else{ + for(i=0; i<12; i++) + { + pdn_addr->addr[i] = (*ie_ptr)[2+i]; + } + } + *ie_ptr += (*ie_ptr)[0]; + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: PDN Type + + Description: Indicates the IP version capability of the IP stack + associated with the UE. + + Document Reference: 24.301 v10.2.0 Section 9.9.4.10 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_pdn_type_ie(uint8 pdn_type, + uint8 bit_offset, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL) + { + **ie_ptr |= pdn_type << bit_offset; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_pdn_type_ie(uint8 **ie_ptr, + uint8 bit_offset, + uint8 *pdn_type) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + pdn_type != NULL) + { + *pdn_type = (**ie_ptr >> bit_offset) & 0x07; + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Protocol Configuration Options + + Description: Transfers external network protocol options + associated with a PDP context activation and + transfers additional (protocol) data (e.g. + configuration parameters, error codes or messages/ + events) associated with an external protocol or an + application. + + Document Reference: 24.301 v10.2.0 Section 9.9.4.11 + 24.008 v10.2.0 Section 10.5.6.3 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_protocol_config_options_ie(LIBLTE_MME_PROTOCOL_CONFIG_OPTIONS_STRUCT *protocol_cnfg_opts, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint32 idx; + uint32 i; + uint32 j; + + if(protocol_cnfg_opts != NULL && + ie_ptr != NULL) + { + (*ie_ptr)[1] = 0x80; + idx = 2; + for(i=0; iN_opts; i++) + { + (*ie_ptr)[idx++] = protocol_cnfg_opts->opt[i].id >> 8; + (*ie_ptr)[idx++] = protocol_cnfg_opts->opt[i].id & 0x00FF; + (*ie_ptr)[idx++] = protocol_cnfg_opts->opt[i].len; + for(j=0; jopt[i].len; j++) + { + (*ie_ptr)[idx++] = protocol_cnfg_opts->opt[i].contents[j]; + } + } + (*ie_ptr)[0] = idx - 1; + *ie_ptr += idx; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_protocol_config_options_ie(uint8 **ie_ptr, + LIBLTE_MME_PROTOCOL_CONFIG_OPTIONS_STRUCT *protocol_cnfg_opts) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint32 idx; + uint32 i; + + if(ie_ptr != NULL && + protocol_cnfg_opts != NULL) + { + idx = 2; + protocol_cnfg_opts->N_opts = 0; + while(idx < (*ie_ptr)[0]) + { + protocol_cnfg_opts->opt[protocol_cnfg_opts->N_opts].id = (*ie_ptr)[idx++] << 8; + protocol_cnfg_opts->opt[protocol_cnfg_opts->N_opts].id |= (*ie_ptr)[idx++]; + protocol_cnfg_opts->opt[protocol_cnfg_opts->N_opts].len = (*ie_ptr)[idx++]; + for(i=0; iopt[protocol_cnfg_opts->N_opts].len; i++) + { + protocol_cnfg_opts->opt[protocol_cnfg_opts->N_opts].contents[i] = (*ie_ptr)[idx++]; + } + protocol_cnfg_opts->N_opts++; + } + *ie_ptr += (*ie_ptr)[0] + 1; + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Quality Of Service + + Description: Specifies the QoS parameters for a PDP context. + + Document Reference: 24.301 v10.2.0 Section 9.9.4.12 + 24.008 v10.2.0 Section 10.5.6.5 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_quality_of_service_ie(LIBLTE_MME_QUALITY_OF_SERVICE_STRUCT *qos, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(qos != NULL && + ie_ptr != NULL) + { + if(qos->dl_ext_present && + qos->ul_ext_present) + { + (*ie_ptr)[0] = 16; + }else if(qos->dl_ext_present){ + (*ie_ptr)[0] = 14; + }else{ + (*ie_ptr)[0] = 12; + } + (*ie_ptr)[1] = ((qos->delay_class & 0x07) << 3) | (qos->reliability_class & 0x07); + (*ie_ptr)[2] = ((qos->peak_throughput & 0x0F) << 4) | (qos->precedence_class & 0x07); + (*ie_ptr)[3] = qos->mean_throughput & 0x1F; + (*ie_ptr)[4] = ((qos->traffic_class & 0x07) << 5) | ((qos->delivery_order & 0x03) << 3) | (qos->delivery_of_erroneous_sdu & 0x03); + (*ie_ptr)[5] = qos->max_sdu_size; + (*ie_ptr)[6] = qos->mbr_ul; + (*ie_ptr)[7] = qos->mbr_dl; + (*ie_ptr)[8] = ((qos->residual_ber & 0x0F) << 4) | (qos->sdu_error_ratio & 0x0F); + (*ie_ptr)[9] = ((qos->transfer_delay & 0x3F) << 2) | (qos->traffic_handling_prio & 0x03); + (*ie_ptr)[10] = qos->gbr_ul; + (*ie_ptr)[11] = qos->gbr_dl; + (*ie_ptr)[12] = ((qos->signalling_ind & 0x01) << 4) | (qos->source_stats_descriptor & 0x0F); + if(qos->dl_ext_present) + { + (*ie_ptr)[13] = qos->mbr_dl_ext; + (*ie_ptr)[14] = qos->gbr_dl_ext; + } + if(qos->ul_ext_present) + { + (*ie_ptr)[15] = qos->mbr_ul_ext; + (*ie_ptr)[16] = qos->gbr_ul_ext; + } + if(qos->dl_ext_present && + qos->ul_ext_present) + { + *ie_ptr += 17; + }else if(qos->dl_ext_present){ + *ie_ptr += 15; + }else{ + *ie_ptr += 13; + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_quality_of_service_ie(uint8 **ie_ptr, + LIBLTE_MME_QUALITY_OF_SERVICE_STRUCT *qos) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + qos != NULL) + { + if(16 == (*ie_ptr)[0]) + { + qos->dl_ext_present = true; + qos->ul_ext_present = true; + }else if(14 == (*ie_ptr)[0]){ + qos->dl_ext_present = true; + qos->ul_ext_present = false; + }else{ + qos->dl_ext_present = false; + qos->ul_ext_present = false; + } + qos->delay_class = ((*ie_ptr)[1] >> 3) & 0x07; + qos->reliability_class = (*ie_ptr)[1] & 0x07; + qos->peak_throughput = (*ie_ptr)[2] >> 4; + qos->precedence_class = (*ie_ptr)[2] & 0x07; + qos->mean_throughput = (*ie_ptr)[3] & 0x1F; + qos->traffic_class = ((*ie_ptr)[4] >> 5) & 0x07; + qos->delivery_order = ((*ie_ptr)[4] >> 3) & 0x03; + qos->delivery_of_erroneous_sdu = (*ie_ptr)[4] & 0x07; + qos->max_sdu_size = (*ie_ptr)[5]; + qos->mbr_ul = (*ie_ptr)[6]; + qos->mbr_dl = (*ie_ptr)[7]; + qos->residual_ber = ((*ie_ptr)[8] >> 4) & 0x0F; + qos->sdu_error_ratio = (*ie_ptr)[8] & 0x0F; + qos->transfer_delay = ((*ie_ptr)[9] >> 2) & 0x3F; + qos->traffic_handling_prio = (*ie_ptr)[9] & 0x03; + qos->gbr_ul = (*ie_ptr)[10]; + qos->gbr_dl = (*ie_ptr)[11]; + qos->signalling_ind = ((*ie_ptr)[12] >> 4) & 0x01; + qos->source_stats_descriptor = (*ie_ptr)[12] & 0x0F; + if(qos->dl_ext_present) + { + qos->mbr_dl_ext = (*ie_ptr)[13]; + qos->gbr_dl_ext = (*ie_ptr)[14]; + } + if(qos->ul_ext_present) + { + qos->mbr_ul_ext = (*ie_ptr)[15]; + qos->gbr_ul_ext = (*ie_ptr)[16]; + } + if(qos->dl_ext_present && + qos->ul_ext_present) + { + *ie_ptr += 17; + }else if(qos->dl_ext_present){ + *ie_ptr += 15; + }else{ + *ie_ptr += 13; + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Radio Priority + + Description: Specifies the priority level the UE shall use at the + lower layers for transmission of data related to a + PDP context or for mobile originated SMS + transmission. + + Document Reference: 24.301 v10.2.0 Section 9.9.4.13 + 24.008 v10.2.0 Section 10.5.7.2 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_radio_priority_ie(uint8 radio_prio, + uint8 bit_offset, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL) + { + (*ie_ptr)[0] |= radio_prio << bit_offset; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_radio_priority_ie(uint8 **ie_ptr, + uint8 bit_offset, + uint8 *radio_prio) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + radio_prio != NULL) + { + *radio_prio |= ((*ie_ptr)[0] >> bit_offset) & 0x07; + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Request Type + + Description: Indicates whether the UE requests to establish a new + connectivity to a PDN or keep the connection(s) to + which it has connected via non-3GPP access. + + Document Reference: 24.301 v10.2.0 Section 9.9.4.14 + 24.008 v10.2.0 Section 10.5.6.17 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_request_type_ie(uint8 req_type, + uint8 bit_offset, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL) + { + **ie_ptr |= req_type << bit_offset; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_request_type_ie(uint8 **ie_ptr, + uint8 bit_offset, + uint8 *req_type) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + req_type != NULL) + { + *req_type = (**ie_ptr >> bit_offset) & 0x07; + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Traffic Flow Aggregate Description + + Description: Specifies the aggregate of one or more packet filters + and their related parameters and operations. + + Document Reference: 24.301 v10.2.0 Section 9.9.4.15 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_traffic_flow_aggregate_description_ie(LIBLTE_MME_TRAFFIC_FLOW_AGGREGATE_DESCRIPTION_STRUCT *tfad, + uint8 **ie_ptr) +{ + return(liblte_mme_pack_traffic_flow_template_ie((LIBLTE_MME_TRAFFIC_FLOW_TEMPLATE_STRUCT *)tfad, ie_ptr)); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_traffic_flow_aggregate_description_ie(uint8 **ie_ptr, + LIBLTE_MME_TRAFFIC_FLOW_AGGREGATE_DESCRIPTION_STRUCT *tfad) +{ + return(liblte_mme_unpack_traffic_flow_template_ie(ie_ptr, (LIBLTE_MME_TRAFFIC_FLOW_TEMPLATE_STRUCT *)tfad)); +} + +/********************************************************************* + IE Name: Traffic Flow Template + + Description: Specifies the TFT parameters and operations for a + PDP context. + + Document Reference: 24.301 v10.2.0 Section 9.9.4.16 + 24.008 v10.2.0 Section 10.5.6.12 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_traffic_flow_template_ie(LIBLTE_MME_TRAFFIC_FLOW_TEMPLATE_STRUCT *tft, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint32 idx; + uint32 i; + uint32 j; + + if(tft != NULL && + ie_ptr != NULL) + { + idx = 1; + (*ie_ptr)[idx] = (tft->tft_op_code & 0x07) << 5; + if(0 != tft->parameter_list_size) + { + (*ie_ptr)[idx] |= 0x10; + } + (*ie_ptr)[idx] |= tft->packet_filter_list_size & 0x0F; + idx++; + + for(i=0; ipacket_filter_list_size; i++) + { + (*ie_ptr)[idx] = (tft->packet_filter_list[i].dir & 0x0F) << 4; + (*ie_ptr)[idx] |= tft->packet_filter_list[i].id & 0x0F; + idx++; + if(LIBLTE_MME_TFT_OPERATION_CODE_DELETE_PACKET_FILTERS_FROM_EXISTING_TFT != tft->tft_op_code) + { + (*ie_ptr)[idx] = tft->packet_filter_list[i].eval_precedence; + idx++; + (*ie_ptr)[idx] = tft->packet_filter_list[i].filter_size; + idx++; + for(j=0; jpacket_filter_list[i].filter_size; j++) + { + (*ie_ptr)[idx] = tft->packet_filter_list[i].filter[j]; + idx++; + } + } + } + + for(i=0; iparameter_list_size; i++) + { + (*ie_ptr)[idx] = tft->parameter_list[i].id; + idx++; + (*ie_ptr)[idx] = tft->parameter_list[i].parameter_size; + idx++; + for(j=0; jparameter_list[i].parameter_size; j++) + { + (*ie_ptr)[idx] = tft->parameter_list[i].parameter[j]; + idx++; + } + } + (*ie_ptr)[0] = idx - 1; + *ie_ptr += idx; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_traffic_flow_template_ie(uint8 **ie_ptr, + LIBLTE_MME_TRAFFIC_FLOW_TEMPLATE_STRUCT *tft) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint32 idx; + uint32 i; + uint32 j; + bool param_list_present; + + if(ie_ptr != NULL && + tft != NULL) + { + idx = 1; + tft->tft_op_code = (LIBLTE_MME_TFT_OPERATION_CODE_ENUM)(((*ie_ptr)[idx] >> 5) & 0x07); + param_list_present = ((*ie_ptr)[idx] >> 4) & 0x01; + tft->packet_filter_list_size = (*ie_ptr)[idx] & 0x0F; + idx++; + + for(i=0; ipacket_filter_list_size; i++) + { + tft->packet_filter_list[i].dir = (LIBLTE_MME_TFT_PACKET_FILTER_DIRECTION_ENUM)(((*ie_ptr)[idx] >> 4) & 0x0F); + tft->packet_filter_list[i].id = (*ie_ptr)[idx] & 0x0F; + idx++; + if(LIBLTE_MME_TFT_OPERATION_CODE_DELETE_PACKET_FILTERS_FROM_EXISTING_TFT != tft->tft_op_code) + { + tft->packet_filter_list[i].eval_precedence = (*ie_ptr)[idx]; + idx++; + tft->packet_filter_list[i].filter_size = (*ie_ptr)[idx]; + idx++; + for(j=0; jpacket_filter_list[i].filter_size; j++) + { + tft->packet_filter_list[i].filter[j] = (*ie_ptr)[idx]; + idx++; + } + } + } + + if(param_list_present) + { + tft->parameter_list_size = 0; + while(idx < (*ie_ptr)[0]) + { + tft->parameter_list[tft->parameter_list_size].id = (*ie_ptr)[idx]; + idx++; + tft->parameter_list[tft->parameter_list_size].parameter_size = (*ie_ptr)[idx]; + idx++; + for(i=0; iparameter_list[tft->parameter_list_size].parameter_size; i++) + { + tft->parameter_list[tft->parameter_list_size].parameter[i] = (*ie_ptr)[idx]; + idx++; + } + tft->parameter_list_size++; + } + } + + *ie_ptr += (*ie_ptr)[0] + 1; + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Transaction Identifier + + Description: Represents the corresponding PDP context in A/Gb + mode or Iu mode which is mapped from the EPS bearer + context. + + Document Reference: 24.301 v10.2.0 Section 9.9.4.17 + 24.008 v10.2.0 Section 10.5.6.7 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_transaction_identifier_ie(LIBLTE_MME_TRANSACTION_IDENTIFIER_STRUCT *trans_id, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(trans_id != NULL && + ie_ptr != NULL) + { + if(LIBLTE_MME_TI_VALUE_IS_GIVEN_BY_TIE == trans_id->tio) + { + (*ie_ptr)[0] = 2; + }else{ + (*ie_ptr)[0] = 1; + } + (*ie_ptr)[1] = ((trans_id->ti_flag & 0x01) << 7) | ((trans_id->tio & 0x07) << 4); + if(LIBLTE_MME_TI_VALUE_IS_GIVEN_BY_TIE == trans_id->tio) + { + (*ie_ptr)[2] = 0x80 | (trans_id->tie & 0x7F); + *ie_ptr += 3; + }else{ + *ie_ptr += 2; + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_transaction_identifier_ie(uint8 **ie_ptr, + LIBLTE_MME_TRANSACTION_IDENTIFIER_STRUCT *trans_id) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + trans_id != NULL) + { + trans_id->ti_flag = (*ie_ptr)[1] >> 7; + trans_id->tio = ((*ie_ptr)[1] >> 4) & 0x07; + if(LIBLTE_MME_TI_VALUE_IS_GIVEN_BY_TIE == trans_id->tio) + { + trans_id->tie = (*ie_ptr)[2] & 0x7F; + } + *ie_ptr += (*ie_ptr)[0] + 1; + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/******************************************************************************* + MESSAGE FUNCTIONS +*******************************************************************************/ + +/********************************************************************* + Message Name: Message Header (Plain NAS Message) + + Description: Message header for plain NAS messages. + + Document Reference: 24.301 v10.2.0 Section 9.1 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_parse_msg_header(LIBLTE_BYTE_MSG_STRUCT *msg, + uint8 *pd, + uint8 *msg_type) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 sec_hdr_type; + + if(msg != NULL && + pd != NULL && + msg_type != NULL) + { + // Security Header Type + sec_hdr_type = (msg->msg[0] & 0xF0) >> 4; + + // Protocol Discriminator + *pd = msg->msg[0] & 0x0F; + + if(LIBLTE_MME_SECURITY_HDR_TYPE_SERVICE_REQUEST == sec_hdr_type) + { + *msg_type = LIBLTE_MME_SECURITY_HDR_TYPE_SERVICE_REQUEST; + }else{ + if(LIBLTE_MME_PD_EPS_SESSION_MANAGEMENT == *pd) + { + // Message Type + *msg_type = msg->msg[2]; + }else{ + if(LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS == sec_hdr_type) + { + // Message Type + *msg_type = msg->msg[1]; + }else{ + // Protocol Discriminator + *pd = msg->msg[6] & 0x0F; + + if(LIBLTE_MME_PD_EPS_SESSION_MANAGEMENT == *pd) + { + *msg_type = msg->msg[8]; + }else{ + *msg_type = msg->msg[7]; + } + } + } + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_pack_security_protected_nas_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + uint8 sec_hdr_type, + uint32 count, + LIBLTE_BYTE_MSG_STRUCT *sec_msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = sec_msg->msg; + uint32 i; + + if(msg != NULL && + sec_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++; + } + + // NAS Message + for(i=0; iN_bytes; i++) + { + *msg_ptr = msg->msg[i]; + msg_ptr++; + } + + // Fill in the number of bytes used + sec_msg->N_bytes = msg_ptr - sec_msg->msg; + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + Message Name: Attach Accept + + Description: Sent by the network to the UE to indicate that the + corresponding attach request has been accepted. + + Document Reference: 24.301 v10.2.0 Section 8.2.1 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_attach_accept_msg(LIBLTE_MME_ATTACH_ACCEPT_MSG_STRUCT *attach_accept, + 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(attach_accept != 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++; + + // Message Type + *msg_ptr = LIBLTE_MME_MSG_TYPE_ATTACH_ACCEPT; + msg_ptr++; + + // EPS Attach Result & Spare Half Octet + *msg_ptr = 0; + liblte_mme_pack_eps_attach_result_ie(attach_accept->eps_attach_result, 0, &msg_ptr); + msg_ptr++; + + // T3412 Value + liblte_mme_pack_gprs_timer_ie(&attach_accept->t3412, &msg_ptr); + + // TAI List + liblte_mme_pack_tracking_area_identity_list_ie(&attach_accept->tai_list, &msg_ptr); + + // ESM Message Container + liblte_mme_pack_esm_message_container_ie(&attach_accept->esm_msg, &msg_ptr); + + // GUTI + if(attach_accept->guti_present) + { + *msg_ptr = LIBLTE_MME_GUTI_IEI; + msg_ptr++; + liblte_mme_pack_eps_mobile_id_ie(&attach_accept->guti, &msg_ptr); + } + + // Location Area Identification + if(attach_accept->lai_present) + { + *msg_ptr = LIBLTE_MME_LOCATION_AREA_IDENTIFICATION_IEI; + msg_ptr++; + liblte_mme_pack_location_area_id_ie(&attach_accept->lai, &msg_ptr); + } + + // MS Identity + if(attach_accept->ms_id_present) + { + *msg_ptr = LIBLTE_MME_MS_IDENTITY_IEI; + msg_ptr++; + liblte_mme_pack_mobile_id_ie(&attach_accept->ms_id, &msg_ptr); + } + + // EMM Cause + if(attach_accept->emm_cause_present) + { + *msg_ptr = LIBLTE_MME_EMM_CAUSE_IEI; + msg_ptr++; + liblte_mme_pack_emm_cause_ie(attach_accept->emm_cause, &msg_ptr); + } + + // T3402 Value + if(attach_accept->t3402_present) + { + *msg_ptr = LIBLTE_MME_T3402_VALUE_IEI; + msg_ptr++; + liblte_mme_pack_gprs_timer_ie(&attach_accept->t3402, &msg_ptr); + } + + // T3423 Value + if(attach_accept->t3423_present) + { + *msg_ptr = LIBLTE_MME_T3423_VALUE_IEI; + msg_ptr++; + liblte_mme_pack_gprs_timer_ie(&attach_accept->t3423, &msg_ptr); + } + + // Equivalent PLMNs + if(attach_accept->equivalent_plmns_present) + { + *msg_ptr = LIBLTE_MME_EQUIVALENT_PLMNS_IEI; + msg_ptr++; + liblte_mme_pack_plmn_list_ie(&attach_accept->equivalent_plmns, &msg_ptr); + } + + // Emergency Number List + if(attach_accept->emerg_num_list_present) + { + *msg_ptr = LIBLTE_MME_EMERGENCY_NUMBER_LIST_IEI; + msg_ptr++; + liblte_mme_pack_emergency_number_list_ie(&attach_accept->emerg_num_list, &msg_ptr); + } + + // EPS Network Feature Support + if(attach_accept->eps_network_feature_support_present) + { + *msg_ptr = LIBLTE_MME_EPS_NETWORK_FEATURE_SUPPORT_IEI; + msg_ptr++; + liblte_mme_pack_eps_network_feature_support_ie(&attach_accept->eps_network_feature_support, &msg_ptr); + } + + // Additional Update Result + if(attach_accept->additional_update_result_present) + { + *msg_ptr = LIBLTE_MME_ADDITIONAL_UPDATE_RESULT_IEI << 4; + liblte_mme_pack_additional_update_result_ie(attach_accept->additional_update_result, 0, &msg_ptr); + msg_ptr++; + } + + // T3412 Extended Value + if(attach_accept->t3412_ext_present) + { + *msg_ptr = LIBLTE_MME_T3412_EXTENDED_VALUE_IEI; + msg_ptr++; + liblte_mme_pack_gprs_timer_3_ie(&attach_accept->t3412_ext, &msg_ptr); + } + + // Fill in the number of bytes used + msg->N_bytes = msg_ptr - msg->msg; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_attach_accept_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_ATTACH_ACCEPT_MSG_STRUCT *attach_accept) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + uint8 sec_hdr_type; + + if(msg != NULL && + attach_accept != NULL) + { + // Security Header Type + sec_hdr_type = (msg->msg[0] & 0xF0) >> 4; + if(LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS == sec_hdr_type) + { + msg_ptr++; + }else{ + msg_ptr += 7; + } + + // Skip Message Type + msg_ptr++; + + // EPS Attach Result & Spare Half Octet + liblte_mme_unpack_eps_attach_result_ie(&msg_ptr, 0, &attach_accept->eps_attach_result); + msg_ptr++; + + // T3412 Value + liblte_mme_unpack_gprs_timer_ie(&msg_ptr, &attach_accept->t3412); + + // TAI List + liblte_mme_unpack_tracking_area_identity_list_ie(&msg_ptr, &attach_accept->tai_list); + + // ESM Message Container + liblte_mme_unpack_esm_message_container_ie(&msg_ptr, &attach_accept->esm_msg); + + // GUTI + if(LIBLTE_MME_GUTI_IEI == *msg_ptr) + { + msg_ptr++; + liblte_mme_unpack_eps_mobile_id_ie(&msg_ptr, &attach_accept->guti); + attach_accept->guti_present = true; + }else{ + attach_accept->guti_present = false; + } + + // Location Area Identification + if(LIBLTE_MME_LOCATION_AREA_IDENTIFICATION_IEI == *msg_ptr) + { + msg_ptr++; + liblte_mme_unpack_location_area_id_ie(&msg_ptr, &attach_accept->lai); + attach_accept->lai_present = true; + }else{ + attach_accept->lai_present = false; + } + + // MS Identity + if(LIBLTE_MME_MS_IDENTITY_IEI == *msg_ptr) + { + msg_ptr++; + liblte_mme_unpack_mobile_id_ie(&msg_ptr, &attach_accept->ms_id); + attach_accept->ms_id_present = true; + }else{ + attach_accept->ms_id_present = false; + } + + // EMM Cause + if(LIBLTE_MME_EMM_CAUSE_IEI == *msg_ptr) + { + msg_ptr++; + liblte_mme_unpack_emm_cause_ie(&msg_ptr, &attach_accept->emm_cause); + attach_accept->emm_cause_present = true; + }else{ + attach_accept->emm_cause_present = false; + } + + // T3402 Value + if(LIBLTE_MME_T3402_VALUE_IEI == *msg_ptr) + { + msg_ptr++; + liblte_mme_unpack_gprs_timer_ie(&msg_ptr, &attach_accept->t3402); + attach_accept->t3402_present = true; + }else{ + attach_accept->t3402_present = false; + } + + // T3423 Value + if(LIBLTE_MME_T3423_VALUE_IEI == *msg_ptr) + { + msg_ptr++; + liblte_mme_unpack_gprs_timer_ie(&msg_ptr, &attach_accept->t3423); + attach_accept->t3423_present = true; + }else{ + attach_accept->t3423_present = false; + } + + // Equivalent PLMNs + if(LIBLTE_MME_EQUIVALENT_PLMNS_IEI == *msg_ptr) + { + msg_ptr++; + liblte_mme_unpack_plmn_list_ie(&msg_ptr, &attach_accept->equivalent_plmns); + attach_accept->equivalent_plmns_present = true; + }else{ + attach_accept->equivalent_plmns_present = false; + } + + // Emergency Number List + if(LIBLTE_MME_EMERGENCY_NUMBER_LIST_IEI == *msg_ptr) + { + msg_ptr++; + liblte_mme_unpack_emergency_number_list_ie(&msg_ptr, &attach_accept->emerg_num_list); + attach_accept->emerg_num_list_present = true; + }else{ + attach_accept->emerg_num_list_present = false; + } + + // EPS Network Feature Support + if(LIBLTE_MME_EPS_NETWORK_FEATURE_SUPPORT_IEI == *msg_ptr) + { + msg_ptr++; + liblte_mme_unpack_eps_network_feature_support_ie(&msg_ptr, &attach_accept->eps_network_feature_support); + attach_accept->eps_network_feature_support_present = true; + }else{ + attach_accept->eps_network_feature_support_present = false; + } + + // Additional Update Result + if((LIBLTE_MME_ADDITIONAL_UPDATE_RESULT_IEI << 4) == (*msg_ptr & 0xF0)) + { + liblte_mme_unpack_additional_update_result_ie(&msg_ptr, 0, &attach_accept->additional_update_result); + msg_ptr++; + attach_accept->additional_update_result_present = true; + }else{ + attach_accept->additional_update_result_present = false; + } + + // T3412 Extended Value + if(LIBLTE_MME_T3412_EXTENDED_VALUE_IEI == *msg_ptr) + { + msg_ptr++; + liblte_mme_unpack_gprs_timer_3_ie(&msg_ptr, &attach_accept->t3412_ext); + attach_accept->t3412_ext_present = true; + }else{ + attach_accept->t3412_ext_present = false; + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + Message Name: Attach Complete + + Description: Sent by the UE to the network in response to an + ATTACH ACCEPT message. + + Document Reference: 24.301 v10.2.0 Section 8.2.2 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_attach_complete_msg(LIBLTE_MME_ATTACH_COMPLETE_MSG_STRUCT *attach_comp, + 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(attach_comp != 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++; + + // Message Type + *msg_ptr = LIBLTE_MME_MSG_TYPE_ATTACH_COMPLETE; + msg_ptr++; + + // ESM Message Container + liblte_mme_pack_esm_message_container_ie(&attach_comp->esm_msg, &msg_ptr); + + // Fill in the number of bytes used + msg->N_bytes = msg_ptr - msg->msg; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_attach_complete_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_ATTACH_COMPLETE_MSG_STRUCT *attach_comp) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + uint8 sec_hdr_type; + + if(msg != NULL && + attach_comp != NULL) + { + // Security Header Type + sec_hdr_type = (msg->msg[0] & 0xF0) >> 4; + if(LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS == sec_hdr_type) + { + msg_ptr++; + }else{ + msg_ptr += 7; + } + + // Skip Message Type + msg_ptr++; + + // ESM Message Container + liblte_mme_unpack_esm_message_container_ie(&msg_ptr, &attach_comp->esm_msg); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + Message Name: Attach Reject + + Description: Sent by the network to the UE to indicate that the + corresponding attach request has been rejected. + + Document Reference: 24.301 v10.2.0 Section 8.2.3 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_attach_reject_msg(LIBLTE_MME_ATTACH_REJECT_MSG_STRUCT *attach_rej, + LIBLTE_BYTE_MSG_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(attach_rej != NULL && + msg != NULL) + { + // Protocol Discriminator and Security Header Type + *msg_ptr = (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT); + msg_ptr++; + + // Message Type + *msg_ptr = LIBLTE_MME_MSG_TYPE_ATTACH_REJECT; + msg_ptr++; + + // EMM Cause + liblte_mme_pack_emm_cause_ie(attach_rej->emm_cause, &msg_ptr); + + // ESM Message Container + if(attach_rej->esm_msg_present) + { + *msg_ptr = LIBLTE_MME_ESM_MSG_CONTAINER_IEI; + msg_ptr++; + liblte_mme_pack_esm_message_container_ie(&attach_rej->esm_msg, &msg_ptr); + } + + // T3446 Value + if(attach_rej->t3446_value_present) + { + *msg_ptr = LIBLTE_MME_T3446_VALUE_IEI; + msg_ptr++; + liblte_mme_pack_gprs_timer_2_ie(attach_rej->t3446_value, &msg_ptr); + } + + // Fill in the number of bytes used + msg->N_bytes = msg_ptr - msg->msg; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_attach_reject_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_ATTACH_REJECT_MSG_STRUCT *attach_rej) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + uint8 sec_hdr_type; + + if(msg != NULL && + attach_rej != NULL) + { + // Security Header Type + sec_hdr_type = (msg->msg[0] & 0xF0) >> 4; + if(LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS == sec_hdr_type) + { + msg_ptr++; + }else{ + msg_ptr += 7; + } + + // Skip Message Type + msg_ptr++; + + // EMM Cause + liblte_mme_unpack_emm_cause_ie(&msg_ptr, &attach_rej->emm_cause); + + // ESM Message Container + if(LIBLTE_MME_ESM_MSG_CONTAINER_IEI == *msg_ptr) + { + msg_ptr++; + liblte_mme_unpack_esm_message_container_ie(&msg_ptr, &attach_rej->esm_msg); + attach_rej->esm_msg_present = true; + }else{ + attach_rej->esm_msg_present = false; + } + + // T3446 Value + if(LIBLTE_MME_T3446_VALUE_IEI == *msg_ptr) + { + msg_ptr++; + liblte_mme_unpack_gprs_timer_2_ie(&msg_ptr, &attach_rej->t3446_value); + attach_rej->t3446_value_present = true; + }else{ + attach_rej->t3446_value_present = false; + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + Message Name: Attach Request + + Description: Sent by the UE to the network to perform an attach + procedure. + + Document Reference: 24.301 v10.2.0 Section 8.2.4 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_attach_request_msg(LIBLTE_MME_ATTACH_REQUEST_MSG_STRUCT *attach_req, + LIBLTE_BYTE_MSG_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(attach_req != NULL && + msg != NULL) + { + // Protocol Discriminator and Security Header Type + *msg_ptr = (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT); + msg_ptr++; + + // Message Type + *msg_ptr = LIBLTE_MME_MSG_TYPE_ATTACH_REQUEST; + msg_ptr++; + + // EPS Attach Type & NAS Key Set Identifier + *msg_ptr = 0; + liblte_mme_pack_eps_attach_type_ie(attach_req->eps_attach_type, 0, &msg_ptr); + liblte_mme_pack_nas_key_set_id_ie(&attach_req->nas_ksi, 4, &msg_ptr); + msg_ptr++; + + // EPS Mobile ID + liblte_mme_pack_eps_mobile_id_ie(&attach_req->eps_mobile_id, &msg_ptr); + + // UE Network Capability + liblte_mme_pack_ue_network_capability_ie(&attach_req->ue_network_cap, &msg_ptr); + + // ESM Message Container + liblte_mme_pack_esm_message_container_ie(&attach_req->esm_msg, &msg_ptr); + + // Old P-TMSI Signature + if(attach_req->old_p_tmsi_signature_present) + { + *msg_ptr = LIBLTE_MME_P_TMSI_SIGNATURE_IEI; + msg_ptr++; + liblte_mme_pack_p_tmsi_signature_ie(attach_req->old_p_tmsi_signature, &msg_ptr); + } + + // Additional GUTI + if(attach_req->additional_guti_present) + { + *msg_ptr = LIBLTE_MME_ADDITIONAL_GUTI_IEI; + msg_ptr++; + liblte_mme_pack_eps_mobile_id_ie(&attach_req->additional_guti, &msg_ptr); + } + + // Last Visited Registered TAI + if(attach_req->last_visited_registered_tai_present) + { + *msg_ptr = LIBLTE_MME_LAST_VISITED_REGISTERED_TAI_IEI; + msg_ptr++; + liblte_mme_pack_tracking_area_id_ie(&attach_req->last_visited_registered_tai, &msg_ptr); + } + + // DRX Parameter + if(attach_req->drx_param_present) + { + *msg_ptr = LIBLTE_MME_DRX_PARAMETER_IEI; + msg_ptr++; + liblte_mme_pack_drx_parameter_ie(&attach_req->drx_param, &msg_ptr); + } + + // MS Network Capability + if(attach_req->ms_network_cap_present) + { + *msg_ptr = LIBLTE_MME_MS_NETWORK_CAPABILITY_IEI; + msg_ptr++; + liblte_mme_pack_ms_network_capability_ie(&attach_req->ms_network_cap, &msg_ptr); + } + + // Old Location Area ID + if(attach_req->old_lai_present) + { + *msg_ptr = LIBLTE_MME_LOCATION_AREA_IDENTIFICATION_IEI; + msg_ptr++; + liblte_mme_pack_location_area_id_ie(&attach_req->old_lai, &msg_ptr); + } + + // TMSI Status + if(attach_req->tmsi_status_present) + { + *msg_ptr = LIBLTE_MME_TMSI_STATUS_IEI << 4; + liblte_mme_pack_tmsi_status_ie(attach_req->tmsi_status, 0, &msg_ptr); + msg_ptr++; + } + + // Mobile Station Classmark 2 + if(attach_req->ms_cm2_present) + { + *msg_ptr = LIBLTE_MME_MS_CLASSMARK_2_IEI; + msg_ptr++; + liblte_mme_pack_mobile_station_classmark_2_ie(&attach_req->ms_cm2, &msg_ptr); + } + + // Mobile Station Classmark 3 + if(attach_req->ms_cm3_present) + { + *msg_ptr = LIBLTE_MME_MS_CLASSMARK_3_IEI; + msg_ptr++; + liblte_mme_pack_mobile_station_classmark_3_ie(&attach_req->ms_cm3, &msg_ptr); + } + + // Supported Codecs + if(attach_req->supported_codecs_present) + { + *msg_ptr = LIBLTE_MME_SUPPORTED_CODEC_LIST_IEI; + msg_ptr++; + liblte_mme_pack_supported_codec_list_ie(&attach_req->supported_codecs, &msg_ptr); + } + + // Additional Update Type + if(attach_req->additional_update_type_present) + { + *msg_ptr = LIBLTE_MME_ADDITIONAL_UPDATE_TYPE_IEI << 4; + liblte_mme_pack_additional_update_type_ie(attach_req->additional_update_type, 0, &msg_ptr); + msg_ptr++; + } + + // Voice Domain Preference and UE's Usage Setting + if(attach_req->voice_domain_pref_and_ue_usage_setting_present) + { + *msg_ptr = LIBLTE_MME_VOICE_DOMAIN_PREF_AND_UE_USAGE_SETTING_IEI; + msg_ptr++; + liblte_mme_pack_voice_domain_pref_and_ue_usage_setting_ie(&attach_req->voice_domain_pref_and_ue_usage_setting, &msg_ptr); + } + + // Device Properties + if(attach_req->device_properties_present) + { + *msg_ptr = LIBLTE_MME_ATTACH_REQUEST_DEVICE_PROPERTIES_IEI << 4; + liblte_mme_pack_device_properties_ie(attach_req->device_properties, 0, &msg_ptr); + msg_ptr++; + } + + // Old GUTI Type + if(attach_req->old_guti_type_present) + { + *msg_ptr = LIBLTE_MME_GUTI_TYPE_IEI << 4; + liblte_mme_pack_guti_type_ie(attach_req->old_guti_type, 0, &msg_ptr); + msg_ptr++; + } + + // Fill in the number of bytes used + msg->N_bytes = msg_ptr - msg->msg; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_attach_request_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_ATTACH_REQUEST_MSG_STRUCT *attach_req) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + uint8 sec_hdr_type; + + if(msg != NULL && + attach_req != NULL) + { + // Security Header Type + sec_hdr_type = (msg->msg[0] & 0xF0) >> 4; + if(LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS == sec_hdr_type) + { + msg_ptr++; + }else{ + msg_ptr += 7; + } + + // Skip Message Type + msg_ptr++; + + // EPS Attach Type & NAS Key Set Identifier + liblte_mme_unpack_eps_attach_type_ie(&msg_ptr, 0, &attach_req->eps_attach_type); + liblte_mme_unpack_nas_key_set_id_ie(&msg_ptr, 4, &attach_req->nas_ksi); + msg_ptr++; + + // EPS Mobile ID + liblte_mme_unpack_eps_mobile_id_ie(&msg_ptr, &attach_req->eps_mobile_id); + + // UE Network Capability + liblte_mme_unpack_ue_network_capability_ie(&msg_ptr, &attach_req->ue_network_cap); + + // ESM Message Container + liblte_mme_unpack_esm_message_container_ie(&msg_ptr, &attach_req->esm_msg); + + // Old P-TMSI Signature + if(LIBLTE_MME_P_TMSI_SIGNATURE_IEI == *msg_ptr) + { + msg_ptr++; + liblte_mme_unpack_p_tmsi_signature_ie(&msg_ptr, &attach_req->old_p_tmsi_signature); + attach_req->old_p_tmsi_signature_present = true; + }else{ + attach_req->old_p_tmsi_signature_present = false; + } + + // Additional GUTI + if(LIBLTE_MME_ADDITIONAL_GUTI_IEI == *msg_ptr) + { + msg_ptr++; + liblte_mme_unpack_eps_mobile_id_ie(&msg_ptr, &attach_req->additional_guti); + attach_req->additional_guti_present = true; + }else{ + attach_req->additional_guti_present = false; + } + + // Last Visited Registered TAI + if(LIBLTE_MME_LAST_VISITED_REGISTERED_TAI_IEI == *msg_ptr) + { + msg_ptr++; + liblte_mme_unpack_tracking_area_id_ie(&msg_ptr, &attach_req->last_visited_registered_tai); + attach_req->last_visited_registered_tai_present = true; + }else{ + attach_req->last_visited_registered_tai_present = false; + } + + // DRX Parameter + if(LIBLTE_MME_DRX_PARAMETER_IEI == *msg_ptr) + { + msg_ptr++; + liblte_mme_unpack_drx_parameter_ie(&msg_ptr, &attach_req->drx_param); + attach_req->drx_param_present = true; + }else{ + attach_req->drx_param_present = false; + } + + // MS Network Capability + if(LIBLTE_MME_MS_NETWORK_CAPABILITY_IEI == *msg_ptr) + { + msg_ptr++; + liblte_mme_unpack_ms_network_capability_ie(&msg_ptr, &attach_req->ms_network_cap); + attach_req->ms_network_cap_present = true; + }else{ + attach_req->ms_network_cap_present = false; + } + + // Old Location Area ID + if(LIBLTE_MME_LOCATION_AREA_IDENTIFICATION_IEI == *msg_ptr) + { + msg_ptr++; + liblte_mme_unpack_location_area_id_ie(&msg_ptr, &attach_req->old_lai); + attach_req->old_lai_present = true; + }else{ + attach_req->old_lai_present = false; + } + + // TMSI Status + if((LIBLTE_MME_TMSI_STATUS_IEI << 4) == (*msg_ptr & 0xF0)) + { + liblte_mme_unpack_tmsi_status_ie(&msg_ptr, 0, &attach_req->tmsi_status); + msg_ptr++; + attach_req->tmsi_status_present = true; + }else{ + attach_req->tmsi_status_present = false; + } + + // Mobile Station Classmark 2 + if(LIBLTE_MME_MS_CLASSMARK_2_IEI == *msg_ptr) + { + msg_ptr++; + liblte_mme_unpack_mobile_station_classmark_2_ie(&msg_ptr, &attach_req->ms_cm2); + attach_req->ms_cm2_present = true; + }else{ + attach_req->ms_cm2_present = false; + } + + // Mobile Station Classmark 3 + if(LIBLTE_MME_MS_CLASSMARK_3_IEI == *msg_ptr) + { + msg_ptr++; + liblte_mme_unpack_mobile_station_classmark_3_ie(&msg_ptr, &attach_req->ms_cm3); + attach_req->ms_cm3_present = true; + }else{ + attach_req->ms_cm3_present = false; + } + + // Supported Codecs + if(LIBLTE_MME_SUPPORTED_CODEC_LIST_IEI == *msg_ptr) + { + msg_ptr++; + liblte_mme_unpack_supported_codec_list_ie(&msg_ptr, &attach_req->supported_codecs); + attach_req->supported_codecs_present = true; + }else{ + attach_req->supported_codecs_present = false; + } + + // Additional Update Type + if((LIBLTE_MME_ADDITIONAL_UPDATE_TYPE_IEI << 4) == (*msg_ptr & 0xF0)) + { + liblte_mme_unpack_additional_update_type_ie(&msg_ptr, 0, &attach_req->additional_update_type); + msg_ptr++; + attach_req->additional_update_type_present = true; + }else{ + attach_req->additional_update_type_present = false; + } + + // Voice Domain Preference and UE's Usage Setting + if(LIBLTE_MME_VOICE_DOMAIN_PREF_AND_UE_USAGE_SETTING_IEI == *msg_ptr) + { + msg_ptr++; + liblte_mme_unpack_voice_domain_pref_and_ue_usage_setting_ie(&msg_ptr, &attach_req->voice_domain_pref_and_ue_usage_setting); + attach_req->voice_domain_pref_and_ue_usage_setting_present = true; + }else{ + attach_req->voice_domain_pref_and_ue_usage_setting_present = false; + } + + // Device Properties + if((LIBLTE_MME_ATTACH_REQUEST_DEVICE_PROPERTIES_IEI << 4) == (*msg_ptr & 0xF0)) + { + liblte_mme_unpack_device_properties_ie(&msg_ptr, 0, &attach_req->device_properties); + msg_ptr++; + attach_req->device_properties_present = true; + }else{ + attach_req->device_properties_present = false; + } + + // Old GUTI Type + if((LIBLTE_MME_GUTI_TYPE_IEI << 4) == (*msg_ptr & 0xF0)) + { + liblte_mme_unpack_guti_type_ie(&msg_ptr, 0, &attach_req->old_guti_type); + msg_ptr++; + attach_req->old_guti_type_present = true; + }else{ + attach_req->old_guti_type_present = false; + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + Message Name: Authentication Failure + + Description: Sent by the UE to the network to indicate that + authentication of the network has failed. + + Document Reference: 24.301 v10.2.0 Section 8.2.5 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_authentication_failure_msg(LIBLTE_MME_AUTHENTICATION_FAILURE_MSG_STRUCT *auth_fail, + LIBLTE_BYTE_MSG_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(auth_fail != NULL && + msg != NULL) + { + // Protocol Discriminator and Security Header Type + *msg_ptr = (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT); + msg_ptr++; + + // Message Type + *msg_ptr = LIBLTE_MME_MSG_TYPE_AUTHENTICATION_FAILURE; + msg_ptr++; + + // EMM Cause + liblte_mme_pack_emm_cause_ie(auth_fail->emm_cause, &msg_ptr); + + // Authentication Failure Parameter + if(auth_fail->auth_fail_param_present) + { + *msg_ptr = LIBLTE_MME_AUTHENTICATION_FAILURE_PARAMETER_IEI; + msg_ptr++; + liblte_mme_pack_authentication_failure_parameter_ie(auth_fail->auth_fail_param, &msg_ptr); + } + + // Fill in the number of bytes used + msg->N_bytes = msg_ptr - msg->msg; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_authentication_failure_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_AUTHENTICATION_FAILURE_MSG_STRUCT *auth_fail) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + uint8 sec_hdr_type; + + if(msg != NULL && + auth_fail != NULL) + { + // Security Header Type + sec_hdr_type = (msg->msg[0] & 0xF0) >> 4; + if(LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS == sec_hdr_type) + { + msg_ptr++; + }else{ + msg_ptr += 7; + } + + // Skip Message Type + msg_ptr++; + + // EMM Cause + liblte_mme_unpack_emm_cause_ie(&msg_ptr, &auth_fail->emm_cause); + + // Authentication Failure Parameter + if(LIBLTE_MME_AUTHENTICATION_FAILURE_PARAMETER_IEI == *msg_ptr) + { + msg_ptr++; + liblte_mme_unpack_authentication_failure_parameter_ie(&msg_ptr, auth_fail->auth_fail_param); + auth_fail->auth_fail_param_present = true; + }else{ + auth_fail->auth_fail_param_present = false; + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + Message Name: Authentication Reject + + Description: Sent by the network to the UE to indicate that the + authentication procedure has failed and that the UE + shall abort all activities. + + Document Reference: 24.301 v10.2.0 Section 8.2.6 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_authentication_reject_msg(LIBLTE_MME_AUTHENTICATION_REJECT_MSG_STRUCT *auth_reject, + LIBLTE_BYTE_MSG_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(auth_reject != NULL && + msg != NULL) + { + // Protocol Discriminator and Security Header Type + *msg_ptr = (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT); + msg_ptr++; + + // Message Type + *msg_ptr = LIBLTE_MME_MSG_TYPE_AUTHENTICATION_REJECT; + msg_ptr++; + + // Fill in the number of bytes used + msg->N_bytes = msg_ptr - msg->msg; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_authentication_reject_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_AUTHENTICATION_REJECT_MSG_STRUCT *auth_reject) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + uint8 sec_hdr_type; + + if(msg != NULL && + auth_reject != NULL) + { + // Security Header Type + sec_hdr_type = (msg->msg[0] & 0xF0) >> 4; + if(LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS == sec_hdr_type) + { + msg_ptr++; + }else{ + msg_ptr += 7; + } + + // Skip Message Type + msg_ptr++; + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + Message Name: Authentication Request + + Description: Sent by the network to the UE to initiate + authentication of the UE identity. + + Document Reference: 24.301 v10.2.0 Section 8.2.7 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_authentication_request_msg(LIBLTE_MME_AUTHENTICATION_REQUEST_MSG_STRUCT *auth_req, + LIBLTE_BYTE_MSG_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(auth_req != NULL && + msg != NULL) + { + // Protocol Discriminator and Security Header Type + *msg_ptr = (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT); + msg_ptr++; + + // Message Type + *msg_ptr = LIBLTE_MME_MSG_TYPE_AUTHENTICATION_REQUEST; + msg_ptr++; + + // NAS Key Set Identifier & Spare Half Octet + *msg_ptr = 0; + liblte_mme_pack_nas_key_set_id_ie(&auth_req->nas_ksi, 0, &msg_ptr); + msg_ptr++; + + // Authentication Parameter RAND + liblte_mme_pack_authentication_parameter_rand_ie(auth_req->rand, &msg_ptr); + + // Authentication Parameter AUTN + liblte_mme_pack_authentication_parameter_autn_ie(auth_req->autn, &msg_ptr); + + // Fill in the number of bytes used + msg->N_bytes = msg_ptr - msg->msg; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_authentication_request_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_AUTHENTICATION_REQUEST_MSG_STRUCT *auth_req) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + uint8 sec_hdr_type; + + if(msg != NULL && + auth_req != NULL) + { + // Security Header Type + sec_hdr_type = (msg->msg[0] & 0xF0) >> 4; + if(LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS == sec_hdr_type) + { + msg_ptr++; + }else{ + msg_ptr += 7; + } + + // Skip Message Type + msg_ptr++; + + // NAS Key Set Identifier & Spare Half Octet + liblte_mme_unpack_nas_key_set_id_ie(&msg_ptr, 0, &auth_req->nas_ksi); + msg_ptr++; + + // Authentication Parameter RAND + liblte_mme_unpack_authentication_parameter_rand_ie(&msg_ptr, auth_req->rand); + + // Authentication Parameter AUTN + liblte_mme_unpack_authentication_parameter_autn_ie(&msg_ptr, auth_req->autn); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + Message Name: Authentication Response + + Description: Sent by the UE to the network to deliver a calculated + authentication response to the network. + + Document Reference: 24.301 v10.2.0 Section 8.2.8 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_authentication_response_msg(LIBLTE_MME_AUTHENTICATION_RESPONSE_MSG_STRUCT *auth_resp, + LIBLTE_BYTE_MSG_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(auth_resp != NULL && + msg != NULL) + { + // Protocol Discriminator and Security Header Type + *msg_ptr = (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT); + msg_ptr++; + + // Message Type + *msg_ptr = LIBLTE_MME_MSG_TYPE_AUTHENTICATION_RESPONSE; + msg_ptr++; + + // Authentication Response Parameter (RES) + liblte_mme_pack_authentication_response_parameter_ie(auth_resp->res, &msg_ptr); + + // Fill in the number of bytes used + msg->N_bytes = msg_ptr - msg->msg; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_authentication_response_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_AUTHENTICATION_RESPONSE_MSG_STRUCT *auth_resp) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + uint8 sec_hdr_type; + + if(msg != NULL && + auth_resp != NULL) + { + // Security Header Type + sec_hdr_type = (msg->msg[0] & 0xF0) >> 4; + if(LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS == sec_hdr_type) + { + msg_ptr++; + }else{ + msg_ptr += 7; + } + + // Skip Message Type + msg_ptr++; + + // Authentication Response Parameter (RES) + liblte_mme_unpack_authentication_response_parameter_ie(&msg_ptr, auth_resp->res); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + Message Name: CS Service Notification + + Description: Sent by the network when a paging request with CS + call indicator was received via SGs for a UE, and a + NAS signalling connection is already established for + the UE. + + Document Reference: 24.301 v10.2.0 Section 8.2.9 +*********************************************************************/ +// FIXME + +/********************************************************************* + Message Name: Detach Accept + + Description: Sent by the network to indicate that the detach + procedure has been completed. + + Document Reference: 24.301 v10.2.0 Section 8.2.10 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_detach_accept_msg(LIBLTE_MME_DETACH_ACCEPT_MSG_STRUCT *detach_accept, + 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(detach_accept != 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++; + + // Message Type + *msg_ptr = LIBLTE_MME_MSG_TYPE_DETACH_ACCEPT; + msg_ptr++; + + // Fill in the number of bytes used + msg->N_bytes = msg_ptr - msg->msg; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_detach_accept_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_DETACH_ACCEPT_MSG_STRUCT *detach_accept) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + uint8 sec_hdr_type; + + if(msg != NULL && + detach_accept != NULL) + { + // Security Header Type + sec_hdr_type = (msg->msg[0] & 0xF0) >> 4; + if(LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS == sec_hdr_type) + { + msg_ptr++; + }else{ + msg_ptr += 7; + } + + // Skip Message Type + msg_ptr++; + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + Message Name: Detach Request + + Description: Sent by the UE to request the release of an EMM + context. + + Document Reference: 24.301 v10.2.0 Section 8.2.11 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_detach_request_msg(LIBLTE_MME_DETACH_REQUEST_MSG_STRUCT *detach_req, + 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(detach_req != 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++; + + // Message Type + *msg_ptr = LIBLTE_MME_MSG_TYPE_DETACH_REQUEST; + msg_ptr++; + + // Detach Type & NAS Key Set Identifier + *msg_ptr = 0; + liblte_mme_pack_detach_type_ie(&detach_req->detach_type, 0, &msg_ptr); + liblte_mme_pack_nas_key_set_id_ie(&detach_req->nas_ksi, 4, &msg_ptr); + msg_ptr++; + + // EPS Mobile ID + liblte_mme_pack_eps_mobile_id_ie(&detach_req->eps_mobile_id, &msg_ptr); + + // Fill in the number of bytes used + msg->N_bytes = msg_ptr - msg->msg; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_detach_request_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_DETACH_REQUEST_MSG_STRUCT *detach_req) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + uint8 sec_hdr_type; + + if(msg != NULL && + detach_req != NULL) + { + // Security Header Type + sec_hdr_type = (msg->msg[0] & 0xF0) >> 4; + if(LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS == sec_hdr_type) + { + msg_ptr++; + }else{ + msg_ptr += 7; + } + + // Skip Message Type + msg_ptr++; + + // Detach Type & NAS Key Set Identifier + liblte_mme_unpack_detach_type_ie(&msg_ptr, 0, &detach_req->detach_type); + liblte_mme_unpack_nas_key_set_id_ie(&msg_ptr, 4, &detach_req->nas_ksi); + msg_ptr++; + + // EPS Mobile ID + liblte_mme_unpack_eps_mobile_id_ie(&msg_ptr, &detach_req->eps_mobile_id); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + Message Name: Downlink NAS Transport + + Description: Sent by the network to the UE in order to carry an + SMS message in encapsulated format. + + Document Reference: 24.301 v10.2.0 Section 8.2.12 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_downlink_nas_transport_msg(LIBLTE_MME_DOWNLINK_NAS_TRANSPORT_MSG_STRUCT *dl_nas_transport, + 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(dl_nas_transport != 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++; + + // Message Type + *msg_ptr = LIBLTE_MME_MSG_TYPE_DOWNLINK_NAS_TRANSPORT; + msg_ptr++; + + // NAS Message Container + liblte_mme_pack_nas_message_container_ie(&dl_nas_transport->nas_msg, &msg_ptr); + + // Fill in the number of bytes used + msg->N_bytes = msg_ptr - msg->msg; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_downlink_nas_transport_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_DOWNLINK_NAS_TRANSPORT_MSG_STRUCT *dl_nas_transport) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + uint8 sec_hdr_type; + + if(msg != NULL && + dl_nas_transport != NULL) + { + // Security Header Type + sec_hdr_type = (msg->msg[0] & 0xF0) >> 4; + if(LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS == sec_hdr_type) + { + msg_ptr++; + }else{ + msg_ptr += 7; + } + + // Skip Message Type + msg_ptr++; + + // NAS Message Container + liblte_mme_unpack_nas_message_container_ie(&msg_ptr, &dl_nas_transport->nas_msg); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + Message Name: EMM Information + + Description: Sent by the network at any time during EMM context is + established to send certain information to the UE. + + Document Reference: 24.301 v10.2.0 Section 8.2.13 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_emm_information_msg(LIBLTE_MME_EMM_INFORMATION_MSG_STRUCT *emm_info, + 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(emm_info != 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++; + + // Message Type + *msg_ptr = LIBLTE_MME_MSG_TYPE_EMM_INFORMATION; + msg_ptr++; + + // Full Name For Network + if(emm_info->full_net_name_present) + { + *msg_ptr = LIBLTE_MME_FULL_NAME_FOR_NETWORK_IEI; + msg_ptr++; + liblte_mme_pack_network_name_ie(&emm_info->full_net_name, &msg_ptr); + } + + // Short Name For Network + if(emm_info->short_net_name_present) + { + *msg_ptr = LIBLTE_MME_SHORT_NAME_FOR_NETWORK_IEI; + msg_ptr++; + liblte_mme_pack_network_name_ie(&emm_info->short_net_name, &msg_ptr); + } + + // Local Time Zone + if(emm_info->local_time_zone_present) + { + *msg_ptr = LIBLTE_MME_LOCAL_TIME_ZONE_IEI; + msg_ptr++; + liblte_mme_pack_time_zone_ie(emm_info->local_time_zone, &msg_ptr); + } + + // Universal Time And Local Time Zone + if(emm_info->utc_and_local_time_zone_present) + { + *msg_ptr = LIBLTE_MME_UNIVERSAL_TIME_AND_LOCAL_TIME_ZONE_IEI; + msg_ptr++; + liblte_mme_pack_time_zone_and_time_ie(&emm_info->utc_and_local_time_zone, &msg_ptr); + } + + // Network Daylight Saving Time + if(emm_info->net_dst_present) + { + *msg_ptr = LIBLTE_MME_NETWORK_DAYLIGHT_SAVING_TIME_IEI; + msg_ptr++; + liblte_mme_pack_daylight_saving_time_ie(emm_info->net_dst, &msg_ptr); + } + + // Fill in the number of bytes used + msg->N_bytes = msg_ptr - msg->msg; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_emm_information_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_EMM_INFORMATION_MSG_STRUCT *emm_info) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + uint8 sec_hdr_type; + + if(msg != NULL && + emm_info != NULL) + { + // Security Header Type + sec_hdr_type = (msg->msg[0] & 0xF0) >> 4; + if(LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS == sec_hdr_type) + { + msg_ptr++; + }else{ + msg_ptr += 7; + } + + // Skip Message Type + msg_ptr++; + + // Full Name For Network + if(LIBLTE_MME_FULL_NAME_FOR_NETWORK_IEI == *msg_ptr) + { + msg_ptr++; + liblte_mme_unpack_network_name_ie(&msg_ptr, &emm_info->full_net_name); + emm_info->full_net_name_present = true; + }else{ + emm_info->full_net_name_present = false; + } + + // Short Name For Network + if(LIBLTE_MME_SHORT_NAME_FOR_NETWORK_IEI == *msg_ptr) + { + msg_ptr++; + liblte_mme_unpack_network_name_ie(&msg_ptr, &emm_info->short_net_name); + emm_info->short_net_name_present = true; + }else{ + emm_info->short_net_name_present = false; + } + + // Local Time Zone + if(LIBLTE_MME_LOCAL_TIME_ZONE_IEI == *msg_ptr) + { + msg_ptr++; + liblte_mme_unpack_time_zone_ie(&msg_ptr, &emm_info->local_time_zone); + emm_info->local_time_zone_present = true; + }else{ + emm_info->local_time_zone_present = false; + } + + // Universal Time And Local Time Zone + if(LIBLTE_MME_UNIVERSAL_TIME_AND_LOCAL_TIME_ZONE_IEI == *msg_ptr) + { + msg_ptr++; + liblte_mme_unpack_time_zone_and_time_ie(&msg_ptr, &emm_info->utc_and_local_time_zone); + emm_info->utc_and_local_time_zone_present = true; + }else{ + emm_info->utc_and_local_time_zone_present = false; + } + + // Network Daylight Saving Time + if(LIBLTE_MME_NETWORK_DAYLIGHT_SAVING_TIME_IEI == *msg_ptr) + { + msg_ptr++; + liblte_mme_unpack_daylight_saving_time_ie(&msg_ptr, &emm_info->net_dst); + emm_info->net_dst_present = true; + }else{ + emm_info->net_dst_present = false; + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + Message Name: EMM Status + + Description: Sent by the UE or by the network at any time to + report certain error conditions. + + Document Reference: 24.301 v10.2.0 Section 8.2.14 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_emm_status_msg(LIBLTE_MME_EMM_STATUS_MSG_STRUCT *emm_status, + 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(emm_status != 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++; + + // Message Type + *msg_ptr = LIBLTE_MME_MSG_TYPE_EMM_STATUS; + msg_ptr++; + + // EMM Cause + liblte_mme_pack_emm_cause_ie(emm_status->emm_cause, &msg_ptr); + + // Fill in the number of bytes used + msg->N_bytes = msg_ptr - msg->msg; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_emm_status_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_EMM_STATUS_MSG_STRUCT *emm_status) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + uint8 sec_hdr_type; + + if(msg != NULL && + emm_status != NULL) + { + // Security Header Type + sec_hdr_type = (msg->msg[0] & 0xF0) >> 4; + if(LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS == sec_hdr_type) + { + msg_ptr++; + }else{ + msg_ptr += 7; + } + + // Skip Message Type + msg_ptr++; + + // EMM Cause + liblte_mme_unpack_emm_cause_ie(&msg_ptr, &emm_status->emm_cause); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + Message Name: Extended Service Request + + Description: Sent by the UE to the network to initiate a CS + fallback or 1xCS fallback call or respond to a mobile + terminated CS fallback or 1xCS fallback request from + the network or to request the establishment of a NAS + signalling connection and of the radio and S1 bearers + for packet services, if the UE needs to provide + additional information that cannot be provided via a + SERVICE REQUEST message. + + Document Reference: 24.301 v10.2.0 Section 8.2.15 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_extended_service_request_msg(LIBLTE_MME_EXTENDED_SERVICE_REQUEST_MSG_STRUCT *ext_service_req, + 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(ext_service_req != 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++; + + // Message Type + *msg_ptr = LIBLTE_MME_MSG_TYPE_EXTENDED_SERVICE_REQUEST; + msg_ptr++; + + // Service Type & NAS Key Set Identifier + *msg_ptr = 0; + liblte_mme_pack_service_type_ie(ext_service_req->service_type, 0, &msg_ptr); + liblte_mme_pack_nas_key_set_id_ie(&ext_service_req->nas_ksi, 4, &msg_ptr); + msg_ptr++; + + // M-TMSI + liblte_mme_pack_mobile_id_ie(&ext_service_req->m_tmsi, &msg_ptr); + + // CSFB Response + if(ext_service_req->csfb_resp_present) + { + *msg_ptr = LIBLTE_MME_CSFB_RESPONSE_IEI << 4; + liblte_mme_pack_csfb_response_ie(ext_service_req->csfb_resp, 0, &msg_ptr); + msg_ptr++; + } + + // EPS Bearer Context Status + if(ext_service_req->eps_bearer_context_status_present) + { + *msg_ptr = LIBLTE_MME_EPS_BEARER_CONTEXT_STATUS_IEI; + msg_ptr++; + liblte_mme_pack_eps_bearer_context_status_ie(&ext_service_req->eps_bearer_context_status, &msg_ptr); + } + + // Device Properties + if(ext_service_req->device_props_present) + { + *msg_ptr = LIBLTE_MME_EXTENDED_SERVICE_REQUEST_DEVICE_PROPERTIES_IEI << 4; + liblte_mme_pack_device_properties_ie(ext_service_req->device_props, 0, &msg_ptr); + msg_ptr++; + } + + // Fill in the number of bytes used + msg->N_bytes = msg_ptr - msg->msg; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_extended_service_request_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_EXTENDED_SERVICE_REQUEST_MSG_STRUCT *ext_service_req) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + uint8 sec_hdr_type; + + if(msg != NULL && + ext_service_req != NULL) + { + // Security Header Type + sec_hdr_type = (msg->msg[0] & 0xF0) >> 4; + if(LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS == sec_hdr_type) + { + msg_ptr++; + }else{ + msg_ptr += 7; + } + + // Skip Message Type + msg_ptr++; + + // Service Type & NAS Key Set Identifier + liblte_mme_unpack_service_type_ie(&msg_ptr, 0, &ext_service_req->service_type); + liblte_mme_unpack_nas_key_set_id_ie(&msg_ptr, 4, &ext_service_req->nas_ksi); + msg_ptr++; + + // M-TMSI + liblte_mme_unpack_mobile_id_ie(&msg_ptr, &ext_service_req->m_tmsi); + + // CSFB Response + if((LIBLTE_MME_CSFB_RESPONSE_IEI << 4) == (*msg_ptr & 0xF0)) + { + liblte_mme_unpack_csfb_response_ie(&msg_ptr, 0, &ext_service_req->csfb_resp); + msg_ptr++; + ext_service_req->csfb_resp_present = true; + }else{ + ext_service_req->csfb_resp_present = false; + } + + // EPS Bearer Context Status + if(LIBLTE_MME_EPS_BEARER_CONTEXT_STATUS_IEI == *msg_ptr) + { + msg_ptr++; + liblte_mme_unpack_eps_bearer_context_status_ie(&msg_ptr, &ext_service_req->eps_bearer_context_status); + ext_service_req->eps_bearer_context_status_present = true; + }else{ + ext_service_req->eps_bearer_context_status_present = false; + } + + // Device Properties + if((LIBLTE_MME_EXTENDED_SERVICE_REQUEST_DEVICE_PROPERTIES_IEI << 4) == (*msg_ptr & 0xF0)) + { + liblte_mme_unpack_device_properties_ie(&msg_ptr, 0, &ext_service_req->device_props); + msg_ptr++; + ext_service_req->device_props_present = true; + }else{ + ext_service_req->device_props_present = false; + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + Message Name: GUTI Reallocation Command + + Description: Sent by the network to the UE to reallocate a GUTI + and optionally provide a new TAI list. + + Document Reference: 24.301 v10.2.0 Section 8.2.16 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_guti_reallocation_command_msg(LIBLTE_MME_GUTI_REALLOCATION_COMMAND_MSG_STRUCT *guti_realloc_cmd, + 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(guti_realloc_cmd != 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++; + + // Message Type + *msg_ptr = LIBLTE_MME_MSG_TYPE_GUTI_REALLOCATION_COMMAND; + msg_ptr++; + + // GUTI + liblte_mme_pack_eps_mobile_id_ie(&guti_realloc_cmd->guti, &msg_ptr); + + // TAI List + if(guti_realloc_cmd->tai_list_present) + { + *msg_ptr = LIBLTE_MME_TAI_LIST_IEI; + msg_ptr++; + liblte_mme_pack_tracking_area_identity_list_ie(&guti_realloc_cmd->tai_list, &msg_ptr); + } + + // Fill in the number of bytes used + msg->N_bytes = msg_ptr - msg->msg; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_guti_reallocation_command_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_GUTI_REALLOCATION_COMMAND_MSG_STRUCT *guti_realloc_cmd) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + uint8 sec_hdr_type; + + if(msg != NULL && + guti_realloc_cmd != NULL) + { + // Security Header Type + sec_hdr_type = (msg->msg[0] & 0xF0) >> 4; + if(LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS == sec_hdr_type) + { + msg_ptr++; + }else{ + msg_ptr += 7; + } + + // Skip Message Type + msg_ptr++; + + // GUTI + liblte_mme_unpack_eps_mobile_id_ie(&msg_ptr, &guti_realloc_cmd->guti); + + // TAI List + if(LIBLTE_MME_TAI_LIST_IEI == *msg_ptr) + { + msg_ptr++; + liblte_mme_unpack_tracking_area_identity_list_ie(&msg_ptr, &guti_realloc_cmd->tai_list); + guti_realloc_cmd->tai_list_present = true; + }else{ + guti_realloc_cmd->tai_list_present = false; + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + Message Name: GUTI Reallocation Complete + + Description: Sent by the UE to the network to indicate that + reallocation of a GUTI has taken place. + + Document Reference: 24.301 v10.2.0 Section 8.2.17 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_guti_reallocation_complete_msg(LIBLTE_MME_GUTI_REALLOCATION_COMPLETE_MSG_STRUCT *guti_realloc_complete, + 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(guti_realloc_complete != 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++; + + // Message Type + *msg_ptr = LIBLTE_MME_MSG_TYPE_GUTI_REALLOCATION_COMPLETE; + msg_ptr++; + + // Fill in the number of bytes used + msg->N_bytes = msg_ptr - msg->msg; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_guti_reallocation_complete_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_GUTI_REALLOCATION_COMPLETE_MSG_STRUCT *guti_realloc_complete) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + uint8 sec_hdr_type; + + if(msg != NULL && + guti_realloc_complete != NULL) + { + // Security Header Type + sec_hdr_type = (msg->msg[0] & 0xF0) >> 4; + if(LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS == sec_hdr_type) + { + msg_ptr++; + }else{ + msg_ptr += 7; + } + + // Skip Message Type + msg_ptr++; + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + Message Name: Identity Request + + Description: Sent by the network to the UE to request the UE to + provide the specified identity. + + Document Reference: 24.301 v10.2.0 Section 8.2.18 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_identity_request_msg(LIBLTE_MME_ID_REQUEST_MSG_STRUCT *id_req, + LIBLTE_BYTE_MSG_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(id_req != NULL && + msg != NULL) + { + // Protocol Discriminator and Security Header Type + *msg_ptr = (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT); + msg_ptr++; + + // Message Type + *msg_ptr = LIBLTE_MME_MSG_TYPE_IDENTITY_REQUEST; + msg_ptr++; + + // ID Type & Spare Half Octet + *msg_ptr = 0; + liblte_mme_pack_identity_type_2_ie(id_req->id_type, 0, &msg_ptr); + msg_ptr++; + + // Fill in the number of bytes used + msg->N_bytes = msg_ptr - msg->msg; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_identity_request_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_ID_REQUEST_MSG_STRUCT *id_req) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + uint8 sec_hdr_type; + + if(msg != NULL && + id_req != NULL) + { + // Security Header Type + sec_hdr_type = (msg->msg[0] & 0xF0) >> 4; + if(LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS == sec_hdr_type) + { + msg_ptr++; + }else{ + msg_ptr += 7; + } + + // Skip Message Type + msg_ptr++; + + // ID Type & Spare Half Offset + liblte_mme_unpack_identity_type_2_ie(&msg_ptr, 0, &id_req->id_type); + msg_ptr++; + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + Message Name: Identity Response + + Description: Sent by the UE to the network in response to an + IDENTITY REQUEST message and provides the requested + identity. + + 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, + LIBLTE_BYTE_MSG_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(id_resp != NULL && + msg != NULL) + { + // Protocol Discriminator and Security Header Type + *msg_ptr = (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT); + msg_ptr++; + + // Message Type + *msg_ptr = LIBLTE_MME_MSG_TYPE_IDENTITY_RESPONSE; + msg_ptr++; + + // Mobile Identity + liblte_mme_pack_mobile_id_ie(&id_resp->mobile_id, &msg_ptr); + + // Fill in the number of bytes used + msg->N_bytes = msg_ptr - msg->msg; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_identity_response_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_ID_RESPONSE_MSG_STRUCT *id_resp) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + uint8 sec_hdr_type; + + if(msg != NULL && + id_resp != NULL) + { + // Security Header Type + sec_hdr_type = (msg->msg[0] & 0xF0) >> 4; + if(LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS == sec_hdr_type) + { + msg_ptr++; + }else{ + msg_ptr += 7; + } + + // Skip Message Type + msg_ptr++; + + // Mobile Identity + liblte_mme_unpack_mobile_id_ie(&msg_ptr, &id_resp->mobile_id); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + Message Name: Security Mode Command + + Description: Sent by the network to the UE to establish NAS + signalling security. + + Document Reference: 24.301 v10.2.0 Section 8.2.20 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_security_mode_command_msg(LIBLTE_MME_SECURITY_MODE_COMMAND_MSG_STRUCT *sec_mode_cmd, + 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(sec_mode_cmd != 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++; + + // Message Type + *msg_ptr = LIBLTE_MME_MSG_TYPE_SECURITY_MODE_COMMAND; + msg_ptr++; + + // Selected NAS Security Algorithms + liblte_mme_pack_nas_security_algorithms_ie(&sec_mode_cmd->selected_nas_sec_algs, &msg_ptr); + + // NAS Key Set Identifier & Spare Half Octet + *msg_ptr = 0; + liblte_mme_pack_nas_key_set_id_ie(&sec_mode_cmd->nas_ksi, 0, &msg_ptr); + msg_ptr++; + + // Replayed UE Security Capabilities + liblte_mme_pack_ue_security_capabilities_ie(&sec_mode_cmd->ue_security_cap, &msg_ptr); + + // IMEISV Request + if(sec_mode_cmd->imeisv_req_present) + { + *msg_ptr = LIBLTE_MME_IMEISV_REQUEST_IEI << 4; + liblte_mme_pack_imeisv_request_ie(sec_mode_cmd->imeisv_req, 0, &msg_ptr); + msg_ptr++; + } + + // Replayed NONCE_ue + if(sec_mode_cmd->nonce_ue_present) + { + *msg_ptr = LIBLTE_MME_REPLAYED_NONCE_UE_IEI; + msg_ptr++; + liblte_mme_pack_nonce_ie(sec_mode_cmd->nonce_ue, &msg_ptr); + } + + // NONCE_mme + if(sec_mode_cmd->nonce_mme_present) + { + *msg_ptr = LIBLTE_MME_NONCE_MME_IEI; + msg_ptr++; + liblte_mme_pack_nonce_ie(sec_mode_cmd->nonce_mme, &msg_ptr); + } + + // Fill in the number of bytes used + msg->N_bytes = msg_ptr - msg->msg; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_security_mode_command_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_SECURITY_MODE_COMMAND_MSG_STRUCT *sec_mode_cmd) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + uint8 sec_hdr_type; + + if(msg != NULL && + sec_mode_cmd != NULL) + { + // Security Header Type + sec_hdr_type = (msg->msg[0] & 0xF0) >> 4; + if(LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS == sec_hdr_type) + { + msg_ptr++; + }else{ + msg_ptr += 7; + } + + // Skip Message Type + msg_ptr++; + + // Selected NAS Security Algorithms + liblte_mme_unpack_nas_security_algorithms_ie(&msg_ptr, &sec_mode_cmd->selected_nas_sec_algs); + + // NAS Key Set Identifier & Spare Half Octet + liblte_mme_unpack_nas_key_set_id_ie(&msg_ptr, 0, &sec_mode_cmd->nas_ksi); + msg_ptr++; + + // Replayed UE Security Capabilities + liblte_mme_unpack_ue_security_capabilities_ie(&msg_ptr, &sec_mode_cmd->ue_security_cap); + + // IMEISV Request + if((LIBLTE_MME_IMEISV_REQUEST_IEI << 4) == (*msg_ptr & 0xF0)) + { + liblte_mme_unpack_imeisv_request_ie(&msg_ptr, 0, &sec_mode_cmd->imeisv_req); + msg_ptr++; + sec_mode_cmd->imeisv_req_present = true; + }else{ + sec_mode_cmd->imeisv_req_present = false; + } + + // Replayed NONCE_ue + if(LIBLTE_MME_REPLAYED_NONCE_UE_IEI == *msg_ptr) + { + msg_ptr++; + liblte_mme_unpack_nonce_ie(&msg_ptr, &sec_mode_cmd->nonce_ue); + sec_mode_cmd->nonce_ue_present = true; + }else{ + sec_mode_cmd->nonce_ue_present = false; + } + + // NONCE_mme + if(LIBLTE_MME_NONCE_MME_IEI == *msg_ptr) + { + msg_ptr++; + liblte_mme_unpack_nonce_ie(&msg_ptr, &sec_mode_cmd->nonce_mme); + sec_mode_cmd->nonce_mme_present = true; + }else{ + sec_mode_cmd->nonce_mme_present = false; + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + Message Name: Security Mode Complete + + Description: Sent by the UE to the network in response to a + SECURITY MODE COMMAND message. + + Document Reference: 24.301 v10.2.0 Section 8.2.21 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_security_mode_complete_msg(LIBLTE_MME_SECURITY_MODE_COMPLETE_MSG_STRUCT *sec_mode_comp, + 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(sec_mode_comp != 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++; + + // Message Type + *msg_ptr = LIBLTE_MME_MSG_TYPE_SECURITY_MODE_COMPLETE; + msg_ptr++; + + // IMEISV + if(sec_mode_comp->imeisv_present) + { + *msg_ptr = LIBLTE_MME_IMEISV_IEI; + msg_ptr++; + liblte_mme_pack_mobile_id_ie(&sec_mode_comp->imeisv, &msg_ptr); + } + + // Fill in the number of bytes used + msg->N_bytes = msg_ptr - msg->msg; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_security_mode_complete_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_SECURITY_MODE_COMPLETE_MSG_STRUCT *sec_mode_comp) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + uint8 sec_hdr_type; + + if(msg != NULL && + sec_mode_comp != NULL) + { + // Security Header Type + sec_hdr_type = (msg->msg[0] & 0xF0) >> 4; + if(LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS == sec_hdr_type) + { + msg_ptr++; + }else{ + msg_ptr += 7; + } + + // Skip Message Type + msg_ptr++; + + // IMEISV + if(LIBLTE_MME_IMEISV_IEI == *msg_ptr) + { + msg_ptr++; + liblte_mme_unpack_mobile_id_ie(&msg_ptr, &sec_mode_comp->imeisv); + sec_mode_comp->imeisv_present = true; + }else{ + sec_mode_comp->imeisv_present = false; + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + Message Name: Security Mode Reject + + Description: Sent by the UE to the network to indicate that the + corresponding security mode command has been + rejected. + + Document Reference: 24.301 v10.2.0 Section 8.2.22 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_security_mode_reject_msg(LIBLTE_MME_SECURITY_MODE_REJECT_MSG_STRUCT *sec_mode_rej, + LIBLTE_BYTE_MSG_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(sec_mode_rej != NULL && + msg != NULL) + { + // Protocol Discriminator and Security Header Type + *msg_ptr = (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT); + msg_ptr++; + + // Message Type + *msg_ptr = LIBLTE_MME_MSG_TYPE_SECURITY_MODE_REJECT; + msg_ptr++; + + // EMM Cause + liblte_mme_pack_emm_cause_ie(sec_mode_rej->emm_cause, &msg_ptr); + + // Fill in the number of bytes used + msg->N_bytes = msg_ptr - msg->msg; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_security_mode_reject_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_SECURITY_MODE_REJECT_MSG_STRUCT *sec_mode_rej) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + uint8 sec_hdr_type; + + if(msg != NULL && + sec_mode_rej != NULL) + { + // Security Header Type + sec_hdr_type = (msg->msg[0] & 0xF0) >> 4; + if(LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS == sec_hdr_type) + { + msg_ptr++; + }else{ + msg_ptr += 7; + } + + // Skip Message Type + msg_ptr++; + + // EMM Cause + liblte_mme_unpack_emm_cause_ie(&msg_ptr, &sec_mode_rej->emm_cause); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + Message Name: Service Reject + + Description: Sent by the network to the UE in order to reject the + service request procedure. + + Document Reference: 24.301 v10.2.0 Section 8.2.24 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_service_reject_msg(LIBLTE_MME_SERVICE_REJECT_MSG_STRUCT *service_rej, + 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(service_rej != 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++; + + // Message Type + *msg_ptr = LIBLTE_MME_MSG_TYPE_SERVICE_REJECT; + msg_ptr++; + + // EMM Cause + liblte_mme_pack_emm_cause_ie(service_rej->emm_cause, &msg_ptr); + + // T3442 Value + if(service_rej->t3442_present) + { + *msg_ptr = LIBLTE_MME_T3442_VALUE_IEI; + msg_ptr++; + liblte_mme_pack_gprs_timer_ie(&service_rej->t3442, &msg_ptr); + } + + // T3446 Value + if(service_rej->t3446_present) + { + *msg_ptr = LIBLTE_MME_T3446_VALUE_IEI; + msg_ptr++; + liblte_mme_pack_gprs_timer_2_ie(service_rej->t3446, &msg_ptr); + } + + // Fill in the number of bytes used + msg->N_bytes = msg_ptr - msg->msg; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_service_reject_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_SERVICE_REJECT_MSG_STRUCT *service_rej) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + uint8 sec_hdr_type; + + if(msg != NULL && + service_rej != NULL) + { + // Security Header Type + sec_hdr_type = (msg->msg[0] & 0xF0) >> 4; + if(LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS == sec_hdr_type) + { + msg_ptr++; + }else{ + msg_ptr += 7; + } + + // Skip Message Type + msg_ptr++; + + // EMM Cause + liblte_mme_unpack_emm_cause_ie(&msg_ptr, &service_rej->emm_cause); + + // T3442 Value + if(LIBLTE_MME_T3442_VALUE_IEI == *msg_ptr) + { + msg_ptr++; + liblte_mme_unpack_gprs_timer_ie(&msg_ptr, &service_rej->t3442); + service_rej->t3442_present = true; + }else{ + service_rej->t3442_present = false; + } + + // T3446 Value + if(LIBLTE_MME_T3446_VALUE_IEI == *msg_ptr) + { + msg_ptr++; + liblte_mme_unpack_gprs_timer_2_ie(&msg_ptr, &service_rej->t3446); + service_rej->t3446_present = true; + }else{ + service_rej->t3446_present = false; + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + Message Name: Service Request + + Description: Sent by the UE to the network to request the + establishment of a NAS signalling connection and of + the radio and S1 bearers. + + Document Reference: 24.301 v10.2.0 Section 8.2.25 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_service_request_msg(LIBLTE_MME_SERVICE_REQUEST_MSG_STRUCT *service_req, + LIBLTE_BYTE_MSG_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(service_req != NULL && + msg != NULL) + { + // Protocol Discriminator and Security Header Type + *msg_ptr = (LIBLTE_MME_SECURITY_HDR_TYPE_SERVICE_REQUEST << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT); + msg_ptr++; + + // KSI and Sequence Number + liblte_mme_pack_ksi_and_sequence_number_ie(&service_req->ksi_and_seq_num, &msg_ptr); + + // Short MAC + liblte_mme_pack_short_mac_ie(service_req->short_mac, &msg_ptr); + + // Fill in the number of bytes used + msg->N_bytes = msg_ptr - msg->msg; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_service_request_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_SERVICE_REQUEST_MSG_STRUCT *service_req) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(msg != NULL && + service_req != NULL) + { + // Protocol Discriminator and Security Header Type + msg_ptr++; + + // KSI and Sequence Number + liblte_mme_unpack_ksi_and_sequence_number_ie(&msg_ptr, &service_req->ksi_and_seq_num); + + // Short MAC + liblte_mme_unpack_short_mac_ie(&msg_ptr, &service_req->short_mac); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + Message Name: Tracking Area Update Accept + + Description: Sent by the network to the UE to provide the UE with + EPS mobility management related data in response to + a tracking area update request message. + + Document Reference: 24.301 v10.2.0 Section 8.2.26 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_tracking_area_update_accept_msg(LIBLTE_MME_TRACKING_AREA_UPDATE_ACCEPT_MSG_STRUCT *ta_update_accept, + 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(ta_update_accept != 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++; + + // Message Type + *msg_ptr = LIBLTE_MME_MSG_TYPE_TRACKING_AREA_UPDATE_ACCEPT; + msg_ptr++; + + // EPS Update Result & Spare Half Octet + *msg_ptr = 0; + liblte_mme_pack_eps_update_result_ie(ta_update_accept->eps_update_result, 0, &msg_ptr); + msg_ptr++; + + // T3412 Value + if(ta_update_accept->t3412_present) + { + *msg_ptr = LIBLTE_MME_T3412_VALUE_IEI; + msg_ptr++; + liblte_mme_pack_gprs_timer_ie(&ta_update_accept->t3412, &msg_ptr); + } + + // GUTI + if(ta_update_accept->guti_present) + { + *msg_ptr = LIBLTE_MME_GUTI_IEI; + msg_ptr++; + liblte_mme_pack_eps_mobile_id_ie(&ta_update_accept->guti, &msg_ptr); + } + + // TAI List + if(ta_update_accept->tai_list_present) + { + *msg_ptr = LIBLTE_MME_TAI_LIST_IEI; + msg_ptr++; + liblte_mme_pack_tracking_area_identity_list_ie(&ta_update_accept->tai_list, &msg_ptr); + } + + // EPS Bearer Context Status + if(ta_update_accept->eps_bearer_context_status_present) + { + *msg_ptr = LIBLTE_MME_EPS_BEARER_CONTEXT_STATUS_IEI; + msg_ptr++; + liblte_mme_pack_eps_bearer_context_status_ie(&ta_update_accept->eps_bearer_context_status, &msg_ptr); + } + + // Location Area Identification + if(ta_update_accept->lai_present) + { + *msg_ptr = LIBLTE_MME_LOCATION_AREA_IDENTIFICATION_IEI; + msg_ptr++; + liblte_mme_pack_location_area_id_ie(&ta_update_accept->lai, &msg_ptr); + } + + // MS Identity + if(ta_update_accept->ms_id_present) + { + *msg_ptr = LIBLTE_MME_MS_IDENTITY_IEI; + msg_ptr++; + liblte_mme_pack_mobile_id_ie(&ta_update_accept->ms_id, &msg_ptr); + } + + // EMM Cause + if(ta_update_accept->emm_cause_present) + { + *msg_ptr = LIBLTE_MME_EMM_CAUSE_IEI; + msg_ptr++; + liblte_mme_pack_emm_cause_ie(ta_update_accept->emm_cause, &msg_ptr); + } + + // T3402 Value + if(ta_update_accept->t3402_present) + { + *msg_ptr = LIBLTE_MME_T3402_VALUE_IEI; + msg_ptr++; + liblte_mme_pack_gprs_timer_ie(&ta_update_accept->t3402, &msg_ptr); + } + + // T3423 Value + if(ta_update_accept->t3423_present) + { + *msg_ptr = LIBLTE_MME_T3423_VALUE_IEI; + msg_ptr++; + liblte_mme_pack_gprs_timer_ie(&ta_update_accept->t3423, &msg_ptr); + } + + // Equivalent PLMNs + if(ta_update_accept->equivalent_plmns_present) + { + *msg_ptr = LIBLTE_MME_EQUIVALENT_PLMNS_IEI; + msg_ptr++; + liblte_mme_pack_plmn_list_ie(&ta_update_accept->equivalent_plmns, &msg_ptr); + } + + // Emergency Number List + if(ta_update_accept->emerg_num_list_present) + { + *msg_ptr = LIBLTE_MME_EMERGENCY_NUMBER_LIST_IEI; + msg_ptr++; + liblte_mme_pack_emergency_number_list_ie(&ta_update_accept->emerg_num_list, &msg_ptr); + } + + // EPS Network Feature Support + if(ta_update_accept->eps_network_feature_support_present) + { + *msg_ptr = LIBLTE_MME_EPS_NETWORK_FEATURE_SUPPORT_IEI; + msg_ptr++; + liblte_mme_pack_eps_network_feature_support_ie(&ta_update_accept->eps_network_feature_support, &msg_ptr); + } + + // Additional Update Result + if(ta_update_accept->additional_update_result_present) + { + *msg_ptr = LIBLTE_MME_ADDITIONAL_UPDATE_RESULT_IEI << 4; + liblte_mme_pack_additional_update_result_ie(ta_update_accept->additional_update_result, 0, &msg_ptr); + msg_ptr++; + } + + // T3412 Extended Value + if(ta_update_accept->t3412_ext_present) + { + *msg_ptr = LIBLTE_MME_T3412_EXTENDED_VALUE_IEI; + msg_ptr++; + liblte_mme_pack_gprs_timer_3_ie(&ta_update_accept->t3412_ext, &msg_ptr); + } + + // Fill in the number of bytes used + msg->N_bytes = msg_ptr - msg->msg; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_tracking_area_update_accept_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_TRACKING_AREA_UPDATE_ACCEPT_MSG_STRUCT *ta_update_accept) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + uint8 sec_hdr_type; + + if(msg != NULL && + ta_update_accept != NULL) + { + // Security Header Type + sec_hdr_type = (msg->msg[0] & 0xF0) >> 4; + if(LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS == sec_hdr_type) + { + msg_ptr++; + }else{ + msg_ptr += 7; + } + + // Skip Message Type + msg_ptr++; + + // EPS Update Result & Spare Half Octet + liblte_mme_unpack_eps_update_result_ie(&msg_ptr, 0, &ta_update_accept->eps_update_result); + msg_ptr++; + + // T3412 Value + if(LIBLTE_MME_T3412_VALUE_IEI == *msg_ptr) + { + msg_ptr++; + liblte_mme_unpack_gprs_timer_ie(&msg_ptr, &ta_update_accept->t3412); + ta_update_accept->t3412_present = true; + }else{ + ta_update_accept->t3412_present = false; + } + + // GUTI + if(LIBLTE_MME_GUTI_IEI == *msg_ptr) + { + msg_ptr++; + liblte_mme_unpack_eps_mobile_id_ie(&msg_ptr, &ta_update_accept->guti); + ta_update_accept->guti_present = true; + }else{ + ta_update_accept->guti_present = false; + } + + // TAI List + if(LIBLTE_MME_TAI_LIST_IEI == *msg_ptr) + { + msg_ptr++; + liblte_mme_unpack_tracking_area_identity_list_ie(&msg_ptr, &ta_update_accept->tai_list); + ta_update_accept->tai_list_present = true; + }else{ + ta_update_accept->tai_list_present = false; + } + + // EPS Bearer Context Status + if(LIBLTE_MME_EPS_BEARER_CONTEXT_STATUS_IEI == *msg_ptr) + { + msg_ptr++; + liblte_mme_unpack_eps_bearer_context_status_ie(&msg_ptr, &ta_update_accept->eps_bearer_context_status); + ta_update_accept->eps_bearer_context_status_present = true; + }else{ + ta_update_accept->eps_bearer_context_status_present = false; + } + + // Location Area Identification + if(LIBLTE_MME_LOCATION_AREA_IDENTIFICATION_IEI == *msg_ptr) + { + msg_ptr++; + liblte_mme_unpack_location_area_id_ie(&msg_ptr, &ta_update_accept->lai); + ta_update_accept->lai_present = true; + }else{ + ta_update_accept->lai_present = false; + } + + // MS Identity + if(LIBLTE_MME_MS_IDENTITY_IEI == *msg_ptr) + { + msg_ptr++; + liblte_mme_unpack_mobile_id_ie(&msg_ptr, &ta_update_accept->ms_id); + ta_update_accept->ms_id_present = true; + }else{ + ta_update_accept->ms_id_present = false; + } + + // EMM Cause + if(LIBLTE_MME_EMM_CAUSE_IEI == *msg_ptr) + { + msg_ptr++; + liblte_mme_unpack_emm_cause_ie(&msg_ptr, &ta_update_accept->emm_cause); + ta_update_accept->emm_cause_present = true; + }else{ + ta_update_accept->emm_cause_present = false; + } + + // T3402 Value + if(LIBLTE_MME_T3402_VALUE_IEI == *msg_ptr) + { + msg_ptr++; + liblte_mme_unpack_gprs_timer_ie(&msg_ptr, &ta_update_accept->t3402); + ta_update_accept->t3402_present = true; + }else{ + ta_update_accept->t3402_present = false; + } + + // T3423 Value + if(LIBLTE_MME_T3423_VALUE_IEI == *msg_ptr) + { + msg_ptr++; + liblte_mme_unpack_gprs_timer_ie(&msg_ptr, &ta_update_accept->t3423); + ta_update_accept->t3423_present = true; + }else{ + ta_update_accept->t3423_present = false; + } + + // Equivalent PLMNs + if(LIBLTE_MME_EQUIVALENT_PLMNS_IEI == *msg_ptr) + { + msg_ptr++; + liblte_mme_unpack_plmn_list_ie(&msg_ptr, &ta_update_accept->equivalent_plmns); + ta_update_accept->equivalent_plmns_present = true; + }else{ + ta_update_accept->equivalent_plmns_present = false; + } + + // Emergency Number List + if(LIBLTE_MME_EMERGENCY_NUMBER_LIST_IEI == *msg_ptr) + { + msg_ptr++; + liblte_mme_unpack_emergency_number_list_ie(&msg_ptr, &ta_update_accept->emerg_num_list); + ta_update_accept->emerg_num_list_present = true; + }else{ + ta_update_accept->emerg_num_list_present = false; + } + + // EPS Network Feature Support + if(LIBLTE_MME_EPS_NETWORK_FEATURE_SUPPORT_IEI == *msg_ptr) + { + msg_ptr++; + liblte_mme_unpack_eps_network_feature_support_ie(&msg_ptr, &ta_update_accept->eps_network_feature_support); + ta_update_accept->eps_network_feature_support_present = true; + }else{ + ta_update_accept->eps_network_feature_support_present = false; + } + + // Additional Update Result + if((LIBLTE_MME_ADDITIONAL_UPDATE_RESULT_IEI << 4) == (*msg_ptr & 0xF0)) + { + liblte_mme_unpack_additional_update_result_ie(&msg_ptr, 0, &ta_update_accept->additional_update_result); + msg_ptr++; + ta_update_accept->additional_update_result_present = true; + }else{ + ta_update_accept->additional_update_result_present = false; + } + + // T3412 Extended Value + if(LIBLTE_MME_T3412_EXTENDED_VALUE_IEI == *msg_ptr) + { + msg_ptr++; + liblte_mme_unpack_gprs_timer_3_ie(&msg_ptr, &ta_update_accept->t3412_ext); + ta_update_accept->t3412_ext_present = true; + }else{ + ta_update_accept->t3412_ext_present = false; + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + Message Name: Tracking Area Update Complete + + Description: Sent by the UE to the network in response to a + tracking area update accept message if a GUTI has + been changed or a new TMSI has been assigned. + + Document Reference: 24.301 v10.2.0 Section 8.2.27 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_tracking_area_update_complete_msg(LIBLTE_MME_TRACKING_AREA_UPDATE_COMPLETE_MSG_STRUCT *ta_update_complete, + 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(ta_update_complete != 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++; + + // Message Type + *msg_ptr = LIBLTE_MME_MSG_TYPE_TRACKING_AREA_UPDATE_COMPLETE; + msg_ptr++; + + // Fill in the number of bytes used + msg->N_bytes = msg_ptr - msg->msg; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_tracking_area_update_complete_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_TRACKING_AREA_UPDATE_COMPLETE_MSG_STRUCT *ta_update_complete) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + uint8 sec_hdr_type; + + if(msg != NULL && + ta_update_complete != NULL) + { + // Security Header Type + sec_hdr_type = (msg->msg[0] & 0xF0) >> 4; + if(LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS == sec_hdr_type) + { + msg_ptr++; + }else{ + msg_ptr += 7; + } + + // Skip Message Type + msg_ptr++; + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + Message Name: Tracking Area Update Reject + + Description: Sent by the network to the UE in order to reject the + tracking area updating procedure. + + Document Reference: 24.301 v10.2.0 Section 8.2.28 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_tracking_area_update_reject_msg(LIBLTE_MME_TRACKING_AREA_UPDATE_REJECT_MSG_STRUCT *ta_update_rej, + 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(ta_update_rej != 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++; + + // Message Type + *msg_ptr = LIBLTE_MME_MSG_TYPE_TRACKING_AREA_UPDATE_REJECT; + msg_ptr++; + + // EMM Cause + liblte_mme_pack_emm_cause_ie(ta_update_rej->emm_cause, &msg_ptr); + + // T3446 Value + if(ta_update_rej->t3446_present) + { + *msg_ptr = LIBLTE_MME_T3446_VALUE_IEI; + msg_ptr++; + liblte_mme_pack_gprs_timer_2_ie(ta_update_rej->t3446, &msg_ptr); + } + + // Fill in the number of bytes used + msg->N_bytes = msg_ptr - msg->msg; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_tracking_area_update_reject_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_TRACKING_AREA_UPDATE_REJECT_MSG_STRUCT *ta_update_rej) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + uint8 sec_hdr_type; + + if(msg != NULL && + ta_update_rej != NULL) + { + // Security Header Type + sec_hdr_type = (msg->msg[0] & 0xF0) >> 4; + if(LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS == sec_hdr_type) + { + msg_ptr++; + }else{ + msg_ptr += 7; + } + + // Skip Message Type + msg_ptr++; + + // EMM Cause + liblte_mme_unpack_emm_cause_ie(&msg_ptr, &ta_update_rej->emm_cause); + + // T3446 Value + if(LIBLTE_MME_T3446_VALUE_IEI == *msg_ptr) + { + msg_ptr++; + liblte_mme_unpack_gprs_timer_2_ie(&msg_ptr, &ta_update_rej->t3446); + ta_update_rej->t3446_present = true; + }else{ + ta_update_rej->t3446_present = false; + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + Message Name: Tracking Area Update Request + + Description: Sent by the UE to the network to initiate a tracking + area updating procedure. + + Document Reference: 24.301 v10.2.0 Section 8.2.29 +*********************************************************************/ +// FIXME + +/********************************************************************* + Message Name: Uplink NAS Transport + + Description: Sent by the UE to the network in order to carry an + SMS message in encapsulated format. + + Document Reference: 24.301 v10.2.0 Section 8.2.30 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_uplink_nas_transport_msg(LIBLTE_MME_UPLINK_NAS_TRANSPORT_MSG_STRUCT *ul_nas_transport, + 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(ul_nas_transport != 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++; + + // Message Type + *msg_ptr = LIBLTE_MME_MSG_TYPE_UPLINK_NAS_TRANSPORT; + msg_ptr++; + + // NAS Message Container + liblte_mme_pack_nas_message_container_ie(&ul_nas_transport->nas_msg, &msg_ptr); + + // Fill in the number of bytes used + msg->N_bytes = msg_ptr - msg->msg; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_uplink_nas_transport_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_UPLINK_NAS_TRANSPORT_MSG_STRUCT *ul_nas_transport) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + uint8 sec_hdr_type; + + if(msg != NULL && + ul_nas_transport != NULL) + { + // Security Header Type + sec_hdr_type = (msg->msg[0] & 0xF0) >> 4; + if(LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS == sec_hdr_type) + { + msg_ptr++; + }else{ + msg_ptr += 7; + } + + // Skip Message Type + msg_ptr++; + + // NAS Message Container + liblte_mme_unpack_nas_message_container_ie(&msg_ptr, &ul_nas_transport->nas_msg); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + Message Name: Downlink Generic NAS Transport + + Description: Sent by the network to the UE in order to carry an + application message in encapsulated format. + + Document Reference: 24.301 v10.2.0 Section 8.2.31 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_downlink_generic_nas_transport_msg(LIBLTE_MME_DOWNLINK_GENERIC_NAS_TRANSPORT_MSG_STRUCT *dl_generic_nas_transport, + 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(dl_generic_nas_transport != 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++; + + // Message Type + *msg_ptr = LIBLTE_MME_MSG_TYPE_DOWNLINK_GENERIC_NAS_TRANSPORT; + msg_ptr++; + + // Generic Message Container Type + liblte_mme_pack_generic_message_container_type_ie(dl_generic_nas_transport->generic_msg_cont_type, &msg_ptr); + + // Generic Message Container + liblte_mme_pack_generic_message_container_ie(&dl_generic_nas_transport->generic_msg_cont, &msg_ptr); + + // Additional Information + liblte_mme_pack_additional_information_ie(&dl_generic_nas_transport->add_info, &msg_ptr); + + // Fill in the number of bytes used + msg->N_bytes = msg_ptr - msg->msg; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_downlink_generic_nas_transport_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_DOWNLINK_GENERIC_NAS_TRANSPORT_MSG_STRUCT *dl_generic_nas_transport) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + uint8 sec_hdr_type; + + if(msg != NULL && + dl_generic_nas_transport != NULL) + { + // Security Header Type + sec_hdr_type = (msg->msg[0] & 0xF0) >> 4; + if(LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS == sec_hdr_type) + { + msg_ptr++; + }else{ + msg_ptr += 7; + } + + // Skip Message Type + msg_ptr++; + + // Generic Message Container Type + liblte_mme_unpack_generic_message_container_type_ie(&msg_ptr, &dl_generic_nas_transport->generic_msg_cont_type); + + // Generic Message Container + liblte_mme_unpack_generic_message_container_ie(&msg_ptr, &dl_generic_nas_transport->generic_msg_cont); + + // Additional Information + liblte_mme_unpack_additional_information_ie(&msg_ptr, &dl_generic_nas_transport->add_info); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + Message Name: Uplink Generic NAS Transport + + Description: Sent by the UE to the network in order to carry an + application protocol message in encapsulated format. + + Document Reference: 24.301 v10.2.0 Section 8.2.32 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_uplink_generic_nas_transport_msg(LIBLTE_MME_UPLINK_GENERIC_NAS_TRANSPORT_MSG_STRUCT *ul_generic_nas_transport, + 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(ul_generic_nas_transport != 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++; + + // Message Type + *msg_ptr = LIBLTE_MME_MSG_TYPE_UPLINK_GENERIC_NAS_TRANSPORT; + msg_ptr++; + + // Generic Message Container Type + liblte_mme_pack_generic_message_container_type_ie(ul_generic_nas_transport->generic_msg_cont_type, &msg_ptr); + + // Generic Message Container + liblte_mme_pack_generic_message_container_ie(&ul_generic_nas_transport->generic_msg_cont, &msg_ptr); + + // Additional Information + liblte_mme_pack_additional_information_ie(&ul_generic_nas_transport->add_info, &msg_ptr); + + // Fill in the number of bytes used + msg->N_bytes = msg_ptr - msg->msg; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_uplink_generic_nas_transport_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_UPLINK_GENERIC_NAS_TRANSPORT_MSG_STRUCT *ul_generic_nas_transport) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + uint8 sec_hdr_type; + + if(msg != NULL && + ul_generic_nas_transport != NULL) + { + // Security Header Type + sec_hdr_type = (msg->msg[0] & 0xF0) >> 4; + if(LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS == sec_hdr_type) + { + msg_ptr++; + }else{ + msg_ptr += 7; + } + + // Skip Message Type + msg_ptr++; + + // Generic Message Container Type + liblte_mme_unpack_generic_message_container_type_ie(&msg_ptr, &ul_generic_nas_transport->generic_msg_cont_type); + + // Generic Message Container + liblte_mme_unpack_generic_message_container_ie(&msg_ptr, &ul_generic_nas_transport->generic_msg_cont); + + // Additional Information + liblte_mme_unpack_additional_information_ie(&msg_ptr, &ul_generic_nas_transport->add_info); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + Message Name: Activate Dedicated EPS Bearer Context Accept + + Description: Sent by the UE to the network to acknowledge + activation of a dedicated EPS bearer context + associated with the same PDN address(es) and APN as + an already active EPS bearer context. + + Document Reference: 24.301 v10.2.0 Section 8.3.1 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_activate_dedicated_eps_bearer_context_accept_msg(LIBLTE_MME_ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_ACCEPT_MSG_STRUCT *act_ded_eps_bearer_context_accept, + LIBLTE_BYTE_MSG_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(act_ded_eps_bearer_context_accept != NULL && + msg != NULL) + { + // Protocol Discriminator and EPS Bearer ID + *msg_ptr = (act_ded_eps_bearer_context_accept->eps_bearer_id << 4) | (LIBLTE_MME_PD_EPS_SESSION_MANAGEMENT); + msg_ptr++; + + // Procedure Transaction ID + *msg_ptr = act_ded_eps_bearer_context_accept->proc_transaction_id; + msg_ptr++; + + // Message Type + *msg_ptr = LIBLTE_MME_MSG_TYPE_ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_ACCEPT; + msg_ptr++; + + // Protocol Configuration Options + if(act_ded_eps_bearer_context_accept->protocol_cnfg_opts_present) + { + *msg_ptr = LIBLTE_MME_PROTOCOL_CONFIGURATION_OPTIONS_IEI; + msg_ptr++; + liblte_mme_pack_protocol_config_options_ie(&act_ded_eps_bearer_context_accept->protocol_cnfg_opts, &msg_ptr); + } + + // Fill in the number of bytes used + msg->N_bytes = msg_ptr - msg->msg; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_activate_dedicated_eps_bearer_context_accept_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_ACCEPT_MSG_STRUCT *act_ded_eps_bearer_context_accept) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(msg != NULL && + act_ded_eps_bearer_context_accept != NULL) + { + // EPS Bearer ID + act_ded_eps_bearer_context_accept->eps_bearer_id = (*msg_ptr >> 4); + msg_ptr++; + + // Procedure Transaction ID + act_ded_eps_bearer_context_accept->proc_transaction_id = *msg_ptr; + msg_ptr++; + + // Skip Message Type + msg_ptr++; + + // Protocol Configuration Options + if(LIBLTE_MME_PROTOCOL_CONFIGURATION_OPTIONS_IEI == *msg_ptr) + { + msg_ptr++; + liblte_mme_unpack_protocol_config_options_ie(&msg_ptr, &act_ded_eps_bearer_context_accept->protocol_cnfg_opts); + act_ded_eps_bearer_context_accept->protocol_cnfg_opts_present = true; + }else{ + act_ded_eps_bearer_context_accept->protocol_cnfg_opts_present = false; + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + Message Name: Activate Dedicated EPS Bearer Context Reject + + Description: Sent by the UE to the network to reject activation + of a dedicated EPS bearer context. + + Document Reference: 24.301 v10.2.0 Section 8.3.2 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_activate_dedicated_eps_bearer_context_reject_msg(LIBLTE_MME_ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REJECT_MSG_STRUCT *act_ded_eps_bearer_context_rej, + LIBLTE_BYTE_MSG_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(act_ded_eps_bearer_context_rej != NULL && + msg != NULL) + { + // Protocol Discriminator and EPS Bearer ID + *msg_ptr = (act_ded_eps_bearer_context_rej->eps_bearer_id << 4) | (LIBLTE_MME_PD_EPS_SESSION_MANAGEMENT); + msg_ptr++; + + // Procedure Transaction ID + *msg_ptr = act_ded_eps_bearer_context_rej->proc_transaction_id; + msg_ptr++; + + // Message Type + *msg_ptr = LIBLTE_MME_MSG_TYPE_ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REJECT; + msg_ptr++; + + // ESM Cause + liblte_mme_pack_esm_cause_ie(act_ded_eps_bearer_context_rej->esm_cause, &msg_ptr); + + // Protocol Configuration Options + if(act_ded_eps_bearer_context_rej->protocol_cnfg_opts_present) + { + *msg_ptr = LIBLTE_MME_PROTOCOL_CONFIGURATION_OPTIONS_IEI; + msg_ptr++; + liblte_mme_pack_protocol_config_options_ie(&act_ded_eps_bearer_context_rej->protocol_cnfg_opts, &msg_ptr); + } + + // Fill in the number of bytes used + msg->N_bytes = msg_ptr - msg->msg; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_activate_dedicated_eps_bearer_context_reject_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REJECT_MSG_STRUCT *act_ded_eps_bearer_context_rej) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(msg != NULL && + act_ded_eps_bearer_context_rej != NULL) + { + // EPS Bearer ID + act_ded_eps_bearer_context_rej->eps_bearer_id = (*msg_ptr >> 4); + msg_ptr++; + + // Procedure Transaction ID + act_ded_eps_bearer_context_rej->proc_transaction_id = *msg_ptr; + msg_ptr++; + + // Skip Message Type + msg_ptr++; + + // ESM Cause + liblte_mme_unpack_esm_cause_ie(&msg_ptr, &act_ded_eps_bearer_context_rej->esm_cause); + + // Protocol Configuration Options + if(LIBLTE_MME_PROTOCOL_CONFIGURATION_OPTIONS_IEI == *msg_ptr) + { + msg_ptr++; + liblte_mme_unpack_protocol_config_options_ie(&msg_ptr, &act_ded_eps_bearer_context_rej->protocol_cnfg_opts); + act_ded_eps_bearer_context_rej->protocol_cnfg_opts_present = true; + }else{ + act_ded_eps_bearer_context_rej->protocol_cnfg_opts_present = false; + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + Message Name: Activate Dedicated EPS Bearer Context Request + + Description: Sent by the network to the UE to request activation + of a dedicated EPS bearer context associated with + the same PDN address(es) and APN as an already + active default EPS bearer context. + + Document Reference: 24.301 v10.2.0 Section 8.3.3 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_activate_dedicated_eps_bearer_context_request_msg(LIBLTE_MME_ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REQUEST_MSG_STRUCT *act_ded_eps_bearer_context_req, + LIBLTE_BYTE_MSG_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(act_ded_eps_bearer_context_req != NULL && + msg != NULL) + { + // Protocol Discriminator and EPS Bearer ID + *msg_ptr = (act_ded_eps_bearer_context_req->eps_bearer_id << 4) | (LIBLTE_MME_PD_EPS_SESSION_MANAGEMENT); + msg_ptr++; + + // Procedure Transaction ID + *msg_ptr = act_ded_eps_bearer_context_req->proc_transaction_id; + msg_ptr++; + + // Message Type + *msg_ptr = LIBLTE_MME_MSG_TYPE_ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REQUEST; + msg_ptr++; + + // Linked EPS Bearer Identity & Spare Half Octet + *msg_ptr = 0; + liblte_mme_pack_linked_eps_bearer_identity_ie(act_ded_eps_bearer_context_req->linked_eps_bearer_id, 0, &msg_ptr); + msg_ptr++; + + // EPS QoS + liblte_mme_pack_eps_quality_of_service_ie(&act_ded_eps_bearer_context_req->eps_qos, &msg_ptr); + + // TFT + liblte_mme_pack_traffic_flow_template_ie(&act_ded_eps_bearer_context_req->tft, &msg_ptr); + + // Transaction Identifier + if(act_ded_eps_bearer_context_req->transaction_id_present) + { + *msg_ptr = LIBLTE_MME_TRANSACTION_IDENTIFIER_IEI; + msg_ptr++; + liblte_mme_pack_transaction_identifier_ie(&act_ded_eps_bearer_context_req->transaction_id, &msg_ptr); + } + + // Negotiated QoS + if(act_ded_eps_bearer_context_req->negotiated_qos_present) + { + *msg_ptr = LIBLTE_MME_QUALITY_OF_SERVICE_IEI; + msg_ptr++; + liblte_mme_pack_quality_of_service_ie(&act_ded_eps_bearer_context_req->negotiated_qos, &msg_ptr); + } + + // Negotiated LLC SAPI + if(act_ded_eps_bearer_context_req->llc_sapi_present) + { + *msg_ptr = LIBLTE_MME_LLC_SAPI_IEI; + msg_ptr++; + liblte_mme_pack_llc_service_access_point_identifier_ie(act_ded_eps_bearer_context_req->llc_sapi, &msg_ptr); + } + + // Radio Priority + if(act_ded_eps_bearer_context_req->radio_prio_present) + { + *msg_ptr = LIBLTE_MME_RADIO_PRIORITY_IEI << 4; + liblte_mme_pack_radio_priority_ie(act_ded_eps_bearer_context_req->radio_prio, 0, &msg_ptr); + msg_ptr++; + } + + // Packet Flow Identifier + if(act_ded_eps_bearer_context_req->packet_flow_id_present) + { + *msg_ptr = LIBLTE_MME_PACKET_FLOW_IDENTIFIER_IEI; + msg_ptr++; + liblte_mme_pack_packet_flow_identifier_ie(act_ded_eps_bearer_context_req->packet_flow_id, &msg_ptr); + } + + // Protocol Configuration Options + if(act_ded_eps_bearer_context_req->protocol_cnfg_opts_present) + { + *msg_ptr = LIBLTE_MME_PROTOCOL_CONFIGURATION_OPTIONS_IEI; + msg_ptr++; + liblte_mme_pack_protocol_config_options_ie(&act_ded_eps_bearer_context_req->protocol_cnfg_opts, &msg_ptr); + } + + // Fill in the number of bytes used + msg->N_bytes = msg_ptr - msg->msg; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_activate_dedicated_eps_bearer_context_request_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REQUEST_MSG_STRUCT *act_ded_eps_bearer_context_req) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(msg != NULL && + act_ded_eps_bearer_context_req != NULL) + { + // EPS Bearer ID + act_ded_eps_bearer_context_req->eps_bearer_id = (*msg_ptr >> 4); + msg_ptr++; + + // Procedure Transaction ID + act_ded_eps_bearer_context_req->proc_transaction_id = *msg_ptr; + msg_ptr++; + + // Skip Message Type + msg_ptr++; + + // Linked Bearer Identity & Spare Half Octet + liblte_mme_unpack_linked_eps_bearer_identity_ie(&msg_ptr, 0, &act_ded_eps_bearer_context_req->linked_eps_bearer_id); + msg_ptr++; + + // EPS QoS + liblte_mme_unpack_eps_quality_of_service_ie(&msg_ptr, &act_ded_eps_bearer_context_req->eps_qos); + + // TFT + liblte_mme_unpack_traffic_flow_template_ie(&msg_ptr, &act_ded_eps_bearer_context_req->tft); + + // Transaction Identifier + if(LIBLTE_MME_TRANSACTION_IDENTIFIER_IEI == *msg_ptr) + { + msg_ptr++; + liblte_mme_unpack_transaction_identifier_ie(&msg_ptr, &act_ded_eps_bearer_context_req->transaction_id); + act_ded_eps_bearer_context_req->transaction_id_present = true; + }else{ + act_ded_eps_bearer_context_req->transaction_id_present = false; + } + + // Negotiated QoS + if(LIBLTE_MME_QUALITY_OF_SERVICE_IEI == *msg_ptr) + { + msg_ptr++; + liblte_mme_unpack_quality_of_service_ie(&msg_ptr, &act_ded_eps_bearer_context_req->negotiated_qos); + act_ded_eps_bearer_context_req->negotiated_qos_present = true; + }else{ + act_ded_eps_bearer_context_req->negotiated_qos_present = false; + } + + // Negotiated LLC SAPI + if(LIBLTE_MME_LLC_SAPI_IEI == *msg_ptr) + { + msg_ptr++; + liblte_mme_unpack_llc_service_access_point_identifier_ie(&msg_ptr, &act_ded_eps_bearer_context_req->llc_sapi); + act_ded_eps_bearer_context_req->llc_sapi_present = true; + }else{ + act_ded_eps_bearer_context_req->llc_sapi_present = false; + } + + // Radio Priority + if((LIBLTE_MME_RADIO_PRIORITY_IEI << 4) == (*msg_ptr & 0xF0)) + { + liblte_mme_unpack_radio_priority_ie(&msg_ptr, 0, &act_ded_eps_bearer_context_req->radio_prio); + msg_ptr++; + act_ded_eps_bearer_context_req->radio_prio_present = true; + }else{ + act_ded_eps_bearer_context_req->radio_prio_present = false; + } + + // Packet Flow Identifier + if(LIBLTE_MME_PACKET_FLOW_IDENTIFIER_IEI == *msg_ptr) + { + msg_ptr++; + liblte_mme_unpack_packet_flow_identifier_ie(&msg_ptr, &act_ded_eps_bearer_context_req->packet_flow_id); + act_ded_eps_bearer_context_req->packet_flow_id_present = true; + }else{ + act_ded_eps_bearer_context_req->packet_flow_id_present = false; + } + + // Protocol Configuration Options + if(LIBLTE_MME_PROTOCOL_CONFIGURATION_OPTIONS_IEI == *msg_ptr) + { + msg_ptr++; + liblte_mme_unpack_protocol_config_options_ie(&msg_ptr, &act_ded_eps_bearer_context_req->protocol_cnfg_opts); + act_ded_eps_bearer_context_req->protocol_cnfg_opts_present = true; + }else{ + act_ded_eps_bearer_context_req->protocol_cnfg_opts_present = false; + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + Message Name: Activate Default EPS Bearer Context Accept + + Description: Sent by the UE to the network to acknowledge + activation of a default EPS bearer context. + + Document Reference: 24.301 v10.2.0 Section 8.3.4 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_activate_default_eps_bearer_context_accept_msg(LIBLTE_MME_ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_ACCEPT_MSG_STRUCT *act_def_eps_bearer_context_accept, + LIBLTE_BYTE_MSG_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(act_def_eps_bearer_context_accept != NULL && + msg != NULL) + { + // Protocol Discriminator and EPS Bearer ID + *msg_ptr = (act_def_eps_bearer_context_accept->eps_bearer_id << 4) | (LIBLTE_MME_PD_EPS_SESSION_MANAGEMENT); + msg_ptr++; + + // Procedure Transaction ID + *msg_ptr = act_def_eps_bearer_context_accept->proc_transaction_id; + msg_ptr++; + + // Message Type + *msg_ptr = LIBLTE_MME_MSG_TYPE_ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_ACCEPT; + msg_ptr++; + + // Protocol Configuration Options + if(act_def_eps_bearer_context_accept->protocol_cnfg_opts_present) + { + *msg_ptr = LIBLTE_MME_PROTOCOL_CONFIGURATION_OPTIONS_IEI; + msg_ptr++; + liblte_mme_pack_protocol_config_options_ie(&act_def_eps_bearer_context_accept->protocol_cnfg_opts, &msg_ptr); + } + + // Fill in the number of bytes used + msg->N_bytes = msg_ptr - msg->msg; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_activate_default_eps_bearer_context_accept_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_ACCEPT_MSG_STRUCT *act_def_eps_bearer_context_accept) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(msg != NULL && + act_def_eps_bearer_context_accept != NULL) + { + // EPS Bearer ID + act_def_eps_bearer_context_accept->eps_bearer_id = (*msg_ptr >> 4); + msg_ptr++; + + // Procedure Transaction ID + act_def_eps_bearer_context_accept->proc_transaction_id = *msg_ptr; + msg_ptr++; + + // Skip Message Type + msg_ptr++; + + // Protocol Configuration Options + if(LIBLTE_MME_PROTOCOL_CONFIGURATION_OPTIONS_IEI == *msg_ptr) + { + msg_ptr++; + liblte_mme_unpack_protocol_config_options_ie(&msg_ptr, &act_def_eps_bearer_context_accept->protocol_cnfg_opts); + act_def_eps_bearer_context_accept->protocol_cnfg_opts_present = true; + }else{ + act_def_eps_bearer_context_accept->protocol_cnfg_opts_present = false; + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + Message Name: Activate Default EPS Bearer Context Reject + + Description: Sent by the UE to the network to reject activation + of a default EPS bearer context. + + Document Reference: 24.301 v10.2.0 Section 8.3.5 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_activate_default_eps_bearer_context_reject_msg(LIBLTE_MME_ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REJECT_MSG_STRUCT *act_def_eps_bearer_context_rej, + LIBLTE_BYTE_MSG_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(act_def_eps_bearer_context_rej != NULL && + msg != NULL) + { + // Protocol Discriminator and EPS Bearer ID + *msg_ptr = (act_def_eps_bearer_context_rej->eps_bearer_id << 4) | (LIBLTE_MME_PD_EPS_SESSION_MANAGEMENT); + msg_ptr++; + + // Procedure Transaction ID + *msg_ptr = act_def_eps_bearer_context_rej->proc_transaction_id; + msg_ptr++; + + // Message Type + *msg_ptr = LIBLTE_MME_MSG_TYPE_ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REJECT; + msg_ptr++; + + // ESM Cause + liblte_mme_pack_esm_cause_ie(act_def_eps_bearer_context_rej->esm_cause, &msg_ptr); + + // Protocol Configuration Options + if(act_def_eps_bearer_context_rej->protocol_cnfg_opts_present) + { + *msg_ptr = LIBLTE_MME_PROTOCOL_CONFIGURATION_OPTIONS_IEI; + msg_ptr++; + liblte_mme_pack_protocol_config_options_ie(&act_def_eps_bearer_context_rej->protocol_cnfg_opts, &msg_ptr); + } + + // Fill in the number of bytes used + msg->N_bytes = msg_ptr - msg->msg; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_activate_default_eps_bearer_context_reject_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REJECT_MSG_STRUCT *act_def_eps_bearer_context_rej) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(msg != NULL && + act_def_eps_bearer_context_rej != NULL) + { + // EPS Bearer ID + act_def_eps_bearer_context_rej->eps_bearer_id = (*msg_ptr >> 4); + msg_ptr++; + + // Procedure Transaction ID + act_def_eps_bearer_context_rej->proc_transaction_id = *msg_ptr; + msg_ptr++; + + // Skip Message Type + msg_ptr++; + + // ESM Cause + liblte_mme_unpack_esm_cause_ie(&msg_ptr, &act_def_eps_bearer_context_rej->esm_cause); + + // Protocol Configuration Options + if(LIBLTE_MME_PROTOCOL_CONFIGURATION_OPTIONS_IEI == *msg_ptr) + { + msg_ptr++; + liblte_mme_unpack_protocol_config_options_ie(&msg_ptr, &act_def_eps_bearer_context_rej->protocol_cnfg_opts); + act_def_eps_bearer_context_rej->protocol_cnfg_opts_present = true; + }else{ + act_def_eps_bearer_context_rej->protocol_cnfg_opts_present = false; + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + Message Name: Activate Default EPS Bearer Context Request + + Description: Sent by the network to the UE to request activation + of a default EPS bearer context. + + Document Reference: 24.301 v10.2.0 Section 8.3.6 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_activate_default_eps_bearer_context_request_msg(LIBLTE_MME_ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_MSG_STRUCT *act_def_eps_bearer_context_req, + LIBLTE_BYTE_MSG_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(act_def_eps_bearer_context_req != NULL && + msg != NULL) + { + // Protocol Discriminator and EPS Bearer ID + *msg_ptr = (act_def_eps_bearer_context_req->eps_bearer_id << 4) | (LIBLTE_MME_PD_EPS_SESSION_MANAGEMENT); + msg_ptr++; + + // Procedure Transaction ID + *msg_ptr = act_def_eps_bearer_context_req->proc_transaction_id; + msg_ptr++; + + // Message Type + *msg_ptr = LIBLTE_MME_MSG_TYPE_ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST; + msg_ptr++; + + // EPS QoS + liblte_mme_pack_eps_quality_of_service_ie(&act_def_eps_bearer_context_req->eps_qos, &msg_ptr); + + // Access Point Name + liblte_mme_pack_access_point_name_ie(&act_def_eps_bearer_context_req->apn, &msg_ptr); + + // PDN Address + liblte_mme_pack_pdn_address_ie(&act_def_eps_bearer_context_req->pdn_addr, &msg_ptr); + + // Transaction Identifier + if(act_def_eps_bearer_context_req->transaction_id_present) + { + *msg_ptr = LIBLTE_MME_TRANSACTION_IDENTIFIER_IEI; + msg_ptr++; + liblte_mme_pack_transaction_identifier_ie(&act_def_eps_bearer_context_req->transaction_id, &msg_ptr); + } + + // Negotiated QoS + if(act_def_eps_bearer_context_req->negotiated_qos_present) + { + *msg_ptr = LIBLTE_MME_QUALITY_OF_SERVICE_IEI; + msg_ptr++; + liblte_mme_pack_quality_of_service_ie(&act_def_eps_bearer_context_req->negotiated_qos, &msg_ptr); + } + + // Negotiated LLC SAPI + if(act_def_eps_bearer_context_req->llc_sapi_present) + { + *msg_ptr = LIBLTE_MME_LLC_SAPI_IEI; + msg_ptr++; + liblte_mme_pack_llc_service_access_point_identifier_ie(act_def_eps_bearer_context_req->llc_sapi, &msg_ptr); + } + + // Radio Priority + if(act_def_eps_bearer_context_req->radio_prio_present) + { + *msg_ptr = LIBLTE_MME_RADIO_PRIORITY_IEI << 4; + liblte_mme_pack_radio_priority_ie(act_def_eps_bearer_context_req->radio_prio, 0, &msg_ptr); + msg_ptr++; + } + + // Packet Flow Identifier + if(act_def_eps_bearer_context_req->packet_flow_id_present) + { + *msg_ptr = LIBLTE_MME_PACKET_FLOW_IDENTIFIER_IEI; + msg_ptr++; + liblte_mme_pack_packet_flow_identifier_ie(act_def_eps_bearer_context_req->packet_flow_id, &msg_ptr); + } + + // APN-AMBR + if(act_def_eps_bearer_context_req->apn_ambr_present) + { + *msg_ptr = LIBLTE_MME_APN_AMBR_IEI; + msg_ptr++; + liblte_mme_pack_apn_aggregate_maximum_bit_rate_ie(&act_def_eps_bearer_context_req->apn_ambr, &msg_ptr); + } + + // ESM Cause + if(act_def_eps_bearer_context_req->esm_cause_present) + { + *msg_ptr = LIBLTE_MME_ESM_CAUSE_IEI; + msg_ptr++; + liblte_mme_pack_esm_cause_ie(act_def_eps_bearer_context_req->esm_cause, &msg_ptr); + } + + // Protocol Configuration Options + if(act_def_eps_bearer_context_req->protocol_cnfg_opts_present) + { + *msg_ptr = LIBLTE_MME_PROTOCOL_CONFIGURATION_OPTIONS_IEI; + msg_ptr++; + liblte_mme_pack_protocol_config_options_ie(&act_def_eps_bearer_context_req->protocol_cnfg_opts, &msg_ptr); + } + + // Connectivity Type + if(act_def_eps_bearer_context_req->connectivity_type_present) + { + *msg_ptr = LIBLTE_MME_CONNECTIVITY_TYPE_IEI << 4; + liblte_mme_pack_connectivity_type_ie(act_def_eps_bearer_context_req->connectivity_type, 0, &msg_ptr); + msg_ptr++; + } + + // Fill in the number of bytes used + msg->N_bytes = msg_ptr - msg->msg; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_activate_default_eps_bearer_context_request_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_MSG_STRUCT *act_def_eps_bearer_context_req) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(msg != NULL && + act_def_eps_bearer_context_req != NULL) + { + // EPS Bearer ID + act_def_eps_bearer_context_req->eps_bearer_id = (*msg_ptr >> 4); + msg_ptr++; + + // Procedure Transaction ID + act_def_eps_bearer_context_req->proc_transaction_id = *msg_ptr; + msg_ptr++; + + // Skip Message Type + msg_ptr++; + + // EPS QoS + liblte_mme_unpack_eps_quality_of_service_ie(&msg_ptr, &act_def_eps_bearer_context_req->eps_qos); + + // Access Point Name + liblte_mme_unpack_access_point_name_ie(&msg_ptr, &act_def_eps_bearer_context_req->apn); + + // PDN Address + liblte_mme_unpack_pdn_address_ie(&msg_ptr, &act_def_eps_bearer_context_req->pdn_addr); + + // Transaction Identifier + if(LIBLTE_MME_TRANSACTION_IDENTIFIER_IEI == *msg_ptr) + { + msg_ptr++; + liblte_mme_unpack_transaction_identifier_ie(&msg_ptr, &act_def_eps_bearer_context_req->transaction_id); + act_def_eps_bearer_context_req->transaction_id_present = true; + }else{ + act_def_eps_bearer_context_req->transaction_id_present = false; + } + + // Negotiated QoS + if(LIBLTE_MME_QUALITY_OF_SERVICE_IEI == *msg_ptr) + { + msg_ptr++; + liblte_mme_unpack_quality_of_service_ie(&msg_ptr, &act_def_eps_bearer_context_req->negotiated_qos); + act_def_eps_bearer_context_req->negotiated_qos_present = true; + }else{ + act_def_eps_bearer_context_req->negotiated_qos_present = false; + } + + // Negotiated LLC SAPI + if(LIBLTE_MME_LLC_SAPI_IEI == *msg_ptr) + { + msg_ptr++; + liblte_mme_unpack_llc_service_access_point_identifier_ie(&msg_ptr, &act_def_eps_bearer_context_req->llc_sapi); + act_def_eps_bearer_context_req->llc_sapi_present = true; + }else{ + act_def_eps_bearer_context_req->llc_sapi_present = false; + } + + // Radio Priority + if((LIBLTE_MME_RADIO_PRIORITY_IEI << 4) == (*msg_ptr & 0xF0)) + { + liblte_mme_unpack_radio_priority_ie(&msg_ptr, 0, &act_def_eps_bearer_context_req->radio_prio); + msg_ptr++; + act_def_eps_bearer_context_req->radio_prio_present = true; + }else{ + act_def_eps_bearer_context_req->radio_prio_present = false; + } + + // Packet Flow Identifier + if(LIBLTE_MME_PACKET_FLOW_IDENTIFIER_IEI == *msg_ptr) + { + msg_ptr++; + liblte_mme_unpack_packet_flow_identifier_ie(&msg_ptr, &act_def_eps_bearer_context_req->packet_flow_id); + act_def_eps_bearer_context_req->packet_flow_id_present = true; + }else{ + act_def_eps_bearer_context_req->packet_flow_id_present = false; + } + + // APN-AMBR + if(LIBLTE_MME_APN_AMBR_IEI == *msg_ptr) + { + msg_ptr++; + liblte_mme_unpack_apn_aggregate_maximum_bit_rate_ie(&msg_ptr, &act_def_eps_bearer_context_req->apn_ambr); + act_def_eps_bearer_context_req->apn_ambr_present = true; + }else{ + act_def_eps_bearer_context_req->apn_ambr_present = false; + } + + // ESM Cause + if(LIBLTE_MME_ESM_CAUSE_IEI == *msg_ptr) + { + msg_ptr++; + liblte_mme_unpack_esm_cause_ie(&msg_ptr, &act_def_eps_bearer_context_req->esm_cause); + act_def_eps_bearer_context_req->esm_cause_present = true; + }else{ + act_def_eps_bearer_context_req->esm_cause_present = false; + } + + // Protocol Configuration Options + if(LIBLTE_MME_PROTOCOL_CONFIGURATION_OPTIONS_IEI == *msg_ptr) + { + msg_ptr++; + liblte_mme_unpack_protocol_config_options_ie(&msg_ptr, &act_def_eps_bearer_context_req->protocol_cnfg_opts); + act_def_eps_bearer_context_req->protocol_cnfg_opts_present = true; + }else{ + act_def_eps_bearer_context_req->protocol_cnfg_opts_present = false; + } + + // Connectivity Type + if((LIBLTE_MME_CONNECTIVITY_TYPE_IEI << 4) == (*msg_ptr & 0xF0)) + { + liblte_mme_unpack_connectivity_type_ie(&msg_ptr, 0, &act_def_eps_bearer_context_req->connectivity_type); + msg_ptr++; + act_def_eps_bearer_context_req->connectivity_type_present = true; + }else{ + act_def_eps_bearer_context_req->connectivity_type_present = false; + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + Message Name: Bearer Resource Allocation Reject + + Description: Sent by the network to the UE to reject the + allocation of a dedicated bearer resource. + + Document Reference: 24.301 v10.2.0 Section 8.3.7 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_bearer_resource_allocation_reject_msg(LIBLTE_MME_BEARER_RESOURCE_ALLOCATION_REJECT_MSG_STRUCT *bearer_res_alloc_rej, + LIBLTE_BYTE_MSG_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(bearer_res_alloc_rej != NULL && + msg != NULL) + { + // Protocol Discriminator and EPS Bearer ID + *msg_ptr = (bearer_res_alloc_rej->eps_bearer_id << 4) | (LIBLTE_MME_PD_EPS_SESSION_MANAGEMENT); + msg_ptr++; + + // Procedure Transaction ID + *msg_ptr = bearer_res_alloc_rej->proc_transaction_id; + msg_ptr++; + + // Message Type + *msg_ptr = LIBLTE_MME_MSG_TYPE_BEARER_RESOURCE_ALLOCATION_REJECT; + msg_ptr++; + + // ESM Cause + liblte_mme_pack_esm_cause_ie(bearer_res_alloc_rej->esm_cause, &msg_ptr); + + // Protocol Configuration Options + if(bearer_res_alloc_rej->protocol_cnfg_opts_present) + { + *msg_ptr = LIBLTE_MME_PROTOCOL_CONFIGURATION_OPTIONS_IEI; + msg_ptr++; + liblte_mme_pack_protocol_config_options_ie(&bearer_res_alloc_rej->protocol_cnfg_opts, &msg_ptr); + } + + // T3496 Value + if(bearer_res_alloc_rej->t3496_present) + { + *msg_ptr = LIBLTE_MME_T3496_VALUE_IEI; + msg_ptr++; + liblte_mme_pack_gprs_timer_3_ie(&bearer_res_alloc_rej->t3496, &msg_ptr); + } + + // Fill in the number of bytes used + msg->N_bytes = msg_ptr - msg->msg; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_bearer_resource_allocation_reject_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_BEARER_RESOURCE_ALLOCATION_REJECT_MSG_STRUCT *bearer_res_alloc_rej) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(msg != NULL && + bearer_res_alloc_rej != NULL) + { + // EPS Bearer ID + bearer_res_alloc_rej->eps_bearer_id = (*msg_ptr >> 4); + msg_ptr++; + + // Procedure Transaction ID + bearer_res_alloc_rej->proc_transaction_id = *msg_ptr; + msg_ptr++; + + // Skip Message Type + msg_ptr++; + + // ESM Cause + liblte_mme_unpack_esm_cause_ie(&msg_ptr, &bearer_res_alloc_rej->esm_cause); + + // Protocol Configuration Options + if(LIBLTE_MME_PROTOCOL_CONFIGURATION_OPTIONS_IEI == *msg_ptr) + { + msg_ptr++; + liblte_mme_unpack_protocol_config_options_ie(&msg_ptr, &bearer_res_alloc_rej->protocol_cnfg_opts); + bearer_res_alloc_rej->protocol_cnfg_opts_present = true; + }else{ + bearer_res_alloc_rej->protocol_cnfg_opts_present = false; + } + + // T3496 Value + if(LIBLTE_MME_T3496_VALUE_IEI == *msg_ptr) + { + msg_ptr++; + liblte_mme_unpack_gprs_timer_3_ie(&msg_ptr, &bearer_res_alloc_rej->t3496); + bearer_res_alloc_rej->t3496_present = true; + }else{ + bearer_res_alloc_rej->t3496_present = false; + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + Message Name: Bearer Resource Allocation Request + + Description: Sent by the UE to the network to request the + allocation of a dedicated bearer resource. + + Document Reference: 24.301 v10.2.0 Section 8.3.8 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_bearer_resource_allocation_request_msg(LIBLTE_MME_BEARER_RESOURCE_ALLOCATION_REQUEST_MSG_STRUCT *bearer_res_alloc_req, + LIBLTE_BYTE_MSG_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(bearer_res_alloc_req != NULL && + msg != NULL) + { + // Protocol Discriminator and EPS Bearer ID + *msg_ptr = (bearer_res_alloc_req->eps_bearer_id << 4) | (LIBLTE_MME_PD_EPS_SESSION_MANAGEMENT); + msg_ptr++; + + // Procedure Transaction ID + *msg_ptr = bearer_res_alloc_req->proc_transaction_id; + msg_ptr++; + + // Message Type + *msg_ptr = LIBLTE_MME_MSG_TYPE_BEARER_RESOURCE_ALLOCATION_REQUEST; + msg_ptr++; + + // Linked EPS Bearer Identity & Spare Half Octet + liblte_mme_pack_linked_eps_bearer_identity_ie(bearer_res_alloc_req->linked_eps_bearer_id, 0, &msg_ptr); + + // Traffic Flow Aggregate + liblte_mme_pack_traffic_flow_aggregate_description_ie(&bearer_res_alloc_req->tfa, &msg_ptr); + + // Required Traffic Flow QoS + liblte_mme_pack_eps_quality_of_service_ie(&bearer_res_alloc_req->req_tf_qos, &msg_ptr); + + // Protocol Configuration Options + if(bearer_res_alloc_req->protocol_cnfg_opts_present) + { + *msg_ptr = LIBLTE_MME_PROTOCOL_CONFIGURATION_OPTIONS_IEI; + msg_ptr++; + liblte_mme_pack_protocol_config_options_ie(&bearer_res_alloc_req->protocol_cnfg_opts, &msg_ptr); + } + + // Device Properties + if(bearer_res_alloc_req->device_properties_present) + { + *msg_ptr = LIBLTE_MME_BEARER_RESOURCE_ALLOCATION_REQUEST_DEVICE_PROPERTIES_IEI << 4; + liblte_mme_pack_device_properties_ie(bearer_res_alloc_req->device_properties, 0, &msg_ptr); + msg_ptr++; + } + + // Fill in the number of bytes used + msg->N_bytes = msg_ptr - msg->msg; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_bearer_resource_allocation_request_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_BEARER_RESOURCE_ALLOCATION_REQUEST_MSG_STRUCT *bearer_res_alloc_req) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(msg != NULL && + bearer_res_alloc_req != NULL) + { + // EPS Bearer ID + bearer_res_alloc_req->eps_bearer_id = (*msg_ptr >> 4); + msg_ptr++; + + // Procedure Transaction ID + bearer_res_alloc_req->proc_transaction_id = *msg_ptr; + msg_ptr++; + + // Skip Message Type + msg_ptr++; + + // Linked EPS Bearer Identity & Spare Half Octet + liblte_mme_unpack_linked_eps_bearer_identity_ie(&msg_ptr, 0, &bearer_res_alloc_req->linked_eps_bearer_id); + + // Traffic Flow Aggregate + liblte_mme_unpack_traffic_flow_aggregate_description_ie(&msg_ptr, &bearer_res_alloc_req->tfa); + + // Required Traffic Flow QoS + liblte_mme_unpack_eps_quality_of_service_ie(&msg_ptr, &bearer_res_alloc_req->req_tf_qos); + + // Protocol Configuration Options + if(LIBLTE_MME_PROTOCOL_CONFIGURATION_OPTIONS_IEI == *msg_ptr) + { + msg_ptr++; + liblte_mme_unpack_protocol_config_options_ie(&msg_ptr, &bearer_res_alloc_req->protocol_cnfg_opts); + bearer_res_alloc_req->protocol_cnfg_opts_present = true; + }else{ + bearer_res_alloc_req->protocol_cnfg_opts_present = false; + } + + // Device Properties + if((LIBLTE_MME_BEARER_RESOURCE_ALLOCATION_REQUEST_DEVICE_PROPERTIES_IEI << 4) == *msg_ptr) + { + liblte_mme_unpack_device_properties_ie(&msg_ptr, 0, &bearer_res_alloc_req->device_properties); + msg_ptr++; + bearer_res_alloc_req->device_properties_present = true; + }else{ + bearer_res_alloc_req->device_properties_present = false; + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + Message Name: Bearer Resource Modification Reject + + Description: Sent by the network to the UE to reject the + modification of a dedicated bearer resource. + + Document Reference: 24.301 v10.2.0 Section 8.3.9 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_bearer_resource_modification_reject_msg(LIBLTE_MME_BEARER_RESOURCE_MODIFICATION_REJECT_MSG_STRUCT *bearer_res_mod_rej, + LIBLTE_BYTE_MSG_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(bearer_res_mod_rej != NULL && + msg != NULL) + { + // Protocol Discriminator and EPS Bearer ID + *msg_ptr = (bearer_res_mod_rej->eps_bearer_id << 4) | (LIBLTE_MME_PD_EPS_SESSION_MANAGEMENT); + msg_ptr++; + + // Procedure Transaction ID + *msg_ptr = bearer_res_mod_rej->proc_transaction_id; + msg_ptr++; + + // Message Type + *msg_ptr = LIBLTE_MME_MSG_TYPE_BEARER_RESOURCE_MODIFICATION_REJECT; + msg_ptr++; + + // ESM Cause + liblte_mme_pack_esm_cause_ie(bearer_res_mod_rej->esm_cause, &msg_ptr); + + // Protocol Configuration Options + if(bearer_res_mod_rej->protocol_cnfg_opts_present) + { + *msg_ptr = LIBLTE_MME_PROTOCOL_CONFIGURATION_OPTIONS_IEI; + msg_ptr++; + liblte_mme_pack_protocol_config_options_ie(&bearer_res_mod_rej->protocol_cnfg_opts, &msg_ptr); + } + + // T3496 Value + if(bearer_res_mod_rej->t3496_present) + { + *msg_ptr = LIBLTE_MME_T3496_VALUE_IEI; + msg_ptr++; + liblte_mme_pack_gprs_timer_3_ie(&bearer_res_mod_rej->t3496, &msg_ptr); + } + + // Fill in the number of bytes used + msg->N_bytes = msg_ptr - msg->msg; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_bearer_resource_modification_reject_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_BEARER_RESOURCE_MODIFICATION_REJECT_MSG_STRUCT *bearer_res_mod_rej) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(msg != NULL && + bearer_res_mod_rej != NULL) + { + // EPS Bearer ID + bearer_res_mod_rej->eps_bearer_id = (*msg_ptr >> 4); + msg_ptr++; + + // Procedure Transaction ID + bearer_res_mod_rej->proc_transaction_id = *msg_ptr; + msg_ptr++; + + // Skip Message Type + msg_ptr++; + + // ESM Cause + liblte_mme_unpack_esm_cause_ie(&msg_ptr, &bearer_res_mod_rej->esm_cause); + + // Protocol Configuration Options + if(LIBLTE_MME_PROTOCOL_CONFIGURATION_OPTIONS_IEI == *msg_ptr) + { + msg_ptr++; + liblte_mme_unpack_protocol_config_options_ie(&msg_ptr, &bearer_res_mod_rej->protocol_cnfg_opts); + bearer_res_mod_rej->protocol_cnfg_opts_present = true; + }else{ + bearer_res_mod_rej->protocol_cnfg_opts_present = false; + } + + // T3496 Value + if(LIBLTE_MME_T3496_VALUE_IEI == *msg_ptr) + { + msg_ptr++; + liblte_mme_unpack_gprs_timer_3_ie(&msg_ptr, &bearer_res_mod_rej->t3496); + bearer_res_mod_rej->t3496_present = true; + }else{ + bearer_res_mod_rej->t3496_present = false; + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + Message Name: Bearer Resource Modification Request + + Description: Sent by the UE to the network to request the + modification of a dedicated bearer resource. + + Document Reference: 24.301 v10.2.0 Section 8.3.10 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_bearer_resource_modification_request_msg(LIBLTE_MME_BEARER_RESOURCE_MODIFICATION_REQUEST_MSG_STRUCT *bearer_res_mod_req, + LIBLTE_BYTE_MSG_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(bearer_res_mod_req != NULL && + msg != NULL) + { + // Protocol Discriminator and EPS Bearer ID + *msg_ptr = (bearer_res_mod_req->eps_bearer_id << 4) | (LIBLTE_MME_PD_EPS_SESSION_MANAGEMENT); + msg_ptr++; + + // Procedure Transaction ID + *msg_ptr = bearer_res_mod_req->proc_transaction_id; + msg_ptr++; + + // Message Type + *msg_ptr = LIBLTE_MME_MSG_TYPE_BEARER_RESOURCE_MODIFICATION_REQUEST; + msg_ptr++; + + // EPS Bearer Identity For Packet Filter & Spare Half Octet + liblte_mme_pack_linked_eps_bearer_identity_ie(bearer_res_mod_req->eps_bearer_id_for_packet_filter, 0, &msg_ptr); + + // Traffic Flow Aggregate + liblte_mme_pack_traffic_flow_aggregate_description_ie(&bearer_res_mod_req->tfa, &msg_ptr); + + // Required Traffic Flow QoS + if(bearer_res_mod_req->req_tf_qos_present) + { + *msg_ptr = LIBLTE_MME_EPS_QUALITY_OF_SERVICE_IEI; + msg_ptr++; + liblte_mme_pack_eps_quality_of_service_ie(&bearer_res_mod_req->req_tf_qos, &msg_ptr); + } + + // ESM Cause + if(bearer_res_mod_req->esm_cause_present) + { + *msg_ptr = LIBLTE_MME_ESM_CAUSE_IEI; + msg_ptr++; + liblte_mme_pack_esm_cause_ie(bearer_res_mod_req->esm_cause, &msg_ptr); + } + + // Protocol Configuration Options + if(bearer_res_mod_req->protocol_cnfg_opts_present) + { + *msg_ptr = LIBLTE_MME_PROTOCOL_CONFIGURATION_OPTIONS_IEI; + msg_ptr++; + liblte_mme_pack_protocol_config_options_ie(&bearer_res_mod_req->protocol_cnfg_opts, &msg_ptr); + } + + // Device Properties + if(bearer_res_mod_req->device_properties_present) + { + *msg_ptr = LIBLTE_MME_BEARER_RESOURCE_MODIFICATION_REQUEST_DEVICE_PROPERTIES_IEI << 4; + liblte_mme_pack_device_properties_ie(bearer_res_mod_req->device_properties, 0, &msg_ptr); + msg_ptr++; + } + + // Fill in the number of bytes used + msg->N_bytes = msg_ptr - msg->msg; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_bearer_resource_modification_request_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_BEARER_RESOURCE_MODIFICATION_REQUEST_MSG_STRUCT *bearer_res_mod_req) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(msg != NULL && + bearer_res_mod_req != NULL) + { + // EPS Bearer ID + bearer_res_mod_req->eps_bearer_id = (*msg_ptr >> 4); + msg_ptr++; + + // Procedure Transaction ID + bearer_res_mod_req->proc_transaction_id = *msg_ptr; + msg_ptr++; + + // Skip Message Type + msg_ptr++; + + // EPS Bearer Identity For Packet Filter & Spare Half Octet + liblte_mme_unpack_linked_eps_bearer_identity_ie(&msg_ptr, 0, &bearer_res_mod_req->eps_bearer_id_for_packet_filter); + + // Traffic Flow Aggregate + liblte_mme_unpack_traffic_flow_aggregate_description_ie(&msg_ptr, &bearer_res_mod_req->tfa); + + // Required Traffic Flow QoS + if(LIBLTE_MME_EPS_QUALITY_OF_SERVICE_IEI == *msg_ptr) + { + msg_ptr++; + liblte_mme_unpack_eps_quality_of_service_ie(&msg_ptr, &bearer_res_mod_req->req_tf_qos); + bearer_res_mod_req->req_tf_qos_present = true; + }else{ + bearer_res_mod_req->req_tf_qos_present = false; + } + + // ESM Cause + if(LIBLTE_MME_ESM_CAUSE_IEI == *msg_ptr) + { + msg_ptr++; + liblte_mme_unpack_esm_cause_ie(&msg_ptr, &bearer_res_mod_req->esm_cause); + bearer_res_mod_req->esm_cause_present = true; + }else{ + bearer_res_mod_req->esm_cause_present = false; + } + + // Protocol Configuration Options + if(LIBLTE_MME_PROTOCOL_CONFIGURATION_OPTIONS_IEI == *msg_ptr) + { + msg_ptr++; + liblte_mme_unpack_protocol_config_options_ie(&msg_ptr, &bearer_res_mod_req->protocol_cnfg_opts); + bearer_res_mod_req->protocol_cnfg_opts_present = true; + }else{ + bearer_res_mod_req->protocol_cnfg_opts_present = false; + } + + // Device Properties + if((LIBLTE_MME_BEARER_RESOURCE_MODIFICATION_REQUEST_DEVICE_PROPERTIES_IEI << 4) == *msg_ptr) + { + liblte_mme_unpack_device_properties_ie(&msg_ptr, 0, &bearer_res_mod_req->device_properties); + msg_ptr++; + bearer_res_mod_req->device_properties_present = true; + }else{ + bearer_res_mod_req->device_properties_present = false; + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + Message Name: Deactivate EPS Bearer Context Accept + + Description: Sent by the UE to acknowledge deactivation of the + EPS bearer context requested in the corresponding + deactivate EPS bearer context request message. + + Document Reference: 24.301 v10.2.0 Section 8.3.11 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_deactivate_eps_bearer_context_accept_msg(LIBLTE_MME_DEACTIVATE_EPS_BEARER_CONTEXT_ACCEPT_MSG_STRUCT *deact_eps_bearer_context_accept, + LIBLTE_BYTE_MSG_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(deact_eps_bearer_context_accept != NULL && + msg != NULL) + { + // Protocol Discriminator and EPS Bearer ID + *msg_ptr = (deact_eps_bearer_context_accept->eps_bearer_id << 4) | (LIBLTE_MME_PD_EPS_SESSION_MANAGEMENT); + msg_ptr++; + + // Procedure Transaction ID + *msg_ptr = deact_eps_bearer_context_accept->proc_transaction_id; + msg_ptr++; + + // Message Type + *msg_ptr = LIBLTE_MME_MSG_TYPE_DEACTIVATE_EPS_BEARER_CONTEXT_ACCEPT; + msg_ptr++; + + // Protocol Configuration Options + if(deact_eps_bearer_context_accept->protocol_cnfg_opts_present) + { + *msg_ptr = LIBLTE_MME_PROTOCOL_CONFIGURATION_OPTIONS_IEI; + msg_ptr++; + liblte_mme_pack_protocol_config_options_ie(&deact_eps_bearer_context_accept->protocol_cnfg_opts, &msg_ptr); + } + + // Fill in the number of bytes used + msg->N_bytes = msg_ptr - msg->msg; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_deactivate_eps_bearer_context_accept_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_DEACTIVATE_EPS_BEARER_CONTEXT_ACCEPT_MSG_STRUCT *deact_eps_bearer_context_accept) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(msg != NULL && + deact_eps_bearer_context_accept != NULL) + { + // EPS Bearer ID + deact_eps_bearer_context_accept->eps_bearer_id = (*msg_ptr >> 4); + msg_ptr++; + + // Procedure Transaction ID + deact_eps_bearer_context_accept->proc_transaction_id = *msg_ptr; + msg_ptr++; + + // Skip Message Type + msg_ptr++; + + // Protocol Configuration Options + if(LIBLTE_MME_PROTOCOL_CONFIGURATION_OPTIONS_IEI == *msg_ptr) + { + msg_ptr++; + liblte_mme_unpack_protocol_config_options_ie(&msg_ptr, &deact_eps_bearer_context_accept->protocol_cnfg_opts); + deact_eps_bearer_context_accept->protocol_cnfg_opts_present = true; + }else{ + deact_eps_bearer_context_accept->protocol_cnfg_opts_present = false; + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + Message Name: Deactivate EPS Bearer Context Request + + Description: Sent by the network to request deactivation of an + EPS bearer context. + + Document Reference: 24.301 v10.2.0 Section 8.3.12 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_deactivate_eps_bearer_context_request_msg(LIBLTE_MME_DEACTIVATE_EPS_BEARER_CONTEXT_REQUEST_MSG_STRUCT *deact_eps_bearer_context_req, + LIBLTE_BYTE_MSG_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(deact_eps_bearer_context_req != NULL && + msg != NULL) + { + // Protocol Discriminator and EPS Bearer ID + *msg_ptr = (deact_eps_bearer_context_req->eps_bearer_id << 4) | (LIBLTE_MME_PD_EPS_SESSION_MANAGEMENT); + msg_ptr++; + + // Procedure Transaction ID + *msg_ptr = deact_eps_bearer_context_req->proc_transaction_id; + msg_ptr++; + + // Message Type + *msg_ptr = LIBLTE_MME_MSG_TYPE_DEACTIVATE_EPS_BEARER_CONTEXT_REQUEST; + msg_ptr++; + + // ESM Cause + liblte_mme_pack_esm_cause_ie(deact_eps_bearer_context_req->esm_cause, &msg_ptr); + + // Protocol Configuration Options + if(deact_eps_bearer_context_req->protocol_cnfg_opts_present) + { + *msg_ptr = LIBLTE_MME_PROTOCOL_CONFIGURATION_OPTIONS_IEI; + msg_ptr++; + liblte_mme_pack_protocol_config_options_ie(&deact_eps_bearer_context_req->protocol_cnfg_opts, &msg_ptr); + } + + // Fill in the number of bytes used + msg->N_bytes = msg_ptr - msg->msg; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_deactivate_eps_bearer_context_request_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_DEACTIVATE_EPS_BEARER_CONTEXT_REQUEST_MSG_STRUCT *deact_eps_bearer_context_req) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(msg != NULL && + deact_eps_bearer_context_req != NULL) + { + // EPS Bearer ID + deact_eps_bearer_context_req->eps_bearer_id = (*msg_ptr >> 4); + msg_ptr++; + + // Procedure Transaction ID + deact_eps_bearer_context_req->proc_transaction_id = *msg_ptr; + msg_ptr++; + + // Skip Message Type + msg_ptr++; + + // ESM Cause + liblte_mme_unpack_esm_cause_ie(&msg_ptr, &deact_eps_bearer_context_req->esm_cause); + + // Protocol Configuration Options + if(LIBLTE_MME_PROTOCOL_CONFIGURATION_OPTIONS_IEI == *msg_ptr) + { + msg_ptr++; + liblte_mme_unpack_protocol_config_options_ie(&msg_ptr, &deact_eps_bearer_context_req->protocol_cnfg_opts); + deact_eps_bearer_context_req->protocol_cnfg_opts_present = true; + }else{ + deact_eps_bearer_context_req->protocol_cnfg_opts_present = false; + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + Message Name: ESM Information Request + + Description: Sent by the network to the UE to request the UE to + provide ESM information, i.e. protocol configuration + options or APN or both. + + Document Reference: 24.301 v10.2.0 Section 8.3.13 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_esm_information_request_msg(LIBLTE_MME_ESM_INFORMATION_REQUEST_MSG_STRUCT *esm_info_req, + LIBLTE_BYTE_MSG_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(esm_info_req != NULL && + msg != NULL) + { + // Protocol Discriminator and EPS Bearer ID + *msg_ptr = (esm_info_req->eps_bearer_id << 4) | (LIBLTE_MME_PD_EPS_SESSION_MANAGEMENT); + msg_ptr++; + + // Procedure Transaction ID + *msg_ptr = esm_info_req->proc_transaction_id; + msg_ptr++; + + // Message Type + *msg_ptr = LIBLTE_MME_MSG_TYPE_ESM_INFORMATION_REQUEST; + msg_ptr++; + + // Fill in the number of bytes used + msg->N_bytes = msg_ptr - msg->msg; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_esm_information_request_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_ESM_INFORMATION_REQUEST_MSG_STRUCT *esm_info_req) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(msg != NULL && + esm_info_req != NULL) + { + // EPS Bearer ID + esm_info_req->eps_bearer_id = (*msg_ptr >> 4); + msg_ptr++; + + // Procedure Transaction ID + esm_info_req->proc_transaction_id = *msg_ptr; + msg_ptr++; + + // Skip Message Type + msg_ptr++; + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + Message Name: ESM Information Response + + Description: Sent by the UE to the network in response to an ESM + INFORMATION REQUEST message and provides the + requested ESM information. + + Document Reference: 24.301 v10.2.0 Section 8.3.14 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_esm_information_response_msg(LIBLTE_MME_ESM_INFORMATION_RESPONSE_MSG_STRUCT *esm_info_resp, + LIBLTE_BYTE_MSG_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(esm_info_resp != NULL && + msg != NULL) + { + // Protocol Discriminator and EPS Bearer ID + *msg_ptr = (esm_info_resp->eps_bearer_id << 4) | (LIBLTE_MME_PD_EPS_SESSION_MANAGEMENT); + msg_ptr++; + + // Procedure Transaction ID + *msg_ptr = esm_info_resp->proc_transaction_id; + msg_ptr++; + + // Message Type + *msg_ptr = LIBLTE_MME_MSG_TYPE_ESM_INFORMATION_RESPONSE; + msg_ptr++; + + // Access Point Name + if(esm_info_resp->apn_present) + { + *msg_ptr = LIBLTE_MME_ACCESS_POINT_NAME_IEI; + msg_ptr++; + liblte_mme_pack_access_point_name_ie(&esm_info_resp->apn, &msg_ptr); + } + + // Protocol Configuration Options + if(esm_info_resp->protocol_cnfg_opts_present) + { + *msg_ptr = LIBLTE_MME_PROTOCOL_CONFIGURATION_OPTIONS_IEI; + msg_ptr++; + liblte_mme_pack_protocol_config_options_ie(&esm_info_resp->protocol_cnfg_opts, &msg_ptr); + } + + // Fill in the number of bytes used + msg->N_bytes = msg_ptr - msg->msg; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_esm_information_response_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_ESM_INFORMATION_RESPONSE_MSG_STRUCT *esm_info_resp) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(msg != NULL && + esm_info_resp != NULL) + { + // EPS Bearer ID + esm_info_resp->eps_bearer_id = (*msg_ptr >> 4); + msg_ptr++; + + // Procedure Transaction ID + esm_info_resp->proc_transaction_id = *msg_ptr; + msg_ptr++; + + // Skip Message Type + msg_ptr++; + + // Access Point Name + if(LIBLTE_MME_ACCESS_POINT_NAME_IEI == *msg_ptr) + { + msg_ptr++; + liblte_mme_unpack_access_point_name_ie(&msg_ptr, &esm_info_resp->apn); + esm_info_resp->apn_present = true; + }else{ + esm_info_resp->apn_present = false; + } + + // Protocol Configuration Options + if(LIBLTE_MME_PROTOCOL_CONFIGURATION_OPTIONS_IEI == *msg_ptr) + { + msg_ptr++; + liblte_mme_unpack_protocol_config_options_ie(&msg_ptr, &esm_info_resp->protocol_cnfg_opts); + esm_info_resp->protocol_cnfg_opts_present = true; + }else{ + esm_info_resp->protocol_cnfg_opts_present = false; + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + Message Name: ESM Status + + Description: Sent by the network or the UE to pass information on + the status of the indicated EPS bearer context and + report certain error conditions. + + Document Reference: 24.301 v10.2.0 Section 8.3.15 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_esm_status_msg(LIBLTE_MME_ESM_STATUS_MSG_STRUCT *esm_status, + LIBLTE_BYTE_MSG_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(esm_status != NULL && + msg != NULL) + { + // Protocol Discriminator and EPS Bearer ID + *msg_ptr = (esm_status->eps_bearer_id << 4) | (LIBLTE_MME_PD_EPS_SESSION_MANAGEMENT); + msg_ptr++; + + // Procedure Transaction ID + *msg_ptr = esm_status->proc_transaction_id; + msg_ptr++; + + // Message Type + *msg_ptr = LIBLTE_MME_MSG_TYPE_ESM_STATUS; + msg_ptr++; + + // ESM Cause + liblte_mme_pack_esm_cause_ie(esm_status->esm_cause, &msg_ptr); + + // Fill in the number of bytes used + msg->N_bytes = msg_ptr - msg->msg; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_esm_status_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_ESM_STATUS_MSG_STRUCT *esm_status) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(msg != NULL && + esm_status != NULL) + { + // EPS Bearer ID + esm_status->eps_bearer_id = (*msg_ptr >> 4); + msg_ptr++; + + // Procedure Transaction ID + esm_status->proc_transaction_id = *msg_ptr; + msg_ptr++; + + // Skip Message Type + msg_ptr++; + + // ESM Cause + liblte_mme_unpack_esm_cause_ie(&msg_ptr, &esm_status->esm_cause); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + Message Name: Modify EPS Bearer Context Accept + + Description: Sent by the UE to the network to acknowledge the + modification of an active EPS bearer context. + + Document Reference: 24.301 v10.2.0 Section 8.3.16 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_modify_eps_bearer_context_accept_msg(LIBLTE_MME_MODIFY_EPS_BEARER_CONTEXT_ACCEPT_MSG_STRUCT *mod_eps_bearer_context_accept, + LIBLTE_BYTE_MSG_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(mod_eps_bearer_context_accept != NULL && + msg != NULL) + { + // Protocol Discriminator and EPS Bearer ID + *msg_ptr = (mod_eps_bearer_context_accept->eps_bearer_id << 4) | (LIBLTE_MME_PD_EPS_SESSION_MANAGEMENT); + msg_ptr++; + + // Procedure Transaction ID + *msg_ptr = mod_eps_bearer_context_accept->proc_transaction_id; + msg_ptr++; + + // Message Type + *msg_ptr = LIBLTE_MME_MSG_TYPE_MODIFY_EPS_BEARER_CONTEXT_ACCEPT; + msg_ptr++; + + // Protocol Configuration Options + if(mod_eps_bearer_context_accept->protocol_cnfg_opts_present) + { + *msg_ptr = LIBLTE_MME_PROTOCOL_CONFIGURATION_OPTIONS_IEI; + msg_ptr++; + liblte_mme_pack_protocol_config_options_ie(&mod_eps_bearer_context_accept->protocol_cnfg_opts, &msg_ptr); + } + + // Fill in the number of bytes used + msg->N_bytes = msg_ptr - msg->msg; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_modify_eps_bearer_context_accept_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_MODIFY_EPS_BEARER_CONTEXT_ACCEPT_MSG_STRUCT *mod_eps_bearer_context_accept) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(msg != NULL && + mod_eps_bearer_context_accept != NULL) + { + // EPS Bearer ID + mod_eps_bearer_context_accept->eps_bearer_id = (*msg_ptr >> 4); + msg_ptr++; + + // Procedure Transaction ID + mod_eps_bearer_context_accept->proc_transaction_id = *msg_ptr; + msg_ptr++; + + // Skip Message Type + msg_ptr++; + + // Protocol Configuration Options + if(LIBLTE_MME_PROTOCOL_CONFIGURATION_OPTIONS_IEI == *msg_ptr) + { + msg_ptr++; + liblte_mme_unpack_protocol_config_options_ie(&msg_ptr, &mod_eps_bearer_context_accept->protocol_cnfg_opts); + mod_eps_bearer_context_accept->protocol_cnfg_opts_present = true; + }else{ + mod_eps_bearer_context_accept->protocol_cnfg_opts_present = false; + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + Message Name: Modify EPS Bearer Context Reject + + Description: Sent by the UE or the network to reject a + modification of an active EPS bearer context. + + Document Reference: 24.301 v10.2.0 Section 8.3.17 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_modify_eps_bearer_context_reject_msg(LIBLTE_MME_MODIFY_EPS_BEARER_CONTEXT_REJECT_MSG_STRUCT *mod_eps_bearer_context_rej, + LIBLTE_BYTE_MSG_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(mod_eps_bearer_context_rej != NULL && + msg != NULL) + { + // Protocol Discriminator and EPS Bearer ID + *msg_ptr = (mod_eps_bearer_context_rej->eps_bearer_id << 4) | (LIBLTE_MME_PD_EPS_SESSION_MANAGEMENT); + msg_ptr++; + + // Procedure Transaction ID + *msg_ptr = mod_eps_bearer_context_rej->proc_transaction_id; + msg_ptr++; + + // Message Type + *msg_ptr = LIBLTE_MME_MSG_TYPE_MODIFY_EPS_BEARER_CONTEXT_REJECT; + msg_ptr++; + + // ESM Cause + liblte_mme_pack_esm_cause_ie(mod_eps_bearer_context_rej->esm_cause, &msg_ptr); + + // Protocol Configuration Options + if(mod_eps_bearer_context_rej->protocol_cnfg_opts_present) + { + *msg_ptr = LIBLTE_MME_PROTOCOL_CONFIGURATION_OPTIONS_IEI; + msg_ptr++; + liblte_mme_pack_protocol_config_options_ie(&mod_eps_bearer_context_rej->protocol_cnfg_opts, &msg_ptr); + } + + // Fill in the number of bytes used + msg->N_bytes = msg_ptr - msg->msg; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_modify_eps_bearer_context_reject_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_MODIFY_EPS_BEARER_CONTEXT_REJECT_MSG_STRUCT *mod_eps_bearer_context_rej) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(msg != NULL && + mod_eps_bearer_context_rej != NULL) + { + // EPS Bearer ID + mod_eps_bearer_context_rej->eps_bearer_id = (*msg_ptr >> 4); + msg_ptr++; + + // Procedure Transaction ID + mod_eps_bearer_context_rej->proc_transaction_id = *msg_ptr; + msg_ptr++; + + // Skip Message Type + msg_ptr++; + + // ESM Cause + liblte_mme_unpack_esm_cause_ie(&msg_ptr, &mod_eps_bearer_context_rej->esm_cause); + + // Protocol Configuration Options + if(LIBLTE_MME_PROTOCOL_CONFIGURATION_OPTIONS_IEI == *msg_ptr) + { + msg_ptr++; + liblte_mme_unpack_protocol_config_options_ie(&msg_ptr, &mod_eps_bearer_context_rej->protocol_cnfg_opts); + mod_eps_bearer_context_rej->protocol_cnfg_opts_present = true; + }else{ + mod_eps_bearer_context_rej->protocol_cnfg_opts_present = false; + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + Message Name: Modify EPS Bearer Context Request + + Description: Sent by the network to the UE to request modification + of an active EPS bearer context. + + Document Reference: 24.301 v10.2.0 Section 8.3.18 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_modify_eps_bearer_context_request_msg(LIBLTE_MME_MODIFY_EPS_BEARER_CONTEXT_REQUEST_MSG_STRUCT *mod_eps_bearer_context_req, + LIBLTE_BYTE_MSG_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(mod_eps_bearer_context_req != NULL && + msg != NULL) + { + // Protocol Discriminator and EPS Bearer ID + *msg_ptr = (mod_eps_bearer_context_req->eps_bearer_id << 4) | (LIBLTE_MME_PD_EPS_SESSION_MANAGEMENT); + msg_ptr++; + + // Procedure Transaction ID + *msg_ptr = mod_eps_bearer_context_req->proc_transaction_id; + msg_ptr++; + + // Message Type + *msg_ptr = LIBLTE_MME_MSG_TYPE_MODIFY_EPS_BEARER_CONTEXT_REQUEST; + msg_ptr++; + + // New EPS QoS + if(mod_eps_bearer_context_req->new_eps_qos_present) + { + *msg_ptr = LIBLTE_MME_EPS_QUALITY_OF_SERVICE_IEI; + msg_ptr++; + liblte_mme_pack_eps_quality_of_service_ie(&mod_eps_bearer_context_req->new_eps_qos, &msg_ptr); + } + + // TFT + if(mod_eps_bearer_context_req->tft_present) + { + *msg_ptr = LIBLTE_MME_TRAFFIC_FLOW_TEMPLATE_IEI; + msg_ptr++; + liblte_mme_pack_traffic_flow_template_ie(&mod_eps_bearer_context_req->tft, &msg_ptr); + } + + // New QoS + if(mod_eps_bearer_context_req->new_qos_present) + { + *msg_ptr = LIBLTE_MME_QUALITY_OF_SERVICE_IEI; + msg_ptr++; + liblte_mme_pack_quality_of_service_ie(&mod_eps_bearer_context_req->new_qos, &msg_ptr); + } + + // Negotiated LLC SAPI + if(mod_eps_bearer_context_req->negotiated_llc_sapi_present) + { + *msg_ptr = LIBLTE_MME_LLC_SAPI_IEI; + msg_ptr++; + liblte_mme_pack_llc_service_access_point_identifier_ie(mod_eps_bearer_context_req->negotiated_llc_sapi, &msg_ptr); + } + + // Radio Priority + if(mod_eps_bearer_context_req->radio_prio_present) + { + *msg_ptr = LIBLTE_MME_RADIO_PRIORITY_IEI << 4; + liblte_mme_pack_radio_priority_ie(mod_eps_bearer_context_req->radio_prio, 0, &msg_ptr); + msg_ptr++; + } + + // Packet Flow Identifier + if(mod_eps_bearer_context_req->packet_flow_id_present) + { + *msg_ptr = LIBLTE_MME_PACKET_FLOW_IDENTIFIER_IEI; + msg_ptr++; + liblte_mme_pack_packet_flow_identifier_ie(mod_eps_bearer_context_req->packet_flow_id, &msg_ptr); + } + + // APN-AMBR + if(mod_eps_bearer_context_req->apn_ambr_present) + { + *msg_ptr = LIBLTE_MME_APN_AMBR_IEI; + msg_ptr++; + liblte_mme_pack_apn_aggregate_maximum_bit_rate_ie(&mod_eps_bearer_context_req->apn_ambr, &msg_ptr); + } + + // Protocol Configuration Options + if(mod_eps_bearer_context_req->protocol_cnfg_opts_present) + { + *msg_ptr = LIBLTE_MME_PROTOCOL_CONFIGURATION_OPTIONS_IEI; + msg_ptr++; + liblte_mme_pack_protocol_config_options_ie(&mod_eps_bearer_context_req->protocol_cnfg_opts, &msg_ptr); + } + + // Fill in the number of bytes used + msg->N_bytes = msg_ptr - msg->msg; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_modify_eps_bearer_context_request_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_MODIFY_EPS_BEARER_CONTEXT_REQUEST_MSG_STRUCT *mod_eps_bearer_context_req) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(msg != NULL && + mod_eps_bearer_context_req != NULL) + { + // EPS Bearer ID + mod_eps_bearer_context_req->eps_bearer_id = (*msg_ptr >> 4); + msg_ptr++; + + // Procedure Transaction ID + mod_eps_bearer_context_req->proc_transaction_id = *msg_ptr; + msg_ptr++; + + // Skip Message Type + msg_ptr++; + + // New EPS QoS + if(LIBLTE_MME_EPS_QUALITY_OF_SERVICE_IEI == *msg_ptr) + { + msg_ptr++; + liblte_mme_unpack_eps_quality_of_service_ie(&msg_ptr, &mod_eps_bearer_context_req->new_eps_qos); + mod_eps_bearer_context_req->new_eps_qos_present = true; + }else{ + mod_eps_bearer_context_req->new_eps_qos_present = false; + } + + // TFT + if(LIBLTE_MME_TRAFFIC_FLOW_TEMPLATE_IEI == *msg_ptr) + { + msg_ptr++; + liblte_mme_unpack_traffic_flow_template_ie(&msg_ptr, &mod_eps_bearer_context_req->tft); + mod_eps_bearer_context_req->tft_present = true; + }else{ + mod_eps_bearer_context_req->tft_present = false; + } + + // New QoS + if(LIBLTE_MME_QUALITY_OF_SERVICE_IEI == *msg_ptr) + { + msg_ptr++; + liblte_mme_unpack_quality_of_service_ie(&msg_ptr, &mod_eps_bearer_context_req->new_qos); + mod_eps_bearer_context_req->new_qos_present = true; + }else{ + mod_eps_bearer_context_req->new_qos_present = false; + } + + // Negotiated LLC SAPI + if(LIBLTE_MME_LLC_SAPI_IEI == *msg_ptr) + { + msg_ptr++; + liblte_mme_unpack_llc_service_access_point_identifier_ie(&msg_ptr, &mod_eps_bearer_context_req->negotiated_llc_sapi); + mod_eps_bearer_context_req->negotiated_llc_sapi_present = true; + }else{ + mod_eps_bearer_context_req->negotiated_llc_sapi_present = false; + } + + // Radio Priority + if((LIBLTE_MME_RADIO_PRIORITY_IEI << 4) == *msg_ptr) + { + liblte_mme_unpack_radio_priority_ie(&msg_ptr, 0, &mod_eps_bearer_context_req->radio_prio); + msg_ptr++; + mod_eps_bearer_context_req->radio_prio_present = true; + }else{ + mod_eps_bearer_context_req->radio_prio_present = false; + } + + // Packet Flow Identifier + if(LIBLTE_MME_PACKET_FLOW_IDENTIFIER_IEI == *msg_ptr) + { + msg_ptr++; + liblte_mme_unpack_packet_flow_identifier_ie(&msg_ptr, &mod_eps_bearer_context_req->packet_flow_id); + mod_eps_bearer_context_req->packet_flow_id_present = true; + }else{ + mod_eps_bearer_context_req->packet_flow_id_present = false; + } + + // APN-AMBR + if(LIBLTE_MME_APN_AMBR_IEI == *msg_ptr) + { + msg_ptr++; + liblte_mme_unpack_apn_aggregate_maximum_bit_rate_ie(&msg_ptr, &mod_eps_bearer_context_req->apn_ambr); + mod_eps_bearer_context_req->apn_ambr_present = true; + }else{ + mod_eps_bearer_context_req->apn_ambr_present = false; + } + + // Protocol Configuration Options + if(LIBLTE_MME_PROTOCOL_CONFIGURATION_OPTIONS_IEI == *msg_ptr) + { + msg_ptr++; + liblte_mme_unpack_protocol_config_options_ie(&msg_ptr, &mod_eps_bearer_context_req->protocol_cnfg_opts); + mod_eps_bearer_context_req->protocol_cnfg_opts_present = true; + }else{ + mod_eps_bearer_context_req->protocol_cnfg_opts_present = false; + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + Message Name: Notification + + Description: Sent by the network to inform the UE about events + which are relevant for the upper layer using an EPS + bearer context or having requested a procedure + transaction. + + Document Reference: 24.301 v10.2.0 Section 8.3.18A +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_notification_msg(LIBLTE_MME_NOTIFICATION_MSG_STRUCT *notification, + LIBLTE_BYTE_MSG_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(notification != NULL && + msg != NULL) + { + // Protocol Discriminator and EPS Bearer ID + *msg_ptr = (notification->eps_bearer_id << 4) | (LIBLTE_MME_PD_EPS_SESSION_MANAGEMENT); + msg_ptr++; + + // Procedure Transaction ID + *msg_ptr = notification->proc_transaction_id; + msg_ptr++; + + // Message Type + *msg_ptr = LIBLTE_MME_MSG_TYPE_NOTIFICATION; + msg_ptr++; + + // Notification Indicator + liblte_mme_pack_notification_indicator_ie(notification->notification_ind, &msg_ptr); + + // Fill in the number of bytes used + msg->N_bytes = msg_ptr - msg->msg; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_notification_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_NOTIFICATION_MSG_STRUCT *notification) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(msg != NULL && + notification != NULL) + { + // EPS Bearer ID + notification->eps_bearer_id = (*msg_ptr >> 4); + msg_ptr++; + + // Procedure Transaction ID + notification->proc_transaction_id = *msg_ptr; + msg_ptr++; + + // Skip Message Type + msg_ptr++; + + // Notification Indicator + liblte_mme_unpack_notification_indicator_ie(&msg_ptr, ¬ification->notification_ind); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + Message Name: PDN Connectivity Reject + + Description: Sent by the network to the UE to reject establishment + of a PDN connection. + + Document Reference: 24.301 v10.2.0 Section 8.3.19 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_pdn_connectivity_reject_msg(LIBLTE_MME_PDN_CONNECTIVITY_REJECT_MSG_STRUCT *pdn_con_rej, + LIBLTE_BYTE_MSG_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(pdn_con_rej != NULL && + msg != NULL) + { + // Protocol Discriminator and EPS Bearer ID + *msg_ptr = (pdn_con_rej->eps_bearer_id << 4) | (LIBLTE_MME_PD_EPS_SESSION_MANAGEMENT); + msg_ptr++; + + // Procedure Transaction ID + *msg_ptr = pdn_con_rej->proc_transaction_id; + msg_ptr++; + + // Message Type + *msg_ptr = LIBLTE_MME_MSG_TYPE_PDN_CONNECTIVITY_REJECT; + msg_ptr++; + + // ESM Cause + liblte_mme_pack_esm_cause_ie(pdn_con_rej->esm_cause, &msg_ptr); + + // Protocol Configuration Options + if(pdn_con_rej->protocol_cnfg_opts_present) + { + *msg_ptr = LIBLTE_MME_PROTOCOL_CONFIGURATION_OPTIONS_IEI; + msg_ptr++; + liblte_mme_pack_protocol_config_options_ie(&pdn_con_rej->protocol_cnfg_opts, &msg_ptr); + } + + // T3496 Value + if(pdn_con_rej->t3496_present) + { + *msg_ptr = LIBLTE_MME_T3496_VALUE_IEI; + msg_ptr++; + liblte_mme_pack_gprs_timer_3_ie(&pdn_con_rej->t3496, &msg_ptr); + } + + // Fill in the number of bytes used + msg->N_bytes = msg_ptr - msg->msg; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_pdn_connectivity_reject_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_PDN_CONNECTIVITY_REJECT_MSG_STRUCT *pdn_con_rej) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(msg != NULL && + pdn_con_rej != NULL) + { + // EPS Bearer ID + pdn_con_rej->eps_bearer_id = (*msg_ptr >> 4); + msg_ptr++; + + // Procedure Transaction ID + pdn_con_rej->proc_transaction_id = *msg_ptr; + msg_ptr++; + + // Skip Message Type + msg_ptr++; + + // ESM Cause + liblte_mme_unpack_esm_cause_ie(&msg_ptr, &pdn_con_rej->esm_cause); + + // Protocol Configuration Options + if(LIBLTE_MME_PROTOCOL_CONFIGURATION_OPTIONS_IEI == *msg_ptr) + { + msg_ptr++; + liblte_mme_unpack_protocol_config_options_ie(&msg_ptr, &pdn_con_rej->protocol_cnfg_opts); + pdn_con_rej->protocol_cnfg_opts_present = true; + }else{ + pdn_con_rej->protocol_cnfg_opts_present = false; + } + + // T3496 Value + if(LIBLTE_MME_T3496_VALUE_IEI == *msg_ptr) + { + msg_ptr++; + liblte_mme_unpack_gprs_timer_3_ie(&msg_ptr, &pdn_con_rej->t3496); + pdn_con_rej->t3496_present = true; + }else{ + pdn_con_rej->t3496_present = false; + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + Message Name: PDN Connectivity Request + + Description: Sent by the UE to the network to initiate + establishment of a PDN connection. + + Document Reference: 24.301 v10.2.0 Section 8.3.20 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_pdn_connectivity_request_msg(LIBLTE_MME_PDN_CONNECTIVITY_REQUEST_MSG_STRUCT *pdn_con_req, + LIBLTE_BYTE_MSG_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(pdn_con_req != NULL && + msg != NULL) + { + // Protocol Discriminator and EPS Bearer ID + *msg_ptr = (pdn_con_req->eps_bearer_id << 4) | (LIBLTE_MME_PD_EPS_SESSION_MANAGEMENT); + msg_ptr++; + + // Procedure Transaction ID + *msg_ptr = pdn_con_req->proc_transaction_id; + msg_ptr++; + + // Message Type + *msg_ptr = LIBLTE_MME_MSG_TYPE_PDN_CONNECTIVITY_REQUEST; + msg_ptr++; + + // Request Type & PDN Type + *msg_ptr = 0; + liblte_mme_pack_request_type_ie(pdn_con_req->request_type, 0, &msg_ptr); + liblte_mme_pack_pdn_type_ie(pdn_con_req->pdn_type, 4, &msg_ptr); + msg_ptr++; + + // ESM Information Transfer Flag + if(pdn_con_req->esm_info_transfer_flag_present) + { + *msg_ptr = LIBLTE_MME_ESM_INFO_TRANSFER_FLAG_IEI << 4; + liblte_mme_pack_esm_info_transfer_flag_ie(pdn_con_req->esm_info_transfer_flag, 0, &msg_ptr); + msg_ptr++; + } + + // Access Point Name + if(pdn_con_req->apn_present) + { + *msg_ptr = LIBLTE_MME_ACCESS_POINT_NAME_IEI; + msg_ptr++; + liblte_mme_pack_access_point_name_ie(&pdn_con_req->apn, &msg_ptr); + } + + // Protocol Configuration Options + if(pdn_con_req->protocol_cnfg_opts_present) + { + *msg_ptr = LIBLTE_MME_PROTOCOL_CONFIGURATION_OPTIONS_IEI; + msg_ptr++; + liblte_mme_pack_protocol_config_options_ie(&pdn_con_req->protocol_cnfg_opts, &msg_ptr); + } + + // Device Properties + if(pdn_con_req->device_properties_present) + { + *msg_ptr = LIBLTE_MME_PDN_CONNECTIVITY_REQUEST_DEVICE_PROPERTIES_IEI << 4; + liblte_mme_pack_device_properties_ie(pdn_con_req->device_properties, 0, &msg_ptr); + msg_ptr++; + } + + // Fill in the number of bytes used + msg->N_bytes = msg_ptr - msg->msg; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_pdn_connectivity_request_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_PDN_CONNECTIVITY_REQUEST_MSG_STRUCT *pdn_con_req) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(msg != NULL && + pdn_con_req != NULL) + { + // EPS Bearer ID + pdn_con_req->eps_bearer_id = (*msg_ptr >> 4); + msg_ptr++; + + // Procedure Transaction ID + pdn_con_req->proc_transaction_id = *msg_ptr; + msg_ptr++; + + // Skip Message Type + msg_ptr++; + + // Request Type & PDN Type + liblte_mme_unpack_request_type_ie(&msg_ptr, 0, &pdn_con_req->request_type); + liblte_mme_unpack_pdn_type_ie(&msg_ptr, 4, &pdn_con_req->pdn_type); + msg_ptr++; + + // ESM Information Transfer Flag + if((LIBLTE_MME_ESM_INFO_TRANSFER_FLAG_IEI << 4) == (*msg_ptr & 0xF0)) + { + liblte_mme_unpack_esm_info_transfer_flag_ie(&msg_ptr, 0, &pdn_con_req->esm_info_transfer_flag); + msg_ptr++; + pdn_con_req->esm_info_transfer_flag_present = true; + }else{ + pdn_con_req->esm_info_transfer_flag_present = false; + } + + // Access Point Name + if(LIBLTE_MME_ACCESS_POINT_NAME_IEI == *msg_ptr) + { + msg_ptr++; + liblte_mme_unpack_access_point_name_ie(&msg_ptr, &pdn_con_req->apn); + pdn_con_req->apn_present = true; + }else{ + pdn_con_req->apn_present = false; + } + + // Protocol Configuration Options + if(LIBLTE_MME_PROTOCOL_CONFIGURATION_OPTIONS_IEI == *msg_ptr) + { + msg_ptr++; + liblte_mme_unpack_protocol_config_options_ie(&msg_ptr, &pdn_con_req->protocol_cnfg_opts); + pdn_con_req->protocol_cnfg_opts_present = true; + }else{ + pdn_con_req->protocol_cnfg_opts_present = false; + } + + // Device Properties + if((LIBLTE_MME_PDN_CONNECTIVITY_REQUEST_DEVICE_PROPERTIES_IEI << 4) == (*msg_ptr & 0xF0)) + { + liblte_mme_unpack_device_properties_ie(&msg_ptr, 0, &pdn_con_req->device_properties); + msg_ptr++; + pdn_con_req->device_properties_present = true; + }else{ + pdn_con_req->device_properties_present = false; + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + Message Name: PDN Disconnect Reject + + Description: Sent by the network to the UE to reject release of a + PDN connection. + + Document Reference: 24.301 v10.2.0 Section 8.3.21 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_pdn_disconnect_reject_msg(LIBLTE_MME_PDN_DISCONNECT_REJECT_MSG_STRUCT *pdn_discon_rej, + LIBLTE_BYTE_MSG_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(pdn_discon_rej != NULL && + msg != NULL) + { + // Protocol Discriminator and EPS Bearer ID + *msg_ptr = (pdn_discon_rej->eps_bearer_id << 4) | (LIBLTE_MME_PD_EPS_SESSION_MANAGEMENT); + msg_ptr++; + + // Procedure Transaction ID + *msg_ptr = pdn_discon_rej->proc_transaction_id; + msg_ptr++; + + // Message Type + *msg_ptr = LIBLTE_MME_MSG_TYPE_PDN_DISCONNECT_REJECT; + msg_ptr++; + + // ESM Cause + liblte_mme_pack_esm_cause_ie(pdn_discon_rej->esm_cause, &msg_ptr); + + // Protocol Configuration Options + if(pdn_discon_rej->protocol_cnfg_opts_present) + { + *msg_ptr = LIBLTE_MME_PROTOCOL_CONFIGURATION_OPTIONS_IEI; + msg_ptr++; + liblte_mme_pack_protocol_config_options_ie(&pdn_discon_rej->protocol_cnfg_opts, &msg_ptr); + } + + // Fill in the number of bytes used + msg->N_bytes = msg_ptr - msg->msg; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_pdn_disconnect_reject_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_PDN_DISCONNECT_REJECT_MSG_STRUCT *pdn_discon_rej) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(msg != NULL && + pdn_discon_rej != NULL) + { + // EPS Bearer ID + pdn_discon_rej->eps_bearer_id = (*msg_ptr >> 4); + msg_ptr++; + + // Procedure Transaction ID + pdn_discon_rej->proc_transaction_id = *msg_ptr; + msg_ptr++; + + // Skip Message Type + msg_ptr++; + + // ESM Cause + liblte_mme_unpack_esm_cause_ie(&msg_ptr, &pdn_discon_rej->esm_cause); + + // Protocol Configuration Options + if(LIBLTE_MME_PROTOCOL_CONFIGURATION_OPTIONS_IEI == *msg_ptr) + { + msg_ptr++; + liblte_mme_unpack_protocol_config_options_ie(&msg_ptr, &pdn_discon_rej->protocol_cnfg_opts); + pdn_discon_rej->protocol_cnfg_opts_present = true; + }else{ + pdn_discon_rej->protocol_cnfg_opts_present = false; + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + Message Name: PDN Disconnect Request + + Description: Sent by the UE to the network to initiate release of + a PDN connection. + + Document Reference: 24.301 v10.2.0 Section 8.3.22 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_mme_pack_pdn_disconnect_request_msg(LIBLTE_MME_PDN_DISCONNECT_REQUEST_MSG_STRUCT *pdn_discon_req, + LIBLTE_BYTE_MSG_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(pdn_discon_req != NULL && + msg != NULL) + { + // Protocol Discriminator and EPS Bearer ID + *msg_ptr = (pdn_discon_req->eps_bearer_id << 4) | (LIBLTE_MME_PD_EPS_SESSION_MANAGEMENT); + msg_ptr++; + + // Procedure Transaction ID + *msg_ptr = pdn_discon_req->proc_transaction_id; + msg_ptr++; + + // Message Type + *msg_ptr = LIBLTE_MME_MSG_TYPE_PDN_DISCONNECT_REQUEST; + msg_ptr++; + + // Linked EPS Bearer Identity & Spare Half Octet + *msg_ptr = 0; + liblte_mme_pack_linked_eps_bearer_identity_ie(pdn_discon_req->linked_eps_bearer_id, 0, &msg_ptr); + msg_ptr++; + + // Protocol Configuration Options + if(pdn_discon_req->protocol_cnfg_opts_present) + { + *msg_ptr = LIBLTE_MME_PROTOCOL_CONFIGURATION_OPTIONS_IEI; + msg_ptr++; + liblte_mme_pack_protocol_config_options_ie(&pdn_discon_req->protocol_cnfg_opts, &msg_ptr); + } + + // Fill in the number of bytes used + msg->N_bytes = msg_ptr - msg->msg; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_mme_unpack_pdn_disconnect_request_msg(LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_MME_PDN_DISCONNECT_REQUEST_MSG_STRUCT *pdn_discon_req) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(msg != NULL && + pdn_discon_req != NULL) + { + // EPS Bearer ID + pdn_discon_req->eps_bearer_id = (*msg_ptr >> 4); + msg_ptr++; + + // Procedure Transaction ID + pdn_discon_req->proc_transaction_id = *msg_ptr; + msg_ptr++; + + // Skip Message Type + msg_ptr++; + + // Linked EPS Bearer Identity & Spare Half Octet + liblte_mme_unpack_linked_eps_bearer_identity_ie(&msg_ptr, 0, &pdn_discon_req->linked_eps_bearer_id); + msg_ptr++; + + // Protocol Configuration Options + if(LIBLTE_MME_PROTOCOL_CONFIGURATION_OPTIONS_IEI == *msg_ptr) + { + msg_ptr++; + liblte_mme_unpack_protocol_config_options_ie(&msg_ptr, &pdn_discon_req->protocol_cnfg_opts); + pdn_discon_req->protocol_cnfg_opts_present = true; + }else{ + pdn_discon_req->protocol_cnfg_opts_present = false; + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} diff --git a/lib/src/asn1/liblte_rrc.cc b/lib/src/asn1/liblte_rrc.cc new file mode 100644 index 000000000..3bfa4a540 --- /dev/null +++ b/lib/src/asn1/liblte_rrc.cc @@ -0,0 +1,13676 @@ +/******************************************************************************* + + Copyright 2012-2014 Ben Wojtowicz + Copyright 2014 Andrew Murphy (SIB13 unpack) + + This program 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. + + This program 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. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + +******************************************************************************* + + File: liblte_rrc.cc + + Description: Contains all the implementations for the LTE Radio Resource + Control Layer library. + + Revision History + ---------- ------------- -------------------------------------------- + 03/24/2012 Ben Wojtowicz Created file. + 04/25/2012 Ben Wojtowicz Added SIB1 parameters, IEs, and messages + 06/02/2012 Ben Wojtowicz Added message and IE packing + 06/09/2012 Ben Wojtowicz Added the number of bits used to SIB1 pack + 08/19/2012 Ben Wojtowicz Added functionality to support SIB2, SIB3, + SIB4, and SIB8 packing and unpacking + 10/06/2012 Ben Wojtowicz Added more decoding/encoding. + 11/10/2012 Ben Wojtowicz Filled in the N_bits for SI messages + 03/03/2013 Ben Wojtowicz Added carrier_freqs_geran, SIB5, SIB6, SIB7 + and paging packing and unpacking. + 07/21/2013 Ben Wojtowicz Fixed several bugs and moved to the common + message struct. + 09/16/2013 Ben Wojtowicz Added error checking on sizes passed to + memcpy. + 03/26/2014 Ben Wojtowicz Added support for RRC Connection Request, + RRC Connection Reestablishment Request, + and UL CCCH Messages. + 05/04/2014 Ben Wojtowicz Added support for DL CCCH Messages. + 06/15/2014 Ben Wojtowicz Added support for UL DCCH Messages. + 08/03/2014 Ben Wojtowicz Added more decoding/encoding and using the + common value_2_bits and bits_2_value + functions. + 09/19/2014 Andrew Murphy Added SIB13 unpack. + 11/01/2014 Ben Wojtowicz Added more decoding/encoding. + 11/09/2014 Ben Wojtowicz Added SIB13 pack. + 11/29/2014 Ben Wojtowicz Fixed a bug in RRC connection reestablishment + UE identity. + +*******************************************************************************/ + +/******************************************************************************* + INCLUDES +*******************************************************************************/ + +#include "srslte/asn1/liblte_rrc.h" + +#include +#include +#include + +/******************************************************************************* + DEFINES +*******************************************************************************/ + + +/******************************************************************************* + TYPEDEFS +*******************************************************************************/ + + +/******************************************************************************* + GLOBAL VARIABLES +*******************************************************************************/ + +LIBLTE_BIT_MSG_STRUCT global_msg; + +/******************************************************************************* + HELPERS +*******************************************************************************/ + +/********************************************************************* + Functions for external logging +*********************************************************************/ +static log_handler_t log_handler; +static void *callback_ctx = NULL; + +void liblte_rrc_log_register_handler(void *ctx, log_handler_t handler) { + log_handler = handler; + callback_ctx = ctx; +} + +static void liblte_rrc_log_print(const char *format, ...) { + va_list args; + va_start(args, format); + if (log_handler) { + char *args_msg = NULL; + if(vasprintf(&args_msg, format, args) > 0) { + log_handler(callback_ctx, args_msg); + } + if (args_msg) { + free(args_msg); + } + } else { + vprintf(format, args); + } + va_end(args); +} + +/********************************************************************* + Description: Simply consume non-critical extensions for rel > r8 +*********************************************************************/ +void liblte_rrc_consume_noncrit_extension(bool ext, const char *func_name, uint8 **ie_ptr) +{ + uint32 i=0; + uint32 elem_flags=0; + uint32 elem_len=0; + + if (ext) { + uint8 n_elems = liblte_bits_2_value(ie_ptr, 7) + 1; + for(i=0; i> 1; + } + if (func_name) { + liblte_rrc_log_print("Detected an extension in RRC function: %s\n", func_name); + } + } +} + +void liblte_rrc_warning_not_handled(bool opt, const char *func_name) +{ + if (opt) { + liblte_rrc_log_print("Unhandled feature in RRC function: %s\n\n", func_name?func_name:"Unknown"); + } +} + +/******************************************************************************* + INFORMATION ELEMENT FUNCTIONS +*******************************************************************************/ + +/********************************************************************* + IE Name: MBSFN Notification Config + + Description: Specifies the MBMS notification related configuration + parameters, that are applicable for all MBSFN areas + + Document Reference: 36.331 v10.0.0 Section 6.3.7 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_mbsfn_notification_config_ie(LIBLTE_RRC_MBSFN_NOTIFICATION_CONFIG_STRUCT *mbsfn_notification_cnfg, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(mbsfn_notification_cnfg != NULL && + ie_ptr != NULL) + { + liblte_value_2_bits(mbsfn_notification_cnfg->repetition_coeff, ie_ptr, 1); + liblte_value_2_bits(mbsfn_notification_cnfg->offset, ie_ptr, 4); + liblte_value_2_bits(mbsfn_notification_cnfg->sf_index - 1, ie_ptr, 3); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_mbsfn_notification_config_ie(uint8 **ie_ptr, + LIBLTE_RRC_MBSFN_NOTIFICATION_CONFIG_STRUCT *mbsfn_notification_cnfg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + mbsfn_notification_cnfg != NULL) + { + mbsfn_notification_cnfg->repetition_coeff = (LIBLTE_RRC_NOTIFICATION_REPETITION_COEFF_R9_ENUM)liblte_bits_2_value(ie_ptr, 1); + mbsfn_notification_cnfg->offset = liblte_bits_2_value(ie_ptr, 4); + mbsfn_notification_cnfg->sf_index = liblte_bits_2_value(ie_ptr, 3) + 1; + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: MBSFN Area Info List + + Description: Contains the information required to acquire the MBMS + control information associated with one or more MBSFN + areas + + Document Reference: 36.331 v10.0.0 Section 6.3.7 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_mbsfn_area_info_ie(LIBLTE_RRC_MBSFN_AREA_INFO_STRUCT *mbsfn_area_info, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(mbsfn_area_info != NULL && + ie_ptr != NULL) + { + // Extension indicator + liblte_value_2_bits(0, ie_ptr, 1); + + liblte_value_2_bits(mbsfn_area_info->mbsfn_area_id_r9, ie_ptr, 8); + liblte_value_2_bits(mbsfn_area_info->non_mbsfn_region_length, ie_ptr, 1); + liblte_value_2_bits(mbsfn_area_info->notification_indicator_r9, ie_ptr, 3); + liblte_value_2_bits(mbsfn_area_info->mcch_repetition_period_r9, ie_ptr, 2); + liblte_value_2_bits(mbsfn_area_info->mcch_offset_r9, ie_ptr, 4); + liblte_value_2_bits(mbsfn_area_info->mcch_modification_period_r9, ie_ptr, 1); + liblte_value_2_bits(mbsfn_area_info->sf_alloc_info_r9, ie_ptr, 6); + liblte_value_2_bits(mbsfn_area_info->signalling_mcs_r9, ie_ptr, 2); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_mbsfn_area_info_ie(uint8 **ie_ptr, + LIBLTE_RRC_MBSFN_AREA_INFO_STRUCT *mbsfn_area_info) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + bool ext; + + if(ie_ptr != NULL && + mbsfn_area_info != NULL) + { + // Extension indicator + ext = liblte_bits_2_value(ie_ptr, 1); + + mbsfn_area_info->mbsfn_area_id_r9 = liblte_bits_2_value(ie_ptr, 8); + mbsfn_area_info->non_mbsfn_region_length = (LIBLTE_RRC_NON_MBSFN_REGION_LENGTH_ENUM)liblte_bits_2_value(ie_ptr, 1); + mbsfn_area_info->notification_indicator_r9 = liblte_bits_2_value(ie_ptr, 3); + mbsfn_area_info->mcch_repetition_period_r9 = (LIBLTE_RRC_MCCH_REPETITION_PERIOD_ENUM)liblte_bits_2_value(ie_ptr, 2); + mbsfn_area_info->mcch_offset_r9 = liblte_bits_2_value(ie_ptr, 4); + mbsfn_area_info->mcch_modification_period_r9 = (LIBLTE_RRC_MCCH_MODIFICATION_PERIOD_ENUM)liblte_bits_2_value(ie_ptr, 1); + mbsfn_area_info->sf_alloc_info_r9 = liblte_bits_2_value(ie_ptr, 6); + mbsfn_area_info->signalling_mcs_r9 = (LIBLTE_RRC_MCCH_SIGNALLING_MCS_ENUM)liblte_bits_2_value(ie_ptr, 2); + + liblte_rrc_consume_noncrit_extension(ext, __func__, ie_ptr); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: MBSFN Subframe Config + + Description: Defines subframes that are reserved for MBSFN in + downlink + + Document Reference: 36.331 v10.0.0 Section 6.3.7 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_mbsfn_subframe_config_ie(LIBLTE_RRC_MBSFN_SUBFRAME_CONFIG_STRUCT *mbsfn_subfr_cnfg, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(mbsfn_subfr_cnfg != NULL && + ie_ptr != NULL) + { + liblte_value_2_bits(mbsfn_subfr_cnfg->radio_fr_alloc_period, ie_ptr, 3); + liblte_value_2_bits(mbsfn_subfr_cnfg->radio_fr_alloc_offset, ie_ptr, 3); + liblte_value_2_bits(mbsfn_subfr_cnfg->subfr_alloc_num_frames, ie_ptr, 1); + if(LIBLTE_RRC_SUBFRAME_ALLOCATION_NUM_FRAMES_ONE == mbsfn_subfr_cnfg->subfr_alloc_num_frames) + { + liblte_value_2_bits(mbsfn_subfr_cnfg->subfr_alloc, ie_ptr, 6); + }else{ + liblte_value_2_bits(mbsfn_subfr_cnfg->subfr_alloc, ie_ptr, 24); + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_mbsfn_subframe_config_ie(uint8 **ie_ptr, + LIBLTE_RRC_MBSFN_SUBFRAME_CONFIG_STRUCT *mbsfn_subfr_cnfg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + mbsfn_subfr_cnfg != NULL) + { + mbsfn_subfr_cnfg->radio_fr_alloc_period = (LIBLTE_RRC_RADIO_FRAME_ALLOCATION_PERIOD_ENUM)liblte_bits_2_value(ie_ptr, 3); + mbsfn_subfr_cnfg->radio_fr_alloc_offset = liblte_bits_2_value(ie_ptr, 3); + mbsfn_subfr_cnfg->subfr_alloc_num_frames = (LIBLTE_RRC_SUBFRAME_ALLOCATION_NUM_FRAMES_ENUM)liblte_bits_2_value(ie_ptr, 1); + if(LIBLTE_RRC_SUBFRAME_ALLOCATION_NUM_FRAMES_ONE == mbsfn_subfr_cnfg->subfr_alloc_num_frames) + { + mbsfn_subfr_cnfg->subfr_alloc = liblte_bits_2_value(ie_ptr, 6); + }else{ + mbsfn_subfr_cnfg->subfr_alloc = liblte_bits_2_value(ie_ptr, 24); + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: PMCH Info List + + Description: Specifies configuration of all PMCHs of an MBSFN area + + Document Reference: 36.331 v10.0.0 Section 6.3.7 +*********************************************************************/ +// FIXME + +/********************************************************************* + IE Name: C-RNTI + + Description: Identifies a UE having a RRC connection within a cell + + Document Reference: 36.331 v10.0.0 Section 6.3.6 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_c_rnti_ie(uint16 rnti, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL) + { + liblte_value_2_bits(rnti, ie_ptr, 16); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_c_rnti_ie(uint8 **ie_ptr, + uint16 *rnti) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + rnti != NULL) + { + *rnti = liblte_bits_2_value(ie_ptr, 16); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Dedicated Info CDMA2000 + + Description: Transfers UE specific CDMA2000 information between + the network and the UE + + Document Reference: 36.331 v10.0.0 Section 6.3.6 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_dedicated_info_cdma2000_ie(LIBLTE_SIMPLE_BYTE_MSG_STRUCT *ded_info_cdma2000, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint32 i; + + if(ded_info_cdma2000 != NULL && + ie_ptr != NULL) + { + if(ded_info_cdma2000->N_bytes < 128) + { + liblte_value_2_bits(0, ie_ptr, 1); + liblte_value_2_bits(ded_info_cdma2000->N_bytes, ie_ptr, 7); + }else if(ded_info_cdma2000->N_bytes < 16383){ + liblte_value_2_bits(1, ie_ptr, 1); + liblte_value_2_bits(0, ie_ptr, 1); + liblte_value_2_bits(ded_info_cdma2000->N_bytes, ie_ptr, 14); + }else{ + // FIXME: Unlikely to have more than 16K of octets + } + + for(i=0; iN_bytes; i++) + { + liblte_value_2_bits(ded_info_cdma2000->msg[i], ie_ptr, 8); + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_dedicated_info_cdma2000_ie(uint8 **ie_ptr, + LIBLTE_SIMPLE_BYTE_MSG_STRUCT *ded_info_cdma2000) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint32 i; + + if(ie_ptr != NULL && + ded_info_cdma2000 != NULL) + { + if(0 == liblte_bits_2_value(ie_ptr, 1)) + { + ded_info_cdma2000->N_bytes = liblte_bits_2_value(ie_ptr, 7); + }else{ + if(0 == liblte_bits_2_value(ie_ptr, 1)) + { + ded_info_cdma2000->N_bytes = liblte_bits_2_value(ie_ptr, 14); + }else{ + // FIXME: Unlikely to have more than 16K of octets + ded_info_cdma2000->N_bytes = 0; + } + } + + for(i=0; iN_bytes; i++) + { + ded_info_cdma2000->msg[i] = liblte_bits_2_value(ie_ptr, 8); + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Dedicated Info NAS + + Description: Transfers UE specific NAS layer information between + the network and the UE + + Document Reference: 36.331 v10.0.0 Section 6.3.6 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_dedicated_info_nas_ie(LIBLTE_SIMPLE_BYTE_MSG_STRUCT *ded_info_nas, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint32 i; + + if(ded_info_nas != NULL && + ie_ptr != NULL) + { + if(ded_info_nas->N_bytes < 128) + { + liblte_value_2_bits(0, ie_ptr, 1); + liblte_value_2_bits(ded_info_nas->N_bytes, ie_ptr, 7); + }else if(ded_info_nas->N_bytes < 16383){ + liblte_value_2_bits(1, ie_ptr, 1); + liblte_value_2_bits(0, ie_ptr, 1); + liblte_value_2_bits(ded_info_nas->N_bytes, ie_ptr, 14); + }else{ + // FIXME: Unlikely to have more than 16K of octets + } + + for(i=0; iN_bytes; i++) + { + liblte_value_2_bits(ded_info_nas->msg[i], ie_ptr, 8); + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_dedicated_info_nas_ie(uint8 **ie_ptr, + LIBLTE_SIMPLE_BYTE_MSG_STRUCT *ded_info_nas) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint32 i; + + if(ie_ptr != NULL && + ded_info_nas != NULL) + { + if(0 == liblte_bits_2_value(ie_ptr, 1)) + { + ded_info_nas->N_bytes = liblte_bits_2_value(ie_ptr, 7); + }else{ + if(0 == liblte_bits_2_value(ie_ptr, 1)) + { + ded_info_nas->N_bytes = liblte_bits_2_value(ie_ptr, 14); + }else{ + // FIXME: Unlikely to have more than 16K of octets + ded_info_nas->N_bytes = 0; + } + } + + for(i=0; iN_bytes; i++) + { + ded_info_nas->msg[i] = liblte_bits_2_value(ie_ptr, 8); + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Filter Coefficient + + Description: Specifies the measurement filtering coefficient + + Document Reference: 36.331 v10.0.0 Section 6.3.6 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_filter_coefficient_ie(LIBLTE_RRC_FILTER_COEFFICIENT_ENUM filter_coeff, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL) + { + // Extension indicator + liblte_value_2_bits(0, ie_ptr, 1); + + liblte_value_2_bits(filter_coeff, ie_ptr, 4); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_filter_coefficient_ie(uint8 **ie_ptr, + LIBLTE_RRC_FILTER_COEFFICIENT_ENUM *filter_coeff) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + filter_coeff != NULL) + { + // Extension indicator + bool ext = liblte_bits_2_value(ie_ptr, 1); + + *filter_coeff = (LIBLTE_RRC_FILTER_COEFFICIENT_ENUM)liblte_bits_2_value(ie_ptr, 4); + + liblte_rrc_consume_noncrit_extension(ext, __func__, ie_ptr); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: MMEC + + Description: Identifies an MME within the scope of an MME group + within a PLMN + + Document Reference: 36.331 v10.0.0 Section 6.3.6 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_mmec_ie(uint8 mmec, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL) + { + liblte_value_2_bits(mmec, ie_ptr, 8); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_mmec_ie(uint8 **ie_ptr, + uint8 *mmec) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + mmec != NULL) + { + *mmec = liblte_bits_2_value(ie_ptr, 8); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Neigh Cell Config + + Description: Provides the information related to MBSFN and TDD + UL/DL configuration of neighbor cells + + Document Reference: 36.331 v10.0.0 Section 6.3.6 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_neigh_cell_config_ie(uint8 neigh_cell_config, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL) + { + liblte_value_2_bits(neigh_cell_config, ie_ptr, 2); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_neigh_cell_config_ie(uint8 **ie_ptr, + uint8 *neigh_cell_config) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + neigh_cell_config != NULL) + { + *neigh_cell_config = liblte_bits_2_value(ie_ptr, 2); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Other Config + + Description: Contains configuration related to other configuration + + Document Reference: 36.331 v10.0.0 Section 6.3.6 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_other_config_ie(LIBLTE_RRC_OTHER_CONFIG_R9_STRUCT *other_cnfg, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(other_cnfg != NULL && + ie_ptr != NULL) + { + // Extension indicator + liblte_value_2_bits(0, ie_ptr, 1); + + // Optional indicator + liblte_value_2_bits(other_cnfg->report_proximity_cnfg_present, ie_ptr, 1); + + if(true == other_cnfg->report_proximity_cnfg_present) + { + // Optional indicators + liblte_value_2_bits(other_cnfg->report_proximity_cnfg.report_proximity_ind_eutra_present, ie_ptr, 1); + liblte_value_2_bits(other_cnfg->report_proximity_cnfg.report_proximity_ind_utra_present, ie_ptr, 1); + + if(true == other_cnfg->report_proximity_cnfg.report_proximity_ind_eutra_present) + { + liblte_value_2_bits(other_cnfg->report_proximity_cnfg.report_proximity_ind_eutra, ie_ptr, 1); + } + + if(true == other_cnfg->report_proximity_cnfg.report_proximity_ind_utra_present) + { + liblte_value_2_bits(other_cnfg->report_proximity_cnfg.report_proximity_ind_utra, ie_ptr, 1); + } + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_other_config_ie(uint8 **ie_ptr, + LIBLTE_RRC_OTHER_CONFIG_R9_STRUCT *other_cnfg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + other_cnfg != NULL) + { + // Extension indicator + bool ext = liblte_bits_2_value(ie_ptr, 1); + + // Optional indicator + other_cnfg->report_proximity_cnfg_present = liblte_bits_2_value(ie_ptr, 1); + + if(true == other_cnfg->report_proximity_cnfg_present) + { + // Optional indicators + other_cnfg->report_proximity_cnfg.report_proximity_ind_eutra_present = liblte_bits_2_value(ie_ptr, 1); + other_cnfg->report_proximity_cnfg.report_proximity_ind_utra_present = liblte_bits_2_value(ie_ptr, 1); + + if(true == other_cnfg->report_proximity_cnfg.report_proximity_ind_eutra_present) + { + other_cnfg->report_proximity_cnfg.report_proximity_ind_eutra = (LIBLTE_RRC_REPORT_PROXIMITY_INDICATION_EUTRA_R9_ENUM)liblte_bits_2_value(ie_ptr, 1); + } + + if(true == other_cnfg->report_proximity_cnfg.report_proximity_ind_utra_present) + { + other_cnfg->report_proximity_cnfg.report_proximity_ind_utra = (LIBLTE_RRC_REPORT_PROXIMITY_INDICATION_UTRA_R9_ENUM)liblte_bits_2_value(ie_ptr, 1); + } + } + + liblte_rrc_consume_noncrit_extension(ext, __func__, ie_ptr); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: RAND CDMA2000 (1xRTT) + + Description: Contains a random value, generated by the eNB, to be + passed to the CDMA2000 upper layers + + Document Reference: 36.331 v10.0.0 Section 6.3.6 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_rand_cdma2000_1xrtt_ie(uint32 rand, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL) + { + liblte_value_2_bits(rand, ie_ptr, 32); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_rand_cdma2000_1xrtt_ie(uint8 **ie_ptr, + uint32 *rand) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + rand != NULL) + { + *rand = liblte_bits_2_value(ie_ptr, 32); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: RAT Type + + Description: Indicates the radio access technology (RAT), + including E-UTRA, of the requested/transferred UE + capabilities + + Document Reference: 36.331 v10.0.0 Section 6.3.6 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_rat_type_ie(LIBLTE_RRC_RAT_TYPE_ENUM rat_type, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL) + { + // Extension indicator + liblte_value_2_bits(0, ie_ptr, 1); + + liblte_value_2_bits(rat_type, ie_ptr, 3); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_rat_type_ie(uint8 **ie_ptr, + LIBLTE_RRC_RAT_TYPE_ENUM *rat_type) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + rat_type != NULL) + { + // Extension indicator + bool ext = liblte_bits_2_value(ie_ptr, 1); + + *rat_type = (LIBLTE_RRC_RAT_TYPE_ENUM)liblte_bits_2_value(ie_ptr, 3); + + liblte_rrc_consume_noncrit_extension(ext, __func__, ie_ptr); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: RRC Transaction Identifier + + Description: Identifies an RRC procedure along with the message + type + + Document Reference: 36.331 v10.0.0 Section 6.3.6 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_rrc_transaction_identifier_ie(uint8 rrc_transaction_id, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL) + { + liblte_value_2_bits(rrc_transaction_id, ie_ptr, 2); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_rrc_transaction_identifier_ie(uint8 **ie_ptr, + uint8 *rrc_transaction_id) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + rrc_transaction_id != NULL) + { + *rrc_transaction_id = liblte_bits_2_value(ie_ptr, 2); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: S-TMSI + + Description: Contains an S-Temporary Mobile Subscriber Identity, + a temporary UE identity provided by the EPC which + uniquely identifies the UE within the tracking area + + Document Reference: 36.331 v10.0.0 Section 6.3.6 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_s_tmsi_ie(LIBLTE_RRC_S_TMSI_STRUCT *s_tmsi, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(s_tmsi != NULL && + ie_ptr != NULL) + { + liblte_rrc_pack_mmec_ie(s_tmsi->mmec, ie_ptr); + liblte_value_2_bits(s_tmsi->m_tmsi, ie_ptr, 32); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_s_tmsi_ie(uint8 **ie_ptr, + LIBLTE_RRC_S_TMSI_STRUCT *s_tmsi) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + s_tmsi != NULL) + { + liblte_rrc_unpack_mmec_ie(ie_ptr, &s_tmsi->mmec); + s_tmsi->m_tmsi = liblte_bits_2_value(ie_ptr, 32); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: UE Capability RAT Container List + + Description: Contains list of containers, one for each RAT for + which UE capabilities are transferred + + Document Reference: 36.331 v10.0.0 Section 6.3.6 +*********************************************************************/ +// FIXME + +/********************************************************************* + IE Name: UE EUTRA Capability + + Description: Conveys the E-UTRA UE Radio Access Capability + Parameters + + Document Reference: 36.331 v10.0.0 Section 6.3.6 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_pdcp_params_ie(LIBLTE_RRC_PDCP_PARAMS_STRUCT *pdcp_params, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint32 i; + + if(pdcp_params != NULL && + ie_ptr != NULL) + { + // Extension indicator + liblte_value_2_bits(0, ie_ptr, 1); + + // Max ROHC CTXTS default? + liblte_value_2_bits(pdcp_params->max_rohc_ctxts_present, ie_ptr, 1); + + // Supported ROHC Profiles + for(i=0; i<9; i++) + { + liblte_value_2_bits(pdcp_params->supported_rohc_profiles[i], ie_ptr, 1); + } + + if(pdcp_params->max_rohc_ctxts_present) + { + liblte_value_2_bits(pdcp_params->max_rohc_ctxts, ie_ptr, 4); + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +LIBLTE_ERROR_ENUM liblte_rrc_unpack_pdcp_params_ie(uint8 **ie_ptr, + LIBLTE_RRC_PDCP_PARAMS_STRUCT *pdcp_params) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint32 i; + + if(ie_ptr != NULL && + pdcp_params != NULL) + { + // Extension indicator + bool ext = liblte_bits_2_value(ie_ptr, 1); + + // Max ROHC CTXTS default? + pdcp_params->max_rohc_ctxts_present = liblte_bits_2_value(ie_ptr, 1); + + // Supported ROHC Profiles + for(i=0; i<9; i++) + { + pdcp_params->supported_rohc_profiles[i] = liblte_bits_2_value(ie_ptr, 1); + } + + if(pdcp_params->max_rohc_ctxts_present) + { + pdcp_params->max_rohc_ctxts = (LIBLTE_RRC_MAX_ROHC_CTXTS_ENUM)liblte_bits_2_value(ie_ptr, 4); + } + + liblte_rrc_consume_noncrit_extension(ext, __func__, ie_ptr); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +LIBLTE_ERROR_ENUM liblte_rrc_pack_phy_layer_params_ie(LIBLTE_RRC_PHY_LAYER_PARAMS_STRUCT *params, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(params != NULL && + ie_ptr != NULL) + { + liblte_value_2_bits(params->tx_antenna_selection_supported, ie_ptr, 1); + liblte_value_2_bits(params->specific_ref_sigs_supported, ie_ptr, 1); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +LIBLTE_ERROR_ENUM liblte_rrc_unpack_phy_layer_params_ie(uint8 **ie_ptr, + LIBLTE_RRC_PHY_LAYER_PARAMS_STRUCT *params) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + params != NULL) + { + params->tx_antenna_selection_supported = liblte_bits_2_value(ie_ptr, 1); + params->specific_ref_sigs_supported = liblte_bits_2_value(ie_ptr, 1); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +LIBLTE_ERROR_ENUM liblte_rrc_pack_rf_params_ie(LIBLTE_RRC_RF_PARAMS_STRUCT *params, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint32 i; + + if(params != NULL && + ie_ptr != NULL) + { + liblte_value_2_bits(params->N_supported_band_eutras-1, ie_ptr, 6); + for(i=0; iN_supported_band_eutras; i++) + { + liblte_value_2_bits(params->supported_band_eutra[i].band_eutra-1, ie_ptr, 6); + liblte_value_2_bits(params->supported_band_eutra[i].half_duplex, ie_ptr, 1); + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +LIBLTE_ERROR_ENUM liblte_rrc_unpack_rf_params_ie(uint8 **ie_ptr, + LIBLTE_RRC_RF_PARAMS_STRUCT *params) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint32 i; + + if(ie_ptr != NULL && + params != NULL) + { + params->N_supported_band_eutras = liblte_bits_2_value(ie_ptr, 6) + 1; + for(i=0; iN_supported_band_eutras; i++) + { + params->supported_band_eutra[i].band_eutra = liblte_bits_2_value(ie_ptr, 6) + 1; + params->supported_band_eutra[i].half_duplex = liblte_bits_2_value(ie_ptr, 1); + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +LIBLTE_ERROR_ENUM liblte_rrc_pack_band_info_eutra_ie(LIBLTE_RRC_BAND_INFO_EUTRA_STRUCT *info, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint32 i; + + if(info != NULL && + ie_ptr != NULL) + { + // Option indicator + liblte_value_2_bits(0, ie_ptr, 1); + + liblte_value_2_bits(info->N_inter_freq_need_for_gaps-1, ie_ptr, 6); + for(i=0; iN_inter_freq_need_for_gaps; i++) + { + liblte_value_2_bits(info->inter_freq_need_for_gaps[i], ie_ptr, 1); + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +LIBLTE_ERROR_ENUM liblte_rrc_unpack_band_info_eutra_ie(uint8 **ie_ptr, + LIBLTE_RRC_BAND_INFO_EUTRA_STRUCT *info) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint32 i; + + if(ie_ptr != NULL && + info != NULL) + { + // Option indicator + liblte_bits_2_value(ie_ptr, 1); + + info->N_inter_freq_need_for_gaps = liblte_bits_2_value(ie_ptr, 6) + 1; + for(i=0; iN_inter_freq_need_for_gaps; i++) + { + info->inter_freq_need_for_gaps[i] = liblte_bits_2_value(ie_ptr, 1); + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +LIBLTE_ERROR_ENUM liblte_rrc_pack_meas_params_ie(LIBLTE_RRC_MEAS_PARAMS_STRUCT *params, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint32 i; + + if(params != NULL && + ie_ptr != NULL) + { + liblte_value_2_bits(params->N_band_list_eutra-1, ie_ptr, 6); + for(i=0; iN_band_list_eutra; i++) + { + liblte_rrc_pack_band_info_eutra_ie(¶ms->band_list_eutra[i], ie_ptr); + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +LIBLTE_ERROR_ENUM liblte_rrc_unpack_meas_params_ie(uint8 **ie_ptr, + LIBLTE_RRC_MEAS_PARAMS_STRUCT *params) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint32 i; + + if(ie_ptr != NULL && + params != NULL) + { + params->N_band_list_eutra = liblte_bits_2_value(ie_ptr, 6) + 1; + for(i=0; iN_band_list_eutra; i++) + { + liblte_rrc_unpack_band_info_eutra_ie(ie_ptr, ¶ms->band_list_eutra[i]); + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +LIBLTE_ERROR_ENUM liblte_rrc_pack_inter_rat_params_ie(LIBLTE_RRC_INTER_RAT_PARAMS_STRUCT *params, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(params != NULL && + ie_ptr != NULL) + { + // WARNING: Hardcoding all options to not present + liblte_value_2_bits(0, ie_ptr, 7); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_inter_rat_params_ie(uint8 **ie_ptr, + LIBLTE_RRC_INTER_RAT_PARAMS_STRUCT *params) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint32 i; + + if(ie_ptr != NULL && + params != NULL) + { + // WARNING: Hardcoding all options to not present + params->utra_fdd_present = false; + params->utra_tdd128_present = false; + params->utra_tdd384_present = false; + params->utra_tdd768_present = false; + params->geran_present = false; + params->cdma2000_hrpd_present = false; + params->cdma2000_1xrtt_present = false; + err = LIBLTE_SUCCESS; + } + + return(err); +} + +LIBLTE_ERROR_ENUM liblte_rrc_pack_ue_eutra_capability_ie(LIBLTE_RRC_UE_EUTRA_CAPABILITY_STRUCT *ue_eutra_capability, + LIBLTE_BIT_MSG_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(ue_eutra_capability != NULL && + msg != NULL) + { + // Option indicator - featureGroupIndicators + liblte_value_2_bits(ue_eutra_capability->feature_group_indicator_present, &msg_ptr, 1); + + // Option indicator - nonCriticalExtension + liblte_value_2_bits(0, &msg_ptr, 1); + + // Option indicator - access stratum release enum + liblte_value_2_bits(0, &msg_ptr, 1); + liblte_value_2_bits(ue_eutra_capability->access_stratum_release, &msg_ptr, 3); + + liblte_value_2_bits(ue_eutra_capability->ue_category - 1, &msg_ptr, 3); + liblte_rrc_pack_pdcp_params_ie(&ue_eutra_capability->pdcp_params, &msg_ptr); + liblte_rrc_pack_phy_layer_params_ie(&ue_eutra_capability->phy_params, &msg_ptr); + liblte_rrc_pack_rf_params_ie(&ue_eutra_capability->rf_params, &msg_ptr); + liblte_rrc_pack_meas_params_ie(&ue_eutra_capability->meas_params, &msg_ptr); + if(ue_eutra_capability->feature_group_indicator_present) + liblte_value_2_bits(ue_eutra_capability->feature_group_indicator, &msg_ptr, 32); + liblte_rrc_pack_inter_rat_params_ie(&ue_eutra_capability->inter_rat_params, &msg_ptr); + + // Fill in the number of bits used + msg->N_bits = msg_ptr - msg->msg; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_ue_eutra_capability_ie(uint8 **ie_ptr, + LIBLTE_RRC_UE_EUTRA_CAPABILITY_STRUCT *ue_eutra_capability) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ue_eutra_capability != NULL && + ie_ptr != NULL) + { + // Option indicator - featureGroupIndicators + ue_eutra_capability->feature_group_indicator_present = liblte_bits_2_value(ie_ptr, 1); + + // Option indicator - nonCriticalExtension + bool ext = liblte_bits_2_value(ie_ptr, 1); + + // Option indicator - access stratum release enum + liblte_bits_2_value(ie_ptr, 1); + ue_eutra_capability->access_stratum_release = liblte_bits_2_value(ie_ptr, 3); + + ue_eutra_capability->ue_category = liblte_bits_2_value(ie_ptr, 3) + 1; + liblte_rrc_unpack_pdcp_params_ie(ie_ptr, &ue_eutra_capability->pdcp_params); + liblte_rrc_unpack_phy_layer_params_ie(ie_ptr, &ue_eutra_capability->phy_params); + liblte_rrc_unpack_rf_params_ie(ie_ptr, &ue_eutra_capability->rf_params); + liblte_rrc_unpack_meas_params_ie(ie_ptr, &ue_eutra_capability->meas_params); + if(ue_eutra_capability->feature_group_indicator_present) + ue_eutra_capability->feature_group_indicator = liblte_bits_2_value(ie_ptr, 32); + liblte_rrc_unpack_inter_rat_params_ie(ie_ptr, &ue_eutra_capability->inter_rat_params); + + liblte_rrc_consume_noncrit_extension(ext, __func__, ie_ptr); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + + + +/********************************************************************* + IE Name: UE Timers and Constants + + Description: Contains timers and constants used by the UE in + either RRC_CONNECTED or RRC_IDLE + + Document Reference: 36.331 v10.0.0 Section 6.3.6 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_ue_timers_and_constants_ie(LIBLTE_RRC_UE_TIMERS_AND_CONSTANTS_STRUCT *ue_timers_and_constants, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ue_timers_and_constants != NULL && + ie_ptr != NULL) + { + // Extension indicator + liblte_value_2_bits(0, ie_ptr, 1); + + liblte_value_2_bits(ue_timers_and_constants->t300, ie_ptr, 3); + liblte_value_2_bits(ue_timers_and_constants->t301, ie_ptr, 3); + liblte_value_2_bits(ue_timers_and_constants->t310, ie_ptr, 3); + liblte_value_2_bits(ue_timers_and_constants->n310, ie_ptr, 3); + liblte_value_2_bits(ue_timers_and_constants->t311, ie_ptr, 3); + liblte_value_2_bits(ue_timers_and_constants->n311, ie_ptr, 3); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_ue_timers_and_constants_ie(uint8 **ie_ptr, + LIBLTE_RRC_UE_TIMERS_AND_CONSTANTS_STRUCT *ue_timers_and_constants) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + ue_timers_and_constants != NULL) + { + // Extension indicator + bool ext = liblte_bits_2_value(ie_ptr, 1); + + ue_timers_and_constants->t300 = (LIBLTE_RRC_T300_ENUM)liblte_bits_2_value(ie_ptr, 3); + ue_timers_and_constants->t301 = (LIBLTE_RRC_T301_ENUM)liblte_bits_2_value(ie_ptr, 3); + ue_timers_and_constants->t310 = (LIBLTE_RRC_T310_ENUM)liblte_bits_2_value(ie_ptr, 3); + ue_timers_and_constants->n310 = (LIBLTE_RRC_N310_ENUM)liblte_bits_2_value(ie_ptr, 3); + ue_timers_and_constants->t311 = (LIBLTE_RRC_T311_ENUM)liblte_bits_2_value(ie_ptr, 3); + ue_timers_and_constants->n311 = (LIBLTE_RRC_N311_ENUM)liblte_bits_2_value(ie_ptr, 3); + + liblte_rrc_consume_noncrit_extension(ext, __func__, ie_ptr); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Allowed Meas Bandwidth + + Description: Indicates the maximum allowed measurement bandwidth + on a carrier frequency as defined by the parameter + Transmission Bandwidth Configuration + + Document Reference: 36.331 v10.0.0 Section 6.3.5 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_allowed_meas_bandwidth_ie(LIBLTE_RRC_ALLOWED_MEAS_BANDWIDTH_ENUM allowed_meas_bw, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL) + { + liblte_value_2_bits(allowed_meas_bw, ie_ptr, 3); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_allowed_meas_bandwidth_ie(uint8 **ie_ptr, + LIBLTE_RRC_ALLOWED_MEAS_BANDWIDTH_ENUM *allowed_meas_bw) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + allowed_meas_bw != NULL) + { + *allowed_meas_bw = (LIBLTE_RRC_ALLOWED_MEAS_BANDWIDTH_ENUM)liblte_bits_2_value(ie_ptr, 3); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Hysteresis + + Description: Used within the entry and leave condition of an + event triggered reporting condition + + Document Reference: 36.331 v10.0.0 Section 6.3.5 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_hysteresis_ie(uint8 hysteresis, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL) + { + // FIXME: Convert from actual value + liblte_value_2_bits(hysteresis, ie_ptr, 5); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_hysteresis_ie(uint8 **ie_ptr, + uint8 *hysteresis) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + hysteresis != NULL) + { + // FIXME: Convert to actual value + *hysteresis = liblte_bits_2_value(ie_ptr, 5); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Location Info + + Description: Transfers location information available at the UE to + correlate measurements and UE position information + + Document Reference: 36.331 v10.0.0 Section 6.3.5 +*********************************************************************/ +// FIXME + +/********************************************************************* + IE Name: Meas Config + + Description: Specifies measurements to be performed by the UE, + and covers intra-frequency, inter-frequency and + inter-RAT mobility as well as configuration of + measurement gaps + + Document Reference: 36.331 v10.0.0 Section 6.3.5 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_meas_config_ie(LIBLTE_RRC_MEAS_CONFIG_STRUCT *meas_cnfg, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint32 i; + + if(meas_cnfg != NULL && + ie_ptr != NULL) + { + // Extension indicator + liblte_value_2_bits(0, ie_ptr, 1); + + // Optional indicators + if(meas_cnfg->N_meas_obj_to_remove) + { + liblte_value_2_bits(1, ie_ptr, 1); + }else{ + liblte_value_2_bits(0, ie_ptr, 1); + } + liblte_value_2_bits(meas_cnfg->meas_obj_to_add_mod_list_present, ie_ptr, 1); + if(meas_cnfg->N_rep_cnfg_to_remove) + { + liblte_value_2_bits(1, ie_ptr, 1); + }else{ + liblte_value_2_bits(0, ie_ptr, 1); + } + liblte_value_2_bits(meas_cnfg->rep_cnfg_to_add_mod_list_present, ie_ptr, 1); + if(meas_cnfg->N_meas_id_to_remove) + { + liblte_value_2_bits(1, ie_ptr, 1); + }else{ + liblte_value_2_bits(0, ie_ptr, 1); + } + liblte_value_2_bits(meas_cnfg->meas_id_to_add_mod_list_present, ie_ptr, 1); + liblte_value_2_bits(meas_cnfg->quantity_cnfg_present, ie_ptr, 1); + liblte_value_2_bits(meas_cnfg->meas_gap_cnfg_present, ie_ptr, 1); + liblte_value_2_bits(meas_cnfg->s_meas_present, ie_ptr, 1); + liblte_value_2_bits(meas_cnfg->pre_reg_info_hrpd_present, ie_ptr, 1); + liblte_value_2_bits(meas_cnfg->speed_state_params_present, ie_ptr, 1); + + // Meas Object To Remove List + if(0 != meas_cnfg->N_meas_obj_to_remove) + { + liblte_value_2_bits(meas_cnfg->N_meas_obj_to_remove - 1, ie_ptr, 5); + } + for(i=0; iN_meas_obj_to_remove; i++) + { + liblte_rrc_pack_meas_object_id_ie(meas_cnfg->meas_obj_to_remove_list[i], ie_ptr); + } + + // Meas Object To Add Mod List + if(meas_cnfg->meas_obj_to_add_mod_list_present) + { + liblte_rrc_pack_meas_object_to_add_mod_list_ie(&meas_cnfg->meas_obj_to_add_mod_list, ie_ptr); + } + + // Report Config To Remove List + if(0 != meas_cnfg->N_rep_cnfg_to_remove) + { + liblte_value_2_bits(meas_cnfg->N_rep_cnfg_to_remove - 1, ie_ptr, 5); + } + for(i=0; iN_rep_cnfg_to_remove; i++) + { + liblte_rrc_pack_report_config_id_ie(meas_cnfg->rep_cnfg_to_remove_list[i], ie_ptr); + } + + // Report Config To Add Mod List + if(meas_cnfg->rep_cnfg_to_add_mod_list_present) + { + liblte_rrc_pack_report_config_to_add_mod_list_ie(&meas_cnfg->rep_cnfg_to_add_mod_list, ie_ptr); + } + + // Meas ID To Remove List + if(0 != meas_cnfg->N_meas_id_to_remove) + { + liblte_value_2_bits(meas_cnfg->N_meas_id_to_remove - 1, ie_ptr, 5); + } + for(i=0; iN_meas_id_to_remove; i++) + { + liblte_rrc_pack_meas_id_ie(meas_cnfg->meas_id_to_remove_list[i], ie_ptr); + } + + // Meas ID To Add Mod List + if(meas_cnfg->meas_id_to_add_mod_list_present) + { + liblte_rrc_pack_meas_id_to_add_mod_list_ie(&meas_cnfg->meas_id_to_add_mod_list, ie_ptr); + } + + // Quantity Config + if(meas_cnfg->quantity_cnfg_present) + { + liblte_rrc_pack_quantity_config_ie(&meas_cnfg->quantity_cnfg, ie_ptr); + } + + // Meas Gap Config + if(meas_cnfg->meas_gap_cnfg_present) + { + liblte_rrc_pack_meas_gap_config_ie(&meas_cnfg->meas_gap_cnfg, ie_ptr); + } + + // S Measure + if(meas_cnfg->s_meas_present) + { + liblte_rrc_pack_rsrp_range_ie(meas_cnfg->s_meas, ie_ptr); + } + + // Pre Registration Info HRPD + if(meas_cnfg->pre_reg_info_hrpd_present) + { + liblte_rrc_pack_pre_registration_info_hrpd_ie(&meas_cnfg->pre_reg_info_hrpd, ie_ptr); + } + + // Speed State Pars + if(meas_cnfg->speed_state_params_present) + { + // Release choice + liblte_value_2_bits(1, ie_ptr, 1); + + // Mobility State Parameters + liblte_rrc_pack_mobility_state_parameters_ie(&meas_cnfg->speed_state_params.mob_state_params, ie_ptr); + + // Time To Trigger SF + liblte_rrc_pack_speed_state_scale_factors_ie(&meas_cnfg->speed_state_params.time_to_trig_sf, ie_ptr); + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_meas_config_ie(uint8 **ie_ptr, + LIBLTE_RRC_MEAS_CONFIG_STRUCT *meas_cnfg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint32 i; + bool meas_obj_to_remove_present; + bool rep_cnfg_to_remove_present; + bool meas_id_to_remove_present; + + if(ie_ptr != NULL && + meas_cnfg != NULL) + { + // Extension indicator + bool ext = liblte_bits_2_value(ie_ptr, 1); + + // Optional indicators + meas_obj_to_remove_present = liblte_bits_2_value(ie_ptr, 1); + meas_cnfg->meas_obj_to_add_mod_list_present = liblte_bits_2_value(ie_ptr, 1); + rep_cnfg_to_remove_present = liblte_bits_2_value(ie_ptr, 1); + meas_cnfg->rep_cnfg_to_add_mod_list_present = liblte_bits_2_value(ie_ptr, 1); + meas_id_to_remove_present = liblte_bits_2_value(ie_ptr, 1); + meas_cnfg->meas_id_to_add_mod_list_present = liblte_bits_2_value(ie_ptr, 1); + meas_cnfg->quantity_cnfg_present = liblte_bits_2_value(ie_ptr, 1); + meas_cnfg->meas_gap_cnfg_present = liblte_bits_2_value(ie_ptr, 1); + meas_cnfg->s_meas_present = liblte_bits_2_value(ie_ptr, 1); + meas_cnfg->pre_reg_info_hrpd_present = liblte_bits_2_value(ie_ptr, 1); + meas_cnfg->speed_state_params_present = liblte_bits_2_value(ie_ptr, 1); + + // Meas Object To Remove List + if(meas_obj_to_remove_present) + { + meas_cnfg->N_meas_obj_to_remove = liblte_bits_2_value(ie_ptr, 5) + 1; + for(i=0; iN_meas_obj_to_remove; i++) + { + liblte_rrc_unpack_meas_object_id_ie(ie_ptr, &meas_cnfg->meas_obj_to_remove_list[i]); + } + }else{ + meas_cnfg->N_meas_obj_to_remove = 0; + } + + // Meas Object To Add Mod List + if(meas_cnfg->meas_obj_to_add_mod_list_present) + { + liblte_rrc_unpack_meas_object_to_add_mod_list_ie(ie_ptr, &meas_cnfg->meas_obj_to_add_mod_list); + } + + // Report Config To Remove List + if(rep_cnfg_to_remove_present) + { + meas_cnfg->N_rep_cnfg_to_remove = liblte_bits_2_value(ie_ptr, 5) + 1; + for(i=0; iN_rep_cnfg_to_remove; i++) + { + liblte_rrc_unpack_report_config_id_ie(ie_ptr, &meas_cnfg->rep_cnfg_to_remove_list[i]); + } + }else{ + meas_cnfg->N_rep_cnfg_to_remove = 0; + } + + // Report Config To Add Mod List + if(meas_cnfg->rep_cnfg_to_add_mod_list_present) + { + liblte_rrc_unpack_report_config_to_add_mod_list_ie(ie_ptr, &meas_cnfg->rep_cnfg_to_add_mod_list); + } + + // Meas ID To Remove List + if(meas_id_to_remove_present) + { + meas_cnfg->N_meas_id_to_remove = liblte_bits_2_value(ie_ptr, 5) + 1; + for(i=0; iN_meas_id_to_remove; i++) + { + liblte_rrc_unpack_meas_id_ie(ie_ptr, &meas_cnfg->meas_id_to_remove_list[i]); + } + }else{ + meas_cnfg->N_meas_id_to_remove = 0; + } + + // Meas ID To Add Mod List + if(meas_cnfg->meas_id_to_add_mod_list_present) + { + liblte_rrc_unpack_meas_id_to_add_mod_list_ie(ie_ptr, &meas_cnfg->meas_id_to_add_mod_list); + } + + // Quantity Config + if(meas_cnfg->quantity_cnfg_present) + { + liblte_rrc_unpack_quantity_config_ie(ie_ptr, &meas_cnfg->quantity_cnfg); + } + + // Meas Gap Config + if(meas_cnfg->meas_gap_cnfg_present) + { + liblte_rrc_unpack_meas_gap_config_ie(ie_ptr, &meas_cnfg->meas_gap_cnfg); + } + + // S Measure + if(meas_cnfg->s_meas_present) + { + liblte_rrc_unpack_rsrp_range_ie(ie_ptr, &meas_cnfg->s_meas); + } + + // Pre Registration Info HRPD + if(meas_cnfg->pre_reg_info_hrpd_present) + { + liblte_rrc_unpack_pre_registration_info_hrpd_ie(ie_ptr, &meas_cnfg->pre_reg_info_hrpd); + } + + // Speed State Pars + if(meas_cnfg->speed_state_params_present) + { + // Release choice + meas_cnfg->speed_state_params_present = liblte_bits_2_value(ie_ptr, 1); + + if(meas_cnfg->speed_state_params_present) + { + // Mobility State Parameters + liblte_rrc_unpack_mobility_state_parameters_ie(ie_ptr, &meas_cnfg->speed_state_params.mob_state_params); + + // Time To Trigger SF + liblte_rrc_unpack_speed_state_scale_factors_ie(ie_ptr, &meas_cnfg->speed_state_params.time_to_trig_sf); + } + } + + liblte_rrc_consume_noncrit_extension(ext, __func__, ie_ptr); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Meas Gap Config + + Description: Specifies the measurement gap configuration and + controls setup/release of measurement gaps + + Document Reference: 36.331 v10.0.0 Section 6.3.5 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_meas_gap_config_ie(LIBLTE_RRC_MEAS_GAP_CONFIG_STRUCT *meas_gap_cnfg, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(meas_gap_cnfg != NULL && + ie_ptr != NULL) + { + // Release choice + liblte_value_2_bits(meas_gap_cnfg->setup_present, ie_ptr, 1); + + if(meas_gap_cnfg->setup_present) + { + // Gap Offset Type + liblte_value_2_bits(meas_gap_cnfg->gap_offset_type, ie_ptr, 1); + + // Gap Offset + if(LIBLTE_RRC_GAP_OFFSET_TYPE_GP0 == meas_gap_cnfg->gap_offset_type) + { + liblte_value_2_bits(meas_gap_cnfg->gap_offset, ie_ptr, 6); + }else{ + liblte_value_2_bits(meas_gap_cnfg->gap_offset, ie_ptr, 7); + } + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_meas_gap_config_ie(uint8 **ie_ptr, + LIBLTE_RRC_MEAS_GAP_CONFIG_STRUCT *meas_gap_cnfg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + meas_gap_cnfg != NULL) + { + // Release choice + meas_gap_cnfg->setup_present = liblte_bits_2_value(ie_ptr, 1); + + if(meas_gap_cnfg->setup_present) + { + // Gap Offset Type + meas_gap_cnfg->gap_offset_type = (LIBLTE_RRC_GAP_OFFSET_TYPE_ENUM)liblte_bits_2_value(ie_ptr, 1); + + // Gap Offset + if(LIBLTE_RRC_GAP_OFFSET_TYPE_GP0 == meas_gap_cnfg->gap_offset_type) + { + meas_gap_cnfg->gap_offset = liblte_bits_2_value(ie_ptr, 6); + }else{ + meas_gap_cnfg->gap_offset = liblte_bits_2_value(ie_ptr, 7); + } + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Meas ID + + Description: Identifies a measurement configuration, i.e. linking + of a measurement object and a reporting configuration + + Document Reference: 36.331 v10.0.0 Section 6.3.5 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_meas_id_ie(uint8 meas_id, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL) + { + liblte_value_2_bits(meas_id - 1, ie_ptr, 5); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_meas_id_ie(uint8 **ie_ptr, + uint8 *meas_id) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + meas_id != NULL) + { + *meas_id = liblte_bits_2_value(ie_ptr, 5) + 1; + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Meas Id To Add Mod List + + Description: Concerns a list of measurement identities to add or + modify, with for each entry the meas ID, the + associated meas object ID and the associated report + config ID + + Document Reference: 36.331 v10.0.0 Section 6.3.5 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_meas_id_to_add_mod_list_ie(LIBLTE_RRC_MEAS_ID_TO_ADD_MOD_LIST_STRUCT *list, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint32 i; + + if(list != NULL && + ie_ptr != NULL) + { + // List Size + liblte_value_2_bits(list->N_meas_id - 1, ie_ptr, 5); + + for(i=0; iN_meas_id; i++) + { + // Meas ID + liblte_rrc_pack_meas_id_ie(list->meas_id_list[i].meas_id, ie_ptr); + + // Meas Object ID + liblte_rrc_pack_meas_object_id_ie(list->meas_id_list[i].meas_obj_id, ie_ptr); + + // Report Config ID + liblte_rrc_pack_report_config_id_ie(list->meas_id_list[i].rep_cnfg_id, ie_ptr); + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_meas_id_to_add_mod_list_ie(uint8 **ie_ptr, + LIBLTE_RRC_MEAS_ID_TO_ADD_MOD_LIST_STRUCT *list) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint32 i; + + if(ie_ptr != NULL && + list != NULL) + { + // List Size + list->N_meas_id = liblte_bits_2_value(ie_ptr, 5) + 1; + + for(i=0; iN_meas_id; i++) + { + // Meas ID + liblte_rrc_unpack_meas_id_ie(ie_ptr, &list->meas_id_list[i].meas_id); + + // Meas Object ID + liblte_rrc_unpack_meas_object_id_ie(ie_ptr, &list->meas_id_list[i].meas_obj_id); + + // Report Config ID + liblte_rrc_unpack_report_config_id_ie(ie_ptr, &list->meas_id_list[i].rep_cnfg_id); + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Meas Object CDMA2000 + + Description: Specifies information applicable for inter-RAT + CDMA2000 neighboring cells + + Document Reference: 36.331 v10.0.0 Section 6.3.5 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_meas_object_cdma2000_ie(LIBLTE_RRC_MEAS_OBJECT_CDMA2000_STRUCT *meas_obj_cdma2000, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint32 i; + + if(meas_obj_cdma2000 != NULL && + ie_ptr != NULL) + { + // Extension indicator + liblte_value_2_bits(0, ie_ptr, 1); + + // Optional indicators + liblte_value_2_bits(meas_obj_cdma2000->search_win_size_present, ie_ptr, 1); + liblte_value_2_bits(meas_obj_cdma2000->cells_to_remove_list_present, ie_ptr, 1); + if(0 != meas_obj_cdma2000->N_cells_to_add_mod) + { + liblte_value_2_bits(1, ie_ptr, 1); + }else{ + liblte_value_2_bits(0, ie_ptr, 1); + } + liblte_value_2_bits(meas_obj_cdma2000->cell_for_which_to_rep_cgi_present, ie_ptr, 1); + + // CDMA2000 Type + liblte_rrc_pack_cdma2000_type_ie(meas_obj_cdma2000->cdma2000_type, ie_ptr); + + // Carrier Freq + liblte_rrc_pack_carrier_freq_cdma2000_ie(&meas_obj_cdma2000->carrier_freq, ie_ptr); + + // Search Window Size + if(meas_obj_cdma2000->search_win_size_present) + { + liblte_value_2_bits(meas_obj_cdma2000->search_win_size, ie_ptr, 4); + } + + // Offset Freq + liblte_rrc_pack_q_offset_range_inter_rat_ie(meas_obj_cdma2000->offset_freq, ie_ptr); + + // Cells To Remove List + if(meas_obj_cdma2000->cells_to_remove_list_present) + { + liblte_rrc_pack_cell_index_list_ie(&meas_obj_cdma2000->cells_to_remove_list, ie_ptr); + } + + // Cells To Add Mod List + if(0 != meas_obj_cdma2000->N_cells_to_add_mod) + { + liblte_value_2_bits(meas_obj_cdma2000->N_cells_to_add_mod - 1, ie_ptr, 5); + } + for(i=0; iN_cells_to_add_mod; i++) + { + // Cell Index + liblte_value_2_bits(meas_obj_cdma2000->cells_to_add_mod_list[i].cell_idx - 1, ie_ptr, 5); + + // Phys Cell ID + liblte_rrc_pack_phys_cell_id_cdma2000_ie(meas_obj_cdma2000->cells_to_add_mod_list[i].pci, ie_ptr); + } + + // Cell For Which To Report CGI + if(meas_obj_cdma2000->cell_for_which_to_rep_cgi_present) + { + liblte_rrc_pack_phys_cell_id_cdma2000_ie(meas_obj_cdma2000->cell_for_which_to_rep_cgi_present, ie_ptr); + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_meas_object_cdma2000_ie(uint8 **ie_ptr, + LIBLTE_RRC_MEAS_OBJECT_CDMA2000_STRUCT *meas_obj_cdma2000) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint32 i; + bool cells_to_add_mod_present; + + if(ie_ptr != NULL && + meas_obj_cdma2000 != NULL) + { + // Extension indicator + liblte_bits_2_value(ie_ptr, 1); + + // Optional indicators + meas_obj_cdma2000->search_win_size_present = liblte_bits_2_value(ie_ptr, 1); + meas_obj_cdma2000->cells_to_remove_list_present = liblte_bits_2_value(ie_ptr, 1); + cells_to_add_mod_present = liblte_bits_2_value(ie_ptr, 1); + meas_obj_cdma2000->cell_for_which_to_rep_cgi_present = liblte_bits_2_value(ie_ptr, 1); + + // CDMA2000 Type + liblte_rrc_unpack_cdma2000_type_ie(ie_ptr, &meas_obj_cdma2000->cdma2000_type); + + // Carrier Freq + liblte_rrc_unpack_carrier_freq_cdma2000_ie(ie_ptr, &meas_obj_cdma2000->carrier_freq); + + // Search Window Size + if(meas_obj_cdma2000->search_win_size_present) + { + meas_obj_cdma2000->search_win_size = liblte_bits_2_value(ie_ptr, 4); + } + + // Offset Freq + liblte_rrc_unpack_q_offset_range_inter_rat_ie(ie_ptr, &meas_obj_cdma2000->offset_freq); + + // Cells To Remove List + if(meas_obj_cdma2000->cells_to_remove_list_present) + { + liblte_rrc_unpack_cell_index_list_ie(ie_ptr, &meas_obj_cdma2000->cells_to_remove_list); + } + + // Cells To Add Mod List + if(cells_to_add_mod_present) + { + meas_obj_cdma2000->N_cells_to_add_mod = liblte_bits_2_value(ie_ptr, 5) + 1; + for(i=0; iN_cells_to_add_mod; i++) + { + // Cell Index + meas_obj_cdma2000->cells_to_add_mod_list[i].cell_idx = liblte_bits_2_value(ie_ptr, 5) + 1; + + // Phys Cell ID + liblte_rrc_unpack_phys_cell_id_cdma2000_ie(ie_ptr, &meas_obj_cdma2000->cells_to_add_mod_list[i].pci); + } + }else{ + meas_obj_cdma2000->N_cells_to_add_mod = 0; + } + + // Cell For Which To Report CGI + if(meas_obj_cdma2000->cell_for_which_to_rep_cgi_present) + { + liblte_rrc_unpack_phys_cell_id_cdma2000_ie(ie_ptr, &meas_obj_cdma2000->cell_for_which_to_rep_cgi); + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Meas Object EUTRA + + Description: Specifies information applicable for intra-frequency + or inter-frequency E-UTRA cells + + Document Reference: 36.331 v10.0.0 Section 6.3.5 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_meas_object_eutra_ie(LIBLTE_RRC_MEAS_OBJECT_EUTRA_STRUCT *meas_obj_eutra, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint32 i; + + if(meas_obj_eutra != NULL && + ie_ptr != NULL) + { + // Extension indicator + liblte_value_2_bits(0, ie_ptr, 1); + + // Optional indicators + liblte_value_2_bits(meas_obj_eutra->cells_to_remove_list_present, ie_ptr, 1); + if(0 != meas_obj_eutra->N_cells_to_add_mod) + { + liblte_value_2_bits(1, ie_ptr, 1); + }else{ + liblte_value_2_bits(0, ie_ptr, 1); + } + liblte_value_2_bits(meas_obj_eutra->black_cells_to_remove_list_present, ie_ptr, 1); + if(0 != meas_obj_eutra->N_black_cells_to_add_mod) + { + liblte_value_2_bits(1, ie_ptr, 1); + }else{ + liblte_value_2_bits(0, ie_ptr, 1); + } + liblte_value_2_bits(meas_obj_eutra->cell_for_which_to_rep_cgi_present, ie_ptr, 1); + + // Carrier Freq + liblte_rrc_pack_arfcn_value_eutra_ie(meas_obj_eutra->carrier_freq, ie_ptr); + + // Allowed Meas Bandwidth + liblte_rrc_pack_allowed_meas_bandwidth_ie(meas_obj_eutra->allowed_meas_bw, ie_ptr); + + // Presence Antenna Port 1 + liblte_rrc_pack_presence_antenna_port_1_ie(meas_obj_eutra->presence_ant_port_1, ie_ptr); + + // Neigh Cell Config + liblte_rrc_pack_neigh_cell_config_ie(meas_obj_eutra->neigh_cell_cnfg, ie_ptr); + + // Offset Freq + liblte_rrc_pack_q_offset_range_ie(meas_obj_eutra->offset_freq, ie_ptr); + + // Cells To Remove List + if(meas_obj_eutra->cells_to_remove_list_present) + { + liblte_rrc_pack_cell_index_list_ie(&meas_obj_eutra->cells_to_remove_list, ie_ptr); + } + + // Cells To Add Mod List + if(0 != meas_obj_eutra->N_cells_to_add_mod) + { + liblte_value_2_bits(meas_obj_eutra->N_cells_to_add_mod - 1, ie_ptr, 5); + } + for(i=0; iN_cells_to_add_mod; i++) + { + // Cell Index + liblte_value_2_bits(meas_obj_eutra->cells_to_add_mod_list[i].cell_idx - 1, ie_ptr, 5); + + // Phys Cell ID + liblte_rrc_pack_phys_cell_id_ie(meas_obj_eutra->cells_to_add_mod_list[i].pci, ie_ptr); + + // Cell Individual Offset + liblte_rrc_pack_q_offset_range_ie(meas_obj_eutra->cells_to_add_mod_list[i].cell_offset, ie_ptr); + } + + // Black Cells To Remove List + if(meas_obj_eutra->black_cells_to_remove_list_present) + { + liblte_rrc_pack_cell_index_list_ie(&meas_obj_eutra->black_cells_to_remove_list, ie_ptr); + } + + // Black Cells To Add Mod List + if(0 != meas_obj_eutra->N_black_cells_to_add_mod) + { + liblte_value_2_bits(meas_obj_eutra->N_black_cells_to_add_mod - 1, ie_ptr, 5); + } + for(i=0; iN_black_cells_to_add_mod; i++) + { + // Cell Index + liblte_value_2_bits(meas_obj_eutra->black_cells_to_add_mod_list[i].cell_idx - 1, ie_ptr, 5); + + // Phys Cell ID Range + liblte_rrc_pack_phys_cell_id_range_ie(&meas_obj_eutra->black_cells_to_add_mod_list[i].pci_range, ie_ptr); + } + + // Cell For Which To Report CGI + if(meas_obj_eutra->cell_for_which_to_rep_cgi_present) + { + liblte_rrc_pack_phys_cell_id_ie(meas_obj_eutra->cell_for_which_to_rep_cgi, ie_ptr); + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_meas_object_eutra_ie(uint8 **ie_ptr, + LIBLTE_RRC_MEAS_OBJECT_EUTRA_STRUCT *meas_obj_eutra) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint32 i; + bool cells_to_add_mod_list_present; + bool black_cells_to_add_mod_list_present; + + if(ie_ptr != NULL && + meas_obj_eutra != NULL) + { + // Extension indicator + liblte_bits_2_value(ie_ptr, 1); + + // Optional indicators + meas_obj_eutra->offset_freq_not_default = liblte_bits_2_value(ie_ptr, 1); + meas_obj_eutra->cells_to_remove_list_present = liblte_bits_2_value(ie_ptr, 1); + cells_to_add_mod_list_present = liblte_bits_2_value(ie_ptr, 1); + meas_obj_eutra->black_cells_to_remove_list_present = liblte_bits_2_value(ie_ptr, 1); + black_cells_to_add_mod_list_present = liblte_bits_2_value(ie_ptr, 1); + meas_obj_eutra->cell_for_which_to_rep_cgi_present = liblte_bits_2_value(ie_ptr, 1); + + // Carrier Freq + liblte_rrc_unpack_arfcn_value_eutra_ie(ie_ptr, &meas_obj_eutra->carrier_freq); + + // Allowed Meas Bandwidth + liblte_rrc_unpack_allowed_meas_bandwidth_ie(ie_ptr, &meas_obj_eutra->allowed_meas_bw); + + // Presence Antenna Port 1 + liblte_rrc_unpack_presence_antenna_port_1_ie(ie_ptr, &meas_obj_eutra->presence_ant_port_1); + + // Neigh Cell Config + liblte_rrc_unpack_neigh_cell_config_ie(ie_ptr, &meas_obj_eutra->neigh_cell_cnfg); + + // Offset Freq + if(meas_obj_eutra->offset_freq_not_default) + { + liblte_rrc_unpack_q_offset_range_ie(ie_ptr, &meas_obj_eutra->offset_freq); + } + + // Cells To Remove List + if(meas_obj_eutra->cells_to_remove_list_present) + { + liblte_rrc_unpack_cell_index_list_ie(ie_ptr, &meas_obj_eutra->cells_to_remove_list); + } + + // Cells To Add Mod List + if(cells_to_add_mod_list_present) + { + meas_obj_eutra->N_cells_to_add_mod = liblte_bits_2_value(ie_ptr, 5) + 1; + for(i=0; iN_cells_to_add_mod; i++) + { + // Cell Index + meas_obj_eutra->cells_to_add_mod_list[i].cell_idx = liblte_bits_2_value(ie_ptr, 5) + 1; + + // Phys Cell ID + liblte_rrc_unpack_phys_cell_id_ie(ie_ptr, &meas_obj_eutra->cells_to_add_mod_list[i].pci); + + // Cell Individual Offset + liblte_rrc_unpack_q_offset_range_ie(ie_ptr, &meas_obj_eutra->cells_to_add_mod_list[i].cell_offset); + } + }else{ + meas_obj_eutra->N_cells_to_add_mod = 0; + } + + // Black Cells To Remove List + if(meas_obj_eutra->black_cells_to_remove_list_present) + { + liblte_rrc_unpack_cell_index_list_ie(ie_ptr, &meas_obj_eutra->black_cells_to_remove_list); + } + + // Black Cells To Add Mod List + if(black_cells_to_add_mod_list_present) + { + meas_obj_eutra->N_black_cells_to_add_mod = liblte_bits_2_value(ie_ptr, 5) + 1; + for(i=0; iN_black_cells_to_add_mod; i++) + { + // Cell Index + meas_obj_eutra->black_cells_to_add_mod_list[i].cell_idx = liblte_bits_2_value(ie_ptr, 5) + 1; + + // Phys Cell ID Range + liblte_rrc_unpack_phys_cell_id_range_ie(ie_ptr, &meas_obj_eutra->black_cells_to_add_mod_list[i].pci_range); + } + }else{ + meas_obj_eutra->N_black_cells_to_add_mod = 0; + } + + // Cell For Which To Report CGI + if(meas_obj_eutra->cell_for_which_to_rep_cgi_present) + { + liblte_rrc_unpack_phys_cell_id_ie(ie_ptr, &meas_obj_eutra->cell_for_which_to_rep_cgi); + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Meas Object GERAN + + Description: Specifies information applicable for inter-RAT + GERAN neighboring frequencies + + Document Reference: 36.331 v10.0.0 Section 6.3.5 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_meas_object_geran_ie(LIBLTE_RRC_MEAS_OBJECT_GERAN_STRUCT *meas_obj_geran, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(meas_obj_geran != NULL && + ie_ptr != NULL) + { + // Extension indicator + liblte_value_2_bits(0, ie_ptr, 1); + + // Optional indicator + liblte_value_2_bits(meas_obj_geran->cell_for_which_to_rep_cgi_present, ie_ptr, 1); + + // Carrier Freqs + liblte_rrc_pack_carrier_freqs_geran_ie(&meas_obj_geran->carrier_freqs, ie_ptr); + + // Offset Freq + liblte_rrc_pack_q_offset_range_inter_rat_ie(meas_obj_geran->offset_freq, ie_ptr); + + // NCC Permitted + liblte_value_2_bits(meas_obj_geran->ncc_permitted, ie_ptr, 8); + + // Cell For Which To Report CGI + if(meas_obj_geran->cell_for_which_to_rep_cgi_present) + { + liblte_rrc_pack_phys_cell_id_geran_ie(&meas_obj_geran->cell_for_which_to_rep_cgi, ie_ptr); + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_meas_object_geran_ie(uint8 **ie_ptr, + LIBLTE_RRC_MEAS_OBJECT_GERAN_STRUCT *meas_obj_geran) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + meas_obj_geran != NULL) + { + // Extension indicator + liblte_bits_2_value(ie_ptr, 1); + + // Optional indicator + meas_obj_geran->cell_for_which_to_rep_cgi_present = liblte_bits_2_value(ie_ptr, 1); + + // Carrier Freqs + liblte_rrc_unpack_carrier_freqs_geran_ie(ie_ptr, &meas_obj_geran->carrier_freqs); + + // Offset Freq + liblte_rrc_unpack_q_offset_range_inter_rat_ie(ie_ptr, &meas_obj_geran->offset_freq); + + // NCC Permitted + meas_obj_geran->ncc_permitted = liblte_bits_2_value(ie_ptr, 8); + + // Cell For Which To Report CGI + if(meas_obj_geran->cell_for_which_to_rep_cgi_present) + { + liblte_rrc_unpack_phys_cell_id_geran_ie(ie_ptr, &meas_obj_geran->cell_for_which_to_rep_cgi); + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Meas Object ID + + Description: Identifies a measurement object configuration + + Document Reference: 36.331 v10.0.0 Section 6.3.5 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_meas_object_id_ie(uint8 meas_object_id, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL) + { + liblte_value_2_bits(meas_object_id - 1, ie_ptr, 5); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_meas_object_id_ie(uint8 **ie_ptr, + uint8 *meas_object_id) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + meas_object_id != NULL) + { + *meas_object_id = liblte_bits_2_value(ie_ptr, 5) + 1; + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Meas Object To Add Mod List + + Description: Concerns a list of measurement objects to add or + modify + + Document Reference: 36.331 v10.0.0 Section 6.3.5 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_meas_object_to_add_mod_list_ie(LIBLTE_RRC_MEAS_OBJECT_TO_ADD_MOD_LIST_STRUCT *list, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint32 i; + + if(list != NULL && + ie_ptr != NULL) + { + // List Size + liblte_value_2_bits(list->N_meas_obj - 1, ie_ptr, 5); + + for(i=0; iN_meas_obj; i++) + { + // Meas Object ID + liblte_rrc_pack_meas_object_id_ie(list->meas_obj_list[i].meas_obj_id, ie_ptr); + + // Meas Object Choice + liblte_value_2_bits(list->meas_obj_list[i].meas_obj_type, ie_ptr, 2); + + // Meas Object + if(LIBLTE_RRC_MEAS_OBJECT_TYPE_EUTRA == list->meas_obj_list[i].meas_obj_type) + { + liblte_rrc_pack_meas_object_eutra_ie(&list->meas_obj_list[i].meas_obj_eutra, ie_ptr); + }else if(LIBLTE_RRC_MEAS_OBJECT_TYPE_UTRA == list->meas_obj_list[i].meas_obj_type){ + liblte_rrc_pack_meas_object_utra_ie(&list->meas_obj_list[i].meas_obj_utra, ie_ptr); + }else if(LIBLTE_RRC_MEAS_OBJECT_TYPE_GERAN == list->meas_obj_list[i].meas_obj_type){ + liblte_rrc_pack_meas_object_geran_ie(&list->meas_obj_list[i].meas_obj_geran, ie_ptr); + }else{ + liblte_rrc_pack_meas_object_cdma2000_ie(&list->meas_obj_list[i].meas_obj_cdma2000, ie_ptr); + } + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_meas_object_to_add_mod_list_ie(uint8 **ie_ptr, + LIBLTE_RRC_MEAS_OBJECT_TO_ADD_MOD_LIST_STRUCT *list) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint32 i; + + if(ie_ptr != NULL && + list != NULL) + { + // List Size + list->N_meas_obj = liblte_bits_2_value(ie_ptr, 5) + 1; + + for(i=0; iN_meas_obj; i++) + { + // Meas Object ID + liblte_rrc_unpack_meas_object_id_ie(ie_ptr, &list->meas_obj_list[i].meas_obj_id); + + // Meas Object Choice Extension + liblte_bits_2_value(ie_ptr, 1); + + // Meas Object Choice + list->meas_obj_list[i].meas_obj_type = (LIBLTE_RRC_MEAS_OBJECT_TYPE_ENUM)liblte_bits_2_value(ie_ptr, 2); + + // Meas Object + if(LIBLTE_RRC_MEAS_OBJECT_TYPE_EUTRA == list->meas_obj_list[i].meas_obj_type) + { + liblte_rrc_unpack_meas_object_eutra_ie(ie_ptr, &list->meas_obj_list[i].meas_obj_eutra); + }else if(LIBLTE_RRC_MEAS_OBJECT_TYPE_UTRA == list->meas_obj_list[i].meas_obj_type){ + liblte_rrc_unpack_meas_object_utra_ie(ie_ptr, &list->meas_obj_list[i].meas_obj_utra); + }else if(LIBLTE_RRC_MEAS_OBJECT_TYPE_GERAN == list->meas_obj_list[i].meas_obj_type){ + liblte_rrc_unpack_meas_object_geran_ie(ie_ptr, &list->meas_obj_list[i].meas_obj_geran); + }else{ + liblte_rrc_unpack_meas_object_cdma2000_ie(ie_ptr, &list->meas_obj_list[i].meas_obj_cdma2000); + } + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Meas Object UTRA + + Description: Specifies information applicable for inter-RAT UTRA + neighboring cells + + Document Reference: 36.331 v10.0.0 Section 6.3.5 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_meas_object_utra_ie(LIBLTE_RRC_MEAS_OBJECT_UTRA_STRUCT *meas_obj_utra, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint32 i; + + if(meas_obj_utra != NULL && + ie_ptr != NULL) + { + // Extension indicator + liblte_value_2_bits(0, ie_ptr, 1); + + // Optional indicators + liblte_value_2_bits(meas_obj_utra->cells_to_remove_list_present, ie_ptr, 1); + liblte_value_2_bits(meas_obj_utra->cells_to_add_mod_list_present, ie_ptr, 1); + liblte_value_2_bits(meas_obj_utra->cells_for_which_to_rep_cgi_present, ie_ptr, 1); + + // Carrier Freq + liblte_rrc_pack_arfcn_value_utra_ie(meas_obj_utra->carrier_freq, ie_ptr); + + // Offset Freq + liblte_rrc_pack_q_offset_range_inter_rat_ie(meas_obj_utra->offset_freq, ie_ptr); + + // Cells To Remove List + if(meas_obj_utra->cells_to_remove_list_present) + { + liblte_rrc_pack_cell_index_list_ie(&meas_obj_utra->cells_to_remove_list, ie_ptr); + } + + // Cells To Add Mod List + if(meas_obj_utra->cells_to_add_mod_list_present) + { + // UTRA System Type + liblte_value_2_bits(meas_obj_utra->cells_to_add_mod_list.type, ie_ptr, 1); + + liblte_value_2_bits(meas_obj_utra->cells_to_add_mod_list.N_cells - 1, ie_ptr, 5); + for(i=0; icells_to_add_mod_list.N_cells; i++) + { + if(LIBLTE_RRC_UTRA_SYSTEM_TYPE_FDD == meas_obj_utra->cells_to_add_mod_list.type) + { + // Cell Index + liblte_value_2_bits(meas_obj_utra->cells_to_add_mod_list.cells_fdd[i].cell_idx - 1, ie_ptr, 5); + + // Phys Cell ID + liblte_rrc_pack_phys_cell_id_utra_fdd_ie(meas_obj_utra->cells_to_add_mod_list.cells_fdd[i].pci, ie_ptr); + }else{ + // Cell Index + liblte_value_2_bits(meas_obj_utra->cells_to_add_mod_list.cells_tdd[i].cell_idx - 1, ie_ptr, 5); + + // Phys Cell ID + liblte_rrc_pack_phys_cell_id_utra_tdd_ie(meas_obj_utra->cells_to_add_mod_list.cells_tdd[i].pci, ie_ptr); + } + } + } + + // Cells For Which To Report CGI + if(meas_obj_utra->cells_for_which_to_rep_cgi_present) + { + // UTRA System Type + liblte_value_2_bits(meas_obj_utra->cells_for_which_to_rep_cgi.type, ie_ptr, 1); + + if(LIBLTE_RRC_UTRA_SYSTEM_TYPE_FDD == meas_obj_utra->cells_for_which_to_rep_cgi.type) + { + // Phys Cell ID + liblte_rrc_pack_phys_cell_id_utra_fdd_ie(meas_obj_utra->cells_for_which_to_rep_cgi.pci_fdd, ie_ptr); + }else{ + // Phys Cell ID + liblte_rrc_pack_phys_cell_id_utra_tdd_ie(meas_obj_utra->cells_for_which_to_rep_cgi.pci_tdd, ie_ptr); + } + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_meas_object_utra_ie(uint8 **ie_ptr, + LIBLTE_RRC_MEAS_OBJECT_UTRA_STRUCT *meas_obj_utra) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint32 i; + + if(ie_ptr != NULL && + meas_obj_utra != NULL) + { + // Extension indicator + liblte_bits_2_value(ie_ptr, 1); + + // Optional indicators + meas_obj_utra->cells_to_remove_list_present = liblte_bits_2_value(ie_ptr, 1); + meas_obj_utra->cells_to_add_mod_list_present = liblte_bits_2_value(ie_ptr, 1); + meas_obj_utra->cells_for_which_to_rep_cgi_present = liblte_bits_2_value(ie_ptr, 1); + + // Carrier Freq + liblte_rrc_unpack_arfcn_value_utra_ie(ie_ptr, &meas_obj_utra->carrier_freq); + + // Offset Freq + liblte_rrc_unpack_q_offset_range_inter_rat_ie(ie_ptr, &meas_obj_utra->offset_freq); + + // Cells To Remove List + if(meas_obj_utra->cells_to_remove_list_present) + { + liblte_rrc_unpack_cell_index_list_ie(ie_ptr, &meas_obj_utra->cells_to_remove_list); + } + + // Cells To Add Mod List + if(meas_obj_utra->cells_to_add_mod_list_present) + { + // UTRA System Type + meas_obj_utra->cells_to_add_mod_list.type = (LIBLTE_RRC_UTRA_SYSTEM_TYPE_ENUM)liblte_bits_2_value(ie_ptr, 1); + + meas_obj_utra->cells_to_add_mod_list.N_cells = liblte_bits_2_value(ie_ptr, 5) + 1; + for(i=0; icells_to_add_mod_list.N_cells; i++) + { + if(LIBLTE_RRC_UTRA_SYSTEM_TYPE_FDD == meas_obj_utra->cells_to_add_mod_list.type) + { + // Cell Index + meas_obj_utra->cells_to_add_mod_list.cells_fdd[i].cell_idx = liblte_bits_2_value(ie_ptr, 5) + 1; + + // Phys Cell ID + liblte_rrc_unpack_phys_cell_id_utra_fdd_ie(ie_ptr, &meas_obj_utra->cells_to_add_mod_list.cells_fdd[i].pci); + }else{ + // Cell Index + meas_obj_utra->cells_to_add_mod_list.cells_tdd[i].cell_idx = liblte_bits_2_value(ie_ptr, 5) + 1; + + // Phys Cell ID + liblte_rrc_unpack_phys_cell_id_utra_tdd_ie(ie_ptr, &meas_obj_utra->cells_to_add_mod_list.cells_tdd[i].pci); + } + } + } + + // Cells For Which To Report CGI + if(meas_obj_utra->cells_for_which_to_rep_cgi_present) + { + // UTRA System Type + meas_obj_utra->cells_for_which_to_rep_cgi.type = (LIBLTE_RRC_UTRA_SYSTEM_TYPE_ENUM)liblte_bits_2_value(ie_ptr, 1); + + if(LIBLTE_RRC_UTRA_SYSTEM_TYPE_FDD == meas_obj_utra->cells_for_which_to_rep_cgi.type) + { + // Phys Cell ID + liblte_rrc_unpack_phys_cell_id_utra_fdd_ie(ie_ptr, &meas_obj_utra->cells_for_which_to_rep_cgi.pci_fdd); + }else{ + // Phys Cell ID + liblte_rrc_unpack_phys_cell_id_utra_tdd_ie(ie_ptr, &meas_obj_utra->cells_for_which_to_rep_cgi.pci_tdd); + } + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Meas Results + + Description: Covers measured results for intra-frequency, + inter-frequency and inter-RAT mobility + + Document Reference: 36.331 v10.0.0 Section 6.3.5 +*********************************************************************/ +// FIXME + +/********************************************************************* + IE Name: Quantity Config + + Description: Specifies the measurement quantities and layer 3 + filtering coefficients for E-UTRA and inter-RAT + measurements + + Document Reference: 36.331 v10.0.0 Section 6.3.5 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_quantity_config_ie(LIBLTE_RRC_QUANTITY_CONFIG_STRUCT *qc, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(qc != NULL && + ie_ptr != NULL) + { + // Extension indicator + liblte_value_2_bits(0, ie_ptr, 1); + + // Optional indicators + liblte_value_2_bits(qc->qc_eutra_present, ie_ptr, 1); + liblte_value_2_bits(qc->qc_utra_present, ie_ptr, 1); + liblte_value_2_bits(qc->qc_geran_present, ie_ptr, 1); + liblte_value_2_bits(qc->qc_cdma2000_present, ie_ptr, 1); + + // Quality Config EUTRA + if(qc->qc_eutra_present) + { + liblte_rrc_pack_filter_coefficient_ie(qc->qc_eutra.fc_rsrp, ie_ptr); + liblte_rrc_pack_filter_coefficient_ie(qc->qc_eutra.fc_rsrq, ie_ptr); + } + + // Quality Config UTRA + if(qc->qc_utra_present) + { + liblte_value_2_bits(qc->qc_utra.mq_fdd, ie_ptr, 1); + liblte_value_2_bits(qc->qc_utra.mq_tdd, ie_ptr, 1); + liblte_rrc_pack_filter_coefficient_ie(qc->qc_utra.fc, ie_ptr); + } + + // Quality Config GERAN + if(qc->qc_geran_present) + { + liblte_value_2_bits(qc->qc_geran.mq, ie_ptr, 1); + liblte_rrc_pack_filter_coefficient_ie(qc->qc_geran.fc, ie_ptr); + } + + // Quality Config CDMA2000 + if(qc->qc_cdma2000_present) + { + liblte_value_2_bits(qc->qc_cdma2000.mq, ie_ptr, 1); + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_quantity_config_ie(uint8 **ie_ptr, + LIBLTE_RRC_QUANTITY_CONFIG_STRUCT *qc) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + qc != NULL) + { + // Extension indicator + liblte_bits_2_value(ie_ptr, 1); + + // Optional indicators + qc->qc_eutra_present = liblte_bits_2_value(ie_ptr, 1); + qc->qc_utra_present = liblte_bits_2_value(ie_ptr, 1); + qc->qc_geran_present = liblte_bits_2_value(ie_ptr, 1); + qc->qc_cdma2000_present = liblte_bits_2_value(ie_ptr, 1); + + // Quantity Config EUTRA + if(qc->qc_eutra_present) + { + qc->qc_eutra.fc_rsrp_not_default = liblte_bits_2_value(ie_ptr, 1); + qc->qc_eutra.fc_rsrq_not_default = liblte_bits_2_value(ie_ptr, 1); + if(qc->qc_eutra.fc_rsrp_not_default) { + liblte_rrc_unpack_filter_coefficient_ie(ie_ptr, &qc->qc_eutra.fc_rsrp); + } + if(qc->qc_eutra.fc_rsrq_not_default) { + liblte_rrc_unpack_filter_coefficient_ie(ie_ptr, &qc->qc_eutra.fc_rsrq); + } + } + + // Quantity Config UTRA + if(qc->qc_utra_present) + { + qc->qc_utra.fc_not_default = liblte_bits_2_value(ie_ptr, 1); + qc->qc_utra.mq_fdd = (LIBLTE_RRC_MEAS_QUANTITY_UTRA_FDD_ENUM)liblte_bits_2_value(ie_ptr, 1); + qc->qc_utra.mq_tdd = LIBLTE_RRC_MEAS_QUANTITY_UTRA_TDD_PCCPCH_RSCP; + if(qc->qc_utra.fc_not_default) { + liblte_rrc_unpack_filter_coefficient_ie(ie_ptr, &qc->qc_utra.fc); + } + } + + // Quantity Config GERAN + if(qc->qc_geran_present) + { + qc->qc_geran.fc_not_default = liblte_bits_2_value(ie_ptr, 1); + qc->qc_geran.mq = LIBLTE_RRC_MEAS_QUANTITY_GERAN_RSSI; + if(qc->qc_geran.fc_not_default) { + liblte_rrc_unpack_filter_coefficient_ie(ie_ptr, &qc->qc_geran.fc); + } + } + + // Quality Config CDMA2000 + if(qc->qc_cdma2000_present) + { + qc->qc_cdma2000.mq = (LIBLTE_RRC_MEAS_QUANTITY_CDMA2000_ENUM)liblte_bits_2_value(ie_ptr, 1); + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Report Config EUTRA + + Description: Specifies criteria for triggering of an E-UTRA + measurement reporting event + + Document Reference: 36.331 v10.0.0 Section 6.3.5 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_report_config_eutra_ie(LIBLTE_RRC_REPORT_CONFIG_EUTRA_STRUCT *rep_cnfg_eutra, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(rep_cnfg_eutra != NULL && + ie_ptr != NULL) + { + // Extension indicator + liblte_value_2_bits(0, ie_ptr, 1); + + // Trigger Type + liblte_value_2_bits(rep_cnfg_eutra->trigger_type, ie_ptr, 1); + if(LIBLTE_RRC_TRIGGER_TYPE_EUTRA_EVENT == rep_cnfg_eutra->trigger_type) + { + // Event ID + // FIXME: Handle extension properly + liblte_value_2_bits(rep_cnfg_eutra->event.event_id, ie_ptr, 3); + if(LIBLTE_RRC_EVENT_ID_EUTRA_A1 == rep_cnfg_eutra->event.event_id) + { + // Threshold Type + liblte_value_2_bits(rep_cnfg_eutra->event.event_a1.eutra.type, ie_ptr, 1); + if(LIBLTE_RRC_THRESHOLD_EUTRA_TYPE_RSRP == rep_cnfg_eutra->event.event_a1.eutra.type) + { + liblte_rrc_pack_rsrp_range_ie(rep_cnfg_eutra->event.event_a1.eutra.range, ie_ptr); + }else{ + liblte_rrc_pack_rsrq_range_ie(rep_cnfg_eutra->event.event_a1.eutra.range, ie_ptr); + } + }else if(LIBLTE_RRC_EVENT_ID_EUTRA_A2 == rep_cnfg_eutra->event.event_id){ + // Threshold Type + liblte_value_2_bits(rep_cnfg_eutra->event.event_a2.eutra.type, ie_ptr, 1); + if(LIBLTE_RRC_THRESHOLD_EUTRA_TYPE_RSRP == rep_cnfg_eutra->event.event_a2.eutra.type) + { + liblte_rrc_pack_rsrp_range_ie(rep_cnfg_eutra->event.event_a2.eutra.range, ie_ptr); + }else{ + liblte_rrc_pack_rsrq_range_ie(rep_cnfg_eutra->event.event_a2.eutra.range, ie_ptr); + } + }else if(LIBLTE_RRC_EVENT_ID_EUTRA_A3 == rep_cnfg_eutra->event.event_id){ + // Offset + liblte_value_2_bits(rep_cnfg_eutra->event.event_a3.offset + 30, ie_ptr, 6); + + // Report On Leave + liblte_value_2_bits(rep_cnfg_eutra->event.event_a3.report_on_leave, ie_ptr, 1); + }else if(LIBLTE_RRC_EVENT_ID_EUTRA_A4 == rep_cnfg_eutra->event.event_id){ + // Threshold Type + liblte_value_2_bits(rep_cnfg_eutra->event.event_a4.eutra.type, ie_ptr, 1); + if(LIBLTE_RRC_THRESHOLD_EUTRA_TYPE_RSRP == rep_cnfg_eutra->event.event_a4.eutra.type) + { + liblte_rrc_pack_rsrp_range_ie(rep_cnfg_eutra->event.event_a4.eutra.range, ie_ptr); + }else{ + liblte_rrc_pack_rsrq_range_ie(rep_cnfg_eutra->event.event_a4.eutra.range, ie_ptr); + } + }else if(LIBLTE_RRC_EVENT_ID_EUTRA_A5 == rep_cnfg_eutra->event.event_id){ + // Threshold1 Type + liblte_value_2_bits(rep_cnfg_eutra->event.event_a5.eutra1.type, ie_ptr, 1); + if(LIBLTE_RRC_THRESHOLD_EUTRA_TYPE_RSRP == rep_cnfg_eutra->event.event_a5.eutra1.type) + { + liblte_rrc_pack_rsrp_range_ie(rep_cnfg_eutra->event.event_a5.eutra1.range, ie_ptr); + }else{ + liblte_rrc_pack_rsrq_range_ie(rep_cnfg_eutra->event.event_a5.eutra1.range, ie_ptr); + } + + // Threshold2 Type + liblte_value_2_bits(rep_cnfg_eutra->event.event_a5.eutra2.type, ie_ptr, 1); + if(LIBLTE_RRC_THRESHOLD_EUTRA_TYPE_RSRP == rep_cnfg_eutra->event.event_a5.eutra2.type) + { + liblte_rrc_pack_rsrp_range_ie(rep_cnfg_eutra->event.event_a5.eutra2.range, ie_ptr); + }else{ + liblte_rrc_pack_rsrq_range_ie(rep_cnfg_eutra->event.event_a5.eutra2.range, ie_ptr); + } + }else{ + // Offset + liblte_value_2_bits(rep_cnfg_eutra->event.event_a6.offset + 30, ie_ptr, 6); + + // Report On Leave + liblte_value_2_bits(rep_cnfg_eutra->event.event_a6.report_on_leave, ie_ptr, 1); + } + + // Hysteresis + liblte_rrc_pack_hysteresis_ie(rep_cnfg_eutra->event.hysteresis, ie_ptr); + + // Time To Trigger + liblte_rrc_pack_time_to_trigger_ie(rep_cnfg_eutra->event.time_to_trigger, ie_ptr); + }else{ + // Purpose + liblte_value_2_bits(rep_cnfg_eutra->periodical.purpose, ie_ptr, 1); + } + + // Trigger Quantity + liblte_value_2_bits(rep_cnfg_eutra->trigger_quantity, ie_ptr, 1); + + // Report Quantity + liblte_value_2_bits(rep_cnfg_eutra->report_quantity, ie_ptr, 1); + + // Max Report Cells + liblte_value_2_bits(rep_cnfg_eutra->max_report_cells - 1, ie_ptr, 3); + + // Report Interval + liblte_rrc_pack_report_interval_ie(rep_cnfg_eutra->report_interval, ie_ptr); + + // Report Amount + liblte_value_2_bits(rep_cnfg_eutra->report_amount, ie_ptr, 3); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_report_config_eutra_ie(uint8 **ie_ptr, + LIBLTE_RRC_REPORT_CONFIG_EUTRA_STRUCT *rep_cnfg_eutra) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + rep_cnfg_eutra != NULL) + { + // Extension indicator + liblte_bits_2_value(ie_ptr, 1); + + // Trigger Type + rep_cnfg_eutra->trigger_type = (LIBLTE_RRC_TRIGGER_TYPE_EUTRA_ENUM)liblte_bits_2_value(ie_ptr, 1); + if(LIBLTE_RRC_TRIGGER_TYPE_EUTRA_EVENT == rep_cnfg_eutra->trigger_type) + { + // Event ID choice extension indicator + liblte_bits_2_value(ie_ptr, 1); + + // Event ID + rep_cnfg_eutra->event.event_id = (LIBLTE_RRC_EVENT_ID_EUTRA_ENUM)liblte_bits_2_value(ie_ptr, 3); + + if(LIBLTE_RRC_EVENT_ID_EUTRA_A1 == rep_cnfg_eutra->event.event_id) + { + // Threshold Type + rep_cnfg_eutra->event.event_a1.eutra.type = (LIBLTE_RRC_THRESHOLD_EUTRA_TYPE_ENUM)liblte_bits_2_value(ie_ptr, 1); + if(LIBLTE_RRC_THRESHOLD_EUTRA_TYPE_RSRP == rep_cnfg_eutra->event.event_a1.eutra.type) + { + liblte_rrc_unpack_rsrp_range_ie(ie_ptr, &rep_cnfg_eutra->event.event_a1.eutra.range); + }else{ + liblte_rrc_unpack_rsrq_range_ie(ie_ptr, &rep_cnfg_eutra->event.event_a1.eutra.range); + } + }else if(LIBLTE_RRC_EVENT_ID_EUTRA_A2 == rep_cnfg_eutra->event.event_id){ + // Threshold Type + rep_cnfg_eutra->event.event_a2.eutra.type = (LIBLTE_RRC_THRESHOLD_EUTRA_TYPE_ENUM)liblte_bits_2_value(ie_ptr, 1); + if(LIBLTE_RRC_THRESHOLD_EUTRA_TYPE_RSRP == rep_cnfg_eutra->event.event_a2.eutra.type) + { + liblte_rrc_unpack_rsrp_range_ie(ie_ptr, &rep_cnfg_eutra->event.event_a2.eutra.range); + }else{ + liblte_rrc_unpack_rsrq_range_ie(ie_ptr, &rep_cnfg_eutra->event.event_a2.eutra.range); + } + }else if(LIBLTE_RRC_EVENT_ID_EUTRA_A3 == rep_cnfg_eutra->event.event_id){ + // Offset + rep_cnfg_eutra->event.event_a3.offset = liblte_bits_2_value(ie_ptr, 6) - 30; + + // Report On Leave + rep_cnfg_eutra->event.event_a3.report_on_leave = liblte_bits_2_value(ie_ptr, 1); + }else if(LIBLTE_RRC_EVENT_ID_EUTRA_A4 == rep_cnfg_eutra->event.event_id){ + // Threshold Type + rep_cnfg_eutra->event.event_a4.eutra.type = (LIBLTE_RRC_THRESHOLD_EUTRA_TYPE_ENUM)liblte_bits_2_value(ie_ptr, 1); + if(LIBLTE_RRC_THRESHOLD_EUTRA_TYPE_RSRP == rep_cnfg_eutra->event.event_a4.eutra.type) + { + liblte_rrc_unpack_rsrp_range_ie(ie_ptr, &rep_cnfg_eutra->event.event_a4.eutra.range); + }else{ + liblte_rrc_unpack_rsrq_range_ie(ie_ptr, &rep_cnfg_eutra->event.event_a4.eutra.range); + } + }else if(LIBLTE_RRC_EVENT_ID_EUTRA_A5 == rep_cnfg_eutra->event.event_id){ + // Threshold1 Type + rep_cnfg_eutra->event.event_a5.eutra1.type = (LIBLTE_RRC_THRESHOLD_EUTRA_TYPE_ENUM)liblte_bits_2_value(ie_ptr, 1); + if(LIBLTE_RRC_THRESHOLD_EUTRA_TYPE_RSRP == rep_cnfg_eutra->event.event_a5.eutra1.type) + { + liblte_rrc_unpack_rsrp_range_ie(ie_ptr, &rep_cnfg_eutra->event.event_a5.eutra1.range); + }else{ + liblte_rrc_unpack_rsrq_range_ie(ie_ptr, &rep_cnfg_eutra->event.event_a5.eutra1.range); + } + + // Threshold2 Type + rep_cnfg_eutra->event.event_a5.eutra2.type = (LIBLTE_RRC_THRESHOLD_EUTRA_TYPE_ENUM)liblte_bits_2_value(ie_ptr, 1); + if(LIBLTE_RRC_THRESHOLD_EUTRA_TYPE_RSRP == rep_cnfg_eutra->event.event_a5.eutra2.type) + { + liblte_rrc_unpack_rsrp_range_ie(ie_ptr, &rep_cnfg_eutra->event.event_a5.eutra2.range); + }else{ + liblte_rrc_unpack_rsrq_range_ie(ie_ptr, &rep_cnfg_eutra->event.event_a5.eutra2.range); + } + }else{ + // Offset + rep_cnfg_eutra->event.event_a6.offset = liblte_bits_2_value(ie_ptr, 6) - 30; + + // Report On Leave + rep_cnfg_eutra->event.event_a6.report_on_leave = liblte_bits_2_value(ie_ptr, 1); + } + + // Hysteresis + liblte_rrc_unpack_hysteresis_ie(ie_ptr, &rep_cnfg_eutra->event.hysteresis); + + // Time To Trigger + liblte_rrc_unpack_time_to_trigger_ie(ie_ptr, &rep_cnfg_eutra->event.time_to_trigger); + }else{ + // Purpose + rep_cnfg_eutra->periodical.purpose = (LIBLTE_RRC_PURPOSE_EUTRA_ENUM)liblte_bits_2_value(ie_ptr, 1); + } + + // Trigger Quantity + rep_cnfg_eutra->trigger_quantity = (LIBLTE_RRC_TRIGGER_QUANTITY_ENUM)liblte_bits_2_value(ie_ptr, 1); + + // Report Quantity + rep_cnfg_eutra->report_quantity = (LIBLTE_RRC_REPORT_QUANTITY_ENUM)liblte_bits_2_value(ie_ptr, 1); + + // Max Report Cells + rep_cnfg_eutra->max_report_cells = liblte_bits_2_value(ie_ptr, 3) + 1; + + // Report Interval + liblte_rrc_unpack_report_interval_ie(ie_ptr, &rep_cnfg_eutra->report_interval); + + // Report Amount + rep_cnfg_eutra->report_amount = (LIBLTE_RRC_REPORT_AMOUNT_ENUM)liblte_bits_2_value(ie_ptr, 3); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Report Config ID + + Description: Identifies a measurement reporting configuration + + Document Reference: 36.331 v10.0.0 Section 6.3.5 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_report_config_id_ie(uint8 report_cnfg_id, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL) + { + liblte_value_2_bits(report_cnfg_id - 1, ie_ptr, 5); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_report_config_id_ie(uint8 **ie_ptr, + uint8 *report_cnfg_id) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + report_cnfg_id != NULL) + { + *report_cnfg_id = liblte_bits_2_value(ie_ptr, 5) + 1; + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Report Config Inter RAT + + Description: Specifies criteria for triggering of an inter-RAT + measurement reporting event + + Document Reference: 36.331 v10.0.0 Section 6.3.5 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_report_config_inter_rat_ie(LIBLTE_RRC_REPORT_CONFIG_INTER_RAT_STRUCT *rep_cnfg_inter_rat, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(rep_cnfg_inter_rat != NULL && + ie_ptr != NULL) + { + // Extension indicator + liblte_value_2_bits(0, ie_ptr, 1); + + // Trigger Type + liblte_value_2_bits(rep_cnfg_inter_rat->trigger_type, ie_ptr, 1); + if(LIBLTE_RRC_TRIGGER_TYPE_INTER_RAT_EVENT == rep_cnfg_inter_rat->trigger_type) + { + // Event ID + liblte_value_2_bits(rep_cnfg_inter_rat->event.event_id, ie_ptr, 1); + if(LIBLTE_RRC_EVENT_ID_INTER_RAT_B1 == rep_cnfg_inter_rat->event.event_id) + { + // Threshold Type + liblte_value_2_bits(rep_cnfg_inter_rat->event.event_b1.type, ie_ptr, 2); + if(LIBLTE_RRC_THRESHOLD_INTER_RAT_TYPE_UTRA == rep_cnfg_inter_rat->event.event_b1.type) + { + // Type + liblte_value_2_bits(rep_cnfg_inter_rat->event.event_b1.utra.type, ie_ptr, 1); + if(LIBLTE_RRC_THRESHOLD_UTRA_TYPE_RSCP == rep_cnfg_inter_rat->event.event_b1.utra.type) + { + liblte_value_2_bits(rep_cnfg_inter_rat->event.event_b1.utra.value + 5, ie_ptr, 7); + }else{ + liblte_value_2_bits(rep_cnfg_inter_rat->event.event_b1.utra.value, ie_ptr, 6); + } + }else if(LIBLTE_RRC_THRESHOLD_INTER_RAT_TYPE_GERAN == rep_cnfg_inter_rat->event.event_b1.type){ + liblte_value_2_bits(rep_cnfg_inter_rat->event.event_b1.geran, ie_ptr, 6); + }else{ + liblte_value_2_bits(rep_cnfg_inter_rat->event.event_b1.cdma2000, ie_ptr, 6); + } + }else{ + // Threshold1 Type + liblte_value_2_bits(rep_cnfg_inter_rat->event.event_b2.eutra.type, ie_ptr, 1); + if(LIBLTE_RRC_THRESHOLD_EUTRA_TYPE_RSRP == rep_cnfg_inter_rat->event.event_b2.eutra.type) + { + liblte_rrc_pack_rsrp_range_ie(rep_cnfg_inter_rat->event.event_b2.eutra.range, ie_ptr); + }else{ + liblte_rrc_pack_rsrq_range_ie(rep_cnfg_inter_rat->event.event_b2.eutra.range, ie_ptr); + } + + // Threshold2 Type + liblte_value_2_bits(rep_cnfg_inter_rat->event.event_b2.type2, ie_ptr, 2); + if(LIBLTE_RRC_THRESHOLD_INTER_RAT_TYPE_UTRA == rep_cnfg_inter_rat->event.event_b2.type2) + { + // Type + liblte_value_2_bits(rep_cnfg_inter_rat->event.event_b2.utra.type, ie_ptr, 1); + if(LIBLTE_RRC_THRESHOLD_UTRA_TYPE_RSCP == rep_cnfg_inter_rat->event.event_b2.utra.type) + { + liblte_value_2_bits(rep_cnfg_inter_rat->event.event_b2.utra.value + 5, ie_ptr, 7); + }else{ + liblte_value_2_bits(rep_cnfg_inter_rat->event.event_b2.utra.value, ie_ptr, 6); + } + }else if(LIBLTE_RRC_THRESHOLD_INTER_RAT_TYPE_GERAN == rep_cnfg_inter_rat->event.event_b2.type2){ + liblte_value_2_bits(rep_cnfg_inter_rat->event.event_b2.geran, ie_ptr, 6); + }else{ + liblte_value_2_bits(rep_cnfg_inter_rat->event.event_b2.cdma2000, ie_ptr, 6); + } + } + + // Hysteresis + liblte_rrc_pack_hysteresis_ie(rep_cnfg_inter_rat->event.hysteresis, ie_ptr); + + // Time To Trigger + liblte_rrc_pack_time_to_trigger_ie(rep_cnfg_inter_rat->event.time_to_trigger, ie_ptr); + }else{ + // Purpose + liblte_value_2_bits(rep_cnfg_inter_rat->periodical.purpose, ie_ptr, 2); + } + + // Max Report Cells + liblte_value_2_bits(rep_cnfg_inter_rat->max_report_cells - 1, ie_ptr, 3); + + // Report Interval + liblte_rrc_pack_report_interval_ie(rep_cnfg_inter_rat->report_interval, ie_ptr); + + // Report Amount + liblte_value_2_bits(rep_cnfg_inter_rat->report_amount, ie_ptr, 3); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_report_config_inter_rat_ie(uint8 **ie_ptr, + LIBLTE_RRC_REPORT_CONFIG_INTER_RAT_STRUCT *rep_cnfg_inter_rat) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + rep_cnfg_inter_rat != NULL) + { + // Extension indicator + liblte_bits_2_value(ie_ptr, 1); + + // Trigger Type + rep_cnfg_inter_rat->trigger_type = (LIBLTE_RRC_TRIGGER_TYPE_INTER_RAT_ENUM)liblte_bits_2_value(ie_ptr, 1); + if(LIBLTE_RRC_TRIGGER_TYPE_INTER_RAT_EVENT == rep_cnfg_inter_rat->trigger_type) + { + // Event ID + rep_cnfg_inter_rat->event.event_id = (LIBLTE_RRC_EVENT_ID_INTER_RAT_ENUM)liblte_bits_2_value(ie_ptr, 1); + if(LIBLTE_RRC_EVENT_ID_INTER_RAT_B1 == rep_cnfg_inter_rat->event.event_id) + { + // Threshold Type + rep_cnfg_inter_rat->event.event_b1.type = (LIBLTE_RRC_THRESHOLD_INTER_RAT_TYPE_ENUM)liblte_bits_2_value(ie_ptr, 2); + if(LIBLTE_RRC_THRESHOLD_INTER_RAT_TYPE_UTRA == rep_cnfg_inter_rat->event.event_b1.type) + { + // Type + rep_cnfg_inter_rat->event.event_b1.utra.type = (LIBLTE_RRC_THRESHOLD_UTRA_TYPE_ENUM)liblte_bits_2_value(ie_ptr, 1); + if(LIBLTE_RRC_THRESHOLD_UTRA_TYPE_RSCP == rep_cnfg_inter_rat->event.event_b1.utra.type) + { + rep_cnfg_inter_rat->event.event_b1.utra.value = liblte_bits_2_value(ie_ptr, 7) - 5; + }else{ + rep_cnfg_inter_rat->event.event_b1.utra.value = liblte_bits_2_value(ie_ptr, 6); + } + }else if(LIBLTE_RRC_THRESHOLD_INTER_RAT_TYPE_GERAN == rep_cnfg_inter_rat->event.event_b1.type){ + rep_cnfg_inter_rat->event.event_b1.geran = liblte_bits_2_value(ie_ptr, 6); + }else{ + rep_cnfg_inter_rat->event.event_b1.cdma2000 = liblte_bits_2_value(ie_ptr, 6); + } + }else{ + // Threshold1 Type + rep_cnfg_inter_rat->event.event_b2.eutra.type = (LIBLTE_RRC_THRESHOLD_EUTRA_TYPE_ENUM)liblte_bits_2_value(ie_ptr, 1); + if(LIBLTE_RRC_THRESHOLD_EUTRA_TYPE_RSRP == rep_cnfg_inter_rat->event.event_b2.eutra.type) + { + liblte_rrc_unpack_rsrp_range_ie(ie_ptr, &rep_cnfg_inter_rat->event.event_b2.eutra.range); + }else{ + liblte_rrc_unpack_rsrq_range_ie(ie_ptr, &rep_cnfg_inter_rat->event.event_b2.eutra.range); + } + + // Threshold2 Type + rep_cnfg_inter_rat->event.event_b2.type2 = (LIBLTE_RRC_THRESHOLD_INTER_RAT_TYPE_ENUM)liblte_bits_2_value(ie_ptr, 2); + if(LIBLTE_RRC_THRESHOLD_INTER_RAT_TYPE_UTRA == rep_cnfg_inter_rat->event.event_b2.type2) + { + // Type + rep_cnfg_inter_rat->event.event_b2.utra.type = (LIBLTE_RRC_THRESHOLD_UTRA_TYPE_ENUM)liblte_bits_2_value(ie_ptr, 1); + if(LIBLTE_RRC_THRESHOLD_UTRA_TYPE_RSCP == rep_cnfg_inter_rat->event.event_b2.utra.type) + { + rep_cnfg_inter_rat->event.event_b2.utra.value = liblte_bits_2_value(ie_ptr, 7) - 5; + }else{ + rep_cnfg_inter_rat->event.event_b2.utra.value = liblte_bits_2_value(ie_ptr, 6); + } + }else if(LIBLTE_RRC_THRESHOLD_INTER_RAT_TYPE_GERAN == rep_cnfg_inter_rat->event.event_b2.type2){ + rep_cnfg_inter_rat->event.event_b2.geran = liblte_bits_2_value(ie_ptr, 6); + }else{ + rep_cnfg_inter_rat->event.event_b2.cdma2000 = liblte_bits_2_value(ie_ptr, 6); + } + } + + // Hysteresis + liblte_rrc_unpack_hysteresis_ie(ie_ptr, &rep_cnfg_inter_rat->event.hysteresis); + + // Time To Trigger + liblte_rrc_unpack_time_to_trigger_ie(ie_ptr, &rep_cnfg_inter_rat->event.time_to_trigger); + }else{ + // Purpose + rep_cnfg_inter_rat->periodical.purpose = (LIBLTE_RRC_PURPOSE_INTER_RAT_ENUM)liblte_bits_2_value(ie_ptr, 2); + } + + // Max Report Cells + rep_cnfg_inter_rat->max_report_cells = liblte_bits_2_value(ie_ptr, 3) + 1; + + // Report Interval + liblte_rrc_unpack_report_interval_ie(ie_ptr, &rep_cnfg_inter_rat->report_interval); + + // Report Amount + rep_cnfg_inter_rat->report_amount = (LIBLTE_RRC_REPORT_AMOUNT_ENUM)liblte_bits_2_value(ie_ptr, 3); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Report Config To Add Mod List + + Description: Concerns a list of reporting configurations to add + or modify + + Document Reference: 36.331 v10.0.0 Section 6.3.5 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_report_config_to_add_mod_list_ie(LIBLTE_RRC_REPORT_CONFIG_TO_ADD_MOD_LIST_STRUCT *list, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint32 i; + + if(list != NULL && + ie_ptr != NULL) + { + // List Size + liblte_value_2_bits(list->N_rep_cnfg - 1, ie_ptr, 5); + + for(i=0; iN_rep_cnfg; i++) + { + // Report Config ID + liblte_rrc_pack_report_config_id_ie(list->rep_cnfg_list[i].rep_cnfg_id, ie_ptr); + + // Report Config Choice + liblte_value_2_bits(list->rep_cnfg_list[i].rep_cnfg_type, ie_ptr, 1); + + if(LIBLTE_RRC_REPORT_CONFIG_TYPE_EUTRA == list->rep_cnfg_list[i].rep_cnfg_type) + { + liblte_rrc_pack_report_config_eutra_ie(&list->rep_cnfg_list[i].rep_cnfg_eutra, ie_ptr); + }else{ + liblte_rrc_pack_report_config_inter_rat_ie(&list->rep_cnfg_list[i].rep_cnfg_inter_rat, ie_ptr); + } + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_report_config_to_add_mod_list_ie(uint8 **ie_ptr, + LIBLTE_RRC_REPORT_CONFIG_TO_ADD_MOD_LIST_STRUCT *list) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint32 i; + + if(ie_ptr != NULL && + list != NULL) + { + // List Size + list->N_rep_cnfg = liblte_bits_2_value(ie_ptr, 5) + 1; + + for(i=0; iN_rep_cnfg; i++) + { + // Report Config ID + liblte_rrc_unpack_report_config_id_ie(ie_ptr, &list->rep_cnfg_list[i].rep_cnfg_id); + + // Report Config Choice + list->rep_cnfg_list[i].rep_cnfg_type = (LIBLTE_RRC_REPORT_CONFIG_TYPE_ENUM)liblte_bits_2_value(ie_ptr, 1); + + if(LIBLTE_RRC_REPORT_CONFIG_TYPE_EUTRA == list->rep_cnfg_list[i].rep_cnfg_type) + { + liblte_rrc_unpack_report_config_eutra_ie(ie_ptr, &list->rep_cnfg_list[i].rep_cnfg_eutra); + }else{ + liblte_rrc_unpack_report_config_inter_rat_ie(ie_ptr, &list->rep_cnfg_list[i].rep_cnfg_inter_rat); + } + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Report Interval + + Description: Indicates the interval between periodic reports + + Document Reference: 36.331 v10.0.0 Section 6.3.5 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_report_interval_ie(LIBLTE_RRC_REPORT_INTERVAL_ENUM report_int, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL) + { + liblte_value_2_bits(report_int, ie_ptr, 4); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_report_interval_ie(uint8 **ie_ptr, + LIBLTE_RRC_REPORT_INTERVAL_ENUM *report_int) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + report_int != NULL) + { + *report_int = (LIBLTE_RRC_REPORT_INTERVAL_ENUM)liblte_bits_2_value(ie_ptr, 4); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: RSRP Range + + Description: Specifies the value range used in RSRP measurements + and thresholds + + Document Reference: 36.331 v10.0.0 Section 6.3.5 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_rsrp_range_ie(uint8 rsrp_range, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL) + { + liblte_value_2_bits(rsrp_range, ie_ptr, 7); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_rsrp_range_ie(uint8 **ie_ptr, + uint8 *rsrp_range) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + rsrp_range != NULL) + { + *rsrp_range = liblte_bits_2_value(ie_ptr, 7); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: RSRQ Range + + Description: Specifies the value range used in RSRQ measurements + and thresholds + + Document Reference: 36.331 v10.0.0 Section 6.3.5 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_rsrq_range_ie(uint8 rsrq_range, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL) + { + liblte_value_2_bits(rsrq_range, ie_ptr, 6); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_rsrq_range_ie(uint8 **ie_ptr, + uint8 *rsrq_range) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + rsrq_range != NULL) + { + *rsrq_range = liblte_bits_2_value(ie_ptr, 6); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Time To Trigger + + Description: Specifies the value range used for the time to + trigger parameter, which concerns the time during + which specific criteria for the event needs to be + met in order to trigger a measurement report + + Document Reference: 36.331 v10.0.0 Section 6.3.5 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_time_to_trigger_ie(LIBLTE_RRC_TIME_TO_TRIGGER_ENUM time_to_trigger, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL) + { + liblte_value_2_bits(time_to_trigger, ie_ptr, 4); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_time_to_trigger_ie(uint8 **ie_ptr, + LIBLTE_RRC_TIME_TO_TRIGGER_ENUM *time_to_trigger) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + time_to_trigger != NULL) + { + *time_to_trigger = (LIBLTE_RRC_TIME_TO_TRIGGER_ENUM)liblte_bits_2_value(ie_ptr, 4); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Additional Spectrum Emission + + Description: FIXME + + Document Reference: 36.331 v10.0.0 Section 6.3.4 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_additional_spectrum_emission_ie(uint8 add_spect_em, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL) + { + liblte_value_2_bits(add_spect_em - 1, ie_ptr, 5); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_additional_spectrum_emission_ie(uint8 **ie_ptr, + uint8 *add_spect_em) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + add_spect_em != NULL) + { + *add_spect_em = liblte_bits_2_value(ie_ptr, 5) + 1; + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: ARFCN value CDMA2000 + + Description: Indicates the CDMA2000 carrier frequency within + a CDMA2000 band + + Document Reference: 36.331 v10.0.0 Section 6.3.4 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_arfcn_value_cdma2000_ie(uint16 arfcn, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL) + { + liblte_value_2_bits(arfcn, ie_ptr, 11); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_arfcn_value_cdma2000_ie(uint8 **ie_ptr, + uint16 *arfcn) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + arfcn != NULL) + { + *arfcn = liblte_bits_2_value(ie_ptr, 11); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: ARFCN value EUTRA + + Description: Indicates the ARFCN applicable for a downlink, + uplink, or bi-directional (TDD) E-UTRA carrier + frequency + + Document Reference: 36.331 v10.0.0 Section 6.3.4 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_arfcn_value_eutra_ie(uint16 arfcn, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL) + { + liblte_value_2_bits(arfcn, ie_ptr, 16); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_arfcn_value_eutra_ie(uint8 **ie_ptr, + uint16 *arfcn) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + arfcn != NULL) + { + *arfcn = liblte_bits_2_value(ie_ptr, 16); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: ARFCN value GERAN + + Description: Specifies the ARFCN value applicable for a GERAN + BCCH carrier frequency + + Document Reference: 36.331 v10.0.0 Section 6.3.4 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_arfcn_value_geran_ie(uint16 arfcn, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL) + { + liblte_value_2_bits(arfcn, ie_ptr, 10); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_arfcn_value_geran_ie(uint8 **ie_ptr, + uint16 *arfcn) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + arfcn != NULL) + { + *arfcn = liblte_bits_2_value(ie_ptr, 10); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: ARFCN value UTRA + + Description: Indicates the ARFCN applicable for a downlink (Nd, + FDD) or bi-directional (Nt, TDD) UTRA carrier + frequency + + Document Reference: 36.331 v10.0.0 Section 6.3.4 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_arfcn_value_utra_ie(uint16 arfcn, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL) + { + liblte_value_2_bits(arfcn, ie_ptr, 14); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_arfcn_value_utra_ie(uint8 **ie_ptr, + uint16 *arfcn) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + arfcn != NULL) + { + *arfcn = liblte_bits_2_value(ie_ptr, 14); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Band Class CDMA2000 + + Description: Defines the CDMA2000 band in which the CDMA2000 + carrier frequency can be found + + Document Reference: 36.331 v10.0.0 Section 6.3.4 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_band_class_cdma2000_ie(LIBLTE_RRC_BAND_CLASS_CDMA2000_ENUM bc_cdma2000, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL) + { + // Extension indicator + liblte_value_2_bits(0, ie_ptr, 1); + + liblte_value_2_bits(bc_cdma2000, ie_ptr, 5); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_band_class_cdma2000_ie(uint8 **ie_ptr, + LIBLTE_RRC_BAND_CLASS_CDMA2000_ENUM *bc_cdma2000) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + bc_cdma2000 != NULL) + { + // Extension indicator + liblte_bits_2_value(ie_ptr, 1); + + *bc_cdma2000 = (LIBLTE_RRC_BAND_CLASS_CDMA2000_ENUM)liblte_bits_2_value(ie_ptr, 5); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Band Indicator GERAN + + Description: Indicates how to interpret an associated GERAN + carrier ARFCN + + Document Reference: 36.331 v10.0.0 Section 6.3.4 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_band_indicator_geran_ie(LIBLTE_RRC_BAND_INDICATOR_GERAN_ENUM bi_geran, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL) + { + liblte_value_2_bits(bi_geran, ie_ptr, 1); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_band_indicator_geran_ie(uint8 **ie_ptr, + LIBLTE_RRC_BAND_INDICATOR_GERAN_ENUM *bi_geran) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + bi_geran != NULL) + { + *bi_geran = (LIBLTE_RRC_BAND_INDICATOR_GERAN_ENUM)liblte_bits_2_value(ie_ptr, 1); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Carrier Freq CDMA2000 + + Description: Provides the CDMA2000 carrier information + + Document Reference: 36.331 v10.0.0 Section 6.3.4 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_carrier_freq_cdma2000_ie(LIBLTE_RRC_CARRIER_FREQ_CDMA2000_STRUCT *carrier_freq, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(carrier_freq != NULL && + ie_ptr != NULL) + { + liblte_rrc_pack_band_class_cdma2000_ie(carrier_freq->bandclass, ie_ptr); + liblte_rrc_pack_arfcn_value_cdma2000_ie(carrier_freq->arfcn, ie_ptr); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_carrier_freq_cdma2000_ie(uint8 **ie_ptr, + LIBLTE_RRC_CARRIER_FREQ_CDMA2000_STRUCT *carrier_freq) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + carrier_freq != NULL) + { + liblte_rrc_unpack_band_class_cdma2000_ie(ie_ptr, &carrier_freq->bandclass); + liblte_rrc_unpack_arfcn_value_cdma2000_ie(ie_ptr, &carrier_freq->arfcn); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Carrier Freq GERAN + + Description: Provides an unambiguous carrier frequency description + of a GERAN cell + + Document Reference: 36.331 v10.0.0 Section 6.3.4 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_carrier_freq_geran_ie(LIBLTE_RRC_CARRIER_FREQ_GERAN_STRUCT *carrier_freq, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(carrier_freq != NULL && + ie_ptr != NULL) + { + liblte_rrc_pack_arfcn_value_geran_ie(carrier_freq->arfcn, ie_ptr); + liblte_rrc_pack_band_indicator_geran_ie(carrier_freq->band_indicator, ie_ptr); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_carrier_freq_geran_ie(uint8 **ie_ptr, + LIBLTE_RRC_CARRIER_FREQ_GERAN_STRUCT *carrier_freq) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + carrier_freq != NULL) + { + liblte_rrc_unpack_arfcn_value_geran_ie(ie_ptr, &carrier_freq->arfcn); + liblte_rrc_unpack_band_indicator_geran_ie(ie_ptr, &carrier_freq->band_indicator); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Carrier Freqs GERAN + + Description: Provides one or more GERAN ARFCN values, which + represent a list of GERAN BCCH carrier frequencies + + Document Reference: 36.331 v10.0.0 Section 6.3.4 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_carrier_freqs_geran_ie(LIBLTE_RRC_CARRIER_FREQS_GERAN_STRUCT *carrier_freqs, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint32 i; + + if(carrier_freqs != NULL && + ie_ptr != NULL) + { + liblte_rrc_pack_arfcn_value_geran_ie(carrier_freqs->starting_arfcn, ie_ptr); + liblte_rrc_pack_band_indicator_geran_ie(carrier_freqs->band_indicator, ie_ptr); + liblte_value_2_bits(carrier_freqs->following_arfcns, ie_ptr, 2); + if(LIBLTE_RRC_FOLLOWING_ARFCNS_EXPLICIT_LIST == carrier_freqs->following_arfcns) + { + liblte_value_2_bits(carrier_freqs->explicit_list_of_arfcns_size, ie_ptr, 5); + for(i=0; iexplicit_list_of_arfcns_size; i++) + { + liblte_rrc_pack_arfcn_value_geran_ie(carrier_freqs->explicit_list_of_arfcns[i], ie_ptr); + } + }else if(LIBLTE_RRC_FOLLOWING_ARFCNS_EQUALLY_SPACED == carrier_freqs->following_arfcns){ + liblte_value_2_bits(carrier_freqs->equally_spaced_arfcns.arfcn_spacing - 1, ie_ptr, 3); + liblte_value_2_bits(carrier_freqs->equally_spaced_arfcns.number_of_arfcns, ie_ptr, 5); + }else{ // LIBLTE_RRC_FOLLOWING_ARFCNS_VARIABLE_BIT_MAP == carrier_freqs->following_arfcns + liblte_value_2_bits(carrier_freqs->variable_bit_map_of_arfcns, ie_ptr, 16); + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_carrier_freqs_geran_ie(uint8 **ie_ptr, + LIBLTE_RRC_CARRIER_FREQS_GERAN_STRUCT *carrier_freqs) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint32 i; + + if(ie_ptr != NULL && + carrier_freqs != NULL) + { + liblte_rrc_unpack_arfcn_value_geran_ie(ie_ptr, &carrier_freqs->starting_arfcn); + liblte_rrc_unpack_band_indicator_geran_ie(ie_ptr, &carrier_freqs->band_indicator); + carrier_freqs->following_arfcns = (LIBLTE_RRC_FOLLOWING_ARFCNS_ENUM)liblte_bits_2_value(ie_ptr, 2); + if(LIBLTE_RRC_FOLLOWING_ARFCNS_EXPLICIT_LIST == carrier_freqs->following_arfcns) + { + carrier_freqs->explicit_list_of_arfcns_size = liblte_bits_2_value(ie_ptr, 5); + for(i=0; iexplicit_list_of_arfcns_size; i++) + { + liblte_rrc_unpack_arfcn_value_geran_ie(ie_ptr, &carrier_freqs->explicit_list_of_arfcns[i]); + } + }else if(LIBLTE_RRC_FOLLOWING_ARFCNS_EQUALLY_SPACED == carrier_freqs->following_arfcns){ + carrier_freqs->equally_spaced_arfcns.arfcn_spacing = liblte_bits_2_value(ie_ptr, 3) + 1; + carrier_freqs->equally_spaced_arfcns.number_of_arfcns = liblte_bits_2_value(ie_ptr, 5); + }else{ // LIBLTE_RRC_FOLLOWING_ARFCNS_VARIABLE_BIT_MAP == carrier_freqs->following_arfcns + carrier_freqs->variable_bit_map_of_arfcns = liblte_bits_2_value(ie_ptr, 16); + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: CDMA2000 Type + + Description: Describes the type of CDMA2000 network + + Document Reference: 36.331 v10.0.0 Section 6.3.4 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_cdma2000_type_ie(LIBLTE_RRC_CDMA2000_TYPE_ENUM cdma2000_type, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL) + { + liblte_value_2_bits(cdma2000_type, ie_ptr, 1); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_cdma2000_type_ie(uint8 **ie_ptr, + LIBLTE_RRC_CDMA2000_TYPE_ENUM *cdma2000_type) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + cdma2000_type != NULL) + { + *cdma2000_type = (LIBLTE_RRC_CDMA2000_TYPE_ENUM)liblte_bits_2_value(ie_ptr, 1); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Cell Identity + + Description: Unambiguously identifies a cell within a PLMN + + Document Reference: 36.331 v10.0.0 Section 6.3.4 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_cell_identity_ie(uint32 cell_id, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL) + { + liblte_value_2_bits(cell_id, ie_ptr, 28); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_cell_identity_ie(uint8 **ie_ptr, + uint32 *cell_id) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + cell_id != NULL) + { + *cell_id = liblte_bits_2_value(ie_ptr, 28); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Cell Index List + + Description: Concerns a list of cell indecies, which may be used + for different purposes + + Document Reference: 36.331 v10.0.0 Section 6.3.4 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_cell_index_list_ie(LIBLTE_RRC_CELL_INDEX_LIST_STRUCT *cell_idx_list, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint32 i; + + if(cell_idx_list != NULL && + ie_ptr != NULL) + { + // List Size + liblte_value_2_bits(cell_idx_list->N_cell_idx - 1, ie_ptr, 5); + + for(i=0; iN_cell_idx; i++) + { + // Cell Index + liblte_value_2_bits(cell_idx_list->cell_idx[i] - 1, ie_ptr, 5); + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_cell_index_list_ie(uint8 **ie_ptr, + LIBLTE_RRC_CELL_INDEX_LIST_STRUCT *cell_idx_list) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint32 i; + + if(ie_ptr != NULL && + cell_idx_list != NULL) + { + // List Size + cell_idx_list->N_cell_idx = liblte_bits_2_value(ie_ptr, 5) + 1; + + for(i=0; iN_cell_idx; i++) + { + // Cell Index + cell_idx_list->cell_idx[i] = liblte_bits_2_value(ie_ptr, 5) + 1; + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Cell Reselection Priority + + Description: Contains the absolute priority of the concerned + carrier frequency/set of frequencies (GERAN)/ + bandclass (CDMA2000), as used by the cell + reselection procedure + + Document Reference: 36.331 v10.0.0 Section 6.3.4 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_cell_reselection_priority_ie(uint8 cell_resel_prio, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL) + { + liblte_value_2_bits(cell_resel_prio, ie_ptr, 3); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_cell_reselection_priority_ie(uint8 **ie_ptr, + uint8 *cell_resel_prio) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + cell_resel_prio != NULL) + { + *cell_resel_prio = liblte_bits_2_value(ie_ptr, 3); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: CSFB Registration Param 1xRTT + + Description: Indicates whether or not the UE shall perform a + CDMA2000 1xRTT pre-registration if the UE does not + have a valid/current pre-registration + + Document Reference: 36.331 v10.0.0 Section 6.3.4 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_csfb_registration_param_1xrtt_ie(LIBLTE_RRC_CSFB_REGISTRATION_PARAM_1XRTT_STRUCT *csfb_reg_param, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(csfb_reg_param != NULL && + ie_ptr != NULL) + { + liblte_value_2_bits(csfb_reg_param->sid, ie_ptr, 15); + liblte_value_2_bits(csfb_reg_param->nid, ie_ptr, 16); + liblte_value_2_bits(csfb_reg_param->multiple_sid, ie_ptr, 1); + liblte_value_2_bits(csfb_reg_param->multiple_nid, ie_ptr, 1); + liblte_value_2_bits(csfb_reg_param->home_reg, ie_ptr, 1); + liblte_value_2_bits(csfb_reg_param->foreign_sid_reg, ie_ptr, 1); + liblte_value_2_bits(csfb_reg_param->foreign_nid_reg, ie_ptr, 1); + liblte_value_2_bits(csfb_reg_param->param_reg, ie_ptr, 1); + liblte_value_2_bits(csfb_reg_param->power_up_reg, ie_ptr, 1); + liblte_value_2_bits(csfb_reg_param->reg_period, ie_ptr, 7); + liblte_value_2_bits(csfb_reg_param->reg_zone, ie_ptr, 12); + liblte_value_2_bits(csfb_reg_param->total_zone, ie_ptr, 3); + liblte_value_2_bits(csfb_reg_param->zone_timer, ie_ptr, 3); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_csfb_registration_param_1xrtt_ie(uint8 **ie_ptr, + LIBLTE_RRC_CSFB_REGISTRATION_PARAM_1XRTT_STRUCT *csfb_reg_param) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + csfb_reg_param != NULL) + { + csfb_reg_param->sid = liblte_bits_2_value(ie_ptr, 15); + csfb_reg_param->nid = liblte_bits_2_value(ie_ptr, 16); + csfb_reg_param->multiple_sid = liblte_bits_2_value(ie_ptr, 1); + csfb_reg_param->multiple_nid = liblte_bits_2_value(ie_ptr, 1); + csfb_reg_param->home_reg = liblte_bits_2_value(ie_ptr, 1); + csfb_reg_param->foreign_sid_reg = liblte_bits_2_value(ie_ptr, 1); + csfb_reg_param->foreign_nid_reg = liblte_bits_2_value(ie_ptr, 1); + csfb_reg_param->param_reg = liblte_bits_2_value(ie_ptr, 1); + csfb_reg_param->power_up_reg = liblte_bits_2_value(ie_ptr, 1); + csfb_reg_param->reg_period = liblte_bits_2_value(ie_ptr, 7); + csfb_reg_param->reg_zone = liblte_bits_2_value(ie_ptr, 12); + csfb_reg_param->total_zone = liblte_bits_2_value(ie_ptr, 3); + csfb_reg_param->zone_timer = liblte_bits_2_value(ie_ptr, 3); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_pack_csfb_registration_param_1xrtt_v920_ie(LIBLTE_RRC_CSFB_REGISTRATION_PARAM_1XRTT_V920_STRUCT *csfb_reg_param, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(csfb_reg_param != NULL && + ie_ptr != NULL) + { + liblte_value_2_bits(csfb_reg_param->power_down_reg, ie_ptr, 1); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_csfb_registration_param_1xrtt_v920_ie(uint8 **ie_ptr, + LIBLTE_RRC_CSFB_REGISTRATION_PARAM_1XRTT_V920_STRUCT *csfb_reg_param) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + csfb_reg_param != NULL) + { + csfb_reg_param->power_down_reg = (LIBLTE_RRC_POWER_DOWN_REG_R9_ENUM)liblte_bits_2_value(ie_ptr, 1); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Cell Global ID EUTRA + + Description: Specifies the Evolved Cell Global Identifier (ECGI), + the globally unique identity of a cell in E-UTRA + + Document Reference: 36.331 v10.0.0 Section 6.3.4 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_cell_global_id_eutra_ie(LIBLTE_RRC_CELL_GLOBAL_ID_EUTRA_STRUCT *cell_global_id, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(cell_global_id != NULL && + ie_ptr != NULL) + { + liblte_rrc_pack_plmn_identity_ie(&cell_global_id->plmn_id, ie_ptr); + liblte_rrc_pack_cell_identity_ie(cell_global_id->cell_id, ie_ptr); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_cell_global_id_eutra_ie(uint8 **ie_ptr, + LIBLTE_RRC_CELL_GLOBAL_ID_EUTRA_STRUCT *cell_global_id) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + cell_global_id != NULL) + { + liblte_rrc_unpack_plmn_identity_ie(ie_ptr, &cell_global_id->plmn_id); + liblte_rrc_unpack_cell_identity_ie(ie_ptr, &cell_global_id->cell_id); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Cell Global ID UTRA + + Description: Specifies the global UTRAN Cell Identifier, the + globally unique identity of a cell in UTRA + + Document Reference: 36.331 v10.0.0 Section 6.3.4 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_cell_global_id_utra_ie(LIBLTE_RRC_CELL_GLOBAL_ID_UTRA_STRUCT *cell_global_id, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(cell_global_id != NULL && + ie_ptr != NULL) + { + liblte_rrc_pack_plmn_identity_ie(&cell_global_id->plmn_id, ie_ptr); + liblte_value_2_bits(cell_global_id->cell_id, ie_ptr, 28); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_cell_global_id_utra_ie(uint8 **ie_ptr, + LIBLTE_RRC_CELL_GLOBAL_ID_UTRA_STRUCT *cell_global_id) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + cell_global_id != NULL) + { + liblte_rrc_unpack_plmn_identity_ie(ie_ptr, &cell_global_id->plmn_id); + cell_global_id->cell_id = liblte_bits_2_value(ie_ptr, 28); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Cell Global ID GERAN + + Description: Specifies the Cell Global Identity (CGI), the + globally unique identity of a cell in GERAN + + Document Reference: 36.331 v10.0.0 Section 6.3.4 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_cell_global_id_geran_ie(LIBLTE_RRC_CELL_GLOBAL_ID_GERAN_STRUCT *cell_global_id, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(cell_global_id != NULL && + ie_ptr != NULL) + { + liblte_rrc_pack_plmn_identity_ie(&cell_global_id->plmn_id, ie_ptr); + liblte_value_2_bits(cell_global_id->lac, ie_ptr, 16); + liblte_value_2_bits(cell_global_id->cell_id, ie_ptr, 16); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_cell_global_id_geran_ie(uint8 **ie_ptr, + LIBLTE_RRC_CELL_GLOBAL_ID_GERAN_STRUCT *cell_global_id) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + cell_global_id != NULL) + { + liblte_rrc_unpack_plmn_identity_ie(ie_ptr, &cell_global_id->plmn_id); + cell_global_id->lac = liblte_bits_2_value(ie_ptr, 16); + cell_global_id->cell_id = liblte_bits_2_value(ie_ptr, 16); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Cell Global ID CDMA2000 + + Description: Specifies the Cell Global Identity (CGI), the + globally unique identity of a cell in CDMA2000 + + Document Reference: 36.331 v10.0.0 Section 6.3.4 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_cell_global_id_cdma2000_ie(LIBLTE_RRC_CELL_GLOBAL_ID_CDMA2000_STRUCT *cell_global_id, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(cell_global_id != NULL && + ie_ptr != NULL) + { + liblte_value_2_bits((uint32)(cell_global_id->onexrtt >> 15), ie_ptr, 32); + liblte_value_2_bits((uint32)(cell_global_id->onexrtt & 0x7FFFULL), ie_ptr, 15); + liblte_value_2_bits(cell_global_id->hrpd[0], ie_ptr, 32); + liblte_value_2_bits(cell_global_id->hrpd[1], ie_ptr, 32); + liblte_value_2_bits(cell_global_id->hrpd[2], ie_ptr, 32); + liblte_value_2_bits(cell_global_id->hrpd[3], ie_ptr, 32); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_cell_global_id_cdma2000_ie(uint8 **ie_ptr, + LIBLTE_RRC_CELL_GLOBAL_ID_CDMA2000_STRUCT *cell_global_id) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + cell_global_id != NULL) + { + cell_global_id->onexrtt = (uint64)liblte_bits_2_value(ie_ptr, 32) << 15; + cell_global_id->onexrtt |= (uint64)liblte_bits_2_value(ie_ptr, 15); + cell_global_id->hrpd[0] = liblte_bits_2_value(ie_ptr, 32); + cell_global_id->hrpd[1] = liblte_bits_2_value(ie_ptr, 32); + cell_global_id->hrpd[2] = liblte_bits_2_value(ie_ptr, 32); + cell_global_id->hrpd[3] = liblte_bits_2_value(ie_ptr, 32); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: CSG Identity + + Description: Identifies a Closed Subscriber Group + + Document Reference: 36.331 v10.0.0 Section 6.3.4 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_csg_identity_ie(uint32 csg_id, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL) + { + liblte_value_2_bits(csg_id, ie_ptr, 27); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_csg_identity_ie(uint8 **ie_ptr, + uint32 *csg_id) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + csg_id != NULL) + { + *csg_id = liblte_bits_2_value(ie_ptr, 27); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Mobility Control Info + + Description: Includes parameters relevant for network controlled + mobility to/within E-UTRA + + Document Reference: 36.331 v10.0.0 Section 6.3.4 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_mobility_control_info_ie(LIBLTE_RRC_MOBILITY_CONTROL_INFO_STRUCT *mob_ctrl_info, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(mob_ctrl_info != NULL && + ie_ptr != NULL) + { + // Extension indicator + liblte_value_2_bits(0, ie_ptr, 1); + + // Optional indicators + liblte_value_2_bits(mob_ctrl_info->carrier_freq_eutra_present, ie_ptr, 1); + liblte_value_2_bits(mob_ctrl_info->carrier_bw_eutra_present, ie_ptr, 1); + liblte_value_2_bits(mob_ctrl_info->add_spect_em_present, ie_ptr, 1); + liblte_value_2_bits(mob_ctrl_info->rach_cnfg_ded_present, ie_ptr, 1); + + // Target Phys Cell ID + liblte_rrc_pack_phys_cell_id_ie(mob_ctrl_info->target_pci, ie_ptr); + + // Carrier Freq + if(mob_ctrl_info->carrier_freq_eutra_present) + { + // Optional indicator + liblte_value_2_bits(mob_ctrl_info->carrier_freq_eutra.ul_carrier_freq_present, ie_ptr, 1); + + // DL Carrier Freq + liblte_rrc_pack_arfcn_value_eutra_ie(mob_ctrl_info->carrier_freq_eutra.dl_carrier_freq, ie_ptr); + + // UL Carrier Freq + if(mob_ctrl_info->carrier_freq_eutra.ul_carrier_freq_present) + { + liblte_rrc_pack_arfcn_value_eutra_ie(mob_ctrl_info->carrier_freq_eutra.ul_carrier_freq, ie_ptr); + } + } + + // Carrier Bandwidth + if(mob_ctrl_info->carrier_bw_eutra_present) + { + // Optional indicator + liblte_value_2_bits(mob_ctrl_info->carrier_bw_eutra.ul_bw_present, ie_ptr, 1); + + // DL Bandwidth + liblte_value_2_bits(mob_ctrl_info->carrier_bw_eutra.dl_bw, ie_ptr, 4); + + // UL Bandwidth + if(mob_ctrl_info->carrier_bw_eutra.ul_bw_present) + { + liblte_value_2_bits(mob_ctrl_info->carrier_bw_eutra.ul_bw, ie_ptr, 4); + } + } + + // Additional Spectrum Emission + if(mob_ctrl_info->add_spect_em_present) + { + liblte_rrc_pack_additional_spectrum_emission_ie(mob_ctrl_info->add_spect_em, ie_ptr); + } + + // T304 + liblte_value_2_bits(mob_ctrl_info->t304, ie_ptr, 3); + + // New UE Identity + liblte_rrc_pack_c_rnti_ie(mob_ctrl_info->new_ue_id, ie_ptr); + + // Radio Resource Config Common + liblte_rrc_pack_rr_config_common_ie(&mob_ctrl_info->rr_cnfg_common, ie_ptr); + + // RACH Config Dedicated + if(mob_ctrl_info->rach_cnfg_ded_present) + { + liblte_rrc_pack_rach_config_dedicated_ie(&mob_ctrl_info->rach_cnfg_ded, ie_ptr); + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_mobility_control_info_ie(uint8 **ie_ptr, + LIBLTE_RRC_MOBILITY_CONTROL_INFO_STRUCT *mob_ctrl_info) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + mob_ctrl_info != NULL) + { + // Extension indicator + liblte_bits_2_value(ie_ptr, 1); + + // Optional indicators + mob_ctrl_info->carrier_freq_eutra_present = liblte_bits_2_value(ie_ptr, 1); + mob_ctrl_info->carrier_bw_eutra_present = liblte_bits_2_value(ie_ptr, 1); + mob_ctrl_info->add_spect_em_present = liblte_bits_2_value(ie_ptr, 1); + mob_ctrl_info->rach_cnfg_ded_present = liblte_bits_2_value(ie_ptr, 1); + + // Target Phys Cell ID + liblte_rrc_unpack_phys_cell_id_ie(ie_ptr, &mob_ctrl_info->target_pci); + + // Carrier Freq + if(mob_ctrl_info->carrier_freq_eutra_present) + { + // Optional indicator + mob_ctrl_info->carrier_freq_eutra.ul_carrier_freq_present = liblte_bits_2_value(ie_ptr, 1); + + // DL Carrier Freq + liblte_rrc_unpack_arfcn_value_eutra_ie(ie_ptr, &mob_ctrl_info->carrier_freq_eutra.dl_carrier_freq); + + // UL Carrier Freq + if(mob_ctrl_info->carrier_freq_eutra.ul_carrier_freq_present) + { + liblte_rrc_unpack_arfcn_value_eutra_ie(ie_ptr, &mob_ctrl_info->carrier_freq_eutra.ul_carrier_freq); + } + } + + // Carrier Bandwidth + if(mob_ctrl_info->carrier_bw_eutra_present) + { + // Optional indicator + mob_ctrl_info->carrier_bw_eutra.ul_bw_present = liblte_bits_2_value(ie_ptr, 1); + + // DL Bandwidth + mob_ctrl_info->carrier_bw_eutra.dl_bw = (LIBLTE_RRC_BANDWIDTH_ENUM)liblte_bits_2_value(ie_ptr, 4); + + // UL Bandwidth + if(mob_ctrl_info->carrier_bw_eutra.ul_bw_present) + { + mob_ctrl_info->carrier_bw_eutra.ul_bw = (LIBLTE_RRC_BANDWIDTH_ENUM)liblte_bits_2_value(ie_ptr, 4); + } + } + + // Additional Spectrum Emission + if(mob_ctrl_info->add_spect_em_present) + { + liblte_rrc_unpack_additional_spectrum_emission_ie(ie_ptr, &mob_ctrl_info->add_spect_em); + } + + // T304 + mob_ctrl_info->t304 = (LIBLTE_RRC_T304_ENUM)liblte_bits_2_value(ie_ptr, 3); + + // New UE Identity + liblte_rrc_unpack_c_rnti_ie(ie_ptr, &mob_ctrl_info->new_ue_id); + + // Radio Resource Config Common + liblte_rrc_unpack_rr_config_common_ie(ie_ptr, &mob_ctrl_info->rr_cnfg_common); + + // RACH Config Dedicated + if(mob_ctrl_info->rach_cnfg_ded_present) + { + liblte_rrc_unpack_rach_config_dedicated_ie(ie_ptr, &mob_ctrl_info->rach_cnfg_ded); + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Mobility Parameters CDMA2000 (1xRTT) + + Description: Contains the parameters provided to the UE for + handover and (enhanced) CSFB to 1xRTT support + + Document Reference: 36.331 v10.0.0 Section 6.3.4 +*********************************************************************/ +// FIXME + +/********************************************************************* + IE Name: Mobility State Parameters + + Description: Contains parameters to determine UE mobility state + + Document Reference: 36.331 v10.0.0 Section 6.3.4 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_mobility_state_parameters_ie(LIBLTE_RRC_MOBILITY_STATE_PARAMETERS_STRUCT *mobility_state_params, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(mobility_state_params != NULL && + ie_ptr != NULL) + { + liblte_value_2_bits(mobility_state_params->t_eval, ie_ptr, 3); + liblte_value_2_bits(mobility_state_params->t_hyst_normal, ie_ptr, 3); + liblte_value_2_bits(mobility_state_params->n_cell_change_medium - 1, ie_ptr, 4); + liblte_value_2_bits(mobility_state_params->n_cell_change_high - 1, ie_ptr, 4); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_mobility_state_parameters_ie(uint8 **ie_ptr, + LIBLTE_RRC_MOBILITY_STATE_PARAMETERS_STRUCT *mobility_state_params) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + mobility_state_params != NULL) + { + mobility_state_params->t_eval = (LIBLTE_RRC_T_EVALUATION_ENUM)liblte_bits_2_value(ie_ptr, 3); + mobility_state_params->t_hyst_normal = (LIBLTE_RRC_T_HYST_NORMAL_ENUM)liblte_bits_2_value(ie_ptr, 3); + mobility_state_params->n_cell_change_medium = liblte_bits_2_value(ie_ptr, 4) + 1; + mobility_state_params->n_cell_change_high = liblte_bits_2_value(ie_ptr, 4) + 1; + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Phys Cell ID + + Description: Indicates the physical layer identity of the cell + + Document Reference: 36.331 v10.0.0 Section 6.3.4 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_phys_cell_id_ie(uint16 phys_cell_id, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL) + { + liblte_value_2_bits(phys_cell_id, ie_ptr, 9); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_phys_cell_id_ie(uint8 **ie_ptr, + uint16 *phys_cell_id) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + phys_cell_id != NULL) + { + *phys_cell_id = liblte_bits_2_value(ie_ptr, 9); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Phys Cell ID Range + + Description: Encodes either a single or a range of physical cell + identities + + Document Reference: 36.331 v10.0.0 Section 6.3.4 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_phys_cell_id_range_ie(LIBLTE_RRC_PHYS_CELL_ID_RANGE_STRUCT *phys_cell_id_range, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + bool opt; + + if(phys_cell_id_range != NULL && + ie_ptr != NULL) + { + opt = (LIBLTE_RRC_PHYS_CELL_ID_RANGE_N1 != phys_cell_id_range->range); + + liblte_value_2_bits(opt, ie_ptr, 1); + + liblte_rrc_pack_phys_cell_id_ie(phys_cell_id_range->start, ie_ptr); + + if(opt) + { + liblte_value_2_bits(phys_cell_id_range->range, ie_ptr, 4); + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_phys_cell_id_range_ie(uint8 **ie_ptr, + LIBLTE_RRC_PHYS_CELL_ID_RANGE_STRUCT *phys_cell_id_range) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + bool opt; + + if(ie_ptr != NULL && + phys_cell_id_range != NULL) + { + opt = liblte_bits_2_value(ie_ptr, 1); + + liblte_rrc_unpack_phys_cell_id_ie(ie_ptr, &phys_cell_id_range->start); + + if(true == opt) + { + phys_cell_id_range->range = (LIBLTE_RRC_PHYS_CELL_ID_RANGE_ENUM)liblte_bits_2_value(ie_ptr, 4); + }else{ + phys_cell_id_range->range = LIBLTE_RRC_PHYS_CELL_ID_RANGE_N1; + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Phys Cell ID Range UTRA FDD List + + Description: Encodes one or more of Phys Cell ID Range UTRA FDD + + Document Reference: 36.331 v10.0.0 Section 6.3.4 +*********************************************************************/ +// FIXME + +/********************************************************************* + IE Name: Phys Cell ID CDMA2000 + + Description: Identifies the PN offset that represents the + "Physical cell identity" in CDMA2000 + + Document Reference: 36.331 v10.0.0 Section 6.3.4 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_phys_cell_id_cdma2000_ie(uint16 phys_cell_id, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL) + { + liblte_value_2_bits(phys_cell_id, ie_ptr, 9); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_phys_cell_id_cdma2000_ie(uint8 **ie_ptr, + uint16 *phys_cell_id) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + phys_cell_id != NULL) + { + *phys_cell_id = liblte_bits_2_value(ie_ptr, 9); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Phys Cell ID GERAN + + Description: Contains the Base Station Identity Code (BSIC) + + Document Reference: 36.331 v10.0.0 Section 6.3.4 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_phys_cell_id_geran_ie(LIBLTE_RRC_PHYS_CELL_ID_GERAN_STRUCT *phys_cell_id, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(phys_cell_id != NULL && + ie_ptr != NULL) + { + liblte_value_2_bits(phys_cell_id->ncc, ie_ptr, 3); + liblte_value_2_bits(phys_cell_id->bcc, ie_ptr, 3); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_phys_cell_id_geran_ie(uint8 **ie_ptr, + LIBLTE_RRC_PHYS_CELL_ID_GERAN_STRUCT *phys_cell_id) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + phys_cell_id != NULL) + { + phys_cell_id->ncc = liblte_bits_2_value(ie_ptr, 3); + phys_cell_id->bcc = liblte_bits_2_value(ie_ptr, 3); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Phys Cell ID UTRA FDD + + Description: Indicates the physical layer identity of the cell + + Document Reference: 36.331 v10.0.0 Section 6.3.4 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_phys_cell_id_utra_fdd_ie(uint16 phys_cell_id, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL) + { + liblte_value_2_bits(phys_cell_id, ie_ptr, 9); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_phys_cell_id_utra_fdd_ie(uint8 **ie_ptr, + uint16 *phys_cell_id) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + phys_cell_id != NULL) + { + *phys_cell_id = liblte_bits_2_value(ie_ptr, 9); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Phys Cell ID UTRA TDD + + Description: Indicates the physical layer identity of the cell + + Document Reference: 36.331 v10.0.0 Section 6.3.4 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_phys_cell_id_utra_tdd_ie(uint8 phys_cell_id, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL) + { + liblte_value_2_bits(phys_cell_id, ie_ptr, 7); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_phys_cell_id_utra_tdd_ie(uint8 **ie_ptr, + uint8 *phys_cell_id) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + phys_cell_id != NULL) + { + *phys_cell_id = liblte_bits_2_value(ie_ptr, 7); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: PLMN Identity + + Description: Identifies a Public Land Mobile Network + + Document Reference: 36.331 v10.0.0 Section 6.3.4 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_plmn_identity_ie(LIBLTE_RRC_PLMN_IDENTITY_STRUCT *plmn_id, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 mcc_opt = true; + uint8 mnc_size; + + if(plmn_id != NULL && + ie_ptr != NULL) + { + liblte_value_2_bits(mcc_opt, ie_ptr, 1); + + if(true == mcc_opt) + { + liblte_value_2_bits((plmn_id->mcc>>8)&0x0F, ie_ptr, 4); + liblte_value_2_bits((plmn_id->mcc>>4)&0x0F, ie_ptr, 4); + liblte_value_2_bits((plmn_id->mcc)&0x0F, ie_ptr, 4); + } + + if((plmn_id->mnc & 0xFF00) == 0xFF00) + { + mnc_size = 2; + liblte_value_2_bits((mnc_size)-2, ie_ptr, 1); + liblte_value_2_bits((plmn_id->mnc>>4)&0x0F, ie_ptr, 4); + liblte_value_2_bits((plmn_id->mnc)&0x0F, ie_ptr, 4); + }else{ + mnc_size = 3; + liblte_value_2_bits((mnc_size)-2, ie_ptr, 1); + liblte_value_2_bits((plmn_id->mnc>>8)&0x0F, ie_ptr, 4); + liblte_value_2_bits((plmn_id->mnc>>4)&0x0F, ie_ptr, 4); + liblte_value_2_bits((plmn_id->mnc)&0x0F, ie_ptr, 4); + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_plmn_identity_ie(uint8 **ie_ptr, + LIBLTE_RRC_PLMN_IDENTITY_STRUCT *plmn_id) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 mcc_opt; + uint8 mnc_size; + + if(ie_ptr != NULL && + plmn_id != NULL) + { + mcc_opt = liblte_bits_2_value(ie_ptr, 1); + + if(true == mcc_opt) + { + plmn_id->mcc = 0xF000; + plmn_id->mcc |= (liblte_bits_2_value(ie_ptr, 4) << 8); + plmn_id->mcc |= (liblte_bits_2_value(ie_ptr, 4) << 4); + plmn_id->mcc |= liblte_bits_2_value(ie_ptr, 4); + + }else{ + plmn_id->mcc = LIBLTE_RRC_MCC_NOT_PRESENT; + } + + mnc_size = (liblte_bits_2_value(ie_ptr, 1) + 2); + if(2 == mnc_size) + { + plmn_id->mnc = 0xFF00; + plmn_id->mnc |= (liblte_bits_2_value(ie_ptr, 4) << 4); + plmn_id->mnc |= liblte_bits_2_value(ie_ptr, 4); + }else{ + plmn_id->mnc = 0xF000; + plmn_id->mnc |= (liblte_bits_2_value(ie_ptr, 4) << 8); + plmn_id->mnc |= (liblte_bits_2_value(ie_ptr, 4) << 4); + plmn_id->mnc |= liblte_bits_2_value(ie_ptr, 4); + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Pre Registration Info HRPD + + Description: FIXME + + Document Reference: 36.331 v10.0.0 Section 6.3.4 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_pre_registration_info_hrpd_ie(LIBLTE_RRC_PRE_REGISTRATION_INFO_HRPD_STRUCT *pre_reg_info_hrpd, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint32 i; + + if(pre_reg_info_hrpd != NULL && + ie_ptr != NULL) + { + // Optional indicators + liblte_value_2_bits(pre_reg_info_hrpd->pre_reg_zone_id_present, ie_ptr, 1); + if(0 != pre_reg_info_hrpd->secondary_pre_reg_zone_id_list_size) + { + liblte_value_2_bits(1, ie_ptr, 1); + }else{ + liblte_value_2_bits(0, ie_ptr, 1); + } + + liblte_value_2_bits(pre_reg_info_hrpd->pre_reg_allowed, ie_ptr, 1); + + if(true == pre_reg_info_hrpd->pre_reg_zone_id_present) + { + liblte_value_2_bits(pre_reg_info_hrpd->pre_reg_zone_id, ie_ptr, 8); + } + + if(0 != pre_reg_info_hrpd->secondary_pre_reg_zone_id_list_size) + { + liblte_value_2_bits(pre_reg_info_hrpd->secondary_pre_reg_zone_id_list_size - 1, ie_ptr, 1); + for(i=0; isecondary_pre_reg_zone_id_list_size; i++) + { + liblte_value_2_bits(pre_reg_info_hrpd->secondary_pre_reg_zone_id_list[i], ie_ptr, 8); + } + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_pre_registration_info_hrpd_ie(uint8 **ie_ptr, + LIBLTE_RRC_PRE_REGISTRATION_INFO_HRPD_STRUCT *pre_reg_info_hrpd) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint32 i; + bool secondary_pre_reg_zone_id_opt; + + if(ie_ptr != NULL && + pre_reg_info_hrpd != NULL) + { + // Optional indicators + pre_reg_info_hrpd->pre_reg_zone_id_present = liblte_bits_2_value(ie_ptr, 1); + secondary_pre_reg_zone_id_opt = liblte_bits_2_value(ie_ptr, 1); + + pre_reg_info_hrpd->pre_reg_allowed = liblte_bits_2_value(ie_ptr, 1); + + if(true == pre_reg_info_hrpd->pre_reg_zone_id_present) + { + pre_reg_info_hrpd->pre_reg_zone_id = liblte_bits_2_value(ie_ptr, 8); + } + + if(true == secondary_pre_reg_zone_id_opt) + { + pre_reg_info_hrpd->secondary_pre_reg_zone_id_list_size = liblte_bits_2_value(ie_ptr, 1) + 1; + for(i=0; isecondary_pre_reg_zone_id_list_size; i++) + { + pre_reg_info_hrpd->secondary_pre_reg_zone_id_list[i] = liblte_bits_2_value(ie_ptr, 8); + } + }else{ + pre_reg_info_hrpd->secondary_pre_reg_zone_id_list_size = 0; + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Q Qual Min + + Description: Indicates for cell selection/re-selection the + required minimum received RSRQ level in the (E-UTRA) + cell + + Document Reference: 36.331 v10.0.0 Section 6.3.4 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_q_qual_min_ie(int8 q_qual_min, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL) + { + liblte_value_2_bits(q_qual_min + 34, ie_ptr, 5); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_q_qual_min_ie(uint8 **ie_ptr, + int8 *q_qual_min) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + q_qual_min != NULL) + { + *q_qual_min = (int8)liblte_bits_2_value(ie_ptr, 5) - 34; + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Q Rx Lev Min + + Description: Indicates the required minimum received RSRP level in + the (E-UTRA) cell for cell selection/re-selection + + Document Reference: 36.331 v10.0.0 Section 6.3.4 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_q_rx_lev_min_ie(int16 q_rx_lev_min, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL) + { + liblte_value_2_bits((q_rx_lev_min / 2) + 70, ie_ptr, 6); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_q_rx_lev_min_ie(uint8 **ie_ptr, + int16 *q_rx_lev_min) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + q_rx_lev_min != NULL) + { + *q_rx_lev_min = ((int16)liblte_bits_2_value(ie_ptr, 6) - 70) * 2; + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Q Offset Range + + Description: Indicates a cell or frequency specific offset to be + applied when evaluating candidates for cell + reselection or when evaluating triggering conditions + for measurement reporting + + Document Reference: 36.331 v10.0.0 Section 6.3.4 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_q_offset_range_ie(LIBLTE_RRC_Q_OFFSET_RANGE_ENUM q_offset_range, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL) + { + liblte_value_2_bits(q_offset_range, ie_ptr, 5); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_q_offset_range_ie(uint8 **ie_ptr, + LIBLTE_RRC_Q_OFFSET_RANGE_ENUM *q_offset_range) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + q_offset_range != NULL) + { + *q_offset_range = (LIBLTE_RRC_Q_OFFSET_RANGE_ENUM)liblte_bits_2_value(ie_ptr, 5); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Q Offset Range Inter RAT + + Description: Indicates a frequency specific offset to be applied + when evaluating triggering conditions for + measurement reporting + + Document Reference: 36.331 v10.0.0 Section 6.3.4 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_q_offset_range_inter_rat_ie(int8 q_offset_range_inter_rat, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL) + { + liblte_value_2_bits(q_offset_range_inter_rat + 15, ie_ptr, 5); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_q_offset_range_inter_rat_ie(uint8 **ie_ptr, + int8 *q_offset_range_inter_rat) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + q_offset_range_inter_rat != NULL) + { + *q_offset_range_inter_rat = (int8)(liblte_bits_2_value(ie_ptr, 5)) - 15; + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Reselection Threshold + + Description: Indicates an RX level threshold for cell reselection + + Document Reference: 36.331 v10.0.0 Section 6.3.4 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_reselection_threshold_ie(uint8 resel_thresh, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL) + { + liblte_value_2_bits(resel_thresh / 2, ie_ptr, 5); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_reselection_threshold_ie(uint8 **ie_ptr, + uint8 *resel_thresh) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + resel_thresh != NULL) + { + *resel_thresh = liblte_bits_2_value(ie_ptr, 5) * 2; + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Reselection Threshold Q + + Description: Indicates a quality level threshold for cell + reselection + + Document Reference: 36.331 v10.0.0 Section 6.3.4 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_reselection_threshold_q_ie(uint8 resel_thresh_q, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL) + { + liblte_value_2_bits(resel_thresh_q, ie_ptr, 5); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_reselection_threshold_q_ie(uint8 **ie_ptr, + uint8 *resel_thresh_q) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + resel_thresh_q != NULL) + { + *resel_thresh_q = liblte_bits_2_value(ie_ptr, 5); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: S Cell Index + + Description: Contains a short identity, used to identify an + SCell + + Document Reference: 36.331 v10.0.0 Section 6.3.4 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_s_cell_index_ie(uint8 s_cell_idx, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL) + { + liblte_value_2_bits(s_cell_idx - 1, ie_ptr, 3); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_s_cell_index_ie(uint8 **ie_ptr, + uint8 *s_cell_idx) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + s_cell_idx != NULL) + { + *s_cell_idx = liblte_bits_2_value(ie_ptr, 3) + 1; + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Serv Cell Index + + Description: Contains a short identity, used to identify a + serving cell + + Document Reference: 36.331 v10.0.0 Section 6.3.4 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_serv_cell_index_ie(uint8 serv_cell_idx, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL) + { + liblte_value_2_bits(serv_cell_idx, ie_ptr, 3); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_serv_cell_index_ie(uint8 **ie_ptr, + uint8 *serv_cell_idx) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + serv_cell_idx != NULL) + { + *serv_cell_idx = liblte_bits_2_value(ie_ptr, 3); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Speed State Scale Factors + + Description: Contains factors, to be applied when the UE is in + medium or high speed state, used for scaling a + mobility control related parameter + + Document Reference: 36.331 v10.0.0 Section 6.3.4 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_speed_state_scale_factors_ie(LIBLTE_RRC_SPEED_STATE_SCALE_FACTORS_STRUCT *speed_state_scale_factors, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(speed_state_scale_factors != NULL && + ie_ptr != NULL) + { + liblte_value_2_bits(speed_state_scale_factors->sf_medium, ie_ptr, 2); + liblte_value_2_bits(speed_state_scale_factors->sf_high, ie_ptr, 2); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_speed_state_scale_factors_ie(uint8 **ie_ptr, + LIBLTE_RRC_SPEED_STATE_SCALE_FACTORS_STRUCT *speed_state_scale_factors) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + speed_state_scale_factors != NULL) + { + speed_state_scale_factors->sf_medium = (LIBLTE_RRC_SSSF_MEDIUM_ENUM)liblte_bits_2_value(ie_ptr, 2); + speed_state_scale_factors->sf_high = (LIBLTE_RRC_SSSF_HIGH_ENUM)liblte_bits_2_value(ie_ptr, 2); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: System Info List GERAN + + Description: Contains system information of a GERAN cell + + Document Reference: 36.331 v10.0.0 Section 6.3.4 +*********************************************************************/ +// FIXME + +/********************************************************************* + IE Name: System Time Info CDMA2000 + + Description: Informs the UE about the absolute time in the current + cell + + Document Reference: 36.331 v10.0.0 Section 6.3.4 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_system_time_info_cdma2000_ie(LIBLTE_RRC_SYSTEM_TIME_INFO_CDMA2000_STRUCT *sys_time_info_cdma2000, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(sys_time_info_cdma2000 != NULL && + ie_ptr != NULL) + { + liblte_value_2_bits(sys_time_info_cdma2000->cdma_eutra_sync, ie_ptr, 1); + liblte_value_2_bits(sys_time_info_cdma2000->system_time_async, ie_ptr, 1); + if(true == sys_time_info_cdma2000->system_time_async) + { + liblte_value_2_bits((uint32)(sys_time_info_cdma2000->system_time >> 17), ie_ptr, 32); + liblte_value_2_bits((uint32)(sys_time_info_cdma2000->system_time & 0x1FFFF), ie_ptr, 17); + }else{ + liblte_value_2_bits((uint32)(sys_time_info_cdma2000->system_time >> 7), ie_ptr, 32); + liblte_value_2_bits((uint32)(sys_time_info_cdma2000->system_time & 0x7F), ie_ptr, 7); + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_system_time_info_cdma2000_ie(uint8 **ie_ptr, + LIBLTE_RRC_SYSTEM_TIME_INFO_CDMA2000_STRUCT *sys_time_info_cdma2000) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + sys_time_info_cdma2000 != NULL) + { + sys_time_info_cdma2000->cdma_eutra_sync = liblte_bits_2_value(ie_ptr, 1); + sys_time_info_cdma2000->system_time_async = liblte_bits_2_value(ie_ptr, 1); + if(true == sys_time_info_cdma2000->system_time_async) + { + sys_time_info_cdma2000->system_time = (uint64)liblte_bits_2_value(ie_ptr, 32) << 17; + sys_time_info_cdma2000->system_time |= (uint64)liblte_bits_2_value(ie_ptr, 17); + }else{ + sys_time_info_cdma2000->system_time = (uint64)liblte_bits_2_value(ie_ptr, 32) << 7; + sys_time_info_cdma2000->system_time |= (uint64)liblte_bits_2_value(ie_ptr, 7); + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Tracking Area Code + + Description: Identifies a tracking area within the scope of a + PLMN + + Document Reference: 36.331 v10.0.0 Section 6.3.4 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_tracking_area_code_ie(uint16 tac, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL) + { + liblte_value_2_bits(tac, ie_ptr, 16); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_tracking_area_code_ie(uint8 **ie_ptr, + uint16 *tac) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + tac != NULL) + { + *tac = liblte_bits_2_value(ie_ptr, 16); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: T Reselection + + Description: Contains the timer T_reselection_rat for E-UTRA, + UTRA, GERAN, or CDMA2000 + + Document Reference: 36.331 v10.0.0 Section 6.3.4 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_t_reselection_ie(uint8 t_resel, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL) + { + liblte_value_2_bits(t_resel, ie_ptr, 3); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_t_reselection_ie(uint8 **ie_ptr, + uint8 *t_resel) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + t_resel != NULL) + { + *t_resel = liblte_bits_2_value(ie_ptr, 3); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Next Hop Chaining Count + + Description: Updates the Kenb key and corresponds to parameter + NCC + + Document Reference: 36.331 v10.0.0 Section 6.3.3 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_next_hop_chaining_count_ie(uint8 next_hop_chaining_count, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL) + { + liblte_value_2_bits(next_hop_chaining_count, ie_ptr, 3); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_next_hop_chaining_count_ie(uint8 **ie_ptr, + uint8 *next_hop_chaining_count) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + next_hop_chaining_count != NULL) + { + *next_hop_chaining_count = liblte_bits_2_value(ie_ptr, 3); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Security Algorithm Config + + Description: Configures AS integrity protection algorithm (SRBs) + and AS ciphering algorithm (SRBs and DRBs) + + Document Reference: 36.331 v10.0.0 Section 6.3.3 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_security_algorithm_config_ie(LIBLTE_RRC_SECURITY_ALGORITHM_CONFIG_STRUCT *sec_alg_cnfg, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(sec_alg_cnfg != NULL && + ie_ptr != NULL) + { + // Extension indicator + liblte_value_2_bits(0, ie_ptr, 1); + + liblte_value_2_bits(sec_alg_cnfg->cipher_alg, ie_ptr, 3); + + // Extension indicator + liblte_value_2_bits(0, ie_ptr, 1); + + liblte_value_2_bits(sec_alg_cnfg->int_alg, ie_ptr, 3); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_security_algorithm_config_ie(uint8 **ie_ptr, + LIBLTE_RRC_SECURITY_ALGORITHM_CONFIG_STRUCT *sec_alg_cnfg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + sec_alg_cnfg != NULL) + { + // Extension indicator + liblte_bits_2_value(ie_ptr, 1); + + sec_alg_cnfg->cipher_alg = (LIBLTE_RRC_CIPHERING_ALGORITHM_ENUM)liblte_bits_2_value(ie_ptr, 3); + + // Extension indicator + liblte_bits_2_value(ie_ptr, 1); + + sec_alg_cnfg->int_alg = (LIBLTE_RRC_INTEGRITY_PROT_ALGORITHM_ENUM)liblte_bits_2_value(ie_ptr, 3); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Short MAC I + + Description: Identifies and verifies the UE at RRC connection + re-establishment + + Document Reference: 36.331 v10.0.0 Section 6.3.3 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_short_mac_i_ie(uint16 short_mac_i, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL) + { + liblte_value_2_bits(short_mac_i, ie_ptr, 16); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_short_mac_i_ie(uint8 **ie_ptr, + uint16 *short_mac_i) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + short_mac_i != NULL) + { + *short_mac_i = liblte_bits_2_value(ie_ptr, 16); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Antenna Info + + Description: Specifies the common and the UE specific antenna + configuration + + Document Reference: 36.331 v10.0.0 Section 6.3.2 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_antenna_info_common_ie(LIBLTE_RRC_ANTENNA_PORTS_COUNT_ENUM antenna_ports_cnt, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL) + { + liblte_value_2_bits(antenna_ports_cnt, ie_ptr, 2); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_antenna_info_common_ie(uint8 **ie_ptr, + LIBLTE_RRC_ANTENNA_PORTS_COUNT_ENUM *antenna_ports_cnt) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + antenna_ports_cnt != NULL) + { + *antenna_ports_cnt = (LIBLTE_RRC_ANTENNA_PORTS_COUNT_ENUM)liblte_bits_2_value(ie_ptr, 2); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_pack_antenna_info_dedicated_ie(LIBLTE_RRC_ANTENNA_INFO_DEDICATED_STRUCT *antenna_info, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(antenna_info != NULL && + ie_ptr != NULL) + { + // Optional indicator + liblte_value_2_bits(antenna_info->codebook_subset_restriction_present, ie_ptr, 1); + + // Transmission Mode + liblte_value_2_bits(antenna_info->tx_mode, ie_ptr, 3); + + // Codebook Subset Restriction + if(antenna_info->codebook_subset_restriction_present) + { + liblte_value_2_bits(antenna_info->codebook_subset_restriction_choice, ie_ptr, 3); + switch(antenna_info->codebook_subset_restriction_choice) + { + case LIBLTE_RRC_CODEBOOK_SUBSET_RESTRICTION_N2_TM3: + liblte_value_2_bits(antenna_info->codebook_subset_restriction, ie_ptr, 2); + break; + case LIBLTE_RRC_CODEBOOK_SUBSET_RESTRICTION_N4_TM3: + case LIBLTE_RRC_CODEBOOK_SUBSET_RESTRICTION_N2_TM5: + case LIBLTE_RRC_CODEBOOK_SUBSET_RESTRICTION_N2_TM6: + liblte_value_2_bits(antenna_info->codebook_subset_restriction, ie_ptr, 4); + break; + case LIBLTE_RRC_CODEBOOK_SUBSET_RESTRICTION_N2_TM4: + liblte_value_2_bits(antenna_info->codebook_subset_restriction, ie_ptr, 6); + break; + case LIBLTE_RRC_CODEBOOK_SUBSET_RESTRICTION_N4_TM4: + liblte_value_2_bits(antenna_info->codebook_subset_restriction >> 32, ie_ptr, 32); + liblte_value_2_bits(antenna_info->codebook_subset_restriction, ie_ptr, 32); + break; + case LIBLTE_RRC_CODEBOOK_SUBSET_RESTRICTION_N4_TM5: + case LIBLTE_RRC_CODEBOOK_SUBSET_RESTRICTION_N4_TM6: + liblte_value_2_bits(antenna_info->codebook_subset_restriction, ie_ptr, 16); + break; + } + } + + // UE Transmit Antenna Selection + liblte_value_2_bits(antenna_info->ue_tx_antenna_selection_setup_present, ie_ptr, 1); + if(antenna_info->ue_tx_antenna_selection_setup_present) + { + liblte_value_2_bits(antenna_info->ue_tx_antenna_selection_setup, ie_ptr, 1); + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_antenna_info_dedicated_ie(uint8 **ie_ptr, + LIBLTE_RRC_ANTENNA_INFO_DEDICATED_STRUCT *antenna_info) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + antenna_info != NULL) + { + // Optional indicator + antenna_info->codebook_subset_restriction_present = liblte_bits_2_value(ie_ptr, 1); + + // Transmission Mode + antenna_info->tx_mode = (LIBLTE_RRC_TRANSMISSION_MODE_ENUM)liblte_bits_2_value(ie_ptr, 3); + + // Codebook Subset Restriction + if(antenna_info->codebook_subset_restriction_present) + { + antenna_info->codebook_subset_restriction_choice = (LIBLTE_RRC_CODEBOOK_SUBSET_RESTRICTION_CHOICE_ENUM)liblte_bits_2_value(ie_ptr, 3); + switch(antenna_info->codebook_subset_restriction_choice) + { + case LIBLTE_RRC_CODEBOOK_SUBSET_RESTRICTION_N2_TM3: + antenna_info->codebook_subset_restriction = liblte_bits_2_value(ie_ptr, 2); + break; + case LIBLTE_RRC_CODEBOOK_SUBSET_RESTRICTION_N4_TM3: + case LIBLTE_RRC_CODEBOOK_SUBSET_RESTRICTION_N2_TM5: + case LIBLTE_RRC_CODEBOOK_SUBSET_RESTRICTION_N2_TM6: + antenna_info->codebook_subset_restriction = liblte_bits_2_value(ie_ptr, 4); + break; + case LIBLTE_RRC_CODEBOOK_SUBSET_RESTRICTION_N2_TM4: + antenna_info->codebook_subset_restriction = liblte_bits_2_value(ie_ptr, 6); + break; + case LIBLTE_RRC_CODEBOOK_SUBSET_RESTRICTION_N4_TM4: + antenna_info->codebook_subset_restriction = (uint64)(liblte_bits_2_value(ie_ptr, 32)) << 32; + antenna_info->codebook_subset_restriction |= liblte_bits_2_value(ie_ptr, 32); + break; + case LIBLTE_RRC_CODEBOOK_SUBSET_RESTRICTION_N4_TM5: + case LIBLTE_RRC_CODEBOOK_SUBSET_RESTRICTION_N4_TM6: + antenna_info->codebook_subset_restriction = liblte_bits_2_value(ie_ptr, 16); + break; + } + } + + // UE Transmit Antenna Selection + antenna_info->ue_tx_antenna_selection_setup_present = liblte_bits_2_value(ie_ptr, 1); + if(antenna_info->ue_tx_antenna_selection_setup_present) + { + antenna_info->ue_tx_antenna_selection_setup = (LIBLTE_RRC_UE_TX_ANTENNA_SELECTION_ENUM)liblte_bits_2_value(ie_ptr, 1); + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: CQI Report Config + + Description: Specifies the CQI reporting configuration + + Document Reference: 36.331 v10.0.0 Section 6.3.2 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_cqi_report_config_ie(LIBLTE_RRC_CQI_REPORT_CONFIG_STRUCT *cqi_report_cnfg, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(cqi_report_cnfg != NULL && + ie_ptr != NULL) + { + // Optional indicators + liblte_value_2_bits(cqi_report_cnfg->report_mode_aperiodic_present, ie_ptr, 1); + liblte_value_2_bits(cqi_report_cnfg->report_periodic_present, ie_ptr, 1); + + // CQI Report Mode Aperiodic + if(cqi_report_cnfg->report_mode_aperiodic_present) + { + liblte_value_2_bits(cqi_report_cnfg->report_mode_aperiodic, ie_ptr, 3); + } + + // Nom PDSCH RS EPRE Offset + liblte_value_2_bits(cqi_report_cnfg->nom_pdsch_rs_epre_offset + 1, ie_ptr, 3); + + // CQI Report Periodic + if(cqi_report_cnfg->report_periodic_present) + { + liblte_value_2_bits(cqi_report_cnfg->report_periodic_setup_present, ie_ptr, 1); + if(cqi_report_cnfg->report_periodic_setup_present) + { + // Optional indicator + liblte_value_2_bits(cqi_report_cnfg->report_periodic.ri_cnfg_idx_present, ie_ptr, 1); + + // CQI PUCCH Resource Index + liblte_value_2_bits(cqi_report_cnfg->report_periodic.pucch_resource_idx, ie_ptr, 11); + + // CQI PMI Config Index + liblte_value_2_bits(cqi_report_cnfg->report_periodic.pmi_cnfg_idx, ie_ptr, 10); + + // CQI Format Indicator Periodic + liblte_value_2_bits(cqi_report_cnfg->report_periodic.format_ind_periodic, ie_ptr, 1); + if(LIBLTE_RRC_CQI_FORMAT_INDICATOR_PERIODIC_SUBBAND_CQI == cqi_report_cnfg->report_periodic.format_ind_periodic) + { + liblte_value_2_bits(cqi_report_cnfg->report_periodic.format_ind_periodic_subband_k - 1, ie_ptr, 2); + } + + // RI Config Index + if(cqi_report_cnfg->report_periodic.ri_cnfg_idx_present) + { + liblte_value_2_bits(cqi_report_cnfg->report_periodic.ri_cnfg_idx, ie_ptr, 10); + } + + // Simultaneous Ack/Nack and CQI + liblte_value_2_bits(cqi_report_cnfg->report_periodic.simult_ack_nack_and_cqi, ie_ptr, 1); + } + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_cqi_report_config_ie(uint8 **ie_ptr, + LIBLTE_RRC_CQI_REPORT_CONFIG_STRUCT *cqi_report_cnfg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + cqi_report_cnfg != NULL) + { + // Optional indicators + cqi_report_cnfg->report_mode_aperiodic_present = liblte_bits_2_value(ie_ptr, 1); + cqi_report_cnfg->report_periodic_present = liblte_bits_2_value(ie_ptr, 1); + + // CQI Report Mode Aperiodic + if(cqi_report_cnfg->report_mode_aperiodic_present) + { + cqi_report_cnfg->report_mode_aperiodic = (LIBLTE_RRC_CQI_REPORT_MODE_APERIODIC_ENUM)liblte_bits_2_value(ie_ptr, 3); + } + + // Nom PDSCH RS EPRE Offset + cqi_report_cnfg->nom_pdsch_rs_epre_offset = liblte_bits_2_value(ie_ptr, 3) - 1; + + // CQI Report Periodic + if(cqi_report_cnfg->report_periodic_present) + { + cqi_report_cnfg->report_periodic_setup_present = liblte_bits_2_value(ie_ptr, 1); + if(cqi_report_cnfg->report_periodic_setup_present) + { + // Optional indicator + cqi_report_cnfg->report_periodic.ri_cnfg_idx_present = liblte_bits_2_value(ie_ptr, 1); + + // CQI PUCCH Resource Index + cqi_report_cnfg->report_periodic.pucch_resource_idx = liblte_bits_2_value(ie_ptr, 11); + + // CQI PMI Config Index + cqi_report_cnfg->report_periodic.pmi_cnfg_idx = liblte_bits_2_value(ie_ptr, 10); + + // CQI Format Indicator Periodic + cqi_report_cnfg->report_periodic.format_ind_periodic = (LIBLTE_RRC_CQI_FORMAT_INDICATOR_PERIODIC_ENUM)liblte_bits_2_value(ie_ptr, 1); + if(LIBLTE_RRC_CQI_FORMAT_INDICATOR_PERIODIC_SUBBAND_CQI == cqi_report_cnfg->report_periodic.format_ind_periodic) + { + cqi_report_cnfg->report_periodic.format_ind_periodic_subband_k = liblte_bits_2_value(ie_ptr, 2) + 1; + } + + // RI Config Index + if(cqi_report_cnfg->report_periodic.ri_cnfg_idx_present) + { + cqi_report_cnfg->report_periodic.ri_cnfg_idx = liblte_bits_2_value(ie_ptr, 10); + } + + // Simultaneous Ack/Nack and CQI + cqi_report_cnfg->report_periodic.simult_ack_nack_and_cqi = liblte_bits_2_value(ie_ptr, 1); + } + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Cross Carrier Scheduling Config + + Description: Specifies the configuration when the cross carrier + scheduling is used in a cell + + Document Reference: 36.331 v10.0.0 Section 6.3.2 +*********************************************************************/ +// FIXME + +/********************************************************************* + IE Name: CSI RS Config + + Description: Specifies the CSI (Channel State Information) + reference signal configuration + + Document Reference: 36.331 v10.0.0 Section 6.3.2 +*********************************************************************/ +// FIXME + +/********************************************************************* + IE Name: DRB Identity + + Description: Identifies a DRB used by a UE + + Document Reference: 36.331 v10.0.0 Section 6.3.2 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_drb_identity_ie(uint8 drb_id, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL) + { + liblte_value_2_bits(drb_id - 1, ie_ptr, 5); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_drb_identity_ie(uint8 **ie_ptr, + uint8 *drb_id) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + drb_id != NULL) + { + *drb_id = liblte_bits_2_value(ie_ptr, 5) + 1; + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Logical Channel Config + + Description: Configures the logical channel parameters + + Document Reference: 36.331 v10.0.0 Section 6.3.2 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_logical_channel_config_ie(LIBLTE_RRC_LOGICAL_CHANNEL_CONFIG_STRUCT *log_chan_cnfg, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(log_chan_cnfg != NULL && + ie_ptr != NULL) + { + // Extension indicator + liblte_value_2_bits(0, ie_ptr, 1); // FIXME: Handle extension + + // Optional indicator + liblte_value_2_bits(log_chan_cnfg->ul_specific_params_present, ie_ptr, 1); + + if(true == log_chan_cnfg->ul_specific_params_present) + { + // Optional indicator + liblte_value_2_bits(log_chan_cnfg->ul_specific_params.log_chan_group_present, ie_ptr, 1); + + liblte_value_2_bits(log_chan_cnfg->ul_specific_params.priority - 1, ie_ptr, 4); + liblte_value_2_bits(log_chan_cnfg->ul_specific_params.prioritized_bit_rate, ie_ptr, 4); + liblte_value_2_bits(log_chan_cnfg->ul_specific_params.bucket_size_duration, ie_ptr, 3); + + if(true == log_chan_cnfg->ul_specific_params.log_chan_group_present) + { + liblte_value_2_bits(log_chan_cnfg->ul_specific_params.log_chan_group, ie_ptr, 2); + } + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_logical_channel_config_ie(uint8 **ie_ptr, + LIBLTE_RRC_LOGICAL_CHANNEL_CONFIG_STRUCT *log_chan_cnfg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + bool ext; + + if(ie_ptr != NULL && + log_chan_cnfg != NULL) + { + // Extension indicator + ext = liblte_bits_2_value(ie_ptr, 1); // FIXME: Handle extension + + // Optional indicator + log_chan_cnfg->ul_specific_params_present = liblte_bits_2_value(ie_ptr, 1); + + if(true == log_chan_cnfg->ul_specific_params_present) + { + // Optional indicator + log_chan_cnfg->ul_specific_params.log_chan_group_present = liblte_bits_2_value(ie_ptr, 1); + + log_chan_cnfg->ul_specific_params.priority = liblte_bits_2_value(ie_ptr, 4) + 1; + log_chan_cnfg->ul_specific_params.prioritized_bit_rate = (LIBLTE_RRC_PRIORITIZED_BIT_RATE_ENUM)liblte_bits_2_value(ie_ptr, 4); + log_chan_cnfg->ul_specific_params.bucket_size_duration = (LIBLTE_RRC_BUCKET_SIZE_DURATION_ENUM)liblte_bits_2_value(ie_ptr, 3); + + if(true == log_chan_cnfg->ul_specific_params.log_chan_group_present) + { + log_chan_cnfg->ul_specific_params.log_chan_group = liblte_bits_2_value(ie_ptr, 2); + } + } + + // Consume non-critical extensions + liblte_rrc_consume_noncrit_extension(ext, __func__, ie_ptr); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: MAC Main Config + + Description: Specifies the MAC main configuration for signalling + and data radio bearers + + Document Reference: 36.331 v10.0.0 Section 6.3.2 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_mac_main_config_ie(LIBLTE_RRC_MAC_MAIN_CONFIG_STRUCT *mac_main_cnfg, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + bool ext = false; + + if(mac_main_cnfg != NULL && + ie_ptr != NULL) + { + // Extension indicator + liblte_value_2_bits(ext, ie_ptr, 1); + + // Optional indicators + liblte_value_2_bits(mac_main_cnfg->ulsch_cnfg_present, ie_ptr, 1); + liblte_value_2_bits(mac_main_cnfg->drx_cnfg_present, ie_ptr, 1); + liblte_value_2_bits(mac_main_cnfg->phr_cnfg_present, ie_ptr, 1); + + // ULSCH Config + if(mac_main_cnfg->ulsch_cnfg_present) + { + // Optional indicators + liblte_value_2_bits(mac_main_cnfg->ulsch_cnfg.max_harq_tx_present, ie_ptr, 1); + liblte_value_2_bits(mac_main_cnfg->ulsch_cnfg.periodic_bsr_timer_present, ie_ptr, 1); + + // Max HARQ TX + if(mac_main_cnfg->ulsch_cnfg.max_harq_tx_present) + { + liblte_value_2_bits(mac_main_cnfg->ulsch_cnfg.max_harq_tx, ie_ptr, 4); + } + + // Periodic BSR Timer + if(mac_main_cnfg->ulsch_cnfg.periodic_bsr_timer_present) + { + liblte_value_2_bits(mac_main_cnfg->ulsch_cnfg.periodic_bsr_timer, ie_ptr, 4); + } + + // Re-TX BSR Timer + liblte_value_2_bits(mac_main_cnfg->ulsch_cnfg.retx_bsr_timer, ie_ptr, 3); + + // TTI Bundling + liblte_value_2_bits(mac_main_cnfg->ulsch_cnfg.tti_bundling, ie_ptr, 1); + } + + // DRX Config + if(mac_main_cnfg->drx_cnfg_present) + { + liblte_value_2_bits(mac_main_cnfg->drx_cnfg.setup_present, ie_ptr, 1); + if(mac_main_cnfg->drx_cnfg.setup_present) + { + // Optional indicators + liblte_value_2_bits(mac_main_cnfg->drx_cnfg.short_drx_present, ie_ptr, 1); + + // On Duration Timer + liblte_value_2_bits(mac_main_cnfg->drx_cnfg.on_duration_timer, ie_ptr, 4); + + // DRX Inactivity Timer + liblte_value_2_bits(mac_main_cnfg->drx_cnfg.drx_inactivity_timer, ie_ptr, 5); + + // DRX Retransmission Timer + liblte_value_2_bits(mac_main_cnfg->drx_cnfg.drx_retx_timer, ie_ptr, 3); + + // Long DRX Cycle Start Offset + liblte_value_2_bits(mac_main_cnfg->drx_cnfg.long_drx_cycle_start_offset_choice, ie_ptr, 4); + switch(mac_main_cnfg->drx_cnfg.long_drx_cycle_start_offset_choice) + { + case LIBLTE_RRC_LONG_DRX_CYCLE_START_OFFSET_SF10: + liblte_value_2_bits(mac_main_cnfg->drx_cnfg.long_drx_cycle_start_offset, ie_ptr, 4); + break; + case LIBLTE_RRC_LONG_DRX_CYCLE_START_OFFSET_SF20: + case LIBLTE_RRC_LONG_DRX_CYCLE_START_OFFSET_SF32: + liblte_value_2_bits(mac_main_cnfg->drx_cnfg.long_drx_cycle_start_offset, ie_ptr, 5); + break; + case LIBLTE_RRC_LONG_DRX_CYCLE_START_OFFSET_SF40: + case LIBLTE_RRC_LONG_DRX_CYCLE_START_OFFSET_SF64: + liblte_value_2_bits(mac_main_cnfg->drx_cnfg.long_drx_cycle_start_offset, ie_ptr, 6); + break; + case LIBLTE_RRC_LONG_DRX_CYCLE_START_OFFSET_SF80: + case LIBLTE_RRC_LONG_DRX_CYCLE_START_OFFSET_SF128: + liblte_value_2_bits(mac_main_cnfg->drx_cnfg.long_drx_cycle_start_offset, ie_ptr, 7); + break; + case LIBLTE_RRC_LONG_DRX_CYCLE_START_OFFSET_SF160: + case LIBLTE_RRC_LONG_DRX_CYCLE_START_OFFSET_SF256: + liblte_value_2_bits(mac_main_cnfg->drx_cnfg.long_drx_cycle_start_offset, ie_ptr, 8); + break; + case LIBLTE_RRC_LONG_DRX_CYCLE_START_OFFSET_SF320: + case LIBLTE_RRC_LONG_DRX_CYCLE_START_OFFSET_SF512: + liblte_value_2_bits(mac_main_cnfg->drx_cnfg.long_drx_cycle_start_offset, ie_ptr, 9); + break; + case LIBLTE_RRC_LONG_DRX_CYCLE_START_OFFSET_SF640: + case LIBLTE_RRC_LONG_DRX_CYCLE_START_OFFSET_SF1024: + liblte_value_2_bits(mac_main_cnfg->drx_cnfg.long_drx_cycle_start_offset, ie_ptr, 10); + break; + case LIBLTE_RRC_LONG_DRX_CYCLE_START_OFFSET_SF1280: + case LIBLTE_RRC_LONG_DRX_CYCLE_START_OFFSET_SF2048: + liblte_value_2_bits(mac_main_cnfg->drx_cnfg.long_drx_cycle_start_offset, ie_ptr, 11); + break; + case LIBLTE_RRC_LONG_DRX_CYCLE_START_OFFSET_SF2560: + liblte_value_2_bits(mac_main_cnfg->drx_cnfg.long_drx_cycle_start_offset, ie_ptr, 12); + break; + } + + // Short DRX + if(mac_main_cnfg->drx_cnfg.short_drx_present) + { + // Short DRX Cycle + liblte_value_2_bits(mac_main_cnfg->drx_cnfg.short_drx_cycle, ie_ptr, 4); + + // DRX Short Cycle Timer + liblte_value_2_bits(mac_main_cnfg->drx_cnfg.short_drx_cycle_timer - 1, ie_ptr, 4); + } + } + } + + // Time Alignment Timer Dedicated + liblte_rrc_pack_time_alignment_timer_ie(mac_main_cnfg->time_alignment_timer, ie_ptr); + + // PHR Config + if(mac_main_cnfg->phr_cnfg_present) + { + liblte_value_2_bits(mac_main_cnfg->phr_cnfg.setup_present, ie_ptr, 1); + if(mac_main_cnfg->phr_cnfg.setup_present) + { + // Periodic PHR Timer + liblte_value_2_bits(mac_main_cnfg->phr_cnfg.periodic_phr_timer, ie_ptr, 3); + + // Prohibit PHR Timer + liblte_value_2_bits(mac_main_cnfg->phr_cnfg.prohibit_phr_timer, ie_ptr, 3); + + // DL Pathloss Change + liblte_value_2_bits(mac_main_cnfg->phr_cnfg.dl_pathloss_change, ie_ptr, 2); + } + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_mac_main_config_ie(uint8 **ie_ptr, + LIBLTE_RRC_MAC_MAIN_CONFIG_STRUCT *mac_main_cnfg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + bool ext; + + if(ie_ptr != NULL && + mac_main_cnfg != NULL) + { + // Extension indicator + ext = liblte_bits_2_value(ie_ptr, 1); + + // Optional indicators + mac_main_cnfg->ulsch_cnfg_present = liblte_bits_2_value(ie_ptr, 1); + mac_main_cnfg->drx_cnfg_present = liblte_bits_2_value(ie_ptr, 1); + mac_main_cnfg->phr_cnfg_present = liblte_bits_2_value(ie_ptr, 1); + + // ULSCH Config + if(mac_main_cnfg->ulsch_cnfg_present) + { + // Optional indicators + mac_main_cnfg->ulsch_cnfg.max_harq_tx_present = liblte_bits_2_value(ie_ptr, 1); + mac_main_cnfg->ulsch_cnfg.periodic_bsr_timer_present = liblte_bits_2_value(ie_ptr, 1); + + // Max HARQ TX + if(mac_main_cnfg->ulsch_cnfg.max_harq_tx_present) + { + mac_main_cnfg->ulsch_cnfg.max_harq_tx = (LIBLTE_RRC_MAX_HARQ_TX_ENUM)liblte_bits_2_value(ie_ptr, 4); + } + + // Periodic BSR Timer + if(mac_main_cnfg->ulsch_cnfg.periodic_bsr_timer_present) + { + mac_main_cnfg->ulsch_cnfg.periodic_bsr_timer = (LIBLTE_RRC_PERIODIC_BSR_TIMER_ENUM)liblte_bits_2_value(ie_ptr, 4); + } + + // Re-TX BSR Timer + mac_main_cnfg->ulsch_cnfg.retx_bsr_timer = (LIBLTE_RRC_RETRANSMISSION_BSR_TIMER_ENUM)liblte_bits_2_value(ie_ptr, 3); + + // TTI Bundling + mac_main_cnfg->ulsch_cnfg.tti_bundling = liblte_bits_2_value(ie_ptr, 1); + } + + // DRX Config + if(mac_main_cnfg->drx_cnfg_present) + { + mac_main_cnfg->drx_cnfg.setup_present = liblte_bits_2_value(ie_ptr, 1); + if(mac_main_cnfg->drx_cnfg.setup_present) + { + // Optional indicators + mac_main_cnfg->drx_cnfg.short_drx_present = liblte_bits_2_value(ie_ptr, 1); + + // On Duration Timer + mac_main_cnfg->drx_cnfg.on_duration_timer = (LIBLTE_RRC_ON_DURATION_TIMER_ENUM)liblte_bits_2_value(ie_ptr, 4); + + // DRX Inactivity Timer + mac_main_cnfg->drx_cnfg.drx_inactivity_timer = (LIBLTE_RRC_DRX_INACTIVITY_TIMER_ENUM)liblte_bits_2_value(ie_ptr, 5); + + // DRX Retransmission Timer + mac_main_cnfg->drx_cnfg.drx_retx_timer = (LIBLTE_RRC_DRX_RETRANSMISSION_TIMER_ENUM)liblte_bits_2_value(ie_ptr, 3); + + // Long DRX Cycle Short Offset + mac_main_cnfg->drx_cnfg.long_drx_cycle_start_offset_choice = (LIBLTE_RRC_LONG_DRX_CYCLE_START_OFFSET_CHOICE_ENUM)liblte_bits_2_value(ie_ptr, 4); + switch(mac_main_cnfg->drx_cnfg.long_drx_cycle_start_offset_choice) + { + case LIBLTE_RRC_LONG_DRX_CYCLE_START_OFFSET_SF10: + mac_main_cnfg->drx_cnfg.long_drx_cycle_start_offset = liblte_bits_2_value(ie_ptr, 4); + break; + case LIBLTE_RRC_LONG_DRX_CYCLE_START_OFFSET_SF20: + case LIBLTE_RRC_LONG_DRX_CYCLE_START_OFFSET_SF32: + mac_main_cnfg->drx_cnfg.long_drx_cycle_start_offset = liblte_bits_2_value(ie_ptr, 5); + break; + case LIBLTE_RRC_LONG_DRX_CYCLE_START_OFFSET_SF40: + case LIBLTE_RRC_LONG_DRX_CYCLE_START_OFFSET_SF64: + mac_main_cnfg->drx_cnfg.long_drx_cycle_start_offset = liblte_bits_2_value(ie_ptr, 6); + break; + case LIBLTE_RRC_LONG_DRX_CYCLE_START_OFFSET_SF80: + case LIBLTE_RRC_LONG_DRX_CYCLE_START_OFFSET_SF128: + mac_main_cnfg->drx_cnfg.long_drx_cycle_start_offset = liblte_bits_2_value(ie_ptr, 7); + break; + case LIBLTE_RRC_LONG_DRX_CYCLE_START_OFFSET_SF160: + case LIBLTE_RRC_LONG_DRX_CYCLE_START_OFFSET_SF256: + mac_main_cnfg->drx_cnfg.long_drx_cycle_start_offset = liblte_bits_2_value(ie_ptr, 8); + break; + case LIBLTE_RRC_LONG_DRX_CYCLE_START_OFFSET_SF320: + case LIBLTE_RRC_LONG_DRX_CYCLE_START_OFFSET_SF512: + mac_main_cnfg->drx_cnfg.long_drx_cycle_start_offset = liblte_bits_2_value(ie_ptr, 9); + break; + case LIBLTE_RRC_LONG_DRX_CYCLE_START_OFFSET_SF640: + case LIBLTE_RRC_LONG_DRX_CYCLE_START_OFFSET_SF1024: + mac_main_cnfg->drx_cnfg.long_drx_cycle_start_offset = liblte_bits_2_value(ie_ptr, 10); + break; + case LIBLTE_RRC_LONG_DRX_CYCLE_START_OFFSET_SF1280: + case LIBLTE_RRC_LONG_DRX_CYCLE_START_OFFSET_SF2048: + mac_main_cnfg->drx_cnfg.long_drx_cycle_start_offset = liblte_bits_2_value(ie_ptr, 11); + break; + case LIBLTE_RRC_LONG_DRX_CYCLE_START_OFFSET_SF2560: + mac_main_cnfg->drx_cnfg.long_drx_cycle_start_offset = liblte_bits_2_value(ie_ptr, 12); + break; + } + + // Short DRX + if(mac_main_cnfg->drx_cnfg.short_drx_present) + { + // Short DRX Cycle + mac_main_cnfg->drx_cnfg.short_drx_cycle = (LIBLTE_RRC_SHORT_DRX_CYCLE_ENUM)liblte_bits_2_value(ie_ptr, 4); + + // DRX Short Cycle Timer + mac_main_cnfg->drx_cnfg.short_drx_cycle_timer = liblte_bits_2_value(ie_ptr, 4) + 1; + } + } + } + + // Time Alignment Timer Dedicated + liblte_rrc_unpack_time_alignment_timer_ie(ie_ptr, &mac_main_cnfg->time_alignment_timer); + + // PHR Config + if(mac_main_cnfg->phr_cnfg_present) + { + mac_main_cnfg->phr_cnfg.setup_present = liblte_bits_2_value(ie_ptr, 1); + if(mac_main_cnfg->phr_cnfg.setup_present) + { + // Periodic PHR Timer + mac_main_cnfg->phr_cnfg.periodic_phr_timer = (LIBLTE_RRC_PERIODIC_PHR_TIMER_ENUM)liblte_bits_2_value(ie_ptr, 3); + + // Prohibit PHR Timer + mac_main_cnfg->phr_cnfg.prohibit_phr_timer = (LIBLTE_RRC_PROHIBIT_PHR_TIMER_ENUM)liblte_bits_2_value(ie_ptr, 3); + + // DL Pathloss Change + mac_main_cnfg->phr_cnfg.dl_pathloss_change = (LIBLTE_RRC_DL_PATHLOSS_CHANGE_ENUM)liblte_bits_2_value(ie_ptr, 2); + } + } + + // Consume non-critical extensions + liblte_rrc_consume_noncrit_extension(ext, __func__, ie_ptr); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: PDCP Config + + Description: Sets the configurable PDCP parameters for data + radio bearers + + Document Reference: 36.331 v10.0.0 Section 6.3.2 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_pdcp_config_ie(LIBLTE_RRC_PDCP_CONFIG_STRUCT *pdcp_cnfg, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(pdcp_cnfg != NULL && + ie_ptr != NULL) + { + // Extension indicator + liblte_value_2_bits(0, ie_ptr, 1); + + // Optional indicators + liblte_value_2_bits(pdcp_cnfg->discard_timer_present, ie_ptr, 1); + liblte_value_2_bits(pdcp_cnfg->rlc_am_status_report_required_present, ie_ptr, 1); + liblte_value_2_bits(pdcp_cnfg->rlc_um_pdcp_sn_size_present, ie_ptr, 1); + + // Discard Timer + if(pdcp_cnfg->discard_timer_present) + { + liblte_value_2_bits(pdcp_cnfg->discard_timer, ie_ptr, 3); + } + + // RLC AM + if(pdcp_cnfg->rlc_am_status_report_required_present) + { + liblte_value_2_bits(pdcp_cnfg->rlc_am_status_report_required, ie_ptr, 1); + } + + // RLC UM + if(pdcp_cnfg->rlc_um_pdcp_sn_size_present) + { + liblte_value_2_bits(pdcp_cnfg->rlc_um_pdcp_sn_size, ie_ptr, 1); + } + + // Header Compression + liblte_value_2_bits(pdcp_cnfg->hdr_compression_rohc, ie_ptr, 1); + if(pdcp_cnfg->hdr_compression_rohc) + { + // Extension indicator + liblte_value_2_bits(0, ie_ptr, 1); + + // Max CID + liblte_value_2_bits(pdcp_cnfg->hdr_compression_max_cid - 1, ie_ptr, 14); + + // Profiles + liblte_value_2_bits(pdcp_cnfg->hdr_compression_profile_0001, ie_ptr, 1); + liblte_value_2_bits(pdcp_cnfg->hdr_compression_profile_0002, ie_ptr, 1); + liblte_value_2_bits(pdcp_cnfg->hdr_compression_profile_0003, ie_ptr, 1); + liblte_value_2_bits(pdcp_cnfg->hdr_compression_profile_0004, ie_ptr, 1); + liblte_value_2_bits(pdcp_cnfg->hdr_compression_profile_0006, ie_ptr, 1); + liblte_value_2_bits(pdcp_cnfg->hdr_compression_profile_0101, ie_ptr, 1); + liblte_value_2_bits(pdcp_cnfg->hdr_compression_profile_0102, ie_ptr, 1); + liblte_value_2_bits(pdcp_cnfg->hdr_compression_profile_0103, ie_ptr, 1); + liblte_value_2_bits(pdcp_cnfg->hdr_compression_profile_0104, ie_ptr, 1); + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_pdcp_config_ie(uint8 **ie_ptr, + LIBLTE_RRC_PDCP_CONFIG_STRUCT *pdcp_cnfg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + pdcp_cnfg != NULL) + { + // Extension indicator + bool ext = liblte_bits_2_value(ie_ptr, 1); + + // Optional indicators + pdcp_cnfg->discard_timer_present = liblte_bits_2_value(ie_ptr, 1); + pdcp_cnfg->rlc_am_status_report_required_present = liblte_bits_2_value(ie_ptr, 1); + pdcp_cnfg->rlc_um_pdcp_sn_size_present = liblte_bits_2_value(ie_ptr, 1); + + // Discard Timer + if(pdcp_cnfg->discard_timer_present) + { + pdcp_cnfg->discard_timer = (LIBLTE_RRC_DISCARD_TIMER_ENUM)liblte_bits_2_value(ie_ptr, 3); + } + + // RLC AM + if(pdcp_cnfg->rlc_am_status_report_required_present) + { + pdcp_cnfg->rlc_am_status_report_required = liblte_bits_2_value(ie_ptr, 1); + } + + // RLC UM + if(pdcp_cnfg->rlc_um_pdcp_sn_size_present) + { + pdcp_cnfg->rlc_um_pdcp_sn_size = (LIBLTE_RRC_PDCP_SN_SIZE_ENUM)liblte_bits_2_value(ie_ptr, 1); + } + + // Header Compression + pdcp_cnfg->hdr_compression_rohc = liblte_bits_2_value(ie_ptr, 1); + if(pdcp_cnfg->hdr_compression_rohc) + { + // Extension indicator + bool ext2 = liblte_bits_2_value(ie_ptr, 1); + + // Max CID + pdcp_cnfg->hdr_compression_max_cid = liblte_bits_2_value(ie_ptr, 14) + 1; + + // Profiles + pdcp_cnfg->hdr_compression_profile_0001 = liblte_bits_2_value(ie_ptr, 1); + pdcp_cnfg->hdr_compression_profile_0002 = liblte_bits_2_value(ie_ptr, 1); + pdcp_cnfg->hdr_compression_profile_0003 = liblte_bits_2_value(ie_ptr, 1); + pdcp_cnfg->hdr_compression_profile_0004 = liblte_bits_2_value(ie_ptr, 1); + pdcp_cnfg->hdr_compression_profile_0006 = liblte_bits_2_value(ie_ptr, 1); + pdcp_cnfg->hdr_compression_profile_0101 = liblte_bits_2_value(ie_ptr, 1); + pdcp_cnfg->hdr_compression_profile_0102 = liblte_bits_2_value(ie_ptr, 1); + pdcp_cnfg->hdr_compression_profile_0103 = liblte_bits_2_value(ie_ptr, 1); + pdcp_cnfg->hdr_compression_profile_0104 = liblte_bits_2_value(ie_ptr, 1); + + liblte_rrc_consume_noncrit_extension(ext2, __func__, ie_ptr); + } + + liblte_rrc_consume_noncrit_extension(ext, __func__, ie_ptr); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: PDSCH Config + + Description: Specifies the common and the UE specific PDSCH + configuration + + Document Reference: 36.331 v10.0.0 Section 6.3.2 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_pdsch_config_common_ie(LIBLTE_RRC_PDSCH_CONFIG_COMMON_STRUCT *pdsch_config, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(pdsch_config != NULL && + ie_ptr != NULL) + { + liblte_value_2_bits(pdsch_config->rs_power + 60, ie_ptr, 7); + liblte_value_2_bits(pdsch_config->p_b, ie_ptr, 2); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_pdsch_config_common_ie(uint8 **ie_ptr, + LIBLTE_RRC_PDSCH_CONFIG_COMMON_STRUCT *pdsch_config) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + pdsch_config != NULL) + { + pdsch_config->rs_power = liblte_bits_2_value(ie_ptr, 7) - 60; + pdsch_config->p_b = liblte_bits_2_value(ie_ptr, 2); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_pack_pdsch_config_dedicated_ie(LIBLTE_RRC_PDSCH_CONFIG_P_A_ENUM p_a, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL) + { + liblte_value_2_bits(p_a, ie_ptr, 3); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_pdsch_config_dedicated_ie(uint8 **ie_ptr, + LIBLTE_RRC_PDSCH_CONFIG_P_A_ENUM *p_a) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(p_a != NULL && + ie_ptr != NULL) + { + *p_a = (LIBLTE_RRC_PDSCH_CONFIG_P_A_ENUM)liblte_bits_2_value(ie_ptr, 3); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: PHICH Config + + Description: Specifies the PHICH configuration + + Document Reference: 36.331 v10.0.0 Section 6.3.2 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_phich_config_ie(LIBLTE_RRC_PHICH_CONFIG_STRUCT *phich_config, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(phich_config != NULL && + ie_ptr != NULL) + { + liblte_value_2_bits(phich_config->dur, ie_ptr, 1); + liblte_value_2_bits(phich_config->res, ie_ptr, 2); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_phich_config_ie(uint8 **ie_ptr, + LIBLTE_RRC_PHICH_CONFIG_STRUCT *phich_config) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + phich_config != NULL) + { + phich_config->dur = (LIBLTE_RRC_PHICH_DURATION_ENUM)liblte_bits_2_value(ie_ptr, 1); + phich_config->res = (LIBLTE_RRC_PHICH_RESOURCE_ENUM)liblte_bits_2_value(ie_ptr, 2); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Physical Config Dedicated + + Description: Specifies the UE specific physical channel + configuration + + Document Reference: 36.331 v10.0.0 Section 6.3.2 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_physical_config_dedicated_ie(LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT *phy_cnfg_ded, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + bool ext = false; + + if(phy_cnfg_ded != NULL && + ie_ptr != NULL) + { + // Extension indicator + liblte_value_2_bits(ext, ie_ptr, 1); + + // Optional indicators + liblte_value_2_bits(phy_cnfg_ded->pdsch_cnfg_ded_present, ie_ptr, 1); + liblte_value_2_bits(phy_cnfg_ded->pucch_cnfg_ded_present, ie_ptr, 1); + liblte_value_2_bits(phy_cnfg_ded->pusch_cnfg_ded_present, ie_ptr, 1); + liblte_value_2_bits(phy_cnfg_ded->ul_pwr_ctrl_ded_present, ie_ptr, 1); + liblte_value_2_bits(phy_cnfg_ded->tpc_pdcch_cnfg_pucch_present, ie_ptr, 1); + liblte_value_2_bits(phy_cnfg_ded->tpc_pdcch_cnfg_pusch_present, ie_ptr, 1); + liblte_value_2_bits(phy_cnfg_ded->cqi_report_cnfg_present, ie_ptr, 1); + liblte_value_2_bits(phy_cnfg_ded->srs_ul_cnfg_ded_present, ie_ptr, 1); + liblte_value_2_bits(phy_cnfg_ded->antenna_info_present, ie_ptr, 1); + liblte_value_2_bits(phy_cnfg_ded->sched_request_cnfg_present, ie_ptr, 1); + + // PDSCH Config + if(phy_cnfg_ded->pdsch_cnfg_ded_present) + { + liblte_rrc_pack_pdsch_config_dedicated_ie(phy_cnfg_ded->pdsch_cnfg_ded, ie_ptr); + } + + // PUCCH Config + if(phy_cnfg_ded->pucch_cnfg_ded_present) + { + liblte_rrc_pack_pucch_config_dedicated_ie(&phy_cnfg_ded->pucch_cnfg_ded, ie_ptr); + } + + // PUSCH Config + if(phy_cnfg_ded->pusch_cnfg_ded_present) + { + liblte_rrc_pack_pusch_config_dedicated_ie(&phy_cnfg_ded->pusch_cnfg_ded, ie_ptr); + } + + // Uplink Power Control + if(phy_cnfg_ded->ul_pwr_ctrl_ded_present) + { + liblte_rrc_pack_ul_power_control_dedicated_ie(&phy_cnfg_ded->ul_pwr_ctrl_ded, ie_ptr); + } + + // TPC PDCCH Config PUCCH + if(phy_cnfg_ded->tpc_pdcch_cnfg_pucch_present) + { + liblte_rrc_pack_tpc_pdcch_config_ie(&phy_cnfg_ded->tpc_pdcch_cnfg_pucch, ie_ptr); + } + + // TPC PDCCH Config PUSCH + if(phy_cnfg_ded->tpc_pdcch_cnfg_pusch_present) + { + liblte_rrc_pack_tpc_pdcch_config_ie(&phy_cnfg_ded->tpc_pdcch_cnfg_pusch, ie_ptr); + } + + // CQI Report Config + if(phy_cnfg_ded->cqi_report_cnfg_present) + { + liblte_rrc_pack_cqi_report_config_ie(&phy_cnfg_ded->cqi_report_cnfg, ie_ptr); + } + + // SRS UL Config + if(phy_cnfg_ded->srs_ul_cnfg_ded_present) + { + liblte_rrc_pack_srs_ul_config_dedicated_ie(&phy_cnfg_ded->srs_ul_cnfg_ded, ie_ptr); + } + + // Antenna Info + if(phy_cnfg_ded->antenna_info_present) + { + liblte_value_2_bits(phy_cnfg_ded->antenna_info_default_value, ie_ptr, 1); + if(!phy_cnfg_ded->antenna_info_default_value) + { + liblte_rrc_pack_antenna_info_dedicated_ie(&phy_cnfg_ded->antenna_info_explicit_value, ie_ptr); + } + } + + // Scheduling Request Config + if(phy_cnfg_ded->sched_request_cnfg_present) + { + liblte_rrc_pack_scheduling_request_config_ie(&phy_cnfg_ded->sched_request_cnfg, ie_ptr); + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_physical_config_dedicated_ie(uint8 **ie_ptr, + LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT *phy_cnfg_ded) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + bool ext; + + if(ie_ptr != NULL && + phy_cnfg_ded != NULL) + { + // Extension indicator + ext = liblte_bits_2_value(ie_ptr, 1); + + // Optional indicators + phy_cnfg_ded->pdsch_cnfg_ded_present = liblte_bits_2_value(ie_ptr, 1); + phy_cnfg_ded->pucch_cnfg_ded_present = liblte_bits_2_value(ie_ptr, 1); + phy_cnfg_ded->pusch_cnfg_ded_present = liblte_bits_2_value(ie_ptr, 1); + phy_cnfg_ded->ul_pwr_ctrl_ded_present = liblte_bits_2_value(ie_ptr, 1); + phy_cnfg_ded->tpc_pdcch_cnfg_pucch_present = liblte_bits_2_value(ie_ptr, 1); + phy_cnfg_ded->tpc_pdcch_cnfg_pusch_present = liblte_bits_2_value(ie_ptr, 1); + phy_cnfg_ded->cqi_report_cnfg_present = liblte_bits_2_value(ie_ptr, 1); + phy_cnfg_ded->srs_ul_cnfg_ded_present = liblte_bits_2_value(ie_ptr, 1); + phy_cnfg_ded->antenna_info_present = liblte_bits_2_value(ie_ptr, 1); + phy_cnfg_ded->sched_request_cnfg_present = liblte_bits_2_value(ie_ptr, 1); + + // PDSCH Config + if(phy_cnfg_ded->pdsch_cnfg_ded_present) + { + liblte_rrc_unpack_pdsch_config_dedicated_ie(ie_ptr, &phy_cnfg_ded->pdsch_cnfg_ded); + } + + // PUCCH Config + if(phy_cnfg_ded->pucch_cnfg_ded_present) + { + liblte_rrc_unpack_pucch_config_dedicated_ie(ie_ptr, &phy_cnfg_ded->pucch_cnfg_ded); + } + + // PUSCH Config + if(phy_cnfg_ded->pusch_cnfg_ded_present) + { + liblte_rrc_unpack_pusch_config_dedicated_ie(ie_ptr, &phy_cnfg_ded->pusch_cnfg_ded); + } + + // Uplink Power Control + if(phy_cnfg_ded->ul_pwr_ctrl_ded_present) + { + liblte_rrc_unpack_ul_power_control_dedicated_ie(ie_ptr, &phy_cnfg_ded->ul_pwr_ctrl_ded); + } + + // TPC PDCCH Config PUCCH + if(phy_cnfg_ded->tpc_pdcch_cnfg_pucch_present) + { + liblte_rrc_unpack_tpc_pdcch_config_ie(ie_ptr, &phy_cnfg_ded->tpc_pdcch_cnfg_pucch); + } + + // TPC PDCCH Config PUSCH + if(phy_cnfg_ded->tpc_pdcch_cnfg_pusch_present) + { + liblte_rrc_unpack_tpc_pdcch_config_ie(ie_ptr, &phy_cnfg_ded->tpc_pdcch_cnfg_pusch); + } + + // CQI Report Config + if(phy_cnfg_ded->cqi_report_cnfg_present) + { + liblte_rrc_unpack_cqi_report_config_ie(ie_ptr, &phy_cnfg_ded->cqi_report_cnfg); + } + + // SRS UL Config + if(phy_cnfg_ded->srs_ul_cnfg_ded_present) + { + liblte_rrc_unpack_srs_ul_config_dedicated_ie(ie_ptr, &phy_cnfg_ded->srs_ul_cnfg_ded); + } + + // Antenna Info + if(phy_cnfg_ded->antenna_info_present) + { + phy_cnfg_ded->antenna_info_default_value = liblte_bits_2_value(ie_ptr, 1); + if(!phy_cnfg_ded->antenna_info_default_value) + { + liblte_rrc_unpack_antenna_info_dedicated_ie(ie_ptr, &phy_cnfg_ded->antenna_info_explicit_value); + } + } + + // Scheduling Request Config + if(phy_cnfg_ded->sched_request_cnfg_present) + { + liblte_rrc_unpack_scheduling_request_config_ie(ie_ptr, &phy_cnfg_ded->sched_request_cnfg); + } + + // Consume non-critical extensions + liblte_rrc_consume_noncrit_extension(ext, __func__, ie_ptr); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: P Max + + Description: Limits the UE's uplink transmission power on a + carrier frequency and is used to calculate the + parameter P Compensation + + Document Reference: 36.331 v10.0.0 Section 6.3.2 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_p_max_ie(int8 p_max, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL) + { + liblte_value_2_bits(p_max + 30, ie_ptr, 6); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_p_max_ie(uint8 **ie_ptr, + int8 *p_max) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + p_max != NULL) + { + *p_max = (int8)liblte_bits_2_value(ie_ptr, 6) - 30; + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: PRACH Config + + Description: Specifies the PRACH configuration in the system + information and in the mobility control information + + Document Reference: 36.331 v10.0.0 Section 6.3.2 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_prach_config_sib_ie(LIBLTE_RRC_PRACH_CONFIG_SIB_STRUCT *prach_cnfg, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(prach_cnfg != NULL && + ie_ptr != NULL) + { + liblte_value_2_bits(prach_cnfg->root_sequence_index, ie_ptr, 10); + liblte_value_2_bits(prach_cnfg->prach_cnfg_info.prach_config_index, ie_ptr, 6); + liblte_value_2_bits(prach_cnfg->prach_cnfg_info.high_speed_flag, ie_ptr, 1); + liblte_value_2_bits(prach_cnfg->prach_cnfg_info.zero_correlation_zone_config, ie_ptr, 4); + liblte_value_2_bits(prach_cnfg->prach_cnfg_info.prach_freq_offset, ie_ptr, 7); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_prach_config_sib_ie(uint8 **ie_ptr, + LIBLTE_RRC_PRACH_CONFIG_SIB_STRUCT *prach_cnfg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + prach_cnfg != NULL) + { + prach_cnfg->root_sequence_index = liblte_bits_2_value(ie_ptr, 10); + prach_cnfg->prach_cnfg_info.prach_config_index = liblte_bits_2_value(ie_ptr, 6); + prach_cnfg->prach_cnfg_info.high_speed_flag = liblte_bits_2_value(ie_ptr, 1); + prach_cnfg->prach_cnfg_info.zero_correlation_zone_config = liblte_bits_2_value(ie_ptr, 4); + prach_cnfg->prach_cnfg_info.prach_freq_offset = liblte_bits_2_value(ie_ptr, 7); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_pack_prach_config_ie(LIBLTE_RRC_PRACH_CONFIG_STRUCT *prach_cnfg, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(prach_cnfg != NULL && + ie_ptr != NULL) + { + // Optional indicator + liblte_value_2_bits(prach_cnfg->prach_cnfg_info_present, ie_ptr, 1); + + liblte_value_2_bits(prach_cnfg->root_sequence_index, ie_ptr, 10); + + if(true == prach_cnfg->prach_cnfg_info_present) + { + liblte_value_2_bits(prach_cnfg->prach_cnfg_info.prach_config_index, ie_ptr, 6); + liblte_value_2_bits(prach_cnfg->prach_cnfg_info.high_speed_flag, ie_ptr, 1); + liblte_value_2_bits(prach_cnfg->prach_cnfg_info.zero_correlation_zone_config, ie_ptr, 4); + liblte_value_2_bits(prach_cnfg->prach_cnfg_info.prach_freq_offset, ie_ptr, 7); + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_prach_config_ie(uint8 **ie_ptr, + LIBLTE_RRC_PRACH_CONFIG_STRUCT *prach_cnfg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + prach_cnfg != NULL) + { + // Optional indicator + prach_cnfg->prach_cnfg_info_present = liblte_bits_2_value(ie_ptr, 1); + + prach_cnfg->root_sequence_index = liblte_bits_2_value(ie_ptr, 10); + + if(true == prach_cnfg->prach_cnfg_info_present) + { + prach_cnfg->prach_cnfg_info.prach_config_index = liblte_bits_2_value(ie_ptr, 6); + prach_cnfg->prach_cnfg_info.high_speed_flag = liblte_bits_2_value(ie_ptr, 1); + prach_cnfg->prach_cnfg_info.zero_correlation_zone_config = liblte_bits_2_value(ie_ptr, 4); + prach_cnfg->prach_cnfg_info.prach_freq_offset = liblte_bits_2_value(ie_ptr, 7); + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_pack_prach_config_scell_r10_ie(uint8 prach_cnfg_idx, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL) + { + liblte_value_2_bits(prach_cnfg_idx, ie_ptr, 6); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_prach_config_scell_r10_ie(uint8 **ie_ptr, + uint8 *prach_cnfg_idx) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + prach_cnfg_idx != NULL) + { + *prach_cnfg_idx = liblte_bits_2_value(ie_ptr, 6); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Presence Antenna Port 1 + + Description: Indicates whether all the neighboring cells use + antenna port 1 + + Document Reference: 36.331 v10.0.0 Section 6.3.2 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_presence_antenna_port_1_ie(bool presence_ant_port_1, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL) + { + liblte_value_2_bits(presence_ant_port_1, ie_ptr, 1); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_presence_antenna_port_1_ie(uint8 **ie_ptr, + bool *presence_ant_port_1) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + presence_ant_port_1 != NULL) + { + *presence_ant_port_1 = liblte_bits_2_value(ie_ptr, 1); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: PUCCH Config + + Description: Specifies the common and the UE specific PUCCH + configuration + + Document Reference: 36.331 v10.0.0 Section 6.3.2 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_pucch_config_common_ie(LIBLTE_RRC_PUCCH_CONFIG_COMMON_STRUCT *pucch_cnfg, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(pucch_cnfg != NULL && + ie_ptr != NULL) + { + liblte_value_2_bits(pucch_cnfg->delta_pucch_shift, ie_ptr, 2); + liblte_value_2_bits(pucch_cnfg->n_rb_cqi, ie_ptr, 7); + liblte_value_2_bits(pucch_cnfg->n_cs_an, ie_ptr, 3); + liblte_value_2_bits(pucch_cnfg->n1_pucch_an, ie_ptr, 11); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_pucch_config_common_ie(uint8 **ie_ptr, + LIBLTE_RRC_PUCCH_CONFIG_COMMON_STRUCT *pucch_cnfg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + pucch_cnfg != NULL) + { + pucch_cnfg->delta_pucch_shift = (LIBLTE_RRC_DELTA_PUCCH_SHIFT_ENUM)liblte_bits_2_value(ie_ptr, 2); + pucch_cnfg->n_rb_cqi = liblte_bits_2_value(ie_ptr, 7); + pucch_cnfg->n_cs_an = liblte_bits_2_value(ie_ptr, 3); + pucch_cnfg->n1_pucch_an = liblte_bits_2_value(ie_ptr, 11); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_pack_pucch_config_dedicated_ie(LIBLTE_RRC_PUCCH_CONFIG_DEDICATED_STRUCT *pucch_cnfg, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(pucch_cnfg != NULL && + ie_ptr != NULL) + { + // Optional indicator + liblte_value_2_bits(pucch_cnfg->tdd_ack_nack_feedback_mode_present, ie_ptr, 1); + + // Ack/Nack Repetition + liblte_value_2_bits(pucch_cnfg->ack_nack_repetition_setup_present, ie_ptr, 1); + if(pucch_cnfg->ack_nack_repetition_setup_present) + { + // Repetition Factor + liblte_value_2_bits(pucch_cnfg->ack_nack_repetition_factor, ie_ptr, 2); + + // N1 PUCCH AN Repetition + liblte_value_2_bits(pucch_cnfg->ack_nack_repetition_n1_pucch_an, ie_ptr, 11); + } + + // TDD Ack/Nack Feedback Mode + if(pucch_cnfg->tdd_ack_nack_feedback_mode_present) + { + liblte_value_2_bits(pucch_cnfg->tdd_ack_nack_feedback_mode, ie_ptr, 1); + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_pucch_config_dedicated_ie(uint8 **ie_ptr, + LIBLTE_RRC_PUCCH_CONFIG_DEDICATED_STRUCT *pucch_cnfg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + pucch_cnfg != NULL) + { + // Optional indicator + pucch_cnfg->tdd_ack_nack_feedback_mode_present = liblte_bits_2_value(ie_ptr, 1); + + // Ack/Nack Repetition + pucch_cnfg->ack_nack_repetition_setup_present = liblte_bits_2_value(ie_ptr, 1); + if(pucch_cnfg->ack_nack_repetition_setup_present) + { + // Repetition Factor + pucch_cnfg->ack_nack_repetition_factor = (LIBLTE_RRC_ACK_NACK_REPETITION_FACTOR_ENUM)liblte_bits_2_value(ie_ptr, 2); + + // N1 PUCCH AN Repetition + pucch_cnfg->ack_nack_repetition_n1_pucch_an = liblte_bits_2_value(ie_ptr, 11); + } + + // TDD Ack/Nack Feedback Mode + if(pucch_cnfg->tdd_ack_nack_feedback_mode_present) + { + pucch_cnfg->tdd_ack_nack_feedback_mode = (LIBLTE_RRC_TDD_ACK_NACK_FEEDBACK_MODE_ENUM)liblte_bits_2_value(ie_ptr, 1); + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: PUSCH Config + + Description: Specifies the common and the UE specific PUSCH + configuration and the reference signal configuration + for PUSCH and PUCCH + + Document Reference: 36.331 v10.0.0 Section 6.3.2 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_pusch_config_common_ie(LIBLTE_RRC_PUSCH_CONFIG_COMMON_STRUCT *pusch_cnfg, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(pusch_cnfg != NULL && + ie_ptr != NULL) + { + // PUSCH Config Basic + liblte_value_2_bits(pusch_cnfg->n_sb - 1, ie_ptr, 2); + liblte_value_2_bits(pusch_cnfg->hopping_mode, ie_ptr, 1); + liblte_value_2_bits(pusch_cnfg->pusch_hopping_offset, ie_ptr, 7); + liblte_value_2_bits(pusch_cnfg->enable_64_qam, ie_ptr, 1); + + // UL Reference Signals PUSCH + liblte_value_2_bits(pusch_cnfg->ul_rs.group_hopping_enabled, ie_ptr, 1); + liblte_value_2_bits(pusch_cnfg->ul_rs.group_assignment_pusch, ie_ptr, 5); + liblte_value_2_bits(pusch_cnfg->ul_rs.sequence_hopping_enabled, ie_ptr, 1); + liblte_value_2_bits(pusch_cnfg->ul_rs.cyclic_shift, ie_ptr, 3); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_pusch_config_common_ie(uint8 **ie_ptr, + LIBLTE_RRC_PUSCH_CONFIG_COMMON_STRUCT *pusch_cnfg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + pusch_cnfg != NULL) + { + // PUSCH Config Basic + pusch_cnfg->n_sb = liblte_bits_2_value(ie_ptr, 2) + 1; + pusch_cnfg->hopping_mode = (LIBLTE_RRC_HOPPING_MODE_ENUM)liblte_bits_2_value(ie_ptr, 1); + pusch_cnfg->pusch_hopping_offset = liblte_bits_2_value(ie_ptr, 7); + pusch_cnfg->enable_64_qam = liblte_bits_2_value(ie_ptr, 1); + + // UL Reference Signals PUSCH + pusch_cnfg->ul_rs.group_hopping_enabled = liblte_bits_2_value(ie_ptr, 1); + pusch_cnfg->ul_rs.group_assignment_pusch = liblte_bits_2_value(ie_ptr, 5); + pusch_cnfg->ul_rs.sequence_hopping_enabled = liblte_bits_2_value(ie_ptr, 1); + pusch_cnfg->ul_rs.cyclic_shift = liblte_bits_2_value(ie_ptr, 3); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_pack_pusch_config_dedicated_ie(LIBLTE_RRC_PUSCH_CONFIG_DEDICATED_STRUCT *pusch_cnfg, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(pusch_cnfg != NULL && + ie_ptr != NULL) + { + // Beta Offset ACK Index + liblte_value_2_bits(pusch_cnfg->beta_offset_ack_idx, ie_ptr, 4); + + // Beta Offset RI Index + liblte_value_2_bits(pusch_cnfg->beta_offset_ri_idx, ie_ptr, 4); + + // Beta Offset CQI Index + liblte_value_2_bits(pusch_cnfg->beta_offset_cqi_idx, ie_ptr, 4); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_pusch_config_dedicated_ie(uint8 **ie_ptr, + LIBLTE_RRC_PUSCH_CONFIG_DEDICATED_STRUCT *pusch_cnfg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + pusch_cnfg != NULL) + { + // Beta Offset ACK Index + pusch_cnfg->beta_offset_ack_idx = liblte_bits_2_value(ie_ptr, 4); + + // Beta Offset RI Index + pusch_cnfg->beta_offset_ri_idx = liblte_bits_2_value(ie_ptr, 4); + + // Beta Offset CQI Index + pusch_cnfg->beta_offset_cqi_idx = liblte_bits_2_value(ie_ptr, 4); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: RACH Config Common + + Description: Specifies the generic random access parameters + + Document Reference: 36.331 v10.0.0 Section 6.3.2 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_rach_config_common_ie(LIBLTE_RRC_RACH_CONFIG_COMMON_STRUCT *rach_cnfg, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(rach_cnfg != NULL && + ie_ptr != NULL) + { + // Extension indicator + liblte_value_2_bits(0, ie_ptr, 1); + + // Preamble Info + liblte_value_2_bits(rach_cnfg->preambles_group_a_cnfg.present, ie_ptr, 1); + liblte_value_2_bits(rach_cnfg->num_ra_preambles, ie_ptr, 4); + if(true == rach_cnfg->preambles_group_a_cnfg.present) + { + // Extension indicator + liblte_value_2_bits(0, ie_ptr, 1); + + liblte_value_2_bits(rach_cnfg->preambles_group_a_cnfg.size_of_ra, ie_ptr, 4); + liblte_value_2_bits(rach_cnfg->preambles_group_a_cnfg.msg_size, ie_ptr, 2); + liblte_value_2_bits(rach_cnfg->preambles_group_a_cnfg.msg_pwr_offset_group_b, ie_ptr, 3); + } + + // Power Ramping Parameters + liblte_value_2_bits(rach_cnfg->pwr_ramping_step, ie_ptr, 2); + liblte_value_2_bits(rach_cnfg->preamble_init_rx_target_pwr, ie_ptr, 4); + + // RA Supervision Info + liblte_value_2_bits(rach_cnfg->preamble_trans_max, ie_ptr, 4); + liblte_value_2_bits(rach_cnfg->ra_resp_win_size, ie_ptr, 3); + liblte_value_2_bits(rach_cnfg->mac_con_res_timer, ie_ptr, 3); + + liblte_value_2_bits(rach_cnfg->max_harq_msg3_tx - 1, ie_ptr, 3); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_rach_config_common_ie(uint8 **ie_ptr, + LIBLTE_RRC_RACH_CONFIG_COMMON_STRUCT *rach_cnfg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + rach_cnfg != NULL) + { + // Extension indicator + bool ext = liblte_bits_2_value(ie_ptr, 1); + + // Preamble Info + rach_cnfg->preambles_group_a_cnfg.present = liblte_bits_2_value(ie_ptr, 1); + rach_cnfg->num_ra_preambles = (LIBLTE_RRC_NUMBER_OF_RA_PREAMBLES_ENUM)liblte_bits_2_value(ie_ptr, 4); + if(true == rach_cnfg->preambles_group_a_cnfg.present) + { + // Extension indicator + bool ext2 = liblte_bits_2_value(ie_ptr, 1); + + rach_cnfg->preambles_group_a_cnfg.size_of_ra = (LIBLTE_RRC_SIZE_OF_RA_PREAMBLES_GROUP_A_ENUM)liblte_bits_2_value(ie_ptr, 4); + rach_cnfg->preambles_group_a_cnfg.msg_size = (LIBLTE_RRC_MESSAGE_SIZE_GROUP_A_ENUM)liblte_bits_2_value(ie_ptr, 2); + rach_cnfg->preambles_group_a_cnfg.msg_pwr_offset_group_b = (LIBLTE_RRC_MESSAGE_POWER_OFFSET_GROUP_B_ENUM)liblte_bits_2_value(ie_ptr, 3); + + liblte_rrc_consume_noncrit_extension(ext2, __func__, ie_ptr); + + }else{ + rach_cnfg->preambles_group_a_cnfg.size_of_ra = (LIBLTE_RRC_SIZE_OF_RA_PREAMBLES_GROUP_A_ENUM)rach_cnfg->num_ra_preambles; + } + + // Power Ramping Parameters + rach_cnfg->pwr_ramping_step = (LIBLTE_RRC_POWER_RAMPING_STEP_ENUM)liblte_bits_2_value(ie_ptr, 2); + rach_cnfg->preamble_init_rx_target_pwr = (LIBLTE_RRC_PREAMBLE_INITIAL_RECEIVED_TARGET_POWER_ENUM)liblte_bits_2_value(ie_ptr, 4); + + // RA Supervision Info + rach_cnfg->preamble_trans_max = (LIBLTE_RRC_PREAMBLE_TRANS_MAX_ENUM)liblte_bits_2_value(ie_ptr, 4); + rach_cnfg->ra_resp_win_size = (LIBLTE_RRC_RA_RESPONSE_WINDOW_SIZE_ENUM)liblte_bits_2_value(ie_ptr, 3); + rach_cnfg->mac_con_res_timer = (LIBLTE_RRC_MAC_CONTENTION_RESOLUTION_TIMER_ENUM)liblte_bits_2_value(ie_ptr, 3); + + rach_cnfg->max_harq_msg3_tx = liblte_bits_2_value(ie_ptr, 3) + 1; + + liblte_rrc_consume_noncrit_extension(ext, __func__, ie_ptr); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: RACH Config Dedicated + + Description: Specifies the dedicated random access parameters + + Document Reference: 36.331 v10.0.0 Section 6.3.2 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_rach_config_dedicated_ie(LIBLTE_RRC_RACH_CONFIG_DEDICATED_STRUCT *rach_cnfg, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(rach_cnfg != NULL && + ie_ptr != NULL) + { + liblte_value_2_bits(rach_cnfg->preamble_index, ie_ptr, 6); + liblte_value_2_bits(rach_cnfg->prach_mask_index, ie_ptr, 4); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_rach_config_dedicated_ie(uint8 **ie_ptr, + LIBLTE_RRC_RACH_CONFIG_DEDICATED_STRUCT *rach_cnfg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + rach_cnfg != NULL) + { + rach_cnfg->preamble_index = liblte_bits_2_value(ie_ptr, 6); + rach_cnfg->prach_mask_index = liblte_bits_2_value(ie_ptr, 4); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Radio Resource Config Common + + Description: Specifies the common radio resource configurations + in the system information and in the mobility control + information, including random access parameters + and static physical layer parameters + + Document Reference: 36.331 v10.0.0 Section 6.3.2 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_rr_config_common_sib_ie(LIBLTE_RRC_RR_CONFIG_COMMON_SIB_STRUCT *rr_cnfg, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(rr_cnfg != NULL && + ie_ptr != NULL) + { + // Extension indicator + liblte_value_2_bits(0, ie_ptr, 1); + + liblte_rrc_pack_rach_config_common_ie(&rr_cnfg->rach_cnfg, ie_ptr); + + // BCCH Config + liblte_value_2_bits(rr_cnfg->bcch_cnfg.modification_period_coeff, ie_ptr, 2); + + // PCCH Config + liblte_value_2_bits(rr_cnfg->pcch_cnfg.default_paging_cycle, ie_ptr, 2); + liblte_value_2_bits(rr_cnfg->pcch_cnfg.nB, ie_ptr, 3); + + liblte_rrc_pack_prach_config_sib_ie(&rr_cnfg->prach_cnfg, ie_ptr); + liblte_rrc_pack_pdsch_config_common_ie(&rr_cnfg->pdsch_cnfg, ie_ptr); + liblte_rrc_pack_pusch_config_common_ie(&rr_cnfg->pusch_cnfg, ie_ptr); + liblte_rrc_pack_pucch_config_common_ie(&rr_cnfg->pucch_cnfg, ie_ptr); + liblte_rrc_pack_srs_ul_config_common_ie(&rr_cnfg->srs_ul_cnfg, ie_ptr); + liblte_rrc_pack_ul_power_control_common_ie(&rr_cnfg->ul_pwr_ctrl, ie_ptr); + + // UL CP Length + liblte_value_2_bits(rr_cnfg->ul_cp_length, ie_ptr, 1); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_rr_config_common_sib_ie(uint8 **ie_ptr, + LIBLTE_RRC_RR_CONFIG_COMMON_SIB_STRUCT *rr_cnfg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + rr_cnfg != NULL) + { + // Extension indicator + bool ext = liblte_bits_2_value(ie_ptr, 1); + + liblte_rrc_unpack_rach_config_common_ie(ie_ptr, &rr_cnfg->rach_cnfg); + + // BCCH Config + rr_cnfg->bcch_cnfg.modification_period_coeff = (LIBLTE_RRC_MODIFICATION_PERIOD_COEFF_ENUM)liblte_bits_2_value(ie_ptr, 2); + + // PCCH Config + rr_cnfg->pcch_cnfg.default_paging_cycle = (LIBLTE_RRC_DEFAULT_PAGING_CYCLE_ENUM)liblte_bits_2_value(ie_ptr, 2); + rr_cnfg->pcch_cnfg.nB = (LIBLTE_RRC_NB_ENUM)liblte_bits_2_value(ie_ptr, 3); + + liblte_rrc_unpack_prach_config_sib_ie(ie_ptr, &rr_cnfg->prach_cnfg); + liblte_rrc_unpack_pdsch_config_common_ie(ie_ptr, &rr_cnfg->pdsch_cnfg); + liblte_rrc_unpack_pusch_config_common_ie(ie_ptr, &rr_cnfg->pusch_cnfg); + liblte_rrc_unpack_pucch_config_common_ie(ie_ptr, &rr_cnfg->pucch_cnfg); + liblte_rrc_unpack_srs_ul_config_common_ie(ie_ptr, &rr_cnfg->srs_ul_cnfg); + liblte_rrc_unpack_ul_power_control_common_ie(ie_ptr, &rr_cnfg->ul_pwr_ctrl); + + // UL CP Length + rr_cnfg->ul_cp_length = (LIBLTE_RRC_UL_CP_LENGTH_ENUM)liblte_bits_2_value(ie_ptr, 1); + + liblte_rrc_consume_noncrit_extension(ext, __func__, ie_ptr); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_pack_rr_config_common_ie(LIBLTE_RRC_RR_CONFIG_COMMON_STRUCT *rr_cnfg, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(rr_cnfg != NULL && + ie_ptr != NULL) + { + // Extension indicator + liblte_value_2_bits(0, ie_ptr, 1); + + // Optional indicators + liblte_value_2_bits(rr_cnfg->rach_cnfg_present, ie_ptr, 1); + liblte_value_2_bits(rr_cnfg->pdsch_cnfg_present, ie_ptr, 1); + liblte_value_2_bits(rr_cnfg->phich_cnfg_present, ie_ptr, 1); + liblte_value_2_bits(rr_cnfg->pucch_cnfg_present, ie_ptr, 1); + liblte_value_2_bits(rr_cnfg->srs_ul_cnfg_present, ie_ptr, 1); + liblte_value_2_bits(rr_cnfg->ul_pwr_ctrl_present, ie_ptr, 1); + liblte_value_2_bits(rr_cnfg->ant_info_present, ie_ptr, 1); + liblte_value_2_bits(rr_cnfg->p_max_present, ie_ptr, 1); + liblte_value_2_bits(rr_cnfg->tdd_cnfg_present, ie_ptr, 1); + + // RACH Config Common + if(rr_cnfg->rach_cnfg_present) + { + liblte_rrc_pack_rach_config_common_ie(&rr_cnfg->rach_cnfg, ie_ptr); + } + + // PRACH Config + liblte_rrc_pack_prach_config_ie(&rr_cnfg->prach_cnfg, ie_ptr); + + // PDSCH Config Common + if(rr_cnfg->pdsch_cnfg_present) + { + liblte_rrc_pack_pdsch_config_common_ie(&rr_cnfg->pdsch_cnfg, ie_ptr); + } + + // PUSCH Config Common + liblte_rrc_pack_pusch_config_common_ie(&rr_cnfg->pusch_cnfg, ie_ptr); + + // PHICH Config + if(rr_cnfg->phich_cnfg_present) + { + liblte_rrc_pack_phich_config_ie(&rr_cnfg->phich_cnfg, ie_ptr); + } + + // PUCCH Config Common + if(rr_cnfg->pucch_cnfg_present) + { + liblte_rrc_pack_pucch_config_common_ie(&rr_cnfg->pucch_cnfg, ie_ptr); + } + + // Sounding RS UL Config Common + if(rr_cnfg->srs_ul_cnfg_present) + { + liblte_rrc_pack_srs_ul_config_common_ie(&rr_cnfg->srs_ul_cnfg, ie_ptr); + } + + // Antenna Info Common + if(rr_cnfg->ant_info_present) + { + liblte_rrc_pack_antenna_info_common_ie(rr_cnfg->ant_info, ie_ptr); + } + + // P Max + if(rr_cnfg->p_max_present) + { + liblte_rrc_pack_p_max_ie(rr_cnfg->p_max, ie_ptr); + } + + // TDD Config + if(rr_cnfg->tdd_cnfg_present) + { + liblte_rrc_pack_tdd_config_ie(&rr_cnfg->tdd_cnfg, ie_ptr); + } + + // UL CP Length + liblte_value_2_bits(rr_cnfg->ul_cp_length, ie_ptr, 1); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_rr_config_common_ie(uint8 **ie_ptr, + LIBLTE_RRC_RR_CONFIG_COMMON_STRUCT *rr_cnfg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + rr_cnfg != NULL) + { + // Extension indicator + bool ext = liblte_bits_2_value(ie_ptr, 1); + + // Optional indicators + rr_cnfg->rach_cnfg_present = liblte_bits_2_value(ie_ptr, 1); + rr_cnfg->pdsch_cnfg_present = liblte_bits_2_value(ie_ptr, 1); + rr_cnfg->phich_cnfg_present = liblte_bits_2_value(ie_ptr, 1); + rr_cnfg->pucch_cnfg_present = liblte_bits_2_value(ie_ptr, 1); + rr_cnfg->srs_ul_cnfg_present = liblte_bits_2_value(ie_ptr, 1); + rr_cnfg->ul_pwr_ctrl_present = liblte_bits_2_value(ie_ptr, 1); + rr_cnfg->ant_info_present = liblte_bits_2_value(ie_ptr, 1); + rr_cnfg->p_max_present = liblte_bits_2_value(ie_ptr, 1); + rr_cnfg->tdd_cnfg_present = liblte_bits_2_value(ie_ptr, 1); + + // RACH Config Common + if(rr_cnfg->rach_cnfg_present) + { + liblte_rrc_unpack_rach_config_common_ie(ie_ptr, &rr_cnfg->rach_cnfg); + } + + // PRACH Config + liblte_rrc_unpack_prach_config_ie(ie_ptr, &rr_cnfg->prach_cnfg); + + // PDSCH Config Common + if(rr_cnfg->pdsch_cnfg_present) + { + liblte_rrc_unpack_pdsch_config_common_ie(ie_ptr, &rr_cnfg->pdsch_cnfg); + } + + // PUSCH Config Common + liblte_rrc_unpack_pusch_config_common_ie(ie_ptr, &rr_cnfg->pusch_cnfg); + + // PHICH Config + if(rr_cnfg->phich_cnfg_present) + { + liblte_rrc_unpack_phich_config_ie(ie_ptr, &rr_cnfg->phich_cnfg); + } + + // PUCCH Config Common + if(rr_cnfg->pucch_cnfg_present) + { + liblte_rrc_unpack_pucch_config_common_ie(ie_ptr, &rr_cnfg->pucch_cnfg); + } + + // Sounding RS UL Config Common + if(rr_cnfg->srs_ul_cnfg_present) + { + liblte_rrc_unpack_srs_ul_config_common_ie(ie_ptr, &rr_cnfg->srs_ul_cnfg); + } + + // Antenna Info Common + if(rr_cnfg->ant_info_present) + { + liblte_rrc_unpack_antenna_info_common_ie(ie_ptr, &rr_cnfg->ant_info); + } + + // P Max + if(rr_cnfg->p_max_present) + { + liblte_rrc_unpack_p_max_ie(ie_ptr, &rr_cnfg->p_max); + } + + // TDD Config + if(rr_cnfg->tdd_cnfg_present) + { + liblte_rrc_unpack_tdd_config_ie(ie_ptr, &rr_cnfg->tdd_cnfg); + } + + // UL CP Length + rr_cnfg->ul_cp_length = (LIBLTE_RRC_UL_CP_LENGTH_ENUM)liblte_bits_2_value(ie_ptr, 1); + + liblte_rrc_consume_noncrit_extension(ext, __func__, ie_ptr); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Radio Resource Config Dedicated + + Description: Sets up/Modifies/Releases RBs, modifies the MAC + main configuration, modifies the SPS configuration + and modifies dedicated physical configuration + + Document Reference: 36.331 v10.0.0 Section 6.3.2 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_rr_config_dedicated_ie(LIBLTE_RRC_RR_CONFIG_DEDICATED_STRUCT *rr_cnfg, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint32 i; + + if(rr_cnfg != NULL && + ie_ptr != NULL) + { + // Extension indicator + liblte_value_2_bits(rr_cnfg->rlf_timers_and_constants_present, ie_ptr, 1); + + // Optional indicators + if(rr_cnfg->srb_to_add_mod_list_size != 0) + { + liblte_value_2_bits(1, ie_ptr, 1); + }else{ + liblte_value_2_bits(0, ie_ptr, 1); + } + if(rr_cnfg->drb_to_add_mod_list_size != 0) + { + liblte_value_2_bits(1, ie_ptr, 1); + }else{ + liblte_value_2_bits(0, ie_ptr, 1); + } + if(rr_cnfg->drb_to_release_list_size != 0) + { + liblte_value_2_bits(1, ie_ptr, 1); + }else{ + liblte_value_2_bits(0, ie_ptr, 1); + } + liblte_value_2_bits(rr_cnfg->mac_main_cnfg_present, ie_ptr, 1); + liblte_value_2_bits(rr_cnfg->sps_cnfg_present, ie_ptr, 1); + liblte_value_2_bits(rr_cnfg->phy_cnfg_ded_present, ie_ptr, 1); + + // SRB To Add Mod List + if(rr_cnfg->srb_to_add_mod_list_size != 0) + { + liblte_value_2_bits(rr_cnfg->srb_to_add_mod_list_size - 1, ie_ptr, 1); + } + for(i=0; isrb_to_add_mod_list_size; i++) + { + // Extension indicator + liblte_value_2_bits(0, ie_ptr, 1); + + // Optional indicators + liblte_value_2_bits(rr_cnfg->srb_to_add_mod_list[i].rlc_cnfg_present, ie_ptr, 1); + liblte_value_2_bits(rr_cnfg->srb_to_add_mod_list[i].lc_cnfg_present, ie_ptr, 1); + + // SRB Identity + liblte_value_2_bits(rr_cnfg->srb_to_add_mod_list[i].srb_id - 1, ie_ptr, 1); + + // RLC Config + if(rr_cnfg->srb_to_add_mod_list[i].rlc_cnfg_present) + { + // Choice + liblte_value_2_bits(rr_cnfg->srb_to_add_mod_list[i].rlc_default_cnfg_present, ie_ptr, 1); + + // Explicit Config + if(!rr_cnfg->srb_to_add_mod_list[i].rlc_default_cnfg_present) + { + liblte_rrc_pack_rlc_config_ie(&rr_cnfg->srb_to_add_mod_list[i].rlc_explicit_cnfg, ie_ptr); + } + } + + // Logical Channel Config + if(rr_cnfg->srb_to_add_mod_list[i].lc_cnfg_present) + { + // Choice + liblte_value_2_bits(rr_cnfg->srb_to_add_mod_list[i].lc_default_cnfg_present, ie_ptr, 1); + + // Explicit Config + if(!rr_cnfg->srb_to_add_mod_list[i].lc_default_cnfg_present) + { + liblte_rrc_pack_logical_channel_config_ie(&rr_cnfg->srb_to_add_mod_list[i].lc_explicit_cnfg, ie_ptr); + } + } + } + + // DRB To Add Mod List + if(rr_cnfg->drb_to_add_mod_list_size != 0) + { + liblte_value_2_bits(rr_cnfg->drb_to_add_mod_list_size - 1, ie_ptr, 4); + } + for(i=0; idrb_to_add_mod_list_size; i++) + { + // Extension indicator + liblte_value_2_bits(0, ie_ptr, 1); + + // Optional indicators + liblte_value_2_bits(rr_cnfg->drb_to_add_mod_list[i].eps_bearer_id_present, ie_ptr, 1); + liblte_value_2_bits(rr_cnfg->drb_to_add_mod_list[i].pdcp_cnfg_present, ie_ptr, 1); + liblte_value_2_bits(rr_cnfg->drb_to_add_mod_list[i].rlc_cnfg_present, ie_ptr, 1); + liblte_value_2_bits(rr_cnfg->drb_to_add_mod_list[i].lc_id_present, ie_ptr, 1); + liblte_value_2_bits(rr_cnfg->drb_to_add_mod_list[i].lc_cnfg_present, ie_ptr, 1); + + // EPS Bearer Identity + if(rr_cnfg->drb_to_add_mod_list[i].eps_bearer_id_present) + { + liblte_value_2_bits(rr_cnfg->drb_to_add_mod_list[i].eps_bearer_id, ie_ptr, 4); + } + + // DRB Identity + liblte_rrc_pack_drb_identity_ie(rr_cnfg->drb_to_add_mod_list[i].drb_id, ie_ptr); + + // PDCP Config + if(rr_cnfg->drb_to_add_mod_list[i].pdcp_cnfg_present) + { + liblte_rrc_pack_pdcp_config_ie(&rr_cnfg->drb_to_add_mod_list[i].pdcp_cnfg, ie_ptr); + } + + // RLC Config + if(rr_cnfg->drb_to_add_mod_list[i].rlc_cnfg_present) + { + liblte_rrc_pack_rlc_config_ie(&rr_cnfg->drb_to_add_mod_list[i].rlc_cnfg, ie_ptr); + } + + // Logical Channel Identity + if(rr_cnfg->drb_to_add_mod_list[i].lc_id_present) + { + liblte_value_2_bits(rr_cnfg->drb_to_add_mod_list[i].lc_id - 3, ie_ptr, 3); + } + + // Logical Channel Configuration + if(rr_cnfg->drb_to_add_mod_list[i].lc_cnfg_present) + { + liblte_rrc_pack_logical_channel_config_ie(&rr_cnfg->drb_to_add_mod_list[i].lc_cnfg, ie_ptr); + } + } + + // DRB To Release List + if(rr_cnfg->drb_to_release_list_size != 0) + { + liblte_value_2_bits(rr_cnfg->drb_to_release_list_size - 1, ie_ptr, 4); + } + for(i=0; idrb_to_release_list_size; i++) + { + liblte_rrc_pack_drb_identity_ie(rr_cnfg->drb_to_release_list[i], ie_ptr); + } + + // MAC Main Config + if(rr_cnfg->mac_main_cnfg_present) + { + liblte_value_2_bits(rr_cnfg->mac_main_cnfg.default_value, ie_ptr, 1); + if(!rr_cnfg->mac_main_cnfg.default_value) + { + liblte_rrc_pack_mac_main_config_ie(&rr_cnfg->mac_main_cnfg.explicit_value, ie_ptr); + } + } + + // SPS Config + if(rr_cnfg->sps_cnfg_present) + { + liblte_rrc_pack_sps_config_ie(&rr_cnfg->sps_cnfg, ie_ptr); + } + + // Physical Config Dedicated + if(rr_cnfg->phy_cnfg_ded_present) + { + liblte_rrc_pack_physical_config_dedicated_ie(&rr_cnfg->phy_cnfg_ded, ie_ptr); + } + + // Extension + // Optional indicators + liblte_value_2_bits(rr_cnfg->rlf_timers_and_constants_present, ie_ptr, 1); + + // RLF Timers and Constants + if(rr_cnfg->rlf_timers_and_constants_present) + { + liblte_rrc_pack_rlf_timers_and_constants_ie(&rr_cnfg->rlf_timers_and_constants, ie_ptr); + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_rr_config_dedicated_ie(uint8 **ie_ptr, + LIBLTE_RRC_RR_CONFIG_DEDICATED_STRUCT *rr_cnfg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint32 i; + bool ext; + bool srb_ext; + bool drb_ext; + bool srb_to_add_mod_list_present; + bool drb_to_add_mod_list_present; + bool drb_to_release_list_present; + + if(ie_ptr != NULL && + rr_cnfg != NULL) + { + // Extension indicator + ext = liblte_bits_2_value(ie_ptr, 1); + + // Optional indicators + srb_to_add_mod_list_present = liblte_bits_2_value(ie_ptr, 1); + drb_to_add_mod_list_present = liblte_bits_2_value(ie_ptr, 1); + drb_to_release_list_present = liblte_bits_2_value(ie_ptr, 1); + rr_cnfg->mac_main_cnfg_present = liblte_bits_2_value(ie_ptr, 1); + rr_cnfg->sps_cnfg_present = liblte_bits_2_value(ie_ptr, 1); + rr_cnfg->phy_cnfg_ded_present = liblte_bits_2_value(ie_ptr, 1); + + // SRB To Add Mod List + if(srb_to_add_mod_list_present) + { + rr_cnfg->srb_to_add_mod_list_size = liblte_bits_2_value(ie_ptr, 1) + 1; + for(i=0; isrb_to_add_mod_list_size; i++) + { + // Extension indicator + srb_ext = liblte_bits_2_value(ie_ptr, 1); + + // Optional indicators + rr_cnfg->srb_to_add_mod_list[i].rlc_cnfg_present = liblte_bits_2_value(ie_ptr, 1); + rr_cnfg->srb_to_add_mod_list[i].lc_cnfg_present = liblte_bits_2_value(ie_ptr, 1); + + // SRB Identity + rr_cnfg->srb_to_add_mod_list[i].srb_id = liblte_bits_2_value(ie_ptr, 1) + 1; + + // RLC Config + if(rr_cnfg->srb_to_add_mod_list[i].rlc_cnfg_present) + { + // Choice + rr_cnfg->srb_to_add_mod_list[i].rlc_default_cnfg_present = liblte_bits_2_value(ie_ptr, 1); + + // Explicit Config + if(!rr_cnfg->srb_to_add_mod_list[i].rlc_default_cnfg_present) + { + liblte_rrc_unpack_rlc_config_ie(ie_ptr, &rr_cnfg->srb_to_add_mod_list[i].rlc_explicit_cnfg); + } + } + + // Logical Channel Config + if(rr_cnfg->srb_to_add_mod_list[i].lc_cnfg_present) + { + // Choice + rr_cnfg->srb_to_add_mod_list[i].lc_default_cnfg_present = liblte_bits_2_value(ie_ptr, 1); + + // Explicit Config + if(!rr_cnfg->srb_to_add_mod_list[i].lc_default_cnfg_present) + { + liblte_rrc_unpack_logical_channel_config_ie(ie_ptr, &rr_cnfg->srb_to_add_mod_list[i].lc_explicit_cnfg); + } + } + + // Consume non-critical extensions + liblte_rrc_consume_noncrit_extension(srb_ext, __func__, ie_ptr); + } + } + + // DRB To Add Mod List + if(drb_to_add_mod_list_present) + { + rr_cnfg->drb_to_add_mod_list_size = liblte_bits_2_value(ie_ptr, 4) + 1; + for(i=0; idrb_to_add_mod_list_size; i++) + { + // Extension indicator + drb_ext = liblte_bits_2_value(ie_ptr, 1); + + // Optional indicators + rr_cnfg->drb_to_add_mod_list[i].eps_bearer_id_present = liblte_bits_2_value(ie_ptr, 1); + rr_cnfg->drb_to_add_mod_list[i].pdcp_cnfg_present = liblte_bits_2_value(ie_ptr, 1); + rr_cnfg->drb_to_add_mod_list[i].rlc_cnfg_present = liblte_bits_2_value(ie_ptr, 1); + rr_cnfg->drb_to_add_mod_list[i].lc_id_present = liblte_bits_2_value(ie_ptr, 1); + rr_cnfg->drb_to_add_mod_list[i].lc_cnfg_present = liblte_bits_2_value(ie_ptr, 1); + + // EPS Bearer Identity + if(rr_cnfg->drb_to_add_mod_list[i].eps_bearer_id_present) + { + rr_cnfg->drb_to_add_mod_list[i].eps_bearer_id = liblte_bits_2_value(ie_ptr, 4); + } + + // DRB Identity + liblte_rrc_unpack_drb_identity_ie(ie_ptr, &rr_cnfg->drb_to_add_mod_list[i].drb_id); + + // PDCP Config + if(rr_cnfg->drb_to_add_mod_list[i].pdcp_cnfg_present) + { + liblte_rrc_unpack_pdcp_config_ie(ie_ptr, &rr_cnfg->drb_to_add_mod_list[i].pdcp_cnfg); + } + + // RLC Config + if(rr_cnfg->drb_to_add_mod_list[i].rlc_cnfg_present) + { + liblte_rrc_unpack_rlc_config_ie(ie_ptr, &rr_cnfg->drb_to_add_mod_list[i].rlc_cnfg); + } + + // Logical Channel Identity + if(rr_cnfg->drb_to_add_mod_list[i].lc_id_present) + { + rr_cnfg->drb_to_add_mod_list[i].lc_id = liblte_bits_2_value(ie_ptr, 3) + 3; + } + + // Logical Channel Configuration + if(rr_cnfg->drb_to_add_mod_list[i].lc_cnfg_present) + { + liblte_rrc_unpack_logical_channel_config_ie(ie_ptr, &rr_cnfg->drb_to_add_mod_list[i].lc_cnfg); + } + + // Consume non-critical extensions + liblte_rrc_consume_noncrit_extension(drb_ext, __func__, ie_ptr); + } + } + + // DRB To Release List + if(drb_to_release_list_present) + { + rr_cnfg->drb_to_release_list_size = liblte_bits_2_value(ie_ptr, 4) + 1; + for(i=0; idrb_to_release_list_size; i++) + { + liblte_rrc_unpack_drb_identity_ie(ie_ptr, &rr_cnfg->drb_to_release_list[i]); + } + } + + // MAC Main Config + if(rr_cnfg->mac_main_cnfg_present) + { + rr_cnfg->mac_main_cnfg.default_value = liblte_bits_2_value(ie_ptr, 1); + if(!rr_cnfg->mac_main_cnfg.default_value) + { + liblte_rrc_unpack_mac_main_config_ie(ie_ptr, &rr_cnfg->mac_main_cnfg.explicit_value); + } + } + + // SPS Config + if(rr_cnfg->sps_cnfg_present) + { + liblte_rrc_unpack_sps_config_ie(ie_ptr, &rr_cnfg->sps_cnfg); + } + + // Physical Config Dedicated + if(rr_cnfg->phy_cnfg_ded_present) + { + liblte_rrc_unpack_physical_config_dedicated_ie(ie_ptr, &rr_cnfg->phy_cnfg_ded); + } + + // Extension (FIXME: only handling r9 extensions) +#if 0 + if(ext) + { + // Optional indicators + rr_cnfg->rlf_timers_and_constants_present = liblte_bits_2_value(ie_ptr, 1); + + // RLF Timers and Constants + if(rr_cnfg->rlf_timers_and_constants_present) + { + liblte_rrc_unpack_rlf_timers_and_constants_ie(ie_ptr, &rr_cnfg->rlf_timers_and_constants); + } + } +#endif + // Modified by ismael, just skip extensions + liblte_rrc_consume_noncrit_extension(ext, __func__, ie_ptr); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: RLC Config + + Description: Specifies the RLC configuration of SRBs and DRBs + + Document Reference: 36.331 v10.0.0 Section 6.3.2 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_rlc_config_ie(LIBLTE_RRC_RLC_CONFIG_STRUCT *rlc_cnfg, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(rlc_cnfg != NULL && + ie_ptr != NULL) + { + // Extension indicator + liblte_value_2_bits(0, ie_ptr, 1); + + // Mode Choice + liblte_value_2_bits(rlc_cnfg->rlc_mode, ie_ptr, 2); + + if(LIBLTE_RRC_RLC_MODE_AM == rlc_cnfg->rlc_mode) + { + // UL AM RLC + { + // T Poll Retransmit + liblte_value_2_bits(rlc_cnfg->ul_am_rlc.t_poll_retx, ie_ptr, 6); + + // Poll PDU + liblte_value_2_bits(rlc_cnfg->ul_am_rlc.poll_pdu, ie_ptr, 3); + + // Poll Byte + liblte_value_2_bits(rlc_cnfg->ul_am_rlc.poll_byte, ie_ptr, 4); + + // Max Retransmission Threshold + liblte_value_2_bits(rlc_cnfg->ul_am_rlc.max_retx_thresh, ie_ptr, 3); + } + + // DL AM RLC + { + // T Reordering + liblte_value_2_bits(rlc_cnfg->dl_am_rlc.t_reordering, ie_ptr, 5); + + // T Status Prohibit + liblte_value_2_bits(rlc_cnfg->dl_am_rlc.t_status_prohibit, ie_ptr, 6); + } + }else if(LIBLTE_RRC_RLC_MODE_UM_BI == rlc_cnfg->rlc_mode){ + // UL UM RLC + { + // SN Field Length + liblte_value_2_bits(rlc_cnfg->ul_um_bi_rlc.sn_field_len, ie_ptr, 1); + } + + // DL UM RLC + { + // SN Field Length + liblte_value_2_bits(rlc_cnfg->dl_um_bi_rlc.sn_field_len, ie_ptr, 1); + + // T Reordering + liblte_value_2_bits(rlc_cnfg->dl_um_bi_rlc.t_reordering, ie_ptr, 5); + } + }else if(LIBLTE_RRC_RLC_MODE_UM_UNI_UL == rlc_cnfg->rlc_mode){ + // SN Field Length + liblte_value_2_bits(rlc_cnfg->ul_um_uni_rlc.sn_field_len, ie_ptr, 1); + }else{ // LIBLTE_RRC_RLC_MODE_UM_UNI_DL == rlc_cnfg->rlc_mode + // SN Field Length + liblte_value_2_bits(rlc_cnfg->dl_um_uni_rlc.sn_field_len, ie_ptr, 1); + + // T Reordering + liblte_value_2_bits(rlc_cnfg->dl_um_uni_rlc.t_reordering, ie_ptr, 5); + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_rlc_config_ie(uint8 **ie_ptr, + LIBLTE_RRC_RLC_CONFIG_STRUCT *rlc_cnfg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + rlc_cnfg != NULL) + { + // Extension indicator + bool ext = liblte_bits_2_value(ie_ptr, 1); + + // Mode Choice + rlc_cnfg->rlc_mode = (LIBLTE_RRC_RLC_MODE_ENUM)liblte_bits_2_value(ie_ptr, 2); + + if(LIBLTE_RRC_RLC_MODE_AM == rlc_cnfg->rlc_mode) + { + // UL AM RLC + { + // T Poll Retransmit + rlc_cnfg->ul_am_rlc.t_poll_retx = (LIBLTE_RRC_T_POLL_RETRANSMIT_ENUM)liblte_bits_2_value(ie_ptr, 6); + + // Poll PDU + rlc_cnfg->ul_am_rlc.poll_pdu = (LIBLTE_RRC_POLL_PDU_ENUM)liblte_bits_2_value(ie_ptr, 3); + + // Poll Byte + rlc_cnfg->ul_am_rlc.poll_byte = (LIBLTE_RRC_POLL_BYTE_ENUM)liblte_bits_2_value(ie_ptr, 4); + + // Max Retransmission Threshold + rlc_cnfg->ul_am_rlc.max_retx_thresh = (LIBLTE_RRC_MAX_RETX_THRESHOLD_ENUM)liblte_bits_2_value(ie_ptr, 3); + } + + // DL AM RLC + { + // T Reordering + rlc_cnfg->dl_am_rlc.t_reordering = (LIBLTE_RRC_T_REORDERING_ENUM)liblte_bits_2_value(ie_ptr, 5); + + // T Status Prohibit + rlc_cnfg->dl_am_rlc.t_status_prohibit = (LIBLTE_RRC_T_STATUS_PROHIBIT_ENUM)liblte_bits_2_value(ie_ptr, 6); + } + }else if(LIBLTE_RRC_RLC_MODE_UM_BI == rlc_cnfg->rlc_mode){ + // UL UM RLC + { + // SN Field Length + rlc_cnfg->ul_um_bi_rlc.sn_field_len = (LIBLTE_RRC_SN_FIELD_LENGTH_ENUM)liblte_bits_2_value(ie_ptr, 1); + } + + // DL UM RLC + { + // SN Field Length + rlc_cnfg->dl_um_bi_rlc.sn_field_len = (LIBLTE_RRC_SN_FIELD_LENGTH_ENUM)liblte_bits_2_value(ie_ptr, 1); + + // T Reordering + rlc_cnfg->dl_um_bi_rlc.t_reordering = (LIBLTE_RRC_T_REORDERING_ENUM)liblte_bits_2_value(ie_ptr, 5); + } + }else if(LIBLTE_RRC_RLC_MODE_UM_UNI_UL == rlc_cnfg->rlc_mode){ + // SN Field Length + rlc_cnfg->ul_um_uni_rlc.sn_field_len = (LIBLTE_RRC_SN_FIELD_LENGTH_ENUM)liblte_bits_2_value(ie_ptr, 1); + }else{ // LIBLTE_RRC_RLC_MODE_UM_UNI_DL == rlc_cnfg->rlc_mode + // SN Field Length + rlc_cnfg->dl_um_uni_rlc.sn_field_len = (LIBLTE_RRC_SN_FIELD_LENGTH_ENUM)liblte_bits_2_value(ie_ptr, 1); + + // T Reordering + rlc_cnfg->dl_um_uni_rlc.t_reordering = (LIBLTE_RRC_T_REORDERING_ENUM)liblte_bits_2_value(ie_ptr, 5); + } + + liblte_rrc_consume_noncrit_extension(ext, __func__, ie_ptr); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: RLF Timers and Constants + + Description: Contains UE specific timers and constants applicable + for UEs in RRC_CONNECTED + + Document Reference: 36.331 v10.0.0 Section 6.3.2 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_rlf_timers_and_constants_ie(LIBLTE_RRC_RLF_TIMERS_AND_CONSTANTS_STRUCT *rlf_timers_and_constants, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(rlf_timers_and_constants != NULL && + ie_ptr != NULL) + { + // Release choice + liblte_value_2_bits(1, ie_ptr, 1); + + // Extension + liblte_value_2_bits(0, ie_ptr, 1); + + liblte_value_2_bits(rlf_timers_and_constants->t301, ie_ptr, 3); + liblte_value_2_bits(rlf_timers_and_constants->t310, ie_ptr, 3); + liblte_value_2_bits(rlf_timers_and_constants->n310, ie_ptr, 3); + liblte_value_2_bits(rlf_timers_and_constants->t311, ie_ptr, 3); + liblte_value_2_bits(rlf_timers_and_constants->n311, ie_ptr, 3); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_rlf_timers_and_constants_ie(uint8 **ie_ptr, + LIBLTE_RRC_RLF_TIMERS_AND_CONSTANTS_STRUCT *rlf_timers_and_constants) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + rlf_timers_and_constants != NULL) + { + // Release choice + liblte_bits_2_value(ie_ptr, 1); + + // Extension + liblte_bits_2_value(ie_ptr, 1); + + rlf_timers_and_constants->t301 = (LIBLTE_RRC_T301_ENUM)liblte_bits_2_value(ie_ptr, 3); + rlf_timers_and_constants->t310 = (LIBLTE_RRC_T310_ENUM)liblte_bits_2_value(ie_ptr, 3); + rlf_timers_and_constants->n310 = (LIBLTE_RRC_N310_ENUM)liblte_bits_2_value(ie_ptr, 3); + rlf_timers_and_constants->t311 = (LIBLTE_RRC_T311_ENUM)liblte_bits_2_value(ie_ptr, 3); + rlf_timers_and_constants->n311 = (LIBLTE_RRC_N311_ENUM)liblte_bits_2_value(ie_ptr, 3); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: RN Subframe Config + + Description: Specifies the subframe configuration for an RN + + Document Reference: 36.331 v10.0.0 Section 6.3.2 +*********************************************************************/ +// FIXME + +/********************************************************************* + IE Name: Scheduling Request Config + + Description: Specifies the scheduling request related parameters + + Document Reference: 36.331 v10.0.0 Section 6.3.2 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_scheduling_request_config_ie(LIBLTE_RRC_SCHEDULING_REQUEST_CONFIG_STRUCT *sched_request_cnfg, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(sched_request_cnfg != NULL && + ie_ptr != NULL) + { + // Setup + liblte_value_2_bits(sched_request_cnfg->setup_present, ie_ptr, 1); + if(sched_request_cnfg->setup_present) + { + // SR PUCCH Resource Index + liblte_value_2_bits(sched_request_cnfg->sr_pucch_resource_idx, ie_ptr, 11); + + // SR Config Index + liblte_value_2_bits(sched_request_cnfg->sr_cnfg_idx, ie_ptr, 8); + + // DRS Trans Max + liblte_value_2_bits(sched_request_cnfg->dsr_trans_max, ie_ptr, 3); + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_scheduling_request_config_ie(uint8 **ie_ptr, + LIBLTE_RRC_SCHEDULING_REQUEST_CONFIG_STRUCT *sched_request_cnfg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + sched_request_cnfg != NULL) + { + // Setup + sched_request_cnfg->setup_present = liblte_bits_2_value(ie_ptr, 1); + if(sched_request_cnfg->setup_present) + { + // SR PUCCH Resource Index + sched_request_cnfg->sr_pucch_resource_idx = liblte_bits_2_value(ie_ptr, 11); + + // SR Config Index + sched_request_cnfg->sr_cnfg_idx = liblte_bits_2_value(ie_ptr, 8); + + // DRS Trans Max + sched_request_cnfg->dsr_trans_max = (LIBLTE_RRC_DSR_TRANS_MAX_ENUM)liblte_bits_2_value(ie_ptr, 3); + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Sounding RS UL Config + + Description: Specifies the uplink Sounding RS configuration for + periodic and aperiodic sounding + + Document Reference: 36.331 v10.0.0 Section 6.3.2 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_srs_ul_config_common_ie(LIBLTE_RRC_SRS_UL_CONFIG_COMMON_STRUCT *srs_ul_cnfg, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(srs_ul_cnfg != NULL && + ie_ptr != NULL) + { + liblte_value_2_bits(srs_ul_cnfg->present, ie_ptr, 1); + + if(true == srs_ul_cnfg->present) + { + liblte_value_2_bits(srs_ul_cnfg->max_up_pts_present, ie_ptr, 1); + + liblte_value_2_bits(srs_ul_cnfg->bw_cnfg, ie_ptr, 3); + liblte_value_2_bits(srs_ul_cnfg->subfr_cnfg, ie_ptr, 4); + liblte_value_2_bits(srs_ul_cnfg->ack_nack_simul_tx, ie_ptr, 1); + + if(true == srs_ul_cnfg->max_up_pts_present) + { + liblte_value_2_bits(srs_ul_cnfg->max_up_pts, ie_ptr, 1); + } + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_srs_ul_config_common_ie(uint8 **ie_ptr, + LIBLTE_RRC_SRS_UL_CONFIG_COMMON_STRUCT *srs_ul_cnfg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + srs_ul_cnfg != NULL) + { + srs_ul_cnfg->present = liblte_bits_2_value(ie_ptr, 1); + + if(true == srs_ul_cnfg->present) + { + srs_ul_cnfg->max_up_pts_present = liblte_bits_2_value(ie_ptr, 1); + + srs_ul_cnfg->bw_cnfg = (LIBLTE_RRC_SRS_BW_CONFIG_ENUM)liblte_bits_2_value(ie_ptr, 3); + srs_ul_cnfg->subfr_cnfg = (LIBLTE_RRC_SRS_SUBFR_CONFIG_ENUM)liblte_bits_2_value(ie_ptr, 4); + srs_ul_cnfg->ack_nack_simul_tx = liblte_bits_2_value(ie_ptr, 1); + + if(true == srs_ul_cnfg->max_up_pts_present) + { + srs_ul_cnfg->max_up_pts = liblte_bits_2_value(ie_ptr, 1); + } + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_pack_srs_ul_config_dedicated_ie(LIBLTE_RRC_SRS_UL_CONFIG_DEDICATED_STRUCT *srs_ul_cnfg, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(srs_ul_cnfg != NULL && + ie_ptr != NULL) + { + // Setup + liblte_value_2_bits(srs_ul_cnfg->setup_present, ie_ptr, 1); + if(srs_ul_cnfg->setup_present) + { + // SRS Bandwidth + liblte_value_2_bits(srs_ul_cnfg->srs_bandwidth, ie_ptr, 2); + + // SRS Hopping Bandwidth + liblte_value_2_bits(srs_ul_cnfg->srs_hopping_bandwidth, ie_ptr, 2); + + // Frequency Domain Position + liblte_value_2_bits(srs_ul_cnfg->freq_domain_pos, ie_ptr, 5); + + // Duration + liblte_value_2_bits(srs_ul_cnfg->duration, ie_ptr, 1); + + // SRS Config Index + liblte_value_2_bits(srs_ul_cnfg->srs_cnfg_idx, ie_ptr, 10); + + // Transmission Comb + liblte_value_2_bits(srs_ul_cnfg->tx_comb, ie_ptr, 1); + + // Cyclic Shift + liblte_value_2_bits(srs_ul_cnfg->cyclic_shift, ie_ptr, 3); + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_srs_ul_config_dedicated_ie(uint8 **ie_ptr, + LIBLTE_RRC_SRS_UL_CONFIG_DEDICATED_STRUCT *srs_ul_cnfg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + srs_ul_cnfg != NULL) + { + // Setup + srs_ul_cnfg->setup_present = liblte_bits_2_value(ie_ptr, 1); + if(srs_ul_cnfg->setup_present) + { + // SRS Bandwidth + srs_ul_cnfg->srs_bandwidth = (LIBLTE_RRC_SRS_BANDWIDTH_ENUM)liblte_bits_2_value(ie_ptr, 2); + + // SRS Hopping Bandwidth + srs_ul_cnfg->srs_hopping_bandwidth = (LIBLTE_RRC_SRS_HOPPING_BANDWIDTH_ENUM)liblte_bits_2_value(ie_ptr, 2); + + // Frequency Domain Position + srs_ul_cnfg->freq_domain_pos = liblte_bits_2_value(ie_ptr, 5); + + // Duration + srs_ul_cnfg->duration = liblte_bits_2_value(ie_ptr, 1); + + // SRS Config Index + srs_ul_cnfg->srs_cnfg_idx = liblte_bits_2_value(ie_ptr, 10); + + // Transmission Comb + srs_ul_cnfg->tx_comb = liblte_bits_2_value(ie_ptr, 1); + + // Cyclic Shift + srs_ul_cnfg->cyclic_shift = (LIBLTE_RRC_CYCLIC_SHIFT_ENUM)liblte_bits_2_value(ie_ptr, 3); + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: SPS Config + + Description: Specifies the semi-persistent scheduling + configuration + + Document Reference: 36.331 v10.0.0 Section 6.3.2 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_sps_config_ie(LIBLTE_RRC_SPS_CONFIG_STRUCT *sps_cnfg, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint32 i; + + if(sps_cnfg != NULL && + ie_ptr != NULL) + { + // Optional indicators + liblte_value_2_bits(sps_cnfg->sps_c_rnti_present, ie_ptr, 1); + liblte_value_2_bits(sps_cnfg->sps_cnfg_dl_present, ie_ptr, 1); + liblte_value_2_bits(sps_cnfg->sps_cnfg_ul_present, ie_ptr, 1); + + // SPS C-RNTI + if(sps_cnfg->sps_c_rnti_present) + { + liblte_rrc_pack_c_rnti_ie(sps_cnfg->sps_c_rnti, ie_ptr); + } + + // SPS Config DL + if(sps_cnfg->sps_cnfg_dl_present) + { + liblte_value_2_bits(sps_cnfg->sps_cnfg_dl.setup_present, ie_ptr, 1); + if(sps_cnfg->sps_cnfg_dl.setup_present) + { + // Extension indicator + liblte_value_2_bits(0, ie_ptr, 1); + + // SPS Interval DL + liblte_value_2_bits(sps_cnfg->sps_cnfg_dl.sps_interval_dl, ie_ptr, 4); + + // Number of Configured SPS Processes + liblte_value_2_bits(sps_cnfg->sps_cnfg_dl.N_sps_processes - 1, ie_ptr, 3); + + // N1 PUCCH AN Persistent List + liblte_value_2_bits(sps_cnfg->sps_cnfg_dl.n1_pucch_an_persistent_list_size - 1, ie_ptr, 2); + for(i=0; isps_cnfg_dl.n1_pucch_an_persistent_list_size; i++) + { + liblte_value_2_bits(sps_cnfg->sps_cnfg_dl.n1_pucch_an_persistent_list[i], ie_ptr, 11); + } + } + } + + // SPS Config UL + if(sps_cnfg->sps_cnfg_ul_present) + { + liblte_value_2_bits(sps_cnfg->sps_cnfg_ul.setup_present, ie_ptr, 1); + if(sps_cnfg->sps_cnfg_ul.setup_present) + { + // Extension indicator + liblte_value_2_bits(0, ie_ptr, 1); + + // Optional indicators + liblte_value_2_bits(sps_cnfg->sps_cnfg_ul.p0_persistent_present, ie_ptr, 1); + liblte_value_2_bits(sps_cnfg->sps_cnfg_ul.two_intervals_cnfg_present, ie_ptr, 1); + + // SPS Interval UL + liblte_value_2_bits(sps_cnfg->sps_cnfg_ul.sps_interval_ul, ie_ptr, 4); + + // Implicit Release After + liblte_value_2_bits(sps_cnfg->sps_cnfg_ul.implicit_release_after, ie_ptr, 2); + + // P0 Persistent + if(sps_cnfg->sps_cnfg_ul.p0_persistent_present) + { + // P0 Nominal PUSCH Persistent + liblte_value_2_bits(sps_cnfg->sps_cnfg_ul.p0_nominal_pusch + 126, ie_ptr, 8); + + // P0 UE PUSCH Persistent + liblte_value_2_bits(sps_cnfg->sps_cnfg_ul.p0_ue_pusch + 8, ie_ptr, 4); + } + + // Two Intervals Config + if(sps_cnfg->sps_cnfg_ul.two_intervals_cnfg_present) + { + liblte_value_2_bits(sps_cnfg->sps_cnfg_ul.two_intervals_cnfg, ie_ptr, 1); + } + } + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_sps_config_ie(uint8 **ie_ptr, + LIBLTE_RRC_SPS_CONFIG_STRUCT *sps_cnfg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint32 i; + + if(ie_ptr != NULL && + sps_cnfg != NULL) + { + // Optional indicators + sps_cnfg->sps_c_rnti_present = liblte_bits_2_value(ie_ptr, 1); + sps_cnfg->sps_cnfg_dl_present = liblte_bits_2_value(ie_ptr, 1); + sps_cnfg->sps_cnfg_ul_present = liblte_bits_2_value(ie_ptr, 1); + + // SPS C-RNTI + if(sps_cnfg->sps_c_rnti_present) + { + liblte_rrc_unpack_c_rnti_ie(ie_ptr, &sps_cnfg->sps_c_rnti); + } + + // SPS Config DL + if(sps_cnfg->sps_cnfg_dl_present) + { + sps_cnfg->sps_cnfg_dl.setup_present = liblte_bits_2_value(ie_ptr, 1); + if(sps_cnfg->sps_cnfg_dl.setup_present) + { + // Extension indicator + bool ext = liblte_bits_2_value(ie_ptr, 1); + + // SPS Interval DL + sps_cnfg->sps_cnfg_dl.sps_interval_dl = (LIBLTE_RRC_SPS_INTERVAL_DL_ENUM)liblte_bits_2_value(ie_ptr, 4); + + // Number of Configured SPS Processes + sps_cnfg->sps_cnfg_dl.N_sps_processes = liblte_bits_2_value(ie_ptr, 3) + 1; + + // N1 PUCCH AN Persistent List + sps_cnfg->sps_cnfg_dl.n1_pucch_an_persistent_list_size = liblte_bits_2_value(ie_ptr, 2) + 1; + for(i=0; isps_cnfg_dl.n1_pucch_an_persistent_list_size; i++) + { + sps_cnfg->sps_cnfg_dl.n1_pucch_an_persistent_list[i] = liblte_bits_2_value(ie_ptr, 11); + } + + liblte_rrc_consume_noncrit_extension(ext, __func__, ie_ptr); + } + } + + // SPS Config UL + if(sps_cnfg->sps_cnfg_ul_present) + { + sps_cnfg->sps_cnfg_ul.setup_present = liblte_bits_2_value(ie_ptr, 1); + if(sps_cnfg->sps_cnfg_ul.setup_present) + { + // Extension indicator + bool ext = liblte_bits_2_value(ie_ptr, 1); + + // Optional indicators + sps_cnfg->sps_cnfg_ul.p0_persistent_present = liblte_bits_2_value(ie_ptr, 1); + sps_cnfg->sps_cnfg_ul.two_intervals_cnfg_present = liblte_bits_2_value(ie_ptr, 1); + + // SPS Interval UL + sps_cnfg->sps_cnfg_ul.sps_interval_ul = (LIBLTE_RRC_SPS_INTERVAL_UL_ENUM)liblte_bits_2_value(ie_ptr, 4); + + // Implicit Release After + sps_cnfg->sps_cnfg_ul.implicit_release_after = (LIBLTE_RRC_IMPLICIT_RELEASE_AFTER_ENUM)liblte_bits_2_value(ie_ptr, 2); + + // P0 Persistent + if(sps_cnfg->sps_cnfg_ul.p0_persistent_present) + { + // P0 Nominal PUSCH Persistent + sps_cnfg->sps_cnfg_ul.p0_nominal_pusch = liblte_bits_2_value(ie_ptr, 8) - 126; + + // P0 UE PUSCH Persistent + sps_cnfg->sps_cnfg_ul.p0_ue_pusch = liblte_bits_2_value(ie_ptr, 4) - 8; + } + + // Two Intervals Config + if(sps_cnfg->sps_cnfg_ul.two_intervals_cnfg_present) + { + sps_cnfg->sps_cnfg_ul.two_intervals_cnfg = (LIBLTE_RRC_TWO_INTERVALS_CONFIG_ENUM)liblte_bits_2_value(ie_ptr, 1); + } + + liblte_rrc_consume_noncrit_extension(ext, __func__, ie_ptr); + } + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: TDD Config + + Description: Specifies the TDD specific physical channel + configuration + + Document Reference: 36.331 v10.0.0 Section 6.3.2 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_tdd_config_ie(LIBLTE_RRC_TDD_CONFIG_STRUCT *tdd_cnfg, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(tdd_cnfg != NULL && + ie_ptr != NULL) + { + liblte_value_2_bits(tdd_cnfg->sf_assignment, ie_ptr, 3); + liblte_value_2_bits(tdd_cnfg->special_sf_patterns, ie_ptr, 4); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_tdd_config_ie(uint8 **ie_ptr, + LIBLTE_RRC_TDD_CONFIG_STRUCT *tdd_cnfg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + tdd_cnfg != NULL) + { + tdd_cnfg->sf_assignment = (LIBLTE_RRC_SUBFRAME_ASSIGNMENT_ENUM)liblte_bits_2_value(ie_ptr, 3); + tdd_cnfg->special_sf_patterns = (LIBLTE_RRC_SPECIAL_SUBFRAME_PATTERNS_ENUM)liblte_bits_2_value(ie_ptr, 4); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Time Alignment Timer + + Description: Controls how long the UE is considered uplink time + aligned + + Document Reference: 36.331 v10.0.0 Section 6.3.2 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_time_alignment_timer_ie(LIBLTE_RRC_TIME_ALIGNMENT_TIMER_ENUM time_alignment_timer, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL) + { + liblte_value_2_bits(time_alignment_timer, ie_ptr, 3); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_time_alignment_timer_ie(uint8 **ie_ptr, + LIBLTE_RRC_TIME_ALIGNMENT_TIMER_ENUM *time_alignment_timer) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + time_alignment_timer != NULL) + { + *time_alignment_timer = (LIBLTE_RRC_TIME_ALIGNMENT_TIMER_ENUM)liblte_bits_2_value(ie_ptr, 3); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: TPC PDCCH Config + + Description: Specifies the RNTIs and indecies for PUCCH and PUSCH + power control + + Document Reference: 36.331 v10.0.0 Section 6.3.2 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_tpc_pdcch_config_ie(LIBLTE_RRC_TPC_PDCCH_CONFIG_STRUCT *tpc_pdcch_cnfg, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(tpc_pdcch_cnfg != NULL && + ie_ptr != NULL) + { + // Setup + liblte_value_2_bits(tpc_pdcch_cnfg->setup_present, ie_ptr, 1); + if(tpc_pdcch_cnfg->setup_present) + { + // TPC RNTI + liblte_value_2_bits(tpc_pdcch_cnfg->tpc_rnti, ie_ptr, 16); + + // TPC Index + liblte_value_2_bits(tpc_pdcch_cnfg->tpc_idx_choice, ie_ptr, 1); + if(LIBLTE_RRC_TPC_INDEX_FORMAT_3 == tpc_pdcch_cnfg->tpc_idx_choice) + { + liblte_value_2_bits(tpc_pdcch_cnfg->tpc_idx - 1, ie_ptr, 4); + }else{ + liblte_value_2_bits(tpc_pdcch_cnfg->tpc_idx - 1, ie_ptr, 5); + } + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_tpc_pdcch_config_ie(uint8 **ie_ptr, + LIBLTE_RRC_TPC_PDCCH_CONFIG_STRUCT *tpc_pdcch_cnfg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + tpc_pdcch_cnfg != NULL) + { + // Setup + tpc_pdcch_cnfg->setup_present = liblte_bits_2_value(ie_ptr, 1); + if(tpc_pdcch_cnfg->setup_present) + { + // TPC RNTI + tpc_pdcch_cnfg->tpc_rnti = liblte_bits_2_value(ie_ptr, 16); + + // TPC Index + tpc_pdcch_cnfg->tpc_idx_choice = (LIBLTE_RRC_TPC_INDEX_ENUM)liblte_bits_2_value(ie_ptr, 1); + if(LIBLTE_RRC_TPC_INDEX_FORMAT_3 == tpc_pdcch_cnfg->tpc_idx_choice) + { + tpc_pdcch_cnfg->tpc_idx = liblte_bits_2_value(ie_ptr, 4) + 1; + }else{ + tpc_pdcch_cnfg->tpc_idx = liblte_bits_2_value(ie_ptr, 5) + 1; + } + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: UL Antenna Info + + Description: Specifies the UL antenna configuration + + Document Reference: 36.331 v10.0.0 Section 6.3.2 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_ul_antenna_info_ie(LIBLTE_RRC_UL_ANTENNA_INFO_STRUCT *ul_ant_info, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ul_ant_info != NULL && + ie_ptr != NULL) + { + // Extension indicator + liblte_value_2_bits(0, ie_ptr, 1); + + liblte_value_2_bits(ul_ant_info->ul_tx_mode, ie_ptr, 3); + liblte_value_2_bits(ul_ant_info->four_ant_port_activated, ie_ptr, 1); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_ul_antenna_info_ie(uint8 **ie_ptr, + LIBLTE_RRC_UL_ANTENNA_INFO_STRUCT *ul_ant_info) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + ul_ant_info != NULL) + { + // Extension indicator + bool ext = liblte_bits_2_value(ie_ptr, 1); + + ul_ant_info->ul_tx_mode = (LIBLTE_RRC_UL_TRANSMISSION_MODE_R10_ENUM)liblte_bits_2_value(ie_ptr, 3); + ul_ant_info->four_ant_port_activated = liblte_bits_2_value(ie_ptr, 1); + + liblte_rrc_consume_noncrit_extension(ext, __func__, ie_ptr); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: Uplink Power Control + + Description: Specifies the parameters for uplink power control in + the system information and in the dedicated + signalling + + Document Reference: 36.331 v10.0.0 Section 6.3.2 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_ul_power_control_common_ie(LIBLTE_RRC_UL_POWER_CONTROL_COMMON_STRUCT *ul_pwr_ctrl, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ul_pwr_ctrl != NULL && + ie_ptr != NULL) + { + liblte_value_2_bits(ul_pwr_ctrl->p0_nominal_pusch + 126, ie_ptr, 8); + liblte_value_2_bits(ul_pwr_ctrl->alpha, ie_ptr, 3); + liblte_value_2_bits(ul_pwr_ctrl->p0_nominal_pucch + 127, ie_ptr, 5); + + // Delta F List + liblte_value_2_bits(ul_pwr_ctrl->delta_flist_pucch.format_1, ie_ptr, 2); + liblte_value_2_bits(ul_pwr_ctrl->delta_flist_pucch.format_1b, ie_ptr, 2); + liblte_value_2_bits(ul_pwr_ctrl->delta_flist_pucch.format_2, ie_ptr, 2); + liblte_value_2_bits(ul_pwr_ctrl->delta_flist_pucch.format_2a, ie_ptr, 2); + liblte_value_2_bits(ul_pwr_ctrl->delta_flist_pucch.format_2b, ie_ptr, 2); + + liblte_value_2_bits((ul_pwr_ctrl->delta_preamble_msg3 / 2) + 1, ie_ptr, 3); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_ul_power_control_common_ie(uint8 **ie_ptr, + LIBLTE_RRC_UL_POWER_CONTROL_COMMON_STRUCT *ul_pwr_ctrl) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + ul_pwr_ctrl != NULL) + { + ul_pwr_ctrl->p0_nominal_pusch = liblte_bits_2_value(ie_ptr, 8) - 126; + ul_pwr_ctrl->alpha = (LIBLTE_RRC_UL_POWER_CONTROL_ALPHA_ENUM)liblte_bits_2_value(ie_ptr, 3); + ul_pwr_ctrl->p0_nominal_pucch = liblte_bits_2_value(ie_ptr, 5) - 127; + + // Delta F List + ul_pwr_ctrl->delta_flist_pucch.format_1 = (LIBLTE_RRC_DELTA_F_PUCCH_FORMAT_1_ENUM)liblte_bits_2_value(ie_ptr, 2); + ul_pwr_ctrl->delta_flist_pucch.format_1b = (LIBLTE_RRC_DELTA_F_PUCCH_FORMAT_1B_ENUM)liblte_bits_2_value(ie_ptr, 2); + ul_pwr_ctrl->delta_flist_pucch.format_2 = (LIBLTE_RRC_DELTA_F_PUCCH_FORMAT_2_ENUM)liblte_bits_2_value(ie_ptr, 2); + ul_pwr_ctrl->delta_flist_pucch.format_2a = (LIBLTE_RRC_DELTA_F_PUCCH_FORMAT_2A_ENUM)liblte_bits_2_value(ie_ptr, 2); + ul_pwr_ctrl->delta_flist_pucch.format_2b = (LIBLTE_RRC_DELTA_F_PUCCH_FORMAT_2B_ENUM)liblte_bits_2_value(ie_ptr, 2); + + ul_pwr_ctrl->delta_preamble_msg3 = (liblte_bits_2_value(ie_ptr, 3) - 1) * 2; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_pack_ul_power_control_dedicated_ie(LIBLTE_RRC_UL_POWER_CONTROL_DEDICATED_STRUCT *ul_pwr_ctrl, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ul_pwr_ctrl != NULL && + ie_ptr != NULL) + { + // Filter Coefficient default? + liblte_value_2_bits(ul_pwr_ctrl->filter_coeff_present, ie_ptr, 1); + + // P0 UE PUSCH + liblte_value_2_bits(ul_pwr_ctrl->p0_ue_pusch + 8, ie_ptr, 4); + + // Delta MCS Enabled + liblte_value_2_bits(ul_pwr_ctrl->delta_mcs_en, ie_ptr, 1); + + // Accumulation Enabled + liblte_value_2_bits(ul_pwr_ctrl->accumulation_en, ie_ptr, 1); + + // P0 UE PUCCH + liblte_value_2_bits(ul_pwr_ctrl->p0_ue_pucch + 8, ie_ptr, 4); + + // P SRS Offset + liblte_value_2_bits(ul_pwr_ctrl->p_srs_offset, ie_ptr, 4); + + // Filter Coefficient + if(ul_pwr_ctrl->filter_coeff_present) + { + liblte_rrc_pack_filter_coefficient_ie(ul_pwr_ctrl->filter_coeff, ie_ptr); + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_ul_power_control_dedicated_ie(uint8 **ie_ptr, + LIBLTE_RRC_UL_POWER_CONTROL_DEDICATED_STRUCT *ul_pwr_ctrl) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + ul_pwr_ctrl != NULL) + { + // Filter Coefficient default? + ul_pwr_ctrl->filter_coeff_present = liblte_bits_2_value(ie_ptr, 1); + + // P0 UE PUSCH + ul_pwr_ctrl->p0_ue_pusch = liblte_bits_2_value(ie_ptr, 4) - 8; + + // Delta MCS Enabled + ul_pwr_ctrl->delta_mcs_en = (LIBLTE_RRC_DELTA_MCS_ENABLED_ENUM)liblte_bits_2_value(ie_ptr, 1); + + // Accumulation Enabled + ul_pwr_ctrl->accumulation_en = liblte_bits_2_value(ie_ptr, 1); + + // P0 UE PUCCH + ul_pwr_ctrl->p0_ue_pucch = liblte_bits_2_value(ie_ptr, 4) - 8; + + // P SRS Offset + ul_pwr_ctrl->p_srs_offset = liblte_bits_2_value(ie_ptr, 4); + + // Filter Coefficient + if(ul_pwr_ctrl->filter_coeff_present) + { + liblte_rrc_unpack_filter_coefficient_ie(ie_ptr, &ul_pwr_ctrl->filter_coeff); + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: System Information Block Type 2 + + Description: Contains radio resource configuration that is common + for all UEs + + Document Reference: 36.331 v10.0.0 Section 6.3.1 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_sys_info_block_type_2_ie(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT *sib2, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint32 i; + bool mbsfn_subfr_cnfg_list_opt; + + if(sib2 != NULL && + ie_ptr != NULL) + { + // Extension indicator + liblte_value_2_bits(0, ie_ptr, 1); + + // Optional indicators + liblte_value_2_bits(sib2->ac_barring_info_present, ie_ptr, 1); + if(0 != sib2->mbsfn_subfr_cnfg_list_size) + { + liblte_value_2_bits(1, ie_ptr, 1); + mbsfn_subfr_cnfg_list_opt = true; + }else{ + liblte_value_2_bits(0, ie_ptr, 1); + mbsfn_subfr_cnfg_list_opt = false; + } + + // AC Barring + if(true == sib2->ac_barring_info_present) + { + liblte_value_2_bits(sib2->ac_barring_for_mo_signalling.enabled, ie_ptr, 1); + liblte_value_2_bits(sib2->ac_barring_for_mo_data.enabled, ie_ptr, 1); + + // AC Barring for emergency + liblte_value_2_bits(sib2->ac_barring_for_emergency, ie_ptr, 1); + + // AC Barring for MO signalling + if(true == sib2->ac_barring_for_mo_signalling.enabled) + { + liblte_value_2_bits(sib2->ac_barring_for_mo_signalling.factor, ie_ptr, 4); + liblte_value_2_bits(sib2->ac_barring_for_mo_signalling.time, ie_ptr, 3); + liblte_value_2_bits(sib2->ac_barring_for_mo_signalling.for_special_ac, ie_ptr, 5); + } + + // AC Barring for MO data + if(true == sib2->ac_barring_for_mo_data.enabled) + { + liblte_value_2_bits(sib2->ac_barring_for_mo_data.factor, ie_ptr, 4); + liblte_value_2_bits(sib2->ac_barring_for_mo_data.time, ie_ptr, 3); + liblte_value_2_bits(sib2->ac_barring_for_mo_data.for_special_ac, ie_ptr, 5); + } + } + + // Radio Resource Config Common + liblte_rrc_pack_rr_config_common_sib_ie(&sib2->rr_config_common_sib, ie_ptr); + + // UE Timers and Constants + liblte_rrc_pack_ue_timers_and_constants_ie(&sib2->ue_timers_and_constants, ie_ptr); + + // Frequency information + { + // Optional indicators + liblte_value_2_bits(sib2->arfcn_value_eutra.present, ie_ptr, 1); + liblte_value_2_bits(sib2->ul_bw.present, ie_ptr, 1); + + // UL Carrier Frequency + if(true == sib2->arfcn_value_eutra.present) + { + liblte_rrc_pack_arfcn_value_eutra_ie(sib2->arfcn_value_eutra.value, ie_ptr); + } + + // UL Bandwidth + if(true == sib2->ul_bw.present) + { + liblte_value_2_bits(sib2->ul_bw.bw, ie_ptr, 3); + } + + // Additional Spectrum Emission + liblte_rrc_pack_additional_spectrum_emission_ie(sib2->additional_spectrum_emission, + ie_ptr); + } + + // MBSFN Subframe Config List + if(true == mbsfn_subfr_cnfg_list_opt) + { + liblte_value_2_bits(sib2->mbsfn_subfr_cnfg_list_size - 1, ie_ptr, 3); + for(i=0; imbsfn_subfr_cnfg_list_size; i++) + { + liblte_rrc_pack_mbsfn_subframe_config_ie(&sib2->mbsfn_subfr_cnfg[i], ie_ptr); + } + } + + // Time Alignment Timer Common + liblte_rrc_pack_time_alignment_timer_ie(sib2->time_alignment_timer, ie_ptr); + + // FIXME: Not handling extensions + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_sys_info_block_type_2_ie(uint8 **ie_ptr, + LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT *sib2) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint32 i; + uint8 ext_ind; + bool mbsfn_subfr_cnfg_list_opt; + + if(ie_ptr != NULL && + sib2 != NULL) + { + // Extension indicator + ext_ind = liblte_bits_2_value(ie_ptr, 1); + + // Optional indicators + sib2->ac_barring_info_present = liblte_bits_2_value(ie_ptr, 1); + mbsfn_subfr_cnfg_list_opt = liblte_bits_2_value(ie_ptr, 1); + + // AC Barring + if(true == sib2->ac_barring_info_present) + { + // Optional indicators + sib2->ac_barring_for_mo_signalling.enabled = liblte_bits_2_value(ie_ptr, 1); + sib2->ac_barring_for_mo_data.enabled = liblte_bits_2_value(ie_ptr, 1); + + // AC Barring for emergency + sib2->ac_barring_for_emergency = liblte_bits_2_value(ie_ptr, 1); + + // AC Barring for MO signalling + if(true == sib2->ac_barring_for_mo_signalling.enabled) + { + sib2->ac_barring_for_mo_signalling.factor = (LIBLTE_RRC_AC_BARRING_FACTOR_ENUM)liblte_bits_2_value(ie_ptr, 4); + sib2->ac_barring_for_mo_signalling.time = (LIBLTE_RRC_AC_BARRING_TIME_ENUM)liblte_bits_2_value(ie_ptr, 3); + sib2->ac_barring_for_mo_signalling.for_special_ac = liblte_bits_2_value(ie_ptr, 5); + } + + // AC Barring for MO data + if(true == sib2->ac_barring_for_mo_data.enabled) + { + sib2->ac_barring_for_mo_data.factor = (LIBLTE_RRC_AC_BARRING_FACTOR_ENUM)liblte_bits_2_value(ie_ptr, 4); + sib2->ac_barring_for_mo_data.time = (LIBLTE_RRC_AC_BARRING_TIME_ENUM)liblte_bits_2_value(ie_ptr, 3); + sib2->ac_barring_for_mo_data.for_special_ac = liblte_bits_2_value(ie_ptr, 5); + } + }else{ + sib2->ac_barring_for_emergency = false; + sib2->ac_barring_for_mo_signalling.enabled = false; + sib2->ac_barring_for_mo_data.enabled = false; + } + + // Radio Resource Config Common + liblte_rrc_unpack_rr_config_common_sib_ie(ie_ptr, &sib2->rr_config_common_sib); + + // UE Timers and Constants + liblte_rrc_unpack_ue_timers_and_constants_ie(ie_ptr, &sib2->ue_timers_and_constants); + + // Frequency information + { + // Optional indicators + sib2->arfcn_value_eutra.present = liblte_bits_2_value(ie_ptr, 1); + sib2->ul_bw.present = liblte_bits_2_value(ie_ptr, 1); + + // UL Carrier Frequency + if(true == sib2->arfcn_value_eutra.present) + { + liblte_rrc_unpack_arfcn_value_eutra_ie(ie_ptr, &sib2->arfcn_value_eutra.value); + } + + // UL Bandwidth + if(true == sib2->ul_bw.present) + { + sib2->ul_bw.bw = (LIBLTE_RRC_UL_BW_ENUM)liblte_bits_2_value(ie_ptr, 3); + } + + // Additional Spectrum Emission + liblte_rrc_unpack_additional_spectrum_emission_ie(ie_ptr, + &sib2->additional_spectrum_emission); + } + + // MBSFN Subframe Config List + if(true == mbsfn_subfr_cnfg_list_opt) + { + sib2->mbsfn_subfr_cnfg_list_size = liblte_bits_2_value(ie_ptr, 3) + 1; + for(i=0; imbsfn_subfr_cnfg_list_size; i++) + { + liblte_rrc_unpack_mbsfn_subframe_config_ie(ie_ptr, &sib2->mbsfn_subfr_cnfg[i]); + } + }else{ + sib2->mbsfn_subfr_cnfg_list_size = 0; + } + + // Time Alignment Timer Common + liblte_rrc_unpack_time_alignment_timer_ie(ie_ptr, &sib2->time_alignment_timer); + + // Extensions + liblte_rrc_consume_noncrit_extension(ext_ind, __func__, ie_ptr); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: System Information Block Type 3 + + Description: Contains cell reselection information common for + intra-frequency, inter-frequency, and/or inter-RAT + cell re-selection as well as intra-frequency cell + re-selection information other than neighboring + cell related + + Document Reference: 36.331 v10.0.0 Section 6.3.1 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_sys_info_block_type_3_ie(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_3_STRUCT *sib3, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(sib3 != NULL && + ie_ptr != NULL) + { + // Extension indicator + liblte_value_2_bits(0, ie_ptr, 1); + + // Cell reselection info common + { + // Optional indicator + liblte_value_2_bits(sib3->speed_state_resel_params.present, ie_ptr, 1); + + liblte_value_2_bits(sib3->q_hyst, ie_ptr, 4); + + // Speed state reselection parameters + if(true == sib3->speed_state_resel_params.present) + { + liblte_rrc_pack_mobility_state_parameters_ie(&sib3->speed_state_resel_params.mobility_state_params, ie_ptr); + + liblte_value_2_bits(sib3->speed_state_resel_params.q_hyst_sf.medium, ie_ptr, 2); + liblte_value_2_bits(sib3->speed_state_resel_params.q_hyst_sf.high, ie_ptr, 2); + } + } + + // Cell reselection serving frequency information + { + // Optional indicators + liblte_value_2_bits(sib3->s_non_intra_search_present, ie_ptr, 1); + + if(true == sib3->s_non_intra_search_present) + { + liblte_rrc_pack_reselection_threshold_ie(sib3->s_non_intra_search, ie_ptr); + } + + liblte_rrc_pack_reselection_threshold_ie(sib3->thresh_serving_low, ie_ptr); + + liblte_rrc_pack_cell_reselection_priority_ie(sib3->cell_resel_prio, ie_ptr); + } + + // Intra frequency cell reselection information + { + // Optional indicators + liblte_value_2_bits(sib3->p_max_present, ie_ptr, 1); + liblte_value_2_bits(sib3->s_intra_search_present, ie_ptr, 1); + liblte_value_2_bits(sib3->allowed_meas_bw_present, ie_ptr, 1); + liblte_value_2_bits(sib3->t_resel_eutra_sf_present, ie_ptr, 1); + + liblte_rrc_pack_q_rx_lev_min_ie(sib3->q_rx_lev_min, ie_ptr); + + if(true == sib3->p_max_present) + { + liblte_rrc_pack_p_max_ie(sib3->p_max, ie_ptr); + } + + if(true == sib3->s_intra_search_present) + { + liblte_rrc_pack_reselection_threshold_ie(sib3->s_intra_search, ie_ptr); + } + + if(true == sib3->allowed_meas_bw_present) + { + liblte_rrc_pack_allowed_meas_bandwidth_ie(sib3->allowed_meas_bw, ie_ptr); + } + + liblte_rrc_pack_presence_antenna_port_1_ie(sib3->presence_ant_port_1, ie_ptr); + + liblte_rrc_pack_neigh_cell_config_ie(sib3->neigh_cell_cnfg, ie_ptr); + + liblte_rrc_pack_t_reselection_ie(sib3->t_resel_eutra, ie_ptr); + + if(true == sib3->t_resel_eutra_sf_present) + { + liblte_rrc_pack_speed_state_scale_factors_ie(&sib3->t_resel_eutra_sf, ie_ptr); + } + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_sys_info_block_type_3_ie(uint8 **ie_ptr, + LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_3_STRUCT *sib3) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + bool ext_ind; + + if(ie_ptr != NULL && + sib3 != NULL) + { + // Extension indicator + ext_ind = liblte_bits_2_value(ie_ptr, 1); + + // Cell reselection info common + { + // Optional indicator + sib3->speed_state_resel_params.present = liblte_bits_2_value(ie_ptr, 1); + + sib3->q_hyst = (LIBLTE_RRC_Q_HYST_ENUM)liblte_bits_2_value(ie_ptr, 4); + + // Speed state reselection parameters + if(true == sib3->speed_state_resel_params.present) + { + liblte_rrc_unpack_mobility_state_parameters_ie(ie_ptr, &sib3->speed_state_resel_params.mobility_state_params); + + sib3->speed_state_resel_params.q_hyst_sf.medium = (LIBLTE_RRC_SF_MEDIUM_ENUM)liblte_bits_2_value(ie_ptr, 2); + sib3->speed_state_resel_params.q_hyst_sf.high = (LIBLTE_RRC_SF_HIGH_ENUM)liblte_bits_2_value(ie_ptr, 2); + } + } + + // Cell reselection serving frequency information + { + // Optional indicators + sib3->s_non_intra_search_present = liblte_bits_2_value(ie_ptr, 1); + + if(true == sib3->s_non_intra_search_present) + { + liblte_rrc_unpack_reselection_threshold_ie(ie_ptr, &sib3->s_non_intra_search); + } + + liblte_rrc_unpack_reselection_threshold_ie(ie_ptr, &sib3->thresh_serving_low); + + liblte_rrc_unpack_cell_reselection_priority_ie(ie_ptr, &sib3->cell_resel_prio); + } + + // Intra frequency cell reselection information + { + // Optional indicators + sib3->p_max_present = liblte_bits_2_value(ie_ptr, 1); + sib3->s_intra_search_present = liblte_bits_2_value(ie_ptr, 1); + sib3->allowed_meas_bw_present = liblte_bits_2_value(ie_ptr, 1); + sib3->t_resel_eutra_sf_present = liblte_bits_2_value(ie_ptr, 1); + + liblte_rrc_unpack_q_rx_lev_min_ie(ie_ptr, &sib3->q_rx_lev_min); + + if(true == sib3->p_max_present) + { + liblte_rrc_unpack_p_max_ie(ie_ptr, &sib3->p_max); + } + + if(true == sib3->s_intra_search_present) + { + liblte_rrc_unpack_reselection_threshold_ie(ie_ptr, &sib3->s_intra_search); + } + + if(true == sib3->allowed_meas_bw_present) + { + liblte_rrc_unpack_allowed_meas_bandwidth_ie(ie_ptr, &sib3->allowed_meas_bw); + } + + liblte_rrc_unpack_presence_antenna_port_1_ie(ie_ptr, &sib3->presence_ant_port_1); + + liblte_rrc_unpack_neigh_cell_config_ie(ie_ptr, &sib3->neigh_cell_cnfg); + + liblte_rrc_unpack_t_reselection_ie(ie_ptr, &sib3->t_resel_eutra); + + if(true == sib3->t_resel_eutra_sf_present) + { + liblte_rrc_unpack_speed_state_scale_factors_ie(ie_ptr, &sib3->t_resel_eutra_sf); + } + } + + // Extensions + liblte_rrc_consume_noncrit_extension(ext_ind, __func__, ie_ptr); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: System Information Block Type 4 + + Description: Contains the neighboring cell related information + relevant only for intra-frequency cell reselection + + Document Reference: 36.331 v10.0.0 Section 6.3.1 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_sys_info_block_type_4_ie(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_4_STRUCT *sib4, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint32 i; + + if(sib4 != NULL && + ie_ptr != NULL) + { + // Extension indicator + liblte_value_2_bits(0, ie_ptr, 1); + + // Optional indicators + if(0 != sib4->intra_freq_neigh_cell_list_size) + { + liblte_value_2_bits(1, ie_ptr, 1); + }else{ + liblte_value_2_bits(0, ie_ptr, 1); + } + if(0 != sib4->intra_freq_black_cell_list_size) + { + liblte_value_2_bits(1, ie_ptr, 1); + }else{ + liblte_value_2_bits(0, ie_ptr, 1); + } + liblte_value_2_bits(sib4->csg_phys_cell_id_range_present, ie_ptr, 1); + + if(0 != sib4->intra_freq_neigh_cell_list_size) + { + liblte_value_2_bits(sib4->intra_freq_neigh_cell_list_size - 1, ie_ptr, 4); + for(i=0; iintra_freq_neigh_cell_list_size; i++) + { + // Extension indicator + liblte_value_2_bits(0, ie_ptr, 1); + + liblte_rrc_pack_phys_cell_id_ie(sib4->intra_freq_neigh_cell_list[i].phys_cell_id, ie_ptr); + liblte_rrc_pack_q_offset_range_ie(sib4->intra_freq_neigh_cell_list[i].q_offset_range, ie_ptr); + } + } + + if(0 != sib4->intra_freq_black_cell_list_size) + { + liblte_value_2_bits(sib4->intra_freq_black_cell_list_size - 1, ie_ptr, 4); + for(i=0; iintra_freq_black_cell_list_size; i++) + { + liblte_rrc_pack_phys_cell_id_range_ie(&sib4->intra_freq_black_cell_list[i], ie_ptr); + } + } + + if(true == sib4->csg_phys_cell_id_range_present) + { + liblte_rrc_pack_phys_cell_id_range_ie(&sib4->csg_phys_cell_id_range, ie_ptr); + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_sys_info_block_type_4_ie(uint8 **ie_ptr, + LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_4_STRUCT *sib4) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint32 i; + bool ext_ind; + bool intra_freq_neigh_cell_list_opt; + bool intra_freq_black_cell_list_opt; + + if(ie_ptr != NULL && + sib4 != NULL) + { + // Extension indicator + ext_ind = liblte_bits_2_value(ie_ptr, 1); + + // Optional indicators + intra_freq_neigh_cell_list_opt = liblte_bits_2_value(ie_ptr, 1); + intra_freq_black_cell_list_opt = liblte_bits_2_value(ie_ptr, 1); + sib4->csg_phys_cell_id_range_present = liblte_bits_2_value(ie_ptr, 1); + + if(true == intra_freq_neigh_cell_list_opt) + { + sib4->intra_freq_neigh_cell_list_size = liblte_bits_2_value(ie_ptr, 4) + 1; + for(i=0; iintra_freq_neigh_cell_list_size; i++) + { + // Extension indicator + liblte_bits_2_value(ie_ptr, 1); + + liblte_rrc_unpack_phys_cell_id_ie(ie_ptr, &sib4->intra_freq_neigh_cell_list[i].phys_cell_id); + liblte_rrc_unpack_q_offset_range_ie(ie_ptr, &sib4->intra_freq_neigh_cell_list[i].q_offset_range); + } + }else{ + sib4->intra_freq_neigh_cell_list_size = 0; + } + + if(true == intra_freq_black_cell_list_opt) + { + sib4->intra_freq_black_cell_list_size = liblte_bits_2_value(ie_ptr, 4) + 1; + for(i=0; iintra_freq_black_cell_list_size; i++) + { + liblte_rrc_unpack_phys_cell_id_range_ie(ie_ptr, &sib4->intra_freq_black_cell_list[i]); + } + }else{ + sib4->intra_freq_black_cell_list_size = 0; + } + + if(true == sib4->csg_phys_cell_id_range_present) + { + liblte_rrc_unpack_phys_cell_id_range_ie(ie_ptr, &sib4->csg_phys_cell_id_range); + } + + // Extension + liblte_rrc_consume_noncrit_extension(ext_ind, __func__, ie_ptr); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: System Information Block Type 5 + + Description: Contains information relevant only for + inter-frequency cell reselection, i.e. information + about other E-UTRA frequencies and inter-frequency + neighboring cells relevant for cell reselection + + Document Reference: 36.331 v10.0.0 Section 6.3.1 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_sys_info_block_type_5_ie(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_5_STRUCT *sib5, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint32 i; + uint32 j; + + if(sib5 != NULL && + ie_ptr != NULL) + { + // Extension indicator + liblte_value_2_bits(0, ie_ptr, 1); + + liblte_value_2_bits(sib5->inter_freq_carrier_freq_list_size - 1, ie_ptr, 3); + for(i=0; iinter_freq_carrier_freq_list_size; i++) + { + // Extension indicator + liblte_value_2_bits(0, ie_ptr, 1); + + // Optional indicators + liblte_value_2_bits(sib5->inter_freq_carrier_freq_list[i].p_max_present, ie_ptr, 1); + liblte_value_2_bits(sib5->inter_freq_carrier_freq_list[i].t_resel_eutra_sf_present, ie_ptr, 1); + liblte_value_2_bits(sib5->inter_freq_carrier_freq_list[i].cell_resel_prio_present, ie_ptr, 1); + if(0 != sib5->inter_freq_carrier_freq_list[i].inter_freq_neigh_cell_list_size) + { + liblte_value_2_bits(1, ie_ptr, 1); + }else{ + liblte_value_2_bits(0, ie_ptr, 1); + } + if(0 != sib5->inter_freq_carrier_freq_list[i].inter_freq_black_cell_list_size) + { + liblte_value_2_bits(1, ie_ptr, 1); + }else{ + liblte_value_2_bits(0, ie_ptr, 1); + } + + liblte_rrc_pack_arfcn_value_eutra_ie(sib5->inter_freq_carrier_freq_list[i].dl_carrier_freq, ie_ptr); + liblte_rrc_pack_q_rx_lev_min_ie(sib5->inter_freq_carrier_freq_list[i].q_rx_lev_min, ie_ptr); + if(true == sib5->inter_freq_carrier_freq_list[i].p_max_present) + { + liblte_rrc_pack_p_max_ie(sib5->inter_freq_carrier_freq_list[i].p_max, ie_ptr); + } + liblte_rrc_pack_t_reselection_ie(sib5->inter_freq_carrier_freq_list[i].t_resel_eutra, ie_ptr); + if(true == sib5->inter_freq_carrier_freq_list[i].t_resel_eutra_sf_present) + { + liblte_rrc_pack_speed_state_scale_factors_ie(&sib5->inter_freq_carrier_freq_list[i].t_resel_eutra_sf, ie_ptr); + } + liblte_rrc_pack_reselection_threshold_ie(sib5->inter_freq_carrier_freq_list[i].threshx_high, ie_ptr); + liblte_rrc_pack_reselection_threshold_ie(sib5->inter_freq_carrier_freq_list[i].threshx_low, ie_ptr); + liblte_rrc_pack_allowed_meas_bandwidth_ie(sib5->inter_freq_carrier_freq_list[i].allowed_meas_bw, ie_ptr); + liblte_rrc_pack_presence_antenna_port_1_ie(sib5->inter_freq_carrier_freq_list[i].presence_ant_port_1, ie_ptr); + if(true == sib5->inter_freq_carrier_freq_list[i].cell_resel_prio_present) + { + liblte_rrc_pack_cell_reselection_priority_ie(sib5->inter_freq_carrier_freq_list[i].cell_resel_prio, ie_ptr); + } + liblte_rrc_pack_neigh_cell_config_ie(sib5->inter_freq_carrier_freq_list[i].neigh_cell_cnfg, ie_ptr); + liblte_rrc_pack_q_offset_range_ie(sib5->inter_freq_carrier_freq_list[i].q_offset_freq, ie_ptr); + if(0 != sib5->inter_freq_carrier_freq_list[i].inter_freq_neigh_cell_list_size) + { + liblte_value_2_bits(sib5->inter_freq_carrier_freq_list[i].inter_freq_neigh_cell_list_size - 1, ie_ptr, 4); + for(j=0; jinter_freq_carrier_freq_list[i].inter_freq_neigh_cell_list_size; j++) + { + liblte_rrc_pack_phys_cell_id_ie(sib5->inter_freq_carrier_freq_list[i].inter_freq_neigh_cell_list[j].phys_cell_id, ie_ptr); + liblte_rrc_pack_q_offset_range_ie(sib5->inter_freq_carrier_freq_list[i].inter_freq_neigh_cell_list[j].q_offset_cell, ie_ptr); + } + } + if(0 != sib5->inter_freq_carrier_freq_list[i].inter_freq_black_cell_list_size) + { + liblte_value_2_bits(sib5->inter_freq_carrier_freq_list[i].inter_freq_black_cell_list_size - 1, ie_ptr, 4); + for(j=0; jinter_freq_carrier_freq_list[i].inter_freq_black_cell_list_size; j++) + { + liblte_rrc_pack_phys_cell_id_range_ie(&sib5->inter_freq_carrier_freq_list[i].inter_freq_black_cell_list[j], ie_ptr); + } + } + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_sys_info_block_type_5_ie(uint8 **ie_ptr, + LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_5_STRUCT *sib5) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint32 i; + uint32 j; + bool ext_ind; + bool inter_freq_carrier_freq_list_ext_ind; + bool q_offset_freq_opt; + bool inter_freq_neigh_cell_list_opt; + bool inter_freq_black_cell_list_opt; + + if(ie_ptr != NULL && + sib5 != NULL) + { + // Extension indicator + ext_ind = liblte_bits_2_value(ie_ptr, 1); + + sib5->inter_freq_carrier_freq_list_size = liblte_bits_2_value(ie_ptr, 3) + 1; + for(i=0; iinter_freq_carrier_freq_list_size; i++) + { + // Extension indicator + inter_freq_carrier_freq_list_ext_ind = liblte_bits_2_value(ie_ptr, 1); + + // Optional indicators + sib5->inter_freq_carrier_freq_list[i].p_max_present = liblte_bits_2_value(ie_ptr, 1); + sib5->inter_freq_carrier_freq_list[i].t_resel_eutra_sf_present = liblte_bits_2_value(ie_ptr, 1); + sib5->inter_freq_carrier_freq_list[i].cell_resel_prio_present = liblte_bits_2_value(ie_ptr, 1); + q_offset_freq_opt = liblte_bits_2_value(ie_ptr, 1); + inter_freq_neigh_cell_list_opt = liblte_bits_2_value(ie_ptr, 1); + inter_freq_black_cell_list_opt = liblte_bits_2_value(ie_ptr, 1); + + liblte_rrc_unpack_arfcn_value_eutra_ie(ie_ptr, &sib5->inter_freq_carrier_freq_list[i].dl_carrier_freq); + liblte_rrc_unpack_q_rx_lev_min_ie(ie_ptr, &sib5->inter_freq_carrier_freq_list[i].q_rx_lev_min); + if(true == sib5->inter_freq_carrier_freq_list[i].p_max_present) + { + liblte_rrc_unpack_p_max_ie(ie_ptr, &sib5->inter_freq_carrier_freq_list[i].p_max); + } + liblte_rrc_unpack_t_reselection_ie(ie_ptr, &sib5->inter_freq_carrier_freq_list[i].t_resel_eutra); + if(true == sib5->inter_freq_carrier_freq_list[i].t_resel_eutra_sf_present) + { + liblte_rrc_unpack_speed_state_scale_factors_ie(ie_ptr, &sib5->inter_freq_carrier_freq_list[i].t_resel_eutra_sf); + } + liblte_rrc_unpack_reselection_threshold_ie(ie_ptr, &sib5->inter_freq_carrier_freq_list[i].threshx_high); + liblte_rrc_unpack_reselection_threshold_ie(ie_ptr, &sib5->inter_freq_carrier_freq_list[i].threshx_low); + liblte_rrc_unpack_allowed_meas_bandwidth_ie(ie_ptr, &sib5->inter_freq_carrier_freq_list[i].allowed_meas_bw); + liblte_rrc_unpack_presence_antenna_port_1_ie(ie_ptr, &sib5->inter_freq_carrier_freq_list[i].presence_ant_port_1); + if(true == sib5->inter_freq_carrier_freq_list[i].cell_resel_prio_present) + { + liblte_rrc_unpack_cell_reselection_priority_ie(ie_ptr, &sib5->inter_freq_carrier_freq_list[i].cell_resel_prio); + } + liblte_rrc_unpack_neigh_cell_config_ie(ie_ptr, &sib5->inter_freq_carrier_freq_list[i].neigh_cell_cnfg); + if(true == q_offset_freq_opt) + { + liblte_rrc_unpack_q_offset_range_ie(ie_ptr, &sib5->inter_freq_carrier_freq_list[i].q_offset_freq); + }else{ + sib5->inter_freq_carrier_freq_list[i].q_offset_freq = LIBLTE_RRC_Q_OFFSET_RANGE_DB_0; + } + if(true == inter_freq_neigh_cell_list_opt) + { + sib5->inter_freq_carrier_freq_list[i].inter_freq_neigh_cell_list_size = liblte_bits_2_value(ie_ptr, 4) + 1; + for(j=0; jinter_freq_carrier_freq_list[i].inter_freq_neigh_cell_list_size; j++) + { + liblte_rrc_unpack_phys_cell_id_ie(ie_ptr, &sib5->inter_freq_carrier_freq_list[i].inter_freq_neigh_cell_list[j].phys_cell_id); + liblte_rrc_unpack_q_offset_range_ie(ie_ptr, &sib5->inter_freq_carrier_freq_list[i].inter_freq_neigh_cell_list[j].q_offset_cell); + } + }else{ + sib5->inter_freq_carrier_freq_list[i].inter_freq_neigh_cell_list_size = 0; + } + if(true == inter_freq_black_cell_list_opt) + { + sib5->inter_freq_carrier_freq_list[i].inter_freq_black_cell_list_size = liblte_bits_2_value(ie_ptr, 4) + 1; + for(j=0; jinter_freq_carrier_freq_list[i].inter_freq_black_cell_list_size; j++) + { + liblte_rrc_unpack_phys_cell_id_range_ie(ie_ptr, &sib5->inter_freq_carrier_freq_list[i].inter_freq_black_cell_list[j]); + } + }else{ + sib5->inter_freq_carrier_freq_list[i].inter_freq_black_cell_list_size = 0; + } + } + + liblte_rrc_consume_noncrit_extension(ext_ind, __func__, ie_ptr); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: System Information Block Type 6 + + Description: Contains information relevant only for inter-RAT + cell reselection, i.e. information about UTRA + frequencies and UTRA neighboring cells relevant for + cell reselection + + Document Reference: 36.331 v10.0.0 Section 6.3.1 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_sys_info_block_type_6_ie(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_6_STRUCT *sib6, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint32 i; + + if(sib6 != NULL && + ie_ptr != NULL) + { + // Extension indicator + liblte_value_2_bits(0, ie_ptr, 1); + + // Optional indicators + if(0 != sib6->carrier_freq_list_utra_fdd_size) + { + liblte_value_2_bits(1, ie_ptr, 1); + }else{ + liblte_value_2_bits(0, ie_ptr, 1); + } + if(0 != sib6->carrier_freq_list_utra_tdd_size) + { + liblte_value_2_bits(1, ie_ptr, 1); + }else{ + liblte_value_2_bits(0, ie_ptr, 1); + } + liblte_value_2_bits(sib6->t_resel_utra_sf_present, ie_ptr, 1); + + if(0 != sib6->carrier_freq_list_utra_fdd_size) + { + liblte_value_2_bits(sib6->carrier_freq_list_utra_fdd_size - 1, ie_ptr, 4); + for(i=0; icarrier_freq_list_utra_fdd_size; i++) + { + // Extension indicator + liblte_value_2_bits(0, ie_ptr, 1); + + // Optional indicator + liblte_value_2_bits(sib6->carrier_freq_list_utra_fdd[i].cell_resel_prio_present, ie_ptr, 1); + + liblte_rrc_pack_arfcn_value_utra_ie(sib6->carrier_freq_list_utra_fdd[i].carrier_freq, ie_ptr); + if(true == sib6->carrier_freq_list_utra_fdd[i].cell_resel_prio_present) + { + liblte_rrc_pack_cell_reselection_priority_ie(sib6->carrier_freq_list_utra_fdd[i].cell_resel_prio, ie_ptr); + } + liblte_rrc_pack_reselection_threshold_ie(sib6->carrier_freq_list_utra_fdd[i].threshx_high, ie_ptr); + liblte_rrc_pack_reselection_threshold_ie(sib6->carrier_freq_list_utra_fdd[i].threshx_low, ie_ptr); + liblte_value_2_bits(((sib6->carrier_freq_list_utra_fdd[i].q_rx_lev_min - 1) / 2) + 60, ie_ptr, 6); + liblte_value_2_bits(sib6->carrier_freq_list_utra_fdd[i].p_max_utra + 50, ie_ptr, 7); + liblte_value_2_bits(sib6->carrier_freq_list_utra_fdd[i].q_qual_min + 24, ie_ptr, 5); + } + } + if(0 != sib6->carrier_freq_list_utra_tdd_size) + { + liblte_value_2_bits(sib6->carrier_freq_list_utra_tdd_size - 1, ie_ptr, 4); + for(i=0; icarrier_freq_list_utra_tdd_size; i++) + { + // Extension indicator + liblte_value_2_bits(0, ie_ptr, 1); + + // Optional indicator + liblte_value_2_bits(sib6->carrier_freq_list_utra_tdd[i].cell_resel_prio_present, ie_ptr, 1); + + liblte_rrc_pack_arfcn_value_utra_ie(sib6->carrier_freq_list_utra_tdd[i].carrier_freq, ie_ptr); + if(true == sib6->carrier_freq_list_utra_tdd[i].cell_resel_prio_present) + { + liblte_rrc_pack_cell_reselection_priority_ie(sib6->carrier_freq_list_utra_tdd[i].cell_resel_prio, ie_ptr); + } + liblte_rrc_pack_reselection_threshold_ie(sib6->carrier_freq_list_utra_tdd[i].threshx_high, ie_ptr); + liblte_rrc_pack_reselection_threshold_ie(sib6->carrier_freq_list_utra_tdd[i].threshx_low, ie_ptr); + liblte_value_2_bits(((sib6->carrier_freq_list_utra_tdd[i].q_rx_lev_min - 1) / 2) + 60, ie_ptr, 6); + liblte_value_2_bits(sib6->carrier_freq_list_utra_tdd[i].p_max_utra + 50, ie_ptr, 7); + } + } + liblte_rrc_pack_t_reselection_ie(sib6->t_resel_utra, ie_ptr); + if(true == sib6->t_resel_utra_sf_present) + { + liblte_rrc_pack_speed_state_scale_factors_ie(&sib6->t_resel_utra_sf, ie_ptr); + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_sys_info_block_type_6_ie(uint8 **ie_ptr, + LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_6_STRUCT *sib6) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint32 i; + bool ext_ind; + bool carrier_freq_list_utra_fdd_opt; + bool carrier_freq_list_utra_fdd_ext_ind; + bool carrier_freq_list_utra_tdd_opt; + bool carrier_freq_list_utra_tdd_ext_ind; + + if(ie_ptr != NULL && + sib6 != NULL) + { + // Extension indicator + ext_ind = liblte_bits_2_value(ie_ptr, 1); + + // Optional indicators + carrier_freq_list_utra_fdd_opt = liblte_bits_2_value(ie_ptr, 1); + carrier_freq_list_utra_tdd_opt = liblte_bits_2_value(ie_ptr, 1); + sib6->t_resel_utra_sf_present = liblte_bits_2_value(ie_ptr, 1); + + if(true == carrier_freq_list_utra_fdd_opt) + { + sib6->carrier_freq_list_utra_fdd_size = liblte_bits_2_value(ie_ptr, 4) + 1; + for(i=0; icarrier_freq_list_utra_fdd_size; i++) + { + // Extension indicator + carrier_freq_list_utra_fdd_ext_ind = liblte_bits_2_value(ie_ptr, 1); + + // Optional indicator + sib6->carrier_freq_list_utra_fdd[i].cell_resel_prio_present = liblte_bits_2_value(ie_ptr, 1); + + liblte_rrc_unpack_arfcn_value_utra_ie(ie_ptr, &sib6->carrier_freq_list_utra_fdd[i].carrier_freq); + if(true == sib6->carrier_freq_list_utra_fdd[i].cell_resel_prio_present) + { + liblte_rrc_unpack_cell_reselection_priority_ie(ie_ptr, &sib6->carrier_freq_list_utra_fdd[i].cell_resel_prio); + } + liblte_rrc_unpack_reselection_threshold_ie(ie_ptr, &sib6->carrier_freq_list_utra_fdd[i].threshx_high); + liblte_rrc_unpack_reselection_threshold_ie(ie_ptr, &sib6->carrier_freq_list_utra_fdd[i].threshx_low); + sib6->carrier_freq_list_utra_fdd[i].q_rx_lev_min = (int8)((liblte_bits_2_value(ie_ptr, 6) - 60) * 2) + 1; + sib6->carrier_freq_list_utra_fdd[i].p_max_utra = (int8)liblte_bits_2_value(ie_ptr, 7) - 50; + sib6->carrier_freq_list_utra_fdd[i].q_qual_min = (int8)liblte_bits_2_value(ie_ptr, 5) - 24; + } + }else{ + sib6->carrier_freq_list_utra_fdd_size = 0; + } + if(true == carrier_freq_list_utra_tdd_opt) + { + sib6->carrier_freq_list_utra_tdd_size = liblte_bits_2_value(ie_ptr, 4) + 1; + for(i=0; icarrier_freq_list_utra_tdd_size; i++) + { + // Extension indicator + carrier_freq_list_utra_tdd_ext_ind = liblte_bits_2_value(ie_ptr, 1); + + // Optional indicator + sib6->carrier_freq_list_utra_tdd[i].cell_resel_prio_present = liblte_bits_2_value(ie_ptr, 1); + + liblte_rrc_unpack_arfcn_value_utra_ie(ie_ptr, &sib6->carrier_freq_list_utra_tdd[i].carrier_freq); + if(true == sib6->carrier_freq_list_utra_tdd[i].cell_resel_prio_present) + { + liblte_rrc_unpack_cell_reselection_priority_ie(ie_ptr, &sib6->carrier_freq_list_utra_tdd[i].cell_resel_prio); + } + liblte_rrc_unpack_reselection_threshold_ie(ie_ptr, &sib6->carrier_freq_list_utra_tdd[i].threshx_high); + liblte_rrc_unpack_reselection_threshold_ie(ie_ptr, &sib6->carrier_freq_list_utra_tdd[i].threshx_low); + sib6->carrier_freq_list_utra_tdd[i].q_rx_lev_min = (int8)((liblte_bits_2_value(ie_ptr, 6) * 2) + 1) - 60; + sib6->carrier_freq_list_utra_tdd[i].p_max_utra = (int8)liblte_bits_2_value(ie_ptr, 7) - 50; + } + }else{ + sib6->carrier_freq_list_utra_tdd_size = 0; + } + liblte_rrc_unpack_t_reselection_ie(ie_ptr, &sib6->t_resel_utra); + if(true == sib6->t_resel_utra_sf_present) + { + liblte_rrc_unpack_speed_state_scale_factors_ie(ie_ptr, &sib6->t_resel_utra_sf); + } + + liblte_rrc_consume_noncrit_extension(ext_ind, __func__, ie_ptr); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: System Information Block Type 7 + + Description: Contains information relevant only for inter-RAT + cell reselection, i.e. information about GERAN + frequencies relevant for cell reselection + + Document Reference: 36.331 v10.0.0 Section 6.3.1 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_sys_info_block_type_7_ie(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_7_STRUCT *sib7, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint32 i; + + if(sib7 != NULL && + ie_ptr != NULL) + { + // Extension indicator + liblte_value_2_bits(0, ie_ptr, 1); + + // Optional indicators + liblte_value_2_bits(sib7->t_resel_geran_sf_present, ie_ptr, 1); + if(0 != sib7->carrier_freqs_info_list_size) + { + liblte_value_2_bits(1, ie_ptr, 1); + }else{ + liblte_value_2_bits(0, ie_ptr, 1); + } + + liblte_rrc_pack_t_reselection_ie(sib7->t_resel_geran, ie_ptr); + if(true == sib7->t_resel_geran_sf_present) + { + liblte_rrc_pack_speed_state_scale_factors_ie(&sib7->t_resel_geran_sf, ie_ptr); + } + if(0 != sib7->carrier_freqs_info_list_size) + { + liblte_value_2_bits(sib7->carrier_freqs_info_list_size - 1, ie_ptr, 4); + for(i=0; icarrier_freqs_info_list_size; i++) + { + // Extension indicator + liblte_value_2_bits(0, ie_ptr, 1); + + liblte_rrc_pack_carrier_freqs_geran_ie(&sib7->carrier_freqs_info_list[i].carrier_freqs, ie_ptr); + + // Common Info + { + // Optional indicators + liblte_value_2_bits(sib7->carrier_freqs_info_list[i].cell_resel_prio_present, ie_ptr, 1); + liblte_value_2_bits(sib7->carrier_freqs_info_list[i].p_max_geran_present, ie_ptr, 1); + + if(true == sib7->carrier_freqs_info_list[i].cell_resel_prio_present) + { + liblte_rrc_pack_cell_reselection_priority_ie(sib7->carrier_freqs_info_list[i].cell_resel_prio, ie_ptr); + } + liblte_value_2_bits(sib7->carrier_freqs_info_list[i].ncc_permitted, ie_ptr, 8); + liblte_value_2_bits((sib7->carrier_freqs_info_list[i].q_rx_lev_min + 115) / 2, ie_ptr, 6); + if(true == sib7->carrier_freqs_info_list[i].p_max_geran_present) + { + liblte_value_2_bits(sib7->carrier_freqs_info_list[i].p_max_geran, ie_ptr, 6); + } + liblte_rrc_pack_reselection_threshold_ie(sib7->carrier_freqs_info_list[i].threshx_high, ie_ptr); + liblte_rrc_pack_reselection_threshold_ie(sib7->carrier_freqs_info_list[i].threshx_low, ie_ptr); + } + } + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_sys_info_block_type_7_ie(uint8 **ie_ptr, + LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_7_STRUCT *sib7) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint32 i; + bool ext_ind; + bool carrier_freqs_info_list_opt; + bool carrier_freqs_info_list_ext_ind; + + if(ie_ptr != NULL && + sib7 != NULL) + { + // Extension indicator + ext_ind = liblte_bits_2_value(ie_ptr, 1); + + // Optional indicators + sib7->t_resel_geran_sf_present = liblte_bits_2_value(ie_ptr, 1); + carrier_freqs_info_list_opt = liblte_bits_2_value(ie_ptr, 1); + + liblte_rrc_unpack_t_reselection_ie(ie_ptr, &sib7->t_resel_geran); + if(true == sib7->t_resel_geran_sf_present) + { + liblte_rrc_unpack_speed_state_scale_factors_ie(ie_ptr, &sib7->t_resel_geran_sf); + } + if(true == carrier_freqs_info_list_opt) + { + sib7->carrier_freqs_info_list_size = liblte_bits_2_value(ie_ptr, 4) + 1; + for(i=0; icarrier_freqs_info_list_size; i++) + { + // Extension indicator + carrier_freqs_info_list_ext_ind = liblte_bits_2_value(ie_ptr, 1); + + liblte_rrc_unpack_carrier_freqs_geran_ie(ie_ptr, &sib7->carrier_freqs_info_list[i].carrier_freqs); + + // Common Info + { + // Optional indicators + sib7->carrier_freqs_info_list[i].cell_resel_prio_present = liblte_bits_2_value(ie_ptr, 1); + sib7->carrier_freqs_info_list[i].p_max_geran_present = liblte_bits_2_value(ie_ptr, 1); + + if(true == sib7->carrier_freqs_info_list[i].cell_resel_prio_present) + { + liblte_rrc_unpack_cell_reselection_priority_ie(ie_ptr, &sib7->carrier_freqs_info_list[i].cell_resel_prio); + } + sib7->carrier_freqs_info_list[i].ncc_permitted = liblte_bits_2_value(ie_ptr, 8); + sib7->carrier_freqs_info_list[i].q_rx_lev_min = (liblte_bits_2_value(ie_ptr, 6) * 2) - 115; + if(true == sib7->carrier_freqs_info_list[i].p_max_geran_present) + { + sib7->carrier_freqs_info_list[i].p_max_geran = liblte_bits_2_value(ie_ptr, 6); + } + liblte_rrc_unpack_reselection_threshold_ie(ie_ptr, &sib7->carrier_freqs_info_list[i].threshx_high); + liblte_rrc_unpack_reselection_threshold_ie(ie_ptr, &sib7->carrier_freqs_info_list[i].threshx_low); + } + } + }else{ + sib7->carrier_freqs_info_list_size = 0; + } + + liblte_rrc_consume_noncrit_extension(ext_ind, __func__, ie_ptr); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: System Information Block Type 8 + + Description: Contains information relevant only for inter-RAT + cell re-selection i.e. information about CDMA2000 + frequencies and CDMA2000 neighboring cells relevant + for cell re-selection + + Document Reference: 36.331 v10.0.0 Section 6.3.1 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_sys_info_block_type_8_ie(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_8_STRUCT *sib8, + uint8 **ie_ptr) +{ + LIBLTE_RRC_NEIGH_CELL_CDMA2000_STRUCT *neigh_cell_list; + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint32 i; + uint32 j; + uint32 k; + + if(sib8 != NULL && + ie_ptr != NULL) + { + // Extension indicator + liblte_value_2_bits(0, ie_ptr, 1); + + // Optional indicators + liblte_value_2_bits(sib8->sys_time_info_present, ie_ptr, 1); + liblte_value_2_bits(sib8->search_win_size_present, ie_ptr, 1); + liblte_value_2_bits(sib8->params_hrpd_present, ie_ptr, 1); + liblte_value_2_bits(sib8->params_1xrtt_present, ie_ptr, 1); + + if(true == sib8->sys_time_info_present) + { + liblte_rrc_pack_system_time_info_cdma2000_ie(&sib8->sys_time_info_cdma2000, ie_ptr); + } + + if(true == sib8->search_win_size_present) + { + liblte_value_2_bits(sib8->search_win_size, ie_ptr, 4); + } + + if(true == sib8->params_hrpd_present) + { + // Optional indicator + liblte_value_2_bits(sib8->cell_resel_params_hrpd_present, ie_ptr, 1); + + liblte_rrc_pack_pre_registration_info_hrpd_ie(&sib8->pre_reg_info_hrpd, ie_ptr); + + if(true == sib8->cell_resel_params_hrpd_present) + { + // Optional indicator + liblte_value_2_bits(sib8->cell_resel_params_hrpd.t_resel_cdma2000_sf_present, ie_ptr, 1); + + liblte_value_2_bits(sib8->cell_resel_params_hrpd.band_class_list_size - 1, ie_ptr, 5); + for(i=0; icell_resel_params_hrpd.band_class_list_size; i++) + { + // Extension indicator + liblte_value_2_bits(0, ie_ptr, 1); + + // Optional indicator + liblte_value_2_bits(sib8->cell_resel_params_hrpd.band_class_list[i].cell_resel_prio_present, ie_ptr, 1); + + liblte_rrc_pack_band_class_cdma2000_ie(sib8->cell_resel_params_hrpd.band_class_list[i].band_class, ie_ptr); + if(true == sib8->cell_resel_params_hrpd.band_class_list[i].cell_resel_prio_present) + { + liblte_rrc_pack_cell_reselection_priority_ie(sib8->cell_resel_params_hrpd.band_class_list[i].cell_resel_prio, ie_ptr); + } + liblte_value_2_bits(sib8->cell_resel_params_hrpd.band_class_list[i].thresh_x_high, ie_ptr, 6); + liblte_value_2_bits(sib8->cell_resel_params_hrpd.band_class_list[i].thresh_x_low, ie_ptr, 6); + } + + liblte_value_2_bits(sib8->cell_resel_params_hrpd.neigh_cell_list_size - 1, ie_ptr, 4); + for(i=0; icell_resel_params_hrpd.neigh_cell_list_size; i++) + { + neigh_cell_list = &sib8->cell_resel_params_hrpd.neigh_cell_list[i]; + liblte_rrc_pack_band_class_cdma2000_ie(neigh_cell_list->band_class, ie_ptr); + liblte_value_2_bits(neigh_cell_list->neigh_cells_per_freq_list_size - 1, ie_ptr, 4); + for(j=0; jneigh_cells_per_freq_list_size; j++) + { + liblte_rrc_pack_arfcn_value_cdma2000_ie(neigh_cell_list->neigh_cells_per_freq_list[j].arfcn, ie_ptr); + liblte_value_2_bits(neigh_cell_list->neigh_cells_per_freq_list[j].phys_cell_id_list_size - 1, ie_ptr, 4); + for(k=0; kneigh_cells_per_freq_list[j].phys_cell_id_list_size; k++) + { + liblte_rrc_pack_phys_cell_id_cdma2000_ie(neigh_cell_list->neigh_cells_per_freq_list[j].phys_cell_id_list[k], ie_ptr); + } + } + } + liblte_rrc_pack_t_reselection_ie(sib8->cell_resel_params_hrpd.t_resel_cdma2000, ie_ptr); + + if(true == sib8->cell_resel_params_hrpd.t_resel_cdma2000_sf_present) + { + liblte_rrc_pack_speed_state_scale_factors_ie(&sib8->cell_resel_params_hrpd.t_resel_cdma2000_sf, ie_ptr); + } + } + } + + if(true == sib8->params_1xrtt_present) + { + // Optional indicators + liblte_value_2_bits(sib8->csfb_reg_param_1xrtt_present, ie_ptr, 1); + liblte_value_2_bits(sib8->long_code_state_1xrtt_present, ie_ptr, 1); + liblte_value_2_bits(sib8->cell_resel_params_1xrtt_present, ie_ptr, 1); + + if(true == sib8->csfb_reg_param_1xrtt_present) + { + liblte_rrc_pack_csfb_registration_param_1xrtt_ie(&sib8->csfb_reg_param_1xrtt, ie_ptr); + } + + if(true == sib8->long_code_state_1xrtt_present) + { + liblte_value_2_bits((uint32)(sib8->long_code_state_1xrtt >> 10), ie_ptr, 32); + liblte_value_2_bits((uint32)(sib8->long_code_state_1xrtt & 0x3FF), ie_ptr, 10); + } + + if(true == sib8->cell_resel_params_1xrtt_present) + { + // Optional indicator + liblte_value_2_bits(sib8->cell_resel_params_1xrtt.t_resel_cdma2000_sf_present, ie_ptr, 1); + + liblte_value_2_bits(sib8->cell_resel_params_1xrtt.band_class_list_size - 1, ie_ptr, 5); + for(i=0; icell_resel_params_1xrtt.band_class_list_size; i++) + { + // Extension indicator + liblte_value_2_bits(0, ie_ptr, 1); + + // Optional indicator + liblte_value_2_bits(sib8->cell_resel_params_1xrtt.band_class_list[i].cell_resel_prio_present, ie_ptr, 1); + + liblte_rrc_pack_band_class_cdma2000_ie(sib8->cell_resel_params_1xrtt.band_class_list[i].band_class, ie_ptr); + if(true == sib8->cell_resel_params_1xrtt.band_class_list[i].cell_resel_prio_present) + { + liblte_rrc_pack_cell_reselection_priority_ie(sib8->cell_resel_params_1xrtt.band_class_list[i].cell_resel_prio, ie_ptr); + } + liblte_value_2_bits(sib8->cell_resel_params_1xrtt.band_class_list[i].thresh_x_high, ie_ptr, 6); + liblte_value_2_bits(sib8->cell_resel_params_1xrtt.band_class_list[i].thresh_x_low, ie_ptr, 6); + } + + liblte_value_2_bits(sib8->cell_resel_params_1xrtt.neigh_cell_list_size - 1, ie_ptr, 4); + for(i=0; icell_resel_params_1xrtt.neigh_cell_list_size; i++) + { + neigh_cell_list = &sib8->cell_resel_params_1xrtt.neigh_cell_list[i]; + liblte_rrc_pack_band_class_cdma2000_ie(neigh_cell_list->band_class, ie_ptr); + liblte_value_2_bits(neigh_cell_list->neigh_cells_per_freq_list_size - 1, ie_ptr, 4); + for(j=0; jneigh_cells_per_freq_list_size; j++) + { + liblte_rrc_pack_arfcn_value_cdma2000_ie(neigh_cell_list->neigh_cells_per_freq_list[j].arfcn, ie_ptr); + liblte_value_2_bits(neigh_cell_list->neigh_cells_per_freq_list[j].phys_cell_id_list_size - 1, ie_ptr, 4); + for(k=0; kneigh_cells_per_freq_list[j].phys_cell_id_list_size; k++) + { + liblte_rrc_pack_phys_cell_id_cdma2000_ie(neigh_cell_list->neigh_cells_per_freq_list[j].phys_cell_id_list[k], ie_ptr); + } + } + } + liblte_rrc_pack_t_reselection_ie(sib8->cell_resel_params_1xrtt.t_resel_cdma2000, ie_ptr); + + if(true == sib8->cell_resel_params_1xrtt.t_resel_cdma2000_sf_present) + { + liblte_rrc_pack_speed_state_scale_factors_ie(&sib8->cell_resel_params_1xrtt.t_resel_cdma2000_sf, ie_ptr); + } + } + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_sys_info_block_type_8_ie(uint8 **ie_ptr, + LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_8_STRUCT *sib8) +{ + LIBLTE_RRC_NEIGH_CELL_CDMA2000_STRUCT *neigh_cell_list; + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint32 i; + uint32 j; + uint32 k; + bool ext_ind; + + if(ie_ptr != NULL && + sib8 != NULL) + { + // Extension indicator + ext_ind = liblte_bits_2_value(ie_ptr, 1); + + // Optional indicators + sib8->sys_time_info_present = liblte_bits_2_value(ie_ptr, 1); + sib8->search_win_size_present = liblte_bits_2_value(ie_ptr, 1); + sib8->params_hrpd_present = liblte_bits_2_value(ie_ptr, 1); + sib8->params_1xrtt_present = liblte_bits_2_value(ie_ptr, 1); + + if(true == sib8->sys_time_info_present) + { + liblte_rrc_unpack_system_time_info_cdma2000_ie(ie_ptr, &sib8->sys_time_info_cdma2000); + } + + if(true == sib8->search_win_size_present) + { + sib8->search_win_size = liblte_bits_2_value(ie_ptr, 4); + } + + if(true == sib8->params_hrpd_present) + { + // Optional indicator + sib8->cell_resel_params_hrpd_present = liblte_bits_2_value(ie_ptr, 1); + + liblte_rrc_unpack_pre_registration_info_hrpd_ie(ie_ptr, &sib8->pre_reg_info_hrpd); + + if(true == sib8->cell_resel_params_hrpd_present) + { + // Optional indicator + sib8->cell_resel_params_hrpd.t_resel_cdma2000_sf_present = liblte_bits_2_value(ie_ptr, 1); + + sib8->cell_resel_params_hrpd.band_class_list_size = liblte_bits_2_value(ie_ptr, 5) + 1; + for(i=0; icell_resel_params_hrpd.band_class_list_size; i++) + { + // Extension indicator + bool ext = liblte_bits_2_value(ie_ptr, 1); + + // Optional indicator + sib8->cell_resel_params_hrpd.band_class_list[i].cell_resel_prio_present = liblte_bits_2_value(ie_ptr, 1); + + liblte_rrc_unpack_band_class_cdma2000_ie(ie_ptr, &sib8->cell_resel_params_hrpd.band_class_list[i].band_class); + if(true == sib8->cell_resel_params_hrpd.band_class_list[i].cell_resel_prio_present) + { + liblte_rrc_unpack_cell_reselection_priority_ie(ie_ptr, &sib8->cell_resel_params_hrpd.band_class_list[i].cell_resel_prio); + } + sib8->cell_resel_params_hrpd.band_class_list[i].thresh_x_high = liblte_bits_2_value(ie_ptr, 6); + sib8->cell_resel_params_hrpd.band_class_list[i].thresh_x_low = liblte_bits_2_value(ie_ptr, 6); + + liblte_rrc_consume_noncrit_extension(ext, __func__, ie_ptr); + + } + + sib8->cell_resel_params_hrpd.neigh_cell_list_size = liblte_bits_2_value(ie_ptr, 4) + 1; + for(i=0; icell_resel_params_hrpd.neigh_cell_list_size; i++) + { + neigh_cell_list = &sib8->cell_resel_params_hrpd.neigh_cell_list[i]; + liblte_rrc_unpack_band_class_cdma2000_ie(ie_ptr, &neigh_cell_list->band_class); + neigh_cell_list->neigh_cells_per_freq_list_size = liblte_bits_2_value(ie_ptr, 4) + 1; + for(j=0; jneigh_cells_per_freq_list_size; j++) + { + liblte_rrc_unpack_arfcn_value_cdma2000_ie(ie_ptr, &neigh_cell_list->neigh_cells_per_freq_list[j].arfcn); + neigh_cell_list->neigh_cells_per_freq_list[j].phys_cell_id_list_size = liblte_bits_2_value(ie_ptr, 4) + 1; + for(k=0; kneigh_cells_per_freq_list[j].phys_cell_id_list_size; k++) + { + liblte_rrc_unpack_phys_cell_id_cdma2000_ie(ie_ptr, &neigh_cell_list->neigh_cells_per_freq_list[j].phys_cell_id_list[k]); + } + } + } + liblte_rrc_unpack_t_reselection_ie(ie_ptr, &sib8->cell_resel_params_hrpd.t_resel_cdma2000); + + if(true == sib8->cell_resel_params_hrpd.t_resel_cdma2000_sf_present) + { + liblte_rrc_unpack_speed_state_scale_factors_ie(ie_ptr, &sib8->cell_resel_params_hrpd.t_resel_cdma2000_sf); + } + } + }else{ + sib8->cell_resel_params_hrpd_present = false; + } + + if(true == sib8->params_1xrtt_present) + { + // Optional indicators + sib8->csfb_reg_param_1xrtt_present = liblte_bits_2_value(ie_ptr, 1); + sib8->long_code_state_1xrtt_present = liblte_bits_2_value(ie_ptr, 1); + sib8->cell_resel_params_1xrtt_present = liblte_bits_2_value(ie_ptr, 1); + + if(true == sib8->csfb_reg_param_1xrtt_present) + { + liblte_rrc_unpack_csfb_registration_param_1xrtt_ie(ie_ptr, &sib8->csfb_reg_param_1xrtt); + } + + if(true == sib8->long_code_state_1xrtt_present) + { + sib8->long_code_state_1xrtt = (uint64)liblte_bits_2_value(ie_ptr, 32) << 10; + sib8->long_code_state_1xrtt |= (uint64)liblte_bits_2_value(ie_ptr, 10); + } + + if(true == sib8->cell_resel_params_1xrtt_present) + { + // Optional indicator + sib8->cell_resel_params_1xrtt.t_resel_cdma2000_sf_present = liblte_bits_2_value(ie_ptr, 1); + + sib8->cell_resel_params_1xrtt.band_class_list_size = liblte_bits_2_value(ie_ptr, 5) + 1; + for(i=0; icell_resel_params_1xrtt.band_class_list_size; i++) + { + // Extension indicator + bool ext2 = liblte_bits_2_value(ie_ptr, 1); + + // Optional indicator + sib8->cell_resel_params_1xrtt.band_class_list[i].cell_resel_prio_present = liblte_bits_2_value(ie_ptr, 1); + + liblte_rrc_unpack_band_class_cdma2000_ie(ie_ptr, &sib8->cell_resel_params_1xrtt.band_class_list[i].band_class); + if(true == sib8->cell_resel_params_1xrtt.band_class_list[i].cell_resel_prio_present) + { + liblte_rrc_unpack_cell_reselection_priority_ie(ie_ptr, &sib8->cell_resel_params_1xrtt.band_class_list[i].cell_resel_prio); + } + sib8->cell_resel_params_1xrtt.band_class_list[i].thresh_x_high = liblte_bits_2_value(ie_ptr, 6); + sib8->cell_resel_params_1xrtt.band_class_list[i].thresh_x_low = liblte_bits_2_value(ie_ptr, 6); + + liblte_rrc_consume_noncrit_extension(ext2, __func__, ie_ptr); + } + + sib8->cell_resel_params_1xrtt.neigh_cell_list_size = liblte_bits_2_value(ie_ptr, 4) + 1; + for(i=0; icell_resel_params_1xrtt.neigh_cell_list_size; i++) + { + neigh_cell_list = &sib8->cell_resel_params_1xrtt.neigh_cell_list[i]; + liblte_rrc_unpack_band_class_cdma2000_ie(ie_ptr, &neigh_cell_list->band_class); + neigh_cell_list->neigh_cells_per_freq_list_size = liblte_bits_2_value(ie_ptr, 4) + 1; + for(j=0; jneigh_cells_per_freq_list_size; j++) + { + liblte_rrc_unpack_arfcn_value_cdma2000_ie(ie_ptr, &neigh_cell_list->neigh_cells_per_freq_list[j].arfcn); + neigh_cell_list->neigh_cells_per_freq_list[j].phys_cell_id_list_size = liblte_bits_2_value(ie_ptr, 4) + 1; + for(k=0; kneigh_cells_per_freq_list[j].phys_cell_id_list_size; k++) + { + liblte_rrc_unpack_phys_cell_id_cdma2000_ie(ie_ptr, &neigh_cell_list->neigh_cells_per_freq_list[j].phys_cell_id_list[k]); + } + } + } + liblte_rrc_unpack_t_reselection_ie(ie_ptr, &sib8->cell_resel_params_1xrtt.t_resel_cdma2000); + + if(true == sib8->cell_resel_params_1xrtt.t_resel_cdma2000_sf_present) + { + liblte_rrc_unpack_speed_state_scale_factors_ie(ie_ptr, &sib8->cell_resel_params_1xrtt.t_resel_cdma2000_sf); + } + } + }else{ + sib8->csfb_reg_param_1xrtt_present = false; + sib8->long_code_state_1xrtt_present = false; + sib8->cell_resel_params_1xrtt_present = false; + } + + liblte_rrc_consume_noncrit_extension(ext_ind, __func__, ie_ptr); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: System Information Block Type 9 + + Description: Contains a home eNB name (HNB name) + + Document Reference: 36.331 v10.0.0 Section 6.3.1 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_sys_info_block_type_9_ie(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_9_STRUCT *sib9, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint32 i; + + if(sib9 != NULL && + ie_ptr != NULL) + { + // Extension indicator + liblte_value_2_bits(0, ie_ptr, 1); + + // Optional indicators + liblte_value_2_bits(sib9->hnb_name_present, ie_ptr, 1); + + if(true == sib9->hnb_name_present) { + // Dynamic octet string - hnb_name + liblte_value_2_bits(sib9->hnb_name_size - 1, ie_ptr, 6); + + // Octets + for(i=0;ihnb_name_size;i++) { + liblte_value_2_bits(sib9->hnb_name[i], ie_ptr, 8); + } + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_sys_info_block_type_9_ie(uint8 **ie_ptr, + LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_9_STRUCT *sib9) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + bool ext_ind; + uint32 i; + + if(ie_ptr != NULL && + sib9 != NULL) + { + // Extension indicator + ext_ind = liblte_bits_2_value(ie_ptr, 1); + + // Optional indicators + sib9->hnb_name_present = liblte_bits_2_value(ie_ptr, 1); + + if(true == sib9->hnb_name_present) { + // Dynamic octet string - hnb_name + // Length + sib9->hnb_name_size = liblte_bits_2_value(ie_ptr, 6) + 1; + + // Octets + for(i=0;ihnb_name_size;i++) { + sib9->hnb_name[i] = liblte_bits_2_value(ie_ptr, 8); + } + } + + liblte_rrc_consume_noncrit_extension(ext_ind, __func__, ie_ptr); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + IE Name: System Information Block Type 10 + + Description: Contains an ETWS primary notification + + Document Reference: 36.331 v10.0.0 Section 6.3.1 +*********************************************************************/ +// FIXME + +/********************************************************************* + IE Name: System Information Block Type 11 + + Description: Contains an ETWS secondary notification + + Document Reference: 36.331 v10.0.0 Section 6.3.1 +*********************************************************************/ +// FIXME + +/********************************************************************* + IE Name: System Information Block Type 12 + + Description: Contains a CMAS notification + + Document Reference: 36.331 v10.0.0 Section 6.3.1 +*********************************************************************/ +// FIXME + +/********************************************************************* + IE Name: System Information Block Type 13 + + Description: Contains the information required to acquire the + MBMS control information associated with one or more + MBSFN areas + + Document Reference: 36.331 v10.0.0 Section 6.3.1 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_sys_info_block_type_13_ie(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_13_STRUCT *sib13, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint32 i; + + if(sib13 != NULL && + ie_ptr != NULL) + { + // Extension indicator + liblte_value_2_bits(0, ie_ptr, 1); + + // Optional indicators + liblte_value_2_bits(0, ie_ptr, 1); + + liblte_value_2_bits(sib13->mbsfn_area_info_list_r9_size - 1, ie_ptr, 3); + for(i=0; imbsfn_area_info_list_r9_size; i++) + { + liblte_rrc_pack_mbsfn_area_info_ie(&sib13->mbsfn_area_info_list_r9[i], ie_ptr); + } + liblte_rrc_pack_mbsfn_notification_config_ie(&sib13->mbms_notification_config, ie_ptr); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_sys_info_block_type_13_ie(uint8 **ie_ptr, + LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_13_STRUCT *sib13) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint32 i; + bool ext_ind; + bool non_crit_ext_present; + + if(ie_ptr != NULL && + sib13 != NULL) + { + // Extension indicator + ext_ind = liblte_bits_2_value(ie_ptr, 1); + + // Optional indicators + non_crit_ext_present = liblte_bits_2_value(ie_ptr, 1); + + sib13->mbsfn_area_info_list_r9_size = liblte_bits_2_value(ie_ptr, 3) + 1; + for(i=0; imbsfn_area_info_list_r9_size; i++) + { + liblte_rrc_unpack_mbsfn_area_info_ie(ie_ptr, &sib13->mbsfn_area_info_list_r9[i]); + } + liblte_rrc_unpack_mbsfn_notification_config_ie(ie_ptr, &sib13->mbms_notification_config); + + liblte_rrc_consume_noncrit_extension(ext_ind, __func__, ie_ptr); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/******************************************************************************* + MESSAGE FUNCTIONS +*******************************************************************************/ + +/********************************************************************* + Message Name: UL Information Transfer + + Description: Used for the uplink transfer dedicated NAS + information + + Document Reference: 36.331 v10.0.0 Section 6.2.2 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_ul_information_transfer_msg(LIBLTE_RRC_UL_INFORMATION_TRANSFER_STRUCT *ul_info_transfer, + LIBLTE_BIT_MSG_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(ul_info_transfer != NULL && + msg != NULL) + { + // Extension choice + liblte_value_2_bits(0, &msg_ptr, 1); + + // C1 choice + liblte_value_2_bits(0, &msg_ptr, 2); + + // Optional indicator + liblte_value_2_bits(0, &msg_ptr, 1); + + // Dedicated info type choice + liblte_value_2_bits(ul_info_transfer->dedicated_info_type, &msg_ptr, 2); + + if(LIBLTE_RRC_UL_INFORMATION_TRANSFER_TYPE_NAS == ul_info_transfer->dedicated_info_type) + { + liblte_rrc_pack_dedicated_info_nas_ie(&ul_info_transfer->dedicated_info, + &msg_ptr); + }else{ + liblte_rrc_pack_dedicated_info_cdma2000_ie(&ul_info_transfer->dedicated_info, + &msg_ptr); + } + + // Fill in the number of bits used + msg->N_bits = msg_ptr - msg->msg; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_ul_information_transfer_msg(LIBLTE_BIT_MSG_STRUCT *msg, + LIBLTE_RRC_UL_INFORMATION_TRANSFER_STRUCT *ul_info_transfer) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(msg != NULL && + ul_info_transfer != NULL) + { + // Extension choice + bool ext = liblte_bits_2_value(&msg_ptr, 1); + + // C1 choice + liblte_bits_2_value(&msg_ptr, 2); + + // Optional indicator + liblte_rrc_warning_not_handled(liblte_bits_2_value(&msg_ptr, 1), __func__);; + + // Dedicated info type choice + ul_info_transfer->dedicated_info_type = (LIBLTE_RRC_UL_INFORMATION_TRANSFER_TYPE_ENUM)liblte_bits_2_value(&msg_ptr, 2); + + if(LIBLTE_RRC_UL_INFORMATION_TRANSFER_TYPE_NAS == ul_info_transfer->dedicated_info_type) + { + liblte_rrc_unpack_dedicated_info_nas_ie(&msg_ptr, + &ul_info_transfer->dedicated_info); + }else{ + liblte_rrc_unpack_dedicated_info_cdma2000_ie(&msg_ptr, + &ul_info_transfer->dedicated_info); + } + + liblte_rrc_consume_noncrit_extension(ext, __func__, &msg_ptr); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + Message Name: UL Handover Preparation Transfer (CDMA2000) + + Description: Used for the uplink transfer of handover related + CDMA2000 information when requested by the higher + layers + + Document Reference: 36.331 v10.0.0 Section 6.2.2 +*********************************************************************/ +// FIXME + +/********************************************************************* + Message Name: UE Information Response + + Description: Used by the UE to transfer the information requested + by the E-UTRAN + + Document Reference: 36.331 v10.0.0 Section 6.2.2 +*********************************************************************/ +// FIXME + +/********************************************************************* + Message Name: UE Information Request + + Description: Used by E-UTRAN to retrieve information from the UE + + Document Reference: 36.331 v10.0.0 Section 6.2.2 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_ue_information_request_msg(LIBLTE_RRC_UE_INFORMATION_REQUEST_STRUCT *ue_info_req, + LIBLTE_BIT_MSG_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(ue_info_req != NULL && + msg != NULL) + { + // RRC Transaction ID + liblte_rrc_pack_rrc_transaction_identifier_ie(ue_info_req->rrc_transaction_id, + &msg_ptr); + + // Extension choice + liblte_value_2_bits(0, &msg_ptr, 1); + + // C1 choice + liblte_value_2_bits(0, &msg_ptr, 2); + + // Optional indicator + liblte_value_2_bits(0, &msg_ptr, 1); + + // RACH report required + liblte_value_2_bits(ue_info_req->rach_report_req, &msg_ptr, 1); + + // RLF report required + liblte_value_2_bits(ue_info_req->rlf_report_req, &msg_ptr, 1); + + // Fill in the number of bits used + msg->N_bits = msg_ptr - msg->msg; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_ue_information_request_msg(LIBLTE_BIT_MSG_STRUCT *msg, + LIBLTE_RRC_UE_INFORMATION_REQUEST_STRUCT *ue_info_req) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(msg != NULL && + ue_info_req != NULL) + { + // RRC Transaction ID + liblte_rrc_unpack_rrc_transaction_identifier_ie(&msg_ptr, + &ue_info_req->rrc_transaction_id); + + // Extension choice + bool ext = liblte_bits_2_value(&msg_ptr, 1); + + // C1 choice + liblte_bits_2_value(&msg_ptr, 2); + + // Optional indicator + liblte_rrc_warning_not_handled(liblte_bits_2_value(&msg_ptr, 1), __func__);; + + // RACH report required + ue_info_req->rach_report_req = liblte_bits_2_value(&msg_ptr, 1); + + // RLF report required + ue_info_req->rlf_report_req = liblte_bits_2_value(&msg_ptr, 1); + + liblte_rrc_consume_noncrit_extension(ext, __func__, &msg_ptr); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + Message Name: UE Capability Information + + Description: Used to transfer UE radio access capabilities + requested by the E-UTRAN + + Document Reference: 36.331 v10.0.0 Section 6.2.2 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_ue_capability_information_msg(LIBLTE_RRC_UE_CAPABILITY_INFORMATION_STRUCT *ue_capability_info, + LIBLTE_BIT_MSG_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + uint32 i; + + if(ue_capability_info != NULL && + msg != NULL) + { + // RRC Transaction ID + liblte_rrc_pack_rrc_transaction_identifier_ie(ue_capability_info->rrc_transaction_id, + &msg_ptr); + + // Extension choice + liblte_value_2_bits(0, &msg_ptr, 1); + + // C1 choice + liblte_value_2_bits(0, &msg_ptr, 3); + + // Optional indicator + liblte_value_2_bits(0, &msg_ptr, 1); + + liblte_value_2_bits(ue_capability_info->N_ue_caps, &msg_ptr, 4); + for(i=0; iN_ue_caps; i++) + { + // RAT-Type + liblte_value_2_bits(0, &msg_ptr, 1); //Optional indicator + liblte_value_2_bits(ue_capability_info->ue_capability_rat[i].rat_type, &msg_ptr, 3); + + // Octet string + LIBLTE_BIT_MSG_STRUCT tmp; + liblte_rrc_pack_ue_eutra_capability_ie(&ue_capability_info->ue_capability_rat[i].eutra_capability, &tmp); + + uint32 pad = 8 - tmp.N_bits%8; + uint32 n_bytes = (tmp.N_bits+pad) / 8; + if(n_bytes < 128) + { + liblte_value_2_bits(0, &msg_ptr, 1); + liblte_value_2_bits(n_bytes, &msg_ptr, 7); + }else if(n_bytes < 16383){ + liblte_value_2_bits(1, &msg_ptr, 1); + liblte_value_2_bits(0, &msg_ptr, 1); + liblte_value_2_bits(n_bytes, &msg_ptr, 14); + }else{ + // FIXME: Unlikely to have more than 16K of octets + } + + for(i=0; iN_bits = msg_ptr - msg->msg; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_ue_capability_information_msg(LIBLTE_BIT_MSG_STRUCT *msg, + LIBLTE_RRC_UE_CAPABILITY_INFORMATION_STRUCT *ue_capability_info) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + uint32 i; + + if(msg != NULL && + ue_capability_info != NULL) + { + // RRC Transaction ID + liblte_rrc_unpack_rrc_transaction_identifier_ie(&msg_ptr, + &ue_capability_info->rrc_transaction_id); + + // Extension choice + bool ext = liblte_bits_2_value(&msg_ptr, 1); + + // C1 choice + liblte_bits_2_value(&msg_ptr, 3); + + // Optional indicator + liblte_rrc_warning_not_handled(liblte_bits_2_value(&msg_ptr, 1), __func__);; + + ue_capability_info->N_ue_caps = liblte_bits_2_value(&msg_ptr, 4); + for(i=0; iN_ue_caps; i++) + { + liblte_bits_2_value(&msg_ptr, 1); //Optional indicator + ue_capability_info->ue_capability_rat[i].rat_type = (LIBLTE_RRC_RAT_TYPE_ENUM)liblte_bits_2_value(&msg_ptr, 3); + + //Octet string + uint32 n_bytes = 0; + if(0 == liblte_bits_2_value(&msg_ptr, 1)) + { + n_bytes = liblte_bits_2_value(&msg_ptr, 7); + }else{ + if(0 == liblte_bits_2_value(&msg_ptr, 1)) + { + n_bytes = liblte_bits_2_value(&msg_ptr, 14); + }else{ + // FIXME: Unlikely to have more than 16K of octets + n_bytes = 0; + } + } + + liblte_rrc_unpack_ue_eutra_capability_ie(&msg_ptr, &ue_capability_info->ue_capability_rat[i].eutra_capability); + } + + liblte_rrc_consume_noncrit_extension(ext, __func__, &msg_ptr); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + + +/********************************************************************* + Message Name: UE Capability Enquiry + + Description: Used to request the transfer of UE radio access + capabilities for E-UTRA as well as for other RATs + + Document Reference: 36.331 v10.0.0 Section 6.2.2 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_ue_capability_enquiry_msg(LIBLTE_RRC_UE_CAPABILITY_ENQUIRY_STRUCT *ue_cap_enquiry, + LIBLTE_BIT_MSG_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + uint32 i; + + if(ue_cap_enquiry != NULL && + msg != NULL) + { + // RRC Transaction ID + liblte_rrc_pack_rrc_transaction_identifier_ie(ue_cap_enquiry->rrc_transaction_id, + &msg_ptr); + + // Extension choice + liblte_value_2_bits(0, &msg_ptr, 1); + + // C1 choice + liblte_value_2_bits(0, &msg_ptr, 2); + + // Optional indicator + liblte_value_2_bits(0, &msg_ptr, 1); + + // UE-CapabilityRequest + liblte_value_2_bits(ue_cap_enquiry->N_ue_cap_reqs - 1, &msg_ptr, 3); + for(i=0; iue_capability_request[i], &msg_ptr); + } + + // Fill in the number of bits used + msg->N_bits = msg_ptr - msg->msg; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_ue_capability_enquiry_msg(LIBLTE_BIT_MSG_STRUCT *msg, + LIBLTE_RRC_UE_CAPABILITY_ENQUIRY_STRUCT *ue_cap_enquiry) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + uint32 i; + + if(msg != NULL && + ue_cap_enquiry != NULL) + { + // RRC Transaction ID + liblte_rrc_unpack_rrc_transaction_identifier_ie(&msg_ptr, + &ue_cap_enquiry->rrc_transaction_id); + + // Extension choice + bool ext = liblte_bits_2_value(&msg_ptr, 1); + + // C1 choice + liblte_bits_2_value(&msg_ptr, 2); + + // Optional indicator + liblte_rrc_warning_not_handled(liblte_bits_2_value(&msg_ptr, 1), __func__);; + + ue_cap_enquiry->N_ue_cap_reqs = liblte_bits_2_value(&msg_ptr, 3) + 1; + for(i=0; iN_ue_cap_reqs; i++) + { + liblte_rrc_unpack_rat_type_ie(&msg_ptr, &ue_cap_enquiry->ue_capability_request[i]); + } + + liblte_rrc_consume_noncrit_extension(ext, __func__, &msg_ptr); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + + +/********************************************************************* + Message Name: System Information Block Type 1 + + Description: Contains information relevant when evaluating if a + UE is allowed to access a cell and defines the + scheduling of other system information + + Document Reference: 36.331 v10.0.0 Section 6.2.2 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_sys_info_block_type_1_msg(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1_STRUCT *sib1, + LIBLTE_BIT_MSG_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + uint32 i; + uint32 j; + uint8 non_crit_ext_opt = false; + uint8 csg_id_opt = false; + uint8 q_rx_lev_min_offset_opt = false; + uint8 extension = false; + + if(sib1 != NULL && + msg != NULL) + { + // Optional indicators + liblte_value_2_bits(sib1->p_max_present, &msg_ptr, 1); + liblte_value_2_bits(sib1->tdd, &msg_ptr, 1); + liblte_value_2_bits(non_crit_ext_opt, &msg_ptr, 1); + + // Cell Access Related Info + liblte_value_2_bits(csg_id_opt, &msg_ptr, 1); + liblte_value_2_bits(sib1->N_plmn_ids - 1, &msg_ptr, 3); + for(i=0; iN_plmn_ids; i++) + { + liblte_rrc_pack_plmn_identity_ie(&sib1->plmn_id[i].id, &msg_ptr); + liblte_value_2_bits(sib1->plmn_id[i].resv_for_oper, &msg_ptr, 1); + } + liblte_rrc_pack_tracking_area_code_ie(sib1->tracking_area_code, &msg_ptr); + liblte_rrc_pack_cell_identity_ie(sib1->cell_id, &msg_ptr); + liblte_value_2_bits(sib1->cell_barred, &msg_ptr, 1); + liblte_value_2_bits(sib1->intra_freq_reselection, &msg_ptr, 1); + liblte_value_2_bits(sib1->csg_indication, &msg_ptr, 1); + if(true == csg_id_opt) + { + liblte_rrc_pack_csg_identity_ie(sib1->csg_id, &msg_ptr); + } + + // Cell Selection Info + liblte_value_2_bits(q_rx_lev_min_offset_opt, &msg_ptr, 1); + liblte_rrc_pack_q_rx_lev_min_ie(sib1->q_rx_lev_min, &msg_ptr); + if(true == q_rx_lev_min_offset_opt) + { + liblte_value_2_bits((sib1->q_rx_lev_min_offset / 2) - 1, &msg_ptr, 3); + } + + // P Max + if(true == sib1->p_max_present) + { + liblte_rrc_pack_p_max_ie(sib1->p_max, &msg_ptr); + } + + // Freq Band Indicator + liblte_value_2_bits(sib1->freq_band_indicator - 1, &msg_ptr, 6); + + // Scheduling Info List + liblte_value_2_bits(sib1->N_sched_info - 1, &msg_ptr, 5); + for(i=0; iN_sched_info; i++) + { + liblte_value_2_bits(sib1->sched_info[i].si_periodicity, &msg_ptr, 3); + liblte_value_2_bits(sib1->sched_info[i].N_sib_mapping_info, &msg_ptr, 5); + for(j=0; jsched_info[i].N_sib_mapping_info; j++) + { + liblte_value_2_bits(extension, &msg_ptr, 1); + liblte_value_2_bits(sib1->sched_info[i].sib_mapping_info[j].sib_type, &msg_ptr, 4); + } + } + + // TDD Config + if(true == sib1->tdd) + { + liblte_rrc_pack_tdd_config_ie(&sib1->tdd_cnfg, &msg_ptr); + } + + // SI Window Length + liblte_value_2_bits(sib1->si_window_length, &msg_ptr, 3); + + // System Info Value Tag + liblte_value_2_bits(sib1->system_info_value_tag, &msg_ptr, 5); + + // Non Critical Extension + // FIXME + + // Fill in the number of bits used + msg->N_bits = msg_ptr - msg->msg; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_sys_info_block_type_1_msg(LIBLTE_BIT_MSG_STRUCT *msg, + LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1_STRUCT *sib1, + uint32 *N_bits_used) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + uint32 i; + uint32 j; + bool tdd_config_opt; + bool non_crit_ext_opt; + bool csg_id_opt; + bool q_rx_lev_min_offset_opt; + bool extension; + + if(msg != NULL && + sib1 != NULL && + N_bits_used != NULL) + { + + // Optional indicators + sib1->p_max_present = liblte_bits_2_value(&msg_ptr, 1); + tdd_config_opt = liblte_bits_2_value(&msg_ptr, 1); + non_crit_ext_opt = liblte_bits_2_value(&msg_ptr, 1); + + // Cell Access Related Info + csg_id_opt = liblte_bits_2_value(&msg_ptr, 1); + sib1->N_plmn_ids = liblte_bits_2_value(&msg_ptr, 3) + 1; + for(i=0; iN_plmn_ids; i++) + { + liblte_rrc_unpack_plmn_identity_ie(&msg_ptr, &sib1->plmn_id[i].id); + if(LIBLTE_RRC_MCC_NOT_PRESENT == sib1->plmn_id[i].id.mcc && + 0 != i) + { + sib1->plmn_id[i].id.mcc = sib1->plmn_id[i-1].id.mcc; + } + sib1->plmn_id[i].resv_for_oper = (LIBLTE_RRC_RESV_FOR_OPER_ENUM)liblte_bits_2_value(&msg_ptr, 1); + } + liblte_rrc_unpack_tracking_area_code_ie(&msg_ptr, &sib1->tracking_area_code); + liblte_rrc_unpack_cell_identity_ie(&msg_ptr, &sib1->cell_id); + sib1->cell_barred = (LIBLTE_RRC_CELL_BARRED_ENUM)liblte_bits_2_value(&msg_ptr, 1); + sib1->intra_freq_reselection = (LIBLTE_RRC_INTRA_FREQ_RESELECTION_ENUM)liblte_bits_2_value(&msg_ptr, 1); + sib1->csg_indication = liblte_bits_2_value(&msg_ptr, 1); + if(true == csg_id_opt) + { + liblte_rrc_unpack_csg_identity_ie(&msg_ptr, &sib1->csg_id); + }else{ + sib1->csg_id = LIBLTE_RRC_CSG_IDENTITY_NOT_PRESENT; + } + + // Cell Selection Info + q_rx_lev_min_offset_opt = liblte_bits_2_value(&msg_ptr, 1); + liblte_rrc_unpack_q_rx_lev_min_ie(&msg_ptr, &sib1->q_rx_lev_min); + if(true == q_rx_lev_min_offset_opt) + { + sib1->q_rx_lev_min_offset = (liblte_bits_2_value(&msg_ptr, 3) + 1) * 2; + }else{ + sib1->q_rx_lev_min_offset = 0; + } + + // P Max + if(true == sib1->p_max_present) + { + liblte_rrc_unpack_p_max_ie(&msg_ptr, &sib1->p_max); + } + + // Freq Band Indicator + sib1->freq_band_indicator = liblte_bits_2_value(&msg_ptr, 6) + 1; + + // Scheduling Info List + sib1->N_sched_info = liblte_bits_2_value(&msg_ptr, 5) + 1; + for(i=0; iN_sched_info; i++) + { + sib1->sched_info[i].si_periodicity = (LIBLTE_RRC_SI_PERIODICITY_ENUM)liblte_bits_2_value(&msg_ptr, 3); + sib1->sched_info[i].N_sib_mapping_info = liblte_bits_2_value(&msg_ptr, 5); + for(j=0; jsched_info[i].N_sib_mapping_info; j++) + { + extension = liblte_bits_2_value(&msg_ptr, 1); + sib1->sched_info[i].sib_mapping_info[j].sib_type = (LIBLTE_RRC_SIB_TYPE_ENUM)liblte_bits_2_value(&msg_ptr, 4); + } + } + + // TDD Config + if(true == tdd_config_opt) + { + sib1->tdd = true; + liblte_rrc_unpack_tdd_config_ie(&msg_ptr, &sib1->tdd_cnfg); + }else{ + sib1->tdd = false; + } + + // SI Window Length + sib1->si_window_length = (LIBLTE_RRC_SI_WINDOW_LENGTH_ENUM)liblte_bits_2_value(&msg_ptr, 3); + + // System Info Value Tag + sib1->system_info_value_tag = liblte_bits_2_value(&msg_ptr, 5); + + // Non Critical Extension + liblte_rrc_consume_noncrit_extension(non_crit_ext_opt, __func__, &msg_ptr); + + // N_bits_used + *N_bits_used = msg_ptr - (msg->msg); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + Message Name: System Information + + Description: Conveys one or more System Information Blocks + + Document Reference: 36.331 v10.0.0 Section 6.2.2 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_sys_info_msg(LIBLTE_RRC_SYS_INFO_MSG_STRUCT *sibs, + LIBLTE_BIT_MSG_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + uint8 *length_ptr; + uint32 length; + uint32 pad_bits; + uint32 i; + + if(sibs != NULL && + msg != NULL) + { + // Critical extensions choice + liblte_value_2_bits(0, &msg_ptr, 1); + + // Optional indicator + liblte_value_2_bits(0, &msg_ptr, 1); + + // Number of SIBs present + liblte_value_2_bits(sibs->N_sibs - 1, &msg_ptr, 5); + + for(i=0; iN_sibs; i++) + { + if(sibs->sibs[i].sib_type < LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_12) + { + // Extension indicator + liblte_value_2_bits(0, &msg_ptr, 1); + + liblte_value_2_bits(sibs->sibs[i].sib_type, &msg_ptr, 4); + switch(sibs->sibs[i].sib_type) + { + case LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2: + err = liblte_rrc_pack_sys_info_block_type_2_ie((LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT *)&sibs->sibs[i].sib, + &msg_ptr); + break; + case LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_3: + err = liblte_rrc_pack_sys_info_block_type_3_ie((LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_3_STRUCT *)&sibs->sibs[i].sib, + &msg_ptr); + break; + case LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_4: + err = liblte_rrc_pack_sys_info_block_type_4_ie((LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_4_STRUCT *)&sibs->sibs[i].sib, + &msg_ptr); + break; + case LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_8: + err = liblte_rrc_pack_sys_info_block_type_8_ie((LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_8_STRUCT *)&sibs->sibs[i].sib, + &msg_ptr); + break; + case LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_9: + err = liblte_rrc_pack_sys_info_block_type_9_ie((LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_9_STRUCT *)&sibs->sibs[i].sib, + &msg_ptr); + break; + case LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_5: + case LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_6: + case LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_7: + case LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_10: + case LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_11: + default: + printf("ERROR: Not handling sib type %u\n", sibs->sibs[i].sib_type); + err = LIBLTE_ERROR_INVALID_INPUTS; + break; + } + }else{ + // Extension indicator + liblte_value_2_bits(1, &msg_ptr, 1); + + liblte_value_2_bits(sibs->sibs[i].sib_type - 10, &msg_ptr, 7); + length_ptr = msg_ptr; + liblte_value_2_bits(0, &msg_ptr, 8); + switch(sibs->sibs[i].sib_type) + { + case LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_13: + err = liblte_rrc_pack_sys_info_block_type_13_ie((LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_13_STRUCT *)&sibs->sibs[i].sib, + &msg_ptr); + break; + case LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_12: + default: + printf("ERROR: Not handling extended sib type %s\n", liblte_rrc_sys_info_block_type_text[sibs->sibs[i].sib_type]); + err = LIBLTE_ERROR_INVALID_INPUTS; + break; + } + length = ((msg_ptr - length_ptr) / 8) - 1; + pad_bits = (msg_ptr - length_ptr) % 8; + if(0 != pad_bits) + { + length++; + } + if(length < 128) + { + liblte_value_2_bits(0, &length_ptr, 1); + liblte_value_2_bits(length, &length_ptr, 7); + }else{ + msg_ptr = length_ptr; + liblte_value_2_bits(0, &msg_ptr, 2); + liblte_value_2_bits(length, &msg_ptr, 14); + switch(sibs->sibs[i].sib_type) + { + case LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_13: + err = liblte_rrc_pack_sys_info_block_type_13_ie((LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_13_STRUCT *)&sibs->sibs[i].sib, + &msg_ptr); + break; + case LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_12: + default: + printf("ERROR: Not handling extended sib type %s\n", liblte_rrc_sys_info_block_type_text[sibs->sibs[i].sib_type]); + err = LIBLTE_ERROR_INVALID_INPUTS; + break; + } + } + liblte_value_2_bits(0, &msg_ptr, pad_bits); + } + + if(LIBLTE_SUCCESS != err) + { + break; + } + } + + // Fill in the number of bits used + msg->N_bits = msg_ptr - msg->msg; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_sys_info_msg(LIBLTE_BIT_MSG_STRUCT *msg, + LIBLTE_RRC_SYS_INFO_MSG_STRUCT *sibs) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + uint8 *head_ptr; + uint32 i; + uint32 length_determinant_octets; + uint8 non_crit_ext_opt; + + if(msg != NULL && + sibs != NULL) + { + // Critical extensions choice + if(0 == liblte_bits_2_value(&msg_ptr, 1)) + { + // Optional indicator + non_crit_ext_opt = liblte_bits_2_value(&msg_ptr, 1); + + // Number of SIBs present + sibs->N_sibs = liblte_bits_2_value(&msg_ptr, 5) + 1; + + for(i=0; iN_sibs; i++) + { + // Extension indicator + if(0 == liblte_bits_2_value(&msg_ptr, 1)) + { + sibs->sibs[i].sib_type = (LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_ENUM)liblte_bits_2_value(&msg_ptr, 4); + switch(sibs->sibs[i].sib_type) + { + case LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2: + err = liblte_rrc_unpack_sys_info_block_type_2_ie(&msg_ptr, + (LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT *)&sibs->sibs[i].sib); + break; + case LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_3: + err = liblte_rrc_unpack_sys_info_block_type_3_ie(&msg_ptr, + (LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_3_STRUCT *)&sibs->sibs[i].sib); + break; + case LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_4: + err = liblte_rrc_unpack_sys_info_block_type_4_ie(&msg_ptr, + (LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_4_STRUCT *)&sibs->sibs[i].sib); + break; + case LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_5: + err = liblte_rrc_unpack_sys_info_block_type_5_ie(&msg_ptr, + (LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_5_STRUCT *)&sibs->sibs[i].sib); + break; + case LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_6: + err = liblte_rrc_unpack_sys_info_block_type_6_ie(&msg_ptr, + (LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_6_STRUCT *)&sibs->sibs[i].sib); + break; + case LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_7: + err = liblte_rrc_unpack_sys_info_block_type_7_ie(&msg_ptr, + (LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_7_STRUCT *)&sibs->sibs[i].sib); + break; + case LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_8: + err = liblte_rrc_unpack_sys_info_block_type_8_ie(&msg_ptr, + (LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_8_STRUCT *)&sibs->sibs[i].sib); + break; + case LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_9: + err = liblte_rrc_unpack_sys_info_block_type_9_ie(&msg_ptr, + (LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_9_STRUCT *)&sibs->sibs[i].sib); + break; + case LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_10: + case LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_11: + default: + printf("ERROR: Not handling sib type %u\n", sibs->sibs[i].sib_type); + err = LIBLTE_ERROR_INVALID_INPUTS; + break; + } + }else{ + sibs->sibs[i].sib_type = (LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_ENUM)(liblte_bits_2_value(&msg_ptr, 7) + 10); + length_determinant_octets = 0; + if(0 == liblte_bits_2_value(&msg_ptr, 1)) + { + length_determinant_octets = liblte_bits_2_value(&msg_ptr, 7); + }else{ + if(0 == liblte_bits_2_value(&msg_ptr, 1)) + { + length_determinant_octets = liblte_bits_2_value(&msg_ptr, 14); + }else{ + printf("ERROR: Not handling fragmented length determinants\n"); + } + } + head_ptr = msg_ptr; + switch(sibs->sibs[i].sib_type) + { + case LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_13: + err = liblte_rrc_unpack_sys_info_block_type_13_ie(&msg_ptr, + (LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_13_STRUCT *)&sibs->sibs[i].sib); + break; + case LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_12: + default: + printf("ERROR: Not handling extended sib type %s\n", liblte_rrc_sys_info_block_type_text[sibs->sibs[i].sib_type]); + err = LIBLTE_ERROR_INVALID_INPUTS; + break; + } + liblte_bits_2_value(&msg_ptr, (msg_ptr - head_ptr) % 8); + } + + if(LIBLTE_SUCCESS != err) + { + break; + } + } + + liblte_rrc_consume_noncrit_extension(non_crit_ext_opt, __func__, &msg_ptr); + + }else{ + printf("ERROR: Not handling critical extensions in system information message\n"); + } + } + + return(err); +} + +/********************************************************************* + Message Name: Security Mode Failure + + Description: Used to indicate an unsuccessful completion of a + security mode command + + Document Reference: 36.331 v10.0.0 Section 6.2.2 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_security_mode_failure_msg(LIBLTE_RRC_SECURITY_MODE_FAILURE_STRUCT *security_mode_failure, + LIBLTE_BIT_MSG_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(security_mode_failure != NULL && + msg != NULL) + { + // RRC Transaction ID + liblte_rrc_pack_rrc_transaction_identifier_ie(security_mode_failure->rrc_transaction_id, + &msg_ptr); + + // Extension choice + liblte_value_2_bits(0, &msg_ptr, 1); + + // Optional indicator + liblte_value_2_bits(0, &msg_ptr, 1); + + // Fill in the number of bits used + msg->N_bits = msg_ptr - msg->msg; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_security_mode_failure_msg(LIBLTE_BIT_MSG_STRUCT *msg, + LIBLTE_RRC_SECURITY_MODE_FAILURE_STRUCT *security_mode_failure) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(msg != NULL && + security_mode_failure != NULL) + { + // RRC Transaction ID + liblte_rrc_unpack_rrc_transaction_identifier_ie(&msg_ptr, + &security_mode_failure->rrc_transaction_id); + + // Extension choice + bool ext = liblte_bits_2_value(&msg_ptr, 1); + + // Optional indicator + liblte_rrc_warning_not_handled(liblte_bits_2_value(&msg_ptr, 1), __func__);; + + liblte_rrc_consume_noncrit_extension(ext, __func__, &msg_ptr); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + Message Name: Security Mode Complete + + Description: Used to confirm the successful completion of a + security mode command + + Document Reference: 36.331 v10.0.0 Section 6.2.2 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_security_mode_complete_msg(LIBLTE_RRC_SECURITY_MODE_COMPLETE_STRUCT *security_mode_complete, + LIBLTE_BIT_MSG_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(security_mode_complete != NULL && + msg != NULL) + { + // RRC Transaction ID + liblte_rrc_pack_rrc_transaction_identifier_ie(security_mode_complete->rrc_transaction_id, + &msg_ptr); + + // Extension choice + liblte_value_2_bits(0, &msg_ptr, 1); + + // Optional indicator + liblte_value_2_bits(0, &msg_ptr, 1); + + // Fill in the number of bits used + msg->N_bits = msg_ptr - msg->msg; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_security_mode_complete_msg(LIBLTE_BIT_MSG_STRUCT *msg, + LIBLTE_RRC_SECURITY_MODE_COMPLETE_STRUCT *security_mode_complete) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(msg != NULL && + security_mode_complete != NULL) + { + // RRC Transaction ID + liblte_rrc_unpack_rrc_transaction_identifier_ie(&msg_ptr, + &security_mode_complete->rrc_transaction_id); + + // Extension choice + bool ext = liblte_bits_2_value(&msg_ptr, 1); + + // Optional indicator + liblte_rrc_warning_not_handled(liblte_bits_2_value(&msg_ptr, 1), __func__);; + + liblte_rrc_consume_noncrit_extension(ext, __func__, &msg_ptr); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + Message Name: Security Mode Command + + Description: Used to command the activation of AS security + + Document Reference: 36.331 v10.0.0 Section 6.2.2 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_security_mode_command_msg(LIBLTE_RRC_SECURITY_MODE_COMMAND_STRUCT *security_mode_cmd, + LIBLTE_BIT_MSG_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(security_mode_cmd != NULL && + msg != NULL) + { + // RRC Transaction ID + liblte_rrc_pack_rrc_transaction_identifier_ie(security_mode_cmd->rrc_transaction_id, + &msg_ptr); + + // Extension choice + liblte_value_2_bits(0, &msg_ptr, 1); + + // C1 choice + liblte_value_2_bits(0, &msg_ptr, 2); + + // Optional indicator + liblte_value_2_bits(0, &msg_ptr, 1); + + // Extension indicator + liblte_value_2_bits(0, &msg_ptr, 1); + + // Security Algorithms Config + liblte_rrc_pack_security_algorithm_config_ie(&security_mode_cmd->sec_algs, + &msg_ptr); + + // Fill in the number of bits used + msg->N_bits = msg_ptr - msg->msg; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_security_mode_command_msg(LIBLTE_BIT_MSG_STRUCT *msg, + LIBLTE_RRC_SECURITY_MODE_COMMAND_STRUCT *security_mode_cmd) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(msg_ptr != NULL && + security_mode_cmd != NULL) + { + // RRC Transaction ID + liblte_rrc_unpack_rrc_transaction_identifier_ie(&msg_ptr, + &security_mode_cmd->rrc_transaction_id); + + // Extension choice + bool ext = liblte_bits_2_value(&msg_ptr, 1); + + // C1 choice + liblte_bits_2_value(&msg_ptr, 2); + + // Optional indicator + liblte_rrc_warning_not_handled(liblte_bits_2_value(&msg_ptr, 1), __func__);; + + // Extension indicator + bool ext2 = liblte_bits_2_value(&msg_ptr, 1); + + liblte_rrc_consume_noncrit_extension(ext2, __func__, &msg_ptr); + + // Security Algorithms Config + liblte_rrc_unpack_security_algorithm_config_ie(&msg_ptr, + &security_mode_cmd->sec_algs); + + liblte_rrc_consume_noncrit_extension(ext, __func__, &msg_ptr); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + Message Name: RRC Connection Setup Complete + + Description: Used to confirm the successful completion of an RRC + connection + + Document Reference: 36.331 v10.0.0 Section 6.2.2 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_rrc_connection_setup_complete_msg(LIBLTE_RRC_CONNECTION_SETUP_COMPLETE_STRUCT *con_setup_complete, + LIBLTE_BIT_MSG_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(con_setup_complete != NULL && + msg != NULL) + { + // RRC Transaction ID + liblte_rrc_pack_rrc_transaction_identifier_ie(con_setup_complete->rrc_transaction_id, + &msg_ptr); + + // Extension choice + liblte_value_2_bits(0, &msg_ptr, 1); + + // C1 choice + liblte_value_2_bits(0, &msg_ptr, 2); + + // Optional indicators + liblte_value_2_bits(con_setup_complete->registered_mme_present, &msg_ptr, 1); + liblte_value_2_bits(0, &msg_ptr, 1); + + // Selected PLMN identity + liblte_value_2_bits(con_setup_complete->selected_plmn_id - 1, &msg_ptr, 3); + + // Registered MME + if(con_setup_complete->registered_mme_present) + { + // Optional indicator + liblte_value_2_bits(con_setup_complete->registered_mme.plmn_id_present, &msg_ptr, 1); + + // PLMN identity + if(con_setup_complete->registered_mme.plmn_id_present) + { + liblte_rrc_pack_plmn_identity_ie(&con_setup_complete->registered_mme.plmn_id, &msg_ptr); + } + + // MMEGI + liblte_value_2_bits(con_setup_complete->registered_mme.mmegi, &msg_ptr, 16); + + // MMEC + liblte_rrc_pack_mmec_ie(con_setup_complete->registered_mme.mmec, &msg_ptr); + } + + // Dedicated info NAS + liblte_rrc_pack_dedicated_info_nas_ie(&con_setup_complete->dedicated_info_nas, + &msg_ptr); + + // Fill in the number of bits used + msg->N_bits = msg_ptr - msg->msg; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_rrc_connection_setup_complete_msg(LIBLTE_BIT_MSG_STRUCT *msg, + LIBLTE_RRC_CONNECTION_SETUP_COMPLETE_STRUCT *con_setup_complete) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(msg != NULL && + con_setup_complete != NULL) + { + // RRC Transaction ID + liblte_rrc_unpack_rrc_transaction_identifier_ie(&msg_ptr, + &con_setup_complete->rrc_transaction_id); + + // Extension choice + bool ext = liblte_bits_2_value(&msg_ptr, 1); + + // C1 choice + liblte_bits_2_value(&msg_ptr, 2); + + // Optional indicators + con_setup_complete->registered_mme_present = liblte_bits_2_value(&msg_ptr, 1); + liblte_rrc_warning_not_handled(liblte_bits_2_value(&msg_ptr, 1), __func__);; + + // Selected PLMN identity + con_setup_complete->selected_plmn_id = liblte_bits_2_value(&msg_ptr, 3) + 1; + + // Registered MME + if(con_setup_complete->registered_mme_present) + { + // Optional indicator + con_setup_complete->registered_mme.plmn_id_present = liblte_bits_2_value(&msg_ptr, 1); + + // PLMN identity + if(con_setup_complete->registered_mme.plmn_id_present) + { + liblte_rrc_unpack_plmn_identity_ie(&msg_ptr, &con_setup_complete->registered_mme.plmn_id); + } + + // MMEGI + con_setup_complete->registered_mme.mmegi = liblte_bits_2_value(&msg_ptr, 16); + + // MMEC + liblte_rrc_unpack_mmec_ie(&msg_ptr, &con_setup_complete->registered_mme.mmec); + } + + // Dedicated info NAS + liblte_rrc_unpack_dedicated_info_nas_ie(&msg_ptr, + &con_setup_complete->dedicated_info_nas); + + liblte_rrc_consume_noncrit_extension(ext, __func__, &msg_ptr); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + Message Name: RRC Connection Setup + + Description: Used to establish SRB1 + + Document Reference: 36.331 v10.0.0 Section 6.2.2 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_rrc_connection_setup_msg(LIBLTE_RRC_CONNECTION_SETUP_STRUCT *con_setup, + LIBLTE_BIT_MSG_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(con_setup != NULL && + msg != NULL) + { + // RRC Transaction ID + liblte_rrc_pack_rrc_transaction_identifier_ie(con_setup->rrc_transaction_id, + &msg_ptr); + + // Extension choice + liblte_value_2_bits(0, &msg_ptr, 1); + + // C1 choice + liblte_value_2_bits(0, &msg_ptr, 3); + + // Optional indicator + liblte_value_2_bits(0, &msg_ptr, 1); + + // Radio Resource Config Dedicated + liblte_rrc_pack_rr_config_dedicated_ie(&con_setup->rr_cnfg, &msg_ptr); + + // Fill in the number of bits used + msg->N_bits = msg_ptr - msg->msg; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_rrc_connection_setup_msg(LIBLTE_BIT_MSG_STRUCT *msg, + LIBLTE_RRC_CONNECTION_SETUP_STRUCT *con_setup) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(msg != NULL && + con_setup != NULL) + { + // RRC Transaction ID + liblte_rrc_unpack_rrc_transaction_identifier_ie(&msg_ptr, + &con_setup->rrc_transaction_id); + + // Critical extension indicator + bool ext = liblte_bits_2_value(&msg_ptr, 1); + + // C1 choice + liblte_bits_2_value(&msg_ptr, 3); + + // Optional indicator + liblte_rrc_warning_not_handled(liblte_bits_2_value(&msg_ptr, 1), __func__);; + + // Radio Resource Config Dedicated + liblte_rrc_unpack_rr_config_dedicated_ie(&msg_ptr, &con_setup->rr_cnfg); + + liblte_rrc_consume_noncrit_extension(ext, __func__, &msg_ptr); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + Message Name: RRC Connection Request + + Description: Used to request the establishment of an RRC + connection + + Document Reference: 36.331 v10.0.0 Section 6.2.2 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_rrc_connection_request_msg(LIBLTE_RRC_CONNECTION_REQUEST_STRUCT *con_req, + LIBLTE_BIT_MSG_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + uint8 ext = false; + + if(con_req != NULL && + msg != NULL) + { + // Extension choice + liblte_value_2_bits(ext, &msg_ptr, 1); + + // UE Identity Type + liblte_value_2_bits(con_req->ue_id_type, &msg_ptr, 1); + + // UE Identity + if(LIBLTE_RRC_CON_REQ_UE_ID_TYPE_S_TMSI == con_req->ue_id_type) + { + liblte_rrc_pack_s_tmsi_ie((LIBLTE_RRC_S_TMSI_STRUCT *)&con_req->ue_id, + &msg_ptr); + }else{ // LIBLTE_RRC_CON_REQ_UE_ID_TYPE_RANDOM_VALUE == con_req->ue_id_type + liblte_value_2_bits((uint32)(con_req->ue_id.random >> 32), &msg_ptr, 8); + liblte_value_2_bits((uint32)(con_req->ue_id.random), &msg_ptr, 32); + } + + // Establishment Cause + liblte_value_2_bits(con_req->cause, &msg_ptr, 3); + + // Spare + liblte_value_2_bits(0, &msg_ptr, 1); + + // Fill in the number of bits used + msg->N_bits = msg_ptr - msg->msg; + + liblte_rrc_consume_noncrit_extension(ext, __func__, &msg_ptr); + + err = LIBLTE_SUCCESS; + + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_rrc_connection_request_msg(LIBLTE_BIT_MSG_STRUCT *msg, + LIBLTE_RRC_CONNECTION_REQUEST_STRUCT *con_req) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(msg != NULL && + con_req != NULL) + { + // Extension Choice + bool ext = liblte_bits_2_value(&msg_ptr, 1); + + // UE Identity Type + con_req->ue_id_type = (LIBLTE_RRC_CON_REQ_UE_ID_TYPE_ENUM)liblte_bits_2_value(&msg_ptr, 1); + + // UE Identity + if(LIBLTE_RRC_CON_REQ_UE_ID_TYPE_S_TMSI == con_req->ue_id_type) + { + liblte_rrc_unpack_s_tmsi_ie(&msg_ptr, + (LIBLTE_RRC_S_TMSI_STRUCT *)&con_req->ue_id); + }else{ // LIBLTE_RRC_CON_REQ_UE_ID_TYPE_RANDOM_VALUE == con_req->ue_id_type + con_req->ue_id.random = (uint64)liblte_bits_2_value(&msg_ptr, 8) << 32; + con_req->ue_id.random |= liblte_bits_2_value(&msg_ptr, 32); + } + + // Establishment Cause + con_req->cause = (LIBLTE_RRC_CON_REQ_EST_CAUSE_ENUM)liblte_bits_2_value(&msg_ptr, 3); + + liblte_rrc_consume_noncrit_extension(ext, __func__, &msg_ptr); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + Message Name: RRC Connection Release + + Description: Used to command the release of an RRC connection + + Document Reference: 36.331 v10.0.0 Section 6.2.2 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_rrc_connection_release_msg(LIBLTE_RRC_CONNECTION_RELEASE_STRUCT *con_release, + LIBLTE_BIT_MSG_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(con_release != NULL && + msg != NULL) + { + // RRC Transaction ID + liblte_rrc_pack_rrc_transaction_identifier_ie(con_release->rrc_transaction_id, + &msg_ptr); + + // Extension choice + liblte_value_2_bits(0, &msg_ptr, 1); + + // C1 choice + liblte_value_2_bits(0, &msg_ptr, 2); + + // Optional indicators + liblte_value_2_bits(0, &msg_ptr, 1); + liblte_value_2_bits(0, &msg_ptr, 1); + liblte_value_2_bits(0, &msg_ptr, 1); + + // Release cause + liblte_value_2_bits(con_release->release_cause, &msg_ptr, 2); + + // Fill in the number of bits used + msg->N_bits = msg_ptr - msg->msg; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_rrc_connection_release_msg(LIBLTE_BIT_MSG_STRUCT *msg, + LIBLTE_RRC_CONNECTION_RELEASE_STRUCT *con_release) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(msg != NULL && + con_release != NULL) + { + // RRC Transaction ID + liblte_rrc_unpack_rrc_transaction_identifier_ie(&msg_ptr, + &con_release->rrc_transaction_id); + + // Extension choice + bool ext = liblte_bits_2_value(&msg_ptr, 1); + + // C1 choice + liblte_bits_2_value(&msg_ptr, 2); + + // Optional indicators + liblte_rrc_warning_not_handled(liblte_bits_2_value(&msg_ptr, 1), __func__);; + liblte_rrc_warning_not_handled(liblte_bits_2_value(&msg_ptr, 1), __func__);; + liblte_rrc_warning_not_handled(liblte_bits_2_value(&msg_ptr, 1), __func__);; + + // Release cause + con_release->release_cause = (LIBLTE_RRC_RELEASE_CAUSE_ENUM)liblte_bits_2_value(&msg_ptr, 2); + + liblte_rrc_consume_noncrit_extension(ext, __func__, &msg_ptr); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + Message Name: RRC Connection Reject + + Description: Used to reject the RRC connection establishment + + Document Reference: 36.331 v10.0.0 Section 6.2.2 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_rrc_connection_reject_msg(LIBLTE_RRC_CONNECTION_REJECT_STRUCT *con_rej, + LIBLTE_BIT_MSG_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(con_rej != NULL && + msg != NULL) + { + // Extension choice + liblte_value_2_bits(0, &msg_ptr, 1); + + // C1 choice + liblte_value_2_bits(0, &msg_ptr, 2); + + // Optional indicator + liblte_value_2_bits(0, &msg_ptr, 1); + + // Wait Time + liblte_value_2_bits(con_rej->wait_time, &msg_ptr, 4); + + // Fill in the number of bits used + msg->N_bits = msg_ptr - msg->msg; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_rrc_connection_reject_msg(LIBLTE_BIT_MSG_STRUCT *msg, + LIBLTE_RRC_CONNECTION_REJECT_STRUCT *con_rej) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(msg != NULL && + con_rej != NULL) + { + // Extension choice + bool ext = liblte_bits_2_value(&msg_ptr, 1); + + // C1 choice + liblte_bits_2_value(&msg_ptr, 2); + + // Optional indicator + liblte_rrc_warning_not_handled(liblte_bits_2_value(&msg_ptr, 1), __func__);; + + // Wait Time + con_rej->wait_time = liblte_bits_2_value(&msg_ptr, 4); + + liblte_rrc_consume_noncrit_extension(ext, __func__, &msg_ptr); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + Message Name: RRC Connection Reestablishment Request + + Description: Used to request the reestablishment of an RRC + connection + + Document Reference: 36.331 v10.0.0 Section 6.2.2 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_rrc_connection_reestablishment_request_msg(LIBLTE_RRC_CONNECTION_REESTABLISHMENT_REQUEST_STRUCT *con_reest_req, + LIBLTE_BIT_MSG_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + uint8 ext = false; + + if(con_reest_req != NULL && + msg != NULL) + { + // Extension choice + liblte_value_2_bits(ext, &msg_ptr, 1); + + if(!ext) + { + // UE Identity + liblte_rrc_pack_c_rnti_ie((uint16)con_reest_req->ue_id.c_rnti, &msg_ptr); + liblte_rrc_pack_phys_cell_id_ie((uint16)con_reest_req->ue_id.phys_cell_id, &msg_ptr); + liblte_rrc_pack_short_mac_i_ie((uint16)con_reest_req->ue_id.short_mac_i, &msg_ptr); + + // Reestablishment Cause + liblte_value_2_bits(con_reest_req->cause, &msg_ptr, 2); + + // Spare + liblte_value_2_bits(0, &msg_ptr, 2); + + // Fill in the number of bits used + msg->N_bits = msg_ptr - msg->msg; + + err = LIBLTE_SUCCESS; + } + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_rrc_connection_reestablishment_request_msg(LIBLTE_BIT_MSG_STRUCT *msg, + LIBLTE_RRC_CONNECTION_REESTABLISHMENT_REQUEST_STRUCT *con_reest_req) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(msg != NULL && + con_reest_req != NULL) + { + // Extension Choice + bool ext = liblte_bits_2_value(&msg_ptr, 1); + + // UE Identity + liblte_rrc_unpack_c_rnti_ie(&msg_ptr, &con_reest_req->ue_id.c_rnti); + liblte_rrc_unpack_phys_cell_id_ie(&msg_ptr, &con_reest_req->ue_id.phys_cell_id); + liblte_rrc_unpack_short_mac_i_ie(&msg_ptr, &con_reest_req->ue_id.short_mac_i); + + // Reestablishment Cause + con_reest_req->cause = (LIBLTE_RRC_CON_REEST_REQ_CAUSE_ENUM)liblte_bits_2_value(&msg_ptr, 2); + + liblte_rrc_consume_noncrit_extension(ext, __func__, &msg_ptr); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + Message Name: RRC Connection Reestablishment Reject + + Description: Used to indicate the rejection of an RRC connection + reestablishment request + + Document Reference: 36.331 v10.0.0 Section 6.2.2 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_rrc_connection_reestablishment_reject_msg(LIBLTE_RRC_CONNECTION_REESTABLISHMENT_REJECT_STRUCT *con_reest_rej, + LIBLTE_BIT_MSG_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(con_reest_rej != NULL && + msg != NULL) + { + // Extension choice + liblte_value_2_bits(0, &msg_ptr, 1); + + // Optional indicator + liblte_value_2_bits(0, &msg_ptr, 1); + + // Fill in the number of bits used + msg->N_bits = msg_ptr - msg->msg; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_rrc_connection_reestablishment_reject_msg(LIBLTE_BIT_MSG_STRUCT *msg, + LIBLTE_RRC_CONNECTION_REESTABLISHMENT_REJECT_STRUCT *con_reest_rej) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(msg != NULL && + con_reest_rej != NULL) + { + // Extension choice + bool ext = liblte_bits_2_value(&msg_ptr, 1); + + // Optional indicator + liblte_rrc_warning_not_handled(liblte_bits_2_value(&msg_ptr, 1), __func__);; + + liblte_rrc_consume_noncrit_extension(ext, __func__, &msg_ptr); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + Message Name: RRC Connection Reestablishment Complete + + Description: Used to confirm the successful completion of an RRC + connection reestablishment + + Document Reference: 36.331 v10.0.0 Section 6.2.2 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_rrc_connection_reestablishment_complete_msg(LIBLTE_RRC_CONNECTION_REESTABLISHMENT_COMPLETE_STRUCT *con_reest_complete, + LIBLTE_BIT_MSG_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(con_reest_complete != NULL && + msg != NULL) + { + // RRC Transaction ID + liblte_rrc_pack_rrc_transaction_identifier_ie(con_reest_complete->rrc_transaction_id, + &msg_ptr); + + // Extension choice + liblte_value_2_bits(0, &msg_ptr, 1); + + // Optional indicator + liblte_value_2_bits(0, &msg_ptr, 1); + + // Fill in the number of bits used + msg->N_bits = msg_ptr - msg->msg; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_rrc_connection_reestablishment_complete_msg(LIBLTE_BIT_MSG_STRUCT *msg, + LIBLTE_RRC_CONNECTION_REESTABLISHMENT_COMPLETE_STRUCT *con_reest_complete) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(msg != NULL && + con_reest_complete != NULL) + { + // RRC Transaction ID + liblte_rrc_unpack_rrc_transaction_identifier_ie(&msg_ptr, + &con_reest_complete->rrc_transaction_id); + + // Extension choice + bool ext = liblte_bits_2_value(&msg_ptr, 1); + + // Optional indicator + liblte_rrc_warning_not_handled(liblte_bits_2_value(&msg_ptr, 1), __func__);; + + liblte_rrc_consume_noncrit_extension(ext, __func__, &msg_ptr); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + Message Name: RRC Connection Reestablishment + + Description: Used to resolve contention and to re-establish SRB1 + + Document Reference: 36.331 v10.0.0 Section 6.2.2 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_rrc_connection_reestablishment_msg(LIBLTE_RRC_CONNECTION_REESTABLISHMENT_STRUCT *con_reest, + LIBLTE_BIT_MSG_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(con_reest != NULL && + msg != NULL) + { + // RRC Transaction ID + liblte_rrc_pack_rrc_transaction_identifier_ie(con_reest->rrc_transaction_id, + &msg_ptr); + + // Extension choice + liblte_value_2_bits(0, &msg_ptr, 1); + + // C1 choice + liblte_value_2_bits(0, &msg_ptr, 3); + + // Optional indicator + liblte_value_2_bits(0, &msg_ptr, 1); + + // Radio Resource Config Dedicated + liblte_rrc_pack_rr_config_dedicated_ie(&con_reest->rr_cnfg, &msg_ptr); + + // Next Hop Chaining Count + liblte_rrc_pack_next_hop_chaining_count_ie(con_reest->next_hop_chaining_count, &msg_ptr); + + // Fill in the number of bits used + msg->N_bits = msg_ptr - msg->msg; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_rrc_connection_reestablishment_msg(LIBLTE_BIT_MSG_STRUCT *msg, + LIBLTE_RRC_CONNECTION_REESTABLISHMENT_STRUCT *con_reest) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(msg != NULL && + con_reest != NULL) + { + // RRC Transaction ID + liblte_rrc_unpack_rrc_transaction_identifier_ie(&msg_ptr, + &con_reest->rrc_transaction_id); + + // Extension choice + bool ext = liblte_bits_2_value(&msg_ptr, 1); + + // C1 choice + liblte_bits_2_value(&msg_ptr, 3); + + // Optional indicator + liblte_rrc_warning_not_handled(liblte_bits_2_value(&msg_ptr, 1), __func__);; + + // Radio Resource Config Dedicated + liblte_rrc_unpack_rr_config_dedicated_ie(&msg_ptr, &con_reest->rr_cnfg); + + // Next Hop Chaining Count + liblte_rrc_unpack_next_hop_chaining_count_ie(&msg_ptr, &con_reest->next_hop_chaining_count); + + liblte_rrc_consume_noncrit_extension(ext, __func__, &msg_ptr); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + Message Name: RRC Connection Reconfiguration Complete + + Description: Used to confirm the successful completion of an RRC + connection reconfiguration + + Document Reference: 36.331 v10.0.0 Section 6.2.2 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_rrc_connection_reconfiguration_complete_msg(LIBLTE_RRC_CONNECTION_RECONFIGURATION_COMPLETE_STRUCT *con_reconfig_complete, + LIBLTE_BIT_MSG_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(con_reconfig_complete != NULL && + msg != NULL) + { + // RRC Transaction ID + liblte_rrc_pack_rrc_transaction_identifier_ie(con_reconfig_complete->rrc_transaction_id, + &msg_ptr); + + // Extension choice + liblte_value_2_bits(0, &msg_ptr, 1); + + // Optional indicator + liblte_value_2_bits(0, &msg_ptr, 1); + + // Fill in the number of bits used + msg->N_bits = msg_ptr - msg->msg; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_rrc_connection_reconfiguration_complete_msg(LIBLTE_BIT_MSG_STRUCT *msg, + LIBLTE_RRC_CONNECTION_RECONFIGURATION_COMPLETE_STRUCT *con_reconfig_complete) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(msg != NULL && + con_reconfig_complete != NULL) + { + // RRC Transaction ID + liblte_rrc_unpack_rrc_transaction_identifier_ie(&msg_ptr, + &con_reconfig_complete->rrc_transaction_id); + + // Extension choice + bool ext = liblte_bits_2_value(&msg_ptr, 1); + + // Optional indicator + liblte_rrc_warning_not_handled(liblte_bits_2_value(&msg_ptr, 1), __func__);; + + liblte_rrc_consume_noncrit_extension(ext, __func__, &msg_ptr); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + Message Name: RRC Connection Reconfiguration + + Description: Modifies an RRC connection + + Document Reference: 36.331 v10.0.0 Section 6.2.2 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_rrc_connection_reconfiguration_msg(LIBLTE_RRC_CONNECTION_RECONFIGURATION_STRUCT *con_reconfig, + LIBLTE_BIT_MSG_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + uint32 i; + + if(con_reconfig != NULL && + msg != NULL) + { + // RRC Transaction ID + liblte_rrc_pack_rrc_transaction_identifier_ie(con_reconfig->rrc_transaction_id, &msg_ptr); + + // Extension choice + liblte_value_2_bits(0, &msg_ptr, 1); + + // C1 choice + liblte_value_2_bits(0, &msg_ptr, 3); + + // Optional indicators + liblte_value_2_bits(con_reconfig->meas_cnfg_present, &msg_ptr, 1); + liblte_value_2_bits(con_reconfig->mob_ctrl_info_present, &msg_ptr, 1); + if(0 == con_reconfig->N_ded_info_nas) + { + liblte_value_2_bits(0, &msg_ptr, 1); + }else{ + liblte_value_2_bits(1, &msg_ptr, 1); + } + liblte_value_2_bits(con_reconfig->rr_cnfg_ded_present, &msg_ptr, 1); + liblte_value_2_bits(con_reconfig->sec_cnfg_ho_present, &msg_ptr, 1); + liblte_value_2_bits(0, &msg_ptr, 1); + + // Meas Config + if(con_reconfig->meas_cnfg_present) + { + liblte_rrc_pack_meas_config_ie(&con_reconfig->meas_cnfg, &msg_ptr); + } + + // Mobility Control Info + if(con_reconfig->mob_ctrl_info_present) + { + liblte_rrc_pack_mobility_control_info_ie(&con_reconfig->mob_ctrl_info, &msg_ptr); + } + + // Dedicated Info NAS List + if(0 != con_reconfig->N_ded_info_nas) + { + liblte_value_2_bits(con_reconfig->N_ded_info_nas - 1, &msg_ptr, 4); + } + for(i=0; iN_ded_info_nas; i++) + { + liblte_rrc_pack_dedicated_info_nas_ie(&con_reconfig->ded_info_nas_list[i], &msg_ptr); + } + + // Radio Resource Config Dedicated + if(con_reconfig->rr_cnfg_ded_present) + { + liblte_rrc_pack_rr_config_dedicated_ie(&con_reconfig->rr_cnfg_ded, &msg_ptr); + } + + // Security Config HO + if(con_reconfig->sec_cnfg_ho_present) + { + // Extension indicator + liblte_value_2_bits(0, &msg_ptr, 1); + + // Handover Type + liblte_value_2_bits(con_reconfig->sec_cnfg_ho.ho_type, &msg_ptr, 1); + + if(LIBLTE_RRC_HANDOVER_TYPE_INTRA_LTE == con_reconfig->sec_cnfg_ho.ho_type) + { + // Optional indicator + liblte_value_2_bits(con_reconfig->sec_cnfg_ho.intra_lte.sec_alg_cnfg_present, &msg_ptr, 1); + + // Security Algorithm Config + if(con_reconfig->sec_cnfg_ho.intra_lte.sec_alg_cnfg_present) + { + liblte_rrc_pack_security_algorithm_config_ie(&con_reconfig->sec_cnfg_ho.intra_lte.sec_alg_cnfg, &msg_ptr); + } + + // Key Change Indicator + liblte_value_2_bits(con_reconfig->sec_cnfg_ho.intra_lte.key_change_ind, &msg_ptr, 1); + + // Next Hop Chaining Count + liblte_rrc_pack_next_hop_chaining_count_ie(con_reconfig->sec_cnfg_ho.intra_lte.next_hop_chaining_count, &msg_ptr); + }else{ + // Security Algorithm Config + liblte_rrc_pack_security_algorithm_config_ie(&con_reconfig->sec_cnfg_ho.inter_rat.sec_alg_cnfg, &msg_ptr); + + // NAS Security Params To EUTRA + for(i=0; i<6; i++) + { + liblte_value_2_bits(con_reconfig->sec_cnfg_ho.inter_rat.nas_sec_param_to_eutra[i], &msg_ptr, 8); + } + } + } + + // Fill in the number of bits used + msg->N_bits = msg_ptr - msg->msg; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_rrc_connection_reconfiguration_msg(LIBLTE_BIT_MSG_STRUCT *msg, + LIBLTE_RRC_CONNECTION_RECONFIGURATION_STRUCT *con_reconfig) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + uint32 i; + bool ded_info_nas_list_present; + + if(msg != NULL && + con_reconfig != NULL) + { + // RRC Transaction ID + liblte_rrc_unpack_rrc_transaction_identifier_ie(&msg_ptr, &con_reconfig->rrc_transaction_id); + + // Extension choice + bool ext = liblte_bits_2_value(&msg_ptr, 1); + + // C1 choice + liblte_bits_2_value(&msg_ptr, 3); + + // Optional indicators + con_reconfig->meas_cnfg_present = liblte_bits_2_value(&msg_ptr, 1); + con_reconfig->mob_ctrl_info_present = liblte_bits_2_value(&msg_ptr, 1); + ded_info_nas_list_present = liblte_bits_2_value(&msg_ptr, 1); + con_reconfig->rr_cnfg_ded_present = liblte_bits_2_value(&msg_ptr, 1); + con_reconfig->sec_cnfg_ho_present = liblte_bits_2_value(&msg_ptr, 1); + liblte_rrc_warning_not_handled(liblte_bits_2_value(&msg_ptr, 1), __func__);; + + // Meas Config + if(con_reconfig->meas_cnfg_present) + { + liblte_rrc_unpack_meas_config_ie(&msg_ptr, &con_reconfig->meas_cnfg); + } + + // Mobility Control Info + if(con_reconfig->mob_ctrl_info_present) + { + liblte_rrc_unpack_mobility_control_info_ie(&msg_ptr, &con_reconfig->mob_ctrl_info); + } + + // Dedicated Info NAS List + if(ded_info_nas_list_present) + { + con_reconfig->N_ded_info_nas = liblte_bits_2_value(&msg_ptr, 4) + 1; + for(i=0; iN_ded_info_nas; i++) + { + liblte_rrc_unpack_dedicated_info_nas_ie(&msg_ptr, &con_reconfig->ded_info_nas_list[i]); + } + }else{ + con_reconfig->N_ded_info_nas = 0; + } + + // Radio Resource Config Dedicated + if(con_reconfig->rr_cnfg_ded_present) + { + liblte_rrc_unpack_rr_config_dedicated_ie(&msg_ptr, &con_reconfig->rr_cnfg_ded); + } + + // Security Config HO + if(con_reconfig->sec_cnfg_ho_present) + { + // Extension indicator + bool ext2 = liblte_bits_2_value(&msg_ptr, 1); + + // Handover Type + con_reconfig->sec_cnfg_ho.ho_type = (LIBLTE_RRC_HANDOVER_TYPE_ENUM)liblte_bits_2_value(&msg_ptr, 1); + + if(LIBLTE_RRC_HANDOVER_TYPE_INTRA_LTE == con_reconfig->sec_cnfg_ho.ho_type) + { + // Optional indicator + con_reconfig->sec_cnfg_ho.intra_lte.sec_alg_cnfg_present = liblte_bits_2_value(&msg_ptr, 1); + + // Security Algorithm Config + if(con_reconfig->sec_cnfg_ho.intra_lte.sec_alg_cnfg_present) + { + liblte_rrc_unpack_security_algorithm_config_ie(&msg_ptr, &con_reconfig->sec_cnfg_ho.intra_lte.sec_alg_cnfg); + } + + // Key Change Indicator + con_reconfig->sec_cnfg_ho.intra_lte.key_change_ind = liblte_bits_2_value(&msg_ptr, 1); + + // Next Hop Chaining Count + liblte_rrc_unpack_next_hop_chaining_count_ie(&msg_ptr, &con_reconfig->sec_cnfg_ho.intra_lte.next_hop_chaining_count); + }else{ + // Security Algorithm Config + liblte_rrc_unpack_security_algorithm_config_ie(&msg_ptr, &con_reconfig->sec_cnfg_ho.inter_rat.sec_alg_cnfg); + + // NAS Security Params To EUTRA + for(i=0; i<6; i++) + { + con_reconfig->sec_cnfg_ho.inter_rat.nas_sec_param_to_eutra[i] = liblte_bits_2_value(&msg_ptr, 8); + } + } + + liblte_rrc_consume_noncrit_extension(ext2, __func__, &msg_ptr); + } + + liblte_rrc_consume_noncrit_extension(ext, __func__, &msg_ptr); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + Message Name: RN Reconfiguration Complete + + Description: Used to confirm the successful completion of an RN + reconfiguration + + Document Reference: 36.331 v10.0.0 Section 6.2.2 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_rn_reconfiguration_complete_msg(LIBLTE_RRC_RN_RECONFIGURATION_COMPLETE_STRUCT *rn_reconfig_complete, + LIBLTE_BIT_MSG_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(rn_reconfig_complete != NULL && + msg != NULL) + { + // RRC Transaction ID + liblte_rrc_pack_rrc_transaction_identifier_ie(rn_reconfig_complete->rrc_transaction_id, + &msg_ptr); + + // Extension choice + liblte_value_2_bits(0, &msg_ptr, 1); + + // C1 choice + liblte_value_2_bits(0, &msg_ptr, 2); + + // Optional indicators + liblte_value_2_bits(0, &msg_ptr, 1); + liblte_value_2_bits(0, &msg_ptr, 1); + + // Fill in the number of bits used + msg->N_bits = msg_ptr - msg->msg; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_rn_reconfiguration_complete_msg(LIBLTE_BIT_MSG_STRUCT *msg, + LIBLTE_RRC_RN_RECONFIGURATION_COMPLETE_STRUCT *rn_reconfig_complete) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(msg != NULL && + rn_reconfig_complete != NULL) + { + // RRC Transaction ID + liblte_rrc_unpack_rrc_transaction_identifier_ie(&msg_ptr, + &rn_reconfig_complete->rrc_transaction_id); + + // Extension choice + bool ext = liblte_bits_2_value(&msg_ptr, 1); + + // C1 choice + liblte_bits_2_value(&msg_ptr, 2); + + // Optional indicators + liblte_rrc_warning_not_handled(liblte_bits_2_value(&msg_ptr, 1), __func__);; + liblte_rrc_warning_not_handled(liblte_bits_2_value(&msg_ptr, 1), __func__);; + + liblte_rrc_consume_noncrit_extension(ext, __func__, &msg_ptr); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + Message Name: RN Reconfiguration + + Description: Modifies the RRC connection between the RN and the + E-UTRAN + + Document Reference: 36.331 v10.0.0 Section 6.2.2 +*********************************************************************/ +// FIXME + +/********************************************************************* + Message Name: Proximity Indication + + Description: Used to indicate that the UE is entering or leaving + the proximity of one or more cells whose CSG IDs are + in the UEs CSG whitelist + + Document Reference: 36.331 v10.0.0 Section 6.2.2 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_proximity_indication_msg(LIBLTE_RRC_PROXIMITY_INDICATION_STRUCT *proximity_ind, + LIBLTE_BIT_MSG_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(proximity_ind != NULL && + msg != NULL) + { + // Extension choice + liblte_value_2_bits(0, &msg_ptr, 1); + + // C1 choice + liblte_value_2_bits(0, &msg_ptr, 2); + + // Optional indicator + liblte_value_2_bits(0, &msg_ptr, 1); + + // Proximity indication type + liblte_value_2_bits(proximity_ind->type, &msg_ptr, 1); + + // Carrier frequency type extension indicator + liblte_value_2_bits(0, &msg_ptr, 1); + + // Carrier frequency choice + liblte_value_2_bits(proximity_ind->carrier_freq_type, &msg_ptr, 1); + + // Carrier frequency + if(LIBLTE_RRC_PROXIMITY_INDICATION_CARRIER_FREQ_TYPE_EUTRA == proximity_ind->carrier_freq_type) + { + liblte_rrc_pack_arfcn_value_eutra_ie(proximity_ind->carrier_freq, + &msg_ptr); + }else{ + liblte_rrc_pack_arfcn_value_utra_ie(proximity_ind->carrier_freq, + &msg_ptr); + } + + // Fill in the number of bits used + msg->N_bits = msg_ptr - msg->msg; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_proximity_indication_msg(LIBLTE_BIT_MSG_STRUCT *msg, + LIBLTE_RRC_PROXIMITY_INDICATION_STRUCT *proximity_ind) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(msg != NULL && + proximity_ind != NULL) + { + // Extension choice + bool ext = liblte_bits_2_value(&msg_ptr, 1); + + // C1 choice + liblte_bits_2_value(&msg_ptr, 2); + + // Optional indicator + liblte_rrc_warning_not_handled(liblte_bits_2_value(&msg_ptr, 1), __func__);; + + // Proximity indication type + proximity_ind->type = (LIBLTE_RRC_PROXIMITY_INDICATION_TYPE_ENUM)liblte_bits_2_value(&msg_ptr, 1); + + // Carrier frequency type extension indicator + liblte_rrc_warning_not_handled(liblte_bits_2_value(&msg_ptr, 1), __func__);; + + // Carrier frequency type + proximity_ind->carrier_freq_type = (LIBLTE_RRC_PROXIMITY_INDICATION_CARRIER_FREQ_TYPE_ENUM)liblte_bits_2_value(&msg_ptr, 1); + + // Carrier frequency + if(LIBLTE_RRC_PROXIMITY_INDICATION_CARRIER_FREQ_TYPE_EUTRA == proximity_ind->carrier_freq) + { + liblte_rrc_unpack_arfcn_value_eutra_ie(&msg_ptr, + &proximity_ind->carrier_freq); + }else{ + liblte_rrc_unpack_arfcn_value_utra_ie(&msg_ptr, + &proximity_ind->carrier_freq); + } + + liblte_rrc_consume_noncrit_extension(ext, __func__, &msg_ptr); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + Message Name: Paging + + Description: Used for the notification of one or more UEs + + Document Reference: 36.331 v10.0.0 Section 6.2.2 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_paging_msg(LIBLTE_RRC_PAGING_STRUCT *page, + LIBLTE_BIT_MSG_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + uint32 i; + uint32 j; + + if(page != NULL && + msg != NULL) + { + // Optional indicators + if(page->paging_record_list_size != 0) + { + liblte_value_2_bits(1, &msg_ptr, 1); + }else{ + liblte_value_2_bits(0, &msg_ptr, 1); + } + liblte_value_2_bits(page->system_info_modification_present, &msg_ptr, 1); + liblte_value_2_bits(page->etws_indication_present, &msg_ptr, 1); + liblte_value_2_bits(page->non_crit_ext_present, &msg_ptr, 1); + + if(page->paging_record_list_size != 0) + { + liblte_value_2_bits(page->paging_record_list_size - 1, &msg_ptr, 4); + for(i=0; ipaging_record_list_size; i++) + { + // Extension indicator + liblte_value_2_bits(0, &msg_ptr, 1); + + // Paging UE identity + { + // Extension indicator + liblte_value_2_bits(0, &msg_ptr, 1); + + liblte_value_2_bits(page->paging_record_list[i].ue_identity.ue_identity_type, &msg_ptr, 1); + if(LIBLTE_RRC_PAGING_UE_IDENTITY_TYPE_S_TMSI == page->paging_record_list[i].ue_identity.ue_identity_type) + { + liblte_rrc_pack_s_tmsi_ie(&page->paging_record_list[i].ue_identity.s_tmsi, + &msg_ptr); + }else{ + liblte_value_2_bits(page->paging_record_list[i].ue_identity.imsi_size - 6, &msg_ptr, 4); + for(j=0; jpaging_record_list[i].ue_identity.imsi_size; j++) + { + liblte_value_2_bits(page->paging_record_list[i].ue_identity.imsi[j], &msg_ptr, 4); + } + } + } + + liblte_value_2_bits(page->paging_record_list[i].cn_domain, &msg_ptr, 1); + } + } + + if(page->system_info_modification_present) + { + liblte_value_2_bits(page->system_info_modification, &msg_ptr, 1); + } + + if(page->etws_indication_present) + { + liblte_value_2_bits(page->etws_indication, &msg_ptr, 1); + } + + if(page->non_crit_ext_present) + { + // Optional indicators + liblte_value_2_bits(page->non_crit_ext.late_non_crit_ext_present, &msg_ptr, 1); + liblte_value_2_bits(page->non_crit_ext.non_crit_ext_present, &msg_ptr, 1); + + if(page->non_crit_ext.late_non_crit_ext_present) + { + // FIXME + } + + if(page->non_crit_ext.non_crit_ext_present) + { + // Optional indicators + liblte_value_2_bits(page->non_crit_ext.non_crit_ext.cmas_ind_present, &msg_ptr, 1); + liblte_value_2_bits(page->non_crit_ext.non_crit_ext.non_crit_ext_present, &msg_ptr, 1); + + if(page->non_crit_ext.non_crit_ext.cmas_ind_present) + { + liblte_value_2_bits(page->non_crit_ext.non_crit_ext.cmas_ind_r9, &msg_ptr, 1); + } + + if(page->non_crit_ext.non_crit_ext.non_crit_ext_present) + { + // FIXME + } + } + } + + // Fill in the number of bits used + msg->N_bits = msg_ptr - msg->msg; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_paging_msg(LIBLTE_BIT_MSG_STRUCT *msg, + LIBLTE_RRC_PAGING_STRUCT *page) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + uint32 i; + uint32 j; + uint8 paging_record_list_present; + + if(msg != NULL && + page != NULL) + { + // Optional indicators + paging_record_list_present = liblte_bits_2_value(&msg_ptr, 1); + page->system_info_modification_present = liblte_bits_2_value(&msg_ptr, 1); + page->etws_indication_present = liblte_bits_2_value(&msg_ptr, 1); + page->non_crit_ext_present = liblte_bits_2_value(&msg_ptr, 1); + + if(paging_record_list_present) + { + page->paging_record_list_size = liblte_bits_2_value(&msg_ptr, 4) + 1; + for(i=0; ipaging_record_list_size; i++) + { + // Extension indicator + bool ext = liblte_bits_2_value(&msg_ptr, 1); + + // Paging UE identity + { + // Extension indicator + bool ext2 = liblte_bits_2_value(&msg_ptr, 1); + + page->paging_record_list[i].ue_identity.ue_identity_type = (LIBLTE_RRC_PAGING_UE_IDENTITY_TYPE_ENUM)liblte_bits_2_value(&msg_ptr, 1); + if(LIBLTE_RRC_PAGING_UE_IDENTITY_TYPE_S_TMSI == page->paging_record_list[i].ue_identity.ue_identity_type) + { + liblte_rrc_unpack_s_tmsi_ie(&msg_ptr, + &page->paging_record_list[i].ue_identity.s_tmsi); + }else{ + page->paging_record_list[i].ue_identity.imsi_size = liblte_bits_2_value(&msg_ptr, 4) + 6; + for(j=0; jpaging_record_list[i].ue_identity.imsi_size; j++) + { + page->paging_record_list[i].ue_identity.imsi[j] = liblte_bits_2_value(&msg_ptr, 4); + } + } + + liblte_rrc_consume_noncrit_extension(ext2, __func__, &msg_ptr); + } + + page->paging_record_list[i].cn_domain = (LIBLTE_RRC_CN_DOMAIN_ENUM)liblte_bits_2_value(&msg_ptr, 1); + + liblte_rrc_consume_noncrit_extension(ext, __func__, &msg_ptr); + } + } + + if(page->system_info_modification_present) + { + page->system_info_modification = (LIBLTE_RRC_SYSTEM_INFO_MODIFICATION_ENUM)liblte_bits_2_value(&msg_ptr, 1); + } + + if(page->etws_indication_present) + { + page->etws_indication = (LIBLTE_RRC_ETWS_INDICATION_ENUM)liblte_bits_2_value(&msg_ptr, 1); + } + + if(page->non_crit_ext_present) + { + // Optional indicators + page->non_crit_ext.late_non_crit_ext_present = liblte_bits_2_value(&msg_ptr, 1); + page->non_crit_ext.non_crit_ext_present = liblte_bits_2_value(&msg_ptr, 1); + + if(page->non_crit_ext.late_non_crit_ext_present) + { + // FIXME + printf("Warning late non-crit-extension not handled in paging message\n"); + } + + if(page->non_crit_ext.non_crit_ext_present) + { + // Optional indicators + page->non_crit_ext.non_crit_ext.cmas_ind_present = liblte_bits_2_value(&msg_ptr, 1); + page->non_crit_ext.non_crit_ext.non_crit_ext_present = liblte_bits_2_value(&msg_ptr, 1); + + if(page->non_crit_ext.non_crit_ext.cmas_ind_present) + { + page->non_crit_ext.non_crit_ext.cmas_ind_r9 = (LIBLTE_RRC_CMAS_INDICATION_R9_ENUM)liblte_bits_2_value(&msg_ptr, 1); + } + + if(page->non_crit_ext.non_crit_ext.non_crit_ext_present) + { + // FIXME + printf("Warning non-crit-extension not handled in paging message\n"); + } + } + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + Message Name: Mobility From EUTRA Command + + Description: Used to command handover or a cell change from E-UTRA + to another RAT, or enhanced CS fallback to CDMA2000 + 1xRTT + + Document Reference: 36.331 v10.0.0 Section 6.2.2 +*********************************************************************/ +// FIXME + +/********************************************************************* + Message Name: Measurement Report + + Description: Used for the indication of measurement results + + Document Reference: 36.331 v10.0.0 Section 6.2.2 +*********************************************************************/ +// FIXME + +/********************************************************************* + Message Name: MBSFN Area Configuration + + Description: Contains the MBMS control information applicable for + an MBSFN area + + Document Reference: 36.331 v10.0.0 Section 6.2.2 +*********************************************************************/ +// FIXME + +/********************************************************************* + Message Name: Master Information Block + + Description: Includes the system information transmitted on BCH + + Document Reference: 36.331 v10.0.0 Section 6.2.2 +*********************************************************************/ +// Inlined with BCCH BCH Message + +/********************************************************************* + Message Name: Logged Measurements Configuration + + Description: Used by E-UTRAN to configure the UE to perform + logging of measurement results while in RRC_IDLE + + Document Reference: 36.331 v10.0.0 Section 6.2.2 +*********************************************************************/ +// FIXME + +/********************************************************************* + Message Name: Handover From EUTRA Preparation Request (CDMA2000) + + Description: Used to trigger the handover preparation procedure + with a CDMA2000 RAT + + Document Reference: 36.331 v10.0.0 Section 6.2.2 +*********************************************************************/ +// FIXME + +/********************************************************************* + Message Name: DL Information Transfer + + Description: Used for the downlink transfer of dedicated NAS + information + + Document Reference: 36.331 v10.0.0 Section 6.2.2 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_dl_information_transfer_msg(LIBLTE_RRC_DL_INFORMATION_TRANSFER_STRUCT *dl_info_transfer, + LIBLTE_BIT_MSG_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(dl_info_transfer != NULL && + msg != NULL) + { + // RRC Transaction ID + liblte_rrc_pack_rrc_transaction_identifier_ie(dl_info_transfer->rrc_transaction_id, + &msg_ptr); + + // Extension choice + liblte_value_2_bits(0, &msg_ptr, 1); + + // C1 choice + liblte_value_2_bits(0, &msg_ptr, 2); + + // Optional indicator + liblte_value_2_bits(0, &msg_ptr, 1); + + // Dedicated info type choice + liblte_value_2_bits(dl_info_transfer->dedicated_info_type, &msg_ptr, 2); + + if(LIBLTE_RRC_DL_INFORMATION_TRANSFER_TYPE_NAS == dl_info_transfer->dedicated_info_type) + { + liblte_rrc_pack_dedicated_info_nas_ie(&dl_info_transfer->dedicated_info, + &msg_ptr); + }else{ + liblte_rrc_pack_dedicated_info_cdma2000_ie(&dl_info_transfer->dedicated_info, + &msg_ptr); + } + + // Fill in the number of bits used + msg->N_bits = msg_ptr - msg->msg; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_dl_information_transfer_msg(LIBLTE_BIT_MSG_STRUCT *msg, + LIBLTE_RRC_DL_INFORMATION_TRANSFER_STRUCT *dl_info_transfer) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(msg != NULL && + dl_info_transfer != NULL) + { + // RRC Transaction ID + liblte_rrc_unpack_rrc_transaction_identifier_ie(&msg_ptr, + &dl_info_transfer->rrc_transaction_id); + + // Extension choice + bool ext = liblte_bits_2_value(&msg_ptr, 1); + + // C1 choice + liblte_bits_2_value(&msg_ptr, 2); + + // Optional indicator + liblte_rrc_warning_not_handled(liblte_bits_2_value(&msg_ptr, 1), __func__);; + + // Dedicated info type choice + dl_info_transfer->dedicated_info_type = (LIBLTE_RRC_DL_INFORMATION_TRANSFER_TYPE_ENUM)liblte_bits_2_value(&msg_ptr, 2); + + if(LIBLTE_RRC_DL_INFORMATION_TRANSFER_TYPE_NAS == dl_info_transfer->dedicated_info_type) + { + liblte_rrc_unpack_dedicated_info_nas_ie(&msg_ptr, + &dl_info_transfer->dedicated_info); + }else{ + liblte_rrc_unpack_dedicated_info_cdma2000_ie(&msg_ptr, + &dl_info_transfer->dedicated_info); + } + + liblte_rrc_consume_noncrit_extension(ext, __func__, &msg_ptr); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + Message Name: CSFB Parameters Response CDMA2000 + + Description: Used to provide the CDMA2000 1xRTT parameters to the + UE so the UE can register with the CDMA2000 1xRTT + network to support CSFB to CDMA2000 1xRTT + + Document Reference: 36.331 v10.0.0 Section 6.2.2 +*********************************************************************/ +// FIXME + +/********************************************************************* + Message Name: CSFB Parameters Request CDMA2000 + + Description: Used by the UE to obtain the CDMA2000 1xRTT + parameters from the network + + Document Reference: 36.331 v10.0.0 Section 6.2.2 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_csfb_parameters_request_cdma2000_msg(LIBLTE_RRC_CSFB_PARAMETERS_REQUEST_CDMA2000_STRUCT *csfb_params_req_cdma2000, + LIBLTE_BIT_MSG_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(csfb_params_req_cdma2000 != NULL && + msg != NULL) + { + // Extension choice + liblte_value_2_bits(0, &msg_ptr, 1); + + // Optional indicator + liblte_value_2_bits(0, &msg_ptr, 1); + + // Fill in the number of bits used + msg->N_bits = msg_ptr - msg->msg; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_csfb_parameters_request_cdma2000_msg(LIBLTE_BIT_MSG_STRUCT *msg, + LIBLTE_RRC_CSFB_PARAMETERS_REQUEST_CDMA2000_STRUCT *csfb_params_req_cdma2000) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(msg != NULL && + csfb_params_req_cdma2000 != NULL) + { + // Extension choice + bool ext = liblte_bits_2_value(&msg_ptr, 1); + + // Optional indicator + liblte_rrc_warning_not_handled(liblte_bits_2_value(&msg_ptr, 1), __func__);; + + liblte_rrc_consume_noncrit_extension(ext, __func__, &msg_ptr); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + Message Name: Counter Check Response + + Description: Used by the UE to respond to a Counter Check message + + Document Reference: 36.331 v10.0.0 Section 6.2.2 +*********************************************************************/ +// FIXME + +/********************************************************************* + Message Name: Counter Check + + Description: Used by the E-UTRAN to indicate the current COUNT MSB + values associated to each DRB and to request the UE + to compare these to its COUNT MSB values and to + report the comparison results to E-UTRAN + + Document Reference: 36.331 v10.0.0 Section 6.2.2 +*********************************************************************/ +// FIXME + +/********************************************************************* + Message Name: BCCH BCH Message + + Description: Contains the set of RRC messages that may be sent + from the E-UTRAN to the UE via BCH on the BCCH + logical channel + + Document Reference: 36.331 v10.0.0 Sections 6.2.1 and 6.2.2 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_bcch_bch_msg(LIBLTE_RRC_MIB_STRUCT *mib, + LIBLTE_BIT_MSG_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(mib != NULL && + msg != NULL) + { + // DL Bandwidth + liblte_value_2_bits(mib->dl_bw, &msg_ptr, 3); + + // PHICH Config + liblte_rrc_pack_phich_config_ie(&mib->phich_config, &msg_ptr); + + // SFN/4 + liblte_value_2_bits(mib->sfn_div_4, &msg_ptr, 8); + + // Spare + liblte_value_2_bits(0, &msg_ptr, 10); + + // Fill in the number of bits used + msg->N_bits = msg_ptr - msg->msg; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_bcch_bch_msg(LIBLTE_BIT_MSG_STRUCT *msg, + LIBLTE_RRC_MIB_STRUCT *mib) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(msg != NULL && + mib != NULL) + { + // DL Bandwidth + mib->dl_bw = (LIBLTE_RRC_DL_BANDWIDTH_ENUM)liblte_bits_2_value(&msg_ptr, 3); + + // PHICH Config + liblte_rrc_unpack_phich_config_ie(&msg_ptr, &mib->phich_config); + + // SFN/4 + mib->sfn_div_4 = liblte_bits_2_value(&msg_ptr, 8); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + Message Name: BCCH DLSCH Message + + Description: Contains the set of RRC messages that may be sent + from the E-UTRAN to the UE via DLSCH on the BCCH + logical channel + + Document Reference: 36.331 v10.0.0 Section 6.2.1 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_bcch_dlsch_msg(LIBLTE_RRC_BCCH_DLSCH_MSG_STRUCT *bcch_dlsch_msg, + LIBLTE_BIT_MSG_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + uint8 ext = false; + + if(bcch_dlsch_msg != NULL && + msg != NULL) + { + // Extension indicator + liblte_value_2_bits(ext, &msg_ptr, 1); + + if(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1 == bcch_dlsch_msg->sibs[0].sib_type) + { + // SIB1 Choice + liblte_value_2_bits(1, &msg_ptr, 1); + + err = liblte_rrc_pack_sys_info_block_type_1_msg((LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1_STRUCT *)&bcch_dlsch_msg->sibs[0].sib, + &global_msg); + if(global_msg.N_bits <= (LIBLTE_MAX_MSG_SIZE_BITS - 2)) + { + memcpy(msg_ptr, global_msg.msg, global_msg.N_bits); + msg->N_bits = global_msg.N_bits + 2; + }else{ + msg->N_bits = 0; + err = LIBLTE_ERROR_INVALID_INPUTS; + } + }else{ + // SIB1 Choice + liblte_value_2_bits(0, &msg_ptr, 1); + + err = liblte_rrc_pack_sys_info_msg(bcch_dlsch_msg, + &global_msg); + if(global_msg.N_bits <= (LIBLTE_MAX_MSG_SIZE_BITS - 2)) + { + memcpy(msg_ptr, global_msg.msg, global_msg.N_bits); + msg->N_bits = global_msg.N_bits + 2; + }else{ + msg->N_bits = 0; + err = LIBLTE_ERROR_INVALID_INPUTS; + } + } + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_bcch_dlsch_msg(LIBLTE_BIT_MSG_STRUCT *msg, + LIBLTE_RRC_BCCH_DLSCH_MSG_STRUCT *bcch_dlsch_msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + uint32 N_bits_used; + uint8 ext; + + if(msg != NULL && + bcch_dlsch_msg != NULL) + { + // Extension indicator + ext = liblte_bits_2_value(&msg_ptr, 1); + + // SIB1 Choice + if(true == liblte_bits_2_value(&msg_ptr, 1)) + { + bcch_dlsch_msg->N_sibs = 1; + bcch_dlsch_msg->sibs[0].sib_type = LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1; + if((msg->N_bits-(msg_ptr-msg->msg)) <= (LIBLTE_MAX_MSG_SIZE_BITS - 2)) + { + memcpy(global_msg.msg, msg_ptr, msg->N_bits-(msg_ptr-msg->msg)); + global_msg.N_bits = msg->N_bits-(msg_ptr-msg->msg); + err = liblte_rrc_unpack_sys_info_block_type_1_msg(&global_msg, + (LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1_STRUCT *)&bcch_dlsch_msg->sibs[0].sib, + &N_bits_used); + msg_ptr += N_bits_used; + } + }else{ + if((msg->N_bits-(msg_ptr-msg->msg)) <= (LIBLTE_MAX_MSG_SIZE_BITS - 2)) + { + memcpy(global_msg.msg, msg_ptr, msg->N_bits-(msg_ptr-msg->msg)); + err = liblte_rrc_unpack_sys_info_msg(&global_msg, + bcch_dlsch_msg); + } + } + + liblte_rrc_consume_noncrit_extension(ext, __func__, &msg_ptr); + } + + return(err); +} + +/********************************************************************* + Message Name: PCCH Message + + Description: Contains the set of RRC messages that may be sent + from the E-UTRAN to the UE on the PCCH logical + channel + + Document Reference: 36.331 v10.0.0 Section 6.2.1 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_pcch_msg(LIBLTE_RRC_PCCH_MSG_STRUCT *pcch_msg, + LIBLTE_BIT_MSG_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + uint8 ext = false; + + if(pcch_msg != NULL && + msg != NULL) + { + // Paging choice + liblte_value_2_bits(0, &msg_ptr, 1); + + err = liblte_rrc_pack_paging_msg(pcch_msg, + &global_msg); + if(global_msg.N_bits <= (LIBLTE_MAX_MSG_SIZE_BITS - 1)) + { + memcpy(msg_ptr, global_msg.msg, global_msg.N_bits); + msg->N_bits = global_msg.N_bits + 1; + }else{ + msg->N_bits = 0; + err = LIBLTE_ERROR_INVALID_INPUTS; + } + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_pcch_msg(LIBLTE_BIT_MSG_STRUCT *msg, + LIBLTE_RRC_PCCH_MSG_STRUCT *pcch_msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + uint32 N_bits_used; + + if(msg != NULL && + pcch_msg != NULL) + { + // Paging choice + liblte_rrc_warning_not_handled(liblte_bits_2_value(&msg_ptr, 1), __func__);; + + if((msg->N_bits-(msg_ptr-msg->msg)) <= (LIBLTE_MAX_MSG_SIZE_BITS - 1)) + { + memcpy(global_msg.msg, msg_ptr, msg->N_bits-(msg_ptr-msg->msg)); + err = liblte_rrc_unpack_paging_msg(&global_msg, + pcch_msg); + } + } + + return(err); +} + +/********************************************************************* + Message Name: DL CCCH Message + + Description: Contains the set of RRC messages that may be sent + from the E-UTRAN to the UE on the downlink CCCH + logical channel + + Document Reference: 36.331 v10.0.0 Section 6.2.1 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_dl_ccch_msg(LIBLTE_RRC_DL_CCCH_MSG_STRUCT *dl_ccch_msg, + LIBLTE_BIT_MSG_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + uint8 ext = false; + + if(dl_ccch_msg != NULL && + msg != NULL) + { + // Extension indicator + liblte_value_2_bits(ext, &msg_ptr, 1); + + // Message type choice + liblte_value_2_bits(dl_ccch_msg->msg_type, &msg_ptr, 2); + + if(LIBLTE_RRC_DL_CCCH_MSG_TYPE_RRC_CON_REEST == dl_ccch_msg->msg_type) + { + err = liblte_rrc_pack_rrc_connection_reestablishment_msg((LIBLTE_RRC_CONNECTION_REESTABLISHMENT_STRUCT *)&dl_ccch_msg->msg, + &global_msg); + }else if(LIBLTE_RRC_DL_CCCH_MSG_TYPE_RRC_CON_REEST_REJ == dl_ccch_msg->msg_type){ + err = liblte_rrc_pack_rrc_connection_reestablishment_reject_msg((LIBLTE_RRC_CONNECTION_REESTABLISHMENT_REJECT_STRUCT *)&dl_ccch_msg->msg, + &global_msg); + }else if(LIBLTE_RRC_DL_CCCH_MSG_TYPE_RRC_CON_REJ == dl_ccch_msg->msg_type){ + err = liblte_rrc_pack_rrc_connection_reject_msg((LIBLTE_RRC_CONNECTION_REJECT_STRUCT *)&dl_ccch_msg->msg, + &global_msg); + }else{ // LIBLTE_RRC_DL_CCCH_MSG_TYPE_RRC_CON_SETUP == dl_ccch_msg->msg_type + err = liblte_rrc_pack_rrc_connection_setup_msg((LIBLTE_RRC_CONNECTION_SETUP_STRUCT *)&dl_ccch_msg->msg, + &global_msg); + } + + if(global_msg.N_bits <= (LIBLTE_MAX_MSG_SIZE_BITS - 3)) + { + memcpy(msg_ptr, global_msg.msg, global_msg.N_bits); + msg->N_bits = global_msg.N_bits + 3; + }else{ + msg->N_bits = 0; + err = LIBLTE_ERROR_INVALID_INPUTS; + } + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_dl_ccch_msg(LIBLTE_BIT_MSG_STRUCT *msg, + LIBLTE_RRC_DL_CCCH_MSG_STRUCT *dl_ccch_msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + uint8 ext; + + if(msg != NULL && + dl_ccch_msg != NULL) + { + // Extension indicator + ext = liblte_bits_2_value(&msg_ptr, 1); + + // Message type choice + dl_ccch_msg->msg_type = (LIBLTE_RRC_DL_CCCH_MSG_TYPE_ENUM)liblte_bits_2_value(&msg_ptr, 2); + + // Message + memcpy(global_msg.msg, msg_ptr, msg->N_bits-(msg_ptr-msg->msg)); + global_msg.N_bits = msg->N_bits-(msg_ptr-msg->msg); + if(LIBLTE_RRC_DL_CCCH_MSG_TYPE_RRC_CON_REEST == dl_ccch_msg->msg_type) + { + err = liblte_rrc_unpack_rrc_connection_reestablishment_msg(&global_msg, + (LIBLTE_RRC_CONNECTION_REESTABLISHMENT_STRUCT *)&dl_ccch_msg->msg); + }else if(LIBLTE_RRC_DL_CCCH_MSG_TYPE_RRC_CON_REEST_REJ == dl_ccch_msg->msg_type){ + err = liblte_rrc_unpack_rrc_connection_reestablishment_reject_msg(&global_msg, + (LIBLTE_RRC_CONNECTION_REESTABLISHMENT_REJECT_STRUCT *)&dl_ccch_msg->msg); + }else if(LIBLTE_RRC_DL_CCCH_MSG_TYPE_RRC_CON_REJ == dl_ccch_msg->msg_type){ + err = liblte_rrc_unpack_rrc_connection_reject_msg(&global_msg, + (LIBLTE_RRC_CONNECTION_REJECT_STRUCT *)&dl_ccch_msg->msg); + }else{ // LIBLTE_RRC_DL_CCCH_MSG_TYPE_RRC_CON_SETUP == dl_ccch_msg->msg_type + err = liblte_rrc_unpack_rrc_connection_setup_msg(&global_msg, + (LIBLTE_RRC_CONNECTION_SETUP_STRUCT *)&dl_ccch_msg->msg); + } + + liblte_rrc_consume_noncrit_extension(ext, __func__, &msg_ptr); + } + + return(err); +} + +/********************************************************************* + Message Name: DL DCCH Message + + Description: Contains the set of RRC messages that may be sent + from the E-UTRAN to the UE on the downlink DCCH + logical channel + + Document Reference: 36.331 v10.0.0 Section 6.2.1 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_dl_dcch_msg(LIBLTE_RRC_DL_DCCH_MSG_STRUCT *dl_dcch_msg, + LIBLTE_BIT_MSG_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + uint8 ext = false; + + if(dl_dcch_msg != NULL && + msg != NULL) + { + // Extension indicator + liblte_value_2_bits(ext, &msg_ptr, 1); + + // Message type choice + liblte_value_2_bits(dl_dcch_msg->msg_type, &msg_ptr, 4); + + // Message + if(LIBLTE_RRC_DL_DCCH_MSG_TYPE_CSFB_PARAMS_RESP_CDMA2000 == dl_dcch_msg->msg_type) + { + printf("NOT HANDLING CSFB PARAMETERS RESPONSE CDMA2000\n"); +// err = liblte_rrc_pack_csfb_parameters_response_cdma2000_msg((LIBLTE_RRC_CSFB_PARAMETERS_RESPONSE_CDMA2000_STRUCT *)&dl_dcch_msg->msg, +// &global_msg); + }else if(LIBLTE_RRC_DL_DCCH_MSG_TYPE_DL_INFO_TRANSFER == dl_dcch_msg->msg_type){ + err = liblte_rrc_pack_dl_information_transfer_msg((LIBLTE_RRC_DL_INFORMATION_TRANSFER_STRUCT *)&dl_dcch_msg->msg, + &global_msg); + }else if(LIBLTE_RRC_DL_DCCH_MSG_TYPE_HANDOVER_FROM_EUTRA_PREP_REQ == dl_dcch_msg->msg_type){ + printf("NOT HANDLING HANDOVER FROM EUTRA PREPARATION REQUEST\n"); +// err = liblte_rrc_pack_handover_from_eutra_preparation_request_msg((LIBLTE_RRC_HANDOVER_FROM_EUTRA_PREPARATION_REQUEST_STRUCT *)&dl_dcch_msg->msg, +// &global_msg); + }else if(LIBLTE_RRC_DL_DCCH_MSG_TYPE_MOBILITY_FROM_EUTRA_COMMAND == dl_dcch_msg->msg_type){ + printf("NOT HANDLING MOBILITY FROM EUTRA COMMAND\n"); +// err = liblte_rrc_pack_mobility_from_eutra_command_msg((LIBLTE_RRC_MOBILITY_FROM_EUTRA_COMMAND_STRUCT *)&dl_dcch_msg->msg, +// &global_msg); + }else if(LIBLTE_RRC_DL_DCCH_MSG_TYPE_RRC_CON_RECONFIG == dl_dcch_msg->msg_type){ + err = liblte_rrc_pack_rrc_connection_reconfiguration_msg((LIBLTE_RRC_CONNECTION_RECONFIGURATION_STRUCT *)&dl_dcch_msg->msg, + &global_msg); + }else if(LIBLTE_RRC_DL_DCCH_MSG_TYPE_RRC_CON_RELEASE == dl_dcch_msg->msg_type){ + err = liblte_rrc_pack_rrc_connection_release_msg((LIBLTE_RRC_CONNECTION_RELEASE_STRUCT *)&dl_dcch_msg->msg, + &global_msg); + }else if(LIBLTE_RRC_DL_DCCH_MSG_TYPE_SECURITY_MODE_COMMAND == dl_dcch_msg->msg_type){ + err = liblte_rrc_pack_security_mode_command_msg((LIBLTE_RRC_SECURITY_MODE_COMMAND_STRUCT *)&dl_dcch_msg->msg, + &global_msg); + }else if(LIBLTE_RRC_DL_DCCH_MSG_TYPE_UE_CAPABILITY_ENQUIRY == dl_dcch_msg->msg_type){ + err = liblte_rrc_pack_ue_capability_enquiry_msg((LIBLTE_RRC_UE_CAPABILITY_ENQUIRY_STRUCT *)&dl_dcch_msg->msg, + &global_msg); + }else if(LIBLTE_RRC_DL_DCCH_MSG_TYPE_COUNTER_CHECK == dl_dcch_msg->msg_type){ + printf("NOT HANDLING COUNTER CHECK\n"); +// err = liblte_rrc_pack_counter_check_msg((LIBLTE_RRC_COUNTER_CHECK_STRUCT *)&dl_dcch_msg->msg, +// &global_msg); + }else if(LIBLTE_RRC_DL_DCCH_MSG_TYPE_UE_INFO_REQ == dl_dcch_msg->msg_type){ + err = liblte_rrc_pack_ue_information_request_msg((LIBLTE_RRC_UE_INFORMATION_REQUEST_STRUCT *)&dl_dcch_msg->msg, + &global_msg); + }else if(LIBLTE_RRC_DL_DCCH_MSG_TYPE_LOGGED_MEASUREMENTS_CONFIG == dl_dcch_msg->msg_type){ + printf("NOT HANDLING LOGGED MEASUREMENTS CONFIGURATION\n"); +// err = liblte_rrc_pack_logged_measurements_configuration_msg((LIBLTE_RRC_LOGGED_MEASUREMENTS_CONFIGURATION_STRUCT *)&dl_dcch_msg->msg, +// &global_msg); + }else{ // LIBLTE_RRC_DL_DCCH_MSG_TYPE_RN_RECONFIG == dl_dcch_msg->msg_type + printf("NOT HANDLING RN RECONFIGURATION\n"); +// err = liblte_rrc_pack_rn_reconfiguration_msg((LIBLTE_RRC_RN_RECONFIGURATION_STRUCT *)&dl_dcch_msg->msg, +// &global_msg); + } + + if(global_msg.N_bits <= (LIBLTE_MAX_MSG_SIZE_BITS - 5)) + { + memcpy(msg_ptr, global_msg.msg, global_msg.N_bits); + msg->N_bits = global_msg.N_bits + 5; + }else{ + msg->N_bits = 0; + err = LIBLTE_ERROR_INVALID_INPUTS; + } + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_dl_dcch_msg(LIBLTE_BIT_MSG_STRUCT *msg, + LIBLTE_RRC_DL_DCCH_MSG_STRUCT *dl_dcch_msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + uint8 ext; + + if(msg != NULL && + dl_dcch_msg != NULL) + { + // Extension indicator + ext = liblte_bits_2_value(&msg_ptr, 1); + + // Message type choice + dl_dcch_msg->msg_type = (LIBLTE_RRC_DL_DCCH_MSG_TYPE_ENUM)liblte_bits_2_value(&msg_ptr, 4); + + // Message + memcpy(global_msg.msg, msg_ptr, msg->N_bits-(msg_ptr-msg->msg)); + global_msg.N_bits = msg->N_bits-(msg_ptr-msg->msg); + if(LIBLTE_RRC_DL_DCCH_MSG_TYPE_CSFB_PARAMS_RESP_CDMA2000 == dl_dcch_msg->msg_type) + { + printf("NOT HANDLING CSFB PARAMETERS RESPONSE CDMA2000\n"); +// err = liblte_rrc_unpack_csfb_parameters_response_cdma2000_msg(&global_msg, +// (LIBLTE_RRC_CSFB_PARAMETERS_RESPONSE_CDMA2000_STRUCT *)&dl_dcch_msg->msg); + }else if(LIBLTE_RRC_DL_DCCH_MSG_TYPE_DL_INFO_TRANSFER == dl_dcch_msg->msg_type){ + err = liblte_rrc_unpack_dl_information_transfer_msg(&global_msg, + (LIBLTE_RRC_DL_INFORMATION_TRANSFER_STRUCT *)&dl_dcch_msg->msg); + }else if(LIBLTE_RRC_DL_DCCH_MSG_TYPE_HANDOVER_FROM_EUTRA_PREP_REQ == dl_dcch_msg->msg_type){ + printf("NOT HANDLING HANDOVER FROM EUTRA PREPARATION REQUEST\n"); +// err = liblte_rrc_unpack_handover_from_eutra_preparation_request_msg(&global_msg, +// (LIBLTE_RRC_HANDOVER_FROM_EUTRA_PREPARATION_REQUEST_STRUCT *)&dl_dcch_msg->msg); + }else if(LIBLTE_RRC_DL_DCCH_MSG_TYPE_MOBILITY_FROM_EUTRA_COMMAND == dl_dcch_msg->msg_type){ + printf("NOT HANDLING MOBILITY FROM EUTRA COMMAND\n"); +// err = liblte_rrc_unpack_mobility_from_eutra_command_msg(&global_msg, +// (LIBLTE_RRC_MOBILITY_FROM_EUTRA_COMMAND_STRUCT *)&dl_dcch_msg->msg); + }else if(LIBLTE_RRC_DL_DCCH_MSG_TYPE_RRC_CON_RECONFIG == dl_dcch_msg->msg_type){ + err = liblte_rrc_unpack_rrc_connection_reconfiguration_msg(&global_msg, + (LIBLTE_RRC_CONNECTION_RECONFIGURATION_STRUCT *)&dl_dcch_msg->msg); + }else if(LIBLTE_RRC_DL_DCCH_MSG_TYPE_RRC_CON_RELEASE == dl_dcch_msg->msg_type){ + err = liblte_rrc_unpack_rrc_connection_release_msg(&global_msg, + (LIBLTE_RRC_CONNECTION_RELEASE_STRUCT *)&dl_dcch_msg->msg); + }else if(LIBLTE_RRC_DL_DCCH_MSG_TYPE_SECURITY_MODE_COMMAND == dl_dcch_msg->msg_type){ + err = liblte_rrc_unpack_security_mode_command_msg(&global_msg, + (LIBLTE_RRC_SECURITY_MODE_COMMAND_STRUCT *)&dl_dcch_msg->msg); + }else if(LIBLTE_RRC_DL_DCCH_MSG_TYPE_UE_CAPABILITY_ENQUIRY == dl_dcch_msg->msg_type){ + err = liblte_rrc_unpack_ue_capability_enquiry_msg(&global_msg, + (LIBLTE_RRC_UE_CAPABILITY_ENQUIRY_STRUCT *)&dl_dcch_msg->msg); + }else if(LIBLTE_RRC_DL_DCCH_MSG_TYPE_COUNTER_CHECK == dl_dcch_msg->msg_type){ + printf("NOT HANDLING COUNTER CHECK\n"); +// err = liblte_rrc_unpack_counter_check_msg(&global_msg, +// (LIBLTE_RRC_COUNTER_CHECK_STRUCT *)&dl_dcch_msg->msg); + }else if(LIBLTE_RRC_DL_DCCH_MSG_TYPE_UE_INFO_REQ == dl_dcch_msg->msg_type){ + err = liblte_rrc_unpack_ue_information_request_msg(&global_msg, + (LIBLTE_RRC_UE_INFORMATION_REQUEST_STRUCT *)&dl_dcch_msg->msg); + }else if(LIBLTE_RRC_DL_DCCH_MSG_TYPE_LOGGED_MEASUREMENTS_CONFIG == dl_dcch_msg->msg_type){ + printf("NOT HANDLING LOGGED MEASUREMENTS CONFIGURATION\n"); +// err = liblte_rrc_unpack_logged_measurements_configuration_msg(&global_msg, +// (LIBLTE_RRC_LOGGED_MEASUREMENTS_CONFIGURATION_STRUCT *)&dl_dcch_msg->msg); + }else{ // LIBLTE_RRC_DL_DCCH_MSG_TYPE_RN_RECONFIG == dl_dcch_msg->msg_type + printf("NOT HANDLING RN RECONFIGURATION\n"); +// err = liblte_rrc_unpack_rn_reconfiguration_msg(&global_msg, +// (LIBLTE_RRC_RN_RECONFIGURATION_STRUCT *)&dl_dcch_msg->msg); + } + + liblte_rrc_consume_noncrit_extension(ext, __func__, &msg_ptr); + } + + return(err); +} + +/********************************************************************* + Message Name: UL CCCH Message + + Description: Contains the set of RRC messages that may be sent + from the UE to the E-UTRAN on the uplink CCCH + logical channel + + Document Reference: 36.331 v10.0.0 Section 6.2.1 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_ul_ccch_msg(LIBLTE_RRC_UL_CCCH_MSG_STRUCT *ul_ccch_msg, + LIBLTE_BIT_MSG_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + uint8 ext = false; + + if(ul_ccch_msg != NULL && + msg != NULL) + { + // Extension indicator + liblte_value_2_bits(ext, &msg_ptr, 1); + + // Message type choice + liblte_value_2_bits(ul_ccch_msg->msg_type, &msg_ptr, 1); + + if(LIBLTE_RRC_UL_CCCH_MSG_TYPE_RRC_CON_REEST_REQ == ul_ccch_msg->msg_type) + { + err = liblte_rrc_pack_rrc_connection_reestablishment_request_msg((LIBLTE_RRC_CONNECTION_REESTABLISHMENT_REQUEST_STRUCT *)&ul_ccch_msg->msg, + &global_msg); + }else{ // LIBLTE_RRC_UL_CCCH_MSG_TYPE_RRC_CON_REQ == ul_ccch_msg->msg_type + err = liblte_rrc_pack_rrc_connection_request_msg((LIBLTE_RRC_CONNECTION_REQUEST_STRUCT *)&ul_ccch_msg->msg, + &global_msg); + } + + if(global_msg.N_bits <= (LIBLTE_MAX_MSG_SIZE_BITS - 2)) + { + memcpy(msg_ptr, global_msg.msg, global_msg.N_bits); + msg->N_bits = global_msg.N_bits + 2; + }else{ + msg->N_bits = 0; + err = LIBLTE_ERROR_INVALID_INPUTS; + } + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_ul_ccch_msg(LIBLTE_BIT_MSG_STRUCT *msg, + LIBLTE_RRC_UL_CCCH_MSG_STRUCT *ul_ccch_msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + uint8 ext; + + if(msg != NULL && + ul_ccch_msg != NULL) + { + // Extension indicator + ext = liblte_bits_2_value(&msg_ptr, 1); + + // Message type choice + ul_ccch_msg->msg_type = (LIBLTE_RRC_UL_CCCH_MSG_TYPE_ENUM)liblte_bits_2_value(&msg_ptr, 1); + + // Message + memcpy(global_msg.msg, msg_ptr, msg->N_bits-(msg_ptr-msg->msg)); + global_msg.N_bits = msg->N_bits-(msg_ptr-msg->msg); + if(LIBLTE_RRC_UL_CCCH_MSG_TYPE_RRC_CON_REEST_REQ == ul_ccch_msg->msg_type) + { + err = liblte_rrc_unpack_rrc_connection_reestablishment_request_msg(&global_msg, + (LIBLTE_RRC_CONNECTION_REESTABLISHMENT_REQUEST_STRUCT *)&ul_ccch_msg->msg); + }else{ // LIBLTE_RRC_UL_CCCH_MSG_TYPE_RRC_CON_REQ == ul_ccch_msg->msg_type + err = liblte_rrc_unpack_rrc_connection_request_msg(&global_msg, + (LIBLTE_RRC_CONNECTION_REQUEST_STRUCT *)&ul_ccch_msg->msg); + } + + liblte_rrc_consume_noncrit_extension(ext, __func__, &msg_ptr); + } + + return(err); +} + +/********************************************************************* + Message Name: UL DCCH Message + + Description: Contains the set of RRC messages that may be sent + from the UE to the E-UTRAN on the uplink DCCH + logical channel + + Document Reference: 36.331 v10.0.0 Section 6.2.1 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_rrc_pack_ul_dcch_msg(LIBLTE_RRC_UL_DCCH_MSG_STRUCT *ul_dcch_msg, + LIBLTE_BIT_MSG_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + uint8 ext = false; + + if(ul_dcch_msg != NULL && + msg != NULL) + { + // Extension indicator + liblte_value_2_bits(ext, &msg_ptr, 1); + + // Message type choice + liblte_value_2_bits(ul_dcch_msg->msg_type, &msg_ptr, 4); + + // Message + if(LIBLTE_RRC_UL_DCCH_MSG_TYPE_CSFB_PARAMS_REQ_CDMA2000 == ul_dcch_msg->msg_type) + { + err = liblte_rrc_pack_csfb_parameters_request_cdma2000_msg((LIBLTE_RRC_CSFB_PARAMETERS_REQUEST_CDMA2000_STRUCT *)&ul_dcch_msg->msg, + &global_msg); + }else if(LIBLTE_RRC_UL_DCCH_MSG_TYPE_MEASUREMENT_REPORT == ul_dcch_msg->msg_type){ + printf("NOT HANDLING MEASUREMENT REPORT\n"); +// err = liblte_rrc_pack_measurement_report_msg((LIBLTE_RRC_MEASUREMENT_REPORT_STRUCT *)&ul_dcch_msg->msg, +// &global_msg); + }else if(LIBLTE_RRC_UL_DCCH_MSG_TYPE_RRC_CON_RECONFIG_COMPLETE == ul_dcch_msg->msg_type){ + err = liblte_rrc_pack_rrc_connection_reconfiguration_complete_msg((LIBLTE_RRC_CONNECTION_RECONFIGURATION_COMPLETE_STRUCT *)&ul_dcch_msg->msg, + &global_msg); + }else if(LIBLTE_RRC_UL_DCCH_MSG_TYPE_RRC_CON_REEST_COMPLETE == ul_dcch_msg->msg_type){ + err = liblte_rrc_pack_rrc_connection_reestablishment_complete_msg((LIBLTE_RRC_CONNECTION_REESTABLISHMENT_COMPLETE_STRUCT *)&ul_dcch_msg->msg, + &global_msg); + }else if(LIBLTE_RRC_UL_DCCH_MSG_TYPE_RRC_CON_SETUP_COMPLETE == ul_dcch_msg->msg_type){ + err = liblte_rrc_pack_rrc_connection_setup_complete_msg((LIBLTE_RRC_CONNECTION_SETUP_COMPLETE_STRUCT *)&ul_dcch_msg->msg, + &global_msg); + }else if(LIBLTE_RRC_UL_DCCH_MSG_TYPE_SECURITY_MODE_COMPLETE == ul_dcch_msg->msg_type){ + err = liblte_rrc_pack_security_mode_complete_msg((LIBLTE_RRC_SECURITY_MODE_COMPLETE_STRUCT *)&ul_dcch_msg->msg, + &global_msg); + }else if(LIBLTE_RRC_UL_DCCH_MSG_TYPE_SECURITY_MODE_FAILURE == ul_dcch_msg->msg_type){ + err = liblte_rrc_pack_security_mode_failure_msg((LIBLTE_RRC_SECURITY_MODE_FAILURE_STRUCT *)&ul_dcch_msg->msg, + &global_msg); + }else if(LIBLTE_RRC_UL_DCCH_MSG_TYPE_UE_CAPABILITY_INFO == ul_dcch_msg->msg_type){ + err = liblte_rrc_pack_ue_capability_information_msg((LIBLTE_RRC_UE_CAPABILITY_INFORMATION_STRUCT *)&ul_dcch_msg->msg, + &global_msg); + }else if(LIBLTE_RRC_UL_DCCH_MSG_TYPE_UL_HANDOVER_PREP_TRANSFER == ul_dcch_msg->msg_type){ + printf("NOT HANDLING UL HANDOVER PREPARATION TRANSFER\n"); +// err = liblte_rrc_pack_ul_handover_preparation_transfer_msg((LIBLTE_RRC_UL_HANDOVER_PREPARATION_TRANSFER_STRUCT *)&ul_dcch_msg->msg, +// &global_msg); + }else if(LIBLTE_RRC_UL_DCCH_MSG_TYPE_UL_INFO_TRANSFER == ul_dcch_msg->msg_type){ + err = liblte_rrc_pack_ul_information_transfer_msg((LIBLTE_RRC_UL_INFORMATION_TRANSFER_STRUCT *)&ul_dcch_msg->msg, + &global_msg); + }else if(LIBLTE_RRC_UL_DCCH_MSG_TYPE_COUNTER_CHECK_RESP == ul_dcch_msg->msg_type){ + printf("NOT HANDLING COUNTER CHECK RESPONSE\n"); +// err = liblte_rrc_pack_counter_check_response_msg((LIBLTE_RRC_COUNTER_CHECK_RESPONSE_STRUCT *)&ul_dcch_msg->msg, +// &global_msg); + }else if(LIBLTE_RRC_UL_DCCH_MSG_TYPE_UE_INFO_RESP == ul_dcch_msg->msg_type){ + printf("NOT HANDLING UE INFORMATION RESPONSE\n"); +// err = liblte_rrc_pack_ue_information_response_msg((LIBLTE_RRC_UE_INFORMATION_RESPONSE_STRUCT *)&ul_dcch_msg->msg, +// &global_msg); + }else if(LIBLTE_RRC_UL_DCCH_MSG_TYPE_PROXIMITY_IND == ul_dcch_msg->msg_type){ + err = liblte_rrc_pack_proximity_indication_msg((LIBLTE_RRC_PROXIMITY_INDICATION_STRUCT *)&ul_dcch_msg->msg, + &global_msg); + }else{ // LIBLTE_RRC_UL_DCCH_MSG_TYPE_RN_RECONFIG_COMPLETE == ul_dcch_msg->msg_type + err = liblte_rrc_pack_rn_reconfiguration_complete_msg((LIBLTE_RRC_RN_RECONFIGURATION_COMPLETE_STRUCT *)&ul_dcch_msg->msg, + &global_msg); + } + + if(global_msg.N_bits <= (LIBLTE_MAX_MSG_SIZE_BITS - 5)) + { + memcpy(msg_ptr, global_msg.msg, global_msg.N_bits); + msg->N_bits = global_msg.N_bits + 5; + }else{ + msg->N_bits = 0; + err = LIBLTE_ERROR_INVALID_INPUTS; + } + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_ul_dcch_msg(LIBLTE_BIT_MSG_STRUCT *msg, + LIBLTE_RRC_UL_DCCH_MSG_STRUCT *ul_dcch_msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + uint8 ext; + + if(msg != NULL && + ul_dcch_msg != NULL) + { + // Extension indicator + ext = liblte_bits_2_value(&msg_ptr, 1); + + // Message type choice + ul_dcch_msg->msg_type = (LIBLTE_RRC_UL_DCCH_MSG_TYPE_ENUM)liblte_bits_2_value(&msg_ptr, 4); + + // Message + memcpy(global_msg.msg, msg_ptr, msg->N_bits-(msg_ptr-msg->msg)); + global_msg.N_bits = msg->N_bits-(msg_ptr-msg->msg); + if(LIBLTE_RRC_UL_DCCH_MSG_TYPE_CSFB_PARAMS_REQ_CDMA2000 == ul_dcch_msg->msg_type) + { + err = liblte_rrc_unpack_csfb_parameters_request_cdma2000_msg(&global_msg, + (LIBLTE_RRC_CSFB_PARAMETERS_REQUEST_CDMA2000_STRUCT *)&ul_dcch_msg->msg); + }else if(LIBLTE_RRC_UL_DCCH_MSG_TYPE_MEASUREMENT_REPORT == ul_dcch_msg->msg_type){ + printf("NOT HANDLING MEASUREMENT REPORT\n"); +// err = liblte_rrc_unpack_measurement_report_msg(&global_msg, +// (LIBLTE_RRC_MEASUREMENT_REPORT_STRUCT *)&ul_dcch_msg->msg); + }else if(LIBLTE_RRC_UL_DCCH_MSG_TYPE_RRC_CON_RECONFIG_COMPLETE == ul_dcch_msg->msg_type){ + err = liblte_rrc_unpack_rrc_connection_reconfiguration_complete_msg(&global_msg, + (LIBLTE_RRC_CONNECTION_RECONFIGURATION_COMPLETE_STRUCT *)&ul_dcch_msg->msg); + }else if(LIBLTE_RRC_UL_DCCH_MSG_TYPE_RRC_CON_REEST_COMPLETE == ul_dcch_msg->msg_type){ + err = liblte_rrc_unpack_rrc_connection_reestablishment_complete_msg(&global_msg, + (LIBLTE_RRC_CONNECTION_REESTABLISHMENT_COMPLETE_STRUCT *)&ul_dcch_msg->msg); + }else if(LIBLTE_RRC_UL_DCCH_MSG_TYPE_RRC_CON_SETUP_COMPLETE == ul_dcch_msg->msg_type){ + err = liblte_rrc_unpack_rrc_connection_setup_complete_msg(&global_msg, + (LIBLTE_RRC_CONNECTION_SETUP_COMPLETE_STRUCT *)&ul_dcch_msg->msg); + }else if(LIBLTE_RRC_UL_DCCH_MSG_TYPE_SECURITY_MODE_COMPLETE == ul_dcch_msg->msg_type){ + err = liblte_rrc_unpack_security_mode_complete_msg(&global_msg, + (LIBLTE_RRC_SECURITY_MODE_COMPLETE_STRUCT *)&ul_dcch_msg->msg); + }else if(LIBLTE_RRC_UL_DCCH_MSG_TYPE_SECURITY_MODE_FAILURE == ul_dcch_msg->msg_type){ + err = liblte_rrc_unpack_security_mode_failure_msg(&global_msg, + (LIBLTE_RRC_SECURITY_MODE_FAILURE_STRUCT *)&ul_dcch_msg->msg); + }else if(LIBLTE_RRC_UL_DCCH_MSG_TYPE_UE_CAPABILITY_INFO == ul_dcch_msg->msg_type){ + printf("NOT HANDLING UE CAPABILITY INFO\n"); +// err = liblte_rrc_unpack_ue_capability_information_msg(&global_msg, +// (LIBLTE_RRC_UE_CAPABILITY_INFORMATION_STRUCT *)&ul_dcch_msg->msg); + }else if(LIBLTE_RRC_UL_DCCH_MSG_TYPE_UL_HANDOVER_PREP_TRANSFER == ul_dcch_msg->msg_type){ + printf("NOT HANDLING UL HANDOVER PREPARATION TRANSFER\n"); +// err = liblte_rrc_unpack_ul_handover_preparation_transfer_msg(&global_msg, +// (LIBLTE_RRC_UL_HANDOVER_PREPARATION_TRANSFER_STRUCT *)&ul_dcch_msg->msg); + }else if(LIBLTE_RRC_UL_DCCH_MSG_TYPE_UL_INFO_TRANSFER == ul_dcch_msg->msg_type){ + err = liblte_rrc_unpack_ul_information_transfer_msg(&global_msg, + (LIBLTE_RRC_UL_INFORMATION_TRANSFER_STRUCT *)&ul_dcch_msg->msg); + }else if(LIBLTE_RRC_UL_DCCH_MSG_TYPE_COUNTER_CHECK_RESP == ul_dcch_msg->msg_type){ + printf("NOT HANDLING COUNTER CHECK RESPONSE\n"); +// err = liblte_rrc_unpack_counter_check_response_msg(&global_msg, +// (LIBLTE_RRC_COUNTER_CHECK_RESPONSE_STRUCT *)&ul_dcch_msg->msg); + }else if(LIBLTE_RRC_UL_DCCH_MSG_TYPE_UE_INFO_RESP == ul_dcch_msg->msg_type){ + printf("NOT HANDLING UE INFORMATION RESPONSE\n"); +// err = liblte_rrc_unpack_ue_information_response_msg(&global_msg, +// (LIBLTE_RRC_UE_INFORMATION_RESPONSE_STRUCT *)&ul_dcch_msg->msg); + }else if(LIBLTE_RRC_UL_DCCH_MSG_TYPE_PROXIMITY_IND == ul_dcch_msg->msg_type){ + err = liblte_rrc_unpack_proximity_indication_msg(&global_msg, + (LIBLTE_RRC_PROXIMITY_INDICATION_STRUCT *)&ul_dcch_msg->msg); + }else{ // LIBLTE_RRC_UL_DCCH_MSG_TYPE_RN_RECONFIG_COMPLETE == ul_dcch_msg->msg_type + err = liblte_rrc_unpack_rn_reconfiguration_complete_msg(&global_msg, + (LIBLTE_RRC_RN_RECONFIGURATION_COMPLETE_STRUCT *)&ul_dcch_msg->msg); + } + + liblte_rrc_consume_noncrit_extension(ext, __func__, &msg_ptr); + + } + + return(err); +} diff --git a/lib/src/asn1/liblte_s1ap.cc b/lib/src/asn1/liblte_s1ap.cc new file mode 100644 index 000000000..31c7391ab --- /dev/null +++ b/lib/src/asn1/liblte_s1ap.cc @@ -0,0 +1,44052 @@ +/******************************************************************************* +/* +/* Copyright 2016 Software Radio Systems Limited +/* +********************************************************************************/ + +#include "srslte/asn1/liblte_s1ap.h" +# include +# include +# include + +/******************************************************************************* + LOGGING +*******************************************************************************/ + +static log_handler_t log_handler; +static void *callback_ctx = NULL; + +void liblte_log_register_handler(void *ctx, log_handler_t handler) { + log_handler = handler; + callback_ctx = ctx; +} + +static void liblte_log_print(const char *format, ...) { + va_list args; + va_start(args, format); + if (log_handler) { + char *args_msg = NULL; + if(vasprintf(&args_msg, format, args) > 0) { + log_handler(callback_ctx, args_msg); + } + if (args_msg) { + free(args_msg); + } + } else { + vprintf(format, args); + } + va_end(args); +} + +/******************************************************************************* +/* ProtocolIE Criticality ENUMERATED +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_criticality( + LIBLTE_S1AP_CRITICALITY_ENUM *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Enum - *ie + liblte_value_2_bits(*ie, ptr, 2); + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_criticality( + uint8_t **ptr, + LIBLTE_S1AP_CRITICALITY_ENUM *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Enum - *ie + *ie = (LIBLTE_S1AP_CRITICALITY_ENUM)liblte_bits_2_value(ptr, 2); + err = LIBLTE_SUCCESS; + } + return err; +} + + +/******************************************************************************* +/* ProtocolIE local INTEGER +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_local( + LIBLTE_S1AP_LOCAL_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Integer - ie->local + // lb:0, ub:65535 + liblte_align_up_zero(ptr, 8); + liblte_value_2_bits(0, ptr, (2*8)-16); + liblte_value_2_bits(ie->local, ptr, 16); + liblte_align_up_zero(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_local( + uint8_t **ptr, + LIBLTE_S1AP_LOCAL_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Integer - ie->local + // lb:0, ub:65535 + liblte_align_up(ptr, 8); + ie->local = (uint16_t)liblte_bits_2_value(ptr, 2.0*8); + liblte_align_up(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + + +/******************************************************************************* +/* ProtocolIE PrivateIE_ID CHOICE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_privateie_id( + LIBLTE_S1AP_PRIVATEIE_ID_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Choice type + liblte_value_2_bits(ie->choice_type, ptr, 1); + + // Choice + if(ie->choice_type == LIBLTE_S1AP_PRIVATEIE_ID_CHOICE_LOCAL) { + if(liblte_s1ap_pack_local(&ie->choice.local, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(ie->choice_type == LIBLTE_S1AP_PRIVATEIE_ID_CHOICE_GLOBAL) { + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_privateie_id( + uint8_t **ptr, + LIBLTE_S1AP_PRIVATEIE_ID_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Choice type + ie->choice_type = (LIBLTE_S1AP_PRIVATEIE_ID_CHOICE_ENUM)liblte_bits_2_value(ptr, 1); + + // Choice + if(ie->choice_type == LIBLTE_S1AP_PRIVATEIE_ID_CHOICE_LOCAL) { + if(liblte_s1ap_unpack_local(ptr, &ie->choice.local) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(ie->choice_type == LIBLTE_S1AP_PRIVATEIE_ID_CHOICE_GLOBAL) { + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE ProtocolExtensionID INTEGER +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_protocolextensionid( + LIBLTE_S1AP_PROTOCOLEXTENSIONID_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Integer - ie->ProtocolExtensionID + // lb:0, ub:65535 + liblte_align_up_zero(ptr, 8); + liblte_value_2_bits(0, ptr, (2*8)-16); + liblte_value_2_bits(ie->ProtocolExtensionID, ptr, 16); + liblte_align_up_zero(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_protocolextensionid( + uint8_t **ptr, + LIBLTE_S1AP_PROTOCOLEXTENSIONID_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Integer - ie->ProtocolExtensionID + // lb:0, ub:65535 + liblte_align_up(ptr, 8); + ie->ProtocolExtensionID = (uint16_t)liblte_bits_2_value(ptr, 2.0*8); + liblte_align_up(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE TriggeringMessage ENUMERATED +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_triggeringmessage( + LIBLTE_S1AP_TRIGGERINGMESSAGE_ENUM *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Enum - *ie + liblte_value_2_bits(*ie, ptr, 2); + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_triggeringmessage( + uint8_t **ptr, + LIBLTE_S1AP_TRIGGERINGMESSAGE_ENUM *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Enum - *ie + *ie = (LIBLTE_S1AP_TRIGGERINGMESSAGE_ENUM)liblte_bits_2_value(ptr, 2); + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE Presence ENUMERATED +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_presence( + LIBLTE_S1AP_PRESENCE_ENUM *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Enum - *ie + liblte_value_2_bits(*ie, ptr, 2); + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_presence( + uint8_t **ptr, + LIBLTE_S1AP_PRESENCE_ENUM *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Enum - *ie + *ie = (LIBLTE_S1AP_PRESENCE_ENUM)liblte_bits_2_value(ptr, 2); + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE ProtocolIE_ID INTEGER +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_protocolie_id( + LIBLTE_S1AP_PROTOCOLIE_ID_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Integer - ie->ProtocolIE_ID + // lb:0, ub:65535 + liblte_align_up_zero(ptr, 8); + liblte_value_2_bits(0, ptr, (2*8)-16); + liblte_value_2_bits(ie->ProtocolIE_ID, ptr, 16); + liblte_align_up_zero(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_protocolie_id( + uint8_t **ptr, + LIBLTE_S1AP_PROTOCOLIE_ID_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Integer - ie->ProtocolIE_ID + // lb:0, ub:65535 + liblte_align_up(ptr, 8); + ie->ProtocolIE_ID = (uint16_t)liblte_bits_2_value(ptr, 2.0*8); + liblte_align_up(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE ProcedureCode INTEGER +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_procedurecode( + LIBLTE_S1AP_PROCEDURECODE_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Integer - ie->ProcedureCode + // lb:0, ub:255 + liblte_align_up_zero(ptr, 8); + liblte_value_2_bits(0, ptr, (1*8)-8); + liblte_value_2_bits(ie->ProcedureCode, ptr, 8); + liblte_align_up_zero(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_procedurecode( + uint8_t **ptr, + LIBLTE_S1AP_PROCEDURECODE_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Integer - ie->ProcedureCode + // lb:0, ub:255 + liblte_align_up(ptr, 8); + ie->ProcedureCode = (uint8_t)liblte_bits_2_value(ptr, 1.0*8); + liblte_align_up(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE ProtocolIE_Field SEQUENCE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_protocolie_field( + LIBLTE_S1AP_PROTOCOLIE_FIELD_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + + if(liblte_s1ap_pack_protocolie_id(&ie->id, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // Enum - ie->criticality + liblte_value_2_bits(ie->criticality, ptr, 2); + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_protocolie_field( + uint8_t **ptr, + LIBLTE_S1AP_PROTOCOLIE_FIELD_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + + if(liblte_s1ap_unpack_protocolie_id(ptr, &ie->id) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + // Enum - ie->criticality + ie->criticality = (LIBLTE_S1AP_CRITICALITY_ENUM)liblte_bits_2_value(ptr, 2); + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE ProtocolExtensionField SEQUENCE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_protocolextensionfield( + LIBLTE_S1AP_PROTOCOLEXTENSIONFIELD_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + + if(liblte_s1ap_pack_protocolextensionid(&ie->id, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // Enum - ie->criticality + liblte_value_2_bits(ie->criticality, ptr, 2); + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_protocolextensionfield( + uint8_t **ptr, + LIBLTE_S1AP_PROTOCOLEXTENSIONFIELD_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + + if(liblte_s1ap_unpack_protocolextensionid(ptr, &ie->id) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + // Enum - ie->criticality + ie->criticality = (LIBLTE_S1AP_CRITICALITY_ENUM)liblte_bits_2_value(ptr, 2); + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE ProtocolIE_FieldPair SEQUENCE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_protocolie_fieldpair( + LIBLTE_S1AP_PROTOCOLIE_FIELDPAIR_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + + if(liblte_s1ap_pack_protocolie_id(&ie->id, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // Enum - ie->firstCriticality + liblte_value_2_bits(ie->firstCriticality, ptr, 2); + + + // Enum - ie->secondCriticality + liblte_value_2_bits(ie->secondCriticality, ptr, 2); + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_protocolie_fieldpair( + uint8_t **ptr, + LIBLTE_S1AP_PROTOCOLIE_FIELDPAIR_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + + if(liblte_s1ap_unpack_protocolie_id(ptr, &ie->id) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + // Enum - ie->firstCriticality + ie->firstCriticality = (LIBLTE_S1AP_CRITICALITY_ENUM)liblte_bits_2_value(ptr, 2); + + + // Enum - ie->secondCriticality + ie->secondCriticality = (LIBLTE_S1AP_CRITICALITY_ENUM)liblte_bits_2_value(ptr, 2); + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE ProtocolExtensionContainer DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:65535 +LIBLTE_ERROR_ENUM liblte_s1ap_pack_protocolextensioncontainer( + LIBLTE_S1AP_PROTOCOLEXTENSIONCONTAINER_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + if(ie->len > 32) { + liblte_log_print("ProtocolExtensionContainer pack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_ENCODE_FAIL; + } + // Length + liblte_value_2_bits(ie->len-1, ptr, 16); + liblte_align_up_zero(ptr, 8); + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_pack_protocolextensionfield(&ie->buffer[i], ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_protocolextensioncontainer( + uint8_t **ptr, + LIBLTE_S1AP_PROTOCOLEXTENSIONCONTAINER_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Length + ie->len = liblte_bits_2_value(ptr, 16) + 1; + liblte_align_up(ptr, 8); + if(ie->len > 32) { + liblte_log_print("ProtocolExtensionContainer unpack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_DECODE_FAIL; + } + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_unpack_protocolextensionfield(ptr, &ie->buffer[i]) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE ProtocolIE_ContainerPair DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:0, ub:65535 +LIBLTE_ERROR_ENUM liblte_s1ap_pack_protocolie_containerpair( + LIBLTE_S1AP_PROTOCOLIE_CONTAINERPAIR_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + if(ie->len > 32) { + liblte_log_print("ProtocolIE_ContainerPair pack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_ENCODE_FAIL; + } + // Length + liblte_value_2_bits(ie->len-0, ptr, 16); + liblte_align_up_zero(ptr, 8); + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_pack_protocolie_fieldpair(&ie->buffer[i], ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_protocolie_containerpair( + uint8_t **ptr, + LIBLTE_S1AP_PROTOCOLIE_CONTAINERPAIR_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Length + ie->len = liblte_bits_2_value(ptr, 16) + 0; + liblte_align_up(ptr, 8); + if(ie->len > 32) { + liblte_log_print("ProtocolIE_ContainerPair unpack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_DECODE_FAIL; + } + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_unpack_protocolie_fieldpair(ptr, &ie->buffer[i]) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE ProtocolIE_ContainerPairList DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:None, ub:None +LIBLTE_ERROR_ENUM liblte_s1ap_pack_protocolie_containerpairlist( + LIBLTE_S1AP_PROTOCOLIE_CONTAINERPAIRLIST_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + if(ie->len > 32) { + liblte_log_print("ProtocolIE_ContainerPairList pack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_ENCODE_FAIL; + } + // Length + if(ie->len < 128) { + liblte_value_2_bits(0, ptr, 1); + liblte_value_2_bits(ie->len, ptr, 7); + } else if(ie->len < 16383) { + liblte_value_2_bits(1, ptr, 1); + liblte_value_2_bits(0, ptr, 1); + liblte_value_2_bits(ie->len, ptr, 14); + } else { + // FIXME: Unlikely to have more than 16K of bits + } + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_pack_protocolie_containerpair(&ie->buffer[i], ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_protocolie_containerpairlist( + uint8_t **ptr, + LIBLTE_S1AP_PROTOCOLIE_CONTAINERPAIRLIST_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Length + if(0 == liblte_bits_2_value(ptr, 1)) { + ie->len = liblte_bits_2_value(ptr, 7); + } else { + if(0 == liblte_bits_2_value(ptr, 1)) { + ie->len = liblte_bits_2_value(ptr, 14); + } else { + // FIXME: Unlikely to have more than 16K of bits + } + } + if(ie->len > 32) { + liblte_log_print("ProtocolIE_ContainerPairList unpack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_DECODE_FAIL; + } + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_unpack_protocolie_containerpair(ptr, &ie->buffer[i]) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE PrivateIE_Field SEQUENCE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_privateie_field( + LIBLTE_S1AP_PRIVATEIE_FIELD_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + + if(liblte_s1ap_pack_privateie_id(&ie->id, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // Enum - ie->criticality + liblte_value_2_bits(ie->criticality, ptr, 2); + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_privateie_field( + uint8_t **ptr, + LIBLTE_S1AP_PRIVATEIE_FIELD_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + + if(liblte_s1ap_unpack_privateie_id(ptr, &ie->id) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + // Enum - ie->criticality + ie->criticality = (LIBLTE_S1AP_CRITICALITY_ENUM)liblte_bits_2_value(ptr, 2); + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE ProtocolIE_SingleContainer SEQUENCE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_protocolie_singlecontainer( + LIBLTE_S1AP_PROTOCOLIE_SINGLECONTAINER_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + + if(liblte_s1ap_pack_protocolie_id(&ie->id, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // Enum - ie->criticality + liblte_value_2_bits(ie->criticality, ptr, 2); + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_protocolie_singlecontainer( + uint8_t **ptr, + LIBLTE_S1AP_PROTOCOLIE_SINGLECONTAINER_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + + if(liblte_s1ap_unpack_protocolie_id(ptr, &ie->id) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + // Enum - ie->criticality + ie->criticality = (LIBLTE_S1AP_CRITICALITY_ENUM)liblte_bits_2_value(ptr, 2); + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE PrivateIE_Container DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:65535 +LIBLTE_ERROR_ENUM liblte_s1ap_pack_privateie_container( + LIBLTE_S1AP_PRIVATEIE_CONTAINER_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + if(ie->len > 32) { + liblte_log_print("PrivateIE_Container pack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_ENCODE_FAIL; + } + // Length + liblte_value_2_bits(ie->len-1, ptr, 16); + liblte_align_up_zero(ptr, 8); + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_pack_privateie_field(&ie->buffer[i], ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_privateie_container( + uint8_t **ptr, + LIBLTE_S1AP_PRIVATEIE_CONTAINER_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Length + ie->len = liblte_bits_2_value(ptr, 16) + 1; + liblte_align_up(ptr, 8); + if(ie->len > 32) { + liblte_log_print("PrivateIE_Container unpack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_DECODE_FAIL; + } + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_unpack_privateie_field(ptr, &ie->buffer[i]) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE BitRate INTEGER +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_bitrate( + LIBLTE_S1AP_BITRATE_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Integer - ie->BitRate + // lb:0, ub:10000000000 + // Range > 65536 - encoded based on value + { + uint32_t n_bits = floor(log2(ie->BitRate-0)+1); + uint32_t n_octets = (n_bits+7)/8; + liblte_value_2_bits(n_octets-1, ptr, 3); + liblte_align_up_zero(ptr, 8); + liblte_value_2_bits(0, ptr, (n_octets*8)-n_bits); + liblte_value_2_bits(ie->BitRate-0, ptr, n_bits); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_bitrate( + uint8_t **ptr, + LIBLTE_S1AP_BITRATE_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Integer - ie->BitRate + // lb:0, ub:10000000000 + // Range > 65536 - encoded based on value + { + uint32_t n_octets = liblte_bits_2_value(ptr, 3) + 1; + liblte_align_up(ptr, 8); + ie->BitRate = liblte_bits_2_value(ptr, n_octets*8) + 0; + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE CauseMisc ENUMERATED +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_causemisc( + LIBLTE_S1AP_CAUSEMISC_ENUM_EXT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("CauseMisc error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // Enum + liblte_value_2_bits(ie->e, ptr, 3); + liblte_align_up_zero(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_causemisc( + uint8_t **ptr, + LIBLTE_S1AP_CAUSEMISC_ENUM_EXT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("CauseMisc error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // Enum + ie->e = (LIBLTE_S1AP_CAUSEMISC_ENUM)liblte_bits_2_value(ptr, 3); + liblte_align_up(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE CauseRadioNetwork ENUMERATED +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_causeradionetwork( + LIBLTE_S1AP_CAUSERADIONETWORK_ENUM_EXT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("CauseRadioNetwork error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // Enum + liblte_value_2_bits(ie->e, ptr, 6); + liblte_align_up_zero(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_causeradionetwork( + uint8_t **ptr, + LIBLTE_S1AP_CAUSERADIONETWORK_ENUM_EXT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("CauseRadioNetwork error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // Enum + ie->e = (LIBLTE_S1AP_CAUSERADIONETWORK_ENUM)liblte_bits_2_value(ptr, 6); + liblte_align_up(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE CauseNas ENUMERATED +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_causenas( + LIBLTE_S1AP_CAUSENAS_ENUM_EXT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("CauseNas error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // Enum + liblte_value_2_bits(ie->e, ptr, 3); + liblte_align_up_zero(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_causenas( + uint8_t **ptr, + LIBLTE_S1AP_CAUSENAS_ENUM_EXT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("CauseNas error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // Enum + ie->e = (LIBLTE_S1AP_CAUSENAS_ENUM)liblte_bits_2_value(ptr, 3); + liblte_align_up(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE CellIdentity STATIC BIT STRING +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_cellidentity( + LIBLTE_S1AP_CELLIDENTITY_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Static bit string - CellIdentity + liblte_align_up_zero(ptr, 8); + uint32_t i; + for(i=0;ibuffer[i], ptr, 1); + } + liblte_align_up_zero(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_cellidentity( + uint8_t **ptr, + LIBLTE_S1AP_CELLIDENTITY_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Static bit string - CellIdentity + liblte_align_up(ptr, 8); + uint32_t i; + for(i=0;ibuffer[i] = liblte_bits_2_value(ptr, 1); + } + liblte_align_up(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE Cdma2000PDU DYNAMIC OCTET STRING +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_cdma2000pdu( + LIBLTE_S1AP_CDMA2000PDU_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Dynamic octet string - Cdma2000PDU + // Length + if(ie->n_octets < 128) { + liblte_value_2_bits(0, ptr, 1); + liblte_value_2_bits(ie->n_octets, ptr, 7); + } else if(ie->n_octets < 16383) { + liblte_value_2_bits(1, ptr, 1); + liblte_value_2_bits(0, ptr, 1); + liblte_value_2_bits(ie->n_octets, ptr, 14); + } else { + // FIXME: Unlikely to have more than 16K of octets + } + + // Octets + uint32_t i; + for(i=0;in_octets;i++) { + liblte_value_2_bits(ie->buffer[i], ptr, 8); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_cdma2000pdu( + uint8_t **ptr, + LIBLTE_S1AP_CDMA2000PDU_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Dynamic octet string - Cdma2000PDU + // Length + if(0 == liblte_bits_2_value(ptr, 1)) { + ie->n_octets = liblte_bits_2_value(ptr, 7); + } else { + if(0 == liblte_bits_2_value(ptr, 1)) { + ie->n_octets = liblte_bits_2_value(ptr, 14); + } else { + // FIXME: Unlikely to have more than 16K of octets + } + } + + // Octets + uint32_t i; + for(i=0;in_octets;i++) { + ie->buffer[i] = liblte_bits_2_value(ptr, 8); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE Cdma2000SectorID DYNAMIC OCTET STRING +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_cdma2000sectorid( + LIBLTE_S1AP_CDMA2000SECTORID_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Dynamic octet string - Cdma2000SectorID + // Length + if(ie->n_octets < 128) { + liblte_value_2_bits(0, ptr, 1); + liblte_value_2_bits(ie->n_octets, ptr, 7); + } else if(ie->n_octets < 16383) { + liblte_value_2_bits(1, ptr, 1); + liblte_value_2_bits(0, ptr, 1); + liblte_value_2_bits(ie->n_octets, ptr, 14); + } else { + // FIXME: Unlikely to have more than 16K of octets + } + + // Octets + uint32_t i; + for(i=0;in_octets;i++) { + liblte_value_2_bits(ie->buffer[i], ptr, 8); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_cdma2000sectorid( + uint8_t **ptr, + LIBLTE_S1AP_CDMA2000SECTORID_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Dynamic octet string - Cdma2000SectorID + // Length + if(0 == liblte_bits_2_value(ptr, 1)) { + ie->n_octets = liblte_bits_2_value(ptr, 7); + } else { + if(0 == liblte_bits_2_value(ptr, 1)) { + ie->n_octets = liblte_bits_2_value(ptr, 14); + } else { + // FIXME: Unlikely to have more than 16K of octets + } + } + + // Octets + uint32_t i; + for(i=0;in_octets;i++) { + ie->buffer[i] = liblte_bits_2_value(ptr, 8); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE Cdma2000HORequiredIndication ENUMERATED +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_cdma2000horequiredindication( + LIBLTE_S1AP_CDMA2000HOREQUIREDINDICATION_ENUM_EXT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("Cdma2000HORequiredIndication error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // Enum + liblte_value_2_bits(ie->e, ptr, 0); + liblte_align_up_zero(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_cdma2000horequiredindication( + uint8_t **ptr, + LIBLTE_S1AP_CDMA2000HOREQUIREDINDICATION_ENUM_EXT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("Cdma2000HORequiredIndication error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // Enum + ie->e = (LIBLTE_S1AP_CDMA2000HOREQUIREDINDICATION_ENUM)liblte_bits_2_value(ptr, 0); + liblte_align_up(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE Cdma2000OneXMSI DYNAMIC OCTET STRING +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_cdma2000onexmsi( + LIBLTE_S1AP_CDMA2000ONEXMSI_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Dynamic octet string - Cdma2000OneXMSI + // Length + if(ie->n_octets < 128) { + liblte_value_2_bits(0, ptr, 1); + liblte_value_2_bits(ie->n_octets, ptr, 7); + } else if(ie->n_octets < 16383) { + liblte_value_2_bits(1, ptr, 1); + liblte_value_2_bits(0, ptr, 1); + liblte_value_2_bits(ie->n_octets, ptr, 14); + } else { + // FIXME: Unlikely to have more than 16K of octets + } + + // Octets + uint32_t i; + for(i=0;in_octets;i++) { + liblte_value_2_bits(ie->buffer[i], ptr, 8); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_cdma2000onexmsi( + uint8_t **ptr, + LIBLTE_S1AP_CDMA2000ONEXMSI_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Dynamic octet string - Cdma2000OneXMSI + // Length + if(0 == liblte_bits_2_value(ptr, 1)) { + ie->n_octets = liblte_bits_2_value(ptr, 7); + } else { + if(0 == liblte_bits_2_value(ptr, 1)) { + ie->n_octets = liblte_bits_2_value(ptr, 14); + } else { + // FIXME: Unlikely to have more than 16K of octets + } + } + + // Octets + uint32_t i; + for(i=0;in_octets;i++) { + ie->buffer[i] = liblte_bits_2_value(ptr, 8); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE Cdma2000OneXRAND DYNAMIC OCTET STRING +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_cdma2000onexrand( + LIBLTE_S1AP_CDMA2000ONEXRAND_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Dynamic octet string - Cdma2000OneXRAND + // Length + if(ie->n_octets < 128) { + liblte_value_2_bits(0, ptr, 1); + liblte_value_2_bits(ie->n_octets, ptr, 7); + } else if(ie->n_octets < 16383) { + liblte_value_2_bits(1, ptr, 1); + liblte_value_2_bits(0, ptr, 1); + liblte_value_2_bits(ie->n_octets, ptr, 14); + } else { + // FIXME: Unlikely to have more than 16K of octets + } + + // Octets + uint32_t i; + for(i=0;in_octets;i++) { + liblte_value_2_bits(ie->buffer[i], ptr, 8); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_cdma2000onexrand( + uint8_t **ptr, + LIBLTE_S1AP_CDMA2000ONEXRAND_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Dynamic octet string - Cdma2000OneXRAND + // Length + if(0 == liblte_bits_2_value(ptr, 1)) { + ie->n_octets = liblte_bits_2_value(ptr, 7); + } else { + if(0 == liblte_bits_2_value(ptr, 1)) { + ie->n_octets = liblte_bits_2_value(ptr, 14); + } else { + // FIXME: Unlikely to have more than 16K of octets + } + } + + // Octets + uint32_t i; + for(i=0;in_octets;i++) { + ie->buffer[i] = liblte_bits_2_value(ptr, 8); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE CNDomain ENUMERATED +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_cndomain( + LIBLTE_S1AP_CNDOMAIN_ENUM *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Enum - *ie + liblte_value_2_bits(*ie, ptr, 1); + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_cndomain( + uint8_t **ptr, + LIBLTE_S1AP_CNDOMAIN_ENUM *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Enum - *ie + *ie = (LIBLTE_S1AP_CNDOMAIN_ENUM)liblte_bits_2_value(ptr, 1); + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE Correlation_ID STATIC OCTET STRING +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_correlation_id( + LIBLTE_S1AP_CORRELATION_ID_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Static octet string - Correlation-ID + if(LIBLTE_S1AP_CORRELATION_ID_OCTET_STRING_LEN > 2) { // X.691 Sec.16 + liblte_align_up_zero(ptr, 8); + } + // Octets + uint32_t i; + for(i=0;ibuffer[i], ptr, 8); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_correlation_id( + uint8_t **ptr, + LIBLTE_S1AP_CORRELATION_ID_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Static octet string - Correlation-ID + if(LIBLTE_S1AP_CORRELATION_ID_OCTET_STRING_LEN > 2) { // X.691 Sec.16 + liblte_align_up(ptr, 8); + } + // Octets + uint32_t i; + for(i=0;ibuffer[i] = liblte_bits_2_value(ptr, 8); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE AdditionalCSFallbackIndicator ENUMERATED +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_additionalcsfallbackindicator( + LIBLTE_S1AP_ADDITIONALCSFALLBACKINDICATOR_ENUM_EXT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("AdditionalCSFallbackIndicator error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // Enum + liblte_value_2_bits(ie->e, ptr, 1); + liblte_align_up_zero(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_additionalcsfallbackindicator( + uint8_t **ptr, + LIBLTE_S1AP_ADDITIONALCSFALLBACKINDICATOR_ENUM_EXT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("AdditionalCSFallbackIndicator error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // Enum + ie->e = (LIBLTE_S1AP_ADDITIONALCSFALLBACKINDICATOR_ENUM)liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE DL_Forwarding ENUMERATED +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_dl_forwarding( + LIBLTE_S1AP_DL_FORWARDING_ENUM_EXT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("DL_Forwarding error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // Enum + liblte_value_2_bits(ie->e, ptr, 0); + liblte_align_up_zero(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_dl_forwarding( + uint8_t **ptr, + LIBLTE_S1AP_DL_FORWARDING_ENUM_EXT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("DL_Forwarding error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // Enum + ie->e = (LIBLTE_S1AP_DL_FORWARDING_ENUM)liblte_bits_2_value(ptr, 0); + liblte_align_up(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE Data_Forwarding_Not_Possible ENUMERATED +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_data_forwarding_not_possible( + LIBLTE_S1AP_DATA_FORWARDING_NOT_POSSIBLE_ENUM_EXT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("Data_Forwarding_Not_Possible error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // Enum + liblte_value_2_bits(ie->e, ptr, 0); + liblte_align_up_zero(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_data_forwarding_not_possible( + uint8_t **ptr, + LIBLTE_S1AP_DATA_FORWARDING_NOT_POSSIBLE_ENUM_EXT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("Data_Forwarding_Not_Possible error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // Enum + ie->e = (LIBLTE_S1AP_DATA_FORWARDING_NOT_POSSIBLE_ENUM)liblte_bits_2_value(ptr, 0); + liblte_align_up(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE EmergencyAreaID STATIC OCTET STRING +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_emergencyareaid( + LIBLTE_S1AP_EMERGENCYAREAID_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Static octet string - EmergencyAreaID + if(LIBLTE_S1AP_EMERGENCYAREAID_OCTET_STRING_LEN > 2) { // X.691 Sec.16 + liblte_align_up_zero(ptr, 8); + } + // Octets + uint32_t i; + for(i=0;ibuffer[i], ptr, 8); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_emergencyareaid( + uint8_t **ptr, + LIBLTE_S1AP_EMERGENCYAREAID_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Static octet string - EmergencyAreaID + if(LIBLTE_S1AP_EMERGENCYAREAID_OCTET_STRING_LEN > 2) { // X.691 Sec.16 + liblte_align_up(ptr, 8); + } + // Octets + uint32_t i; + for(i=0;ibuffer[i] = liblte_bits_2_value(ptr, 8); + } + err = LIBLTE_SUCCESS; + } + return err; +} + + +/******************************************************************************* +/* ProtocolIE macroENB_ID STATIC BIT STRING +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_macroenb_id( + LIBLTE_S1AP_MACROENB_ID_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Static bit string - macroENB-ID + liblte_align_up_zero(ptr, 8); + uint32_t i; + for(i=0;ibuffer[i], ptr, 1); + } + liblte_align_up_zero(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_macroenb_id( + uint8_t **ptr, + LIBLTE_S1AP_MACROENB_ID_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Static bit string - macroENB-ID + liblte_align_up(ptr, 8); + uint32_t i; + for(i=0;ibuffer[i] = liblte_bits_2_value(ptr, 1); + } + liblte_align_up(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + + + +/******************************************************************************* +/* ProtocolIE homeENB_ID STATIC BIT STRING +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_homeenb_id( + LIBLTE_S1AP_HOMEENB_ID_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Static bit string - homeENB-ID + liblte_align_up_zero(ptr, 8); + uint32_t i; + for(i=0;ibuffer[i], ptr, 1); + } + liblte_align_up_zero(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_homeenb_id( + uint8_t **ptr, + LIBLTE_S1AP_HOMEENB_ID_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Static bit string - homeENB-ID + liblte_align_up(ptr, 8); + uint32_t i; + for(i=0;ibuffer[i] = liblte_bits_2_value(ptr, 1); + } + liblte_align_up(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + + +/******************************************************************************* +/* ProtocolIE ENB_ID CHOICE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_enb_id( + LIBLTE_S1AP_ENB_ID_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("ENB_ID error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // Choice type + liblte_value_2_bits(ie->choice_type, ptr, 1); + + // Choice + if(ie->choice_type == LIBLTE_S1AP_ENB_ID_CHOICE_MACROENB_ID) { + if(liblte_s1ap_pack_macroenb_id(&ie->choice.macroENB_ID, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(ie->choice_type == LIBLTE_S1AP_ENB_ID_CHOICE_HOMEENB_ID) { + if(liblte_s1ap_pack_homeenb_id(&ie->choice.homeENB_ID, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_enb_id( + uint8_t **ptr, + LIBLTE_S1AP_ENB_ID_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("ENB_ID error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // Choice type + ie->choice_type = (LIBLTE_S1AP_ENB_ID_CHOICE_ENUM)liblte_bits_2_value(ptr, 1); + + // Choice + if(ie->choice_type == LIBLTE_S1AP_ENB_ID_CHOICE_MACROENB_ID) { + if(liblte_s1ap_unpack_macroenb_id(ptr, &ie->choice.macroENB_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(ie->choice_type == LIBLTE_S1AP_ENB_ID_CHOICE_HOMEENB_ID) { + if(liblte_s1ap_unpack_homeenb_id(ptr, &ie->choice.homeENB_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE ENBname PrintableString +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_enbname( + LIBLTE_S1AP_ENBNAME_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Printable string - ENBname + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("ENBname error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // Length + liblte_value_2_bits(ie->n_octets-1, ptr, 8); + liblte_align_up_zero(ptr, 8); + + uint32_t i; + for(i=0;in_octets;i++) { + liblte_value_2_bits(ie->buffer[i], ptr, 8); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_enbname( + uint8_t **ptr, + LIBLTE_S1AP_ENBNAME_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Printable string - ENBname + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("ENBname error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // Length + ie->n_octets = liblte_bits_2_value(ptr, 8) + 1; + liblte_align_up(ptr, 8); + + uint32_t i; + for(i=0;in_octets;i++) { + ie->buffer[i] = liblte_bits_2_value(ptr, 8); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE EncryptionAlgorithms STATIC BIT STRING +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_encryptionalgorithms( + LIBLTE_S1AP_ENCRYPTIONALGORITHMS_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Static bit string - EncryptionAlgorithms + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("EncryptionAlgorithms error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + uint32_t i; + for(i=0;ibuffer[i], ptr, 1); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_encryptionalgorithms( + uint8_t **ptr, + LIBLTE_S1AP_ENCRYPTIONALGORITHMS_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Static bit string - EncryptionAlgorithms + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("EncryptionAlgorithms error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + uint32_t i; + for(i=0;ibuffer[i] = liblte_bits_2_value(ptr, 1); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE EventType ENUMERATED +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_eventtype( + LIBLTE_S1AP_EVENTTYPE_ENUM_EXT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("EventType error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // Enum + liblte_value_2_bits(ie->e, ptr, 2); + liblte_align_up_zero(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_eventtype( + uint8_t **ptr, + LIBLTE_S1AP_EVENTTYPE_ENUM_EXT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("EventType error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // Enum + ie->e = (LIBLTE_S1AP_EVENTTYPE_ENUM)liblte_bits_2_value(ptr, 2); + liblte_align_up(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE ExtendedRNC_ID INTEGER +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_extendedrnc_id( + LIBLTE_S1AP_EXTENDEDRNC_ID_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Integer - ie->ExtendedRNC_ID + // lb:4096, ub:65535 + liblte_align_up_zero(ptr, 8); + liblte_value_2_bits(0, ptr, (2*8)-16); + liblte_value_2_bits(ie->ExtendedRNC_ID, ptr, 16); + liblte_align_up_zero(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_extendedrnc_id( + uint8_t **ptr, + LIBLTE_S1AP_EXTENDEDRNC_ID_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Integer - ie->ExtendedRNC_ID + // lb:4096, ub:65535 + liblte_align_up(ptr, 8); + ie->ExtendedRNC_ID = (uint16_t)liblte_bits_2_value(ptr, 2.0*8); + liblte_align_up(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE ForbiddenInterRATs ENUMERATED +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_forbiddeninterrats( + LIBLTE_S1AP_FORBIDDENINTERRATS_ENUM_EXT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("ForbiddenInterRATs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // Enum + liblte_value_2_bits(ie->e, ptr, 3); + liblte_align_up_zero(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_forbiddeninterrats( + uint8_t **ptr, + LIBLTE_S1AP_FORBIDDENINTERRATS_ENUM_EXT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("ForbiddenInterRATs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // Enum + ie->e = (LIBLTE_S1AP_FORBIDDENINTERRATS_ENUM)liblte_bits_2_value(ptr, 3); + liblte_align_up(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE GWContextReleaseIndication ENUMERATED +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_gwcontextreleaseindication( + LIBLTE_S1AP_GWCONTEXTRELEASEINDICATION_ENUM_EXT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("GWContextReleaseIndication error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // Enum + liblte_value_2_bits(ie->e, ptr, 0); + liblte_align_up_zero(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_gwcontextreleaseindication( + uint8_t **ptr, + LIBLTE_S1AP_GWCONTEXTRELEASEINDICATION_ENUM_EXT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("GWContextReleaseIndication error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // Enum + ie->e = (LIBLTE_S1AP_GWCONTEXTRELEASEINDICATION_ENUM)liblte_bits_2_value(ptr, 0); + liblte_align_up(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE HFN INTEGER +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_hfn( + LIBLTE_S1AP_HFN_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Integer - ie->HFN + // lb:0, ub:1048575 + // Range > 65536 - encoded based on value + { + uint32_t n_bits = floor(log2(ie->HFN-0)+1); + uint32_t n_octets = (n_bits+7)/8; + liblte_value_2_bits(n_octets-1, ptr, 2); + liblte_align_up_zero(ptr, 8); + liblte_value_2_bits(0, ptr, (n_octets*8)-n_bits); + liblte_value_2_bits(ie->HFN-0, ptr, n_bits); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_hfn( + uint8_t **ptr, + LIBLTE_S1AP_HFN_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Integer - ie->HFN + // lb:0, ub:1048575 + // Range > 65536 - encoded based on value + { + uint32_t n_octets = liblte_bits_2_value(ptr, 2) + 1; + liblte_align_up(ptr, 8); + ie->HFN = liblte_bits_2_value(ptr, n_octets*8) + 0; + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE IMSI DYNAMIC OCTET STRING +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_imsi( + LIBLTE_S1AP_IMSI_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Dynamic octet string - IMSI + // Length + if(ie->n_octets < 128) { + liblte_value_2_bits(0, ptr, 1); + liblte_value_2_bits(ie->n_octets, ptr, 7); + } else if(ie->n_octets < 16383) { + liblte_value_2_bits(1, ptr, 1); + liblte_value_2_bits(0, ptr, 1); + liblte_value_2_bits(ie->n_octets, ptr, 14); + } else { + // FIXME: Unlikely to have more than 16K of octets + } + + // Octets + uint32_t i; + for(i=0;in_octets;i++) { + liblte_value_2_bits(ie->buffer[i], ptr, 8); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_imsi( + uint8_t **ptr, + LIBLTE_S1AP_IMSI_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Dynamic octet string - IMSI + // Length + if(0 == liblte_bits_2_value(ptr, 1)) { + ie->n_octets = liblte_bits_2_value(ptr, 7); + } else { + if(0 == liblte_bits_2_value(ptr, 1)) { + ie->n_octets = liblte_bits_2_value(ptr, 14); + } else { + // FIXME: Unlikely to have more than 16K of octets + } + } + + // Octets + uint32_t i; + for(i=0;in_octets;i++) { + ie->buffer[i] = liblte_bits_2_value(ptr, 8); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE InterfacesToTrace STATIC BIT STRING +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_interfacestotrace( + LIBLTE_S1AP_INTERFACESTOTRACE_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Static bit string - InterfacesToTrace + uint32_t i; + for(i=0;ibuffer[i], ptr, 1); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_interfacestotrace( + uint8_t **ptr, + LIBLTE_S1AP_INTERFACESTOTRACE_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Static bit string - InterfacesToTrace + uint32_t i; + for(i=0;ibuffer[i] = liblte_bits_2_value(ptr, 1); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE LAC STATIC OCTET STRING +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_lac( + LIBLTE_S1AP_LAC_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Static octet string - LAC + if(LIBLTE_S1AP_LAC_OCTET_STRING_LEN > 2) { // X.691 Sec.16 + liblte_align_up_zero(ptr, 8); + } + // Octets + uint32_t i; + for(i=0;ibuffer[i], ptr, 8); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_lac( + uint8_t **ptr, + LIBLTE_S1AP_LAC_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Static octet string - LAC + if(LIBLTE_S1AP_LAC_OCTET_STRING_LEN > 2) { // X.691 Sec.16 + liblte_align_up(ptr, 8); + } + // Octets + uint32_t i; + for(i=0;ibuffer[i] = liblte_bits_2_value(ptr, 8); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE LastVisitedUTRANCellInformation DYNAMIC OCTET STRING +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_lastvisitedutrancellinformation( + LIBLTE_S1AP_LASTVISITEDUTRANCELLINFORMATION_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Dynamic octet string - LastVisitedUTRANCellInformation + // Length + if(ie->n_octets < 128) { + liblte_value_2_bits(0, ptr, 1); + liblte_value_2_bits(ie->n_octets, ptr, 7); + } else if(ie->n_octets < 16383) { + liblte_value_2_bits(1, ptr, 1); + liblte_value_2_bits(0, ptr, 1); + liblte_value_2_bits(ie->n_octets, ptr, 14); + } else { + // FIXME: Unlikely to have more than 16K of octets + } + + // Octets + uint32_t i; + for(i=0;in_octets;i++) { + liblte_value_2_bits(ie->buffer[i], ptr, 8); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_lastvisitedutrancellinformation( + uint8_t **ptr, + LIBLTE_S1AP_LASTVISITEDUTRANCELLINFORMATION_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Dynamic octet string - LastVisitedUTRANCellInformation + // Length + if(0 == liblte_bits_2_value(ptr, 1)) { + ie->n_octets = liblte_bits_2_value(ptr, 7); + } else { + if(0 == liblte_bits_2_value(ptr, 1)) { + ie->n_octets = liblte_bits_2_value(ptr, 14); + } else { + // FIXME: Unlikely to have more than 16K of octets + } + } + + // Octets + uint32_t i; + for(i=0;in_octets;i++) { + ie->buffer[i] = liblte_bits_2_value(ptr, 8); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE L3_Information DYNAMIC OCTET STRING +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_l3_information( + LIBLTE_S1AP_L3_INFORMATION_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Dynamic octet string - L3-Information + // Length + if(ie->n_octets < 128) { + liblte_value_2_bits(0, ptr, 1); + liblte_value_2_bits(ie->n_octets, ptr, 7); + } else if(ie->n_octets < 16383) { + liblte_value_2_bits(1, ptr, 1); + liblte_value_2_bits(0, ptr, 1); + liblte_value_2_bits(ie->n_octets, ptr, 14); + } else { + // FIXME: Unlikely to have more than 16K of octets + } + + // Octets + uint32_t i; + for(i=0;in_octets;i++) { + liblte_value_2_bits(ie->buffer[i], ptr, 8); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_l3_information( + uint8_t **ptr, + LIBLTE_S1AP_L3_INFORMATION_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Dynamic octet string - L3-Information + // Length + if(0 == liblte_bits_2_value(ptr, 1)) { + ie->n_octets = liblte_bits_2_value(ptr, 7); + } else { + if(0 == liblte_bits_2_value(ptr, 1)) { + ie->n_octets = liblte_bits_2_value(ptr, 14); + } else { + // FIXME: Unlikely to have more than 16K of octets + } + } + + // Octets + uint32_t i; + for(i=0;in_octets;i++) { + ie->buffer[i] = liblte_bits_2_value(ptr, 8); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE LHN_ID DYNAMIC OCTET STRING +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_lhn_id( + LIBLTE_S1AP_LHN_ID_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Dynamic octet string - LHN-ID + // Length + if(ie->n_octets < 128) { + liblte_value_2_bits(0, ptr, 1); + liblte_value_2_bits(ie->n_octets, ptr, 7); + } else if(ie->n_octets < 16383) { + liblte_value_2_bits(1, ptr, 1); + liblte_value_2_bits(0, ptr, 1); + liblte_value_2_bits(ie->n_octets, ptr, 14); + } else { + // FIXME: Unlikely to have more than 16K of octets + } + + // Octets + uint32_t i; + for(i=0;in_octets;i++) { + liblte_value_2_bits(ie->buffer[i], ptr, 8); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_lhn_id( + uint8_t **ptr, + LIBLTE_S1AP_LHN_ID_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Dynamic octet string - LHN-ID + // Length + if(0 == liblte_bits_2_value(ptr, 1)) { + ie->n_octets = liblte_bits_2_value(ptr, 7); + } else { + if(0 == liblte_bits_2_value(ptr, 1)) { + ie->n_octets = liblte_bits_2_value(ptr, 14); + } else { + // FIXME: Unlikely to have more than 16K of octets + } + } + + // Octets + uint32_t i; + for(i=0;in_octets;i++) { + ie->buffer[i] = liblte_bits_2_value(ptr, 8); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE LoggingDuration ENUMERATED +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_loggingduration( + LIBLTE_S1AP_LOGGINGDURATION_ENUM *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Enum - *ie + liblte_value_2_bits(*ie, ptr, 3); + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_loggingduration( + uint8_t **ptr, + LIBLTE_S1AP_LOGGINGDURATION_ENUM *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Enum - *ie + *ie = (LIBLTE_S1AP_LOGGINGDURATION_ENUM)liblte_bits_2_value(ptr, 3); + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE MDT_Activation ENUMERATED +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_mdt_activation( + LIBLTE_S1AP_MDT_ACTIVATION_ENUM_EXT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("MDT_Activation error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // Enum + liblte_value_2_bits(ie->e, ptr, 2); + liblte_align_up_zero(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_mdt_activation( + uint8_t **ptr, + LIBLTE_S1AP_MDT_ACTIVATION_ENUM_EXT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("MDT_Activation error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // Enum + ie->e = (LIBLTE_S1AP_MDT_ACTIVATION_ENUM)liblte_bits_2_value(ptr, 2); + liblte_align_up(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE ManagementBasedMDTAllowed ENUMERATED +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_managementbasedmdtallowed( + LIBLTE_S1AP_MANAGEMENTBASEDMDTALLOWED_ENUM_EXT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("ManagementBasedMDTAllowed error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // Enum + liblte_value_2_bits(ie->e, ptr, 0); + liblte_align_up_zero(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_managementbasedmdtallowed( + uint8_t **ptr, + LIBLTE_S1AP_MANAGEMENTBASEDMDTALLOWED_ENUM_EXT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("ManagementBasedMDTAllowed error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // Enum + ie->e = (LIBLTE_S1AP_MANAGEMENTBASEDMDTALLOWED_ENUM)liblte_bits_2_value(ptr, 0); + liblte_align_up(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE PrivacyIndicator ENUMERATED +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_privacyindicator( + LIBLTE_S1AP_PRIVACYINDICATOR_ENUM_EXT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("PrivacyIndicator error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // Enum + liblte_value_2_bits(ie->e, ptr, 1); + liblte_align_up_zero(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_privacyindicator( + uint8_t **ptr, + LIBLTE_S1AP_PRIVACYINDICATOR_ENUM_EXT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("PrivacyIndicator error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // Enum + ie->e = (LIBLTE_S1AP_PRIVACYINDICATOR_ENUM)liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE MeasurementsToActivate STATIC BIT STRING +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_measurementstoactivate( + LIBLTE_S1AP_MEASUREMENTSTOACTIVATE_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Static bit string - MeasurementsToActivate + uint32_t i; + for(i=0;ibuffer[i], ptr, 1); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_measurementstoactivate( + uint8_t **ptr, + LIBLTE_S1AP_MEASUREMENTSTOACTIVATE_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Static bit string - MeasurementsToActivate + uint32_t i; + for(i=0;ibuffer[i] = liblte_bits_2_value(ptr, 1); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE MessageIdentifier STATIC BIT STRING +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_messageidentifier( + LIBLTE_S1AP_MESSAGEIDENTIFIER_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Static bit string - MessageIdentifier + uint32_t i; + for(i=0;ibuffer[i], ptr, 1); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_messageidentifier( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGEIDENTIFIER_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Static bit string - MessageIdentifier + uint32_t i; + for(i=0;ibuffer[i] = liblte_bits_2_value(ptr, 1); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE MMEname PrintableString +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_mmename( + LIBLTE_S1AP_MMENAME_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Printable string - MMEname + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("MMEname error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // Length + liblte_value_2_bits(ie->n_octets-1, ptr, 8); + liblte_align_up_zero(ptr, 8); + + uint32_t i; + for(i=0;in_octets;i++) { + liblte_value_2_bits(ie->buffer[i], ptr, 8); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_mmename( + uint8_t **ptr, + LIBLTE_S1AP_MMENAME_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Printable string - MMEname + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("MMEname error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // Length + ie->n_octets = liblte_bits_2_value(ptr, 8) + 1; + liblte_align_up(ptr, 8); + + uint32_t i; + for(i=0;in_octets;i++) { + ie->buffer[i] = liblte_bits_2_value(ptr, 8); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE MME_Group_ID STATIC OCTET STRING +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_mme_group_id( + LIBLTE_S1AP_MME_GROUP_ID_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Static octet string - MME-Group-ID + if(LIBLTE_S1AP_MME_GROUP_ID_OCTET_STRING_LEN > 2) { // X.691 Sec.16 + liblte_align_up_zero(ptr, 8); + } + // Octets + uint32_t i; + for(i=0;ibuffer[i], ptr, 8); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_mme_group_id( + uint8_t **ptr, + LIBLTE_S1AP_MME_GROUP_ID_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Static octet string - MME-Group-ID + if(LIBLTE_S1AP_MME_GROUP_ID_OCTET_STRING_LEN > 2) { // X.691 Sec.16 + liblte_align_up(ptr, 8); + } + // Octets + uint32_t i; + for(i=0;ibuffer[i] = liblte_bits_2_value(ptr, 8); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE MME_UE_S1AP_ID INTEGER +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_mme_ue_s1ap_id( + LIBLTE_S1AP_MME_UE_S1AP_ID_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Integer - ie->MME_UE_S1AP_ID + // lb:0, ub:4294967295 + // Range > 65536 - encoded based on value + { + uint32_t n_bits = floor(log2(ie->MME_UE_S1AP_ID-0)+1); + uint32_t n_octets = (n_bits+7)/8; + liblte_value_2_bits(n_octets-1, ptr, 2); + liblte_align_up_zero(ptr, 8); + liblte_value_2_bits(0, ptr, (n_octets*8)-n_bits); + liblte_value_2_bits(ie->MME_UE_S1AP_ID-0, ptr, n_bits); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_mme_ue_s1ap_id( + uint8_t **ptr, + LIBLTE_S1AP_MME_UE_S1AP_ID_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Integer - ie->MME_UE_S1AP_ID + // lb:0, ub:4294967295 + // Range > 65536 - encoded based on value + { + uint32_t n_octets = liblte_bits_2_value(ptr, 2) + 1; + liblte_align_up(ptr, 8); + ie->MME_UE_S1AP_ID = liblte_bits_2_value(ptr, n_octets*8) + 0; + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE MSClassmark2 DYNAMIC OCTET STRING +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_msclassmark2( + LIBLTE_S1AP_MSCLASSMARK2_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Dynamic octet string - MSClassmark2 + // Length + if(ie->n_octets < 128) { + liblte_value_2_bits(0, ptr, 1); + liblte_value_2_bits(ie->n_octets, ptr, 7); + } else if(ie->n_octets < 16383) { + liblte_value_2_bits(1, ptr, 1); + liblte_value_2_bits(0, ptr, 1); + liblte_value_2_bits(ie->n_octets, ptr, 14); + } else { + // FIXME: Unlikely to have more than 16K of octets + } + + // Octets + uint32_t i; + for(i=0;in_octets;i++) { + liblte_value_2_bits(ie->buffer[i], ptr, 8); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_msclassmark2( + uint8_t **ptr, + LIBLTE_S1AP_MSCLASSMARK2_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Dynamic octet string - MSClassmark2 + // Length + if(0 == liblte_bits_2_value(ptr, 1)) { + ie->n_octets = liblte_bits_2_value(ptr, 7); + } else { + if(0 == liblte_bits_2_value(ptr, 1)) { + ie->n_octets = liblte_bits_2_value(ptr, 14); + } else { + // FIXME: Unlikely to have more than 16K of octets + } + } + + // Octets + uint32_t i; + for(i=0;in_octets;i++) { + ie->buffer[i] = liblte_bits_2_value(ptr, 8); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE NAS_PDU DYNAMIC OCTET STRING +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_nas_pdu( + LIBLTE_S1AP_NAS_PDU_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Dynamic octet string - NAS-PDU + // Length + if(ie->n_octets < 128) { + liblte_value_2_bits(0, ptr, 1); + liblte_value_2_bits(ie->n_octets, ptr, 7); + } else if(ie->n_octets < 16383) { + liblte_value_2_bits(1, ptr, 1); + liblte_value_2_bits(0, ptr, 1); + liblte_value_2_bits(ie->n_octets, ptr, 14); + } else { + // FIXME: Unlikely to have more than 16K of octets + } + + // Octets + uint32_t i; + for(i=0;in_octets;i++) { + liblte_value_2_bits(ie->buffer[i], ptr, 8); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_nas_pdu( + uint8_t **ptr, + LIBLTE_S1AP_NAS_PDU_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Dynamic octet string - NAS-PDU + // Length + if(0 == liblte_bits_2_value(ptr, 1)) { + ie->n_octets = liblte_bits_2_value(ptr, 7); + } else { + if(0 == liblte_bits_2_value(ptr, 1)) { + ie->n_octets = liblte_bits_2_value(ptr, 14); + } else { + // FIXME: Unlikely to have more than 16K of octets + } + } + + // Octets + uint32_t i; + for(i=0;in_octets;i++) { + ie->buffer[i] = liblte_bits_2_value(ptr, 8); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE NASSecurityParameterstoE_UTRAN DYNAMIC OCTET STRING +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_nassecurityparameterstoe_utran( + LIBLTE_S1AP_NASSECURITYPARAMETERSTOE_UTRAN_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Dynamic octet string - NASSecurityParameterstoE-UTRAN + // Length + if(ie->n_octets < 128) { + liblte_value_2_bits(0, ptr, 1); + liblte_value_2_bits(ie->n_octets, ptr, 7); + } else if(ie->n_octets < 16383) { + liblte_value_2_bits(1, ptr, 1); + liblte_value_2_bits(0, ptr, 1); + liblte_value_2_bits(ie->n_octets, ptr, 14); + } else { + // FIXME: Unlikely to have more than 16K of octets + } + + // Octets + uint32_t i; + for(i=0;in_octets;i++) { + liblte_value_2_bits(ie->buffer[i], ptr, 8); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_nassecurityparameterstoe_utran( + uint8_t **ptr, + LIBLTE_S1AP_NASSECURITYPARAMETERSTOE_UTRAN_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Dynamic octet string - NASSecurityParameterstoE-UTRAN + // Length + if(0 == liblte_bits_2_value(ptr, 1)) { + ie->n_octets = liblte_bits_2_value(ptr, 7); + } else { + if(0 == liblte_bits_2_value(ptr, 1)) { + ie->n_octets = liblte_bits_2_value(ptr, 14); + } else { + // FIXME: Unlikely to have more than 16K of octets + } + } + + // Octets + uint32_t i; + for(i=0;in_octets;i++) { + ie->buffer[i] = liblte_bits_2_value(ptr, 8); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE NumberOfBroadcasts INTEGER +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_numberofbroadcasts( + LIBLTE_S1AP_NUMBEROFBROADCASTS_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Integer - ie->NumberOfBroadcasts + // lb:0, ub:65535 + liblte_align_up_zero(ptr, 8); + liblte_value_2_bits(0, ptr, (2*8)-16); + liblte_value_2_bits(ie->NumberOfBroadcasts, ptr, 16); + liblte_align_up_zero(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_numberofbroadcasts( + uint8_t **ptr, + LIBLTE_S1AP_NUMBEROFBROADCASTS_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Integer - ie->NumberOfBroadcasts + // lb:0, ub:65535 + liblte_align_up(ptr, 8); + ie->NumberOfBroadcasts = (uint16_t)liblte_bits_2_value(ptr, 2.0*8); + liblte_align_up(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE OverloadAction ENUMERATED +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_overloadaction( + LIBLTE_S1AP_OVERLOADACTION_ENUM_EXT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("OverloadAction error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // Enum + liblte_value_2_bits(ie->e, ptr, 3); + liblte_align_up_zero(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_overloadaction( + uint8_t **ptr, + LIBLTE_S1AP_OVERLOADACTION_ENUM_EXT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("OverloadAction error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // Enum + ie->e = (LIBLTE_S1AP_OVERLOADACTION_ENUM)liblte_bits_2_value(ptr, 3); + liblte_align_up(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE PagingDRX ENUMERATED +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_pagingdrx( + LIBLTE_S1AP_PAGINGDRX_ENUM_EXT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("PagingDRX error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // Enum + liblte_value_2_bits(ie->e, ptr, 2); + liblte_align_up_zero(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_pagingdrx( + uint8_t **ptr, + LIBLTE_S1AP_PAGINGDRX_ENUM_EXT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("PagingDRX error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // Enum + ie->e = (LIBLTE_S1AP_PAGINGDRX_ENUM)liblte_bits_2_value(ptr, 2); + liblte_align_up(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE PDCP_SN INTEGER +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_pdcp_sn( + LIBLTE_S1AP_PDCP_SN_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Integer - ie->PDCP_SN + // lb:0, ub:4095 + liblte_align_up_zero(ptr, 8); + liblte_value_2_bits(0, ptr, (1*8)-12); + liblte_value_2_bits(ie->PDCP_SN, ptr, 12); + liblte_align_up_zero(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_pdcp_sn( + uint8_t **ptr, + LIBLTE_S1AP_PDCP_SN_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Integer - ie->PDCP_SN + // lb:0, ub:4095 + liblte_align_up(ptr, 8); + ie->PDCP_SN = (uint16_t)liblte_bits_2_value(ptr, 1.0*8); + liblte_align_up(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE Port_Number STATIC OCTET STRING +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_port_number( + LIBLTE_S1AP_PORT_NUMBER_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Static octet string - Port-Number + if(LIBLTE_S1AP_PORT_NUMBER_OCTET_STRING_LEN > 2) { // X.691 Sec.16 + liblte_align_up_zero(ptr, 8); + } + // Octets + uint32_t i; + for(i=0;ibuffer[i], ptr, 8); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_port_number( + uint8_t **ptr, + LIBLTE_S1AP_PORT_NUMBER_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Static octet string - Port-Number + if(LIBLTE_S1AP_PORT_NUMBER_OCTET_STRING_LEN > 2) { // X.691 Sec.16 + liblte_align_up(ptr, 8); + } + // Octets + uint32_t i; + for(i=0;ibuffer[i] = liblte_bits_2_value(ptr, 8); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE Pre_emptionVulnerability ENUMERATED +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_pre_emptionvulnerability( + LIBLTE_S1AP_PRE_EMPTIONVULNERABILITY_ENUM *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Enum - *ie + liblte_value_2_bits(*ie, ptr, 1); + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_pre_emptionvulnerability( + uint8_t **ptr, + LIBLTE_S1AP_PRE_EMPTIONVULNERABILITY_ENUM *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Enum - *ie + *ie = (LIBLTE_S1AP_PRE_EMPTIONVULNERABILITY_ENUM)liblte_bits_2_value(ptr, 1); + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE PS_ServiceNotAvailable ENUMERATED +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_ps_servicenotavailable( + LIBLTE_S1AP_PS_SERVICENOTAVAILABLE_ENUM_EXT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("PS_ServiceNotAvailable error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // Enum + liblte_value_2_bits(ie->e, ptr, 0); + liblte_align_up_zero(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_ps_servicenotavailable( + uint8_t **ptr, + LIBLTE_S1AP_PS_SERVICENOTAVAILABLE_ENUM_EXT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("PS_ServiceNotAvailable error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // Enum + ie->e = (LIBLTE_S1AP_PS_SERVICENOTAVAILABLE_ENUM)liblte_bits_2_value(ptr, 0); + liblte_align_up(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE ReceiveStatusofULPDCPSDUs STATIC BIT STRING +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_receivestatusofulpdcpsdus( + LIBLTE_S1AP_RECEIVESTATUSOFULPDCPSDUS_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Static bit string - ReceiveStatusofULPDCPSDUs + liblte_align_up_zero(ptr, 8); + uint32_t i; + for(i=0;ibuffer[i], ptr, 1); + } + liblte_align_up_zero(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_receivestatusofulpdcpsdus( + uint8_t **ptr, + LIBLTE_S1AP_RECEIVESTATUSOFULPDCPSDUS_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Static bit string - ReceiveStatusofULPDCPSDUs + liblte_align_up(ptr, 8); + uint32_t i; + for(i=0;ibuffer[i] = liblte_bits_2_value(ptr, 1); + } + liblte_align_up(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE RelativeMMECapacity INTEGER +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_relativemmecapacity( + LIBLTE_S1AP_RELATIVEMMECAPACITY_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Integer - ie->RelativeMMECapacity + // lb:0, ub:255 + liblte_align_up_zero(ptr, 8); + liblte_value_2_bits(0, ptr, (1*8)-8); + liblte_value_2_bits(ie->RelativeMMECapacity, ptr, 8); + liblte_align_up_zero(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_relativemmecapacity( + uint8_t **ptr, + LIBLTE_S1AP_RELATIVEMMECAPACITY_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Integer - ie->RelativeMMECapacity + // lb:0, ub:255 + liblte_align_up(ptr, 8); + ie->RelativeMMECapacity = (uint8_t)liblte_bits_2_value(ptr, 1.0*8); + liblte_align_up(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE RAC STATIC OCTET STRING +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_rac( + LIBLTE_S1AP_RAC_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Static octet string - RAC + if(LIBLTE_S1AP_RAC_OCTET_STRING_LEN > 2) { // X.691 Sec.16 + liblte_align_up_zero(ptr, 8); + } + // Octets + uint32_t i; + for(i=0;ibuffer[i], ptr, 8); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_rac( + uint8_t **ptr, + LIBLTE_S1AP_RAC_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Static octet string - RAC + if(LIBLTE_S1AP_RAC_OCTET_STRING_LEN > 2) { // X.691 Sec.16 + liblte_align_up(ptr, 8); + } + // Octets + uint32_t i; + for(i=0;ibuffer[i] = liblte_bits_2_value(ptr, 8); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE ReportIntervalMDT ENUMERATED +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_reportintervalmdt( + LIBLTE_S1AP_REPORTINTERVALMDT_ENUM *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Enum - *ie + liblte_value_2_bits(*ie, ptr, 4); + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_reportintervalmdt( + uint8_t **ptr, + LIBLTE_S1AP_REPORTINTERVALMDT_ENUM *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Enum - *ie + *ie = (LIBLTE_S1AP_REPORTINTERVALMDT_ENUM)liblte_bits_2_value(ptr, 4); + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE ReportArea ENUMERATED +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_reportarea( + LIBLTE_S1AP_REPORTAREA_ENUM_EXT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("ReportArea error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // Enum + liblte_value_2_bits(ie->e, ptr, 0); + liblte_align_up_zero(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_reportarea( + uint8_t **ptr, + LIBLTE_S1AP_REPORTAREA_ENUM_EXT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("ReportArea error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // Enum + ie->e = (LIBLTE_S1AP_REPORTAREA_ENUM)liblte_bits_2_value(ptr, 0); + liblte_align_up(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE RNC_ID INTEGER +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_rnc_id( + LIBLTE_S1AP_RNC_ID_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Integer - ie->RNC_ID + // lb:0, ub:4095 + liblte_align_up_zero(ptr, 8); + liblte_value_2_bits(0, ptr, (1*8)-12); + liblte_value_2_bits(ie->RNC_ID, ptr, 12); + liblte_align_up_zero(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_rnc_id( + uint8_t **ptr, + LIBLTE_S1AP_RNC_ID_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Integer - ie->RNC_ID + // lb:0, ub:4095 + liblte_align_up(ptr, 8); + ie->RNC_ID = (uint16_t)liblte_bits_2_value(ptr, 1.0*8); + liblte_align_up(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE RRC_Establishment_Cause ENUMERATED +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_rrc_establishment_cause( + LIBLTE_S1AP_RRC_ESTABLISHMENT_CAUSE_ENUM_EXT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("RRC_Establishment_Cause error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // Enum + liblte_value_2_bits(ie->e, ptr, 3); + liblte_align_up_zero(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_rrc_establishment_cause( + uint8_t **ptr, + LIBLTE_S1AP_RRC_ESTABLISHMENT_CAUSE_ENUM_EXT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("RRC_Establishment_Cause error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // Enum + ie->e = (LIBLTE_S1AP_RRC_ESTABLISHMENT_CAUSE_ENUM)liblte_bits_2_value(ptr, 3); + liblte_align_up(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE Routing_ID INTEGER +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_routing_id( + LIBLTE_S1AP_ROUTING_ID_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Integer - ie->Routing_ID + // lb:0, ub:255 + liblte_align_up_zero(ptr, 8); + liblte_value_2_bits(0, ptr, (1*8)-8); + liblte_value_2_bits(ie->Routing_ID, ptr, 8); + liblte_align_up_zero(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_routing_id( + uint8_t **ptr, + LIBLTE_S1AP_ROUTING_ID_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Integer - ie->Routing_ID + // lb:0, ub:255 + liblte_align_up(ptr, 8); + ie->Routing_ID = (uint8_t)liblte_bits_2_value(ptr, 1.0*8); + liblte_align_up(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE SONInformationRequest ENUMERATED +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_soninformationrequest( + LIBLTE_S1AP_SONINFORMATIONREQUEST_ENUM_EXT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("SONInformationRequest error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // Enum + liblte_value_2_bits(ie->e, ptr, 1); + liblte_align_up_zero(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_soninformationrequest( + uint8_t **ptr, + LIBLTE_S1AP_SONINFORMATIONREQUEST_ENUM_EXT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("SONInformationRequest error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // Enum + ie->e = (LIBLTE_S1AP_SONINFORMATIONREQUEST_ENUM)liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE Source_ToTarget_TransparentContainer DYNAMIC OCTET STRING +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_source_totarget_transparentcontainer( + LIBLTE_S1AP_SOURCE_TOTARGET_TRANSPARENTCONTAINER_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Dynamic octet string - Source-ToTarget-TransparentContainer + // Length + if(ie->n_octets < 128) { + liblte_value_2_bits(0, ptr, 1); + liblte_value_2_bits(ie->n_octets, ptr, 7); + } else if(ie->n_octets < 16383) { + liblte_value_2_bits(1, ptr, 1); + liblte_value_2_bits(0, ptr, 1); + liblte_value_2_bits(ie->n_octets, ptr, 14); + } else { + // FIXME: Unlikely to have more than 16K of octets + } + + // Octets + uint32_t i; + for(i=0;in_octets;i++) { + liblte_value_2_bits(ie->buffer[i], ptr, 8); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_source_totarget_transparentcontainer( + uint8_t **ptr, + LIBLTE_S1AP_SOURCE_TOTARGET_TRANSPARENTCONTAINER_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Dynamic octet string - Source-ToTarget-TransparentContainer + // Length + if(0 == liblte_bits_2_value(ptr, 1)) { + ie->n_octets = liblte_bits_2_value(ptr, 7); + } else { + if(0 == liblte_bits_2_value(ptr, 1)) { + ie->n_octets = liblte_bits_2_value(ptr, 14); + } else { + // FIXME: Unlikely to have more than 16K of octets + } + } + + // Octets + uint32_t i; + for(i=0;in_octets;i++) { + ie->buffer[i] = liblte_bits_2_value(ptr, 8); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE SRVCCHOIndication ENUMERATED +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_srvcchoindication( + LIBLTE_S1AP_SRVCCHOINDICATION_ENUM_EXT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("SRVCCHOIndication error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // Enum + liblte_value_2_bits(ie->e, ptr, 1); + liblte_align_up_zero(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_srvcchoindication( + uint8_t **ptr, + LIBLTE_S1AP_SRVCCHOINDICATION_ENUM_EXT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("SRVCCHOIndication error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // Enum + ie->e = (LIBLTE_S1AP_SRVCCHOINDICATION_ENUM)liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE SourceRNC_ToTargetRNC_TransparentContainer DYNAMIC OCTET STRING +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_sourcernc_totargetrnc_transparentcontainer( + LIBLTE_S1AP_SOURCERNC_TOTARGETRNC_TRANSPARENTCONTAINER_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Dynamic octet string - SourceRNC-ToTargetRNC-TransparentContainer + // Length + if(ie->n_octets < 128) { + liblte_value_2_bits(0, ptr, 1); + liblte_value_2_bits(ie->n_octets, ptr, 7); + } else if(ie->n_octets < 16383) { + liblte_value_2_bits(1, ptr, 1); + liblte_value_2_bits(0, ptr, 1); + liblte_value_2_bits(ie->n_octets, ptr, 14); + } else { + // FIXME: Unlikely to have more than 16K of octets + } + + // Octets + uint32_t i; + for(i=0;in_octets;i++) { + liblte_value_2_bits(ie->buffer[i], ptr, 8); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_sourcernc_totargetrnc_transparentcontainer( + uint8_t **ptr, + LIBLTE_S1AP_SOURCERNC_TOTARGETRNC_TRANSPARENTCONTAINER_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Dynamic octet string - SourceRNC-ToTargetRNC-TransparentContainer + // Length + if(0 == liblte_bits_2_value(ptr, 1)) { + ie->n_octets = liblte_bits_2_value(ptr, 7); + } else { + if(0 == liblte_bits_2_value(ptr, 1)) { + ie->n_octets = liblte_bits_2_value(ptr, 14); + } else { + // FIXME: Unlikely to have more than 16K of octets + } + } + + // Octets + uint32_t i; + for(i=0;in_octets;i++) { + ie->buffer[i] = liblte_bits_2_value(ptr, 8); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE SubscriberProfileIDforRFP INTEGER +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_subscriberprofileidforrfp( + LIBLTE_S1AP_SUBSCRIBERPROFILEIDFORRFP_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Integer - ie->SubscriberProfileIDforRFP + // lb:1, ub:256 + liblte_align_up_zero(ptr, 8); + liblte_value_2_bits(0, ptr, (1*8)-8); + liblte_value_2_bits(ie->SubscriberProfileIDforRFP, ptr, 8); + liblte_align_up_zero(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_subscriberprofileidforrfp( + uint8_t **ptr, + LIBLTE_S1AP_SUBSCRIBERPROFILEIDFORRFP_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Integer - ie->SubscriberProfileIDforRFP + // lb:1, ub:256 + liblte_align_up(ptr, 8); + ie->SubscriberProfileIDforRFP = (uint8_t)liblte_bits_2_value(ptr, 1.0*8); + liblte_align_up(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE SynchronizationStatus ENUMERATED +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_synchronizationstatus( + LIBLTE_S1AP_SYNCHRONIZATIONSTATUS_ENUM_EXT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("SynchronizationStatus error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // Enum + liblte_value_2_bits(ie->e, ptr, 1); + liblte_align_up_zero(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_synchronizationstatus( + uint8_t **ptr, + LIBLTE_S1AP_SYNCHRONIZATIONSTATUS_ENUM_EXT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("SynchronizationStatus error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // Enum + ie->e = (LIBLTE_S1AP_SYNCHRONIZATIONSTATUS_ENUM)liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE TargetRNC_ToSourceRNC_TransparentContainer DYNAMIC OCTET STRING +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_targetrnc_tosourcernc_transparentcontainer( + LIBLTE_S1AP_TARGETRNC_TOSOURCERNC_TRANSPARENTCONTAINER_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Dynamic octet string - TargetRNC-ToSourceRNC-TransparentContainer + // Length + if(ie->n_octets < 128) { + liblte_value_2_bits(0, ptr, 1); + liblte_value_2_bits(ie->n_octets, ptr, 7); + } else if(ie->n_octets < 16383) { + liblte_value_2_bits(1, ptr, 1); + liblte_value_2_bits(0, ptr, 1); + liblte_value_2_bits(ie->n_octets, ptr, 14); + } else { + // FIXME: Unlikely to have more than 16K of octets + } + + // Octets + uint32_t i; + for(i=0;in_octets;i++) { + liblte_value_2_bits(ie->buffer[i], ptr, 8); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_targetrnc_tosourcernc_transparentcontainer( + uint8_t **ptr, + LIBLTE_S1AP_TARGETRNC_TOSOURCERNC_TRANSPARENTCONTAINER_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Dynamic octet string - TargetRNC-ToSourceRNC-TransparentContainer + // Length + if(0 == liblte_bits_2_value(ptr, 1)) { + ie->n_octets = liblte_bits_2_value(ptr, 7); + } else { + if(0 == liblte_bits_2_value(ptr, 1)) { + ie->n_octets = liblte_bits_2_value(ptr, 14); + } else { + // FIXME: Unlikely to have more than 16K of octets + } + } + + // Octets + uint32_t i; + for(i=0;in_octets;i++) { + ie->buffer[i] = liblte_bits_2_value(ptr, 8); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE Threshold_RSRQ INTEGER +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_threshold_rsrq( + LIBLTE_S1AP_THRESHOLD_RSRQ_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Integer - ie->Threshold_RSRQ + // lb:0, ub:34 + liblte_value_2_bits(ie->Threshold_RSRQ, ptr, 6); + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_threshold_rsrq( + uint8_t **ptr, + LIBLTE_S1AP_THRESHOLD_RSRQ_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Integer - ie->Threshold_RSRQ + // lb:0, ub:34 + ie->Threshold_RSRQ = (uint8_t)liblte_bits_2_value(ptr, 6); + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE Time_UE_StayedInCell INTEGER +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_time_ue_stayedincell( + LIBLTE_S1AP_TIME_UE_STAYEDINCELL_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Integer - ie->Time_UE_StayedInCell + // lb:0, ub:4095 + liblte_align_up_zero(ptr, 8); + liblte_value_2_bits(0, ptr, (1*8)-12); + liblte_value_2_bits(ie->Time_UE_StayedInCell, ptr, 12); + liblte_align_up_zero(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_time_ue_stayedincell( + uint8_t **ptr, + LIBLTE_S1AP_TIME_UE_STAYEDINCELL_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Integer - ie->Time_UE_StayedInCell + // lb:0, ub:4095 + liblte_align_up(ptr, 8); + ie->Time_UE_StayedInCell = (uint16_t)liblte_bits_2_value(ptr, 1.0*8); + liblte_align_up(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE TransportLayerAddress DYNAMIC BIT STRING +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_transportlayeraddress( + LIBLTE_S1AP_TRANSPORTLAYERADDRESS_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Dynamic bit string - TransportLayerAddress + // lb:1, ub:160 + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("TransportLayerAddress error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // Length + liblte_value_2_bits(ie->n_bits-1, ptr, 8); + liblte_align_up_zero(ptr, 8); + + // Bits + uint32_t i; + for(i=0;in_bits;i++) { + liblte_value_2_bits(ie->buffer[i], ptr, 1); + } + liblte_align_up_zero(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_transportlayeraddress( + uint8_t **ptr, + LIBLTE_S1AP_TRANSPORTLAYERADDRESS_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Dynamic bit string - TransportLayerAddress + // lb:1, ub:160 + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("TransportLayerAddress error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // Length + ie->n_bits = liblte_bits_2_value(ptr, 8) + 1; + liblte_align_up(ptr, 8); + + // Bits + uint32_t i; + for(i=0;in_bits;i++) { + ie->buffer[i] = liblte_bits_2_value(ptr, 1); + } + liblte_align_up(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE TraceDepth ENUMERATED +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_tracedepth( + LIBLTE_S1AP_TRACEDEPTH_ENUM_EXT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("TraceDepth error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // Enum + liblte_value_2_bits(ie->e, ptr, 3); + liblte_align_up_zero(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_tracedepth( + uint8_t **ptr, + LIBLTE_S1AP_TRACEDEPTH_ENUM_EXT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("TraceDepth error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // Enum + ie->e = (LIBLTE_S1AP_TRACEDEPTH_ENUM)liblte_bits_2_value(ptr, 3); + liblte_align_up(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE TrafficLoadReductionIndication INTEGER +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_trafficloadreductionindication( + LIBLTE_S1AP_TRAFFICLOADREDUCTIONINDICATION_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Integer - ie->TrafficLoadReductionIndication + // lb:1, ub:99 + liblte_value_2_bits(ie->TrafficLoadReductionIndication, ptr, 7); + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_trafficloadreductionindication( + uint8_t **ptr, + LIBLTE_S1AP_TRAFFICLOADREDUCTIONINDICATION_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Integer - ie->TrafficLoadReductionIndication + // lb:1, ub:99 + ie->TrafficLoadReductionIndication = (uint8_t)liblte_bits_2_value(ptr, 7); + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE UERadioCapability DYNAMIC OCTET STRING +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_ueradiocapability( + LIBLTE_S1AP_UERADIOCAPABILITY_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Dynamic octet string - UERadioCapability + // Length + if(ie->n_octets < 128) { + liblte_value_2_bits(0, ptr, 1); + liblte_value_2_bits(ie->n_octets, ptr, 7); + } else if(ie->n_octets < 16383) { + liblte_value_2_bits(1, ptr, 1); + liblte_value_2_bits(0, ptr, 1); + liblte_value_2_bits(ie->n_octets, ptr, 14); + } else { + // FIXME: Unlikely to have more than 16K of octets + } + + // Octets + uint32_t i; + for(i=0;in_octets;i++) { + liblte_value_2_bits(ie->buffer[i], ptr, 8); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_ueradiocapability( + uint8_t **ptr, + LIBLTE_S1AP_UERADIOCAPABILITY_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Dynamic octet string - UERadioCapability + // Length + if(0 == liblte_bits_2_value(ptr, 1)) { + ie->n_octets = liblte_bits_2_value(ptr, 7); + } else { + if(0 == liblte_bits_2_value(ptr, 1)) { + ie->n_octets = liblte_bits_2_value(ptr, 14); + } else { + // FIXME: Unlikely to have more than 16K of octets + } + } + + // Octets + uint32_t i; + for(i=0;in_octets;i++) { + ie->buffer[i] = liblte_bits_2_value(ptr, 8); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE WarningType STATIC OCTET STRING +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_warningtype( + LIBLTE_S1AP_WARNINGTYPE_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Static octet string - WarningType + if(LIBLTE_S1AP_WARNINGTYPE_OCTET_STRING_LEN > 2) { // X.691 Sec.16 + liblte_align_up_zero(ptr, 8); + } + // Octets + uint32_t i; + for(i=0;ibuffer[i], ptr, 8); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_warningtype( + uint8_t **ptr, + LIBLTE_S1AP_WARNINGTYPE_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Static octet string - WarningType + if(LIBLTE_S1AP_WARNINGTYPE_OCTET_STRING_LEN > 2) { // X.691 Sec.16 + liblte_align_up(ptr, 8); + } + // Octets + uint32_t i; + for(i=0;ibuffer[i] = liblte_bits_2_value(ptr, 8); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE WarningMessageContents DYNAMIC OCTET STRING +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_warningmessagecontents( + LIBLTE_S1AP_WARNINGMESSAGECONTENTS_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Dynamic octet string - WarningMessageContents + // Length + if(ie->n_octets < 128) { + liblte_value_2_bits(0, ptr, 1); + liblte_value_2_bits(ie->n_octets, ptr, 7); + } else if(ie->n_octets < 16383) { + liblte_value_2_bits(1, ptr, 1); + liblte_value_2_bits(0, ptr, 1); + liblte_value_2_bits(ie->n_octets, ptr, 14); + } else { + // FIXME: Unlikely to have more than 16K of octets + } + + // Octets + uint32_t i; + for(i=0;in_octets;i++) { + liblte_value_2_bits(ie->buffer[i], ptr, 8); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_warningmessagecontents( + uint8_t **ptr, + LIBLTE_S1AP_WARNINGMESSAGECONTENTS_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Dynamic octet string - WarningMessageContents + // Length + if(0 == liblte_bits_2_value(ptr, 1)) { + ie->n_octets = liblte_bits_2_value(ptr, 7); + } else { + if(0 == liblte_bits_2_value(ptr, 1)) { + ie->n_octets = liblte_bits_2_value(ptr, 14); + } else { + // FIXME: Unlikely to have more than 16K of octets + } + } + + // Octets + uint32_t i; + for(i=0;in_octets;i++) { + ie->buffer[i] = liblte_bits_2_value(ptr, 8); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE CauseProtocol ENUMERATED +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_causeprotocol( + LIBLTE_S1AP_CAUSEPROTOCOL_ENUM_EXT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("CauseProtocol error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // Enum + liblte_value_2_bits(ie->e, ptr, 3); + liblte_align_up_zero(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_causeprotocol( + uint8_t **ptr, + LIBLTE_S1AP_CAUSEPROTOCOL_ENUM_EXT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("CauseProtocol error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // Enum + ie->e = (LIBLTE_S1AP_CAUSEPROTOCOL_ENUM)liblte_bits_2_value(ptr, 3); + liblte_align_up(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE CellAccessMode ENUMERATED +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_cellaccessmode( + LIBLTE_S1AP_CELLACCESSMODE_ENUM_EXT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("CellAccessMode error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // Enum + liblte_value_2_bits(ie->e, ptr, 0); + liblte_align_up_zero(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_cellaccessmode( + uint8_t **ptr, + LIBLTE_S1AP_CELLACCESSMODE_ENUM_EXT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("CellAccessMode error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // Enum + ie->e = (LIBLTE_S1AP_CELLACCESSMODE_ENUM)liblte_bits_2_value(ptr, 0); + liblte_align_up(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE Cdma2000RATType ENUMERATED +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_cdma2000rattype( + LIBLTE_S1AP_CDMA2000RATTYPE_ENUM_EXT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("Cdma2000RATType error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // Enum + liblte_value_2_bits(ie->e, ptr, 1); + liblte_align_up_zero(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_cdma2000rattype( + uint8_t **ptr, + LIBLTE_S1AP_CDMA2000RATTYPE_ENUM_EXT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("Cdma2000RATType error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // Enum + ie->e = (LIBLTE_S1AP_CDMA2000RATTYPE_ENUM)liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE Cdma2000OneXMEID DYNAMIC OCTET STRING +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_cdma2000onexmeid( + LIBLTE_S1AP_CDMA2000ONEXMEID_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Dynamic octet string - Cdma2000OneXMEID + // Length + if(ie->n_octets < 128) { + liblte_value_2_bits(0, ptr, 1); + liblte_value_2_bits(ie->n_octets, ptr, 7); + } else if(ie->n_octets < 16383) { + liblte_value_2_bits(1, ptr, 1); + liblte_value_2_bits(0, ptr, 1); + liblte_value_2_bits(ie->n_octets, ptr, 14); + } else { + // FIXME: Unlikely to have more than 16K of octets + } + + // Octets + uint32_t i; + for(i=0;in_octets;i++) { + liblte_value_2_bits(ie->buffer[i], ptr, 8); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_cdma2000onexmeid( + uint8_t **ptr, + LIBLTE_S1AP_CDMA2000ONEXMEID_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Dynamic octet string - Cdma2000OneXMEID + // Length + if(0 == liblte_bits_2_value(ptr, 1)) { + ie->n_octets = liblte_bits_2_value(ptr, 7); + } else { + if(0 == liblte_bits_2_value(ptr, 1)) { + ie->n_octets = liblte_bits_2_value(ptr, 14); + } else { + // FIXME: Unlikely to have more than 16K of octets + } + } + + // Octets + uint32_t i; + for(i=0;in_octets;i++) { + ie->buffer[i] = liblte_bits_2_value(ptr, 8); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE Cell_Size ENUMERATED +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_cell_size( + LIBLTE_S1AP_CELL_SIZE_ENUM_EXT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("Cell_Size error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // Enum + liblte_value_2_bits(ie->e, ptr, 2); + liblte_align_up_zero(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_cell_size( + uint8_t **ptr, + LIBLTE_S1AP_CELL_SIZE_ENUM_EXT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("Cell_Size error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // Enum + ie->e = (LIBLTE_S1AP_CELL_SIZE_ENUM)liblte_bits_2_value(ptr, 2); + liblte_align_up(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE CI STATIC OCTET STRING +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_ci( + LIBLTE_S1AP_CI_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Static octet string - CI + if(LIBLTE_S1AP_CI_OCTET_STRING_LEN > 2) { // X.691 Sec.16 + liblte_align_up_zero(ptr, 8); + } + // Octets + uint32_t i; + for(i=0;ibuffer[i], ptr, 8); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_ci( + uint8_t **ptr, + LIBLTE_S1AP_CI_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Static octet string - CI + if(LIBLTE_S1AP_CI_OCTET_STRING_LEN > 2) { // X.691 Sec.16 + liblte_align_up(ptr, 8); + } + // Octets + uint32_t i; + for(i=0;ibuffer[i] = liblte_bits_2_value(ptr, 8); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE CSFallbackIndicator ENUMERATED +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_csfallbackindicator( + LIBLTE_S1AP_CSFALLBACKINDICATOR_ENUM_EXT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("CSFallbackIndicator error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // Enum + liblte_value_2_bits(ie->e, ptr, 1); + liblte_align_up_zero(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_csfallbackindicator( + uint8_t **ptr, + LIBLTE_S1AP_CSFALLBACKINDICATOR_ENUM_EXT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("CSFallbackIndicator error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // Enum + ie->e = (LIBLTE_S1AP_CSFALLBACKINDICATOR_ENUM)liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE CSGMembershipStatus ENUMERATED +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_csgmembershipstatus( + LIBLTE_S1AP_CSGMEMBERSHIPSTATUS_ENUM *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Enum - *ie + liblte_value_2_bits(*ie, ptr, 1); + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_csgmembershipstatus( + uint8_t **ptr, + LIBLTE_S1AP_CSGMEMBERSHIPSTATUS_ENUM *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Enum - *ie + *ie = (LIBLTE_S1AP_CSGMEMBERSHIPSTATUS_ENUM)liblte_bits_2_value(ptr, 1); + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE DataCodingScheme STATIC BIT STRING +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_datacodingscheme( + LIBLTE_S1AP_DATACODINGSCHEME_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Static bit string - DataCodingScheme + uint32_t i; + for(i=0;ibuffer[i], ptr, 1); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_datacodingscheme( + uint8_t **ptr, + LIBLTE_S1AP_DATACODINGSCHEME_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Static bit string - DataCodingScheme + uint32_t i; + for(i=0;ibuffer[i] = liblte_bits_2_value(ptr, 1); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE EmergencyAreaIDList DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:65535 +LIBLTE_ERROR_ENUM liblte_s1ap_pack_emergencyareaidlist( + LIBLTE_S1AP_EMERGENCYAREAIDLIST_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + if(ie->len > 32) { + liblte_log_print("EmergencyAreaIDList pack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_ENCODE_FAIL; + } + // Length + liblte_value_2_bits(ie->len-1, ptr, 16); + liblte_align_up_zero(ptr, 8); + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_pack_emergencyareaid(&ie->buffer[i], ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_emergencyareaidlist( + uint8_t **ptr, + LIBLTE_S1AP_EMERGENCYAREAIDLIST_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Length + ie->len = liblte_bits_2_value(ptr, 16) + 1; + liblte_align_up(ptr, 8); + if(ie->len > 32) { + liblte_log_print("EmergencyAreaIDList unpack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_DECODE_FAIL; + } + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_unpack_emergencyareaid(ptr, &ie->buffer[i]) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE EmergencyAreaIDListForRestart DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:256 +LIBLTE_ERROR_ENUM liblte_s1ap_pack_emergencyareaidlistforrestart( + LIBLTE_S1AP_EMERGENCYAREAIDLISTFORRESTART_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + if(ie->len > 32) { + liblte_log_print("EmergencyAreaIDListForRestart pack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_ENCODE_FAIL; + } + // Length + liblte_value_2_bits(ie->len-1, ptr, 8); + liblte_align_up_zero(ptr, 8); + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_pack_emergencyareaid(&ie->buffer[i], ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_emergencyareaidlistforrestart( + uint8_t **ptr, + LIBLTE_S1AP_EMERGENCYAREAIDLISTFORRESTART_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Length + ie->len = liblte_bits_2_value(ptr, 8) + 1; + liblte_align_up(ptr, 8); + if(ie->len > 32) { + liblte_log_print("EmergencyAreaIDListForRestart unpack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_DECODE_FAIL; + } + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_unpack_emergencyareaid(ptr, &ie->buffer[i]) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE ENB_UE_S1AP_ID INTEGER +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_enb_ue_s1ap_id( + LIBLTE_S1AP_ENB_UE_S1AP_ID_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Integer - ie->ENB_UE_S1AP_ID + // lb:0, ub:16777215 + // Range > 65536 - encoded based on value + { + uint32_t n_bits = floor(log2(ie->ENB_UE_S1AP_ID-0)+1); + uint32_t n_octets = (n_bits+7)/8; + liblte_value_2_bits(n_octets-1, ptr, 2); + liblte_align_up_zero(ptr, 8); + liblte_value_2_bits(0, ptr, (n_octets*8)-n_bits); + liblte_value_2_bits(ie->ENB_UE_S1AP_ID-0, ptr, n_bits); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_enb_ue_s1ap_id( + uint8_t **ptr, + LIBLTE_S1AP_ENB_UE_S1AP_ID_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Integer - ie->ENB_UE_S1AP_ID + // lb:0, ub:16777215 + // Range > 65536 - encoded based on value + { + uint32_t n_octets = liblte_bits_2_value(ptr, 2) + 1; + liblte_align_up(ptr, 8); + ie->ENB_UE_S1AP_ID = liblte_bits_2_value(ptr, n_octets*8) + 0; + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE E_RAB_ID INTEGER +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rab_id( + LIBLTE_S1AP_E_RAB_ID_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Integer - ie->E_RAB_ID + // lb:0, ub:15 + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("ie->E_RAB_ID error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_value_2_bits(ie->E_RAB_ID, ptr, 4); + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rab_id( + uint8_t **ptr, + LIBLTE_S1AP_E_RAB_ID_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Integer - ie->E_RAB_ID + // lb:0, ub:15 + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("ie->E_RAB_ID error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + ie->E_RAB_ID = (uint8_t)liblte_bits_2_value(ptr, 4); + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE E_RABInformationListItem SEQUENCE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabinformationlistitem( + LIBLTE_S1AP_E_RABINFORMATIONLISTITEM_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("E_RABInformationListItem error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + liblte_value_2_bits(ie->dL_Forwarding_present?1:0, ptr, 1); + liblte_value_2_bits(ie->iE_Extensions_present?1:0, ptr, 1); + + if(liblte_s1ap_pack_e_rab_id(&ie->e_RAB_ID, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(ie->dL_Forwarding_present) { + if(liblte_s1ap_pack_dl_forwarding(&ie->dL_Forwarding, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_pack_protocolextensioncontainer(&ie->iE_Extensions, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabinformationlistitem( + uint8_t **ptr, + LIBLTE_S1AP_E_RABINFORMATIONLISTITEM_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("E_RABInformationListItem error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + ie->dL_Forwarding_present = liblte_bits_2_value(ptr, 1); + ie->iE_Extensions_present = liblte_bits_2_value(ptr, 1); + + if(liblte_s1ap_unpack_e_rab_id(ptr, &ie->e_RAB_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(ie->dL_Forwarding_present) { + if(liblte_s1ap_unpack_dl_forwarding(ptr, &ie->dL_Forwarding) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_unpack_protocolextensioncontainer(ptr, &ie->iE_Extensions) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE EUTRANRoundTripDelayEstimationInfo INTEGER +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_eutranroundtripdelayestimationinfo( + LIBLTE_S1AP_EUTRANROUNDTRIPDELAYESTIMATIONINFO_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Integer - ie->EUTRANRoundTripDelayEstimationInfo + // lb:0, ub:2047 + liblte_align_up_zero(ptr, 8); + liblte_value_2_bits(0, ptr, (1*8)-11); + liblte_value_2_bits(ie->EUTRANRoundTripDelayEstimationInfo, ptr, 11); + liblte_align_up_zero(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_eutranroundtripdelayestimationinfo( + uint8_t **ptr, + LIBLTE_S1AP_EUTRANROUNDTRIPDELAYESTIMATIONINFO_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Integer - ie->EUTRANRoundTripDelayEstimationInfo + // lb:0, ub:2047 + liblte_align_up(ptr, 8); + ie->EUTRANRoundTripDelayEstimationInfo = (uint16_t)liblte_bits_2_value(ptr, 1.0*8); + liblte_align_up(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE ForbiddenLACs DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:4096 +LIBLTE_ERROR_ENUM liblte_s1ap_pack_forbiddenlacs( + LIBLTE_S1AP_FORBIDDENLACS_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + if(ie->len > 32) { + liblte_log_print("ForbiddenLACs pack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_ENCODE_FAIL; + } + // Length + liblte_value_2_bits(ie->len-1, ptr, 12); + liblte_align_up_zero(ptr, 8); + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_pack_lac(&ie->buffer[i], ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_forbiddenlacs( + uint8_t **ptr, + LIBLTE_S1AP_FORBIDDENLACS_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Length + ie->len = liblte_bits_2_value(ptr, 12) + 1; + liblte_align_up(ptr, 8); + if(ie->len > 32) { + liblte_log_print("ForbiddenLACs unpack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_DECODE_FAIL; + } + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_unpack_lac(ptr, &ie->buffer[i]) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE GTP_TEID STATIC OCTET STRING +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_gtp_teid( + LIBLTE_S1AP_GTP_TEID_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Static octet string - GTP-TEID + if(LIBLTE_S1AP_GTP_TEID_OCTET_STRING_LEN > 2) { // X.691 Sec.16 + liblte_align_up_zero(ptr, 8); + } + // Octets + uint32_t i; + for(i=0;ibuffer[i], ptr, 8); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_gtp_teid( + uint8_t **ptr, + LIBLTE_S1AP_GTP_TEID_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Static octet string - GTP-TEID + if(LIBLTE_S1AP_GTP_TEID_OCTET_STRING_LEN > 2) { // X.691 Sec.16 + liblte_align_up(ptr, 8); + } + // Octets + uint32_t i; + for(i=0;ibuffer[i] = liblte_bits_2_value(ptr, 8); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE GUMMEIType ENUMERATED +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_gummeitype( + LIBLTE_S1AP_GUMMEITYPE_ENUM_EXT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("GUMMEIType error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // Enum + liblte_value_2_bits(ie->e, ptr, 1); + liblte_align_up_zero(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_gummeitype( + uint8_t **ptr, + LIBLTE_S1AP_GUMMEITYPE_ENUM_EXT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("GUMMEIType error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // Enum + ie->e = (LIBLTE_S1AP_GUMMEITYPE_ENUM)liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE HandoverType ENUMERATED +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_handovertype( + LIBLTE_S1AP_HANDOVERTYPE_ENUM_EXT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("HandoverType error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // Enum + liblte_value_2_bits(ie->e, ptr, 3); + liblte_align_up_zero(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_handovertype( + uint8_t **ptr, + LIBLTE_S1AP_HANDOVERTYPE_ENUM_EXT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("HandoverType error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // Enum + ie->e = (LIBLTE_S1AP_HANDOVERTYPE_ENUM)liblte_bits_2_value(ptr, 3); + liblte_align_up(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE IntegrityProtectionAlgorithms STATIC BIT STRING +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_integrityprotectionalgorithms( + LIBLTE_S1AP_INTEGRITYPROTECTIONALGORITHMS_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Static bit string - IntegrityProtectionAlgorithms + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("IntegrityProtectionAlgorithms error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + uint32_t i; + for(i=0;ibuffer[i], ptr, 1); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_integrityprotectionalgorithms( + uint8_t **ptr, + LIBLTE_S1AP_INTEGRITYPROTECTIONALGORITHMS_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Static bit string - IntegrityProtectionAlgorithms + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("IntegrityProtectionAlgorithms error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + uint32_t i; + for(i=0;ibuffer[i] = liblte_bits_2_value(ptr, 1); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE LastVisitedGERANCellInformation CHOICE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_lastvisitedgerancellinformation( + LIBLTE_S1AP_LASTVISITEDGERANCELLINFORMATION_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("LastVisitedGERANCellInformation error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // Choice type + liblte_value_2_bits(ie->choice_type, ptr, 0); + + // Choice + if(ie->choice_type == LIBLTE_S1AP_LASTVISITEDGERANCELLINFORMATION_CHOICE_UNDEFINED) { + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_lastvisitedgerancellinformation( + uint8_t **ptr, + LIBLTE_S1AP_LASTVISITEDGERANCELLINFORMATION_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("LastVisitedGERANCellInformation error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // Choice type + ie->choice_type = (LIBLTE_S1AP_LASTVISITEDGERANCELLINFORMATION_CHOICE_ENUM)liblte_bits_2_value(ptr, 0); + + // Choice + if(ie->choice_type == LIBLTE_S1AP_LASTVISITEDGERANCELLINFORMATION_CHOICE_UNDEFINED) { + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE Links_to_log ENUMERATED +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_links_to_log( + LIBLTE_S1AP_LINKS_TO_LOG_ENUM_EXT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("Links_to_log error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // Enum + liblte_value_2_bits(ie->e, ptr, 2); + liblte_align_up_zero(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_links_to_log( + uint8_t **ptr, + LIBLTE_S1AP_LINKS_TO_LOG_ENUM_EXT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("Links_to_log error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // Enum + ie->e = (LIBLTE_S1AP_LINKS_TO_LOG_ENUM)liblte_bits_2_value(ptr, 2); + liblte_align_up(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE LoggingInterval ENUMERATED +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_logginginterval( + LIBLTE_S1AP_LOGGINGINTERVAL_ENUM *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Enum - *ie + liblte_value_2_bits(*ie, ptr, 3); + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_logginginterval( + uint8_t **ptr, + LIBLTE_S1AP_LOGGINGINTERVAL_ENUM *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Enum - *ie + *ie = (LIBLTE_S1AP_LOGGINGINTERVAL_ENUM)liblte_bits_2_value(ptr, 3); + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE M3period ENUMERATED +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_m3period( + LIBLTE_S1AP_M3PERIOD_ENUM_EXT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("M3period error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // Enum + liblte_value_2_bits(ie->e, ptr, 2); + liblte_align_up_zero(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_m3period( + uint8_t **ptr, + LIBLTE_S1AP_M3PERIOD_ENUM_EXT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("M3period error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // Enum + ie->e = (LIBLTE_S1AP_M3PERIOD_ENUM)liblte_bits_2_value(ptr, 2); + liblte_align_up(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE M4period ENUMERATED +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_m4period( + LIBLTE_S1AP_M4PERIOD_ENUM_EXT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("M4period error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // Enum + liblte_value_2_bits(ie->e, ptr, 3); + liblte_align_up_zero(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_m4period( + uint8_t **ptr, + LIBLTE_S1AP_M4PERIOD_ENUM_EXT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("M4period error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // Enum + ie->e = (LIBLTE_S1AP_M4PERIOD_ENUM)liblte_bits_2_value(ptr, 3); + liblte_align_up(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE M5period ENUMERATED +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_m5period( + LIBLTE_S1AP_M5PERIOD_ENUM_EXT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("M5period error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // Enum + liblte_value_2_bits(ie->e, ptr, 3); + liblte_align_up_zero(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_m5period( + uint8_t **ptr, + LIBLTE_S1AP_M5PERIOD_ENUM_EXT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("M5period error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // Enum + ie->e = (LIBLTE_S1AP_M5PERIOD_ENUM)liblte_bits_2_value(ptr, 3); + liblte_align_up(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE MobilityInformation STATIC BIT STRING +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_mobilityinformation( + LIBLTE_S1AP_MOBILITYINFORMATION_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Static bit string - MobilityInformation + liblte_align_up_zero(ptr, 8); + uint32_t i; + for(i=0;ibuffer[i], ptr, 1); + } + liblte_align_up_zero(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_mobilityinformation( + uint8_t **ptr, + LIBLTE_S1AP_MOBILITYINFORMATION_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Static bit string - MobilityInformation + liblte_align_up(ptr, 8); + uint32_t i; + for(i=0;ibuffer[i] = liblte_bits_2_value(ptr, 1); + } + liblte_align_up(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE MME_Code STATIC OCTET STRING +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_mme_code( + LIBLTE_S1AP_MME_CODE_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Static octet string - MME-Code + if(LIBLTE_S1AP_MME_CODE_OCTET_STRING_LEN > 2) { // X.691 Sec.16 + liblte_align_up_zero(ptr, 8); + } + // Octets + uint32_t i; + for(i=0;ibuffer[i], ptr, 8); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_mme_code( + uint8_t **ptr, + LIBLTE_S1AP_MME_CODE_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Static octet string - MME-Code + if(LIBLTE_S1AP_MME_CODE_OCTET_STRING_LEN > 2) { // X.691 Sec.16 + liblte_align_up(ptr, 8); + } + // Octets + uint32_t i; + for(i=0;ibuffer[i] = liblte_bits_2_value(ptr, 8); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE MSClassmark3 DYNAMIC OCTET STRING +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_msclassmark3( + LIBLTE_S1AP_MSCLASSMARK3_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Dynamic octet string - MSClassmark3 + // Length + if(ie->n_octets < 128) { + liblte_value_2_bits(0, ptr, 1); + liblte_value_2_bits(ie->n_octets, ptr, 7); + } else if(ie->n_octets < 16383) { + liblte_value_2_bits(1, ptr, 1); + liblte_value_2_bits(0, ptr, 1); + liblte_value_2_bits(ie->n_octets, ptr, 14); + } else { + // FIXME: Unlikely to have more than 16K of octets + } + + // Octets + uint32_t i; + for(i=0;in_octets;i++) { + liblte_value_2_bits(ie->buffer[i], ptr, 8); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_msclassmark3( + uint8_t **ptr, + LIBLTE_S1AP_MSCLASSMARK3_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Dynamic octet string - MSClassmark3 + // Length + if(0 == liblte_bits_2_value(ptr, 1)) { + ie->n_octets = liblte_bits_2_value(ptr, 7); + } else { + if(0 == liblte_bits_2_value(ptr, 1)) { + ie->n_octets = liblte_bits_2_value(ptr, 14); + } else { + // FIXME: Unlikely to have more than 16K of octets + } + } + + // Octets + uint32_t i; + for(i=0;in_octets;i++) { + ie->buffer[i] = liblte_bits_2_value(ptr, 8); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE NumberofBroadcastRequest INTEGER +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_numberofbroadcastrequest( + LIBLTE_S1AP_NUMBEROFBROADCASTREQUEST_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Integer - ie->NumberofBroadcastRequest + // lb:0, ub:65535 + liblte_align_up_zero(ptr, 8); + liblte_value_2_bits(0, ptr, (2*8)-16); + liblte_value_2_bits(ie->NumberofBroadcastRequest, ptr, 16); + liblte_align_up_zero(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_numberofbroadcastrequest( + uint8_t **ptr, + LIBLTE_S1AP_NUMBEROFBROADCASTREQUEST_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Integer - ie->NumberofBroadcastRequest + // lb:0, ub:65535 + liblte_align_up(ptr, 8); + ie->NumberofBroadcastRequest = (uint16_t)liblte_bits_2_value(ptr, 2.0*8); + liblte_align_up(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE OverloadResponse CHOICE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_overloadresponse( + LIBLTE_S1AP_OVERLOADRESPONSE_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("OverloadResponse error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // Choice type + liblte_value_2_bits(ie->choice_type, ptr, 0); + + // Choice + if(ie->choice_type == LIBLTE_S1AP_OVERLOADRESPONSE_CHOICE_OVERLOADACTION) { + if(liblte_s1ap_pack_overloadaction(&ie->choice.overloadAction, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_overloadresponse( + uint8_t **ptr, + LIBLTE_S1AP_OVERLOADRESPONSE_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("OverloadResponse error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // Choice type + ie->choice_type = (LIBLTE_S1AP_OVERLOADRESPONSE_CHOICE_ENUM)liblte_bits_2_value(ptr, 0); + + // Choice + if(ie->choice_type == LIBLTE_S1AP_OVERLOADRESPONSE_CHOICE_OVERLOADACTION) { + if(liblte_s1ap_unpack_overloadaction(ptr, &ie->choice.overloadAction) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE PDCP_SNExtended INTEGER +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_pdcp_snextended( + LIBLTE_S1AP_PDCP_SNEXTENDED_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Integer - ie->PDCP_SNExtended + // lb:0, ub:32767 + liblte_align_up_zero(ptr, 8); + liblte_value_2_bits(0, ptr, (1*8)-15); + liblte_value_2_bits(ie->PDCP_SNExtended, ptr, 15); + liblte_align_up_zero(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_pdcp_snextended( + uint8_t **ptr, + LIBLTE_S1AP_PDCP_SNEXTENDED_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Integer - ie->PDCP_SNExtended + // lb:0, ub:32767 + liblte_align_up(ptr, 8); + ie->PDCP_SNExtended = (uint16_t)liblte_bits_2_value(ptr, 1.0*8); + liblte_align_up(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE Pre_emptionCapability ENUMERATED +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_pre_emptioncapability( + LIBLTE_S1AP_PRE_EMPTIONCAPABILITY_ENUM *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Enum - *ie + liblte_value_2_bits(*ie, ptr, 1); + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_pre_emptioncapability( + uint8_t **ptr, + LIBLTE_S1AP_PRE_EMPTIONCAPABILITY_ENUM *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Enum - *ie + *ie = (LIBLTE_S1AP_PRE_EMPTIONCAPABILITY_ENUM)liblte_bits_2_value(ptr, 1); + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE QCI INTEGER +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_qci( + LIBLTE_S1AP_QCI_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Integer - ie->QCI + // lb:0, ub:255 + liblte_align_up_zero(ptr, 8); + liblte_value_2_bits(0, ptr, (1*8)-8); + liblte_value_2_bits(ie->QCI, ptr, 8); + liblte_align_up_zero(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_qci( + uint8_t **ptr, + LIBLTE_S1AP_QCI_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Integer - ie->QCI + // lb:0, ub:255 + liblte_align_up(ptr, 8); + ie->QCI = (uint8_t)liblte_bits_2_value(ptr, 1.0*8); + liblte_align_up(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE RelayNode_Indicator ENUMERATED +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_relaynode_indicator( + LIBLTE_S1AP_RELAYNODE_INDICATOR_ENUM_EXT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("RelayNode_Indicator error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // Enum + liblte_value_2_bits(ie->e, ptr, 0); + liblte_align_up_zero(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_relaynode_indicator( + uint8_t **ptr, + LIBLTE_S1AP_RELAYNODE_INDICATOR_ENUM_EXT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("RelayNode_Indicator error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // Enum + ie->e = (LIBLTE_S1AP_RELAYNODE_INDICATOR_ENUM)liblte_bits_2_value(ptr, 0); + liblte_align_up(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE M1ReportingTrigger ENUMERATED +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_m1reportingtrigger( + LIBLTE_S1AP_M1REPORTINGTRIGGER_ENUM_EXT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("M1ReportingTrigger error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // Enum + liblte_value_2_bits(ie->e, ptr, 2); + liblte_align_up_zero(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_m1reportingtrigger( + uint8_t **ptr, + LIBLTE_S1AP_M1REPORTINGTRIGGER_ENUM_EXT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("M1ReportingTrigger error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // Enum + ie->e = (LIBLTE_S1AP_M1REPORTINGTRIGGER_ENUM)liblte_bits_2_value(ptr, 2); + liblte_align_up(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE RIMInformation DYNAMIC OCTET STRING +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_riminformation( + LIBLTE_S1AP_RIMINFORMATION_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Dynamic octet string - RIMInformation + // Length + if(ie->n_octets < 128) { + liblte_value_2_bits(0, ptr, 1); + liblte_value_2_bits(ie->n_octets, ptr, 7); + } else if(ie->n_octets < 16383) { + liblte_value_2_bits(1, ptr, 1); + liblte_value_2_bits(0, ptr, 1); + liblte_value_2_bits(ie->n_octets, ptr, 14); + } else { + // FIXME: Unlikely to have more than 16K of octets + } + + // Octets + uint32_t i; + for(i=0;in_octets;i++) { + liblte_value_2_bits(ie->buffer[i], ptr, 8); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_riminformation( + uint8_t **ptr, + LIBLTE_S1AP_RIMINFORMATION_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Dynamic octet string - RIMInformation + // Length + if(0 == liblte_bits_2_value(ptr, 1)) { + ie->n_octets = liblte_bits_2_value(ptr, 7); + } else { + if(0 == liblte_bits_2_value(ptr, 1)) { + ie->n_octets = liblte_bits_2_value(ptr, 14); + } else { + // FIXME: Unlikely to have more than 16K of octets + } + } + + // Octets + uint32_t i; + for(i=0;in_octets;i++) { + ie->buffer[i] = liblte_bits_2_value(ptr, 8); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE RepetitionPeriod INTEGER +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_repetitionperiod( + LIBLTE_S1AP_REPETITIONPERIOD_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Integer - ie->RepetitionPeriod + // lb:0, ub:4095 + liblte_align_up_zero(ptr, 8); + liblte_value_2_bits(0, ptr, (1*8)-12); + liblte_value_2_bits(ie->RepetitionPeriod, ptr, 12); + liblte_align_up_zero(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_repetitionperiod( + uint8_t **ptr, + LIBLTE_S1AP_REPETITIONPERIOD_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Integer - ie->RepetitionPeriod + // lb:0, ub:4095 + liblte_align_up(ptr, 8); + ie->RepetitionPeriod = (uint16_t)liblte_bits_2_value(ptr, 1.0*8); + liblte_align_up(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE SecurityKey STATIC BIT STRING +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_securitykey( + LIBLTE_S1AP_SECURITYKEY_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Static bit string - SecurityKey + liblte_align_up_zero(ptr, 8); + uint32_t i; + for(i=0;ibuffer[i], ptr, 1); + } + liblte_align_up_zero(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_securitykey( + uint8_t **ptr, + LIBLTE_S1AP_SECURITYKEY_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Static bit string - SecurityKey + liblte_align_up(ptr, 8); + uint32_t i; + for(i=0;ibuffer[i] = liblte_bits_2_value(ptr, 1); + } + liblte_align_up(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE SerialNumber STATIC BIT STRING +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_serialnumber( + LIBLTE_S1AP_SERIALNUMBER_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Static bit string - SerialNumber + uint32_t i; + for(i=0;ibuffer[i], ptr, 1); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_serialnumber( + uint8_t **ptr, + LIBLTE_S1AP_SERIALNUMBER_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Static bit string - SerialNumber + uint32_t i; + for(i=0;ibuffer[i] = liblte_bits_2_value(ptr, 1); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE SourceBSS_ToTargetBSS_TransparentContainer DYNAMIC OCTET STRING +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_sourcebss_totargetbss_transparentcontainer( + LIBLTE_S1AP_SOURCEBSS_TOTARGETBSS_TRANSPARENTCONTAINER_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Dynamic octet string - SourceBSS-ToTargetBSS-TransparentContainer + // Length + if(ie->n_octets < 128) { + liblte_value_2_bits(0, ptr, 1); + liblte_value_2_bits(ie->n_octets, ptr, 7); + } else if(ie->n_octets < 16383) { + liblte_value_2_bits(1, ptr, 1); + liblte_value_2_bits(0, ptr, 1); + liblte_value_2_bits(ie->n_octets, ptr, 14); + } else { + // FIXME: Unlikely to have more than 16K of octets + } + + // Octets + uint32_t i; + for(i=0;in_octets;i++) { + liblte_value_2_bits(ie->buffer[i], ptr, 8); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_sourcebss_totargetbss_transparentcontainer( + uint8_t **ptr, + LIBLTE_S1AP_SOURCEBSS_TOTARGETBSS_TRANSPARENTCONTAINER_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Dynamic octet string - SourceBSS-ToTargetBSS-TransparentContainer + // Length + if(0 == liblte_bits_2_value(ptr, 1)) { + ie->n_octets = liblte_bits_2_value(ptr, 7); + } else { + if(0 == liblte_bits_2_value(ptr, 1)) { + ie->n_octets = liblte_bits_2_value(ptr, 14); + } else { + // FIXME: Unlikely to have more than 16K of octets + } + } + + // Octets + uint32_t i; + for(i=0;in_octets;i++) { + ie->buffer[i] = liblte_bits_2_value(ptr, 8); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE SRVCCOperationPossible ENUMERATED +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_srvccoperationpossible( + LIBLTE_S1AP_SRVCCOPERATIONPOSSIBLE_ENUM_EXT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("SRVCCOperationPossible error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // Enum + liblte_value_2_bits(ie->e, ptr, 0); + liblte_align_up_zero(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_srvccoperationpossible( + uint8_t **ptr, + LIBLTE_S1AP_SRVCCOPERATIONPOSSIBLE_ENUM_EXT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("SRVCCOperationPossible error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // Enum + ie->e = (LIBLTE_S1AP_SRVCCOPERATIONPOSSIBLE_ENUM)liblte_bits_2_value(ptr, 0); + liblte_align_up(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE ServedGroupIDs DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:65535 +LIBLTE_ERROR_ENUM liblte_s1ap_pack_servedgroupids( + LIBLTE_S1AP_SERVEDGROUPIDS_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + if(ie->len > 32) { + liblte_log_print("ServedGroupIDs pack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_ENCODE_FAIL; + } + // Length + liblte_value_2_bits(ie->len-1, ptr, 16); + liblte_align_up_zero(ptr, 8); + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_pack_mme_group_id(&ie->buffer[i], ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_servedgroupids( + uint8_t **ptr, + LIBLTE_S1AP_SERVEDGROUPIDS_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Length + ie->len = liblte_bits_2_value(ptr, 16) + 1; + liblte_align_up(ptr, 8); + if(ie->len > 32) { + liblte_log_print("ServedGroupIDs unpack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_DECODE_FAIL; + } + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_unpack_mme_group_id(ptr, &ie->buffer[i]) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE StratumLevel INTEGER +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_stratumlevel( + LIBLTE_S1AP_STRATUMLEVEL_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Integer - ie->StratumLevel + // lb:0, ub:3 + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("ie->StratumLevel error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_value_2_bits(ie->StratumLevel, ptr, 2); + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_stratumlevel( + uint8_t **ptr, + LIBLTE_S1AP_STRATUMLEVEL_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Integer - ie->StratumLevel + // lb:0, ub:3 + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("ie->StratumLevel error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + ie->StratumLevel = (uint8_t)liblte_bits_2_value(ptr, 2); + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE TAC STATIC OCTET STRING +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_tac( + LIBLTE_S1AP_TAC_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Static octet string - TAC + if(LIBLTE_S1AP_TAC_OCTET_STRING_LEN > 2) { // X.691 Sec.16 + liblte_align_up_zero(ptr, 8); + } + // Octets + uint32_t i; + for(i=0;ibuffer[i], ptr, 8); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_tac( + uint8_t **ptr, + LIBLTE_S1AP_TAC_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Static octet string - TAC + if(LIBLTE_S1AP_TAC_OCTET_STRING_LEN > 2) { // X.691 Sec.16 + liblte_align_up(ptr, 8); + } + // Octets + uint32_t i; + for(i=0;ibuffer[i] = liblte_bits_2_value(ptr, 8); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE TAListforMDT DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:8 +LIBLTE_ERROR_ENUM liblte_s1ap_pack_talistformdt( + LIBLTE_S1AP_TALISTFORMDT_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + if(ie->len > 32) { + liblte_log_print("TAListforMDT pack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_ENCODE_FAIL; + } + // Length + liblte_value_2_bits(ie->len-1, ptr, 3); + liblte_align_up_zero(ptr, 8); + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_pack_tac(&ie->buffer[i], ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_talistformdt( + uint8_t **ptr, + LIBLTE_S1AP_TALISTFORMDT_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Length + ie->len = liblte_bits_2_value(ptr, 3) + 1; + liblte_align_up(ptr, 8); + if(ie->len > 32) { + liblte_log_print("TAListforMDT unpack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_DECODE_FAIL; + } + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_unpack_tac(ptr, &ie->buffer[i]) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE TBCD_STRING STATIC OCTET STRING +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_tbcd_string( + LIBLTE_S1AP_TBCD_STRING_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Static octet string - TBCD-STRING + if(LIBLTE_S1AP_TBCD_STRING_OCTET_STRING_LEN > 2) { // X.691 Sec.16 + liblte_align_up_zero(ptr, 8); + } + // Octets + uint32_t i; + for(i=0;ibuffer[i], ptr, 8); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_tbcd_string( + uint8_t **ptr, + LIBLTE_S1AP_TBCD_STRING_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Static octet string - TBCD-STRING + if(LIBLTE_S1AP_TBCD_STRING_OCTET_STRING_LEN > 2) { // X.691 Sec.16 + liblte_align_up(ptr, 8); + } + // Octets + uint32_t i; + for(i=0;ibuffer[i] = liblte_bits_2_value(ptr, 8); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE Target_ToSource_TransparentContainer DYNAMIC OCTET STRING +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_target_tosource_transparentcontainer( + LIBLTE_S1AP_TARGET_TOSOURCE_TRANSPARENTCONTAINER_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Dynamic octet string - Target-ToSource-TransparentContainer + // Length + if(ie->n_octets < 128) { + liblte_value_2_bits(0, ptr, 1); + liblte_value_2_bits(ie->n_octets, ptr, 7); + } else if(ie->n_octets < 16383) { + liblte_value_2_bits(1, ptr, 1); + liblte_value_2_bits(0, ptr, 1); + liblte_value_2_bits(ie->n_octets, ptr, 14); + } else { + // FIXME: Unlikely to have more than 16K of octets + } + + // Octets + uint32_t i; + for(i=0;in_octets;i++) { + liblte_value_2_bits(ie->buffer[i], ptr, 8); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_target_tosource_transparentcontainer( + uint8_t **ptr, + LIBLTE_S1AP_TARGET_TOSOURCE_TRANSPARENTCONTAINER_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Dynamic octet string - Target-ToSource-TransparentContainer + // Length + if(0 == liblte_bits_2_value(ptr, 1)) { + ie->n_octets = liblte_bits_2_value(ptr, 7); + } else { + if(0 == liblte_bits_2_value(ptr, 1)) { + ie->n_octets = liblte_bits_2_value(ptr, 14); + } else { + // FIXME: Unlikely to have more than 16K of octets + } + } + + // Octets + uint32_t i; + for(i=0;in_octets;i++) { + ie->buffer[i] = liblte_bits_2_value(ptr, 8); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE Threshold_RSRP INTEGER +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_threshold_rsrp( + LIBLTE_S1AP_THRESHOLD_RSRP_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Integer - ie->Threshold_RSRP + // lb:0, ub:97 + liblte_value_2_bits(ie->Threshold_RSRP, ptr, 7); + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_threshold_rsrp( + uint8_t **ptr, + LIBLTE_S1AP_THRESHOLD_RSRP_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Integer - ie->Threshold_RSRP + // lb:0, ub:97 + ie->Threshold_RSRP = (uint8_t)liblte_bits_2_value(ptr, 7); + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE Time_UE_StayedInCell_EnhancedGranularity INTEGER +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_time_ue_stayedincell_enhancedgranularity( + LIBLTE_S1AP_TIME_UE_STAYEDINCELL_ENHANCEDGRANULARITY_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Integer - ie->Time_UE_StayedInCell_EnhancedGranularity + // lb:0, ub:40950 + liblte_align_up_zero(ptr, 8); + liblte_value_2_bits(0, ptr, (2*8)-16); + liblte_value_2_bits(ie->Time_UE_StayedInCell_EnhancedGranularity, ptr, 16); + liblte_align_up_zero(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_time_ue_stayedincell_enhancedgranularity( + uint8_t **ptr, + LIBLTE_S1AP_TIME_UE_STAYEDINCELL_ENHANCEDGRANULARITY_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Integer - ie->Time_UE_StayedInCell_EnhancedGranularity + // lb:0, ub:40950 + liblte_align_up(ptr, 8); + ie->Time_UE_StayedInCell_EnhancedGranularity = (uint16_t)liblte_bits_2_value(ptr, 2.0*8); + liblte_align_up(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE E_UTRAN_Trace_ID STATIC OCTET STRING +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_utran_trace_id( + LIBLTE_S1AP_E_UTRAN_TRACE_ID_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Static octet string - E-UTRAN-Trace-ID + if(LIBLTE_S1AP_E_UTRAN_TRACE_ID_OCTET_STRING_LEN > 2) { // X.691 Sec.16 + liblte_align_up_zero(ptr, 8); + } + // Octets + uint32_t i; + for(i=0;ibuffer[i], ptr, 8); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_utran_trace_id( + uint8_t **ptr, + LIBLTE_S1AP_E_UTRAN_TRACE_ID_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Static octet string - E-UTRAN-Trace-ID + if(LIBLTE_S1AP_E_UTRAN_TRACE_ID_OCTET_STRING_LEN > 2) { // X.691 Sec.16 + liblte_align_up(ptr, 8); + } + // Octets + uint32_t i; + for(i=0;ibuffer[i] = liblte_bits_2_value(ptr, 8); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE TypeOfError ENUMERATED +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_typeoferror( + LIBLTE_S1AP_TYPEOFERROR_ENUM_EXT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("TypeOfError error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // Enum + liblte_value_2_bits(ie->e, ptr, 1); + liblte_align_up_zero(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_typeoferror( + uint8_t **ptr, + LIBLTE_S1AP_TYPEOFERROR_ENUM_EXT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("TypeOfError error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // Enum + ie->e = (LIBLTE_S1AP_TYPEOFERROR_ENUM)liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE UEAggregateMaximumBitrate SEQUENCE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_ueaggregatemaximumbitrate( + LIBLTE_S1AP_UEAGGREGATEMAXIMUMBITRATE_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("UEAggregateMaximumBitrate error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + liblte_value_2_bits(ie->iE_Extensions_present?1:0, ptr, 1); + + if(liblte_s1ap_pack_bitrate(&ie->uEaggregateMaximumBitRateDL, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(liblte_s1ap_pack_bitrate(&ie->uEaggregateMaximumBitRateUL, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_pack_protocolextensioncontainer(&ie->iE_Extensions, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_ueaggregatemaximumbitrate( + uint8_t **ptr, + LIBLTE_S1AP_UEAGGREGATEMAXIMUMBITRATE_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("UEAggregateMaximumBitrate error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + ie->iE_Extensions_present = liblte_bits_2_value(ptr, 1); + + if(liblte_s1ap_unpack_bitrate(ptr, &ie->uEaggregateMaximumBitRateDL) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(liblte_s1ap_unpack_bitrate(ptr, &ie->uEaggregateMaximumBitRateUL) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_unpack_protocolextensioncontainer(ptr, &ie->iE_Extensions) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE UE_S1AP_ID_pair SEQUENCE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_ue_s1ap_id_pair( + LIBLTE_S1AP_UE_S1AP_ID_PAIR_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("UE_S1AP_ID_pair error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + liblte_value_2_bits(ie->iE_Extensions_present?1:0, ptr, 1); + + if(liblte_s1ap_pack_mme_ue_s1ap_id(&ie->mME_UE_S1AP_ID, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(liblte_s1ap_pack_enb_ue_s1ap_id(&ie->eNB_UE_S1AP_ID, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_pack_protocolextensioncontainer(&ie->iE_Extensions, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_ue_s1ap_id_pair( + uint8_t **ptr, + LIBLTE_S1AP_UE_S1AP_ID_PAIR_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("UE_S1AP_ID_pair error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + ie->iE_Extensions_present = liblte_bits_2_value(ptr, 1); + + if(liblte_s1ap_unpack_mme_ue_s1ap_id(ptr, &ie->mME_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(liblte_s1ap_unpack_enb_ue_s1ap_id(ptr, &ie->eNB_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_unpack_protocolextensioncontainer(ptr, &ie->iE_Extensions) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE UEIdentityIndexValue STATIC BIT STRING +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_ueidentityindexvalue( + LIBLTE_S1AP_UEIDENTITYINDEXVALUE_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Static bit string - UEIdentityIndexValue + uint32_t i; + for(i=0;ibuffer[i], ptr, 1); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_ueidentityindexvalue( + uint8_t **ptr, + LIBLTE_S1AP_UEIDENTITYINDEXVALUE_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Static bit string - UEIdentityIndexValue + uint32_t i; + for(i=0;ibuffer[i] = liblte_bits_2_value(ptr, 1); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE UESecurityCapabilities SEQUENCE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_uesecuritycapabilities( + LIBLTE_S1AP_UESECURITYCAPABILITIES_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("UESecurityCapabilities error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + liblte_value_2_bits(ie->iE_Extensions_present?1:0, ptr, 1); + + if(liblte_s1ap_pack_encryptionalgorithms(&ie->encryptionAlgorithms, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(liblte_s1ap_pack_integrityprotectionalgorithms(&ie->integrityProtectionAlgorithms, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_pack_protocolextensioncontainer(&ie->iE_Extensions, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_uesecuritycapabilities( + uint8_t **ptr, + LIBLTE_S1AP_UESECURITYCAPABILITIES_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("UESecurityCapabilities error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + ie->iE_Extensions_present = liblte_bits_2_value(ptr, 1); + + if(liblte_s1ap_unpack_encryptionalgorithms(ptr, &ie->encryptionAlgorithms) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(liblte_s1ap_unpack_integrityprotectionalgorithms(ptr, &ie->integrityProtectionAlgorithms) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_unpack_protocolextensioncontainer(ptr, &ie->iE_Extensions) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE VoiceSupportMatchIndicator ENUMERATED +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_voicesupportmatchindicator( + LIBLTE_S1AP_VOICESUPPORTMATCHINDICATOR_ENUM_EXT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("VoiceSupportMatchIndicator error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // Enum + liblte_value_2_bits(ie->e, ptr, 1); + liblte_align_up_zero(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_voicesupportmatchindicator( + uint8_t **ptr, + LIBLTE_S1AP_VOICESUPPORTMATCHINDICATOR_ENUM_EXT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("VoiceSupportMatchIndicator error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // Enum + ie->e = (LIBLTE_S1AP_VOICESUPPORTMATCHINDICATOR_ENUM)liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE WarningSecurityInfo STATIC OCTET STRING +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_warningsecurityinfo( + LIBLTE_S1AP_WARNINGSECURITYINFO_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Static octet string - WarningSecurityInfo + if(LIBLTE_S1AP_WARNINGSECURITYINFO_OCTET_STRING_LEN > 2) { // X.691 Sec.16 + liblte_align_up_zero(ptr, 8); + } + // Octets + uint32_t i; + for(i=0;ibuffer[i], ptr, 8); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_warningsecurityinfo( + uint8_t **ptr, + LIBLTE_S1AP_WARNINGSECURITYINFO_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Static octet string - WarningSecurityInfo + if(LIBLTE_S1AP_WARNINGSECURITYINFO_OCTET_STRING_LEN > 2) { // X.691 Sec.16 + liblte_align_up(ptr, 8); + } + // Octets + uint32_t i; + for(i=0;ibuffer[i] = liblte_bits_2_value(ptr, 8); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE ENBX2GTPTLAs DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:16 +LIBLTE_ERROR_ENUM liblte_s1ap_pack_enbx2gtptlas( + LIBLTE_S1AP_ENBX2GTPTLAS_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + if(ie->len > 32) { + liblte_log_print("ENBX2GTPTLAs pack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_ENCODE_FAIL; + } + // Length + liblte_value_2_bits(ie->len-1, ptr, 4); + liblte_align_up_zero(ptr, 8); + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_pack_transportlayeraddress(&ie->buffer[i], ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_enbx2gtptlas( + uint8_t **ptr, + LIBLTE_S1AP_ENBX2GTPTLAS_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Length + ie->len = liblte_bits_2_value(ptr, 4) + 1; + liblte_align_up(ptr, 8); + if(ie->len > 32) { + liblte_log_print("ENBX2GTPTLAs unpack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_DECODE_FAIL; + } + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_unpack_transportlayeraddress(ptr, &ie->buffer[i]) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE CauseTransport ENUMERATED +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_causetransport( + LIBLTE_S1AP_CAUSETRANSPORT_ENUM_EXT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("CauseTransport error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // Enum + liblte_value_2_bits(ie->e, ptr, 1); + liblte_align_up_zero(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_causetransport( + uint8_t **ptr, + LIBLTE_S1AP_CAUSETRANSPORT_ENUM_EXT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("CauseTransport error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // Enum + ie->e = (LIBLTE_S1AP_CAUSETRANSPORT_ENUM)liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE Cdma2000HOStatus ENUMERATED +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_cdma2000hostatus( + LIBLTE_S1AP_CDMA2000HOSTATUS_ENUM_EXT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("Cdma2000HOStatus error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // Enum + liblte_value_2_bits(ie->e, ptr, 1); + liblte_align_up_zero(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_cdma2000hostatus( + uint8_t **ptr, + LIBLTE_S1AP_CDMA2000HOSTATUS_ENUM_EXT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("Cdma2000HOStatus error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // Enum + ie->e = (LIBLTE_S1AP_CDMA2000HOSTATUS_ENUM)liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE Cdma2000OneXPilot DYNAMIC OCTET STRING +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_cdma2000onexpilot( + LIBLTE_S1AP_CDMA2000ONEXPILOT_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Dynamic octet string - Cdma2000OneXPilot + // Length + if(ie->n_octets < 128) { + liblte_value_2_bits(0, ptr, 1); + liblte_value_2_bits(ie->n_octets, ptr, 7); + } else if(ie->n_octets < 16383) { + liblte_value_2_bits(1, ptr, 1); + liblte_value_2_bits(0, ptr, 1); + liblte_value_2_bits(ie->n_octets, ptr, 14); + } else { + // FIXME: Unlikely to have more than 16K of octets + } + + // Octets + uint32_t i; + for(i=0;in_octets;i++) { + liblte_value_2_bits(ie->buffer[i], ptr, 8); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_cdma2000onexpilot( + uint8_t **ptr, + LIBLTE_S1AP_CDMA2000ONEXPILOT_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Dynamic octet string - Cdma2000OneXPilot + // Length + if(0 == liblte_bits_2_value(ptr, 1)) { + ie->n_octets = liblte_bits_2_value(ptr, 7); + } else { + if(0 == liblte_bits_2_value(ptr, 1)) { + ie->n_octets = liblte_bits_2_value(ptr, 14); + } else { + // FIXME: Unlikely to have more than 16K of octets + } + } + + // Octets + uint32_t i; + for(i=0;in_octets;i++) { + ie->buffer[i] = liblte_bits_2_value(ptr, 8); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE ConcurrentWarningMessageIndicator ENUMERATED +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_concurrentwarningmessageindicator( + LIBLTE_S1AP_CONCURRENTWARNINGMESSAGEINDICATOR_ENUM *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Enum - *ie + liblte_value_2_bits(*ie, ptr, 0); + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_concurrentwarningmessageindicator( + uint8_t **ptr, + LIBLTE_S1AP_CONCURRENTWARNINGMESSAGEINDICATOR_ENUM *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Enum - *ie + *ie = (LIBLTE_S1AP_CONCURRENTWARNINGMESSAGEINDICATOR_ENUM)liblte_bits_2_value(ptr, 0); + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE COUNTvalue SEQUENCE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_countvalue( + LIBLTE_S1AP_COUNTVALUE_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("COUNTvalue error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + liblte_value_2_bits(ie->iE_Extensions_present?1:0, ptr, 1); + + if(liblte_s1ap_pack_pdcp_sn(&ie->pDCP_SN, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(liblte_s1ap_pack_hfn(&ie->hFN, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_pack_protocolextensioncontainer(&ie->iE_Extensions, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_countvalue( + uint8_t **ptr, + LIBLTE_S1AP_COUNTVALUE_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("COUNTvalue error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + ie->iE_Extensions_present = liblte_bits_2_value(ptr, 1); + + if(liblte_s1ap_unpack_pdcp_sn(ptr, &ie->pDCP_SN) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(liblte_s1ap_unpack_hfn(ptr, &ie->hFN) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_unpack_protocolextensioncontainer(ptr, &ie->iE_Extensions) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE CriticalityDiagnostics_IE_Item SEQUENCE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_criticalitydiagnostics_ie_item( + LIBLTE_S1AP_CRITICALITYDIAGNOSTICS_IE_ITEM_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("CriticalityDiagnostics_IE_Item error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + liblte_value_2_bits(ie->iE_Extensions_present?1:0, ptr, 1); + + // Enum - ie->iECriticality + liblte_value_2_bits(ie->iECriticality, ptr, 2); + + if(liblte_s1ap_pack_protocolie_id(&ie->iE_ID, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(liblte_s1ap_pack_typeoferror(&ie->typeOfError, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_pack_protocolextensioncontainer(&ie->iE_Extensions, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_criticalitydiagnostics_ie_item( + uint8_t **ptr, + LIBLTE_S1AP_CRITICALITYDIAGNOSTICS_IE_ITEM_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("CriticalityDiagnostics_IE_Item error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + ie->iE_Extensions_present = liblte_bits_2_value(ptr, 1); + + // Enum - ie->iECriticality + ie->iECriticality = (LIBLTE_S1AP_CRITICALITY_ENUM)liblte_bits_2_value(ptr, 2); + + if(liblte_s1ap_unpack_protocolie_id(ptr, &ie->iE_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(liblte_s1ap_unpack_typeoferror(ptr, &ie->typeOfError) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_unpack_protocolextensioncontainer(ptr, &ie->iE_Extensions) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE ENBX2TLAs DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:2 +LIBLTE_ERROR_ENUM liblte_s1ap_pack_enbx2tlas( + LIBLTE_S1AP_ENBX2TLAS_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + if(ie->len > 32) { + liblte_log_print("ENBX2TLAs pack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_ENCODE_FAIL; + } + // Length + liblte_value_2_bits(ie->len-1, ptr, 0); + liblte_align_up_zero(ptr, 8); + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_pack_transportlayeraddress(&ie->buffer[i], ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_enbx2tlas( + uint8_t **ptr, + LIBLTE_S1AP_ENBX2TLAS_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Length + ie->len = liblte_bits_2_value(ptr, 0) + 1; + liblte_align_up(ptr, 8); + if(ie->len > 32) { + liblte_log_print("ENBX2TLAs unpack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_DECODE_FAIL; + } + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_unpack_transportlayeraddress(ptr, &ie->buffer[i]) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE ExtendedRepetitionPeriod INTEGER +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_extendedrepetitionperiod( + LIBLTE_S1AP_EXTENDEDREPETITIONPERIOD_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Integer - ie->ExtendedRepetitionPeriod + // lb:4096, ub:131071 + // Range > 65536 - encoded based on value + { + uint32_t n_bits = floor(log2(ie->ExtendedRepetitionPeriod-4096)+1); + uint32_t n_octets = (n_bits+7)/8; + liblte_value_2_bits(n_octets-1, ptr, 2); + liblte_align_up_zero(ptr, 8); + liblte_value_2_bits(0, ptr, (n_octets*8)-n_bits); + liblte_value_2_bits(ie->ExtendedRepetitionPeriod-4096, ptr, n_bits); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_extendedrepetitionperiod( + uint8_t **ptr, + LIBLTE_S1AP_EXTENDEDREPETITIONPERIOD_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Integer - ie->ExtendedRepetitionPeriod + // lb:4096, ub:131071 + // Range > 65536 - encoded based on value + { + uint32_t n_octets = liblte_bits_2_value(ptr, 2) + 1; + liblte_align_up(ptr, 8); + ie->ExtendedRepetitionPeriod = liblte_bits_2_value(ptr, n_octets*8) + 4096; + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE ForbiddenTACs DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:4096 +LIBLTE_ERROR_ENUM liblte_s1ap_pack_forbiddentacs( + LIBLTE_S1AP_FORBIDDENTACS_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + if(ie->len > 32) { + liblte_log_print("ForbiddenTACs pack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_ENCODE_FAIL; + } + // Length + liblte_value_2_bits(ie->len-1, ptr, 12); + liblte_align_up_zero(ptr, 8); + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_pack_tac(&ie->buffer[i], ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_forbiddentacs( + uint8_t **ptr, + LIBLTE_S1AP_FORBIDDENTACS_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Length + ie->len = liblte_bits_2_value(ptr, 12) + 1; + liblte_align_up(ptr, 8); + if(ie->len > 32) { + liblte_log_print("ForbiddenTACs unpack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_DECODE_FAIL; + } + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_unpack_tac(ptr, &ie->buffer[i]) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE GBR_QosInformation SEQUENCE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_gbr_qosinformation( + LIBLTE_S1AP_GBR_QOSINFORMATION_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("GBR_QosInformation error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + liblte_value_2_bits(ie->iE_Extensions_present?1:0, ptr, 1); + + if(liblte_s1ap_pack_bitrate(&ie->e_RAB_MaximumBitrateDL, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(liblte_s1ap_pack_bitrate(&ie->e_RAB_MaximumBitrateUL, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(liblte_s1ap_pack_bitrate(&ie->e_RAB_GuaranteedBitrateDL, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(liblte_s1ap_pack_bitrate(&ie->e_RAB_GuaranteedBitrateUL, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_pack_protocolextensioncontainer(&ie->iE_Extensions, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_gbr_qosinformation( + uint8_t **ptr, + LIBLTE_S1AP_GBR_QOSINFORMATION_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("GBR_QosInformation error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + ie->iE_Extensions_present = liblte_bits_2_value(ptr, 1); + + if(liblte_s1ap_unpack_bitrate(ptr, &ie->e_RAB_MaximumBitrateDL) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(liblte_s1ap_unpack_bitrate(ptr, &ie->e_RAB_MaximumBitrateUL) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(liblte_s1ap_unpack_bitrate(ptr, &ie->e_RAB_GuaranteedBitrateDL) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(liblte_s1ap_unpack_bitrate(ptr, &ie->e_RAB_GuaranteedBitrateUL) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_unpack_protocolextensioncontainer(ptr, &ie->iE_Extensions) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE HFNModified INTEGER +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_hfnmodified( + LIBLTE_S1AP_HFNMODIFIED_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Integer - ie->HFNModified + // lb:0, ub:131071 + // Range > 65536 - encoded based on value + { + uint32_t n_bits = floor(log2(ie->HFNModified-0)+1); + uint32_t n_octets = (n_bits+7)/8; + liblte_value_2_bits(n_octets-1, ptr, 2); + liblte_align_up_zero(ptr, 8); + liblte_value_2_bits(0, ptr, (n_octets*8)-n_bits); + liblte_value_2_bits(ie->HFNModified-0, ptr, n_bits); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_hfnmodified( + uint8_t **ptr, + LIBLTE_S1AP_HFNMODIFIED_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Integer - ie->HFNModified + // lb:0, ub:131071 + // Range > 65536 - encoded based on value + { + uint32_t n_octets = liblte_bits_2_value(ptr, 2) + 1; + liblte_align_up(ptr, 8); + ie->HFNModified = liblte_bits_2_value(ptr, n_octets*8) + 0; + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE KillAllWarningMessages ENUMERATED +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_killallwarningmessages( + LIBLTE_S1AP_KILLALLWARNINGMESSAGES_ENUM *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Enum - *ie + liblte_value_2_bits(*ie, ptr, 0); + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_killallwarningmessages( + uint8_t **ptr, + LIBLTE_S1AP_KILLALLWARNINGMESSAGES_ENUM *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Enum - *ie + *ie = (LIBLTE_S1AP_KILLALLWARNINGMESSAGES_ENUM)liblte_bits_2_value(ptr, 0); + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE LPPa_PDU DYNAMIC OCTET STRING +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_lppa_pdu( + LIBLTE_S1AP_LPPA_PDU_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Dynamic octet string - LPPa-PDU + // Length + if(ie->n_octets < 128) { + liblte_value_2_bits(0, ptr, 1); + liblte_value_2_bits(ie->n_octets, ptr, 7); + } else if(ie->n_octets < 16383) { + liblte_value_2_bits(1, ptr, 1); + liblte_value_2_bits(0, ptr, 1); + liblte_value_2_bits(ie->n_octets, ptr, 14); + } else { + // FIXME: Unlikely to have more than 16K of octets + } + + // Octets + uint32_t i; + for(i=0;in_octets;i++) { + liblte_value_2_bits(ie->buffer[i], ptr, 8); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_lppa_pdu( + uint8_t **ptr, + LIBLTE_S1AP_LPPA_PDU_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Dynamic octet string - LPPa-PDU + // Length + if(0 == liblte_bits_2_value(ptr, 1)) { + ie->n_octets = liblte_bits_2_value(ptr, 7); + } else { + if(0 == liblte_bits_2_value(ptr, 1)) { + ie->n_octets = liblte_bits_2_value(ptr, 14); + } else { + // FIXME: Unlikely to have more than 16K of octets + } + } + + // Octets + uint32_t i; + for(i=0;in_octets;i++) { + ie->buffer[i] = liblte_bits_2_value(ptr, 8); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE M3Configuration SEQUENCE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_m3configuration( + LIBLTE_S1AP_M3CONFIGURATION_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("M3Configuration error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + liblte_value_2_bits(ie->iE_Extensions_present?1:0, ptr, 1); + + if(liblte_s1ap_pack_m3period(&ie->m3period, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_pack_protocolextensioncontainer(&ie->iE_Extensions, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_m3configuration( + uint8_t **ptr, + LIBLTE_S1AP_M3CONFIGURATION_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("M3Configuration error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + ie->iE_Extensions_present = liblte_bits_2_value(ptr, 1); + + if(liblte_s1ap_unpack_m3period(ptr, &ie->m3period) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_unpack_protocolextensioncontainer(ptr, &ie->iE_Extensions) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE M5Configuration SEQUENCE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_m5configuration( + LIBLTE_S1AP_M5CONFIGURATION_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("M5Configuration error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + liblte_value_2_bits(ie->iE_Extensions_present?1:0, ptr, 1); + + if(liblte_s1ap_pack_m5period(&ie->m5period, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(liblte_s1ap_pack_links_to_log(&ie->m5_links_to_log, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_pack_protocolextensioncontainer(&ie->iE_Extensions, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_m5configuration( + uint8_t **ptr, + LIBLTE_S1AP_M5CONFIGURATION_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("M5Configuration error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + ie->iE_Extensions_present = liblte_bits_2_value(ptr, 1); + + if(liblte_s1ap_unpack_m5period(ptr, &ie->m5period) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(liblte_s1ap_unpack_links_to_log(ptr, &ie->m5_links_to_log) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_unpack_protocolextensioncontainer(ptr, &ie->iE_Extensions) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE MeasurementThresholdA2 CHOICE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_measurementthresholda2( + LIBLTE_S1AP_MEASUREMENTTHRESHOLDA2_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("MeasurementThresholdA2 error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // Choice type + liblte_value_2_bits(ie->choice_type, ptr, 1); + + // Choice + if(ie->choice_type == LIBLTE_S1AP_MEASUREMENTTHRESHOLDA2_CHOICE_THRESHOLD_RSRP) { + if(liblte_s1ap_pack_threshold_rsrp(&ie->choice.threshold_RSRP, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(ie->choice_type == LIBLTE_S1AP_MEASUREMENTTHRESHOLDA2_CHOICE_THRESHOLD_RSRQ) { + if(liblte_s1ap_pack_threshold_rsrq(&ie->choice.threshold_RSRQ, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_measurementthresholda2( + uint8_t **ptr, + LIBLTE_S1AP_MEASUREMENTTHRESHOLDA2_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("MeasurementThresholdA2 error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // Choice type + ie->choice_type = (LIBLTE_S1AP_MEASUREMENTTHRESHOLDA2_CHOICE_ENUM)liblte_bits_2_value(ptr, 1); + + // Choice + if(ie->choice_type == LIBLTE_S1AP_MEASUREMENTTHRESHOLDA2_CHOICE_THRESHOLD_RSRP) { + if(liblte_s1ap_unpack_threshold_rsrp(ptr, &ie->choice.threshold_RSRP) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(ie->choice_type == LIBLTE_S1AP_MEASUREMENTTHRESHOLDA2_CHOICE_THRESHOLD_RSRQ) { + if(liblte_s1ap_unpack_threshold_rsrq(ptr, &ie->choice.threshold_RSRQ) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE M_TMSI STATIC OCTET STRING +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_m_tmsi( + LIBLTE_S1AP_M_TMSI_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Static octet string - M-TMSI + if(LIBLTE_S1AP_M_TMSI_OCTET_STRING_LEN > 2) { // X.691 Sec.16 + liblte_align_up_zero(ptr, 8); + } + // Octets + uint32_t i; + for(i=0;ibuffer[i], ptr, 8); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_m_tmsi( + uint8_t **ptr, + LIBLTE_S1AP_M_TMSI_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Static octet string - M-TMSI + if(LIBLTE_S1AP_M_TMSI_OCTET_STRING_LEN > 2) { // X.691 Sec.16 + liblte_align_up(ptr, 8); + } + // Octets + uint32_t i; + for(i=0;ibuffer[i] = liblte_bits_2_value(ptr, 8); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE OldBSS_ToNewBSS_Information DYNAMIC OCTET STRING +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_oldbss_tonewbss_information( + LIBLTE_S1AP_OLDBSS_TONEWBSS_INFORMATION_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Dynamic octet string - OldBSS-ToNewBSS-Information + // Length + if(ie->n_octets < 128) { + liblte_value_2_bits(0, ptr, 1); + liblte_value_2_bits(ie->n_octets, ptr, 7); + } else if(ie->n_octets < 16383) { + liblte_value_2_bits(1, ptr, 1); + liblte_value_2_bits(0, ptr, 1); + liblte_value_2_bits(ie->n_octets, ptr, 14); + } else { + // FIXME: Unlikely to have more than 16K of octets + } + + // Octets + uint32_t i; + for(i=0;in_octets;i++) { + liblte_value_2_bits(ie->buffer[i], ptr, 8); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_oldbss_tonewbss_information( + uint8_t **ptr, + LIBLTE_S1AP_OLDBSS_TONEWBSS_INFORMATION_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Dynamic octet string - OldBSS-ToNewBSS-Information + // Length + if(0 == liblte_bits_2_value(ptr, 1)) { + ie->n_octets = liblte_bits_2_value(ptr, 7); + } else { + if(0 == liblte_bits_2_value(ptr, 1)) { + ie->n_octets = liblte_bits_2_value(ptr, 14); + } else { + // FIXME: Unlikely to have more than 16K of octets + } + } + + // Octets + uint32_t i; + for(i=0;in_octets;i++) { + ie->buffer[i] = liblte_bits_2_value(ptr, 8); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE PLMNidentity STATIC OCTET STRING +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_plmnidentity( + LIBLTE_S1AP_PLMNIDENTITY_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Static octet string - PLMNidentity + if(LIBLTE_S1AP_PLMNIDENTITY_OCTET_STRING_LEN > 2) { // X.691 Sec.16 + liblte_align_up_zero(ptr, 8); + } + // Octets + uint32_t i; + for(i=0;ibuffer[i], ptr, 8); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_plmnidentity( + uint8_t **ptr, + LIBLTE_S1AP_PLMNIDENTITY_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Static octet string - PLMNidentity + if(LIBLTE_S1AP_PLMNIDENTITY_OCTET_STRING_LEN > 2) { // X.691 Sec.16 + liblte_align_up(ptr, 8); + } + // Octets + uint32_t i; + for(i=0;ibuffer[i] = liblte_bits_2_value(ptr, 8); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE ReceiveStatusOfULPDCPSDUsExtended DYNAMIC BIT STRING +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_receivestatusofulpdcpsdusextended( + LIBLTE_S1AP_RECEIVESTATUSOFULPDCPSDUSEXTENDED_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Dynamic bit string - ReceiveStatusOfULPDCPSDUsExtended + // lb:1, ub:16384 + // Length + liblte_value_2_bits(ie->n_bits-1, ptr, 14); + liblte_align_up_zero(ptr, 8); + + // Bits + uint32_t i; + for(i=0;in_bits;i++) { + liblte_value_2_bits(ie->buffer[i], ptr, 1); + } + liblte_align_up_zero(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_receivestatusofulpdcpsdusextended( + uint8_t **ptr, + LIBLTE_S1AP_RECEIVESTATUSOFULPDCPSDUSEXTENDED_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Dynamic bit string - ReceiveStatusOfULPDCPSDUsExtended + // lb:1, ub:16384 + // Length + ie->n_bits = liblte_bits_2_value(ptr, 14) + 1; + liblte_align_up(ptr, 8); + + // Bits + uint32_t i; + for(i=0;in_bits;i++) { + ie->buffer[i] = liblte_bits_2_value(ptr, 1); + } + liblte_align_up(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE RequestType SEQUENCE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_requesttype( + LIBLTE_S1AP_REQUESTTYPE_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("RequestType error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + liblte_value_2_bits(ie->iE_Extensions_present?1:0, ptr, 1); + + if(liblte_s1ap_pack_eventtype(&ie->eventType, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(liblte_s1ap_pack_reportarea(&ie->reportArea, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_pack_protocolextensioncontainer(&ie->iE_Extensions, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_requesttype( + uint8_t **ptr, + LIBLTE_S1AP_REQUESTTYPE_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("RequestType error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + ie->iE_Extensions_present = liblte_bits_2_value(ptr, 1); + + if(liblte_s1ap_unpack_eventtype(ptr, &ie->eventType) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(liblte_s1ap_unpack_reportarea(ptr, &ie->reportArea) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_unpack_protocolextensioncontainer(ptr, &ie->iE_Extensions) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE RRC_Container DYNAMIC OCTET STRING +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_rrc_container( + LIBLTE_S1AP_RRC_CONTAINER_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Dynamic octet string - RRC-Container + // Length + if(ie->n_octets < 128) { + liblte_value_2_bits(0, ptr, 1); + liblte_value_2_bits(ie->n_octets, ptr, 7); + } else if(ie->n_octets < 16383) { + liblte_value_2_bits(1, ptr, 1); + liblte_value_2_bits(0, ptr, 1); + liblte_value_2_bits(ie->n_octets, ptr, 14); + } else { + // FIXME: Unlikely to have more than 16K of octets + } + + // Octets + uint32_t i; + for(i=0;in_octets;i++) { + liblte_value_2_bits(ie->buffer[i], ptr, 8); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_rrc_container( + uint8_t **ptr, + LIBLTE_S1AP_RRC_CONTAINER_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Dynamic octet string - RRC-Container + // Length + if(0 == liblte_bits_2_value(ptr, 1)) { + ie->n_octets = liblte_bits_2_value(ptr, 7); + } else { + if(0 == liblte_bits_2_value(ptr, 1)) { + ie->n_octets = liblte_bits_2_value(ptr, 14); + } else { + // FIXME: Unlikely to have more than 16K of octets + } + } + + // Octets + uint32_t i; + for(i=0;in_octets;i++) { + ie->buffer[i] = liblte_bits_2_value(ptr, 8); + } + err = LIBLTE_SUCCESS; + } + return err; +} + + +/******************************************************************************* +/* ProtocolIE nextHopChainingCount INTEGER +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_nexthopchainingcount( + LIBLTE_S1AP_NEXTHOPCHAININGCOUNT_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Integer - ie->nextHopChainingCount + // lb:0, ub:7 + liblte_value_2_bits(ie->nextHopChainingCount, ptr, 3); + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_nexthopchainingcount( + uint8_t **ptr, + LIBLTE_S1AP_NEXTHOPCHAININGCOUNT_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Integer - ie->nextHopChainingCount + // lb:0, ub:7 + ie->nextHopChainingCount = (uint8_t)liblte_bits_2_value(ptr, 3); + err = LIBLTE_SUCCESS; + } + return err; +} + + +/******************************************************************************* +/* ProtocolIE SecurityContext SEQUENCE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_securitycontext( + LIBLTE_S1AP_SECURITYCONTEXT_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("SecurityContext error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + liblte_value_2_bits(ie->iE_Extensions_present?1:0, ptr, 1); + + if(liblte_s1ap_pack_nexthopchainingcount(&ie->nextHopChainingCount, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(liblte_s1ap_pack_securitykey(&ie->nextHopParameter, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_pack_protocolextensioncontainer(&ie->iE_Extensions, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_securitycontext( + uint8_t **ptr, + LIBLTE_S1AP_SECURITYCONTEXT_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("SecurityContext error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + ie->iE_Extensions_present = liblte_bits_2_value(ptr, 1); + + if(liblte_s1ap_unpack_nexthopchainingcount(ptr, &ie->nextHopChainingCount) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(liblte_s1ap_unpack_securitykey(ptr, &ie->nextHopParameter) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_unpack_protocolextensioncontainer(ptr, &ie->iE_Extensions) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE ServedMMECs DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:256 +LIBLTE_ERROR_ENUM liblte_s1ap_pack_servedmmecs( + LIBLTE_S1AP_SERVEDMMECS_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + if(ie->len > 32) { + liblte_log_print("ServedMMECs pack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_ENCODE_FAIL; + } + // Length + liblte_value_2_bits(ie->len-1, ptr, 8); + liblte_align_up_zero(ptr, 8); + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_pack_mme_code(&ie->buffer[i], ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_servedmmecs( + uint8_t **ptr, + LIBLTE_S1AP_SERVEDMMECS_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Length + ie->len = liblte_bits_2_value(ptr, 8) + 1; + liblte_align_up(ptr, 8); + if(ie->len > 32) { + liblte_log_print("ServedMMECs unpack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_DECODE_FAIL; + } + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_unpack_mme_code(ptr, &ie->buffer[i]) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE TimeSynchronizationInfo SEQUENCE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_timesynchronizationinfo( + LIBLTE_S1AP_TIMESYNCHRONIZATIONINFO_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("TimeSynchronizationInfo error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + liblte_value_2_bits(ie->iE_Extensions_present?1:0, ptr, 1); + + if(liblte_s1ap_pack_stratumlevel(&ie->stratumLevel, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(liblte_s1ap_pack_synchronizationstatus(&ie->synchronizationStatus, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_pack_protocolextensioncontainer(&ie->iE_Extensions, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_timesynchronizationinfo( + uint8_t **ptr, + LIBLTE_S1AP_TIMESYNCHRONIZATIONINFO_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("TimeSynchronizationInfo error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + ie->iE_Extensions_present = liblte_bits_2_value(ptr, 1); + + if(liblte_s1ap_unpack_stratumlevel(ptr, &ie->stratumLevel) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(liblte_s1ap_unpack_synchronizationstatus(ptr, &ie->synchronizationStatus) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_unpack_protocolextensioncontainer(ptr, &ie->iE_Extensions) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE TAI SEQUENCE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_tai( + LIBLTE_S1AP_TAI_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("TAI error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + liblte_value_2_bits(ie->iE_Extensions_present?1:0, ptr, 1); + + if(liblte_s1ap_pack_tbcd_string(&ie->pLMNidentity, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(liblte_s1ap_pack_tac(&ie->tAC, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_pack_protocolextensioncontainer(&ie->iE_Extensions, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_tai( + uint8_t **ptr, + LIBLTE_S1AP_TAI_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("TAI error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + ie->iE_Extensions_present = liblte_bits_2_value(ptr, 1); + + if(liblte_s1ap_unpack_tbcd_string(ptr, &ie->pLMNidentity) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(liblte_s1ap_unpack_tac(ptr, &ie->tAC) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_unpack_protocolextensioncontainer(ptr, &ie->iE_Extensions) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE TABasedMDT SEQUENCE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_tabasedmdt( + LIBLTE_S1AP_TABASEDMDT_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("TABasedMDT error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + liblte_value_2_bits(ie->iE_Extensions_present?1:0, ptr, 1); + + if(liblte_s1ap_pack_talistformdt(&ie->tAListforMDT, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_pack_protocolextensioncontainer(&ie->iE_Extensions, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_tabasedmdt( + uint8_t **ptr, + LIBLTE_S1AP_TABASEDMDT_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("TABasedMDT error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + ie->iE_Extensions_present = liblte_bits_2_value(ptr, 1); + + if(liblte_s1ap_unpack_talistformdt(ptr, &ie->tAListforMDT) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_unpack_protocolextensioncontainer(ptr, &ie->iE_Extensions) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE TargeteNB_ToSourceeNB_TransparentContainer SEQUENCE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_targetenb_tosourceenb_transparentcontainer( + LIBLTE_S1AP_TARGETENB_TOSOURCEENB_TRANSPARENTCONTAINER_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("TargeteNB_ToSourceeNB_TransparentContainer error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + liblte_value_2_bits(ie->iE_Extensions_present?1:0, ptr, 1); + + if(liblte_s1ap_pack_rrc_container(&ie->rRC_Container, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_pack_protocolextensioncontainer(&ie->iE_Extensions, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_targetenb_tosourceenb_transparentcontainer( + uint8_t **ptr, + LIBLTE_S1AP_TARGETENB_TOSOURCEENB_TRANSPARENTCONTAINER_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("TargeteNB_ToSourceeNB_TransparentContainer error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + ie->iE_Extensions_present = liblte_bits_2_value(ptr, 1); + + if(liblte_s1ap_unpack_rrc_container(ptr, &ie->rRC_Container) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_unpack_protocolextensioncontainer(ptr, &ie->iE_Extensions) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE M1ThresholdEventA2 SEQUENCE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_m1thresholdeventa2( + LIBLTE_S1AP_M1THRESHOLDEVENTA2_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("M1ThresholdEventA2 error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + liblte_value_2_bits(ie->iE_Extensions_present?1:0, ptr, 1); + + if(liblte_s1ap_pack_measurementthresholda2(&ie->measurementThreshold, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_pack_protocolextensioncontainer(&ie->iE_Extensions, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_m1thresholdeventa2( + uint8_t **ptr, + LIBLTE_S1AP_M1THRESHOLDEVENTA2_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("M1ThresholdEventA2 error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + ie->iE_Extensions_present = liblte_bits_2_value(ptr, 1); + + if(liblte_s1ap_unpack_measurementthresholda2(ptr, &ie->measurementThreshold) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_unpack_protocolextensioncontainer(ptr, &ie->iE_Extensions) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE TransportInformation SEQUENCE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_transportinformation( + LIBLTE_S1AP_TRANSPORTINFORMATION_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("TransportInformation error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + + if(liblte_s1ap_pack_transportlayeraddress(&ie->transportLayerAddress, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(liblte_s1ap_pack_gtp_teid(&ie->uL_GTP_TEID, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_transportinformation( + uint8_t **ptr, + LIBLTE_S1AP_TRANSPORTINFORMATION_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("TransportInformation error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + + if(liblte_s1ap_unpack_transportlayeraddress(ptr, &ie->transportLayerAddress) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(liblte_s1ap_unpack_gtp_teid(ptr, &ie->uL_GTP_TEID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE TunnelInformation SEQUENCE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_tunnelinformation( + LIBLTE_S1AP_TUNNELINFORMATION_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("TunnelInformation error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + liblte_value_2_bits(ie->uDP_Port_Number_present?1:0, ptr, 1); + liblte_value_2_bits(ie->iE_Extensions_present?1:0, ptr, 1); + + if(liblte_s1ap_pack_transportlayeraddress(&ie->transportLayerAddress, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(ie->uDP_Port_Number_present) { + if(liblte_s1ap_pack_port_number(&ie->uDP_Port_Number, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_pack_protocolextensioncontainer(&ie->iE_Extensions, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_tunnelinformation( + uint8_t **ptr, + LIBLTE_S1AP_TUNNELINFORMATION_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("TunnelInformation error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + ie->uDP_Port_Number_present = liblte_bits_2_value(ptr, 1); + ie->iE_Extensions_present = liblte_bits_2_value(ptr, 1); + + if(liblte_s1ap_unpack_transportlayeraddress(ptr, &ie->transportLayerAddress) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(ie->uDP_Port_Number_present) { + if(liblte_s1ap_unpack_port_number(ptr, &ie->uDP_Port_Number) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_unpack_protocolextensioncontainer(ptr, &ie->iE_Extensions) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE UE_S1AP_IDs CHOICE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_ue_s1ap_ids( + LIBLTE_S1AP_UE_S1AP_IDS_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("UE_S1AP_IDs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // Choice type + liblte_value_2_bits(ie->choice_type, ptr, 1); + + // Choice + if(ie->choice_type == LIBLTE_S1AP_UE_S1AP_IDS_CHOICE_UE_S1AP_ID_PAIR) { + if(liblte_s1ap_pack_ue_s1ap_id_pair(&ie->choice.uE_S1AP_ID_pair, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(ie->choice_type == LIBLTE_S1AP_UE_S1AP_IDS_CHOICE_MME_UE_S1AP_ID) { + if(liblte_s1ap_pack_mme_ue_s1ap_id(&ie->choice.mME_UE_S1AP_ID, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_ue_s1ap_ids( + uint8_t **ptr, + LIBLTE_S1AP_UE_S1AP_IDS_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("UE_S1AP_IDs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // Choice type + ie->choice_type = (LIBLTE_S1AP_UE_S1AP_IDS_CHOICE_ENUM)liblte_bits_2_value(ptr, 1); + + // Choice + if(ie->choice_type == LIBLTE_S1AP_UE_S1AP_IDS_CHOICE_UE_S1AP_ID_PAIR) { + if(liblte_s1ap_unpack_ue_s1ap_id_pair(ptr, &ie->choice.uE_S1AP_ID_pair) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(ie->choice_type == LIBLTE_S1AP_UE_S1AP_IDS_CHOICE_MME_UE_S1AP_ID) { + if(liblte_s1ap_unpack_mme_ue_s1ap_id(ptr, &ie->choice.mME_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE ENBX2ExtTLA SEQUENCE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_enbx2exttla( + LIBLTE_S1AP_ENBX2EXTTLA_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("ENBX2ExtTLA error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + liblte_value_2_bits(ie->iPsecTLA_present?1:0, ptr, 1); + liblte_value_2_bits(ie->gTPTLAa_present?1:0, ptr, 1); + liblte_value_2_bits(ie->iE_Extensions_present?1:0, ptr, 1); + + if(ie->iPsecTLA_present) { + if(liblte_s1ap_pack_transportlayeraddress(&ie->iPsecTLA, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + + if(ie->gTPTLAa_present) { + if(liblte_s1ap_pack_enbx2gtptlas(&ie->gTPTLAa, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_pack_protocolextensioncontainer(&ie->iE_Extensions, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_enbx2exttla( + uint8_t **ptr, + LIBLTE_S1AP_ENBX2EXTTLA_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("ENBX2ExtTLA error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + ie->iPsecTLA_present = liblte_bits_2_value(ptr, 1); + ie->gTPTLAa_present = liblte_bits_2_value(ptr, 1); + ie->iE_Extensions_present = liblte_bits_2_value(ptr, 1); + + if(ie->iPsecTLA_present) { + if(liblte_s1ap_unpack_transportlayeraddress(ptr, &ie->iPsecTLA) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + + if(ie->gTPTLAa_present) { + if(liblte_s1ap_unpack_enbx2gtptlas(ptr, &ie->gTPTLAa) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_unpack_protocolextensioncontainer(ptr, &ie->iE_Extensions) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE BPLMNs DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:6 +LIBLTE_ERROR_ENUM liblte_s1ap_pack_bplmns( + LIBLTE_S1AP_BPLMNS_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + if(ie->len > 32) { + liblte_log_print("BPLMNs pack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_ENCODE_FAIL; + } + // Length + liblte_value_2_bits(ie->len-1, ptr, 3); + liblte_align_up_zero(ptr, 8); + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_pack_tbcd_string(&ie->buffer[i], ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_bplmns( + uint8_t **ptr, + LIBLTE_S1AP_BPLMNS_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Length + ie->len = liblte_bits_2_value(ptr, 3) + 1; + liblte_align_up(ptr, 8); + if(ie->len > 32) { + liblte_log_print("BPLMNs unpack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_DECODE_FAIL; + } + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_unpack_tbcd_string(ptr, &ie->buffer[i]) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE Cause CHOICE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_cause( + LIBLTE_S1AP_CAUSE_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("Cause error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // Choice type + liblte_value_2_bits(ie->choice_type, ptr, 3); + + // Choice + if(ie->choice_type == LIBLTE_S1AP_CAUSE_CHOICE_RADIONETWORK) { + if(liblte_s1ap_pack_causeradionetwork(&ie->choice.radioNetwork, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(ie->choice_type == LIBLTE_S1AP_CAUSE_CHOICE_TRANSPORT) { + if(liblte_s1ap_pack_causetransport(&ie->choice.transport, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(ie->choice_type == LIBLTE_S1AP_CAUSE_CHOICE_NAS) { + if(liblte_s1ap_pack_causenas(&ie->choice.nas, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(ie->choice_type == LIBLTE_S1AP_CAUSE_CHOICE_PROTOCOL) { + if(liblte_s1ap_pack_causeprotocol(&ie->choice.protocol, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(ie->choice_type == LIBLTE_S1AP_CAUSE_CHOICE_MISC) { + if(liblte_s1ap_pack_causemisc(&ie->choice.misc, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_cause( + uint8_t **ptr, + LIBLTE_S1AP_CAUSE_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("Cause error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // Choice type + ie->choice_type = (LIBLTE_S1AP_CAUSE_CHOICE_ENUM)liblte_bits_2_value(ptr, 3); + + // Choice + if(ie->choice_type == LIBLTE_S1AP_CAUSE_CHOICE_RADIONETWORK) { + if(liblte_s1ap_unpack_causeradionetwork(ptr, &ie->choice.radioNetwork) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(ie->choice_type == LIBLTE_S1AP_CAUSE_CHOICE_TRANSPORT) { + if(liblte_s1ap_unpack_causetransport(ptr, &ie->choice.transport) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(ie->choice_type == LIBLTE_S1AP_CAUSE_CHOICE_NAS) { + if(liblte_s1ap_unpack_causenas(ptr, &ie->choice.nas) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(ie->choice_type == LIBLTE_S1AP_CAUSE_CHOICE_PROTOCOL) { + if(liblte_s1ap_unpack_causeprotocol(ptr, &ie->choice.protocol) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(ie->choice_type == LIBLTE_S1AP_CAUSE_CHOICE_MISC) { + if(liblte_s1ap_unpack_causemisc(ptr, &ie->choice.misc) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE Cdma2000OneXSRVCCInfo SEQUENCE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_cdma2000onexsrvccinfo( + LIBLTE_S1AP_CDMA2000ONEXSRVCCINFO_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("Cdma2000OneXSRVCCInfo error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + liblte_value_2_bits(ie->iE_Extensions_present?1:0, ptr, 1); + + if(liblte_s1ap_pack_cdma2000onexmeid(&ie->cdma2000OneXMEID, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(liblte_s1ap_pack_cdma2000onexmsi(&ie->cdma2000OneXMSI, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(liblte_s1ap_pack_cdma2000onexpilot(&ie->cdma2000OneXPilot, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_pack_protocolextensioncontainer(&ie->iE_Extensions, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_cdma2000onexsrvccinfo( + uint8_t **ptr, + LIBLTE_S1AP_CDMA2000ONEXSRVCCINFO_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("Cdma2000OneXSRVCCInfo error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + ie->iE_Extensions_present = liblte_bits_2_value(ptr, 1); + + if(liblte_s1ap_unpack_cdma2000onexmeid(ptr, &ie->cdma2000OneXMEID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(liblte_s1ap_unpack_cdma2000onexmsi(ptr, &ie->cdma2000OneXMSI) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(liblte_s1ap_unpack_cdma2000onexpilot(ptr, &ie->cdma2000OneXPilot) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_unpack_protocolextensioncontainer(ptr, &ie->iE_Extensions) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE CGI SEQUENCE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_cgi( + LIBLTE_S1AP_CGI_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("CGI error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + liblte_value_2_bits(ie->rAC_present?1:0, ptr, 1); + liblte_value_2_bits(ie->iE_Extensions_present?1:0, ptr, 1); + + if(liblte_s1ap_pack_tbcd_string(&ie->pLMNidentity, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(liblte_s1ap_pack_lac(&ie->lAC, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(liblte_s1ap_pack_ci(&ie->cI, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(ie->rAC_present) { + if(liblte_s1ap_pack_rac(&ie->rAC, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_pack_protocolextensioncontainer(&ie->iE_Extensions, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_cgi( + uint8_t **ptr, + LIBLTE_S1AP_CGI_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("CGI error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + ie->rAC_present = liblte_bits_2_value(ptr, 1); + ie->iE_Extensions_present = liblte_bits_2_value(ptr, 1); + + if(liblte_s1ap_unpack_tbcd_string(ptr, &ie->pLMNidentity) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(liblte_s1ap_unpack_lac(ptr, &ie->lAC) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(liblte_s1ap_unpack_ci(ptr, &ie->cI) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(ie->rAC_present) { + if(liblte_s1ap_unpack_rac(ptr, &ie->rAC) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_unpack_protocolextensioncontainer(ptr, &ie->iE_Extensions) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE COUNTValueExtended SEQUENCE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_countvalueextended( + LIBLTE_S1AP_COUNTVALUEEXTENDED_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("COUNTValueExtended error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + liblte_value_2_bits(ie->iE_Extensions_present?1:0, ptr, 1); + + if(liblte_s1ap_pack_pdcp_snextended(&ie->pDCP_SNExtended, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(liblte_s1ap_pack_hfnmodified(&ie->hFNModified, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_pack_protocolextensioncontainer(&ie->iE_Extensions, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_countvalueextended( + uint8_t **ptr, + LIBLTE_S1AP_COUNTVALUEEXTENDED_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("COUNTValueExtended error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + ie->iE_Extensions_present = liblte_bits_2_value(ptr, 1); + + if(liblte_s1ap_unpack_pdcp_snextended(ptr, &ie->pDCP_SNExtended) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(liblte_s1ap_unpack_hfnmodified(ptr, &ie->hFNModified) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_unpack_protocolextensioncontainer(ptr, &ie->iE_Extensions) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE CriticalityDiagnostics_IE_List DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:256 +LIBLTE_ERROR_ENUM liblte_s1ap_pack_criticalitydiagnostics_ie_list( + LIBLTE_S1AP_CRITICALITYDIAGNOSTICS_IE_LIST_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + if(ie->len > 32) { + liblte_log_print("CriticalityDiagnostics_IE_List pack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_ENCODE_FAIL; + } + // Length + liblte_value_2_bits(ie->len-1, ptr, 8); + liblte_align_up_zero(ptr, 8); + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_pack_criticalitydiagnostics_ie_item(&ie->buffer[i], ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_criticalitydiagnostics_ie_list( + uint8_t **ptr, + LIBLTE_S1AP_CRITICALITYDIAGNOSTICS_IE_LIST_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Length + ie->len = liblte_bits_2_value(ptr, 8) + 1; + liblte_align_up(ptr, 8); + if(ie->len > 32) { + liblte_log_print("CriticalityDiagnostics_IE_List unpack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_DECODE_FAIL; + } + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_unpack_criticalitydiagnostics_ie_item(ptr, &ie->buffer[i]) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE Global_ENB_ID SEQUENCE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_global_enb_id( + LIBLTE_S1AP_GLOBAL_ENB_ID_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("Global_ENB_ID error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + liblte_value_2_bits(ie->iE_Extensions_present?1:0, ptr, 1); + + if(liblte_s1ap_pack_tbcd_string(&ie->pLMNidentity, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(liblte_s1ap_pack_enb_id(&ie->eNB_ID, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_pack_protocolextensioncontainer(&ie->iE_Extensions, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_global_enb_id( + uint8_t **ptr, + LIBLTE_S1AP_GLOBAL_ENB_ID_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("Global_ENB_ID error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + ie->iE_Extensions_present = liblte_bits_2_value(ptr, 1); + + if(liblte_s1ap_unpack_tbcd_string(ptr, &ie->pLMNidentity) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(liblte_s1ap_unpack_enb_id(ptr, &ie->eNB_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_unpack_protocolextensioncontainer(ptr, &ie->iE_Extensions) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE EPLMNs DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:15 +LIBLTE_ERROR_ENUM liblte_s1ap_pack_eplmns( + LIBLTE_S1AP_EPLMNS_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + if(ie->len > 32) { + liblte_log_print("EPLMNs pack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_ENCODE_FAIL; + } + // Length + liblte_value_2_bits(ie->len-1, ptr, 4); + liblte_align_up_zero(ptr, 8); + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_pack_tbcd_string(&ie->buffer[i], ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_eplmns( + uint8_t **ptr, + LIBLTE_S1AP_EPLMNS_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Length + ie->len = liblte_bits_2_value(ptr, 4) + 1; + liblte_align_up(ptr, 8); + if(ie->len > 32) { + liblte_log_print("EPLMNs unpack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_DECODE_FAIL; + } + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_unpack_tbcd_string(ptr, &ie->buffer[i]) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE E_RABItem SEQUENCE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabitem( + LIBLTE_S1AP_E_RABITEM_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("E_RABItem error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + liblte_value_2_bits(ie->iE_Extensions_present?1:0, ptr, 1); + + if(liblte_s1ap_pack_e_rab_id(&ie->e_RAB_ID, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(liblte_s1ap_pack_cause(&ie->cause, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_pack_protocolextensioncontainer(&ie->iE_Extensions, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabitem( + uint8_t **ptr, + LIBLTE_S1AP_E_RABITEM_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("E_RABItem error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + ie->iE_Extensions_present = liblte_bits_2_value(ptr, 1); + + if(liblte_s1ap_unpack_e_rab_id(ptr, &ie->e_RAB_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(liblte_s1ap_unpack_cause(ptr, &ie->cause) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_unpack_protocolextensioncontainer(ptr, &ie->iE_Extensions) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE EUTRAN_CGI SEQUENCE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_eutran_cgi( + LIBLTE_S1AP_EUTRAN_CGI_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("EUTRAN_CGI error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + liblte_value_2_bits(ie->iE_Extensions_present?1:0, ptr, 1); + + if(liblte_s1ap_pack_tbcd_string(&ie->pLMNidentity, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(liblte_s1ap_pack_cellidentity(&ie->cell_ID, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_pack_protocolextensioncontainer(&ie->iE_Extensions, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_eutran_cgi( + uint8_t **ptr, + LIBLTE_S1AP_EUTRAN_CGI_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("EUTRAN_CGI error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + ie->iE_Extensions_present = liblte_bits_2_value(ptr, 1); + + if(liblte_s1ap_unpack_tbcd_string(ptr, &ie->pLMNidentity) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(liblte_s1ap_unpack_cellidentity(ptr, &ie->cell_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_unpack_protocolextensioncontainer(ptr, &ie->iE_Extensions) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE ForbiddenTAs_Item SEQUENCE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_forbiddentas_item( + LIBLTE_S1AP_FORBIDDENTAS_ITEM_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("ForbiddenTAs_Item error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + liblte_value_2_bits(ie->iE_Extensions_present?1:0, ptr, 1); + + if(liblte_s1ap_pack_tbcd_string(&ie->pLMN_Identity, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(liblte_s1ap_pack_forbiddentacs(&ie->forbiddenTACs, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_pack_protocolextensioncontainer(&ie->iE_Extensions, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_forbiddentas_item( + uint8_t **ptr, + LIBLTE_S1AP_FORBIDDENTAS_ITEM_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("ForbiddenTAs_Item error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + ie->iE_Extensions_present = liblte_bits_2_value(ptr, 1); + + if(liblte_s1ap_unpack_tbcd_string(ptr, &ie->pLMN_Identity) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(liblte_s1ap_unpack_forbiddentacs(ptr, &ie->forbiddenTACs) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_unpack_protocolextensioncontainer(ptr, &ie->iE_Extensions) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE ForbiddenLAs_Item SEQUENCE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_forbiddenlas_item( + LIBLTE_S1AP_FORBIDDENLAS_ITEM_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("ForbiddenLAs_Item error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + liblte_value_2_bits(ie->iE_Extensions_present?1:0, ptr, 1); + + if(liblte_s1ap_pack_tbcd_string(&ie->pLMN_Identity, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(liblte_s1ap_pack_forbiddenlacs(&ie->forbiddenLACs, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_pack_protocolextensioncontainer(&ie->iE_Extensions, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_forbiddenlas_item( + uint8_t **ptr, + LIBLTE_S1AP_FORBIDDENLAS_ITEM_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("ForbiddenLAs_Item error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + ie->iE_Extensions_present = liblte_bits_2_value(ptr, 1); + + if(liblte_s1ap_unpack_tbcd_string(ptr, &ie->pLMN_Identity) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(liblte_s1ap_unpack_forbiddenlacs(ptr, &ie->forbiddenLACs) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_unpack_protocolextensioncontainer(ptr, &ie->iE_Extensions) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE LAI SEQUENCE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_lai( + LIBLTE_S1AP_LAI_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("LAI error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + liblte_value_2_bits(ie->iE_Extensions_present?1:0, ptr, 1); + + if(liblte_s1ap_pack_tbcd_string(&ie->pLMNidentity, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(liblte_s1ap_pack_lac(&ie->lAC, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_pack_protocolextensioncontainer(&ie->iE_Extensions, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_lai( + uint8_t **ptr, + LIBLTE_S1AP_LAI_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("LAI error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + ie->iE_Extensions_present = liblte_bits_2_value(ptr, 1); + + if(liblte_s1ap_unpack_tbcd_string(ptr, &ie->pLMNidentity) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(liblte_s1ap_unpack_lac(ptr, &ie->lAC) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_unpack_protocolextensioncontainer(ptr, &ie->iE_Extensions) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE M4Configuration SEQUENCE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_m4configuration( + LIBLTE_S1AP_M4CONFIGURATION_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("M4Configuration error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + liblte_value_2_bits(ie->iE_Extensions_present?1:0, ptr, 1); + + if(liblte_s1ap_pack_m4period(&ie->m4period, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(liblte_s1ap_pack_links_to_log(&ie->m4_links_to_log, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_pack_protocolextensioncontainer(&ie->iE_Extensions, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_m4configuration( + uint8_t **ptr, + LIBLTE_S1AP_M4CONFIGURATION_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("M4Configuration error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + ie->iE_Extensions_present = liblte_bits_2_value(ptr, 1); + + if(liblte_s1ap_unpack_m4period(ptr, &ie->m4period) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(liblte_s1ap_unpack_links_to_log(ptr, &ie->m4_links_to_log) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_unpack_protocolextensioncontainer(ptr, &ie->iE_Extensions) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE MDTPLMNList DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:16 +LIBLTE_ERROR_ENUM liblte_s1ap_pack_mdtplmnlist( + LIBLTE_S1AP_MDTPLMNLIST_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + if(ie->len > 32) { + liblte_log_print("MDTPLMNList pack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_ENCODE_FAIL; + } + // Length + liblte_value_2_bits(ie->len-1, ptr, 4); + liblte_align_up_zero(ptr, 8); + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_pack_tbcd_string(&ie->buffer[i], ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_mdtplmnlist( + uint8_t **ptr, + LIBLTE_S1AP_MDTPLMNLIST_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Length + ie->len = liblte_bits_2_value(ptr, 4) + 1; + liblte_align_up(ptr, 8); + if(ie->len > 32) { + liblte_log_print("MDTPLMNList unpack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_DECODE_FAIL; + } + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_unpack_tbcd_string(ptr, &ie->buffer[i]) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE MMERelaySupportIndicator ENUMERATED +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_mmerelaysupportindicator( + LIBLTE_S1AP_MMERELAYSUPPORTINDICATOR_ENUM_EXT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("MMERelaySupportIndicator error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // Enum + liblte_value_2_bits(ie->e, ptr, 0); + liblte_align_up_zero(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_mmerelaysupportindicator( + uint8_t **ptr, + LIBLTE_S1AP_MMERELAYSUPPORTINDICATOR_ENUM_EXT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("MMERelaySupportIndicator error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // Enum + ie->e = (LIBLTE_S1AP_MMERELAYSUPPORTINDICATOR_ENUM)liblte_bits_2_value(ptr, 0); + liblte_align_up(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE PagingPriority ENUMERATED +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_pagingpriority( + LIBLTE_S1AP_PAGINGPRIORITY_ENUM_EXT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("PagingPriority error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // Enum + liblte_value_2_bits(ie->e, ptr, 3); + liblte_align_up_zero(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_pagingpriority( + uint8_t **ptr, + LIBLTE_S1AP_PAGINGPRIORITY_ENUM_EXT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("PagingPriority error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // Enum + ie->e = (LIBLTE_S1AP_PAGINGPRIORITY_ENUM)liblte_bits_2_value(ptr, 3); + liblte_align_up(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE PriorityLevel INTEGER +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_prioritylevel( + LIBLTE_S1AP_PRIORITYLEVEL_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Integer - ie->PriorityLevel + // lb:0, ub:15 + liblte_value_2_bits(ie->PriorityLevel, ptr, 4); + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_prioritylevel( + uint8_t **ptr, + LIBLTE_S1AP_PRIORITYLEVEL_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Integer - ie->PriorityLevel + // lb:0, ub:15 + ie->PriorityLevel = (uint8_t)liblte_bits_2_value(ptr, 4); + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE ECGIListForRestart DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:256 +LIBLTE_ERROR_ENUM liblte_s1ap_pack_ecgilistforrestart( + LIBLTE_S1AP_ECGILISTFORRESTART_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + if(ie->len > 32) { + liblte_log_print("ECGIListForRestart pack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_ENCODE_FAIL; + } + // Length + liblte_value_2_bits(ie->len-1, ptr, 8); + liblte_align_up_zero(ptr, 8); + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_pack_eutran_cgi(&ie->buffer[i], ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_ecgilistforrestart( + uint8_t **ptr, + LIBLTE_S1AP_ECGILISTFORRESTART_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Length + ie->len = liblte_bits_2_value(ptr, 8) + 1; + liblte_align_up(ptr, 8); + if(ie->len > 32) { + liblte_log_print("ECGIListForRestart unpack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_DECODE_FAIL; + } + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_unpack_eutran_cgi(ptr, &ie->buffer[i]) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE SourceeNB_ID SEQUENCE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_sourceenb_id( + LIBLTE_S1AP_SOURCEENB_ID_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + liblte_value_2_bits(ie->iE_Extensions_present?1:0, ptr, 1); + + if(liblte_s1ap_pack_global_enb_id(&ie->global_ENB_ID, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(liblte_s1ap_pack_tai(&ie->selected_TAI, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_pack_protocolextensioncontainer(&ie->iE_Extensions, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_sourceenb_id( + uint8_t **ptr, + LIBLTE_S1AP_SOURCEENB_ID_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + ie->iE_Extensions_present = liblte_bits_2_value(ptr, 1); + + if(liblte_s1ap_unpack_global_enb_id(ptr, &ie->global_ENB_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(liblte_s1ap_unpack_tai(ptr, &ie->selected_TAI) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_unpack_protocolextensioncontainer(ptr, &ie->iE_Extensions) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE ServedPLMNs DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:32 +LIBLTE_ERROR_ENUM liblte_s1ap_pack_servedplmns( + LIBLTE_S1AP_SERVEDPLMNS_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + if(ie->len > 32) { + liblte_log_print("ServedPLMNs pack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_ENCODE_FAIL; + } + // Length + liblte_value_2_bits(ie->len-1, ptr, 5); + liblte_align_up_zero(ptr, 8); + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_pack_tbcd_string(&ie->buffer[i], ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_servedplmns( + uint8_t **ptr, + LIBLTE_S1AP_SERVEDPLMNS_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Length + ie->len = liblte_bits_2_value(ptr, 5) + 1; + liblte_align_up(ptr, 8); + if(ie->len > 32) { + liblte_log_print("ServedPLMNs unpack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_DECODE_FAIL; + } + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_unpack_tbcd_string(ptr, &ie->buffer[i]) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE SupportedTAs_Item SEQUENCE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_supportedtas_item( + LIBLTE_S1AP_SUPPORTEDTAS_ITEM_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("SupportedTAs_Item error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + liblte_value_2_bits(ie->iE_Extensions_present?1:0, ptr, 1); + + if(liblte_s1ap_pack_tac(&ie->tAC, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(liblte_s1ap_pack_bplmns(&ie->broadcastPLMNs, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_pack_protocolextensioncontainer(&ie->iE_Extensions, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_supportedtas_item( + uint8_t **ptr, + LIBLTE_S1AP_SUPPORTEDTAS_ITEM_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("SupportedTAs_Item error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + ie->iE_Extensions_present = liblte_bits_2_value(ptr, 1); + + if(liblte_s1ap_unpack_tac(ptr, &ie->tAC) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(liblte_s1ap_unpack_bplmns(ptr, &ie->broadcastPLMNs) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_unpack_protocolextensioncontainer(ptr, &ie->iE_Extensions) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE TAIListforMDT DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:8 +LIBLTE_ERROR_ENUM liblte_s1ap_pack_tailistformdt( + LIBLTE_S1AP_TAILISTFORMDT_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + if(ie->len > 32) { + liblte_log_print("TAIListforMDT pack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_ENCODE_FAIL; + } + // Length + liblte_value_2_bits(ie->len-1, ptr, 3); + liblte_align_up_zero(ptr, 8); + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_pack_tai(&ie->buffer[i], ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_tailistformdt( + uint8_t **ptr, + LIBLTE_S1AP_TAILISTFORMDT_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Length + ie->len = liblte_bits_2_value(ptr, 3) + 1; + liblte_align_up(ptr, 8); + if(ie->len > 32) { + liblte_log_print("TAIListforMDT unpack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_DECODE_FAIL; + } + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_unpack_tai(ptr, &ie->buffer[i]) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE CompletedCellinTAI_Item SEQUENCE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_completedcellintai_item( + LIBLTE_S1AP_COMPLETEDCELLINTAI_ITEM_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("CompletedCellinTAI_Item error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + liblte_value_2_bits(ie->iE_Extensions_present?1:0, ptr, 1); + + if(liblte_s1ap_pack_eutran_cgi(&ie->eCGI, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_pack_protocolextensioncontainer(&ie->iE_Extensions, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_completedcellintai_item( + uint8_t **ptr, + LIBLTE_S1AP_COMPLETEDCELLINTAI_ITEM_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("CompletedCellinTAI_Item error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + ie->iE_Extensions_present = liblte_bits_2_value(ptr, 1); + + if(liblte_s1ap_unpack_eutran_cgi(ptr, &ie->eCGI) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_unpack_protocolextensioncontainer(ptr, &ie->iE_Extensions) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE TargeteNB_ID SEQUENCE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_targetenb_id( + LIBLTE_S1AP_TARGETENB_ID_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("TargeteNB_ID error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + liblte_value_2_bits(ie->iE_Extensions_present?1:0, ptr, 1); + + if(liblte_s1ap_pack_global_enb_id(&ie->global_ENB_ID, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(liblte_s1ap_pack_tai(&ie->selected_TAI, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_pack_protocolextensioncontainer(&ie->iE_Extensions, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_targetenb_id( + uint8_t **ptr, + LIBLTE_S1AP_TARGETENB_ID_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("TargeteNB_ID error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + ie->iE_Extensions_present = liblte_bits_2_value(ptr, 1); + + if(liblte_s1ap_unpack_global_enb_id(ptr, &ie->global_ENB_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(liblte_s1ap_unpack_tai(ptr, &ie->selected_TAI) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_unpack_protocolextensioncontainer(ptr, &ie->iE_Extensions) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE TargetBSS_ToSourceBSS_TransparentContainer DYNAMIC OCTET STRING +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_targetbss_tosourcebss_transparentcontainer( + LIBLTE_S1AP_TARGETBSS_TOSOURCEBSS_TRANSPARENTCONTAINER_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Dynamic octet string - TargetBSS-ToSourceBSS-TransparentContainer + // Length + if(ie->n_octets < 128) { + liblte_value_2_bits(0, ptr, 1); + liblte_value_2_bits(ie->n_octets, ptr, 7); + } else if(ie->n_octets < 16383) { + liblte_value_2_bits(1, ptr, 1); + liblte_value_2_bits(0, ptr, 1); + liblte_value_2_bits(ie->n_octets, ptr, 14); + } else { + // FIXME: Unlikely to have more than 16K of octets + } + + // Octets + uint32_t i; + for(i=0;in_octets;i++) { + liblte_value_2_bits(ie->buffer[i], ptr, 8); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_targetbss_tosourcebss_transparentcontainer( + uint8_t **ptr, + LIBLTE_S1AP_TARGETBSS_TOSOURCEBSS_TRANSPARENTCONTAINER_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Dynamic octet string - TargetBSS-ToSourceBSS-TransparentContainer + // Length + if(0 == liblte_bits_2_value(ptr, 1)) { + ie->n_octets = liblte_bits_2_value(ptr, 7); + } else { + if(0 == liblte_bits_2_value(ptr, 1)) { + ie->n_octets = liblte_bits_2_value(ptr, 14); + } else { + // FIXME: Unlikely to have more than 16K of octets + } + } + + // Octets + uint32_t i; + for(i=0;in_octets;i++) { + ie->buffer[i] = liblte_bits_2_value(ptr, 8); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE TAIListForRestart DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:2048 +LIBLTE_ERROR_ENUM liblte_s1ap_pack_tailistforrestart( + LIBLTE_S1AP_TAILISTFORRESTART_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + if(ie->len > 32) { + liblte_log_print("TAIListForRestart pack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_ENCODE_FAIL; + } + // Length + liblte_value_2_bits(ie->len-1, ptr, 11); + liblte_align_up_zero(ptr, 8); + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_pack_tai(&ie->buffer[i], ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_tailistforrestart( + uint8_t **ptr, + LIBLTE_S1AP_TAILISTFORRESTART_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Length + ie->len = liblte_bits_2_value(ptr, 11) + 1; + liblte_align_up(ptr, 8); + if(ie->len > 32) { + liblte_log_print("TAIListForRestart unpack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_DECODE_FAIL; + } + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_unpack_tai(ptr, &ie->buffer[i]) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE UserLocationInformation SEQUENCE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_userlocationinformation( + LIBLTE_S1AP_USERLOCATIONINFORMATION_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("UserLocationInformation error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + liblte_value_2_bits(ie->iE_Extensions_present?1:0, ptr, 1); + + if(liblte_s1ap_pack_eutran_cgi(&ie->eutran_cgi, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(liblte_s1ap_pack_tai(&ie->tai, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_pack_protocolextensioncontainer(&ie->iE_Extensions, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_userlocationinformation( + uint8_t **ptr, + LIBLTE_S1AP_USERLOCATIONINFORMATION_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("UserLocationInformation error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + ie->iE_Extensions_present = liblte_bits_2_value(ptr, 1); + + if(liblte_s1ap_unpack_eutran_cgi(ptr, &ie->eutran_cgi) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(liblte_s1ap_unpack_tai(ptr, &ie->tai) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_unpack_protocolextensioncontainer(ptr, &ie->iE_Extensions) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE ENBX2ExtTLAs DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:16 +LIBLTE_ERROR_ENUM liblte_s1ap_pack_enbx2exttlas( + LIBLTE_S1AP_ENBX2EXTTLAS_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + if(ie->len > 32) { + liblte_log_print("ENBX2ExtTLAs pack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_ENCODE_FAIL; + } + // Length + liblte_value_2_bits(ie->len-1, ptr, 4); + liblte_align_up_zero(ptr, 8); + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_pack_enbx2exttla(&ie->buffer[i], ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_enbx2exttlas( + uint8_t **ptr, + LIBLTE_S1AP_ENBX2EXTTLAS_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Length + ie->len = liblte_bits_2_value(ptr, 4) + 1; + liblte_align_up(ptr, 8); + if(ie->len > 32) { + liblte_log_print("ENBX2ExtTLAs unpack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_DECODE_FAIL; + } + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_unpack_enbx2exttla(ptr, &ie->buffer[i]) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE AllocationAndRetentionPriority SEQUENCE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_allocationandretentionpriority( + LIBLTE_S1AP_ALLOCATIONANDRETENTIONPRIORITY_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("AllocationAndRetentionPriority error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + liblte_value_2_bits(ie->iE_Extensions_present?1:0, ptr, 1); + + if(liblte_s1ap_pack_prioritylevel(&ie->priorityLevel, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // Enum - ie->pre_emptionCapability + liblte_value_2_bits(ie->pre_emptionCapability, ptr, 1); + + // Enum - ie->pre_emptionVulnerability + liblte_value_2_bits(ie->pre_emptionVulnerability, ptr, 1); + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_pack_protocolextensioncontainer(&ie->iE_Extensions, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_allocationandretentionpriority( + uint8_t **ptr, + LIBLTE_S1AP_ALLOCATIONANDRETENTIONPRIORITY_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("AllocationAndRetentionPriority error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + ie->iE_Extensions_present = liblte_bits_2_value(ptr, 1); + + if(liblte_s1ap_unpack_prioritylevel(ptr, &ie->priorityLevel) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + // Enum - ie->pre_emptionCapability + ie->pre_emptionCapability = (LIBLTE_S1AP_PRE_EMPTIONCAPABILITY_ENUM)liblte_bits_2_value(ptr, 1); + + // Enum - ie->pre_emptionVulnerability + ie->pre_emptionVulnerability = (LIBLTE_S1AP_PRE_EMPTIONVULNERABILITY_ENUM)liblte_bits_2_value(ptr, 1); + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_unpack_protocolextensioncontainer(ptr, &ie->iE_Extensions) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE CancelledCellinEAI_Item SEQUENCE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_cancelledcellineai_item( + LIBLTE_S1AP_CANCELLEDCELLINEAI_ITEM_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("CancelledCellinEAI_Item error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + liblte_value_2_bits(ie->iE_Extensions_present?1:0, ptr, 1); + + if(liblte_s1ap_pack_eutran_cgi(&ie->eCGI, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(liblte_s1ap_pack_numberofbroadcasts(&ie->numberOfBroadcasts, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_pack_protocolextensioncontainer(&ie->iE_Extensions, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_cancelledcellineai_item( + uint8_t **ptr, + LIBLTE_S1AP_CANCELLEDCELLINEAI_ITEM_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("CancelledCellinEAI_Item error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + ie->iE_Extensions_present = liblte_bits_2_value(ptr, 1); + + if(liblte_s1ap_unpack_eutran_cgi(ptr, &ie->eCGI) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(liblte_s1ap_unpack_numberofbroadcasts(ptr, &ie->numberOfBroadcasts) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_unpack_protocolextensioncontainer(ptr, &ie->iE_Extensions) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE CancelledCellinTAI_Item SEQUENCE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_cancelledcellintai_item( + LIBLTE_S1AP_CANCELLEDCELLINTAI_ITEM_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("CancelledCellinTAI_Item error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + liblte_value_2_bits(ie->iE_Extensions_present?1:0, ptr, 1); + + if(liblte_s1ap_pack_eutran_cgi(&ie->eCGI, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(liblte_s1ap_pack_numberofbroadcasts(&ie->numberOfBroadcasts, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_pack_protocolextensioncontainer(&ie->iE_Extensions, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_cancelledcellintai_item( + uint8_t **ptr, + LIBLTE_S1AP_CANCELLEDCELLINTAI_ITEM_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("CancelledCellinTAI_Item error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + ie->iE_Extensions_present = liblte_bits_2_value(ptr, 1); + + if(liblte_s1ap_unpack_eutran_cgi(ptr, &ie->eCGI) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(liblte_s1ap_unpack_numberofbroadcasts(ptr, &ie->numberOfBroadcasts) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_unpack_protocolextensioncontainer(ptr, &ie->iE_Extensions) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE CellID_Broadcast_Item SEQUENCE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_cellid_broadcast_item( + LIBLTE_S1AP_CELLID_BROADCAST_ITEM_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("CellID_Broadcast_Item error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + liblte_value_2_bits(ie->iE_Extensions_present?1:0, ptr, 1); + + if(liblte_s1ap_pack_eutran_cgi(&ie->eCGI, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_pack_protocolextensioncontainer(&ie->iE_Extensions, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_cellid_broadcast_item( + uint8_t **ptr, + LIBLTE_S1AP_CELLID_BROADCAST_ITEM_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("CellID_Broadcast_Item error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + ie->iE_Extensions_present = liblte_bits_2_value(ptr, 1); + + if(liblte_s1ap_unpack_eutran_cgi(ptr, &ie->eCGI) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_unpack_protocolextensioncontainer(ptr, &ie->iE_Extensions) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE CellID_Cancelled_Item SEQUENCE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_cellid_cancelled_item( + LIBLTE_S1AP_CELLID_CANCELLED_ITEM_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("CellID_Cancelled_Item error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + liblte_value_2_bits(ie->iE_Extensions_present?1:0, ptr, 1); + + if(liblte_s1ap_pack_eutran_cgi(&ie->eCGI, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(liblte_s1ap_pack_numberofbroadcasts(&ie->numberOfBroadcasts, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_pack_protocolextensioncontainer(&ie->iE_Extensions, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_cellid_cancelled_item( + uint8_t **ptr, + LIBLTE_S1AP_CELLID_CANCELLED_ITEM_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("CellID_Cancelled_Item error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + ie->iE_Extensions_present = liblte_bits_2_value(ptr, 1); + + if(liblte_s1ap_unpack_eutran_cgi(ptr, &ie->eCGI) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(liblte_s1ap_unpack_numberofbroadcasts(ptr, &ie->numberOfBroadcasts) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_unpack_protocolextensioncontainer(ptr, &ie->iE_Extensions) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE CellIdListforMDT DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:32 +LIBLTE_ERROR_ENUM liblte_s1ap_pack_cellidlistformdt( + LIBLTE_S1AP_CELLIDLISTFORMDT_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + if(ie->len > 32) { + liblte_log_print("CellIdListforMDT pack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_ENCODE_FAIL; + } + // Length + liblte_value_2_bits(ie->len-1, ptr, 5); + liblte_align_up_zero(ptr, 8); + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_pack_eutran_cgi(&ie->buffer[i], ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_cellidlistformdt( + uint8_t **ptr, + LIBLTE_S1AP_CELLIDLISTFORMDT_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Length + ie->len = liblte_bits_2_value(ptr, 5) + 1; + liblte_align_up(ptr, 8); + if(ie->len > 32) { + liblte_log_print("CellIdListforMDT unpack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_DECODE_FAIL; + } + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_unpack_eutran_cgi(ptr, &ie->buffer[i]) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE CSG_Id STATIC BIT STRING +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_csg_id( + LIBLTE_S1AP_CSG_ID_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Static bit string - CSG-Id + liblte_align_up_zero(ptr, 8); + uint32_t i; + for(i=0;ibuffer[i], ptr, 1); + } + liblte_align_up_zero(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_csg_id( + uint8_t **ptr, + LIBLTE_S1AP_CSG_ID_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Static bit string - CSG-Id + liblte_align_up(ptr, 8); + uint32_t i; + for(i=0;ibuffer[i] = liblte_bits_2_value(ptr, 1); + } + liblte_align_up(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE CSG_IdList_Item SEQUENCE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_csg_idlist_item( + LIBLTE_S1AP_CSG_IDLIST_ITEM_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("CSG_IdList_Item error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + liblte_value_2_bits(ie->iE_Extensions_present?1:0, ptr, 1); + + if(liblte_s1ap_pack_csg_id(&ie->cSG_Id, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_pack_protocolextensioncontainer(&ie->iE_Extensions, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_csg_idlist_item( + uint8_t **ptr, + LIBLTE_S1AP_CSG_IDLIST_ITEM_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("CSG_IdList_Item error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + ie->iE_Extensions_present = liblte_bits_2_value(ptr, 1); + + if(liblte_s1ap_unpack_csg_id(ptr, &ie->cSG_Id) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_unpack_protocolextensioncontainer(ptr, &ie->iE_Extensions) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE Direct_Forwarding_Path_Availability ENUMERATED +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_direct_forwarding_path_availability( + LIBLTE_S1AP_DIRECT_FORWARDING_PATH_AVAILABILITY_ENUM_EXT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("Direct_Forwarding_Path_Availability error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // Enum + liblte_value_2_bits(ie->e, ptr, 0); + liblte_align_up_zero(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_direct_forwarding_path_availability( + uint8_t **ptr, + LIBLTE_S1AP_DIRECT_FORWARDING_PATH_AVAILABILITY_ENUM_EXT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("Direct_Forwarding_Path_Availability error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // Enum + ie->e = (LIBLTE_S1AP_DIRECT_FORWARDING_PATH_AVAILABILITY_ENUM)liblte_bits_2_value(ptr, 0); + liblte_align_up(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE CompletedCellinEAI_Item SEQUENCE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_completedcellineai_item( + LIBLTE_S1AP_COMPLETEDCELLINEAI_ITEM_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("CompletedCellinEAI_Item error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + liblte_value_2_bits(ie->iE_Extensions_present?1:0, ptr, 1); + + if(liblte_s1ap_pack_eutran_cgi(&ie->eCGI, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_pack_protocolextensioncontainer(&ie->iE_Extensions, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_completedcellineai_item( + uint8_t **ptr, + LIBLTE_S1AP_COMPLETEDCELLINEAI_ITEM_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("CompletedCellinEAI_Item error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + ie->iE_Extensions_present = liblte_bits_2_value(ptr, 1); + + if(liblte_s1ap_unpack_eutran_cgi(ptr, &ie->eCGI) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_unpack_protocolextensioncontainer(ptr, &ie->iE_Extensions) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Container List E_RABInformationList DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:256 +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabinformationlist( + LIBLTE_S1AP_E_RABINFORMATIONLIST_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + if(ie->len > 32) { + liblte_log_print("E_RABInformationList pack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_ENCODE_FAIL; + } + // Length + liblte_value_2_bits(ie->len-1, ptr, 8); + liblte_align_up_zero(ptr, 8); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + uint32_t i; + for(i=0;ilen;i++) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_e_rabinformationlistitem(&ie->buffer[i], &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_E_RABINFORMATIONLISTITEM, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabinformationlist( + uint8_t **ptr, + LIBLTE_S1AP_E_RABINFORMATIONLIST_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + + // Length + ie->len = liblte_bits_2_value(ptr, 8) + 1; + liblte_align_up(ptr, 8); + if(ie->len > 32) { + liblte_log_print("E_RABInformationList unpack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_DECODE_FAIL; + } + + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_unpack_protocolie_header(ptr, &ie_id, &crit, &len) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + if(LIBLTE_S1AP_IE_ID_E_RABINFORMATIONLISTITEM != ie_id) { + return LIBLTE_ERROR_DECODE_FAIL; + } + if(liblte_s1ap_unpack_e_rabinformationlistitem(ptr, &ie->buffer[i]) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE ForbiddenTAs DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:16 +LIBLTE_ERROR_ENUM liblte_s1ap_pack_forbiddentas( + LIBLTE_S1AP_FORBIDDENTAS_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + if(ie->len > 32) { + liblte_log_print("ForbiddenTAs pack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_ENCODE_FAIL; + } + // Length + liblte_value_2_bits(ie->len-1, ptr, 4); + liblte_align_up_zero(ptr, 8); + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_pack_forbiddentas_item(&ie->buffer[i], ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_forbiddentas( + uint8_t **ptr, + LIBLTE_S1AP_FORBIDDENTAS_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Length + ie->len = liblte_bits_2_value(ptr, 4) + 1; + liblte_align_up(ptr, 8); + if(ie->len > 32) { + liblte_log_print("ForbiddenTAs unpack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_DECODE_FAIL; + } + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_unpack_forbiddentas_item(ptr, &ie->buffer[i]) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE GUMMEI SEQUENCE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_gummei( + LIBLTE_S1AP_GUMMEI_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("GUMMEI error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + liblte_value_2_bits(ie->iE_Extensions_present?1:0, ptr, 1); + + if(liblte_s1ap_pack_tbcd_string(&ie->pLMN_Identity, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(liblte_s1ap_pack_mme_group_id(&ie->mME_Group_ID, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(liblte_s1ap_pack_mme_code(&ie->mME_Code, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_pack_protocolextensioncontainer(&ie->iE_Extensions, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_gummei( + uint8_t **ptr, + LIBLTE_S1AP_GUMMEI_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("GUMMEI error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + ie->iE_Extensions_present = liblte_bits_2_value(ptr, 1); + + if(liblte_s1ap_unpack_tbcd_string(ptr, &ie->pLMN_Identity) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(liblte_s1ap_unpack_mme_group_id(ptr, &ie->mME_Group_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(liblte_s1ap_unpack_mme_code(ptr, &ie->mME_Code) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_unpack_protocolextensioncontainer(ptr, &ie->iE_Extensions) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE LoggedMDT SEQUENCE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_loggedmdt( + LIBLTE_S1AP_LOGGEDMDT_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("LoggedMDT error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + liblte_value_2_bits(ie->iE_Extensions_present?1:0, ptr, 1); + + // Enum - ie->loggingInterval + liblte_value_2_bits(ie->loggingInterval, ptr, 3); + + // Enum - ie->loggingDuration + liblte_value_2_bits(ie->loggingDuration, ptr, 3); + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_pack_protocolextensioncontainer(&ie->iE_Extensions, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_loggedmdt( + uint8_t **ptr, + LIBLTE_S1AP_LOGGEDMDT_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("LoggedMDT error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + ie->iE_Extensions_present = liblte_bits_2_value(ptr, 1); + + // Enum - ie->loggingInterval + ie->loggingInterval = (LIBLTE_S1AP_LOGGINGINTERVAL_ENUM)liblte_bits_2_value(ptr, 3); + + // Enum - ie->loggingDuration + ie->loggingDuration = (LIBLTE_S1AP_LOGGINGDURATION_ENUM)liblte_bits_2_value(ptr, 3); + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_unpack_protocolextensioncontainer(ptr, &ie->iE_Extensions) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE NASSecurityParametersfromE_UTRAN DYNAMIC OCTET STRING +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_nassecurityparametersfrome_utran( + LIBLTE_S1AP_NASSECURITYPARAMETERSFROME_UTRAN_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Dynamic octet string - NASSecurityParametersfromE-UTRAN + // Length + if(ie->n_octets < 128) { + liblte_value_2_bits(0, ptr, 1); + liblte_value_2_bits(ie->n_octets, ptr, 7); + } else if(ie->n_octets < 16383) { + liblte_value_2_bits(1, ptr, 1); + liblte_value_2_bits(0, ptr, 1); + liblte_value_2_bits(ie->n_octets, ptr, 14); + } else { + // FIXME: Unlikely to have more than 16K of octets + } + + // Octets + uint32_t i; + for(i=0;in_octets;i++) { + liblte_value_2_bits(ie->buffer[i], ptr, 8); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_nassecurityparametersfrome_utran( + uint8_t **ptr, + LIBLTE_S1AP_NASSECURITYPARAMETERSFROME_UTRAN_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Dynamic octet string - NASSecurityParametersfromE-UTRAN + // Length + if(0 == liblte_bits_2_value(ptr, 1)) { + ie->n_octets = liblte_bits_2_value(ptr, 7); + } else { + if(0 == liblte_bits_2_value(ptr, 1)) { + ie->n_octets = liblte_bits_2_value(ptr, 14); + } else { + // FIXME: Unlikely to have more than 16K of octets + } + } + + // Octets + uint32_t i; + for(i=0;in_octets;i++) { + ie->buffer[i] = liblte_bits_2_value(ptr, 8); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE ReportAmountMDT ENUMERATED +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_reportamountmdt( + LIBLTE_S1AP_REPORTAMOUNTMDT_ENUM *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Enum - *ie + liblte_value_2_bits(*ie, ptr, 3); + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_reportamountmdt( + uint8_t **ptr, + LIBLTE_S1AP_REPORTAMOUNTMDT_ENUM *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Enum - *ie + *ie = (LIBLTE_S1AP_REPORTAMOUNTMDT_ENUM)liblte_bits_2_value(ptr, 3); + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE ServedGUMMEIsItem SEQUENCE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_servedgummeisitem( + LIBLTE_S1AP_SERVEDGUMMEISITEM_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("ServedGUMMEIsItem error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + liblte_value_2_bits(ie->iE_Extensions_present?1:0, ptr, 1); + + if(liblte_s1ap_pack_servedplmns(&ie->servedPLMNs, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(liblte_s1ap_pack_servedgroupids(&ie->servedGroupIDs, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(liblte_s1ap_pack_servedmmecs(&ie->servedMMECs, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_pack_protocolextensioncontainer(&ie->iE_Extensions, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_servedgummeisitem( + uint8_t **ptr, + LIBLTE_S1AP_SERVEDGUMMEISITEM_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("ServedGUMMEIsItem error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + ie->iE_Extensions_present = liblte_bits_2_value(ptr, 1); + + if(liblte_s1ap_unpack_servedplmns(ptr, &ie->servedPLMNs) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(liblte_s1ap_unpack_servedgroupids(ptr, &ie->servedGroupIDs) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(liblte_s1ap_unpack_servedmmecs(ptr, &ie->servedMMECs) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_unpack_protocolextensioncontainer(ptr, &ie->iE_Extensions) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE S_TMSI SEQUENCE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_s_tmsi( + LIBLTE_S1AP_S_TMSI_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("S_TMSI error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + liblte_value_2_bits(ie->iE_Extensions_present?1:0, ptr, 1); + + if(liblte_s1ap_pack_mme_code(&ie->mMEC, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(liblte_s1ap_pack_m_tmsi(&ie->m_TMSI, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_pack_protocolextensioncontainer(&ie->iE_Extensions, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_s_tmsi( + uint8_t **ptr, + LIBLTE_S1AP_S_TMSI_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("S_TMSI error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + ie->iE_Extensions_present = liblte_bits_2_value(ptr, 1); + + if(liblte_s1ap_unpack_mme_code(ptr, &ie->mMEC) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(liblte_s1ap_unpack_m_tmsi(ptr, &ie->m_TMSI) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_unpack_protocolextensioncontainer(ptr, &ie->iE_Extensions) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE TAIListforWarning DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:65535 +LIBLTE_ERROR_ENUM liblte_s1ap_pack_tailistforwarning( + LIBLTE_S1AP_TAILISTFORWARNING_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + if(ie->len > 32) { + liblte_log_print("TAIListforWarning pack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_ENCODE_FAIL; + } + // Length + liblte_value_2_bits(ie->len-1, ptr, 16); + liblte_align_up_zero(ptr, 8); + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_pack_tai(&ie->buffer[i], ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_tailistforwarning( + uint8_t **ptr, + LIBLTE_S1AP_TAILISTFORWARNING_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Length + ie->len = liblte_bits_2_value(ptr, 16) + 1; + liblte_align_up(ptr, 8); + if(ie->len > 32) { + liblte_log_print("TAIListforWarning unpack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_DECODE_FAIL; + } + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_unpack_tai(ptr, &ie->buffer[i]) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE CompletedCellinTAI DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:65535 +LIBLTE_ERROR_ENUM liblte_s1ap_pack_completedcellintai( + LIBLTE_S1AP_COMPLETEDCELLINTAI_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + if(ie->len > 32) { + liblte_log_print("CompletedCellinTAI pack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_ENCODE_FAIL; + } + // Length + liblte_value_2_bits(ie->len-1, ptr, 16); + liblte_align_up_zero(ptr, 8); + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_pack_completedcellintai_item(&ie->buffer[i], ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_completedcellintai( + uint8_t **ptr, + LIBLTE_S1AP_COMPLETEDCELLINTAI_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Length + ie->len = liblte_bits_2_value(ptr, 16) + 1; + liblte_align_up(ptr, 8); + if(ie->len > 32) { + liblte_log_print("CompletedCellinTAI unpack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_DECODE_FAIL; + } + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_unpack_completedcellintai_item(ptr, &ie->buffer[i]) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE TargetRNC_ID SEQUENCE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_targetrnc_id( + LIBLTE_S1AP_TARGETRNC_ID_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("TargetRNC_ID error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + liblte_value_2_bits(ie->rAC_present?1:0, ptr, 1); + liblte_value_2_bits(ie->extendedRNC_ID_present?1:0, ptr, 1); + liblte_value_2_bits(ie->iE_Extensions_present?1:0, ptr, 1); + + if(liblte_s1ap_pack_lai(&ie->lAI, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(ie->rAC_present) { + if(liblte_s1ap_pack_rac(&ie->rAC, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + + if(liblte_s1ap_pack_rnc_id(&ie->rNC_ID, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(ie->extendedRNC_ID_present) { + if(liblte_s1ap_pack_extendedrnc_id(&ie->extendedRNC_ID, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_pack_protocolextensioncontainer(&ie->iE_Extensions, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_targetrnc_id( + uint8_t **ptr, + LIBLTE_S1AP_TARGETRNC_ID_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("TargetRNC_ID error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + ie->rAC_present = liblte_bits_2_value(ptr, 1); + ie->extendedRNC_ID_present = liblte_bits_2_value(ptr, 1); + ie->iE_Extensions_present = liblte_bits_2_value(ptr, 1); + + if(liblte_s1ap_unpack_lai(ptr, &ie->lAI) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(ie->rAC_present) { + if(liblte_s1ap_unpack_rac(ptr, &ie->rAC) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + + if(liblte_s1ap_unpack_rnc_id(ptr, &ie->rNC_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(ie->extendedRNC_ID_present) { + if(liblte_s1ap_unpack_extendedrnc_id(ptr, &ie->extendedRNC_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_unpack_protocolextensioncontainer(ptr, &ie->iE_Extensions) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE UE_associatedLogicalS1_ConnectionItem SEQUENCE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_ue_associatedlogicals1_connectionitem( + LIBLTE_S1AP_UE_ASSOCIATEDLOGICALS1_CONNECTIONITEM_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("UE_associatedLogicalS1_ConnectionItem error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + liblte_value_2_bits(ie->mME_UE_S1AP_ID_present?1:0, ptr, 1); + liblte_value_2_bits(ie->eNB_UE_S1AP_ID_present?1:0, ptr, 1); + liblte_value_2_bits(ie->iE_Extensions_present?1:0, ptr, 1); + + if(ie->mME_UE_S1AP_ID_present) { + if(liblte_s1ap_pack_mme_ue_s1ap_id(&ie->mME_UE_S1AP_ID, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + + if(ie->eNB_UE_S1AP_ID_present) { + if(liblte_s1ap_pack_enb_ue_s1ap_id(&ie->eNB_UE_S1AP_ID, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_pack_protocolextensioncontainer(&ie->iE_Extensions, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_ue_associatedlogicals1_connectionitem( + uint8_t **ptr, + LIBLTE_S1AP_UE_ASSOCIATEDLOGICALS1_CONNECTIONITEM_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("UE_associatedLogicalS1_ConnectionItem error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + ie->mME_UE_S1AP_ID_present = liblte_bits_2_value(ptr, 1); + ie->eNB_UE_S1AP_ID_present = liblte_bits_2_value(ptr, 1); + ie->iE_Extensions_present = liblte_bits_2_value(ptr, 1); + + if(ie->mME_UE_S1AP_ID_present) { + if(liblte_s1ap_unpack_mme_ue_s1ap_id(ptr, &ie->mME_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + + if(ie->eNB_UE_S1AP_ID_present) { + if(liblte_s1ap_unpack_enb_ue_s1ap_id(ptr, &ie->eNB_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_unpack_protocolextensioncontainer(ptr, &ie->iE_Extensions) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE UEPagingID CHOICE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_uepagingid( + LIBLTE_S1AP_UEPAGINGID_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("UEPagingID error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // Choice type + liblte_value_2_bits(ie->choice_type, ptr, 1); + + // Choice + if(ie->choice_type == LIBLTE_S1AP_UEPAGINGID_CHOICE_S_TMSI) { + if(liblte_s1ap_pack_s_tmsi(&ie->choice.s_TMSI, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(ie->choice_type == LIBLTE_S1AP_UEPAGINGID_CHOICE_IMSI) { + if(liblte_s1ap_pack_imsi(&ie->choice.iMSI, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_uepagingid( + uint8_t **ptr, + LIBLTE_S1AP_UEPAGINGID_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("UEPagingID error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // Choice type + ie->choice_type = (LIBLTE_S1AP_UEPAGINGID_CHOICE_ENUM)liblte_bits_2_value(ptr, 1); + + // Choice + if(ie->choice_type == LIBLTE_S1AP_UEPAGINGID_CHOICE_S_TMSI) { + if(liblte_s1ap_unpack_s_tmsi(ptr, &ie->choice.s_TMSI) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(ie->choice_type == LIBLTE_S1AP_UEPAGINGID_CHOICE_IMSI) { + if(liblte_s1ap_unpack_imsi(ptr, &ie->choice.iMSI) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE Bearers_SubjectToStatusTransfer_Item SEQUENCE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_bearers_subjecttostatustransfer_item( + LIBLTE_S1AP_BEARERS_SUBJECTTOSTATUSTRANSFER_ITEM_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("Bearers_SubjectToStatusTransfer_Item error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + liblte_value_2_bits(ie->receiveStatusofULPDCPSDUs_present?1:0, ptr, 1); + liblte_value_2_bits(ie->iE_Extensions_present?1:0, ptr, 1); + + if(liblte_s1ap_pack_e_rab_id(&ie->e_RAB_ID, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(liblte_s1ap_pack_countvalue(&ie->uL_COUNTvalue, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(liblte_s1ap_pack_countvalue(&ie->dL_COUNTvalue, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(ie->receiveStatusofULPDCPSDUs_present) { + if(liblte_s1ap_pack_receivestatusofulpdcpsdus(&ie->receiveStatusofULPDCPSDUs, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_pack_protocolextensioncontainer(&ie->iE_Extensions, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_bearers_subjecttostatustransfer_item( + uint8_t **ptr, + LIBLTE_S1AP_BEARERS_SUBJECTTOSTATUSTRANSFER_ITEM_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("Bearers_SubjectToStatusTransfer_Item error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + ie->receiveStatusofULPDCPSDUs_present = liblte_bits_2_value(ptr, 1); + ie->iE_Extensions_present = liblte_bits_2_value(ptr, 1); + + if(liblte_s1ap_unpack_e_rab_id(ptr, &ie->e_RAB_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(liblte_s1ap_unpack_countvalue(ptr, &ie->uL_COUNTvalue) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(liblte_s1ap_unpack_countvalue(ptr, &ie->dL_COUNTvalue) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(ie->receiveStatusofULPDCPSDUs_present) { + if(liblte_s1ap_unpack_receivestatusofulpdcpsdus(ptr, &ie->receiveStatusofULPDCPSDUs) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_unpack_protocolextensioncontainer(ptr, &ie->iE_Extensions) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE CancelledCellinEAI DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:65535 +LIBLTE_ERROR_ENUM liblte_s1ap_pack_cancelledcellineai( + LIBLTE_S1AP_CANCELLEDCELLINEAI_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + if(ie->len > 32) { + liblte_log_print("CancelledCellinEAI pack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_ENCODE_FAIL; + } + // Length + liblte_value_2_bits(ie->len-1, ptr, 16); + liblte_align_up_zero(ptr, 8); + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_pack_cancelledcellineai_item(&ie->buffer[i], ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_cancelledcellineai( + uint8_t **ptr, + LIBLTE_S1AP_CANCELLEDCELLINEAI_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Length + ie->len = liblte_bits_2_value(ptr, 16) + 1; + liblte_align_up(ptr, 8); + if(ie->len > 32) { + liblte_log_print("CancelledCellinEAI unpack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_DECODE_FAIL; + } + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_unpack_cancelledcellineai_item(ptr, &ie->buffer[i]) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE CellID_Broadcast DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:65535 +LIBLTE_ERROR_ENUM liblte_s1ap_pack_cellid_broadcast( + LIBLTE_S1AP_CELLID_BROADCAST_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + if(ie->len > 32) { + liblte_log_print("CellID_Broadcast pack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_ENCODE_FAIL; + } + // Length + liblte_value_2_bits(ie->len-1, ptr, 16); + liblte_align_up_zero(ptr, 8); + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_pack_cellid_broadcast_item(&ie->buffer[i], ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_cellid_broadcast( + uint8_t **ptr, + LIBLTE_S1AP_CELLID_BROADCAST_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Length + ie->len = liblte_bits_2_value(ptr, 16) + 1; + liblte_align_up(ptr, 8); + if(ie->len > 32) { + liblte_log_print("CellID_Broadcast unpack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_DECODE_FAIL; + } + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_unpack_cellid_broadcast_item(ptr, &ie->buffer[i]) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE CellBasedMDT SEQUENCE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_cellbasedmdt( + LIBLTE_S1AP_CELLBASEDMDT_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("CellBasedMDT error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + liblte_value_2_bits(ie->iE_Extensions_present?1:0, ptr, 1); + + if(liblte_s1ap_pack_cellidlistformdt(&ie->cellIdListforMDT, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_pack_protocolextensioncontainer(&ie->iE_Extensions, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_cellbasedmdt( + uint8_t **ptr, + LIBLTE_S1AP_CELLBASEDMDT_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("CellBasedMDT error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + ie->iE_Extensions_present = liblte_bits_2_value(ptr, 1); + + if(liblte_s1ap_unpack_cellidlistformdt(ptr, &ie->cellIdListforMDT) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_unpack_protocolextensioncontainer(ptr, &ie->iE_Extensions) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE CSG_IdList DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:256 +LIBLTE_ERROR_ENUM liblte_s1ap_pack_csg_idlist( + LIBLTE_S1AP_CSG_IDLIST_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + if(ie->len > 32) { + liblte_log_print("CSG_IdList pack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_ENCODE_FAIL; + } + // Length + liblte_value_2_bits(ie->len-1, ptr, 8); + liblte_align_up_zero(ptr, 8); + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_pack_csg_idlist_item(&ie->buffer[i], ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_csg_idlist( + uint8_t **ptr, + LIBLTE_S1AP_CSG_IDLIST_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Length + ie->len = liblte_bits_2_value(ptr, 8) + 1; + liblte_align_up(ptr, 8); + if(ie->len > 32) { + liblte_log_print("CSG_IdList unpack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_DECODE_FAIL; + } + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_unpack_csg_idlist_item(ptr, &ie->buffer[i]) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE ECGIList DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:65535 +LIBLTE_ERROR_ENUM liblte_s1ap_pack_ecgilist( + LIBLTE_S1AP_ECGILIST_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + if(ie->len > 32) { + liblte_log_print("ECGIList pack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_ENCODE_FAIL; + } + // Length + liblte_value_2_bits(ie->len-1, ptr, 16); + liblte_align_up_zero(ptr, 8); + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_pack_eutran_cgi(&ie->buffer[i], ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_ecgilist( + uint8_t **ptr, + LIBLTE_S1AP_ECGILIST_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Length + ie->len = liblte_bits_2_value(ptr, 16) + 1; + liblte_align_up(ptr, 8); + if(ie->len > 32) { + liblte_log_print("ECGIList unpack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_DECODE_FAIL; + } + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_unpack_eutran_cgi(ptr, &ie->buffer[i]) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE EmergencyAreaID_Cancelled_Item SEQUENCE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_emergencyareaid_cancelled_item( + LIBLTE_S1AP_EMERGENCYAREAID_CANCELLED_ITEM_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("EmergencyAreaID_Cancelled_Item error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + liblte_value_2_bits(ie->iE_Extensions_present?1:0, ptr, 1); + + if(liblte_s1ap_pack_emergencyareaid(&ie->emergencyAreaID, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(liblte_s1ap_pack_cancelledcellineai(&ie->cancelledCellinEAI, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_pack_protocolextensioncontainer(&ie->iE_Extensions, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_emergencyareaid_cancelled_item( + uint8_t **ptr, + LIBLTE_S1AP_EMERGENCYAREAID_CANCELLED_ITEM_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("EmergencyAreaID_Cancelled_Item error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + ie->iE_Extensions_present = liblte_bits_2_value(ptr, 1); + + if(liblte_s1ap_unpack_emergencyareaid(ptr, &ie->emergencyAreaID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(liblte_s1ap_unpack_cancelledcellineai(ptr, &ie->cancelledCellinEAI) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_unpack_protocolextensioncontainer(ptr, &ie->iE_Extensions) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE GERAN_Cell_ID SEQUENCE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_geran_cell_id( + LIBLTE_S1AP_GERAN_CELL_ID_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("GERAN_Cell_ID error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + liblte_value_2_bits(ie->iE_Extensions_present?1:0, ptr, 1); + + if(liblte_s1ap_pack_lai(&ie->lAI, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(liblte_s1ap_pack_rac(&ie->rAC, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(liblte_s1ap_pack_ci(&ie->cI, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_pack_protocolextensioncontainer(&ie->iE_Extensions, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_geran_cell_id( + uint8_t **ptr, + LIBLTE_S1AP_GERAN_CELL_ID_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("GERAN_Cell_ID error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + ie->iE_Extensions_present = liblte_bits_2_value(ptr, 1); + + if(liblte_s1ap_unpack_lai(ptr, &ie->lAI) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(liblte_s1ap_unpack_rac(ptr, &ie->rAC) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(liblte_s1ap_unpack_ci(ptr, &ie->cI) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_unpack_protocolextensioncontainer(ptr, &ie->iE_Extensions) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Container List E_RABList DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:256 +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rablist( + LIBLTE_S1AP_E_RABLIST_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + if(ie->len > 32) { + liblte_log_print("E_RABList pack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_ENCODE_FAIL; + } + // Length + liblte_value_2_bits(ie->len-1, ptr, 8); + liblte_align_up_zero(ptr, 8); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + uint32_t i; + for(i=0;ilen;i++) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_e_rabitem(&ie->buffer[i], &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_E_RABITEM, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rablist( + uint8_t **ptr, + LIBLTE_S1AP_E_RABLIST_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + + // Length + ie->len = liblte_bits_2_value(ptr, 8) + 1; + liblte_align_up(ptr, 8); + if(ie->len > 32) { + liblte_log_print("E_RABList unpack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_DECODE_FAIL; + } + + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_unpack_protocolie_header(ptr, &ie_id, &crit, &len) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + if(LIBLTE_S1AP_IE_ID_E_RABITEM != ie_id) { + return LIBLTE_ERROR_DECODE_FAIL; + } + if(liblte_s1ap_unpack_e_rabitem(ptr, &ie->buffer[i]) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE ForbiddenLAs DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:16 +LIBLTE_ERROR_ENUM liblte_s1ap_pack_forbiddenlas( + LIBLTE_S1AP_FORBIDDENLAS_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + if(ie->len > 32) { + liblte_log_print("ForbiddenLAs pack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_ENCODE_FAIL; + } + // Length + liblte_value_2_bits(ie->len-1, ptr, 4); + liblte_align_up_zero(ptr, 8); + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_pack_forbiddenlas_item(&ie->buffer[i], ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_forbiddenlas( + uint8_t **ptr, + LIBLTE_S1AP_FORBIDDENLAS_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Length + ie->len = liblte_bits_2_value(ptr, 4) + 1; + liblte_align_up(ptr, 8); + if(ie->len > 32) { + liblte_log_print("ForbiddenLAs unpack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_DECODE_FAIL; + } + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_unpack_forbiddenlas_item(ptr, &ie->buffer[i]) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE MDT_Location_Info STATIC BIT STRING +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_mdt_location_info( + LIBLTE_S1AP_MDT_LOCATION_INFO_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Static bit string - MDT-Location-Info + uint32_t i; + for(i=0;ibuffer[i], ptr, 1); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_mdt_location_info( + uint8_t **ptr, + LIBLTE_S1AP_MDT_LOCATION_INFO_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Static bit string - MDT-Location-Info + uint32_t i; + for(i=0;ibuffer[i] = liblte_bits_2_value(ptr, 1); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE M1PeriodicReporting SEQUENCE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_m1periodicreporting( + LIBLTE_S1AP_M1PERIODICREPORTING_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("M1PeriodicReporting error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + liblte_value_2_bits(ie->iE_Extensions_present?1:0, ptr, 1); + + // Enum - ie->reportInterval + liblte_value_2_bits(ie->reportInterval, ptr, 4); + + // Enum - ie->reportAmount + liblte_value_2_bits(ie->reportAmount, ptr, 3); + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_pack_protocolextensioncontainer(&ie->iE_Extensions, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_m1periodicreporting( + uint8_t **ptr, + LIBLTE_S1AP_M1PERIODICREPORTING_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("M1PeriodicReporting error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + ie->iE_Extensions_present = liblte_bits_2_value(ptr, 1); + + // Enum - ie->reportInterval + ie->reportInterval = (LIBLTE_S1AP_REPORTINTERVALMDT_ENUM)liblte_bits_2_value(ptr, 4); + + // Enum - ie->reportAmount + ie->reportAmount = (LIBLTE_S1AP_REPORTAMOUNTMDT_ENUM)liblte_bits_2_value(ptr, 3); + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_unpack_protocolextensioncontainer(ptr, &ie->iE_Extensions) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + + +/******************************************************************************* +/* ProtocolIE eHRPD_Sector_ID DYNAMIC OCTET STRING +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_ehrpd_sector_id( + LIBLTE_S1AP_EHRPD_SECTOR_ID_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Dynamic octet string - eHRPD-Sector-ID + // Length + if(ie->n_octets < 128) { + liblte_value_2_bits(0, ptr, 1); + liblte_value_2_bits(ie->n_octets, ptr, 7); + } else if(ie->n_octets < 16383) { + liblte_value_2_bits(1, ptr, 1); + liblte_value_2_bits(0, ptr, 1); + liblte_value_2_bits(ie->n_octets, ptr, 14); + } else { + // FIXME: Unlikely to have more than 16K of octets + } + + // Octets + uint32_t i; + for(i=0;in_octets;i++) { + liblte_value_2_bits(ie->buffer[i], ptr, 8); + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_ehrpd_sector_id( + uint8_t **ptr, + LIBLTE_S1AP_EHRPD_SECTOR_ID_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Dynamic octet string - eHRPD-Sector-ID + // Length + if(0 == liblte_bits_2_value(ptr, 1)) { + ie->n_octets = liblte_bits_2_value(ptr, 7); + } else { + if(0 == liblte_bits_2_value(ptr, 1)) { + ie->n_octets = liblte_bits_2_value(ptr, 14); + } else { + // FIXME: Unlikely to have more than 16K of octets + } + } + + // Octets + uint32_t i; + for(i=0;in_octets;i++) { + ie->buffer[i] = liblte_bits_2_value(ptr, 8); + } + err = LIBLTE_SUCCESS; + } + return err; +} + + +/******************************************************************************* +/* ProtocolIE RIMRoutingAddress CHOICE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_rimroutingaddress( + LIBLTE_S1AP_RIMROUTINGADDRESS_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("RIMRoutingAddress error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // Choice type + liblte_value_2_bits(ie->choice_type, ptr, 2); + + // Choice + if(ie->choice_type == LIBLTE_S1AP_RIMROUTINGADDRESS_CHOICE_GERAN_CELL_ID) { + if(liblte_s1ap_pack_geran_cell_id(&ie->choice.gERAN_Cell_ID, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(ie->choice_type == LIBLTE_S1AP_RIMROUTINGADDRESS_CHOICE_TARGETRNC_ID) { + if(liblte_s1ap_pack_targetrnc_id(&ie->choice.targetRNC_ID, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(ie->choice_type == LIBLTE_S1AP_RIMROUTINGADDRESS_CHOICE_EHRPD_SECTOR_ID) { + if(liblte_s1ap_pack_ehrpd_sector_id(&ie->choice.eHRPD_Sector_ID, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_rimroutingaddress( + uint8_t **ptr, + LIBLTE_S1AP_RIMROUTINGADDRESS_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("RIMRoutingAddress error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // Choice type + ie->choice_type = (LIBLTE_S1AP_RIMROUTINGADDRESS_CHOICE_ENUM)liblte_bits_2_value(ptr, 2); + + // Choice + if(ie->choice_type == LIBLTE_S1AP_RIMROUTINGADDRESS_CHOICE_GERAN_CELL_ID) { + if(liblte_s1ap_unpack_geran_cell_id(ptr, &ie->choice.gERAN_Cell_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(ie->choice_type == LIBLTE_S1AP_RIMROUTINGADDRESS_CHOICE_TARGETRNC_ID) { + if(liblte_s1ap_unpack_targetrnc_id(ptr, &ie->choice.targetRNC_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(ie->choice_type == LIBLTE_S1AP_RIMROUTINGADDRESS_CHOICE_EHRPD_SECTOR_ID) { + if(liblte_s1ap_unpack_ehrpd_sector_id(ptr, &ie->choice.eHRPD_Sector_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE ServedGUMMEIs DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:8 +LIBLTE_ERROR_ENUM liblte_s1ap_pack_servedgummeis( + LIBLTE_S1AP_SERVEDGUMMEIS_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + if(ie->len > 32) { + liblte_log_print("ServedGUMMEIs pack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_ENCODE_FAIL; + } + // Length + liblte_value_2_bits(ie->len-1, ptr, 3); + liblte_align_up_zero(ptr, 8); + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_pack_servedgummeisitem(&ie->buffer[i], ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_servedgummeis( + uint8_t **ptr, + LIBLTE_S1AP_SERVEDGUMMEIS_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Length + ie->len = liblte_bits_2_value(ptr, 3) + 1; + liblte_align_up(ptr, 8); + if(ie->len > 32) { + liblte_log_print("ServedGUMMEIs unpack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_DECODE_FAIL; + } + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_unpack_servedgummeisitem(ptr, &ie->buffer[i]) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE TAIBasedMDT SEQUENCE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_taibasedmdt( + LIBLTE_S1AP_TAIBASEDMDT_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("TAIBasedMDT error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + liblte_value_2_bits(ie->iE_Extensions_present?1:0, ptr, 1); + + if(liblte_s1ap_pack_tailistformdt(&ie->tAIListforMDT, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_pack_protocolextensioncontainer(&ie->iE_Extensions, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_taibasedmdt( + uint8_t **ptr, + LIBLTE_S1AP_TAIBASEDMDT_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("TAIBasedMDT error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + ie->iE_Extensions_present = liblte_bits_2_value(ptr, 1); + + if(liblte_s1ap_unpack_tailistformdt(ptr, &ie->tAIListforMDT) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_unpack_protocolextensioncontainer(ptr, &ie->iE_Extensions) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE TAI_Broadcast_Item SEQUENCE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_tai_broadcast_item( + LIBLTE_S1AP_TAI_BROADCAST_ITEM_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("TAI_Broadcast_Item error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + liblte_value_2_bits(ie->iE_Extensions_present?1:0, ptr, 1); + + if(liblte_s1ap_pack_tai(&ie->tAI, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(liblte_s1ap_pack_completedcellintai(&ie->completedCellinTAI, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_pack_protocolextensioncontainer(&ie->iE_Extensions, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_tai_broadcast_item( + uint8_t **ptr, + LIBLTE_S1AP_TAI_BROADCAST_ITEM_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("TAI_Broadcast_Item error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + ie->iE_Extensions_present = liblte_bits_2_value(ptr, 1); + + if(liblte_s1ap_unpack_tai(ptr, &ie->tAI) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(liblte_s1ap_unpack_completedcellintai(ptr, &ie->completedCellinTAI) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_unpack_protocolextensioncontainer(ptr, &ie->iE_Extensions) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE TargetID CHOICE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_targetid( + LIBLTE_S1AP_TARGETID_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("TargetID error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // Choice type + liblte_value_2_bits(ie->choice_type, ptr, 2); + + // Choice + if(ie->choice_type == LIBLTE_S1AP_TARGETID_CHOICE_TARGETENB_ID) { + if(liblte_s1ap_pack_targetenb_id(&ie->choice.targeteNB_ID, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(ie->choice_type == LIBLTE_S1AP_TARGETID_CHOICE_TARGETRNC_ID) { + if(liblte_s1ap_pack_targetrnc_id(&ie->choice.targetRNC_ID, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(ie->choice_type == LIBLTE_S1AP_TARGETID_CHOICE_CGI) { + if(liblte_s1ap_pack_cgi(&ie->choice.cGI, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_targetid( + uint8_t **ptr, + LIBLTE_S1AP_TARGETID_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("TargetID error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // Choice type + ie->choice_type = (LIBLTE_S1AP_TARGETID_CHOICE_ENUM)liblte_bits_2_value(ptr, 2); + + // Choice + if(ie->choice_type == LIBLTE_S1AP_TARGETID_CHOICE_TARGETENB_ID) { + if(liblte_s1ap_unpack_targetenb_id(ptr, &ie->choice.targeteNB_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(ie->choice_type == LIBLTE_S1AP_TARGETID_CHOICE_TARGETRNC_ID) { + if(liblte_s1ap_unpack_targetrnc_id(ptr, &ie->choice.targetRNC_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(ie->choice_type == LIBLTE_S1AP_TARGETID_CHOICE_CGI) { + if(liblte_s1ap_unpack_cgi(ptr, &ie->choice.cGI) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE WarningAreaList CHOICE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_warningarealist( + LIBLTE_S1AP_WARNINGAREALIST_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("WarningAreaList error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // Choice type + liblte_value_2_bits(ie->choice_type, ptr, 2); + + // Choice + if(ie->choice_type == LIBLTE_S1AP_WARNINGAREALIST_CHOICE_CELLIDLIST) { + if(liblte_s1ap_pack_ecgilist(&ie->choice.cellIDList, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(ie->choice_type == LIBLTE_S1AP_WARNINGAREALIST_CHOICE_TRACKINGAREALISTFORWARNING) { + if(liblte_s1ap_pack_tailistforwarning(&ie->choice.trackingAreaListforWarning, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(ie->choice_type == LIBLTE_S1AP_WARNINGAREALIST_CHOICE_EMERGENCYAREAIDLIST) { + if(liblte_s1ap_pack_emergencyareaidlist(&ie->choice.emergencyAreaIDList, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_warningarealist( + uint8_t **ptr, + LIBLTE_S1AP_WARNINGAREALIST_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("WarningAreaList error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // Choice type + ie->choice_type = (LIBLTE_S1AP_WARNINGAREALIST_CHOICE_ENUM)liblte_bits_2_value(ptr, 2); + + // Choice + if(ie->choice_type == LIBLTE_S1AP_WARNINGAREALIST_CHOICE_CELLIDLIST) { + if(liblte_s1ap_unpack_ecgilist(ptr, &ie->choice.cellIDList) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(ie->choice_type == LIBLTE_S1AP_WARNINGAREALIST_CHOICE_TRACKINGAREALISTFORWARNING) { + if(liblte_s1ap_unpack_tailistforwarning(ptr, &ie->choice.trackingAreaListforWarning) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(ie->choice_type == LIBLTE_S1AP_WARNINGAREALIST_CHOICE_EMERGENCYAREAIDLIST) { + if(liblte_s1ap_unpack_emergencyareaidlist(ptr, &ie->choice.emergencyAreaIDList) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE AreaScopeOfMDT CHOICE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_areascopeofmdt( + LIBLTE_S1AP_AREASCOPEOFMDT_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("AreaScopeOfMDT error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // Choice type + liblte_value_2_bits(ie->choice_type, ptr, 2); + + // Choice + if(ie->choice_type == LIBLTE_S1AP_AREASCOPEOFMDT_CHOICE_CELLBASED) { + if(liblte_s1ap_pack_cellbasedmdt(&ie->choice.cellBased, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(ie->choice_type == LIBLTE_S1AP_AREASCOPEOFMDT_CHOICE_TABASED) { + if(liblte_s1ap_pack_tabasedmdt(&ie->choice.tABased, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(ie->choice_type == LIBLTE_S1AP_AREASCOPEOFMDT_CHOICE_PLMNWIDE) { + } else if(ie->choice_type == LIBLTE_S1AP_AREASCOPEOFMDT_CHOICE_TAIBASED) { + if(liblte_s1ap_pack_taibasedmdt(&ie->choice.tAIBased, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_areascopeofmdt( + uint8_t **ptr, + LIBLTE_S1AP_AREASCOPEOFMDT_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("AreaScopeOfMDT error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // Choice type + ie->choice_type = (LIBLTE_S1AP_AREASCOPEOFMDT_CHOICE_ENUM)liblte_bits_2_value(ptr, 2); + + // Choice + if(ie->choice_type == LIBLTE_S1AP_AREASCOPEOFMDT_CHOICE_CELLBASED) { + if(liblte_s1ap_unpack_cellbasedmdt(ptr, &ie->choice.cellBased) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(ie->choice_type == LIBLTE_S1AP_AREASCOPEOFMDT_CHOICE_TABASED) { + if(liblte_s1ap_unpack_tabasedmdt(ptr, &ie->choice.tABased) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(ie->choice_type == LIBLTE_S1AP_AREASCOPEOFMDT_CHOICE_PLMNWIDE) { + } else if(ie->choice_type == LIBLTE_S1AP_AREASCOPEOFMDT_CHOICE_TAIBASED) { + if(liblte_s1ap_unpack_taibasedmdt(ptr, &ie->choice.tAIBased) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE CancelledCellinTAI DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:65535 +LIBLTE_ERROR_ENUM liblte_s1ap_pack_cancelledcellintai( + LIBLTE_S1AP_CANCELLEDCELLINTAI_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + if(ie->len > 32) { + liblte_log_print("CancelledCellinTAI pack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_ENCODE_FAIL; + } + // Length + liblte_value_2_bits(ie->len-1, ptr, 16); + liblte_align_up_zero(ptr, 8); + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_pack_cancelledcellintai_item(&ie->buffer[i], ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_cancelledcellintai( + uint8_t **ptr, + LIBLTE_S1AP_CANCELLEDCELLINTAI_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Length + ie->len = liblte_bits_2_value(ptr, 16) + 1; + liblte_align_up(ptr, 8); + if(ie->len > 32) { + liblte_log_print("CancelledCellinTAI unpack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_DECODE_FAIL; + } + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_unpack_cancelledcellintai_item(ptr, &ie->buffer[i]) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE CellType SEQUENCE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_celltype( + LIBLTE_S1AP_CELLTYPE_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("CellType error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + liblte_value_2_bits(ie->iE_Extensions_present?1:0, ptr, 1); + + if(liblte_s1ap_pack_cell_size(&ie->cell_Size, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_pack_protocolextensioncontainer(&ie->iE_Extensions, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_celltype( + uint8_t **ptr, + LIBLTE_S1AP_CELLTYPE_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("CellType error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + ie->iE_Extensions_present = liblte_bits_2_value(ptr, 1); + + if(liblte_s1ap_unpack_cell_size(ptr, &ie->cell_Size) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_unpack_protocolextensioncontainer(ptr, &ie->iE_Extensions) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE EmergencyAreaID_Cancelled DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:65535 +LIBLTE_ERROR_ENUM liblte_s1ap_pack_emergencyareaid_cancelled( + LIBLTE_S1AP_EMERGENCYAREAID_CANCELLED_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + if(ie->len > 32) { + liblte_log_print("EmergencyAreaID_Cancelled pack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_ENCODE_FAIL; + } + // Length + liblte_value_2_bits(ie->len-1, ptr, 16); + liblte_align_up_zero(ptr, 8); + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_pack_emergencyareaid_cancelled_item(&ie->buffer[i], ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_emergencyareaid_cancelled( + uint8_t **ptr, + LIBLTE_S1AP_EMERGENCYAREAID_CANCELLED_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Length + ie->len = liblte_bits_2_value(ptr, 16) + 1; + liblte_align_up(ptr, 8); + if(ie->len > 32) { + liblte_log_print("EmergencyAreaID_Cancelled unpack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_DECODE_FAIL; + } + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_unpack_emergencyareaid_cancelled_item(ptr, &ie->buffer[i]) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE GUMMEIList DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:256 +LIBLTE_ERROR_ENUM liblte_s1ap_pack_gummeilist( + LIBLTE_S1AP_GUMMEILIST_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + if(ie->len > 32) { + liblte_log_print("GUMMEIList pack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_ENCODE_FAIL; + } + // Length + liblte_value_2_bits(ie->len-1, ptr, 8); + liblte_align_up_zero(ptr, 8); + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_pack_gummei(&ie->buffer[i], ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_gummeilist( + uint8_t **ptr, + LIBLTE_S1AP_GUMMEILIST_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Length + ie->len = liblte_bits_2_value(ptr, 8) + 1; + liblte_align_up(ptr, 8); + if(ie->len > 32) { + liblte_log_print("GUMMEIList unpack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_DECODE_FAIL; + } + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_unpack_gummei(ptr, &ie->buffer[i]) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE E_RABLevelQoSParameters SEQUENCE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rablevelqosparameters( + LIBLTE_S1AP_E_RABLEVELQOSPARAMETERS_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("E_RABLevelQoSParameters error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + liblte_value_2_bits(ie->gbrQosInformation_present?1:0, ptr, 1); + liblte_value_2_bits(ie->iE_Extensions_present?1:0, ptr, 1); + + if(liblte_s1ap_pack_qci(&ie->qCI, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(liblte_s1ap_pack_allocationandretentionpriority(&ie->allocationRetentionPriority, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(ie->gbrQosInformation_present) { + if(liblte_s1ap_pack_gbr_qosinformation(&ie->gbrQosInformation, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_pack_protocolextensioncontainer(&ie->iE_Extensions, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rablevelqosparameters( + uint8_t **ptr, + LIBLTE_S1AP_E_RABLEVELQOSPARAMETERS_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("E_RABLevelQoSParameters error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + ie->gbrQosInformation_present = liblte_bits_2_value(ptr, 1); + ie->iE_Extensions_present = liblte_bits_2_value(ptr, 1); + + if(liblte_s1ap_unpack_qci(ptr, &ie->qCI) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(liblte_s1ap_unpack_allocationandretentionpriority(ptr, &ie->allocationRetentionPriority) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(ie->gbrQosInformation_present) { + if(liblte_s1ap_unpack_gbr_qosinformation(ptr, &ie->gbrQosInformation) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_unpack_protocolextensioncontainer(ptr, &ie->iE_Extensions) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE LastVisitedEUTRANCellInformation SEQUENCE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_lastvisitedeutrancellinformation( + LIBLTE_S1AP_LASTVISITEDEUTRANCELLINFORMATION_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("LastVisitedEUTRANCellInformation error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + liblte_value_2_bits(ie->iE_Extensions_present?1:0, ptr, 1); + + if(liblte_s1ap_pack_eutran_cgi(&ie->global_Cell_ID, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(liblte_s1ap_pack_celltype(&ie->cellType, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(liblte_s1ap_pack_time_ue_stayedincell(&ie->time_UE_StayedInCell, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_pack_protocolextensioncontainer(&ie->iE_Extensions, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_lastvisitedeutrancellinformation( + uint8_t **ptr, + LIBLTE_S1AP_LASTVISITEDEUTRANCELLINFORMATION_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("LastVisitedEUTRANCellInformation error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + ie->iE_Extensions_present = liblte_bits_2_value(ptr, 1); + + if(liblte_s1ap_unpack_eutran_cgi(ptr, &ie->global_Cell_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(liblte_s1ap_unpack_celltype(ptr, &ie->cellType) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(liblte_s1ap_unpack_time_ue_stayedincell(ptr, &ie->time_UE_StayedInCell) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_unpack_protocolextensioncontainer(ptr, &ie->iE_Extensions) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE RIMTransfer SEQUENCE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_rimtransfer( + LIBLTE_S1AP_RIMTRANSFER_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("RIMTransfer error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + liblte_value_2_bits(ie->rIMRoutingAddress_present?1:0, ptr, 1); + liblte_value_2_bits(ie->iE_Extensions_present?1:0, ptr, 1); + + if(liblte_s1ap_pack_riminformation(&ie->rIMInformation, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(ie->rIMRoutingAddress_present) { + if(liblte_s1ap_pack_rimroutingaddress(&ie->rIMRoutingAddress, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_pack_protocolextensioncontainer(&ie->iE_Extensions, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_rimtransfer( + uint8_t **ptr, + LIBLTE_S1AP_RIMTRANSFER_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("RIMTransfer error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + ie->rIMRoutingAddress_present = liblte_bits_2_value(ptr, 1); + ie->iE_Extensions_present = liblte_bits_2_value(ptr, 1); + + if(liblte_s1ap_unpack_riminformation(ptr, &ie->rIMInformation) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(ie->rIMRoutingAddress_present) { + if(liblte_s1ap_unpack_rimroutingaddress(ptr, &ie->rIMRoutingAddress) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_unpack_protocolextensioncontainer(ptr, &ie->iE_Extensions) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE SupportedTAs DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:256 +LIBLTE_ERROR_ENUM liblte_s1ap_pack_supportedtas( + LIBLTE_S1AP_SUPPORTEDTAS_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + if(ie->len > 32) { + liblte_log_print("SupportedTAs pack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_ENCODE_FAIL; + } + // Length + liblte_value_2_bits(ie->len-1, ptr, 8); + liblte_align_up_zero(ptr, 8); + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_pack_supportedtas_item(&ie->buffer[i], ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_supportedtas( + uint8_t **ptr, + LIBLTE_S1AP_SUPPORTEDTAS_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Length + ie->len = liblte_bits_2_value(ptr, 8) + 1; + liblte_align_up(ptr, 8); + if(ie->len > 32) { + liblte_log_print("SupportedTAs unpack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_DECODE_FAIL; + } + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_unpack_supportedtas_item(ptr, &ie->buffer[i]) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE TAI_Cancelled_Item SEQUENCE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_tai_cancelled_item( + LIBLTE_S1AP_TAI_CANCELLED_ITEM_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("TAI_Cancelled_Item error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + liblte_value_2_bits(ie->iE_Extensions_present?1:0, ptr, 1); + + if(liblte_s1ap_pack_tai(&ie->tAI, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(liblte_s1ap_pack_cancelledcellintai(&ie->cancelledCellinTAI, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_pack_protocolextensioncontainer(&ie->iE_Extensions, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_tai_cancelled_item( + uint8_t **ptr, + LIBLTE_S1AP_TAI_CANCELLED_ITEM_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("TAI_Cancelled_Item error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + ie->iE_Extensions_present = liblte_bits_2_value(ptr, 1); + + if(liblte_s1ap_unpack_tai(ptr, &ie->tAI) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(liblte_s1ap_unpack_cancelledcellintai(ptr, &ie->cancelledCellinTAI) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_unpack_protocolextensioncontainer(ptr, &ie->iE_Extensions) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE X2TNLConfigurationInfo SEQUENCE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_x2tnlconfigurationinfo( + LIBLTE_S1AP_X2TNLCONFIGURATIONINFO_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("X2TNLConfigurationInfo error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + liblte_value_2_bits(ie->iE_Extensions_present?1:0, ptr, 1); + + if(liblte_s1ap_pack_enbx2tlas(&ie->eNBX2TransportLayerAddresses, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_pack_protocolextensioncontainer(&ie->iE_Extensions, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_x2tnlconfigurationinfo( + uint8_t **ptr, + LIBLTE_S1AP_X2TNLCONFIGURATIONINFO_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("X2TNLConfigurationInfo error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + ie->iE_Extensions_present = liblte_bits_2_value(ptr, 1); + + if(liblte_s1ap_unpack_enbx2tlas(ptr, &ie->eNBX2TransportLayerAddresses) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_unpack_protocolextensioncontainer(ptr, &ie->iE_Extensions) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Container List Bearers_SubjectToStatusTransferList DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:256 +LIBLTE_ERROR_ENUM liblte_s1ap_pack_bearers_subjecttostatustransferlist( + LIBLTE_S1AP_BEARERS_SUBJECTTOSTATUSTRANSFERLIST_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + if(ie->len > 32) { + liblte_log_print("Bearers_SubjectToStatusTransferList pack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_ENCODE_FAIL; + } + // Length + liblte_value_2_bits(ie->len-1, ptr, 8); + liblte_align_up_zero(ptr, 8); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + uint32_t i; + for(i=0;ilen;i++) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_bearers_subjecttostatustransfer_item(&ie->buffer[i], &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_BEARERS_SUBJECTTOSTATUSTRANSFER_ITEM, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_bearers_subjecttostatustransferlist( + uint8_t **ptr, + LIBLTE_S1AP_BEARERS_SUBJECTTOSTATUSTRANSFERLIST_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + + // Length + ie->len = liblte_bits_2_value(ptr, 8) + 1; + liblte_align_up(ptr, 8); + if(ie->len > 32) { + liblte_log_print("Bearers_SubjectToStatusTransferList unpack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_DECODE_FAIL; + } + + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_unpack_protocolie_header(ptr, &ie_id, &crit, &len) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + if(LIBLTE_S1AP_IE_ID_BEARERS_SUBJECTTOSTATUSTRANSFER_ITEM != ie_id) { + return LIBLTE_ERROR_DECODE_FAIL; + } + if(liblte_s1ap_unpack_bearers_subjecttostatustransfer_item(ptr, &ie->buffer[i]) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE CellID_Cancelled DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:65535 +LIBLTE_ERROR_ENUM liblte_s1ap_pack_cellid_cancelled( + LIBLTE_S1AP_CELLID_CANCELLED_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + if(ie->len > 32) { + liblte_log_print("CellID_Cancelled pack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_ENCODE_FAIL; + } + // Length + liblte_value_2_bits(ie->len-1, ptr, 16); + liblte_align_up_zero(ptr, 8); + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_pack_cellid_cancelled_item(&ie->buffer[i], ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_cellid_cancelled( + uint8_t **ptr, + LIBLTE_S1AP_CELLID_CANCELLED_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Length + ie->len = liblte_bits_2_value(ptr, 16) + 1; + liblte_align_up(ptr, 8); + if(ie->len > 32) { + liblte_log_print("CellID_Cancelled unpack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_DECODE_FAIL; + } + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_unpack_cellid_cancelled_item(ptr, &ie->buffer[i]) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE CompletedCellinEAI DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:65535 +LIBLTE_ERROR_ENUM liblte_s1ap_pack_completedcellineai( + LIBLTE_S1AP_COMPLETEDCELLINEAI_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + if(ie->len > 32) { + liblte_log_print("CompletedCellinEAI pack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_ENCODE_FAIL; + } + // Length + liblte_value_2_bits(ie->len-1, ptr, 16); + liblte_align_up_zero(ptr, 8); + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_pack_completedcellineai_item(&ie->buffer[i], ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_completedcellineai( + uint8_t **ptr, + LIBLTE_S1AP_COMPLETEDCELLINEAI_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Length + ie->len = liblte_bits_2_value(ptr, 16) + 1; + liblte_align_up(ptr, 8); + if(ie->len > 32) { + liblte_log_print("CompletedCellinEAI unpack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_DECODE_FAIL; + } + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_unpack_completedcellineai_item(ptr, &ie->buffer[i]) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE HandoverRestrictionList SEQUENCE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_handoverrestrictionlist( + LIBLTE_S1AP_HANDOVERRESTRICTIONLIST_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("HandoverRestrictionList error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + liblte_value_2_bits(ie->equivalentPLMNs_present?1:0, ptr, 1); + liblte_value_2_bits(ie->forbiddenTAs_present?1:0, ptr, 1); + liblte_value_2_bits(ie->forbiddenLAs_present?1:0, ptr, 1); + liblte_value_2_bits(ie->forbiddenInterRATs_present?1:0, ptr, 1); + liblte_value_2_bits(ie->iE_Extensions_present?1:0, ptr, 1); + + if(liblte_s1ap_pack_tbcd_string(&ie->servingPLMN, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(ie->equivalentPLMNs_present) { + if(liblte_s1ap_pack_eplmns(&ie->equivalentPLMNs, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + + if(ie->forbiddenTAs_present) { + if(liblte_s1ap_pack_forbiddentas(&ie->forbiddenTAs, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + + if(ie->forbiddenLAs_present) { + if(liblte_s1ap_pack_forbiddenlas(&ie->forbiddenLAs, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + + if(ie->forbiddenInterRATs_present) { + if(liblte_s1ap_pack_forbiddeninterrats(&ie->forbiddenInterRATs, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_pack_protocolextensioncontainer(&ie->iE_Extensions, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_handoverrestrictionlist( + uint8_t **ptr, + LIBLTE_S1AP_HANDOVERRESTRICTIONLIST_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("HandoverRestrictionList error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + ie->equivalentPLMNs_present = liblte_bits_2_value(ptr, 1); + ie->forbiddenTAs_present = liblte_bits_2_value(ptr, 1); + ie->forbiddenLAs_present = liblte_bits_2_value(ptr, 1); + ie->forbiddenInterRATs_present = liblte_bits_2_value(ptr, 1); + ie->iE_Extensions_present = liblte_bits_2_value(ptr, 1); + + if(liblte_s1ap_unpack_tbcd_string(ptr, &ie->servingPLMN) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(ie->equivalentPLMNs_present) { + if(liblte_s1ap_unpack_eplmns(ptr, &ie->equivalentPLMNs) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + + if(ie->forbiddenTAs_present) { + if(liblte_s1ap_unpack_forbiddentas(ptr, &ie->forbiddenTAs) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + + if(ie->forbiddenLAs_present) { + if(liblte_s1ap_unpack_forbiddenlas(ptr, &ie->forbiddenLAs) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + + if(ie->forbiddenInterRATs_present) { + if(liblte_s1ap_unpack_forbiddeninterrats(ptr, &ie->forbiddenInterRATs) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_unpack_protocolextensioncontainer(ptr, &ie->iE_Extensions) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE LastVisitedCell_Item CHOICE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_lastvisitedcell_item( + LIBLTE_S1AP_LASTVISITEDCELL_ITEM_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("LastVisitedCell_Item error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // Choice type + liblte_value_2_bits(ie->choice_type, ptr, 2); + + // Choice + if(ie->choice_type == LIBLTE_S1AP_LASTVISITEDCELL_ITEM_CHOICE_E_UTRAN_CELL) { + if(liblte_s1ap_pack_lastvisitedeutrancellinformation(&ie->choice.e_UTRAN_Cell, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(ie->choice_type == LIBLTE_S1AP_LASTVISITEDCELL_ITEM_CHOICE_UTRAN_CELL) { + if(liblte_s1ap_pack_lastvisitedutrancellinformation(&ie->choice.uTRAN_Cell, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(ie->choice_type == LIBLTE_S1AP_LASTVISITEDCELL_ITEM_CHOICE_GERAN_CELL) { + if(liblte_s1ap_pack_lastvisitedgerancellinformation(&ie->choice.gERAN_Cell, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_lastvisitedcell_item( + uint8_t **ptr, + LIBLTE_S1AP_LASTVISITEDCELL_ITEM_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("LastVisitedCell_Item error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // Choice type + ie->choice_type = (LIBLTE_S1AP_LASTVISITEDCELL_ITEM_CHOICE_ENUM)liblte_bits_2_value(ptr, 2); + + // Choice + if(ie->choice_type == LIBLTE_S1AP_LASTVISITEDCELL_ITEM_CHOICE_E_UTRAN_CELL) { + if(liblte_s1ap_unpack_lastvisitedeutrancellinformation(ptr, &ie->choice.e_UTRAN_Cell) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(ie->choice_type == LIBLTE_S1AP_LASTVISITEDCELL_ITEM_CHOICE_UTRAN_CELL) { + if(liblte_s1ap_unpack_lastvisitedutrancellinformation(ptr, &ie->choice.uTRAN_Cell) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(ie->choice_type == LIBLTE_S1AP_LASTVISITEDCELL_ITEM_CHOICE_GERAN_CELL) { + if(liblte_s1ap_unpack_lastvisitedgerancellinformation(ptr, &ie->choice.gERAN_Cell) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE SONInformationReply SEQUENCE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_soninformationreply( + LIBLTE_S1AP_SONINFORMATIONREPLY_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("SONInformationReply error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + liblte_value_2_bits(ie->x2TNLConfigurationInfo_present?1:0, ptr, 1); + liblte_value_2_bits(ie->iE_Extensions_present?1:0, ptr, 1); + + if(ie->x2TNLConfigurationInfo_present) { + if(liblte_s1ap_pack_x2tnlconfigurationinfo(&ie->x2TNLConfigurationInfo, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_pack_protocolextensioncontainer(&ie->iE_Extensions, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_soninformationreply( + uint8_t **ptr, + LIBLTE_S1AP_SONINFORMATIONREPLY_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("SONInformationReply error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + ie->x2TNLConfigurationInfo_present = liblte_bits_2_value(ptr, 1); + ie->iE_Extensions_present = liblte_bits_2_value(ptr, 1); + + if(ie->x2TNLConfigurationInfo_present) { + if(liblte_s1ap_unpack_x2tnlconfigurationinfo(ptr, &ie->x2TNLConfigurationInfo) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_unpack_protocolextensioncontainer(ptr, &ie->iE_Extensions) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE TAI_Broadcast DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:65535 +LIBLTE_ERROR_ENUM liblte_s1ap_pack_tai_broadcast( + LIBLTE_S1AP_TAI_BROADCAST_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + if(ie->len > 32) { + liblte_log_print("TAI_Broadcast pack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_ENCODE_FAIL; + } + // Length + liblte_value_2_bits(ie->len-1, ptr, 16); + liblte_align_up_zero(ptr, 8); + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_pack_tai_broadcast_item(&ie->buffer[i], ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_tai_broadcast( + uint8_t **ptr, + LIBLTE_S1AP_TAI_BROADCAST_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Length + ie->len = liblte_bits_2_value(ptr, 16) + 1; + liblte_align_up(ptr, 8); + if(ie->len > 32) { + liblte_log_print("TAI_Broadcast unpack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_DECODE_FAIL; + } + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_unpack_tai_broadcast_item(ptr, &ie->buffer[i]) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE TimeToWait ENUMERATED +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_timetowait( + LIBLTE_S1AP_TIMETOWAIT_ENUM_EXT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("TimeToWait error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // Enum + liblte_value_2_bits(ie->e, ptr, 3); + liblte_align_up_zero(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_timetowait( + uint8_t **ptr, + LIBLTE_S1AP_TIMETOWAIT_ENUM_EXT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("TimeToWait error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // Enum + ie->e = (LIBLTE_S1AP_TIMETOWAIT_ENUM)liblte_bits_2_value(ptr, 3); + liblte_align_up(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE UE_HistoryInformation DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:16 +LIBLTE_ERROR_ENUM liblte_s1ap_pack_ue_historyinformation( + LIBLTE_S1AP_UE_HISTORYINFORMATION_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + if(ie->len > 32) { + liblte_log_print("UE_HistoryInformation pack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_ENCODE_FAIL; + } + // Length + liblte_value_2_bits(ie->len-1, ptr, 4); + liblte_align_up_zero(ptr, 8); + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_pack_lastvisitedcell_item(&ie->buffer[i], ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_ue_historyinformation( + uint8_t **ptr, + LIBLTE_S1AP_UE_HISTORYINFORMATION_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Length + ie->len = liblte_bits_2_value(ptr, 4) + 1; + liblte_align_up(ptr, 8); + if(ie->len > 32) { + liblte_log_print("UE_HistoryInformation unpack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_DECODE_FAIL; + } + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_unpack_lastvisitedcell_item(ptr, &ie->buffer[i]) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE CriticalityDiagnostics SEQUENCE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_criticalitydiagnostics( + LIBLTE_S1AP_CRITICALITYDIAGNOSTICS_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("CriticalityDiagnostics error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + liblte_value_2_bits(ie->procedureCode_present?1:0, ptr, 1); + liblte_value_2_bits(ie->triggeringMessage_present?1:0, ptr, 1); + liblte_value_2_bits(ie->procedureCriticality_present?1:0, ptr, 1); + liblte_value_2_bits(ie->iEsCriticalityDiagnostics_present?1:0, ptr, 1); + liblte_value_2_bits(ie->iE_Extensions_present?1:0, ptr, 1); + + if(ie->procedureCode_present) { + if(liblte_s1ap_pack_procedurecode(&ie->procedureCode, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + + if(ie->triggeringMessage_present) { + // Enum - ie->triggeringMessage + liblte_value_2_bits(ie->triggeringMessage, ptr, 2); + } + + if(ie->procedureCriticality_present) { + // Enum - ie->procedureCriticality + liblte_value_2_bits(ie->procedureCriticality, ptr, 2); + } + + if(ie->iEsCriticalityDiagnostics_present) { + if(liblte_s1ap_pack_criticalitydiagnostics_ie_list(&ie->iEsCriticalityDiagnostics, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_pack_protocolextensioncontainer(&ie->iE_Extensions, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_criticalitydiagnostics( + uint8_t **ptr, + LIBLTE_S1AP_CRITICALITYDIAGNOSTICS_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("CriticalityDiagnostics error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + ie->procedureCode_present = liblte_bits_2_value(ptr, 1); + ie->triggeringMessage_present = liblte_bits_2_value(ptr, 1); + ie->procedureCriticality_present = liblte_bits_2_value(ptr, 1); + ie->iEsCriticalityDiagnostics_present = liblte_bits_2_value(ptr, 1); + ie->iE_Extensions_present = liblte_bits_2_value(ptr, 1); + + if(ie->procedureCode_present) { + if(liblte_s1ap_unpack_procedurecode(ptr, &ie->procedureCode) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + + if(ie->triggeringMessage_present) { + // Enum - ie->triggeringMessage + ie->triggeringMessage = (LIBLTE_S1AP_TRIGGERINGMESSAGE_ENUM)liblte_bits_2_value(ptr, 2); + } + + if(ie->procedureCriticality_present) { + // Enum - ie->procedureCriticality + ie->procedureCriticality = (LIBLTE_S1AP_CRITICALITY_ENUM)liblte_bits_2_value(ptr, 2); + } + + if(ie->iEsCriticalityDiagnostics_present) { + if(liblte_s1ap_unpack_criticalitydiagnostics_ie_list(ptr, &ie->iEsCriticalityDiagnostics) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_unpack_protocolextensioncontainer(ptr, &ie->iE_Extensions) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE EmergencyAreaID_Broadcast_Item SEQUENCE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_emergencyareaid_broadcast_item( + LIBLTE_S1AP_EMERGENCYAREAID_BROADCAST_ITEM_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("EmergencyAreaID_Broadcast_Item error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + liblte_value_2_bits(ie->iE_Extensions_present?1:0, ptr, 1); + + if(liblte_s1ap_pack_emergencyareaid(&ie->emergencyAreaID, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(liblte_s1ap_pack_completedcellineai(&ie->completedCellinEAI, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_pack_protocolextensioncontainer(&ie->iE_Extensions, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_emergencyareaid_broadcast_item( + uint8_t **ptr, + LIBLTE_S1AP_EMERGENCYAREAID_BROADCAST_ITEM_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("EmergencyAreaID_Broadcast_Item error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + ie->iE_Extensions_present = liblte_bits_2_value(ptr, 1); + + if(liblte_s1ap_unpack_emergencyareaid(ptr, &ie->emergencyAreaID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(liblte_s1ap_unpack_completedcellineai(ptr, &ie->completedCellinEAI) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_unpack_protocolextensioncontainer(ptr, &ie->iE_Extensions) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE ImmediateMDT SEQUENCE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_immediatemdt( + LIBLTE_S1AP_IMMEDIATEMDT_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("ImmediateMDT error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + liblte_value_2_bits(ie->m1thresholdeventA2_present?1:0, ptr, 1); + liblte_value_2_bits(ie->m1periodicReporting_present?1:0, ptr, 1); + liblte_value_2_bits(ie->iE_Extensions_present?1:0, ptr, 1); + + if(liblte_s1ap_pack_measurementstoactivate(&ie->measurementsToActivate, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(liblte_s1ap_pack_m1reportingtrigger(&ie->m1reportingTrigger, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(ie->m1thresholdeventA2_present) { + if(liblte_s1ap_pack_m1thresholdeventa2(&ie->m1thresholdeventA2, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + + if(ie->m1periodicReporting_present) { + if(liblte_s1ap_pack_m1periodicreporting(&ie->m1periodicReporting, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_pack_protocolextensioncontainer(&ie->iE_Extensions, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_immediatemdt( + uint8_t **ptr, + LIBLTE_S1AP_IMMEDIATEMDT_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("ImmediateMDT error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + ie->m1thresholdeventA2_present = liblte_bits_2_value(ptr, 1); + ie->m1periodicReporting_present = liblte_bits_2_value(ptr, 1); + ie->iE_Extensions_present = liblte_bits_2_value(ptr, 1); + + if(liblte_s1ap_unpack_measurementstoactivate(ptr, &ie->measurementsToActivate) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(liblte_s1ap_unpack_m1reportingtrigger(ptr, &ie->m1reportingTrigger) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(ie->m1thresholdeventA2_present) { + if(liblte_s1ap_unpack_m1thresholdeventa2(ptr, &ie->m1thresholdeventA2) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + + if(ie->m1periodicReporting_present) { + if(liblte_s1ap_unpack_m1periodicreporting(ptr, &ie->m1periodicReporting) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_unpack_protocolextensioncontainer(ptr, &ie->iE_Extensions) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE MDTMode CHOICE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_mdtmode( + LIBLTE_S1AP_MDTMODE_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("MDTMode error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // Choice type + liblte_value_2_bits(ie->choice_type, ptr, 1); + + // Choice + if(ie->choice_type == LIBLTE_S1AP_MDTMODE_CHOICE_IMMEDIATEMDT) { + if(liblte_s1ap_pack_immediatemdt(&ie->choice.immediateMDT, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(ie->choice_type == LIBLTE_S1AP_MDTMODE_CHOICE_LOGGEDMDT) { + if(liblte_s1ap_pack_loggedmdt(&ie->choice.loggedMDT, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_mdtmode( + uint8_t **ptr, + LIBLTE_S1AP_MDTMODE_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("MDTMode error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // Choice type + ie->choice_type = (LIBLTE_S1AP_MDTMODE_CHOICE_ENUM)liblte_bits_2_value(ptr, 1); + + // Choice + if(ie->choice_type == LIBLTE_S1AP_MDTMODE_CHOICE_IMMEDIATEMDT) { + if(liblte_s1ap_unpack_immediatemdt(ptr, &ie->choice.immediateMDT) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(ie->choice_type == LIBLTE_S1AP_MDTMODE_CHOICE_LOGGEDMDT) { + if(liblte_s1ap_unpack_loggedmdt(ptr, &ie->choice.loggedMDT) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE SourceeNB_ToTargeteNB_TransparentContainer SEQUENCE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_sourceenb_totargetenb_transparentcontainer( + LIBLTE_S1AP_SOURCEENB_TOTARGETENB_TRANSPARENTCONTAINER_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("SourceeNB_ToTargeteNB_TransparentContainer error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + liblte_value_2_bits(ie->e_RABInformationList_present?1:0, ptr, 1); + liblte_value_2_bits(ie->subscriberProfileIDforRFP_present?1:0, ptr, 1); + liblte_value_2_bits(ie->iE_Extensions_present?1:0, ptr, 1); + + if(liblte_s1ap_pack_rrc_container(&ie->rRC_Container, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(ie->e_RABInformationList_present) { + if(liblte_s1ap_pack_e_rabinformationlist(&ie->e_RABInformationList, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + + if(liblte_s1ap_pack_eutran_cgi(&ie->targetCell_ID, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(ie->subscriberProfileIDforRFP_present) { + if(liblte_s1ap_pack_subscriberprofileidforrfp(&ie->subscriberProfileIDforRFP, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + + if(liblte_s1ap_pack_ue_historyinformation(&ie->uE_HistoryInformation, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_pack_protocolextensioncontainer(&ie->iE_Extensions, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_sourceenb_totargetenb_transparentcontainer( + uint8_t **ptr, + LIBLTE_S1AP_SOURCEENB_TOTARGETENB_TRANSPARENTCONTAINER_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("SourceeNB_ToTargeteNB_TransparentContainer error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + ie->e_RABInformationList_present = liblte_bits_2_value(ptr, 1); + ie->subscriberProfileIDforRFP_present = liblte_bits_2_value(ptr, 1); + ie->iE_Extensions_present = liblte_bits_2_value(ptr, 1); + + if(liblte_s1ap_unpack_rrc_container(ptr, &ie->rRC_Container) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(ie->e_RABInformationList_present) { + if(liblte_s1ap_unpack_e_rabinformationlist(ptr, &ie->e_RABInformationList) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + + if(liblte_s1ap_unpack_eutran_cgi(ptr, &ie->targetCell_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(ie->subscriberProfileIDforRFP_present) { + if(liblte_s1ap_unpack_subscriberprofileidforrfp(ptr, &ie->subscriberProfileIDforRFP) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + + if(liblte_s1ap_unpack_ue_historyinformation(ptr, &ie->uE_HistoryInformation) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_unpack_protocolextensioncontainer(ptr, &ie->iE_Extensions) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE EmergencyAreaID_Broadcast DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:65535 +LIBLTE_ERROR_ENUM liblte_s1ap_pack_emergencyareaid_broadcast( + LIBLTE_S1AP_EMERGENCYAREAID_BROADCAST_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + if(ie->len > 32) { + liblte_log_print("EmergencyAreaID_Broadcast pack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_ENCODE_FAIL; + } + // Length + liblte_value_2_bits(ie->len-1, ptr, 16); + liblte_align_up_zero(ptr, 8); + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_pack_emergencyareaid_broadcast_item(&ie->buffer[i], ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_emergencyareaid_broadcast( + uint8_t **ptr, + LIBLTE_S1AP_EMERGENCYAREAID_BROADCAST_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Length + ie->len = liblte_bits_2_value(ptr, 16) + 1; + liblte_align_up(ptr, 8); + if(ie->len > 32) { + liblte_log_print("EmergencyAreaID_Broadcast unpack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_DECODE_FAIL; + } + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_unpack_emergencyareaid_broadcast_item(ptr, &ie->buffer[i]) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE MDT_Configuration SEQUENCE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_mdt_configuration( + LIBLTE_S1AP_MDT_CONFIGURATION_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("MDT_Configuration error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + liblte_value_2_bits(ie->iE_Extensions_present?1:0, ptr, 1); + + if(liblte_s1ap_pack_mdt_activation(&ie->mdt_Activation, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(liblte_s1ap_pack_areascopeofmdt(&ie->areaScopeOfMDT, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(liblte_s1ap_pack_mdtmode(&ie->mDTMode, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_pack_protocolextensioncontainer(&ie->iE_Extensions, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_mdt_configuration( + uint8_t **ptr, + LIBLTE_S1AP_MDT_CONFIGURATION_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("MDT_Configuration error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + ie->iE_Extensions_present = liblte_bits_2_value(ptr, 1); + + if(liblte_s1ap_unpack_mdt_activation(ptr, &ie->mdt_Activation) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(liblte_s1ap_unpack_areascopeofmdt(ptr, &ie->areaScopeOfMDT) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(liblte_s1ap_unpack_mdtmode(ptr, &ie->mDTMode) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_unpack_protocolextensioncontainer(ptr, &ie->iE_Extensions) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE TAI_Cancelled DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:65535 +LIBLTE_ERROR_ENUM liblte_s1ap_pack_tai_cancelled( + LIBLTE_S1AP_TAI_CANCELLED_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + if(ie->len > 32) { + liblte_log_print("TAI_Cancelled pack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_ENCODE_FAIL; + } + // Length + liblte_value_2_bits(ie->len-1, ptr, 16); + liblte_align_up_zero(ptr, 8); + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_pack_tai_cancelled_item(&ie->buffer[i], ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_tai_cancelled( + uint8_t **ptr, + LIBLTE_S1AP_TAI_CANCELLED_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Length + ie->len = liblte_bits_2_value(ptr, 16) + 1; + liblte_align_up(ptr, 8); + if(ie->len > 32) { + liblte_log_print("TAI_Cancelled unpack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_DECODE_FAIL; + } + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_unpack_tai_cancelled_item(ptr, &ie->buffer[i]) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE BroadcastCancelledAreaList CHOICE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_broadcastcancelledarealist( + LIBLTE_S1AP_BROADCASTCANCELLEDAREALIST_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("BroadcastCancelledAreaList error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // Choice type + liblte_value_2_bits(ie->choice_type, ptr, 2); + + // Choice + if(ie->choice_type == LIBLTE_S1AP_BROADCASTCANCELLEDAREALIST_CHOICE_CELLID_CANCELLED) { + if(liblte_s1ap_pack_cellid_cancelled(&ie->choice.cellID_Cancelled, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(ie->choice_type == LIBLTE_S1AP_BROADCASTCANCELLEDAREALIST_CHOICE_TAI_CANCELLED) { + if(liblte_s1ap_pack_tai_cancelled(&ie->choice.tAI_Cancelled, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(ie->choice_type == LIBLTE_S1AP_BROADCASTCANCELLEDAREALIST_CHOICE_EMERGENCYAREAID_CANCELLED) { + if(liblte_s1ap_pack_emergencyareaid_cancelled(&ie->choice.emergencyAreaID_Cancelled, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_broadcastcancelledarealist( + uint8_t **ptr, + LIBLTE_S1AP_BROADCASTCANCELLEDAREALIST_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("BroadcastCancelledAreaList error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // Choice type + ie->choice_type = (LIBLTE_S1AP_BROADCASTCANCELLEDAREALIST_CHOICE_ENUM)liblte_bits_2_value(ptr, 2); + + // Choice + if(ie->choice_type == LIBLTE_S1AP_BROADCASTCANCELLEDAREALIST_CHOICE_CELLID_CANCELLED) { + if(liblte_s1ap_unpack_cellid_cancelled(ptr, &ie->choice.cellID_Cancelled) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(ie->choice_type == LIBLTE_S1AP_BROADCASTCANCELLEDAREALIST_CHOICE_TAI_CANCELLED) { + if(liblte_s1ap_unpack_tai_cancelled(ptr, &ie->choice.tAI_Cancelled) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(ie->choice_type == LIBLTE_S1AP_BROADCASTCANCELLEDAREALIST_CHOICE_EMERGENCYAREAID_CANCELLED) { + if(liblte_s1ap_unpack_emergencyareaid_cancelled(ptr, &ie->choice.emergencyAreaID_Cancelled) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE ENB_StatusTransfer_TransparentContainer SEQUENCE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_enb_statustransfer_transparentcontainer( + LIBLTE_S1AP_ENB_STATUSTRANSFER_TRANSPARENTCONTAINER_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("ENB_StatusTransfer_TransparentContainer error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + liblte_value_2_bits(ie->iE_Extensions_present?1:0, ptr, 1); + + if(liblte_s1ap_pack_bearers_subjecttostatustransferlist(&ie->bearers_SubjectToStatusTransferList, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_pack_protocolextensioncontainer(&ie->iE_Extensions, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_enb_statustransfer_transparentcontainer( + uint8_t **ptr, + LIBLTE_S1AP_ENB_STATUSTRANSFER_TRANSPARENTCONTAINER_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("ENB_StatusTransfer_TransparentContainer error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + ie->iE_Extensions_present = liblte_bits_2_value(ptr, 1); + + if(liblte_s1ap_unpack_bearers_subjecttostatustransferlist(ptr, &ie->bearers_SubjectToStatusTransferList) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_unpack_protocolextensioncontainer(ptr, &ie->iE_Extensions) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE TraceActivation SEQUENCE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_traceactivation( + LIBLTE_S1AP_TRACEACTIVATION_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("TraceActivation error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + liblte_value_2_bits(ie->iE_Extensions_present?1:0, ptr, 1); + + if(liblte_s1ap_pack_e_utran_trace_id(&ie->e_UTRAN_Trace_ID, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(liblte_s1ap_pack_interfacestotrace(&ie->interfacesToTrace, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(liblte_s1ap_pack_tracedepth(&ie->traceDepth, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(liblte_s1ap_pack_transportlayeraddress(&ie->traceCollectionEntityIPAddress, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_pack_protocolextensioncontainer(&ie->iE_Extensions, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_traceactivation( + uint8_t **ptr, + LIBLTE_S1AP_TRACEACTIVATION_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("TraceActivation error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + ie->iE_Extensions_present = liblte_bits_2_value(ptr, 1); + + if(liblte_s1ap_unpack_e_utran_trace_id(ptr, &ie->e_UTRAN_Trace_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(liblte_s1ap_unpack_interfacestotrace(ptr, &ie->interfacesToTrace) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(liblte_s1ap_unpack_tracedepth(ptr, &ie->traceDepth) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(liblte_s1ap_unpack_transportlayeraddress(ptr, &ie->traceCollectionEntityIPAddress) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_unpack_protocolextensioncontainer(ptr, &ie->iE_Extensions) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE BroadcastCompletedAreaList CHOICE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_broadcastcompletedarealist( + LIBLTE_S1AP_BROADCASTCOMPLETEDAREALIST_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("BroadcastCompletedAreaList error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // Choice type + liblte_value_2_bits(ie->choice_type, ptr, 2); + + // Choice + if(ie->choice_type == LIBLTE_S1AP_BROADCASTCOMPLETEDAREALIST_CHOICE_CELLID_BROADCAST) { + if(liblte_s1ap_pack_cellid_broadcast(&ie->choice.cellID_Broadcast, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(ie->choice_type == LIBLTE_S1AP_BROADCASTCOMPLETEDAREALIST_CHOICE_TAI_BROADCAST) { + if(liblte_s1ap_pack_tai_broadcast(&ie->choice.tAI_Broadcast, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(ie->choice_type == LIBLTE_S1AP_BROADCASTCOMPLETEDAREALIST_CHOICE_EMERGENCYAREAID_BROADCAST) { + if(liblte_s1ap_pack_emergencyareaid_broadcast(&ie->choice.emergencyAreaID_Broadcast, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_broadcastcompletedarealist( + uint8_t **ptr, + LIBLTE_S1AP_BROADCASTCOMPLETEDAREALIST_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("BroadcastCompletedAreaList error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // Choice type + ie->choice_type = (LIBLTE_S1AP_BROADCASTCOMPLETEDAREALIST_CHOICE_ENUM)liblte_bits_2_value(ptr, 2); + + // Choice + if(ie->choice_type == LIBLTE_S1AP_BROADCASTCOMPLETEDAREALIST_CHOICE_CELLID_BROADCAST) { + if(liblte_s1ap_unpack_cellid_broadcast(ptr, &ie->choice.cellID_Broadcast) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(ie->choice_type == LIBLTE_S1AP_BROADCASTCOMPLETEDAREALIST_CHOICE_TAI_BROADCAST) { + if(liblte_s1ap_unpack_tai_broadcast(ptr, &ie->choice.tAI_Broadcast) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(ie->choice_type == LIBLTE_S1AP_BROADCASTCOMPLETEDAREALIST_CHOICE_EMERGENCYAREAID_BROADCAST) { + if(liblte_s1ap_unpack_emergencyareaid_broadcast(ptr, &ie->choice.emergencyAreaID_Broadcast) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE SONInformation CHOICE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_soninformation( + LIBLTE_S1AP_SONINFORMATION_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("SONInformation error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // Choice type + liblte_value_2_bits(ie->choice_type, ptr, 1); + + // Choice + if(ie->choice_type == LIBLTE_S1AP_SONINFORMATION_CHOICE_SONINFORMATIONREQUEST) { + if(liblte_s1ap_pack_soninformationrequest(&ie->choice.sONInformationRequest, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(ie->choice_type == LIBLTE_S1AP_SONINFORMATION_CHOICE_SONINFORMATIONREPLY) { + if(liblte_s1ap_pack_soninformationreply(&ie->choice.sONInformationReply, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_soninformation( + uint8_t **ptr, + LIBLTE_S1AP_SONINFORMATION_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("SONInformation error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // Choice type + ie->choice_type = (LIBLTE_S1AP_SONINFORMATION_CHOICE_ENUM)liblte_bits_2_value(ptr, 1); + + // Choice + if(ie->choice_type == LIBLTE_S1AP_SONINFORMATION_CHOICE_SONINFORMATIONREQUEST) { + if(liblte_s1ap_unpack_soninformationrequest(ptr, &ie->choice.sONInformationRequest) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(ie->choice_type == LIBLTE_S1AP_SONINFORMATION_CHOICE_SONINFORMATIONREPLY) { + if(liblte_s1ap_unpack_soninformationreply(ptr, &ie->choice.sONInformationReply) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE SONConfigurationTransfer SEQUENCE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_sonconfigurationtransfer( + LIBLTE_S1AP_SONCONFIGURATIONTRANSFER_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("SONConfigurationTransfer error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + liblte_value_2_bits(ie->iE_Extensions_present?1:0, ptr, 1); + + if(liblte_s1ap_pack_targetenb_id(&ie->targeteNB_ID, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(liblte_s1ap_pack_sourceenb_id(&ie->sourceeNB_ID, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(liblte_s1ap_pack_soninformation(&ie->sONInformation, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_pack_protocolextensioncontainer(&ie->iE_Extensions, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_sonconfigurationtransfer( + uint8_t **ptr, + LIBLTE_S1AP_SONCONFIGURATIONTRANSFER_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("SONConfigurationTransfer error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + ie->iE_Extensions_present = liblte_bits_2_value(ptr, 1); + + if(liblte_s1ap_unpack_targetenb_id(ptr, &ie->targeteNB_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(liblte_s1ap_unpack_sourceenb_id(ptr, &ie->sourceeNB_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(liblte_s1ap_unpack_soninformation(ptr, &ie->sONInformation) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_unpack_protocolextensioncontainer(ptr, &ie->iE_Extensions) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE ResetAll ENUMERATED +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_resetall( + LIBLTE_S1AP_RESETALL_ENUM_EXT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("ResetAll error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // Enum + liblte_value_2_bits(ie->e, ptr, 0); + liblte_align_up_zero(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_resetall( + uint8_t **ptr, + LIBLTE_S1AP_RESETALL_ENUM_EXT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("ResetAll error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // Enum + ie->e = (LIBLTE_S1AP_RESETALL_ENUM)liblte_bits_2_value(ptr, 0); + liblte_align_up(ptr, 8); + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE Inter_SystemInformationTransferType CHOICE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_inter_systeminformationtransfertype( + LIBLTE_S1AP_INTER_SYSTEMINFORMATIONTRANSFERTYPE_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("Inter_SystemInformationTransferType error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // Choice type + liblte_value_2_bits(ie->choice_type, ptr, 0); + + // Choice + if(ie->choice_type == LIBLTE_S1AP_INTER_SYSTEMINFORMATIONTRANSFERTYPE_CHOICE_RIMTRANSFER) { + if(liblte_s1ap_pack_rimtransfer(&ie->choice.rIMTransfer, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_inter_systeminformationtransfertype( + uint8_t **ptr, + LIBLTE_S1AP_INTER_SYSTEMINFORMATIONTRANSFERTYPE_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("Inter_SystemInformationTransferType error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // Choice type + ie->choice_type = (LIBLTE_S1AP_INTER_SYSTEMINFORMATIONTRANSFERTYPE_CHOICE_ENUM)liblte_bits_2_value(ptr, 0); + + // Choice + if(ie->choice_type == LIBLTE_S1AP_INTER_SYSTEMINFORMATIONTRANSFERTYPE_CHOICE_RIMTRANSFER) { + if(liblte_s1ap_unpack_rimtransfer(ptr, &ie->choice.rIMTransfer) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE E_RAB_IE_ContainerPairList DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:256 +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rab_ie_containerpairlist( + LIBLTE_S1AP_E_RAB_IE_CONTAINERPAIRLIST_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + if(ie->len > 32) { + liblte_log_print("E_RAB_IE_ContainerPairList pack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_ENCODE_FAIL; + } + // Length + liblte_value_2_bits(ie->len-1, ptr, 8); + liblte_align_up_zero(ptr, 8); + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_pack_protocolie_containerpair(&ie->buffer[i], ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rab_ie_containerpairlist( + uint8_t **ptr, + LIBLTE_S1AP_E_RAB_IE_CONTAINERPAIRLIST_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Length + ie->len = liblte_bits_2_value(ptr, 8) + 1; + liblte_align_up(ptr, 8); + if(ie->len > 32) { + liblte_log_print("E_RAB_IE_ContainerPairList unpack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_DECODE_FAIL; + } + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_unpack_protocolie_containerpair(ptr, &ie->buffer[i]) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE E_RABDataForwardingItem SEQUENCE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabdataforwardingitem( + LIBLTE_S1AP_E_RABDATAFORWARDINGITEM_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("E_RABDataForwardingItem error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + liblte_value_2_bits(ie->dL_transportLayerAddress_present?1:0, ptr, 1); + liblte_value_2_bits(ie->dL_gTP_TEID_present?1:0, ptr, 1); + liblte_value_2_bits(ie->uL_TransportLayerAddress_present?1:0, ptr, 1); + liblte_value_2_bits(ie->uL_GTP_TEID_present?1:0, ptr, 1); + liblte_value_2_bits(ie->iE_Extensions_present?1:0, ptr, 1); + + if(liblte_s1ap_pack_e_rab_id(&ie->e_RAB_ID, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(ie->dL_transportLayerAddress_present) { + if(liblte_s1ap_pack_transportlayeraddress(&ie->dL_transportLayerAddress, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + + if(ie->dL_gTP_TEID_present) { + if(liblte_s1ap_pack_gtp_teid(&ie->dL_gTP_TEID, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + + if(ie->uL_TransportLayerAddress_present) { + if(liblte_s1ap_pack_transportlayeraddress(&ie->uL_TransportLayerAddress, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + + if(ie->uL_GTP_TEID_present) { + if(liblte_s1ap_pack_gtp_teid(&ie->uL_GTP_TEID, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_pack_protocolextensioncontainer(&ie->iE_Extensions, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabdataforwardingitem( + uint8_t **ptr, + LIBLTE_S1AP_E_RABDATAFORWARDINGITEM_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("E_RABDataForwardingItem error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + ie->dL_transportLayerAddress_present = liblte_bits_2_value(ptr, 1); + ie->dL_gTP_TEID_present = liblte_bits_2_value(ptr, 1); + ie->uL_TransportLayerAddress_present = liblte_bits_2_value(ptr, 1); + ie->uL_GTP_TEID_present = liblte_bits_2_value(ptr, 1); + ie->iE_Extensions_present = liblte_bits_2_value(ptr, 1); + + if(liblte_s1ap_unpack_e_rab_id(ptr, &ie->e_RAB_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(ie->dL_transportLayerAddress_present) { + if(liblte_s1ap_unpack_transportlayeraddress(ptr, &ie->dL_transportLayerAddress) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + + if(ie->dL_gTP_TEID_present) { + if(liblte_s1ap_unpack_gtp_teid(ptr, &ie->dL_gTP_TEID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + + if(ie->uL_TransportLayerAddress_present) { + if(liblte_s1ap_unpack_transportlayeraddress(ptr, &ie->uL_TransportLayerAddress) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + + if(ie->uL_GTP_TEID_present) { + if(liblte_s1ap_unpack_gtp_teid(ptr, &ie->uL_GTP_TEID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_unpack_protocolextensioncontainer(ptr, &ie->iE_Extensions) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE E_RABToBeSetupItemHOReq SEQUENCE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabtobesetupitemhoreq( + LIBLTE_S1AP_E_RABTOBESETUPITEMHOREQ_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("E_RABToBeSetupItemHOReq error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + liblte_value_2_bits(ie->iE_Extensions_present?1:0, ptr, 1); + + if(liblte_s1ap_pack_e_rab_id(&ie->e_RAB_ID, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(liblte_s1ap_pack_transportlayeraddress(&ie->transportLayerAddress, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(liblte_s1ap_pack_gtp_teid(&ie->gTP_TEID, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(liblte_s1ap_pack_e_rablevelqosparameters(&ie->e_RABlevelQosParameters, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_pack_protocolextensioncontainer(&ie->iE_Extensions, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabtobesetupitemhoreq( + uint8_t **ptr, + LIBLTE_S1AP_E_RABTOBESETUPITEMHOREQ_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("E_RABToBeSetupItemHOReq error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + ie->iE_Extensions_present = liblte_bits_2_value(ptr, 1); + + if(liblte_s1ap_unpack_e_rab_id(ptr, &ie->e_RAB_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(liblte_s1ap_unpack_transportlayeraddress(ptr, &ie->transportLayerAddress) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(liblte_s1ap_unpack_gtp_teid(ptr, &ie->gTP_TEID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(liblte_s1ap_unpack_e_rablevelqosparameters(ptr, &ie->e_RABlevelQosParameters) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_unpack_protocolextensioncontainer(ptr, &ie->iE_Extensions) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE E_RABAdmittedItem SEQUENCE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabadmitteditem( + LIBLTE_S1AP_E_RABADMITTEDITEM_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("E_RABAdmittedItem error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + liblte_value_2_bits(ie->dL_transportLayerAddress_present?1:0, ptr, 1); + liblte_value_2_bits(ie->dL_gTP_TEID_present?1:0, ptr, 1); + liblte_value_2_bits(ie->uL_TransportLayerAddress_present?1:0, ptr, 1); + liblte_value_2_bits(ie->uL_GTP_TEID_present?1:0, ptr, 1); + liblte_value_2_bits(ie->iE_Extensions_present?1:0, ptr, 1); + + if(liblte_s1ap_pack_e_rab_id(&ie->e_RAB_ID, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(liblte_s1ap_pack_transportlayeraddress(&ie->transportLayerAddress, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(liblte_s1ap_pack_gtp_teid(&ie->gTP_TEID, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(ie->dL_transportLayerAddress_present) { + if(liblte_s1ap_pack_transportlayeraddress(&ie->dL_transportLayerAddress, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + + if(ie->dL_gTP_TEID_present) { + if(liblte_s1ap_pack_gtp_teid(&ie->dL_gTP_TEID, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + + if(ie->uL_TransportLayerAddress_present) { + if(liblte_s1ap_pack_transportlayeraddress(&ie->uL_TransportLayerAddress, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + + if(ie->uL_GTP_TEID_present) { + if(liblte_s1ap_pack_gtp_teid(&ie->uL_GTP_TEID, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_pack_protocolextensioncontainer(&ie->iE_Extensions, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabadmitteditem( + uint8_t **ptr, + LIBLTE_S1AP_E_RABADMITTEDITEM_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("E_RABAdmittedItem error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + ie->dL_transportLayerAddress_present = liblte_bits_2_value(ptr, 1); + ie->dL_gTP_TEID_present = liblte_bits_2_value(ptr, 1); + ie->uL_TransportLayerAddress_present = liblte_bits_2_value(ptr, 1); + ie->uL_GTP_TEID_present = liblte_bits_2_value(ptr, 1); + ie->iE_Extensions_present = liblte_bits_2_value(ptr, 1); + + if(liblte_s1ap_unpack_e_rab_id(ptr, &ie->e_RAB_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(liblte_s1ap_unpack_transportlayeraddress(ptr, &ie->transportLayerAddress) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(liblte_s1ap_unpack_gtp_teid(ptr, &ie->gTP_TEID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(ie->dL_transportLayerAddress_present) { + if(liblte_s1ap_unpack_transportlayeraddress(ptr, &ie->dL_transportLayerAddress) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + + if(ie->dL_gTP_TEID_present) { + if(liblte_s1ap_unpack_gtp_teid(ptr, &ie->dL_gTP_TEID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + + if(ie->uL_TransportLayerAddress_present) { + if(liblte_s1ap_unpack_transportlayeraddress(ptr, &ie->uL_TransportLayerAddress) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + + if(ie->uL_GTP_TEID_present) { + if(liblte_s1ap_unpack_gtp_teid(ptr, &ie->uL_GTP_TEID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_unpack_protocolextensioncontainer(ptr, &ie->iE_Extensions) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE E_RABFailedToSetupItemHOReqAck SEQUENCE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabfailedtosetupitemhoreqack( + LIBLTE_S1AP_E_RABFAILEDTOSETUPITEMHOREQACK_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("E_RABFailedToSetupItemHOReqAck error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + liblte_value_2_bits(ie->iE_Extensions_present?1:0, ptr, 1); + + if(liblte_s1ap_pack_e_rab_id(&ie->e_RAB_ID, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(liblte_s1ap_pack_cause(&ie->cause, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_pack_protocolextensioncontainer(&ie->iE_Extensions, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabfailedtosetupitemhoreqack( + uint8_t **ptr, + LIBLTE_S1AP_E_RABFAILEDTOSETUPITEMHOREQACK_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("E_RABFailedToSetupItemHOReqAck error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + ie->iE_Extensions_present = liblte_bits_2_value(ptr, 1); + + if(liblte_s1ap_unpack_e_rab_id(ptr, &ie->e_RAB_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(liblte_s1ap_unpack_cause(ptr, &ie->cause) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_unpack_protocolextensioncontainer(ptr, &ie->iE_Extensions) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE E_RABToBeSwitchedDLItem SEQUENCE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabtobeswitcheddlitem( + LIBLTE_S1AP_E_RABTOBESWITCHEDDLITEM_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("E_RABToBeSwitchedDLItem error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + liblte_value_2_bits(ie->iE_Extensions_present?1:0, ptr, 1); + + if(liblte_s1ap_pack_e_rab_id(&ie->e_RAB_ID, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(liblte_s1ap_pack_transportlayeraddress(&ie->transportLayerAddress, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(liblte_s1ap_pack_gtp_teid(&ie->gTP_TEID, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_pack_protocolextensioncontainer(&ie->iE_Extensions, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabtobeswitcheddlitem( + uint8_t **ptr, + LIBLTE_S1AP_E_RABTOBESWITCHEDDLITEM_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("E_RABToBeSwitchedDLItem error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + ie->iE_Extensions_present = liblte_bits_2_value(ptr, 1); + + if(liblte_s1ap_unpack_e_rab_id(ptr, &ie->e_RAB_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(liblte_s1ap_unpack_transportlayeraddress(ptr, &ie->transportLayerAddress) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(liblte_s1ap_unpack_gtp_teid(ptr, &ie->gTP_TEID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_unpack_protocolextensioncontainer(ptr, &ie->iE_Extensions) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE E_RABToBeSwitchedULItem SEQUENCE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabtobeswitchedulitem( + LIBLTE_S1AP_E_RABTOBESWITCHEDULITEM_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("E_RABToBeSwitchedULItem error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + liblte_value_2_bits(ie->iE_Extensions_present?1:0, ptr, 1); + + if(liblte_s1ap_pack_e_rab_id(&ie->e_RAB_ID, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(liblte_s1ap_pack_transportlayeraddress(&ie->transportLayerAddress, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(liblte_s1ap_pack_gtp_teid(&ie->gTP_TEID, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_pack_protocolextensioncontainer(&ie->iE_Extensions, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabtobeswitchedulitem( + uint8_t **ptr, + LIBLTE_S1AP_E_RABTOBESWITCHEDULITEM_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("E_RABToBeSwitchedULItem error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + ie->iE_Extensions_present = liblte_bits_2_value(ptr, 1); + + if(liblte_s1ap_unpack_e_rab_id(ptr, &ie->e_RAB_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(liblte_s1ap_unpack_transportlayeraddress(ptr, &ie->transportLayerAddress) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(liblte_s1ap_unpack_gtp_teid(ptr, &ie->gTP_TEID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_unpack_protocolextensioncontainer(ptr, &ie->iE_Extensions) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE E_RABToBeSetupItemBearerSUReq SEQUENCE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabtobesetupitembearersureq( + LIBLTE_S1AP_E_RABTOBESETUPITEMBEARERSUREQ_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("E_RABToBeSetupItemBearerSUReq error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + liblte_value_2_bits(ie->iE_Extensions_present?1:0, ptr, 1); + + if(liblte_s1ap_pack_e_rab_id(&ie->e_RAB_ID, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(liblte_s1ap_pack_e_rablevelqosparameters(&ie->e_RABlevelQoSParameters, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(liblte_s1ap_pack_transportlayeraddress(&ie->transportLayerAddress, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(liblte_s1ap_pack_gtp_teid(&ie->gTP_TEID, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(liblte_s1ap_pack_nas_pdu(&ie->nAS_PDU, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_pack_protocolextensioncontainer(&ie->iE_Extensions, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabtobesetupitembearersureq( + uint8_t **ptr, + LIBLTE_S1AP_E_RABTOBESETUPITEMBEARERSUREQ_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("E_RABToBeSetupItemBearerSUReq error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + ie->iE_Extensions_present = liblte_bits_2_value(ptr, 1); + + if(liblte_s1ap_unpack_e_rab_id(ptr, &ie->e_RAB_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(liblte_s1ap_unpack_e_rablevelqosparameters(ptr, &ie->e_RABlevelQoSParameters) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(liblte_s1ap_unpack_transportlayeraddress(ptr, &ie->transportLayerAddress) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(liblte_s1ap_unpack_gtp_teid(ptr, &ie->gTP_TEID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(liblte_s1ap_unpack_nas_pdu(ptr, &ie->nAS_PDU) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_unpack_protocolextensioncontainer(ptr, &ie->iE_Extensions) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE E_RABSetupItemBearerSURes SEQUENCE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabsetupitembearersures( + LIBLTE_S1AP_E_RABSETUPITEMBEARERSURES_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("E_RABSetupItemBearerSURes error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + liblte_value_2_bits(ie->iE_Extensions_present?1:0, ptr, 1); + + if(liblte_s1ap_pack_e_rab_id(&ie->e_RAB_ID, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(liblte_s1ap_pack_transportlayeraddress(&ie->transportLayerAddress, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(liblte_s1ap_pack_gtp_teid(&ie->gTP_TEID, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_pack_protocolextensioncontainer(&ie->iE_Extensions, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabsetupitembearersures( + uint8_t **ptr, + LIBLTE_S1AP_E_RABSETUPITEMBEARERSURES_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("E_RABSetupItemBearerSURes error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + ie->iE_Extensions_present = liblte_bits_2_value(ptr, 1); + + if(liblte_s1ap_unpack_e_rab_id(ptr, &ie->e_RAB_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(liblte_s1ap_unpack_transportlayeraddress(ptr, &ie->transportLayerAddress) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(liblte_s1ap_unpack_gtp_teid(ptr, &ie->gTP_TEID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_unpack_protocolextensioncontainer(ptr, &ie->iE_Extensions) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE E_RABToBeModifiedItemBearerModReq SEQUENCE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabtobemodifieditembearermodreq( + LIBLTE_S1AP_E_RABTOBEMODIFIEDITEMBEARERMODREQ_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("E_RABToBeModifiedItemBearerModReq error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + liblte_value_2_bits(ie->iE_Extensions_present?1:0, ptr, 1); + + if(liblte_s1ap_pack_e_rab_id(&ie->e_RAB_ID, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(liblte_s1ap_pack_e_rablevelqosparameters(&ie->e_RABLevelQoSParameters, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(liblte_s1ap_pack_nas_pdu(&ie->nAS_PDU, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_pack_protocolextensioncontainer(&ie->iE_Extensions, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabtobemodifieditembearermodreq( + uint8_t **ptr, + LIBLTE_S1AP_E_RABTOBEMODIFIEDITEMBEARERMODREQ_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("E_RABToBeModifiedItemBearerModReq error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + ie->iE_Extensions_present = liblte_bits_2_value(ptr, 1); + + if(liblte_s1ap_unpack_e_rab_id(ptr, &ie->e_RAB_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(liblte_s1ap_unpack_e_rablevelqosparameters(ptr, &ie->e_RABLevelQoSParameters) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(liblte_s1ap_unpack_nas_pdu(ptr, &ie->nAS_PDU) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_unpack_protocolextensioncontainer(ptr, &ie->iE_Extensions) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE E_RABModifyItemBearerModRes SEQUENCE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabmodifyitembearermodres( + LIBLTE_S1AP_E_RABMODIFYITEMBEARERMODRES_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("E_RABModifyItemBearerModRes error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + liblte_value_2_bits(ie->iE_Extensions_present?1:0, ptr, 1); + + if(liblte_s1ap_pack_e_rab_id(&ie->e_RAB_ID, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_pack_protocolextensioncontainer(&ie->iE_Extensions, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabmodifyitembearermodres( + uint8_t **ptr, + LIBLTE_S1AP_E_RABMODIFYITEMBEARERMODRES_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("E_RABModifyItemBearerModRes error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + ie->iE_Extensions_present = liblte_bits_2_value(ptr, 1); + + if(liblte_s1ap_unpack_e_rab_id(ptr, &ie->e_RAB_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_unpack_protocolextensioncontainer(ptr, &ie->iE_Extensions) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE E_RABReleaseItemBearerRelComp SEQUENCE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabreleaseitembearerrelcomp( + LIBLTE_S1AP_E_RABRELEASEITEMBEARERRELCOMP_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("E_RABReleaseItemBearerRelComp error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + liblte_value_2_bits(ie->iE_Extensions_present?1:0, ptr, 1); + + if(liblte_s1ap_pack_e_rab_id(&ie->e_RAB_ID, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_pack_protocolextensioncontainer(&ie->iE_Extensions, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabreleaseitembearerrelcomp( + uint8_t **ptr, + LIBLTE_S1AP_E_RABRELEASEITEMBEARERRELCOMP_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("E_RABReleaseItemBearerRelComp error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + ie->iE_Extensions_present = liblte_bits_2_value(ptr, 1); + + if(liblte_s1ap_unpack_e_rab_id(ptr, &ie->e_RAB_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_unpack_protocolextensioncontainer(ptr, &ie->iE_Extensions) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE E_RABToBeSetupItemCtxtSUReq SEQUENCE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabtobesetupitemctxtsureq( + LIBLTE_S1AP_E_RABTOBESETUPITEMCTXTSUREQ_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("E_RABToBeSetupItemCtxtSUReq error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + liblte_value_2_bits(ie->nAS_PDU_present?1:0, ptr, 1); + liblte_value_2_bits(ie->iE_Extensions_present?1:0, ptr, 1); + + if(liblte_s1ap_pack_e_rab_id(&ie->e_RAB_ID, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(liblte_s1ap_pack_e_rablevelqosparameters(&ie->e_RABlevelQoSParameters, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(liblte_s1ap_pack_transportlayeraddress(&ie->transportLayerAddress, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(liblte_s1ap_pack_gtp_teid(&ie->gTP_TEID, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(ie->nAS_PDU_present) { + if(liblte_s1ap_pack_nas_pdu(&ie->nAS_PDU, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_pack_protocolextensioncontainer(&ie->iE_Extensions, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabtobesetupitemctxtsureq( + uint8_t **ptr, + LIBLTE_S1AP_E_RABTOBESETUPITEMCTXTSUREQ_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("E_RABToBeSetupItemCtxtSUReq error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + ie->nAS_PDU_present = liblte_bits_2_value(ptr, 1); + ie->iE_Extensions_present = liblte_bits_2_value(ptr, 1); + + if(liblte_s1ap_unpack_e_rab_id(ptr, &ie->e_RAB_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(liblte_s1ap_unpack_e_rablevelqosparameters(ptr, &ie->e_RABlevelQoSParameters) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(liblte_s1ap_unpack_transportlayeraddress(ptr, &ie->transportLayerAddress) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(liblte_s1ap_unpack_gtp_teid(ptr, &ie->gTP_TEID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(ie->nAS_PDU_present) { + if(liblte_s1ap_unpack_nas_pdu(ptr, &ie->nAS_PDU) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_unpack_protocolextensioncontainer(ptr, &ie->iE_Extensions) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE E_RABSetupItemCtxtSURes SEQUENCE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabsetupitemctxtsures( + LIBLTE_S1AP_E_RABSETUPITEMCTXTSURES_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("E_RABSetupItemCtxtSURes error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + liblte_value_2_bits(ie->iE_Extensions_present?1:0, ptr, 1); + + if(liblte_s1ap_pack_e_rab_id(&ie->e_RAB_ID, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(liblte_s1ap_pack_transportlayeraddress(&ie->transportLayerAddress, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(liblte_s1ap_pack_gtp_teid(&ie->gTP_TEID, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_pack_protocolextensioncontainer(&ie->iE_Extensions, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabsetupitemctxtsures( + uint8_t **ptr, + LIBLTE_S1AP_E_RABSETUPITEMCTXTSURES_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("E_RABSetupItemCtxtSURes error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + ie->iE_Extensions_present = liblte_bits_2_value(ptr, 1); + + if(liblte_s1ap_unpack_e_rab_id(ptr, &ie->e_RAB_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(liblte_s1ap_unpack_transportlayeraddress(ptr, &ie->transportLayerAddress) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(liblte_s1ap_unpack_gtp_teid(ptr, &ie->gTP_TEID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_unpack_protocolextensioncontainer(ptr, &ie->iE_Extensions) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE TAIItem SEQUENCE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_taiitem( + LIBLTE_S1AP_TAIITEM_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("TAIItem error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + liblte_value_2_bits(ie->iE_Extensions_present?1:0, ptr, 1); + + if(liblte_s1ap_pack_tai(&ie->tAI, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_pack_protocolextensioncontainer(&ie->iE_Extensions, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_taiitem( + uint8_t **ptr, + LIBLTE_S1AP_TAIITEM_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("TAIItem error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + ie->iE_Extensions_present = liblte_bits_2_value(ptr, 1); + + if(liblte_s1ap_unpack_tai(ptr, &ie->tAI) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + + if(ie->iE_Extensions_present) { + if(liblte_s1ap_unpack_protocolextensioncontainer(ptr, &ie->iE_Extensions) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Container List UE_associatedLogicalS1_ConnectionListRes DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:256 +LIBLTE_ERROR_ENUM liblte_s1ap_pack_ue_associatedlogicals1_connectionlistres( + LIBLTE_S1AP_UE_ASSOCIATEDLOGICALS1_CONNECTIONLISTRES_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + if(ie->len > 32) { + liblte_log_print("UE_associatedLogicalS1_ConnectionListRes pack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_ENCODE_FAIL; + } + // Length + liblte_value_2_bits(ie->len-1, ptr, 8); + liblte_align_up_zero(ptr, 8); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + uint32_t i; + for(i=0;ilen;i++) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_ue_associatedlogicals1_connectionitem(&ie->buffer[i], &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_UE_ASSOCIATEDLOGICALS1_CONNECTIONITEM, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_ue_associatedlogicals1_connectionlistres( + uint8_t **ptr, + LIBLTE_S1AP_UE_ASSOCIATEDLOGICALS1_CONNECTIONLISTRES_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + + // Length + ie->len = liblte_bits_2_value(ptr, 8) + 1; + liblte_align_up(ptr, 8); + if(ie->len > 32) { + liblte_log_print("UE_associatedLogicalS1_ConnectionListRes unpack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_DECODE_FAIL; + } + + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_unpack_protocolie_header(ptr, &ie_id, &crit, &len) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + if(LIBLTE_S1AP_IE_ID_UE_ASSOCIATEDLOGICALS1_CONNECTIONITEM != ie_id) { + return LIBLTE_ERROR_DECODE_FAIL; + } + if(liblte_s1ap_unpack_ue_associatedlogicals1_connectionitem(ptr, &ie->buffer[i]) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Container List UE_associatedLogicalS1_ConnectionListResAck DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:256 +LIBLTE_ERROR_ENUM liblte_s1ap_pack_ue_associatedlogicals1_connectionlistresack( + LIBLTE_S1AP_UE_ASSOCIATEDLOGICALS1_CONNECTIONLISTRESACK_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + if(ie->len > 32) { + liblte_log_print("UE_associatedLogicalS1_ConnectionListResAck pack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_ENCODE_FAIL; + } + // Length + liblte_value_2_bits(ie->len-1, ptr, 8); + liblte_align_up_zero(ptr, 8); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + uint32_t i; + for(i=0;ilen;i++) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_ue_associatedlogicals1_connectionitem(&ie->buffer[i], &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_UE_ASSOCIATEDLOGICALS1_CONNECTIONITEM, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_ue_associatedlogicals1_connectionlistresack( + uint8_t **ptr, + LIBLTE_S1AP_UE_ASSOCIATEDLOGICALS1_CONNECTIONLISTRESACK_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + + // Length + ie->len = liblte_bits_2_value(ptr, 8) + 1; + liblte_align_up(ptr, 8); + if(ie->len > 32) { + liblte_log_print("UE_associatedLogicalS1_ConnectionListResAck unpack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_DECODE_FAIL; + } + + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_unpack_protocolie_header(ptr, &ie_id, &crit, &len) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + if(LIBLTE_S1AP_IE_ID_UE_ASSOCIATEDLOGICALS1_CONNECTIONITEM != ie_id) { + return LIBLTE_ERROR_DECODE_FAIL; + } + if(liblte_s1ap_unpack_ue_associatedlogicals1_connectionitem(ptr, &ie->buffer[i]) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE PrivateMessage SEQUENCE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_privatemessage( + LIBLTE_S1AP_PRIVATEMESSAGE_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("PrivateMessage error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + + if(liblte_s1ap_pack_privateie_container(&ie->privateIEs, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_privatemessage( + uint8_t **ptr, + LIBLTE_S1AP_PRIVATEMESSAGE_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("PrivateMessage error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + + if(liblte_s1ap_unpack_privateie_container(ptr, &ie->privateIEs) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE ResetType CHOICE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_resettype( + LIBLTE_S1AP_RESETTYPE_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + liblte_value_2_bits(ie->ext?1:0, ptr, 1); + if(ie->ext) { + liblte_log_print("ResetType error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // Choice type + liblte_value_2_bits(ie->choice_type, ptr, 1); + + // Choice + if(ie->choice_type == LIBLTE_S1AP_RESETTYPE_CHOICE_S1_INTERFACE) { + if(liblte_s1ap_pack_resetall(&ie->choice.s1_Interface, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(ie->choice_type == LIBLTE_S1AP_RESETTYPE_CHOICE_PARTOFS1_INTERFACE) { + if(liblte_s1ap_pack_ue_associatedlogicals1_connectionlistres(&ie->choice.partOfS1_Interface, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_resettype( + uint8_t **ptr, + LIBLTE_S1AP_RESETTYPE_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + // Extension + ie->ext = liblte_bits_2_value(ptr, 1); + if(ie->ext) { + liblte_log_print("ResetType error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // Choice type + ie->choice_type = (LIBLTE_S1AP_RESETTYPE_CHOICE_ENUM)liblte_bits_2_value(ptr, 1); + + // Choice + if(ie->choice_type == LIBLTE_S1AP_RESETTYPE_CHOICE_S1_INTERFACE) { + if(liblte_s1ap_unpack_resetall(ptr, &ie->choice.s1_Interface) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(ie->choice_type == LIBLTE_S1AP_RESETTYPE_CHOICE_PARTOFS1_INTERFACE) { + if(liblte_s1ap_unpack_ue_associatedlogicals1_connectionlistres(ptr, &ie->choice.partOfS1_Interface) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Container List E_RABSubjecttoDataForwardingList DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:256 +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabsubjecttodataforwardinglist( + LIBLTE_S1AP_E_RABSUBJECTTODATAFORWARDINGLIST_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + if(ie->len > 32) { + liblte_log_print("E_RABSubjecttoDataForwardingList pack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_ENCODE_FAIL; + } + // Length + liblte_value_2_bits(ie->len-1, ptr, 8); + liblte_align_up_zero(ptr, 8); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + uint32_t i; + for(i=0;ilen;i++) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_e_rabdataforwardingitem(&ie->buffer[i], &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_E_RABDATAFORWARDINGITEM, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabsubjecttodataforwardinglist( + uint8_t **ptr, + LIBLTE_S1AP_E_RABSUBJECTTODATAFORWARDINGLIST_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + + // Length + ie->len = liblte_bits_2_value(ptr, 8) + 1; + liblte_align_up(ptr, 8); + if(ie->len > 32) { + liblte_log_print("E_RABSubjecttoDataForwardingList unpack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_DECODE_FAIL; + } + + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_unpack_protocolie_header(ptr, &ie_id, &crit, &len) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + if(LIBLTE_S1AP_IE_ID_E_RABDATAFORWARDINGITEM != ie_id) { + return LIBLTE_ERROR_DECODE_FAIL; + } + if(liblte_s1ap_unpack_e_rabdataforwardingitem(ptr, &ie->buffer[i]) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Container List E_RABToBeSetupListHOReq DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:256 +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabtobesetuplisthoreq( + LIBLTE_S1AP_E_RABTOBESETUPLISTHOREQ_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + if(ie->len > 32) { + liblte_log_print("E_RABToBeSetupListHOReq pack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_ENCODE_FAIL; + } + // Length + liblte_value_2_bits(ie->len-1, ptr, 8); + liblte_align_up_zero(ptr, 8); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + uint32_t i; + for(i=0;ilen;i++) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_e_rabtobesetupitemhoreq(&ie->buffer[i], &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_E_RABTOBESETUPITEMHOREQ, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabtobesetuplisthoreq( + uint8_t **ptr, + LIBLTE_S1AP_E_RABTOBESETUPLISTHOREQ_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + + // Length + ie->len = liblte_bits_2_value(ptr, 8) + 1; + liblte_align_up(ptr, 8); + if(ie->len > 32) { + liblte_log_print("E_RABToBeSetupListHOReq unpack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_DECODE_FAIL; + } + + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_unpack_protocolie_header(ptr, &ie_id, &crit, &len) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + if(LIBLTE_S1AP_IE_ID_E_RABTOBESETUPITEMHOREQ != ie_id) { + return LIBLTE_ERROR_DECODE_FAIL; + } + if(liblte_s1ap_unpack_e_rabtobesetupitemhoreq(ptr, &ie->buffer[i]) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Container List E_RABAdmittedList DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:256 +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabadmittedlist( + LIBLTE_S1AP_E_RABADMITTEDLIST_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + if(ie->len > 32) { + liblte_log_print("E_RABAdmittedList pack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_ENCODE_FAIL; + } + // Length + liblte_value_2_bits(ie->len-1, ptr, 8); + liblte_align_up_zero(ptr, 8); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + uint32_t i; + for(i=0;ilen;i++) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_e_rabadmitteditem(&ie->buffer[i], &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_E_RABADMITTEDITEM, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabadmittedlist( + uint8_t **ptr, + LIBLTE_S1AP_E_RABADMITTEDLIST_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + + // Length + ie->len = liblte_bits_2_value(ptr, 8) + 1; + liblte_align_up(ptr, 8); + if(ie->len > 32) { + liblte_log_print("E_RABAdmittedList unpack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_DECODE_FAIL; + } + + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_unpack_protocolie_header(ptr, &ie_id, &crit, &len) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + if(LIBLTE_S1AP_IE_ID_E_RABADMITTEDITEM != ie_id) { + return LIBLTE_ERROR_DECODE_FAIL; + } + if(liblte_s1ap_unpack_e_rabadmitteditem(ptr, &ie->buffer[i]) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Container List E_RABToBeSwitchedDLList DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:256 +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabtobeswitcheddllist( + LIBLTE_S1AP_E_RABTOBESWITCHEDDLLIST_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + if(ie->len > 32) { + liblte_log_print("E_RABToBeSwitchedDLList pack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_ENCODE_FAIL; + } + // Length + liblte_value_2_bits(ie->len-1, ptr, 8); + liblte_align_up_zero(ptr, 8); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + uint32_t i; + for(i=0;ilen;i++) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_e_rabtobeswitcheddlitem(&ie->buffer[i], &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_E_RABTOBESWITCHEDDLITEM, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabtobeswitcheddllist( + uint8_t **ptr, + LIBLTE_S1AP_E_RABTOBESWITCHEDDLLIST_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + + // Length + ie->len = liblte_bits_2_value(ptr, 8) + 1; + liblte_align_up(ptr, 8); + if(ie->len > 32) { + liblte_log_print("E_RABToBeSwitchedDLList unpack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_DECODE_FAIL; + } + + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_unpack_protocolie_header(ptr, &ie_id, &crit, &len) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + if(LIBLTE_S1AP_IE_ID_E_RABTOBESWITCHEDDLITEM != ie_id) { + return LIBLTE_ERROR_DECODE_FAIL; + } + if(liblte_s1ap_unpack_e_rabtobeswitcheddlitem(ptr, &ie->buffer[i]) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Container List E_RABToBeSwitchedULList DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:256 +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabtobeswitchedullist( + LIBLTE_S1AP_E_RABTOBESWITCHEDULLIST_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + if(ie->len > 32) { + liblte_log_print("E_RABToBeSwitchedULList pack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_ENCODE_FAIL; + } + // Length + liblte_value_2_bits(ie->len-1, ptr, 8); + liblte_align_up_zero(ptr, 8); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + uint32_t i; + for(i=0;ilen;i++) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_e_rabtobeswitchedulitem(&ie->buffer[i], &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_E_RABTOBESWITCHEDULITEM, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabtobeswitchedullist( + uint8_t **ptr, + LIBLTE_S1AP_E_RABTOBESWITCHEDULLIST_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + + // Length + ie->len = liblte_bits_2_value(ptr, 8) + 1; + liblte_align_up(ptr, 8); + if(ie->len > 32) { + liblte_log_print("E_RABToBeSwitchedULList unpack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_DECODE_FAIL; + } + + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_unpack_protocolie_header(ptr, &ie_id, &crit, &len) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + if(LIBLTE_S1AP_IE_ID_E_RABTOBESWITCHEDULITEM != ie_id) { + return LIBLTE_ERROR_DECODE_FAIL; + } + if(liblte_s1ap_unpack_e_rabtobeswitchedulitem(ptr, &ie->buffer[i]) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Container List E_RABToBeSetupListBearerSUReq DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:256 +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabtobesetuplistbearersureq( + LIBLTE_S1AP_E_RABTOBESETUPLISTBEARERSUREQ_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + if(ie->len > 32) { + liblte_log_print("E_RABToBeSetupListBearerSUReq pack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_ENCODE_FAIL; + } + // Length + liblte_value_2_bits(ie->len-1, ptr, 8); + liblte_align_up_zero(ptr, 8); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + uint32_t i; + for(i=0;ilen;i++) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_e_rabtobesetupitembearersureq(&ie->buffer[i], &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_E_RABTOBESETUPITEMBEARERSUREQ, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabtobesetuplistbearersureq( + uint8_t **ptr, + LIBLTE_S1AP_E_RABTOBESETUPLISTBEARERSUREQ_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + + // Length + ie->len = liblte_bits_2_value(ptr, 8) + 1; + liblte_align_up(ptr, 8); + if(ie->len > 32) { + liblte_log_print("E_RABToBeSetupListBearerSUReq unpack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_DECODE_FAIL; + } + + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_unpack_protocolie_header(ptr, &ie_id, &crit, &len) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + if(LIBLTE_S1AP_IE_ID_E_RABTOBESETUPITEMBEARERSUREQ != ie_id) { + return LIBLTE_ERROR_DECODE_FAIL; + } + if(liblte_s1ap_unpack_e_rabtobesetupitembearersureq(ptr, &ie->buffer[i]) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Container List E_RABSetupListBearerSURes DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:256 +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabsetuplistbearersures( + LIBLTE_S1AP_E_RABSETUPLISTBEARERSURES_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + if(ie->len > 32) { + liblte_log_print("E_RABSetupListBearerSURes pack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_ENCODE_FAIL; + } + // Length + liblte_value_2_bits(ie->len-1, ptr, 8); + liblte_align_up_zero(ptr, 8); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + uint32_t i; + for(i=0;ilen;i++) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_e_rabsetupitembearersures(&ie->buffer[i], &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_E_RABSETUPITEMBEARERSURES, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabsetuplistbearersures( + uint8_t **ptr, + LIBLTE_S1AP_E_RABSETUPLISTBEARERSURES_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + + // Length + ie->len = liblte_bits_2_value(ptr, 8) + 1; + liblte_align_up(ptr, 8); + if(ie->len > 32) { + liblte_log_print("E_RABSetupListBearerSURes unpack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_DECODE_FAIL; + } + + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_unpack_protocolie_header(ptr, &ie_id, &crit, &len) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + if(LIBLTE_S1AP_IE_ID_E_RABSETUPITEMBEARERSURES != ie_id) { + return LIBLTE_ERROR_DECODE_FAIL; + } + if(liblte_s1ap_unpack_e_rabsetupitembearersures(ptr, &ie->buffer[i]) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Container List E_RABToBeModifiedListBearerModReq DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:256 +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabtobemodifiedlistbearermodreq( + LIBLTE_S1AP_E_RABTOBEMODIFIEDLISTBEARERMODREQ_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + if(ie->len > 32) { + liblte_log_print("E_RABToBeModifiedListBearerModReq pack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_ENCODE_FAIL; + } + // Length + liblte_value_2_bits(ie->len-1, ptr, 8); + liblte_align_up_zero(ptr, 8); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + uint32_t i; + for(i=0;ilen;i++) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_e_rabtobemodifieditembearermodreq(&ie->buffer[i], &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_E_RABTOBEMODIFIEDITEMBEARERMODREQ, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabtobemodifiedlistbearermodreq( + uint8_t **ptr, + LIBLTE_S1AP_E_RABTOBEMODIFIEDLISTBEARERMODREQ_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + + // Length + ie->len = liblte_bits_2_value(ptr, 8) + 1; + liblte_align_up(ptr, 8); + if(ie->len > 32) { + liblte_log_print("E_RABToBeModifiedListBearerModReq unpack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_DECODE_FAIL; + } + + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_unpack_protocolie_header(ptr, &ie_id, &crit, &len) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + if(LIBLTE_S1AP_IE_ID_E_RABTOBEMODIFIEDITEMBEARERMODREQ != ie_id) { + return LIBLTE_ERROR_DECODE_FAIL; + } + if(liblte_s1ap_unpack_e_rabtobemodifieditembearermodreq(ptr, &ie->buffer[i]) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Container List E_RABModifyListBearerModRes DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:256 +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabmodifylistbearermodres( + LIBLTE_S1AP_E_RABMODIFYLISTBEARERMODRES_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + if(ie->len > 32) { + liblte_log_print("E_RABModifyListBearerModRes pack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_ENCODE_FAIL; + } + // Length + liblte_value_2_bits(ie->len-1, ptr, 8); + liblte_align_up_zero(ptr, 8); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + uint32_t i; + for(i=0;ilen;i++) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_e_rabmodifyitembearermodres(&ie->buffer[i], &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_E_RABMODIFYITEMBEARERMODRES, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabmodifylistbearermodres( + uint8_t **ptr, + LIBLTE_S1AP_E_RABMODIFYLISTBEARERMODRES_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + + // Length + ie->len = liblte_bits_2_value(ptr, 8) + 1; + liblte_align_up(ptr, 8); + if(ie->len > 32) { + liblte_log_print("E_RABModifyListBearerModRes unpack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_DECODE_FAIL; + } + + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_unpack_protocolie_header(ptr, &ie_id, &crit, &len) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + if(LIBLTE_S1AP_IE_ID_E_RABMODIFYITEMBEARERMODRES != ie_id) { + return LIBLTE_ERROR_DECODE_FAIL; + } + if(liblte_s1ap_unpack_e_rabmodifyitembearermodres(ptr, &ie->buffer[i]) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Container List E_RABReleaseListBearerRelComp DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:256 +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabreleaselistbearerrelcomp( + LIBLTE_S1AP_E_RABRELEASELISTBEARERRELCOMP_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + if(ie->len > 32) { + liblte_log_print("E_RABReleaseListBearerRelComp pack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_ENCODE_FAIL; + } + // Length + liblte_value_2_bits(ie->len-1, ptr, 8); + liblte_align_up_zero(ptr, 8); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + uint32_t i; + for(i=0;ilen;i++) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_e_rabreleaseitembearerrelcomp(&ie->buffer[i], &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_E_RABRELEASEITEMBEARERRELCOMP, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabreleaselistbearerrelcomp( + uint8_t **ptr, + LIBLTE_S1AP_E_RABRELEASELISTBEARERRELCOMP_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + + // Length + ie->len = liblte_bits_2_value(ptr, 8) + 1; + liblte_align_up(ptr, 8); + if(ie->len > 32) { + liblte_log_print("E_RABReleaseListBearerRelComp unpack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_DECODE_FAIL; + } + + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_unpack_protocolie_header(ptr, &ie_id, &crit, &len) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + if(LIBLTE_S1AP_IE_ID_E_RABRELEASEITEMBEARERRELCOMP != ie_id) { + return LIBLTE_ERROR_DECODE_FAIL; + } + if(liblte_s1ap_unpack_e_rabreleaseitembearerrelcomp(ptr, &ie->buffer[i]) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Container List E_RABToBeSetupListCtxtSUReq DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:256 +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabtobesetuplistctxtsureq( + LIBLTE_S1AP_E_RABTOBESETUPLISTCTXTSUREQ_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + if(ie->len > 32) { + liblte_log_print("E_RABToBeSetupListCtxtSUReq pack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_ENCODE_FAIL; + } + // Length + liblte_value_2_bits(ie->len-1, ptr, 8); + liblte_align_up_zero(ptr, 8); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + uint32_t i; + for(i=0;ilen;i++) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_e_rabtobesetupitemctxtsureq(&ie->buffer[i], &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_E_RABTOBESETUPITEMCTXTSUREQ, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabtobesetuplistctxtsureq( + uint8_t **ptr, + LIBLTE_S1AP_E_RABTOBESETUPLISTCTXTSUREQ_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + + // Length + ie->len = liblte_bits_2_value(ptr, 8) + 1; + liblte_align_up(ptr, 8); + if(ie->len > 32) { + liblte_log_print("E_RABToBeSetupListCtxtSUReq unpack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_DECODE_FAIL; + } + + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_unpack_protocolie_header(ptr, &ie_id, &crit, &len) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + if(LIBLTE_S1AP_IE_ID_E_RABTOBESETUPITEMCTXTSUREQ != ie_id) { + return LIBLTE_ERROR_DECODE_FAIL; + } + if(liblte_s1ap_unpack_e_rabtobesetupitemctxtsureq(ptr, &ie->buffer[i]) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Container List E_RABSetupListCtxtSURes DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:256 +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabsetuplistctxtsures( + LIBLTE_S1AP_E_RABSETUPLISTCTXTSURES_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + if(ie->len > 32) { + liblte_log_print("E_RABSetupListCtxtSURes pack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_ENCODE_FAIL; + } + // Length + liblte_value_2_bits(ie->len-1, ptr, 8); + liblte_align_up_zero(ptr, 8); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + uint32_t i; + for(i=0;ilen;i++) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_e_rabsetupitemctxtsures(&ie->buffer[i], &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_E_RABSETUPITEMCTXTSURES, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabsetuplistctxtsures( + uint8_t **ptr, + LIBLTE_S1AP_E_RABSETUPLISTCTXTSURES_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + + // Length + ie->len = liblte_bits_2_value(ptr, 8) + 1; + liblte_align_up(ptr, 8); + if(ie->len > 32) { + liblte_log_print("E_RABSetupListCtxtSURes unpack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_DECODE_FAIL; + } + + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_unpack_protocolie_header(ptr, &ie_id, &crit, &len) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + if(LIBLTE_S1AP_IE_ID_E_RABSETUPITEMCTXTSURES != ie_id) { + return LIBLTE_ERROR_DECODE_FAIL; + } + if(liblte_s1ap_unpack_e_rabsetupitemctxtsures(ptr, &ie->buffer[i]) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Container List TAIList DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:256 +LIBLTE_ERROR_ENUM liblte_s1ap_pack_tailist( + LIBLTE_S1AP_TAILIST_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + if(ie->len > 32) { + liblte_log_print("TAIList pack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_ENCODE_FAIL; + } + // Length + liblte_value_2_bits(ie->len-1, ptr, 8); + liblte_align_up_zero(ptr, 8); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + uint32_t i; + for(i=0;ilen;i++) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_taiitem(&ie->buffer[i], &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_TAIITEM, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_tailist( + uint8_t **ptr, + LIBLTE_S1AP_TAILIST_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + + // Length + ie->len = liblte_bits_2_value(ptr, 8) + 1; + liblte_align_up(ptr, 8); + if(ie->len > 32) { + liblte_log_print("TAIList unpack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_DECODE_FAIL; + } + + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_unpack_protocolie_header(ptr, &ie_id, &crit, &len) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + if(LIBLTE_S1AP_IE_ID_TAIITEM != ie_id) { + return LIBLTE_ERROR_DECODE_FAIL; + } + if(liblte_s1ap_unpack_taiitem(ptr, &ie->buffer[i]) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Container List E_RABFailedtoSetupListHOReqAck DYNAMIC SEQUENCE OF +********************************************************************************/ +// lb:1, ub:256 +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabfailedtosetuplisthoreqack( + LIBLTE_S1AP_E_RABFAILEDTOSETUPLISTHOREQACK_STRUCT *ie, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + if(ie->len > 32) { + liblte_log_print("E_RABFailedtoSetupListHOReqAck pack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_ENCODE_FAIL; + } + // Length + liblte_value_2_bits(ie->len-1, ptr, 8); + liblte_align_up_zero(ptr, 8); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + uint32_t i; + for(i=0;ilen;i++) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_e_rabfailedtosetupitemhoreqack(&ie->buffer[i], &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_E_RABFAILEDTOSETUPITEMHOREQACK, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabfailedtosetuplisthoreqack( + uint8_t **ptr, + LIBLTE_S1AP_E_RABFAILEDTOSETUPLISTHOREQACK_STRUCT *ie) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + + // Length + ie->len = liblte_bits_2_value(ptr, 8) + 1; + liblte_align_up(ptr, 8); + if(ie->len > 32) { + liblte_log_print("E_RABFailedtoSetupListHOReqAck unpack error - max supported dynamic sequence length = 32, ie->len = %d\n", ie->len); + return LIBLTE_ERROR_DECODE_FAIL; + } + + uint32_t i; + for(i=0;ilen;i++) { + if(liblte_s1ap_unpack_protocolie_header(ptr, &ie_id, &crit, &len) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + if(LIBLTE_S1AP_IE_ID_E_RABFAILEDTOSETUPITEMHOREQACK != ie_id) { + return LIBLTE_ERROR_DECODE_FAIL; + } + if(liblte_s1ap_unpack_e_rabfailedtosetupitemhoreqack(ptr, &ie->buffer[i]) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message AllocationAndRetentionPriority_Ext STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_allocationandretentionpriority_ext( + LIBLTE_S1AP_MESSAGE_ALLOCATIONANDRETENTIONPRIORITY_EXT_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("AllocationAndRetentionPriority-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 0; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_allocationandretentionpriority_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_ALLOCATIONANDRETENTIONPRIORITY_EXT_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("AllocationAndRetentionPriority-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message CancelledCellinEAI_Item_Ext STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_cancelledcellineai_item_ext( + LIBLTE_S1AP_MESSAGE_CANCELLEDCELLINEAI_ITEM_EXT_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("CancelledCellinEAI-Item-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 0; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_cancelledcellineai_item_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_CANCELLEDCELLINEAI_ITEM_EXT_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("CancelledCellinEAI-Item-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message CancelledCellinTAI_Item_Ext STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_cancelledcellintai_item_ext( + LIBLTE_S1AP_MESSAGE_CANCELLEDCELLINTAI_ITEM_EXT_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("CancelledCellinTAI-Item-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 0; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_cancelledcellintai_item_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_CANCELLEDCELLINTAI_ITEM_EXT_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("CancelledCellinTAI-Item-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message CellID_Broadcast_Item_Ext STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_cellid_broadcast_item_ext( + LIBLTE_S1AP_MESSAGE_CELLID_BROADCAST_ITEM_EXT_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("CellID-Broadcast-Item-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 0; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_cellid_broadcast_item_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_CELLID_BROADCAST_ITEM_EXT_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("CellID-Broadcast-Item-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message CellID_Cancelled_Item_Ext STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_cellid_cancelled_item_ext( + LIBLTE_S1AP_MESSAGE_CELLID_CANCELLED_ITEM_EXT_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("CellID-Cancelled-Item-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 0; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_cellid_cancelled_item_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_CELLID_CANCELLED_ITEM_EXT_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("CellID-Cancelled-Item-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message CellBasedMDT_Ext STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_cellbasedmdt_ext( + LIBLTE_S1AP_MESSAGE_CELLBASEDMDT_EXT_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("CellBasedMDT-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 0; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_cellbasedmdt_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_CELLBASEDMDT_EXT_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("CellBasedMDT-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message Cdma2000OneXSRVCCInfo_Ext STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_cdma2000onexsrvccinfo_ext( + LIBLTE_S1AP_MESSAGE_CDMA2000ONEXSRVCCINFO_EXT_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("Cdma2000OneXSRVCCInfo-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 0; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_cdma2000onexsrvccinfo_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_CDMA2000ONEXSRVCCINFO_EXT_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("Cdma2000OneXSRVCCInfo-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message CellType_Ext STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_celltype_ext( + LIBLTE_S1AP_MESSAGE_CELLTYPE_EXT_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("CellType-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 0; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_celltype_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_CELLTYPE_EXT_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("CellType-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message CGI_Ext STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_cgi_ext( + LIBLTE_S1AP_MESSAGE_CGI_EXT_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("CGI-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 0; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_cgi_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_CGI_EXT_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("CGI-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message CSG_IdList_Item_Ext STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_csg_idlist_item_ext( + LIBLTE_S1AP_MESSAGE_CSG_IDLIST_ITEM_EXT_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("CSG-IdList-Item-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 0; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_csg_idlist_item_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_CSG_IDLIST_ITEM_EXT_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("CSG-IdList-Item-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message COUNTvalue_Ext STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_countvalue_ext( + LIBLTE_S1AP_MESSAGE_COUNTVALUE_EXT_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("COUNTvalue-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 0; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_countvalue_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_COUNTVALUE_EXT_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("COUNTvalue-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message COUNTValueExtended_Ext STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_countvalueextended_ext( + LIBLTE_S1AP_MESSAGE_COUNTVALUEEXTENDED_EXT_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("COUNTValueExtended-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 0; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_countvalueextended_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_COUNTVALUEEXTENDED_EXT_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("COUNTValueExtended-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message CriticalityDiagnostics_Ext STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_criticalitydiagnostics_ext( + LIBLTE_S1AP_MESSAGE_CRITICALITYDIAGNOSTICS_EXT_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("CriticalityDiagnostics-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 0; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_criticalitydiagnostics_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_CRITICALITYDIAGNOSTICS_EXT_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("CriticalityDiagnostics-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message CriticalityDiagnostics_IE_Item_Ext STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_criticalitydiagnostics_ie_item_ext( + LIBLTE_S1AP_MESSAGE_CRITICALITYDIAGNOSTICS_IE_ITEM_EXT_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("CriticalityDiagnostics-IE-Item-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 0; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_criticalitydiagnostics_ie_item_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_CRITICALITYDIAGNOSTICS_IE_ITEM_EXT_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("CriticalityDiagnostics-IE-Item-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message EmergencyAreaID_Broadcast_Item_Ext STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_emergencyareaid_broadcast_item_ext( + LIBLTE_S1AP_MESSAGE_EMERGENCYAREAID_BROADCAST_ITEM_EXT_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("EmergencyAreaID-Broadcast-Item-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 0; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_emergencyareaid_broadcast_item_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_EMERGENCYAREAID_BROADCAST_ITEM_EXT_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("EmergencyAreaID-Broadcast-Item-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message EmergencyAreaID_Cancelled_Item_Ext STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_emergencyareaid_cancelled_item_ext( + LIBLTE_S1AP_MESSAGE_EMERGENCYAREAID_CANCELLED_ITEM_EXT_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("EmergencyAreaID-Cancelled-Item-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 0; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_emergencyareaid_cancelled_item_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_EMERGENCYAREAID_CANCELLED_ITEM_EXT_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("EmergencyAreaID-Cancelled-Item-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message CompletedCellinEAI_Item_Ext STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_completedcellineai_item_ext( + LIBLTE_S1AP_MESSAGE_COMPLETEDCELLINEAI_ITEM_EXT_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("CompletedCellinEAI-Item-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 0; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_completedcellineai_item_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_COMPLETEDCELLINEAI_ITEM_EXT_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("CompletedCellinEAI-Item-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message GERAN_Cell_ID_Ext STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_geran_cell_id_ext( + LIBLTE_S1AP_MESSAGE_GERAN_CELL_ID_EXT_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("GERAN-Cell-ID-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 0; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_geran_cell_id_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_GERAN_CELL_ID_EXT_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("GERAN-Cell-ID-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message GlobalENB_ID_Ext STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_globalenb_id_ext( + LIBLTE_S1AP_MESSAGE_GLOBALENB_ID_EXT_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("GlobalENB-ID-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 0; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_globalenb_id_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_GLOBALENB_ID_EXT_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("GlobalENB-ID-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message ENB_StatusTransfer_TransparentContainer_Ext STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_enb_statustransfer_transparentcontainer_ext( + LIBLTE_S1AP_MESSAGE_ENB_STATUSTRANSFER_TRANSPARENTCONTAINER_EXT_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("ENB-StatusTransfer-TransparentContainer-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 0; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_enb_statustransfer_transparentcontainer_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_ENB_STATUSTRANSFER_TRANSPARENTCONTAINER_EXT_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("ENB-StatusTransfer-TransparentContainer-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message E_RABInformationListItem_Ext STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabinformationlistitem_ext( + LIBLTE_S1AP_MESSAGE_E_RABINFORMATIONLISTITEM_EXT_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("E-RABInformationListItem-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 0; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabinformationlistitem_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_E_RABINFORMATIONLISTITEM_EXT_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("E-RABInformationListItem-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message E_RABItem_Ext STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabitem_ext( + LIBLTE_S1AP_MESSAGE_E_RABITEM_EXT_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("E-RABItem-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 0; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabitem_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_E_RABITEM_EXT_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("E-RABItem-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message E_RABQoSParameters_Ext STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabqosparameters_ext( + LIBLTE_S1AP_MESSAGE_E_RABQOSPARAMETERS_EXT_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("E-RABQoSParameters-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 0; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabqosparameters_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_E_RABQOSPARAMETERS_EXT_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("E-RABQoSParameters-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message EUTRAN_CGI_Ext STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_eutran_cgi_ext( + LIBLTE_S1AP_MESSAGE_EUTRAN_CGI_EXT_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("EUTRAN-CGI-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 0; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_eutran_cgi_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_EUTRAN_CGI_EXT_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("EUTRAN-CGI-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message ForbiddenTAs_Item_Ext STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_forbiddentas_item_ext( + LIBLTE_S1AP_MESSAGE_FORBIDDENTAS_ITEM_EXT_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("ForbiddenTAs-Item-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 0; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_forbiddentas_item_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_FORBIDDENTAS_ITEM_EXT_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("ForbiddenTAs-Item-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message ForbiddenLAs_Item_Ext STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_forbiddenlas_item_ext( + LIBLTE_S1AP_MESSAGE_FORBIDDENLAS_ITEM_EXT_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("ForbiddenLAs-Item-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 0; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_forbiddenlas_item_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_FORBIDDENLAS_ITEM_EXT_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("ForbiddenLAs-Item-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message GBR_QosInformation_Ext STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_gbr_qosinformation_ext( + LIBLTE_S1AP_MESSAGE_GBR_QOSINFORMATION_EXT_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("GBR-QosInformation-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 0; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_gbr_qosinformation_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_GBR_QOSINFORMATION_EXT_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("GBR-QosInformation-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message GUMMEI_Ext STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_gummei_ext( + LIBLTE_S1AP_MESSAGE_GUMMEI_EXT_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("GUMMEI-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 0; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_gummei_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_GUMMEI_EXT_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("GUMMEI-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message HandoverRestrictionList_Ext STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_handoverrestrictionlist_ext( + LIBLTE_S1AP_MESSAGE_HANDOVERRESTRICTIONLIST_EXT_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("HandoverRestrictionList-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 0; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_handoverrestrictionlist_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_HANDOVERRESTRICTIONLIST_EXT_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("HandoverRestrictionList-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message LAI_Ext STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_lai_ext( + LIBLTE_S1AP_MESSAGE_LAI_EXT_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("LAI-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 0; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_lai_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_LAI_EXT_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("LAI-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message LoggedMDT_Ext STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_loggedmdt_ext( + LIBLTE_S1AP_MESSAGE_LOGGEDMDT_EXT_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("LoggedMDT-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 0; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_loggedmdt_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_LOGGEDMDT_EXT_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("LoggedMDT-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message M3Configuration_Ext STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_m3configuration_ext( + LIBLTE_S1AP_MESSAGE_M3CONFIGURATION_EXT_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("M3Configuration-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 0; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_m3configuration_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_M3CONFIGURATION_EXT_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("M3Configuration-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message M4Configuration_Ext STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_m4configuration_ext( + LIBLTE_S1AP_MESSAGE_M4CONFIGURATION_EXT_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("M4Configuration-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 0; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_m4configuration_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_M4CONFIGURATION_EXT_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("M4Configuration-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message M5Configuration_Ext STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_m5configuration_ext( + LIBLTE_S1AP_MESSAGE_M5CONFIGURATION_EXT_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("M5Configuration-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 0; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_m5configuration_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_M5CONFIGURATION_EXT_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("M5Configuration-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message M1PeriodicReporting_Ext STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_m1periodicreporting_ext( + LIBLTE_S1AP_MESSAGE_M1PERIODICREPORTING_EXT_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("M1PeriodicReporting-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 0; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_m1periodicreporting_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_M1PERIODICREPORTING_EXT_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("M1PeriodicReporting-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message RequestType_Ext STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_requesttype_ext( + LIBLTE_S1AP_MESSAGE_REQUESTTYPE_EXT_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("RequestType-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 0; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_requesttype_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_REQUESTTYPE_EXT_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("RequestType-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message RIMTransfer_Ext STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_rimtransfer_ext( + LIBLTE_S1AP_MESSAGE_RIMTRANSFER_EXT_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("RIMTransfer-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 0; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_rimtransfer_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_RIMTRANSFER_EXT_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("RIMTransfer-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message SecurityContext_Ext STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_securitycontext_ext( + LIBLTE_S1AP_MESSAGE_SECURITYCONTEXT_EXT_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("SecurityContext-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 0; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_securitycontext_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_SECURITYCONTEXT_EXT_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("SecurityContext-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message SourceeNB_ID_Ext STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_sourceenb_id_ext( + LIBLTE_S1AP_MESSAGE_SOURCEENB_ID_EXT_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("SourceeNB-ID-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 0; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_sourceenb_id_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_SOURCEENB_ID_EXT_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("SourceeNB-ID-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message ServedGUMMEIsItem_Ext STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_servedgummeisitem_ext( + LIBLTE_S1AP_MESSAGE_SERVEDGUMMEISITEM_EXT_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("ServedGUMMEIsItem-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 0; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_servedgummeisitem_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_SERVEDGUMMEISITEM_EXT_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("ServedGUMMEIsItem-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message SupportedTAs_Item_Ext STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_supportedtas_item_ext( + LIBLTE_S1AP_MESSAGE_SUPPORTEDTAS_ITEM_EXT_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("SupportedTAs-Item-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 0; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_supportedtas_item_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_SUPPORTEDTAS_ITEM_EXT_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("SupportedTAs-Item-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message TimeSynchronizationInfo_Ext STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_timesynchronizationinfo_ext( + LIBLTE_S1AP_MESSAGE_TIMESYNCHRONIZATIONINFO_EXT_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("TimeSynchronizationInfo-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 0; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_timesynchronizationinfo_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_TIMESYNCHRONIZATIONINFO_EXT_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("TimeSynchronizationInfo-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message S_TMSI_Ext STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_s_tmsi_ext( + LIBLTE_S1AP_MESSAGE_S_TMSI_EXT_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("S-TMSI-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 0; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_s_tmsi_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_S_TMSI_EXT_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("S-TMSI-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message TAIBasedMDT_Ext STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_taibasedmdt_ext( + LIBLTE_S1AP_MESSAGE_TAIBASEDMDT_EXT_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("TAIBasedMDT-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 0; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_taibasedmdt_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_TAIBASEDMDT_EXT_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("TAIBasedMDT-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message TAI_Ext STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_tai_ext( + LIBLTE_S1AP_MESSAGE_TAI_EXT_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("TAI-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 0; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_tai_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_TAI_EXT_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("TAI-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message TAI_Broadcast_Item_Ext STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_tai_broadcast_item_ext( + LIBLTE_S1AP_MESSAGE_TAI_BROADCAST_ITEM_EXT_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("TAI-Broadcast-Item-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 0; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_tai_broadcast_item_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_TAI_BROADCAST_ITEM_EXT_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("TAI-Broadcast-Item-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message TAI_Cancelled_Item_Ext STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_tai_cancelled_item_ext( + LIBLTE_S1AP_MESSAGE_TAI_CANCELLED_ITEM_EXT_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("TAI-Cancelled-Item-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 0; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_tai_cancelled_item_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_TAI_CANCELLED_ITEM_EXT_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("TAI-Cancelled-Item-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message TABasedMDT_Ext STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_tabasedmdt_ext( + LIBLTE_S1AP_MESSAGE_TABASEDMDT_EXT_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("TABasedMDT-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 0; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_tabasedmdt_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_TABASEDMDT_EXT_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("TABasedMDT-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message CompletedCellinTAI_Item_Ext STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_completedcellintai_item_ext( + LIBLTE_S1AP_MESSAGE_COMPLETEDCELLINTAI_ITEM_EXT_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("CompletedCellinTAI-Item-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 0; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_completedcellintai_item_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_COMPLETEDCELLINTAI_ITEM_EXT_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("CompletedCellinTAI-Item-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message TargeteNB_ID_Ext STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_targetenb_id_ext( + LIBLTE_S1AP_MESSAGE_TARGETENB_ID_EXT_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("TargeteNB-ID-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 0; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_targetenb_id_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_TARGETENB_ID_EXT_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("TargeteNB-ID-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message TargetRNC_ID_Ext STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_targetrnc_id_ext( + LIBLTE_S1AP_MESSAGE_TARGETRNC_ID_EXT_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("TargetRNC-ID-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 0; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_targetrnc_id_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_TARGETRNC_ID_EXT_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("TargetRNC-ID-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message TargeteNB_ToSourceeNB_TransparentContainer_Ext STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_targetenb_tosourceenb_transparentcontainer_ext( + LIBLTE_S1AP_MESSAGE_TARGETENB_TOSOURCEENB_TRANSPARENTCONTAINER_EXT_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("TargeteNB-ToSourceeNB-TransparentContainer-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 0; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_targetenb_tosourceenb_transparentcontainer_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_TARGETENB_TOSOURCEENB_TRANSPARENTCONTAINER_EXT_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("TargeteNB-ToSourceeNB-TransparentContainer-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message M1ThresholdEventA2_Ext STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_m1thresholdeventa2_ext( + LIBLTE_S1AP_MESSAGE_M1THRESHOLDEVENTA2_EXT_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("M1ThresholdEventA2-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 0; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_m1thresholdeventa2_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_M1THRESHOLDEVENTA2_EXT_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("M1ThresholdEventA2-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message Tunnel_Information_Ext STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_tunnel_information_ext( + LIBLTE_S1AP_MESSAGE_TUNNEL_INFORMATION_EXT_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("Tunnel-Information-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 0; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_tunnel_information_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_TUNNEL_INFORMATION_EXT_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("Tunnel-Information-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message UEAggregate_MaximumBitrates_Ext STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_ueaggregate_maximumbitrates_ext( + LIBLTE_S1AP_MESSAGE_UEAGGREGATE_MAXIMUMBITRATES_EXT_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("UEAggregate-MaximumBitrates-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 0; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_ueaggregate_maximumbitrates_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_UEAGGREGATE_MAXIMUMBITRATES_EXT_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("UEAggregate-MaximumBitrates-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message UE_S1AP_ID_pair_Ext STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_ue_s1ap_id_pair_ext( + LIBLTE_S1AP_MESSAGE_UE_S1AP_ID_PAIR_EXT_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("UE-S1AP-ID-pair-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 0; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_ue_s1ap_id_pair_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_UE_S1AP_ID_PAIR_EXT_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("UE-S1AP-ID-pair-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message UE_associatedLogicalS1_ConnectionItemExt STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_ue_associatedlogicals1_connectionitemext( + LIBLTE_S1AP_MESSAGE_UE_ASSOCIATEDLOGICALS1_CONNECTIONITEMEXT_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("UE-associatedLogicalS1-ConnectionItemExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 0; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_ue_associatedlogicals1_connectionitemext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_UE_ASSOCIATEDLOGICALS1_CONNECTIONITEMEXT_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("UE-associatedLogicalS1-ConnectionItemExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message UESecurityCapabilities_Ext STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_uesecuritycapabilities_ext( + LIBLTE_S1AP_MESSAGE_UESECURITYCAPABILITIES_EXT_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("UESecurityCapabilities-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 0; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_uesecuritycapabilities_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_UESECURITYCAPABILITIES_EXT_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("UESecurityCapabilities-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message UserLocationInformation_Ext STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_userlocationinformation_ext( + LIBLTE_S1AP_MESSAGE_USERLOCATIONINFORMATION_EXT_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("UserLocationInformation-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 0; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_userlocationinformation_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_USERLOCATIONINFORMATION_EXT_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("UserLocationInformation-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message ENBX2ExtTLA_Ext STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_enbx2exttla_ext( + LIBLTE_S1AP_MESSAGE_ENBX2EXTTLA_EXT_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("ENBX2ExtTLA-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 0; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_enbx2exttla_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_ENBX2EXTTLA_EXT_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("ENBX2ExtTLA-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message SourceeNB_ToTargeteNB_TransparentContainer_Ext STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_sourceenb_totargetenb_transparentcontainer_ext( + LIBLTE_S1AP_MESSAGE_SOURCEENB_TOTARGETENB_TRANSPARENTCONTAINER_EXT_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("SourceeNB-ToTargeteNB-TransparentContainer-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 1; + if(!msg->MobilityInformation_present) + n_ie--; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - MobilityInformation + if(msg->MobilityInformation_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_mobilityinformation(&msg->MobilityInformation, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_MOBILITYINFORMATION, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_sourceenb_totargetenb_transparentcontainer_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_SOURCEENB_TOTARGETENB_TRANSPARENTCONTAINER_EXT_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + msg->MobilityInformation_present = false; + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("SourceeNB-ToTargeteNB-TransparentContainer-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iMobilityInformation) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->MobilityInformation_present = true; + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message E_RABInformationList STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabinformationlist( + LIBLTE_S1AP_MESSAGE_E_RABINFORMATIONLIST_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("E-RABInformationListIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 1; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - E_RABInformationListItem + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_e_rabinformationlistitem(&msg->E_RABInformationListItem, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_E_RABINFORMATIONLISTITEM, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabinformationlist( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_E_RABINFORMATIONLIST_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("E-RABInformationListIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iE_RABInformationListItem) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message LastVisitedEUTRANCellInformation_Ext STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_lastvisitedeutrancellinformation_ext( + LIBLTE_S1AP_MESSAGE_LASTVISITEDEUTRANCELLINFORMATION_EXT_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("LastVisitedEUTRANCellInformation-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 2; + if(!msg->Time_UE_StayedInCell_EnhancedGranularity_present) + n_ie--; + if(!msg->HO_Cause_present) + n_ie--; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - Time_UE_StayedInCell_EnhancedGranularity + if(msg->Time_UE_StayedInCell_EnhancedGranularity_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_time_ue_stayedincell_enhancedgranularity(&msg->Time_UE_StayedInCell_EnhancedGranularity, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_TIME_UE_STAYEDINCELL_ENHANCEDGRANULARITY, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - HO_Cause + if(msg->HO_Cause_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_cause(&msg->HO_Cause, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_HO_CAUSE, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_lastvisitedeutrancellinformation_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_LASTVISITEDEUTRANCELLINFORMATION_EXT_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + msg->Time_UE_StayedInCell_EnhancedGranularity_present = false; + msg->HO_Cause_present = false; + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("LastVisitedEUTRANCellInformation-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iTime_UE_StayedInCell_EnhancedGranularity) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->Time_UE_StayedInCell_EnhancedGranularity_present = true; + } else if(LIBLTE_S1AP_IE_ID_HO_CAUSE == ie_id) { + if(liblte_s1ap_unpack_cause(ptr, &msg->HO_Cause) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->HO_Cause_present = true; + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message SONInformationReply_Ext STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_soninformationreply_ext( + LIBLTE_S1AP_MESSAGE_SONINFORMATIONREPLY_EXT_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("SONInformationReply-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 1; + if(!msg->Time_Synchronization_Info_present) + n_ie--; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - Time_Synchronization_Info + if(msg->Time_Synchronization_Info_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_timesynchronizationinfo(&msg->Time_Synchronization_Info, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_TIME_SYNCHRONIZATION_INFO, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_soninformationreply_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_SONINFORMATIONREPLY_EXT_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + msg->Time_Synchronization_Info_present = false; + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("SONInformationReply-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iTime_Synchronization_Info) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->Time_Synchronization_Info_present = true; + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message Bearers_SubjectToStatusTransfer_ItemExt STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_bearers_subjecttostatustransfer_itemext( + LIBLTE_S1AP_MESSAGE_BEARERS_SUBJECTTOSTATUSTRANSFER_ITEMEXT_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("Bearers-SubjectToStatusTransfer-ItemExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 3; + if(!msg->ULCOUNTValueExtended_present) + n_ie--; + if(!msg->DLCOUNTValueExtended_present) + n_ie--; + if(!msg->ReceiveStatusOfULPDCPSDUsExtended_present) + n_ie--; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - ULCOUNTValueExtended + if(msg->ULCOUNTValueExtended_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_countvalueextended(&msg->ULCOUNTValueExtended, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_ULCOUNTVALUEEXTENDED, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - DLCOUNTValueExtended + if(msg->DLCOUNTValueExtended_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_countvalueextended(&msg->DLCOUNTValueExtended, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_DLCOUNTVALUEEXTENDED, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - ReceiveStatusOfULPDCPSDUsExtended + if(msg->ReceiveStatusOfULPDCPSDUsExtended_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_receivestatusofulpdcpsdusextended(&msg->ReceiveStatusOfULPDCPSDUsExtended, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_RECEIVESTATUSOFULPDCPSDUSEXTENDED, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_bearers_subjecttostatustransfer_itemext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_BEARERS_SUBJECTTOSTATUSTRANSFER_ITEMEXT_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + msg->ULCOUNTValueExtended_present = false; + msg->DLCOUNTValueExtended_present = false; + msg->ReceiveStatusOfULPDCPSDUsExtended_present = false; + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("Bearers-SubjectToStatusTransfer-ItemExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iULCOUNTValueExtended) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->ULCOUNTValueExtended_present = true; + } else if(LIBLTE_S1AP_IE_ID_DLCOUNTVALUEEXTENDED == ie_id) { + if(liblte_s1ap_unpack_countvalueextended(ptr, &msg->DLCOUNTValueExtended) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->DLCOUNTValueExtended_present = true; + } else if(LIBLTE_S1AP_IE_ID_RECEIVESTATUSOFULPDCPSDUSEXTENDED == ie_id) { + if(liblte_s1ap_unpack_receivestatusofulpdcpsdusextended(ptr, &msg->ReceiveStatusOfULPDCPSDUsExtended) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->ReceiveStatusOfULPDCPSDUsExtended_present = true; + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message E_RABItem STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabitem( + LIBLTE_S1AP_MESSAGE_E_RABITEM_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("E-RABItemIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 1; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - E_RABItem + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_e_rabitem(&msg->E_RABItem, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_E_RABITEM, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabitem( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_E_RABITEM_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("E-RABItemIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iE_RABItem) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message MDT_Configuration_Ext STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_mdt_configuration_ext( + LIBLTE_S1AP_MESSAGE_MDT_CONFIGURATION_EXT_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("MDT-Configuration-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 1; + if(!msg->SignallingBasedMDTPLMNList_present) + n_ie--; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - SignallingBasedMDTPLMNList + if(msg->SignallingBasedMDTPLMNList_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_mdtplmnlist(&msg->SignallingBasedMDTPLMNList, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_SIGNALLINGBASEDMDTPLMNLIST, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_mdt_configuration_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_MDT_CONFIGURATION_EXT_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + msg->SignallingBasedMDTPLMNList_present = false; + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("MDT-Configuration-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iSignallingBasedMDTPLMNList) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->SignallingBasedMDTPLMNList_present = true; + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message X2TNLConfigurationInfo_Ext STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_x2tnlconfigurationinfo_ext( + LIBLTE_S1AP_MESSAGE_X2TNLCONFIGURATIONINFO_EXT_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("X2TNLConfigurationInfo-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 1; + if(!msg->eNBX2ExtendedTransportLayerAddresses_present) + n_ie--; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - eNBX2ExtendedTransportLayerAddresses + if(msg->eNBX2ExtendedTransportLayerAddresses_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_enbx2exttlas(&msg->eNBX2ExtendedTransportLayerAddresses, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_ENBX2EXTENDEDTRANSPORTLAYERADDRESSES, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_x2tnlconfigurationinfo_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_X2TNLCONFIGURATIONINFO_EXT_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + msg->eNBX2ExtendedTransportLayerAddresses_present = false; + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("X2TNLConfigurationInfo-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;ieNBX2ExtendedTransportLayerAddresses) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->eNBX2ExtendedTransportLayerAddresses_present = true; + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message Bearers_SubjectToStatusTransfer_Item STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_bearers_subjecttostatustransfer_item( + LIBLTE_S1AP_MESSAGE_BEARERS_SUBJECTTOSTATUSTRANSFER_ITEM_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("Bearers-SubjectToStatusTransfer-ItemIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 1; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - Bearers_SubjectToStatusTransfer_Item + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_bearers_subjecttostatustransfer_item(&msg->Bearers_SubjectToStatusTransfer_Item, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_BEARERS_SUBJECTTOSTATUSTRANSFER_ITEM, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_bearers_subjecttostatustransfer_item( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_BEARERS_SUBJECTTOSTATUSTRANSFER_ITEM_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("Bearers-SubjectToStatusTransfer-ItemIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iBearers_SubjectToStatusTransfer_Item) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message ImmediateMDT_Ext STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_immediatemdt_ext( + LIBLTE_S1AP_MESSAGE_IMMEDIATEMDT_EXT_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("ImmediateMDT-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 4; + if(!msg->M3Configuration_present) + n_ie--; + if(!msg->M4Configuration_present) + n_ie--; + if(!msg->M5Configuration_present) + n_ie--; + if(!msg->MDT_Location_Info_present) + n_ie--; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - M3Configuration + if(msg->M3Configuration_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_m3configuration(&msg->M3Configuration, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_M3CONFIGURATION, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - M4Configuration + if(msg->M4Configuration_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_m4configuration(&msg->M4Configuration, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_M4CONFIGURATION, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - M5Configuration + if(msg->M5Configuration_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_m5configuration(&msg->M5Configuration, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_M5CONFIGURATION, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - MDT_Location_Info + if(msg->MDT_Location_Info_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_mdt_location_info(&msg->MDT_Location_Info, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_MDT_LOCATION_INFO, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_immediatemdt_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_IMMEDIATEMDT_EXT_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + msg->M3Configuration_present = false; + msg->M4Configuration_present = false; + msg->M5Configuration_present = false; + msg->MDT_Location_Info_present = false; + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("ImmediateMDT-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iM3Configuration) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_M4CONFIGURATION == ie_id) { + if(liblte_s1ap_unpack_m4configuration(ptr, &msg->M4Configuration) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_M5CONFIGURATION == ie_id) { + if(liblte_s1ap_unpack_m5configuration(ptr, &msg->M5Configuration) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_MDT_LOCATION_INFO == ie_id) { + if(liblte_s1ap_unpack_mdt_location_info(ptr, &msg->MDT_Location_Info) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->MDT_Location_Info_present = true; + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message SONConfigurationTransfer_Ext STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_sonconfigurationtransfer_ext( + LIBLTE_S1AP_MESSAGE_SONCONFIGURATIONTRANSFER_EXT_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("SONConfigurationTransfer-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 1; + if(!msg->x2TNLConfigurationInfo_present) + n_ie--; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - x2TNLConfigurationInfo + if(msg->x2TNLConfigurationInfo_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_x2tnlconfigurationinfo(&msg->x2TNLConfigurationInfo, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_X2TNLCONFIGURATIONINFO, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_sonconfigurationtransfer_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_SONCONFIGURATIONTRANSFER_EXT_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + msg->x2TNLConfigurationInfo_present = false; + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("SONConfigurationTransfer-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;ix2TNLConfigurationInfo) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message TraceActivation_Ext STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_traceactivation_ext( + LIBLTE_S1AP_MESSAGE_TRACEACTIVATION_EXT_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("TraceActivation-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 1; + if(!msg->MDTConfiguration_present) + n_ie--; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - MDTConfiguration + if(msg->MDTConfiguration_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_mdt_configuration(&msg->MDTConfiguration, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_MDTCONFIGURATION, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_traceactivation_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_TRACEACTIVATION_EXT_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + msg->MDTConfiguration_present = false; + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("TraceActivation-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iMDTConfiguration) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->MDTConfiguration_present = true; + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message HandoverRequired STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_handoverrequired( + LIBLTE_S1AP_MESSAGE_HANDOVERREQUIRED_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("HandoverRequiredIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 14; + if(!msg->Direct_Forwarding_Path_Availability_present) + n_ie--; + if(!msg->SRVCCHOIndication_present) + n_ie--; + if(!msg->Source_ToTarget_TransparentContainer_Secondary_present) + n_ie--; + if(!msg->MSClassmark2_present) + n_ie--; + if(!msg->MSClassmark3_present) + n_ie--; + if(!msg->CSG_Id_present) + n_ie--; + if(!msg->CellAccessMode_present) + n_ie--; + if(!msg->PS_ServiceNotAvailable_present) + n_ie--; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - MME_UE_S1AP_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_mme_ue_s1ap_id(&msg->MME_UE_S1AP_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_MME_UE_S1AP_ID, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - eNB_UE_S1AP_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_enb_ue_s1ap_id(&msg->eNB_UE_S1AP_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_ENB_UE_S1AP_ID, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - HandoverType + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_handovertype(&msg->HandoverType, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_HANDOVERTYPE, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - Cause + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_cause(&msg->Cause, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_CAUSE, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - TargetID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_targetid(&msg->TargetID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_TARGETID, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - Direct_Forwarding_Path_Availability + if(msg->Direct_Forwarding_Path_Availability_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_direct_forwarding_path_availability(&msg->Direct_Forwarding_Path_Availability, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_DIRECT_FORWARDING_PATH_AVAILABILITY, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - SRVCCHOIndication + if(msg->SRVCCHOIndication_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_srvcchoindication(&msg->SRVCCHOIndication, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_SRVCCHOINDICATION, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - Source_ToTarget_TransparentContainer + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_source_totarget_transparentcontainer(&msg->Source_ToTarget_TransparentContainer, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_SOURCE_TOTARGET_TRANSPARENTCONTAINER, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - Source_ToTarget_TransparentContainer_Secondary + if(msg->Source_ToTarget_TransparentContainer_Secondary_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_source_totarget_transparentcontainer(&msg->Source_ToTarget_TransparentContainer_Secondary, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_SOURCE_TOTARGET_TRANSPARENTCONTAINER_SECONDARY, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - MSClassmark2 + if(msg->MSClassmark2_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_msclassmark2(&msg->MSClassmark2, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_MSCLASSMARK2, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - MSClassmark3 + if(msg->MSClassmark3_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_msclassmark3(&msg->MSClassmark3, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_MSCLASSMARK3, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - CSG_Id + if(msg->CSG_Id_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_csg_id(&msg->CSG_Id, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_CSG_ID, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - CellAccessMode + if(msg->CellAccessMode_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_cellaccessmode(&msg->CellAccessMode, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_CELLACCESSMODE, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - PS_ServiceNotAvailable + if(msg->PS_ServiceNotAvailable_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_ps_servicenotavailable(&msg->PS_ServiceNotAvailable, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_PS_SERVICENOTAVAILABLE, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_handoverrequired( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_HANDOVERREQUIRED_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + msg->Direct_Forwarding_Path_Availability_present = false; + msg->SRVCCHOIndication_present = false; + msg->Source_ToTarget_TransparentContainer_Secondary_present = false; + msg->MSClassmark2_present = false; + msg->MSClassmark3_present = false; + msg->CSG_Id_present = false; + msg->CellAccessMode_present = false; + msg->PS_ServiceNotAvailable_present = false; + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("HandoverRequiredIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iMME_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_ENB_UE_S1AP_ID == ie_id) { + if(liblte_s1ap_unpack_enb_ue_s1ap_id(ptr, &msg->eNB_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_HANDOVERTYPE == ie_id) { + if(liblte_s1ap_unpack_handovertype(ptr, &msg->HandoverType) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_CAUSE == ie_id) { + if(liblte_s1ap_unpack_cause(ptr, &msg->Cause) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_TARGETID == ie_id) { + if(liblte_s1ap_unpack_targetid(ptr, &msg->TargetID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_DIRECT_FORWARDING_PATH_AVAILABILITY == ie_id) { + if(liblte_s1ap_unpack_direct_forwarding_path_availability(ptr, &msg->Direct_Forwarding_Path_Availability) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->Direct_Forwarding_Path_Availability_present = true; + } else if(LIBLTE_S1AP_IE_ID_SRVCCHOINDICATION == ie_id) { + if(liblte_s1ap_unpack_srvcchoindication(ptr, &msg->SRVCCHOIndication) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->SRVCCHOIndication_present = true; + } else if(LIBLTE_S1AP_IE_ID_SOURCE_TOTARGET_TRANSPARENTCONTAINER == ie_id) { + if(liblte_s1ap_unpack_source_totarget_transparentcontainer(ptr, &msg->Source_ToTarget_TransparentContainer) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_SOURCE_TOTARGET_TRANSPARENTCONTAINER_SECONDARY == ie_id) { + if(liblte_s1ap_unpack_source_totarget_transparentcontainer(ptr, &msg->Source_ToTarget_TransparentContainer_Secondary) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->Source_ToTarget_TransparentContainer_Secondary_present = true; + } else if(LIBLTE_S1AP_IE_ID_MSCLASSMARK2 == ie_id) { + if(liblte_s1ap_unpack_msclassmark2(ptr, &msg->MSClassmark2) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_MSCLASSMARK3 == ie_id) { + if(liblte_s1ap_unpack_msclassmark3(ptr, &msg->MSClassmark3) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_CSG_ID == ie_id) { + if(liblte_s1ap_unpack_csg_id(ptr, &msg->CSG_Id) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->CSG_Id_present = true; + } else if(LIBLTE_S1AP_IE_ID_CELLACCESSMODE == ie_id) { + if(liblte_s1ap_unpack_cellaccessmode(ptr, &msg->CellAccessMode) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->CellAccessMode_present = true; + } else if(LIBLTE_S1AP_IE_ID_PS_SERVICENOTAVAILABLE == ie_id) { + if(liblte_s1ap_unpack_ps_servicenotavailable(ptr, &msg->PS_ServiceNotAvailable) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->PS_ServiceNotAvailable_present = true; + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message E_RABDataForwardingItem_Ext STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabdataforwardingitem_ext( + LIBLTE_S1AP_MESSAGE_E_RABDATAFORWARDINGITEM_EXT_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("E-RABDataForwardingItem-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 0; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabdataforwardingitem_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_E_RABDATAFORWARDINGITEM_EXT_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("E-RABDataForwardingItem-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message HandoverPreparationFailure STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_handoverpreparationfailure( + LIBLTE_S1AP_MESSAGE_HANDOVERPREPARATIONFAILURE_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("HandoverPreparationFailureIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 4; + if(!msg->CriticalityDiagnostics_present) + n_ie--; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - MME_UE_S1AP_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_mme_ue_s1ap_id(&msg->MME_UE_S1AP_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_MME_UE_S1AP_ID, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - eNB_UE_S1AP_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_enb_ue_s1ap_id(&msg->eNB_UE_S1AP_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_ENB_UE_S1AP_ID, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - Cause + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_cause(&msg->Cause, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_CAUSE, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - CriticalityDiagnostics + if(msg->CriticalityDiagnostics_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_criticalitydiagnostics(&msg->CriticalityDiagnostics, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_CRITICALITYDIAGNOSTICS, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_handoverpreparationfailure( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_HANDOVERPREPARATIONFAILURE_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + msg->CriticalityDiagnostics_present = false; + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("HandoverPreparationFailureIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iMME_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_ENB_UE_S1AP_ID == ie_id) { + if(liblte_s1ap_unpack_enb_ue_s1ap_id(ptr, &msg->eNB_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_CAUSE == ie_id) { + if(liblte_s1ap_unpack_cause(ptr, &msg->Cause) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_CRITICALITYDIAGNOSTICS == ie_id) { + if(liblte_s1ap_unpack_criticalitydiagnostics(ptr, &msg->CriticalityDiagnostics) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->CriticalityDiagnostics_present = true; + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message E_RABToBeSetupItemHOReq_Ext STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabtobesetupitemhoreq_ext( + LIBLTE_S1AP_MESSAGE_E_RABTOBESETUPITEMHOREQ_EXT_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("E-RABToBeSetupItemHOReq-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 1; + if(!msg->Data_Forwarding_Not_Possible_present) + n_ie--; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - Data_Forwarding_Not_Possible + if(msg->Data_Forwarding_Not_Possible_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_data_forwarding_not_possible(&msg->Data_Forwarding_Not_Possible, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_DATA_FORWARDING_NOT_POSSIBLE, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabtobesetupitemhoreq_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_E_RABTOBESETUPITEMHOREQ_EXT_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + msg->Data_Forwarding_Not_Possible_present = false; + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("E-RABToBeSetupItemHOReq-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iData_Forwarding_Not_Possible) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->Data_Forwarding_Not_Possible_present = true; + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message E_RABAdmittedItem_Ext STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabadmitteditem_ext( + LIBLTE_S1AP_MESSAGE_E_RABADMITTEDITEM_EXT_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("E-RABAdmittedItem-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 0; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabadmitteditem_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_E_RABADMITTEDITEM_EXT_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("E-RABAdmittedItem-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message E_RABFailedToSetupItemHOReqAckExt STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabfailedtosetupitemhoreqackext( + LIBLTE_S1AP_MESSAGE_E_RABFAILEDTOSETUPITEMHOREQACKEXT_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("E-RABFailedToSetupItemHOReqAckExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 0; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabfailedtosetupitemhoreqackext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_E_RABFAILEDTOSETUPITEMHOREQACKEXT_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("E-RABFailedToSetupItemHOReqAckExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message HandoverFailure STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_handoverfailure( + LIBLTE_S1AP_MESSAGE_HANDOVERFAILURE_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("HandoverFailureIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 3; + if(!msg->CriticalityDiagnostics_present) + n_ie--; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - MME_UE_S1AP_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_mme_ue_s1ap_id(&msg->MME_UE_S1AP_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_MME_UE_S1AP_ID, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - Cause + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_cause(&msg->Cause, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_CAUSE, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - CriticalityDiagnostics + if(msg->CriticalityDiagnostics_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_criticalitydiagnostics(&msg->CriticalityDiagnostics, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_CRITICALITYDIAGNOSTICS, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_handoverfailure( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_HANDOVERFAILURE_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + msg->CriticalityDiagnostics_present = false; + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("HandoverFailureIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iMME_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_CAUSE == ie_id) { + if(liblte_s1ap_unpack_cause(ptr, &msg->Cause) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_CRITICALITYDIAGNOSTICS == ie_id) { + if(liblte_s1ap_unpack_criticalitydiagnostics(ptr, &msg->CriticalityDiagnostics) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->CriticalityDiagnostics_present = true; + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message HandoverNotify STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_handovernotify( + LIBLTE_S1AP_MESSAGE_HANDOVERNOTIFY_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("HandoverNotifyIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 6; + if(!msg->Tunnel_Information_for_BBF_present) + n_ie--; + if(!msg->LHN_ID_present) + n_ie--; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - MME_UE_S1AP_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_mme_ue_s1ap_id(&msg->MME_UE_S1AP_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_MME_UE_S1AP_ID, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - eNB_UE_S1AP_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_enb_ue_s1ap_id(&msg->eNB_UE_S1AP_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_ENB_UE_S1AP_ID, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - EUTRAN_CGI + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_eutran_cgi(&msg->EUTRAN_CGI, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_EUTRAN_CGI, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - TAI + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_tai(&msg->TAI, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_TAI, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - Tunnel_Information_for_BBF + if(msg->Tunnel_Information_for_BBF_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_tunnelinformation(&msg->Tunnel_Information_for_BBF, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_TUNNEL_INFORMATION_FOR_BBF, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - LHN_ID + if(msg->LHN_ID_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_lhn_id(&msg->LHN_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_LHN_ID, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_handovernotify( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_HANDOVERNOTIFY_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + msg->Tunnel_Information_for_BBF_present = false; + msg->LHN_ID_present = false; + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("HandoverNotifyIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iMME_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_ENB_UE_S1AP_ID == ie_id) { + if(liblte_s1ap_unpack_enb_ue_s1ap_id(ptr, &msg->eNB_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_EUTRAN_CGI == ie_id) { + if(liblte_s1ap_unpack_eutran_cgi(ptr, &msg->EUTRAN_CGI) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_TAI == ie_id) { + if(liblte_s1ap_unpack_tai(ptr, &msg->TAI) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_TUNNEL_INFORMATION_FOR_BBF == ie_id) { + if(liblte_s1ap_unpack_tunnelinformation(ptr, &msg->Tunnel_Information_for_BBF) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->Tunnel_Information_for_BBF_present = true; + } else if(LIBLTE_S1AP_IE_ID_LHN_ID == ie_id) { + if(liblte_s1ap_unpack_lhn_id(ptr, &msg->LHN_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->LHN_ID_present = true; + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message E_RABToBeSwitchedDLItem_Ext STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabtobeswitcheddlitem_ext( + LIBLTE_S1AP_MESSAGE_E_RABTOBESWITCHEDDLITEM_EXT_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("E-RABToBeSwitchedDLItem-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 0; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabtobeswitcheddlitem_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_E_RABTOBESWITCHEDDLITEM_EXT_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("E-RABToBeSwitchedDLItem-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message E_RABToBeSwitchedULItem_Ext STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabtobeswitchedulitem_ext( + LIBLTE_S1AP_MESSAGE_E_RABTOBESWITCHEDULITEM_EXT_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("E-RABToBeSwitchedULItem-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 0; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabtobeswitchedulitem_ext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_E_RABTOBESWITCHEDULITEM_EXT_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("E-RABToBeSwitchedULItem-ExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message PathSwitchRequestFailure STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_pathswitchrequestfailure( + LIBLTE_S1AP_MESSAGE_PATHSWITCHREQUESTFAILURE_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("PathSwitchRequestFailureIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 4; + if(!msg->CriticalityDiagnostics_present) + n_ie--; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - MME_UE_S1AP_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_mme_ue_s1ap_id(&msg->MME_UE_S1AP_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_MME_UE_S1AP_ID, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - eNB_UE_S1AP_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_enb_ue_s1ap_id(&msg->eNB_UE_S1AP_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_ENB_UE_S1AP_ID, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - Cause + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_cause(&msg->Cause, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_CAUSE, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - CriticalityDiagnostics + if(msg->CriticalityDiagnostics_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_criticalitydiagnostics(&msg->CriticalityDiagnostics, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_CRITICALITYDIAGNOSTICS, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_pathswitchrequestfailure( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_PATHSWITCHREQUESTFAILURE_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + msg->CriticalityDiagnostics_present = false; + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("PathSwitchRequestFailureIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iMME_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_ENB_UE_S1AP_ID == ie_id) { + if(liblte_s1ap_unpack_enb_ue_s1ap_id(ptr, &msg->eNB_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_CAUSE == ie_id) { + if(liblte_s1ap_unpack_cause(ptr, &msg->Cause) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_CRITICALITYDIAGNOSTICS == ie_id) { + if(liblte_s1ap_unpack_criticalitydiagnostics(ptr, &msg->CriticalityDiagnostics) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->CriticalityDiagnostics_present = true; + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message HandoverCancel STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_handovercancel( + LIBLTE_S1AP_MESSAGE_HANDOVERCANCEL_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("HandoverCancelIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 3; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - MME_UE_S1AP_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_mme_ue_s1ap_id(&msg->MME_UE_S1AP_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_MME_UE_S1AP_ID, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - eNB_UE_S1AP_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_enb_ue_s1ap_id(&msg->eNB_UE_S1AP_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_ENB_UE_S1AP_ID, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - Cause + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_cause(&msg->Cause, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_CAUSE, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_handovercancel( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_HANDOVERCANCEL_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("HandoverCancelIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iMME_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_ENB_UE_S1AP_ID == ie_id) { + if(liblte_s1ap_unpack_enb_ue_s1ap_id(ptr, &msg->eNB_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_CAUSE == ie_id) { + if(liblte_s1ap_unpack_cause(ptr, &msg->Cause) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message HandoverCancelAcknowledge STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_handovercancelacknowledge( + LIBLTE_S1AP_MESSAGE_HANDOVERCANCELACKNOWLEDGE_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("HandoverCancelAcknowledgeIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 3; + if(!msg->CriticalityDiagnostics_present) + n_ie--; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - MME_UE_S1AP_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_mme_ue_s1ap_id(&msg->MME_UE_S1AP_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_MME_UE_S1AP_ID, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - eNB_UE_S1AP_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_enb_ue_s1ap_id(&msg->eNB_UE_S1AP_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_ENB_UE_S1AP_ID, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - CriticalityDiagnostics + if(msg->CriticalityDiagnostics_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_criticalitydiagnostics(&msg->CriticalityDiagnostics, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_CRITICALITYDIAGNOSTICS, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_handovercancelacknowledge( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_HANDOVERCANCELACKNOWLEDGE_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + msg->CriticalityDiagnostics_present = false; + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("HandoverCancelAcknowledgeIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iMME_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_ENB_UE_S1AP_ID == ie_id) { + if(liblte_s1ap_unpack_enb_ue_s1ap_id(ptr, &msg->eNB_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_CRITICALITYDIAGNOSTICS == ie_id) { + if(liblte_s1ap_unpack_criticalitydiagnostics(ptr, &msg->CriticalityDiagnostics) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->CriticalityDiagnostics_present = true; + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message E_RABToBeSetupItemBearerSUReqExt STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabtobesetupitembearersureqext( + LIBLTE_S1AP_MESSAGE_E_RABTOBESETUPITEMBEARERSUREQEXT_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("E-RABToBeSetupItemBearerSUReqExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 2; + if(!msg->Correlation_ID_present) + n_ie--; + if(!msg->SIPTO_Correlation_ID_present) + n_ie--; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - Correlation_ID + if(msg->Correlation_ID_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_correlation_id(&msg->Correlation_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_CORRELATION_ID, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - SIPTO_Correlation_ID + if(msg->SIPTO_Correlation_ID_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_correlation_id(&msg->SIPTO_Correlation_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_SIPTO_CORRELATION_ID, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabtobesetupitembearersureqext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_E_RABTOBESETUPITEMBEARERSUREQEXT_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + msg->Correlation_ID_present = false; + msg->SIPTO_Correlation_ID_present = false; + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("E-RABToBeSetupItemBearerSUReqExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iCorrelation_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->Correlation_ID_present = true; + } else if(LIBLTE_S1AP_IE_ID_SIPTO_CORRELATION_ID == ie_id) { + if(liblte_s1ap_unpack_correlation_id(ptr, &msg->SIPTO_Correlation_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->SIPTO_Correlation_ID_present = true; + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message E_RABSetupItemBearerSUResExt STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabsetupitembearersuresext( + LIBLTE_S1AP_MESSAGE_E_RABSETUPITEMBEARERSURESEXT_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("E-RABSetupItemBearerSUResExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 0; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabsetupitembearersuresext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_E_RABSETUPITEMBEARERSURESEXT_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("E-RABSetupItemBearerSUResExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message E_RABToBeModifyItemBearerModReqExt STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabtobemodifyitembearermodreqext( + LIBLTE_S1AP_MESSAGE_E_RABTOBEMODIFYITEMBEARERMODREQEXT_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("E-RABToBeModifyItemBearerModReqExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 1; + if(!msg->TransportInformation_present) + n_ie--; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - TransportInformation + if(msg->TransportInformation_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_transportinformation(&msg->TransportInformation, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_TRANSPORTINFORMATION, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabtobemodifyitembearermodreqext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_E_RABTOBEMODIFYITEMBEARERMODREQEXT_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + msg->TransportInformation_present = false; + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("E-RABToBeModifyItemBearerModReqExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iTransportInformation) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->TransportInformation_present = true; + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message E_RABModifyItemBearerModResExt STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabmodifyitembearermodresext( + LIBLTE_S1AP_MESSAGE_E_RABMODIFYITEMBEARERMODRESEXT_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("E-RABModifyItemBearerModResExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 0; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabmodifyitembearermodresext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_E_RABMODIFYITEMBEARERMODRESEXT_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("E-RABModifyItemBearerModResExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message E_RABReleaseCommand STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabreleasecommand( + LIBLTE_S1AP_MESSAGE_E_RABRELEASECOMMAND_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("E-RABReleaseCommandIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 5; + if(!msg->uEaggregateMaximumBitrate_present) + n_ie--; + if(!msg->NAS_PDU_present) + n_ie--; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - MME_UE_S1AP_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_mme_ue_s1ap_id(&msg->MME_UE_S1AP_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_MME_UE_S1AP_ID, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - eNB_UE_S1AP_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_enb_ue_s1ap_id(&msg->eNB_UE_S1AP_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_ENB_UE_S1AP_ID, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - uEaggregateMaximumBitrate + if(msg->uEaggregateMaximumBitrate_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_ueaggregatemaximumbitrate(&msg->uEaggregateMaximumBitrate, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_UEAGGREGATEMAXIMUMBITRATE, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - E_RABToBeReleasedList + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_e_rablist(&msg->E_RABToBeReleasedList, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_E_RABTOBERELEASEDLIST, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - NAS_PDU + if(msg->NAS_PDU_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_nas_pdu(&msg->NAS_PDU, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_NAS_PDU, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabreleasecommand( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_E_RABRELEASECOMMAND_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + msg->uEaggregateMaximumBitrate_present = false; + msg->NAS_PDU_present = false; + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("E-RABReleaseCommandIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iMME_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_ENB_UE_S1AP_ID == ie_id) { + if(liblte_s1ap_unpack_enb_ue_s1ap_id(ptr, &msg->eNB_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_UEAGGREGATEMAXIMUMBITRATE == ie_id) { + if(liblte_s1ap_unpack_ueaggregatemaximumbitrate(ptr, &msg->uEaggregateMaximumBitrate) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->uEaggregateMaximumBitrate_present = true; + } else if(LIBLTE_S1AP_IE_ID_E_RABTOBERELEASEDLIST == ie_id) { + if(liblte_s1ap_unpack_e_rablist(ptr, &msg->E_RABToBeReleasedList) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_NAS_PDU == ie_id) { + if(liblte_s1ap_unpack_nas_pdu(ptr, &msg->NAS_PDU) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->NAS_PDU_present = true; + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message E_RABReleaseItemBearerRelCompExt STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabreleaseitembearerrelcompext( + LIBLTE_S1AP_MESSAGE_E_RABRELEASEITEMBEARERRELCOMPEXT_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("E-RABReleaseItemBearerRelCompExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 0; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabreleaseitembearerrelcompext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_E_RABRELEASEITEMBEARERRELCOMPEXT_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("E-RABReleaseItemBearerRelCompExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message E_RABReleaseIndication STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabreleaseindication( + LIBLTE_S1AP_MESSAGE_E_RABRELEASEINDICATION_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("E-RABReleaseIndicationIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 4; + if(!msg->UserLocationInformation_present) + n_ie--; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - MME_UE_S1AP_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_mme_ue_s1ap_id(&msg->MME_UE_S1AP_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_MME_UE_S1AP_ID, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - eNB_UE_S1AP_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_enb_ue_s1ap_id(&msg->eNB_UE_S1AP_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_ENB_UE_S1AP_ID, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - E_RABReleasedList + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_e_rablist(&msg->E_RABReleasedList, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_E_RABRELEASEDLIST, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - UserLocationInformation + if(msg->UserLocationInformation_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_userlocationinformation(&msg->UserLocationInformation, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_USERLOCATIONINFORMATION, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabreleaseindication( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_E_RABRELEASEINDICATION_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + msg->UserLocationInformation_present = false; + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("E-RABReleaseIndicationIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iMME_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_ENB_UE_S1AP_ID == ie_id) { + if(liblte_s1ap_unpack_enb_ue_s1ap_id(ptr, &msg->eNB_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_E_RABRELEASEDLIST == ie_id) { + if(liblte_s1ap_unpack_e_rablist(ptr, &msg->E_RABReleasedList) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_USERLOCATIONINFORMATION == ie_id) { + if(liblte_s1ap_unpack_userlocationinformation(ptr, &msg->UserLocationInformation) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->UserLocationInformation_present = true; + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message E_RABToBeSetupItemCtxtSUReqExt STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabtobesetupitemctxtsureqext( + LIBLTE_S1AP_MESSAGE_E_RABTOBESETUPITEMCTXTSUREQEXT_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("E-RABToBeSetupItemCtxtSUReqExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 2; + if(!msg->Correlation_ID_present) + n_ie--; + if(!msg->SIPTO_Correlation_ID_present) + n_ie--; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - Correlation_ID + if(msg->Correlation_ID_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_correlation_id(&msg->Correlation_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_CORRELATION_ID, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - SIPTO_Correlation_ID + if(msg->SIPTO_Correlation_ID_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_correlation_id(&msg->SIPTO_Correlation_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_SIPTO_CORRELATION_ID, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabtobesetupitemctxtsureqext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_E_RABTOBESETUPITEMCTXTSUREQEXT_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + msg->Correlation_ID_present = false; + msg->SIPTO_Correlation_ID_present = false; + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("E-RABToBeSetupItemCtxtSUReqExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iCorrelation_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->Correlation_ID_present = true; + } else if(LIBLTE_S1AP_IE_ID_SIPTO_CORRELATION_ID == ie_id) { + if(liblte_s1ap_unpack_correlation_id(ptr, &msg->SIPTO_Correlation_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->SIPTO_Correlation_ID_present = true; + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message E_RABSetupItemCtxtSUResExt STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabsetupitemctxtsuresext( + LIBLTE_S1AP_MESSAGE_E_RABSETUPITEMCTXTSURESEXT_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("E-RABSetupItemCtxtSUResExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 0; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabsetupitemctxtsuresext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_E_RABSETUPITEMCTXTSURESEXT_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("E-RABSetupItemCtxtSUResExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message InitialContextSetupFailure STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_initialcontextsetupfailure( + LIBLTE_S1AP_MESSAGE_INITIALCONTEXTSETUPFAILURE_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("InitialContextSetupFailureIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 4; + if(!msg->CriticalityDiagnostics_present) + n_ie--; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - MME_UE_S1AP_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_mme_ue_s1ap_id(&msg->MME_UE_S1AP_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_MME_UE_S1AP_ID, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - eNB_UE_S1AP_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_enb_ue_s1ap_id(&msg->eNB_UE_S1AP_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_ENB_UE_S1AP_ID, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - Cause + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_cause(&msg->Cause, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_CAUSE, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - CriticalityDiagnostics + if(msg->CriticalityDiagnostics_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_criticalitydiagnostics(&msg->CriticalityDiagnostics, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_CRITICALITYDIAGNOSTICS, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_initialcontextsetupfailure( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_INITIALCONTEXTSETUPFAILURE_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + msg->CriticalityDiagnostics_present = false; + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("InitialContextSetupFailureIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iMME_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_ENB_UE_S1AP_ID == ie_id) { + if(liblte_s1ap_unpack_enb_ue_s1ap_id(ptr, &msg->eNB_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_CAUSE == ie_id) { + if(liblte_s1ap_unpack_cause(ptr, &msg->Cause) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_CRITICALITYDIAGNOSTICS == ie_id) { + if(liblte_s1ap_unpack_criticalitydiagnostics(ptr, &msg->CriticalityDiagnostics) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->CriticalityDiagnostics_present = true; + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message TAIItemExt STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_taiitemext( + LIBLTE_S1AP_MESSAGE_TAIITEMEXT_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("TAIItemExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 0; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_taiitemext( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_TAIITEMEXT_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("TAIItemExtIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message UEContextReleaseRequest STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_uecontextreleaserequest( + LIBLTE_S1AP_MESSAGE_UECONTEXTRELEASEREQUEST_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("UEContextReleaseRequest-IEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 4; + if(!msg->GWContextReleaseIndication_present) + n_ie--; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - MME_UE_S1AP_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_mme_ue_s1ap_id(&msg->MME_UE_S1AP_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_MME_UE_S1AP_ID, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - eNB_UE_S1AP_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_enb_ue_s1ap_id(&msg->eNB_UE_S1AP_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_ENB_UE_S1AP_ID, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - Cause + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_cause(&msg->Cause, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_CAUSE, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - GWContextReleaseIndication + if(msg->GWContextReleaseIndication_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_gwcontextreleaseindication(&msg->GWContextReleaseIndication, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_GWCONTEXTRELEASEINDICATION, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_uecontextreleaserequest( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_UECONTEXTRELEASEREQUEST_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + msg->GWContextReleaseIndication_present = false; + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("UEContextReleaseRequest-IEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iMME_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_ENB_UE_S1AP_ID == ie_id) { + if(liblte_s1ap_unpack_enb_ue_s1ap_id(ptr, &msg->eNB_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_CAUSE == ie_id) { + if(liblte_s1ap_unpack_cause(ptr, &msg->Cause) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_GWCONTEXTRELEASEINDICATION == ie_id) { + if(liblte_s1ap_unpack_gwcontextreleaseindication(ptr, &msg->GWContextReleaseIndication) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->GWContextReleaseIndication_present = true; + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message UEContextReleaseCommand STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_uecontextreleasecommand( + LIBLTE_S1AP_MESSAGE_UECONTEXTRELEASECOMMAND_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("UEContextReleaseCommand-IEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 2; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - UE_S1AP_IDs + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_ue_s1ap_ids(&msg->UE_S1AP_IDs, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_UE_S1AP_IDS, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - Cause + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_cause(&msg->Cause, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_CAUSE, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_uecontextreleasecommand( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_UECONTEXTRELEASECOMMAND_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("UEContextReleaseCommand-IEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iUE_S1AP_IDs) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_CAUSE == ie_id) { + if(liblte_s1ap_unpack_cause(ptr, &msg->Cause) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message UEContextReleaseComplete STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_uecontextreleasecomplete( + LIBLTE_S1AP_MESSAGE_UECONTEXTRELEASECOMPLETE_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("UEContextReleaseComplete-IEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 4; + if(!msg->CriticalityDiagnostics_present) + n_ie--; + if(!msg->UserLocationInformation_present) + n_ie--; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - MME_UE_S1AP_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_mme_ue_s1ap_id(&msg->MME_UE_S1AP_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_MME_UE_S1AP_ID, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - eNB_UE_S1AP_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_enb_ue_s1ap_id(&msg->eNB_UE_S1AP_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_ENB_UE_S1AP_ID, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - CriticalityDiagnostics + if(msg->CriticalityDiagnostics_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_criticalitydiagnostics(&msg->CriticalityDiagnostics, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_CRITICALITYDIAGNOSTICS, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - UserLocationInformation + if(msg->UserLocationInformation_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_userlocationinformation(&msg->UserLocationInformation, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_USERLOCATIONINFORMATION, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_uecontextreleasecomplete( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_UECONTEXTRELEASECOMPLETE_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + msg->CriticalityDiagnostics_present = false; + msg->UserLocationInformation_present = false; + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("UEContextReleaseComplete-IEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iMME_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_ENB_UE_S1AP_ID == ie_id) { + if(liblte_s1ap_unpack_enb_ue_s1ap_id(ptr, &msg->eNB_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_CRITICALITYDIAGNOSTICS == ie_id) { + if(liblte_s1ap_unpack_criticalitydiagnostics(ptr, &msg->CriticalityDiagnostics) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->CriticalityDiagnostics_present = true; + } else if(LIBLTE_S1AP_IE_ID_USERLOCATIONINFORMATION == ie_id) { + if(liblte_s1ap_unpack_userlocationinformation(ptr, &msg->UserLocationInformation) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->UserLocationInformation_present = true; + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message UEContextModificationRequest STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_uecontextmodificationrequest( + LIBLTE_S1AP_MESSAGE_UECONTEXTMODIFICATIONREQUEST_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("UEContextModificationRequestIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 10; + if(!msg->SecurityKey_present) + n_ie--; + if(!msg->SubscriberProfileIDforRFP_present) + n_ie--; + if(!msg->uEaggregateMaximumBitrate_present) + n_ie--; + if(!msg->CSFallbackIndicator_present) + n_ie--; + if(!msg->UESecurityCapabilities_present) + n_ie--; + if(!msg->CSGMembershipStatus_present) + n_ie--; + if(!msg->RegisteredLAI_present) + n_ie--; + if(!msg->AdditionalCSFallbackIndicator_present) + n_ie--; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - MME_UE_S1AP_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_mme_ue_s1ap_id(&msg->MME_UE_S1AP_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_MME_UE_S1AP_ID, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - eNB_UE_S1AP_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_enb_ue_s1ap_id(&msg->eNB_UE_S1AP_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_ENB_UE_S1AP_ID, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - SecurityKey + if(msg->SecurityKey_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_securitykey(&msg->SecurityKey, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_SECURITYKEY, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - SubscriberProfileIDforRFP + if(msg->SubscriberProfileIDforRFP_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_subscriberprofileidforrfp(&msg->SubscriberProfileIDforRFP, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_SUBSCRIBERPROFILEIDFORRFP, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - uEaggregateMaximumBitrate + if(msg->uEaggregateMaximumBitrate_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_ueaggregatemaximumbitrate(&msg->uEaggregateMaximumBitrate, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_UEAGGREGATEMAXIMUMBITRATE, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - CSFallbackIndicator + if(msg->CSFallbackIndicator_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_csfallbackindicator(&msg->CSFallbackIndicator, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_CSFALLBACKINDICATOR, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - UESecurityCapabilities + if(msg->UESecurityCapabilities_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_uesecuritycapabilities(&msg->UESecurityCapabilities, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_UESECURITYCAPABILITIES, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - CSGMembershipStatus + if(msg->CSGMembershipStatus_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_csgmembershipstatus(&msg->CSGMembershipStatus, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_CSGMEMBERSHIPSTATUS, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - RegisteredLAI + if(msg->RegisteredLAI_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_lai(&msg->RegisteredLAI, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_REGISTEREDLAI, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - AdditionalCSFallbackIndicator + if(msg->AdditionalCSFallbackIndicator_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_additionalcsfallbackindicator(&msg->AdditionalCSFallbackIndicator, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_ADDITIONALCSFALLBACKINDICATOR, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_uecontextmodificationrequest( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_UECONTEXTMODIFICATIONREQUEST_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + msg->SecurityKey_present = false; + msg->SubscriberProfileIDforRFP_present = false; + msg->uEaggregateMaximumBitrate_present = false; + msg->CSFallbackIndicator_present = false; + msg->UESecurityCapabilities_present = false; + msg->CSGMembershipStatus_present = false; + msg->RegisteredLAI_present = false; + msg->AdditionalCSFallbackIndicator_present = false; + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("UEContextModificationRequestIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iMME_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_ENB_UE_S1AP_ID == ie_id) { + if(liblte_s1ap_unpack_enb_ue_s1ap_id(ptr, &msg->eNB_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_SECURITYKEY == ie_id) { + if(liblte_s1ap_unpack_securitykey(ptr, &msg->SecurityKey) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->SecurityKey_present = true; + } else if(LIBLTE_S1AP_IE_ID_SUBSCRIBERPROFILEIDFORRFP == ie_id) { + if(liblte_s1ap_unpack_subscriberprofileidforrfp(ptr, &msg->SubscriberProfileIDforRFP) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->SubscriberProfileIDforRFP_present = true; + } else if(LIBLTE_S1AP_IE_ID_UEAGGREGATEMAXIMUMBITRATE == ie_id) { + if(liblte_s1ap_unpack_ueaggregatemaximumbitrate(ptr, &msg->uEaggregateMaximumBitrate) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->uEaggregateMaximumBitrate_present = true; + } else if(LIBLTE_S1AP_IE_ID_CSFALLBACKINDICATOR == ie_id) { + if(liblte_s1ap_unpack_csfallbackindicator(ptr, &msg->CSFallbackIndicator) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->CSFallbackIndicator_present = true; + } else if(LIBLTE_S1AP_IE_ID_UESECURITYCAPABILITIES == ie_id) { + if(liblte_s1ap_unpack_uesecuritycapabilities(ptr, &msg->UESecurityCapabilities) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->UESecurityCapabilities_present = true; + } else if(LIBLTE_S1AP_IE_ID_CSGMEMBERSHIPSTATUS == ie_id) { + if(liblte_s1ap_unpack_csgmembershipstatus(ptr, &msg->CSGMembershipStatus) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->CSGMembershipStatus_present = true; + } else if(LIBLTE_S1AP_IE_ID_REGISTEREDLAI == ie_id) { + if(liblte_s1ap_unpack_lai(ptr, &msg->RegisteredLAI) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->RegisteredLAI_present = true; + } else if(LIBLTE_S1AP_IE_ID_ADDITIONALCSFALLBACKINDICATOR == ie_id) { + if(liblte_s1ap_unpack_additionalcsfallbackindicator(ptr, &msg->AdditionalCSFallbackIndicator) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message UEContextModificationResponse STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_uecontextmodificationresponse( + LIBLTE_S1AP_MESSAGE_UECONTEXTMODIFICATIONRESPONSE_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("UEContextModificationResponseIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 3; + if(!msg->CriticalityDiagnostics_present) + n_ie--; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - MME_UE_S1AP_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_mme_ue_s1ap_id(&msg->MME_UE_S1AP_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_MME_UE_S1AP_ID, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - eNB_UE_S1AP_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_enb_ue_s1ap_id(&msg->eNB_UE_S1AP_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_ENB_UE_S1AP_ID, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - CriticalityDiagnostics + if(msg->CriticalityDiagnostics_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_criticalitydiagnostics(&msg->CriticalityDiagnostics, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_CRITICALITYDIAGNOSTICS, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_uecontextmodificationresponse( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_UECONTEXTMODIFICATIONRESPONSE_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + msg->CriticalityDiagnostics_present = false; + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("UEContextModificationResponseIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iMME_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_ENB_UE_S1AP_ID == ie_id) { + if(liblte_s1ap_unpack_enb_ue_s1ap_id(ptr, &msg->eNB_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_CRITICALITYDIAGNOSTICS == ie_id) { + if(liblte_s1ap_unpack_criticalitydiagnostics(ptr, &msg->CriticalityDiagnostics) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->CriticalityDiagnostics_present = true; + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message UEContextModificationFailure STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_uecontextmodificationfailure( + LIBLTE_S1AP_MESSAGE_UECONTEXTMODIFICATIONFAILURE_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("UEContextModificationFailureIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 4; + if(!msg->CriticalityDiagnostics_present) + n_ie--; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - MME_UE_S1AP_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_mme_ue_s1ap_id(&msg->MME_UE_S1AP_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_MME_UE_S1AP_ID, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - eNB_UE_S1AP_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_enb_ue_s1ap_id(&msg->eNB_UE_S1AP_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_ENB_UE_S1AP_ID, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - Cause + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_cause(&msg->Cause, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_CAUSE, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - CriticalityDiagnostics + if(msg->CriticalityDiagnostics_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_criticalitydiagnostics(&msg->CriticalityDiagnostics, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_CRITICALITYDIAGNOSTICS, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_uecontextmodificationfailure( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_UECONTEXTMODIFICATIONFAILURE_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + msg->CriticalityDiagnostics_present = false; + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("UEContextModificationFailureIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iMME_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_ENB_UE_S1AP_ID == ie_id) { + if(liblte_s1ap_unpack_enb_ue_s1ap_id(ptr, &msg->eNB_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_CAUSE == ie_id) { + if(liblte_s1ap_unpack_cause(ptr, &msg->Cause) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_CRITICALITYDIAGNOSTICS == ie_id) { + if(liblte_s1ap_unpack_criticalitydiagnostics(ptr, &msg->CriticalityDiagnostics) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->CriticalityDiagnostics_present = true; + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message UERadioCapabilityMatchRequest STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_ueradiocapabilitymatchrequest( + LIBLTE_S1AP_MESSAGE_UERADIOCAPABILITYMATCHREQUEST_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("UERadioCapabilityMatchRequestIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 3; + if(!msg->UERadioCapability_present) + n_ie--; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - MME_UE_S1AP_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_mme_ue_s1ap_id(&msg->MME_UE_S1AP_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_MME_UE_S1AP_ID, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - eNB_UE_S1AP_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_enb_ue_s1ap_id(&msg->eNB_UE_S1AP_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_ENB_UE_S1AP_ID, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - UERadioCapability + if(msg->UERadioCapability_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_ueradiocapability(&msg->UERadioCapability, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_UERADIOCAPABILITY, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_ueradiocapabilitymatchrequest( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_UERADIOCAPABILITYMATCHREQUEST_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + msg->UERadioCapability_present = false; + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("UERadioCapabilityMatchRequestIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iMME_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_ENB_UE_S1AP_ID == ie_id) { + if(liblte_s1ap_unpack_enb_ue_s1ap_id(ptr, &msg->eNB_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_UERADIOCAPABILITY == ie_id) { + if(liblte_s1ap_unpack_ueradiocapability(ptr, &msg->UERadioCapability) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->UERadioCapability_present = true; + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message UERadioCapabilityMatchResponse STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_ueradiocapabilitymatchresponse( + LIBLTE_S1AP_MESSAGE_UERADIOCAPABILITYMATCHRESPONSE_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("UERadioCapabilityMatchResponseIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 4; + if(!msg->CriticalityDiagnostics_present) + n_ie--; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - MME_UE_S1AP_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_mme_ue_s1ap_id(&msg->MME_UE_S1AP_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_MME_UE_S1AP_ID, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - eNB_UE_S1AP_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_enb_ue_s1ap_id(&msg->eNB_UE_S1AP_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_ENB_UE_S1AP_ID, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - VoiceSupportMatchIndicator + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_voicesupportmatchindicator(&msg->VoiceSupportMatchIndicator, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_VOICESUPPORTMATCHINDICATOR, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - CriticalityDiagnostics + if(msg->CriticalityDiagnostics_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_criticalitydiagnostics(&msg->CriticalityDiagnostics, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_CRITICALITYDIAGNOSTICS, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_ueradiocapabilitymatchresponse( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_UERADIOCAPABILITYMATCHRESPONSE_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + msg->CriticalityDiagnostics_present = false; + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("UERadioCapabilityMatchResponseIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iMME_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_ENB_UE_S1AP_ID == ie_id) { + if(liblte_s1ap_unpack_enb_ue_s1ap_id(ptr, &msg->eNB_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_VOICESUPPORTMATCHINDICATOR == ie_id) { + if(liblte_s1ap_unpack_voicesupportmatchindicator(ptr, &msg->VoiceSupportMatchIndicator) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_CRITICALITYDIAGNOSTICS == ie_id) { + if(liblte_s1ap_unpack_criticalitydiagnostics(ptr, &msg->CriticalityDiagnostics) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->CriticalityDiagnostics_present = true; + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message DownlinkNASTransport STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_downlinknastransport( + LIBLTE_S1AP_MESSAGE_DOWNLINKNASTRANSPORT_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("DownlinkNASTransport-IEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 5; + if(!msg->HandoverRestrictionList_present) + n_ie--; + if(!msg->SubscriberProfileIDforRFP_present) + n_ie--; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - MME_UE_S1AP_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_mme_ue_s1ap_id(&msg->MME_UE_S1AP_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_MME_UE_S1AP_ID, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - eNB_UE_S1AP_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_enb_ue_s1ap_id(&msg->eNB_UE_S1AP_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_ENB_UE_S1AP_ID, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - NAS_PDU + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_nas_pdu(&msg->NAS_PDU, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_NAS_PDU, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - HandoverRestrictionList + if(msg->HandoverRestrictionList_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_handoverrestrictionlist(&msg->HandoverRestrictionList, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_HANDOVERRESTRICTIONLIST, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - SubscriberProfileIDforRFP + if(msg->SubscriberProfileIDforRFP_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_subscriberprofileidforrfp(&msg->SubscriberProfileIDforRFP, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_SUBSCRIBERPROFILEIDFORRFP, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_downlinknastransport( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_DOWNLINKNASTRANSPORT_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + msg->HandoverRestrictionList_present = false; + msg->SubscriberProfileIDforRFP_present = false; + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("DownlinkNASTransport-IEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iMME_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_ENB_UE_S1AP_ID == ie_id) { + if(liblte_s1ap_unpack_enb_ue_s1ap_id(ptr, &msg->eNB_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_NAS_PDU == ie_id) { + if(liblte_s1ap_unpack_nas_pdu(ptr, &msg->NAS_PDU) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_HANDOVERRESTRICTIONLIST == ie_id) { + if(liblte_s1ap_unpack_handoverrestrictionlist(ptr, &msg->HandoverRestrictionList) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->HandoverRestrictionList_present = true; + } else if(LIBLTE_S1AP_IE_ID_SUBSCRIBERPROFILEIDFORRFP == ie_id) { + if(liblte_s1ap_unpack_subscriberprofileidforrfp(ptr, &msg->SubscriberProfileIDforRFP) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->SubscriberProfileIDforRFP_present = true; + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message InitialUEMessage STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_initialuemessage( + LIBLTE_S1AP_MESSAGE_INITIALUEMESSAGE_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("InitialUEMessage-IEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 15; + if(!msg->S_TMSI_present) + n_ie--; + if(!msg->CSG_Id_present) + n_ie--; + if(!msg->GUMMEI_ID_present) + n_ie--; + if(!msg->CellAccessMode_present) + n_ie--; + if(!msg->GW_TransportLayerAddress_present) + n_ie--; + if(!msg->RelayNode_Indicator_present) + n_ie--; + if(!msg->GUMMEIType_present) + n_ie--; + if(!msg->Tunnel_Information_for_BBF_present) + n_ie--; + if(!msg->SIPTO_L_GW_TransportLayerAddress_present) + n_ie--; + if(!msg->LHN_ID_present) + n_ie--; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - eNB_UE_S1AP_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_enb_ue_s1ap_id(&msg->eNB_UE_S1AP_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_ENB_UE_S1AP_ID, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - NAS_PDU + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_nas_pdu(&msg->NAS_PDU, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_NAS_PDU, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - TAI + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_tai(&msg->TAI, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_TAI, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - EUTRAN_CGI + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_eutran_cgi(&msg->EUTRAN_CGI, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_EUTRAN_CGI, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - RRC_Establishment_Cause + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_rrc_establishment_cause(&msg->RRC_Establishment_Cause, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_RRC_ESTABLISHMENT_CAUSE, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - S_TMSI + if(msg->S_TMSI_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_s_tmsi(&msg->S_TMSI, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_S_TMSI, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - CSG_Id + if(msg->CSG_Id_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_csg_id(&msg->CSG_Id, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_CSG_ID, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - GUMMEI_ID + if(msg->GUMMEI_ID_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_gummei(&msg->GUMMEI_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_GUMMEI_ID, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - CellAccessMode + if(msg->CellAccessMode_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_cellaccessmode(&msg->CellAccessMode, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_CELLACCESSMODE, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - GW_TransportLayerAddress + if(msg->GW_TransportLayerAddress_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_transportlayeraddress(&msg->GW_TransportLayerAddress, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_GW_TRANSPORTLAYERADDRESS, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - RelayNode_Indicator + if(msg->RelayNode_Indicator_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_relaynode_indicator(&msg->RelayNode_Indicator, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_RELAYNODE_INDICATOR, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - GUMMEIType + if(msg->GUMMEIType_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_gummeitype(&msg->GUMMEIType, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_GUMMEITYPE, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - Tunnel_Information_for_BBF + if(msg->Tunnel_Information_for_BBF_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_tunnelinformation(&msg->Tunnel_Information_for_BBF, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_TUNNEL_INFORMATION_FOR_BBF, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - SIPTO_L_GW_TransportLayerAddress + if(msg->SIPTO_L_GW_TransportLayerAddress_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_transportlayeraddress(&msg->SIPTO_L_GW_TransportLayerAddress, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_SIPTO_L_GW_TRANSPORTLAYERADDRESS, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - LHN_ID + if(msg->LHN_ID_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_lhn_id(&msg->LHN_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_LHN_ID, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_initialuemessage( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_INITIALUEMESSAGE_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + msg->S_TMSI_present = false; + msg->CSG_Id_present = false; + msg->GUMMEI_ID_present = false; + msg->CellAccessMode_present = false; + msg->GW_TransportLayerAddress_present = false; + msg->RelayNode_Indicator_present = false; + msg->GUMMEIType_present = false; + msg->Tunnel_Information_for_BBF_present = false; + msg->SIPTO_L_GW_TransportLayerAddress_present = false; + msg->LHN_ID_present = false; + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("InitialUEMessage-IEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;ieNB_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_NAS_PDU == ie_id) { + if(liblte_s1ap_unpack_nas_pdu(ptr, &msg->NAS_PDU) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_TAI == ie_id) { + if(liblte_s1ap_unpack_tai(ptr, &msg->TAI) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_EUTRAN_CGI == ie_id) { + if(liblte_s1ap_unpack_eutran_cgi(ptr, &msg->EUTRAN_CGI) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_RRC_ESTABLISHMENT_CAUSE == ie_id) { + if(liblte_s1ap_unpack_rrc_establishment_cause(ptr, &msg->RRC_Establishment_Cause) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_S_TMSI == ie_id) { + if(liblte_s1ap_unpack_s_tmsi(ptr, &msg->S_TMSI) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->S_TMSI_present = true; + } else if(LIBLTE_S1AP_IE_ID_CSG_ID == ie_id) { + if(liblte_s1ap_unpack_csg_id(ptr, &msg->CSG_Id) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->CSG_Id_present = true; + } else if(LIBLTE_S1AP_IE_ID_GUMMEI_ID == ie_id) { + if(liblte_s1ap_unpack_gummei(ptr, &msg->GUMMEI_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->GUMMEI_ID_present = true; + } else if(LIBLTE_S1AP_IE_ID_CELLACCESSMODE == ie_id) { + if(liblte_s1ap_unpack_cellaccessmode(ptr, &msg->CellAccessMode) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->CellAccessMode_present = true; + } else if(LIBLTE_S1AP_IE_ID_GW_TRANSPORTLAYERADDRESS == ie_id) { + if(liblte_s1ap_unpack_transportlayeraddress(ptr, &msg->GW_TransportLayerAddress) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->GW_TransportLayerAddress_present = true; + } else if(LIBLTE_S1AP_IE_ID_RELAYNODE_INDICATOR == ie_id) { + if(liblte_s1ap_unpack_relaynode_indicator(ptr, &msg->RelayNode_Indicator) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->RelayNode_Indicator_present = true; + } else if(LIBLTE_S1AP_IE_ID_GUMMEITYPE == ie_id) { + if(liblte_s1ap_unpack_gummeitype(ptr, &msg->GUMMEIType) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->GUMMEIType_present = true; + } else if(LIBLTE_S1AP_IE_ID_TUNNEL_INFORMATION_FOR_BBF == ie_id) { + if(liblte_s1ap_unpack_tunnelinformation(ptr, &msg->Tunnel_Information_for_BBF) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->Tunnel_Information_for_BBF_present = true; + } else if(LIBLTE_S1AP_IE_ID_SIPTO_L_GW_TRANSPORTLAYERADDRESS == ie_id) { + if(liblte_s1ap_unpack_transportlayeraddress(ptr, &msg->SIPTO_L_GW_TransportLayerAddress) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->SIPTO_L_GW_TransportLayerAddress_present = true; + } else if(LIBLTE_S1AP_IE_ID_LHN_ID == ie_id) { + if(liblte_s1ap_unpack_lhn_id(ptr, &msg->LHN_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->LHN_ID_present = true; + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message UplinkNASTransport STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_uplinknastransport( + LIBLTE_S1AP_MESSAGE_UPLINKNASTRANSPORT_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("UplinkNASTransport-IEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 8; + if(!msg->GW_TransportLayerAddress_present) + n_ie--; + if(!msg->SIPTO_L_GW_TransportLayerAddress_present) + n_ie--; + if(!msg->LHN_ID_present) + n_ie--; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - MME_UE_S1AP_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_mme_ue_s1ap_id(&msg->MME_UE_S1AP_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_MME_UE_S1AP_ID, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - eNB_UE_S1AP_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_enb_ue_s1ap_id(&msg->eNB_UE_S1AP_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_ENB_UE_S1AP_ID, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - NAS_PDU + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_nas_pdu(&msg->NAS_PDU, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_NAS_PDU, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - EUTRAN_CGI + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_eutran_cgi(&msg->EUTRAN_CGI, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_EUTRAN_CGI, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - TAI + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_tai(&msg->TAI, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_TAI, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - GW_TransportLayerAddress + if(msg->GW_TransportLayerAddress_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_transportlayeraddress(&msg->GW_TransportLayerAddress, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_GW_TRANSPORTLAYERADDRESS, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - SIPTO_L_GW_TransportLayerAddress + if(msg->SIPTO_L_GW_TransportLayerAddress_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_transportlayeraddress(&msg->SIPTO_L_GW_TransportLayerAddress, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_SIPTO_L_GW_TRANSPORTLAYERADDRESS, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - LHN_ID + if(msg->LHN_ID_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_lhn_id(&msg->LHN_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_LHN_ID, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_uplinknastransport( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_UPLINKNASTRANSPORT_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + msg->GW_TransportLayerAddress_present = false; + msg->SIPTO_L_GW_TransportLayerAddress_present = false; + msg->LHN_ID_present = false; + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("UplinkNASTransport-IEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iMME_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_ENB_UE_S1AP_ID == ie_id) { + if(liblte_s1ap_unpack_enb_ue_s1ap_id(ptr, &msg->eNB_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_NAS_PDU == ie_id) { + if(liblte_s1ap_unpack_nas_pdu(ptr, &msg->NAS_PDU) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_EUTRAN_CGI == ie_id) { + if(liblte_s1ap_unpack_eutran_cgi(ptr, &msg->EUTRAN_CGI) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_TAI == ie_id) { + if(liblte_s1ap_unpack_tai(ptr, &msg->TAI) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_GW_TRANSPORTLAYERADDRESS == ie_id) { + if(liblte_s1ap_unpack_transportlayeraddress(ptr, &msg->GW_TransportLayerAddress) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->GW_TransportLayerAddress_present = true; + } else if(LIBLTE_S1AP_IE_ID_SIPTO_L_GW_TRANSPORTLAYERADDRESS == ie_id) { + if(liblte_s1ap_unpack_transportlayeraddress(ptr, &msg->SIPTO_L_GW_TransportLayerAddress) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->SIPTO_L_GW_TransportLayerAddress_present = true; + } else if(LIBLTE_S1AP_IE_ID_LHN_ID == ie_id) { + if(liblte_s1ap_unpack_lhn_id(ptr, &msg->LHN_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->LHN_ID_present = true; + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message NASNonDeliveryIndication STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_nasnondeliveryindication( + LIBLTE_S1AP_MESSAGE_NASNONDELIVERYINDICATION_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("NASNonDeliveryIndication-IEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 4; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - MME_UE_S1AP_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_mme_ue_s1ap_id(&msg->MME_UE_S1AP_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_MME_UE_S1AP_ID, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - eNB_UE_S1AP_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_enb_ue_s1ap_id(&msg->eNB_UE_S1AP_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_ENB_UE_S1AP_ID, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - NAS_PDU + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_nas_pdu(&msg->NAS_PDU, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_NAS_PDU, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - Cause + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_cause(&msg->Cause, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_CAUSE, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_nasnondeliveryindication( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_NASNONDELIVERYINDICATION_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("NASNonDeliveryIndication-IEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iMME_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_ENB_UE_S1AP_ID == ie_id) { + if(liblte_s1ap_unpack_enb_ue_s1ap_id(ptr, &msg->eNB_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_NAS_PDU == ie_id) { + if(liblte_s1ap_unpack_nas_pdu(ptr, &msg->NAS_PDU) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_CAUSE == ie_id) { + if(liblte_s1ap_unpack_cause(ptr, &msg->Cause) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message UE_associatedLogicalS1_ConnectionItem STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_ue_associatedlogicals1_connectionitem( + LIBLTE_S1AP_MESSAGE_UE_ASSOCIATEDLOGICALS1_CONNECTIONITEM_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("UE-associatedLogicalS1-ConnectionItemRes error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 1; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - UE_associatedLogicalS1_ConnectionItem + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_ue_associatedlogicals1_connectionitem(&msg->UE_associatedLogicalS1_ConnectionItem, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_UE_ASSOCIATEDLOGICALS1_CONNECTIONITEM, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_ue_associatedlogicals1_connectionitem( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_UE_ASSOCIATEDLOGICALS1_CONNECTIONITEM_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("UE-associatedLogicalS1-ConnectionItemRes error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iUE_associatedLogicalS1_ConnectionItem) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message UE_associatedLogicalS1_ConnectionItemRes STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_ue_associatedlogicals1_connectionitemres( + LIBLTE_S1AP_MESSAGE_UE_ASSOCIATEDLOGICALS1_CONNECTIONITEMRES_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("UE-associatedLogicalS1-ConnectionItemResAck error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 1; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - UE_associatedLogicalS1_ConnectionItem + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_ue_associatedlogicals1_connectionitem(&msg->UE_associatedLogicalS1_ConnectionItem, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_UE_ASSOCIATEDLOGICALS1_CONNECTIONITEM, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_ue_associatedlogicals1_connectionitemres( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_UE_ASSOCIATEDLOGICALS1_CONNECTIONITEMRES_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("UE-associatedLogicalS1-ConnectionItemResAck error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iUE_associatedLogicalS1_ConnectionItem) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message ErrorIndication STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_errorindication( + LIBLTE_S1AP_MESSAGE_ERRORINDICATION_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("ErrorIndicationIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 4; + if(!msg->MME_UE_S1AP_ID_present) + n_ie--; + if(!msg->eNB_UE_S1AP_ID_present) + n_ie--; + if(!msg->Cause_present) + n_ie--; + if(!msg->CriticalityDiagnostics_present) + n_ie--; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - MME_UE_S1AP_ID + if(msg->MME_UE_S1AP_ID_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_mme_ue_s1ap_id(&msg->MME_UE_S1AP_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_MME_UE_S1AP_ID, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - eNB_UE_S1AP_ID + if(msg->eNB_UE_S1AP_ID_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_enb_ue_s1ap_id(&msg->eNB_UE_S1AP_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_ENB_UE_S1AP_ID, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - Cause + if(msg->Cause_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_cause(&msg->Cause, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_CAUSE, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - CriticalityDiagnostics + if(msg->CriticalityDiagnostics_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_criticalitydiagnostics(&msg->CriticalityDiagnostics, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_CRITICALITYDIAGNOSTICS, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_errorindication( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_ERRORINDICATION_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + msg->MME_UE_S1AP_ID_present = false; + msg->eNB_UE_S1AP_ID_present = false; + msg->Cause_present = false; + msg->CriticalityDiagnostics_present = false; + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("ErrorIndicationIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iMME_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->MME_UE_S1AP_ID_present = true; + } else if(LIBLTE_S1AP_IE_ID_ENB_UE_S1AP_ID == ie_id) { + if(liblte_s1ap_unpack_enb_ue_s1ap_id(ptr, &msg->eNB_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->eNB_UE_S1AP_ID_present = true; + } else if(LIBLTE_S1AP_IE_ID_CAUSE == ie_id) { + if(liblte_s1ap_unpack_cause(ptr, &msg->Cause) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->Cause_present = true; + } else if(LIBLTE_S1AP_IE_ID_CRITICALITYDIAGNOSTICS == ie_id) { + if(liblte_s1ap_unpack_criticalitydiagnostics(ptr, &msg->CriticalityDiagnostics) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->CriticalityDiagnostics_present = true; + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message S1SetupRequest STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_s1setuprequest( + LIBLTE_S1AP_MESSAGE_S1SETUPREQUEST_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("S1SetupRequestIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 5; + if(!msg->eNBname_present) + n_ie--; + if(!msg->CSG_IdList_present) + n_ie--; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - Global_ENB_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_global_enb_id(&msg->Global_ENB_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_GLOBAL_ENB_ID, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - eNBname + if(msg->eNBname_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_enbname(&msg->eNBname, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_ENBNAME, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - SupportedTAs + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_supportedtas(&msg->SupportedTAs, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_SUPPORTEDTAS, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - DefaultPagingDRX + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_pagingdrx(&msg->DefaultPagingDRX, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_DEFAULTPAGINGDRX, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - CSG_IdList + if(msg->CSG_IdList_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_csg_idlist(&msg->CSG_IdList, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_CSG_IDLIST, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_s1setuprequest( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_S1SETUPREQUEST_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + msg->eNBname_present = false; + msg->CSG_IdList_present = false; + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("S1SetupRequestIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iGlobal_ENB_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_ENBNAME == ie_id) { + if(liblte_s1ap_unpack_enbname(ptr, &msg->eNBname) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->eNBname_present = true; + } else if(LIBLTE_S1AP_IE_ID_SUPPORTEDTAS == ie_id) { + if(liblte_s1ap_unpack_supportedtas(ptr, &msg->SupportedTAs) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_DEFAULTPAGINGDRX == ie_id) { + if(liblte_s1ap_unpack_pagingdrx(ptr, &msg->DefaultPagingDRX) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_CSG_IDLIST == ie_id) { + if(liblte_s1ap_unpack_csg_idlist(ptr, &msg->CSG_IdList) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->CSG_IdList_present = true; + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message S1SetupResponse STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_s1setupresponse( + LIBLTE_S1AP_MESSAGE_S1SETUPRESPONSE_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("S1SetupResponseIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 5; + if(!msg->MMEname_present) + n_ie--; + if(!msg->MMERelaySupportIndicator_present) + n_ie--; + if(!msg->CriticalityDiagnostics_present) + n_ie--; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - MMEname + if(msg->MMEname_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_mmename(&msg->MMEname, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_MMENAME, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - ServedGUMMEIs + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_servedgummeis(&msg->ServedGUMMEIs, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_SERVEDGUMMEIS, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - RelativeMMECapacity + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_relativemmecapacity(&msg->RelativeMMECapacity, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_RELATIVEMMECAPACITY, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - MMERelaySupportIndicator + if(msg->MMERelaySupportIndicator_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_mmerelaysupportindicator(&msg->MMERelaySupportIndicator, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_MMERELAYSUPPORTINDICATOR, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - CriticalityDiagnostics + if(msg->CriticalityDiagnostics_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_criticalitydiagnostics(&msg->CriticalityDiagnostics, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_CRITICALITYDIAGNOSTICS, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_s1setupresponse( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_S1SETUPRESPONSE_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + msg->MMEname_present = false; + msg->MMERelaySupportIndicator_present = false; + msg->CriticalityDiagnostics_present = false; + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("S1SetupResponseIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iMMEname) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->MMEname_present = true; + } else if(LIBLTE_S1AP_IE_ID_SERVEDGUMMEIS == ie_id) { + if(liblte_s1ap_unpack_servedgummeis(ptr, &msg->ServedGUMMEIs) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_RELATIVEMMECAPACITY == ie_id) { + if(liblte_s1ap_unpack_relativemmecapacity(ptr, &msg->RelativeMMECapacity) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_MMERELAYSUPPORTINDICATOR == ie_id) { + if(liblte_s1ap_unpack_mmerelaysupportindicator(ptr, &msg->MMERelaySupportIndicator) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->MMERelaySupportIndicator_present = true; + } else if(LIBLTE_S1AP_IE_ID_CRITICALITYDIAGNOSTICS == ie_id) { + if(liblte_s1ap_unpack_criticalitydiagnostics(ptr, &msg->CriticalityDiagnostics) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->CriticalityDiagnostics_present = true; + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message S1SetupFailure STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_s1setupfailure( + LIBLTE_S1AP_MESSAGE_S1SETUPFAILURE_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("S1SetupFailureIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 3; + if(!msg->TimeToWait_present) + n_ie--; + if(!msg->CriticalityDiagnostics_present) + n_ie--; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - Cause + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_cause(&msg->Cause, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_CAUSE, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - TimeToWait + if(msg->TimeToWait_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_timetowait(&msg->TimeToWait, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_TIMETOWAIT, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - CriticalityDiagnostics + if(msg->CriticalityDiagnostics_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_criticalitydiagnostics(&msg->CriticalityDiagnostics, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_CRITICALITYDIAGNOSTICS, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_s1setupfailure( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_S1SETUPFAILURE_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + msg->TimeToWait_present = false; + msg->CriticalityDiagnostics_present = false; + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("S1SetupFailureIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iCause) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_TIMETOWAIT == ie_id) { + if(liblte_s1ap_unpack_timetowait(ptr, &msg->TimeToWait) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->TimeToWait_present = true; + } else if(LIBLTE_S1AP_IE_ID_CRITICALITYDIAGNOSTICS == ie_id) { + if(liblte_s1ap_unpack_criticalitydiagnostics(ptr, &msg->CriticalityDiagnostics) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->CriticalityDiagnostics_present = true; + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message ENBConfigurationUpdate STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_enbconfigurationupdate( + LIBLTE_S1AP_MESSAGE_ENBCONFIGURATIONUPDATE_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("ENBConfigurationUpdateIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 4; + if(!msg->eNBname_present) + n_ie--; + if(!msg->SupportedTAs_present) + n_ie--; + if(!msg->CSG_IdList_present) + n_ie--; + if(!msg->DefaultPagingDRX_present) + n_ie--; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - eNBname + if(msg->eNBname_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_enbname(&msg->eNBname, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_ENBNAME, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - SupportedTAs + if(msg->SupportedTAs_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_supportedtas(&msg->SupportedTAs, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_SUPPORTEDTAS, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - CSG_IdList + if(msg->CSG_IdList_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_csg_idlist(&msg->CSG_IdList, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_CSG_IDLIST, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - DefaultPagingDRX + if(msg->DefaultPagingDRX_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_pagingdrx(&msg->DefaultPagingDRX, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_DEFAULTPAGINGDRX, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_enbconfigurationupdate( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_ENBCONFIGURATIONUPDATE_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + msg->eNBname_present = false; + msg->SupportedTAs_present = false; + msg->CSG_IdList_present = false; + msg->DefaultPagingDRX_present = false; + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("ENBConfigurationUpdateIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;ieNBname) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->eNBname_present = true; + } else if(LIBLTE_S1AP_IE_ID_SUPPORTEDTAS == ie_id) { + if(liblte_s1ap_unpack_supportedtas(ptr, &msg->SupportedTAs) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->SupportedTAs_present = true; + } else if(LIBLTE_S1AP_IE_ID_CSG_IDLIST == ie_id) { + if(liblte_s1ap_unpack_csg_idlist(ptr, &msg->CSG_IdList) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->CSG_IdList_present = true; + } else if(LIBLTE_S1AP_IE_ID_DEFAULTPAGINGDRX == ie_id) { + if(liblte_s1ap_unpack_pagingdrx(ptr, &msg->DefaultPagingDRX) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->DefaultPagingDRX_present = true; + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message ENBConfigurationUpdateAcknowledge STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_enbconfigurationupdateacknowledge( + LIBLTE_S1AP_MESSAGE_ENBCONFIGURATIONUPDATEACKNOWLEDGE_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("ENBConfigurationUpdateAcknowledgeIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 1; + if(!msg->CriticalityDiagnostics_present) + n_ie--; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - CriticalityDiagnostics + if(msg->CriticalityDiagnostics_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_criticalitydiagnostics(&msg->CriticalityDiagnostics, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_CRITICALITYDIAGNOSTICS, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_enbconfigurationupdateacknowledge( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_ENBCONFIGURATIONUPDATEACKNOWLEDGE_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + msg->CriticalityDiagnostics_present = false; + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("ENBConfigurationUpdateAcknowledgeIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iCriticalityDiagnostics) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->CriticalityDiagnostics_present = true; + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message ENBConfigurationUpdateFailure STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_enbconfigurationupdatefailure( + LIBLTE_S1AP_MESSAGE_ENBCONFIGURATIONUPDATEFAILURE_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("ENBConfigurationUpdateFailureIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 3; + if(!msg->TimeToWait_present) + n_ie--; + if(!msg->CriticalityDiagnostics_present) + n_ie--; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - Cause + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_cause(&msg->Cause, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_CAUSE, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - TimeToWait + if(msg->TimeToWait_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_timetowait(&msg->TimeToWait, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_TIMETOWAIT, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - CriticalityDiagnostics + if(msg->CriticalityDiagnostics_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_criticalitydiagnostics(&msg->CriticalityDiagnostics, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_CRITICALITYDIAGNOSTICS, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_enbconfigurationupdatefailure( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_ENBCONFIGURATIONUPDATEFAILURE_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + msg->TimeToWait_present = false; + msg->CriticalityDiagnostics_present = false; + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("ENBConfigurationUpdateFailureIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iCause) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_TIMETOWAIT == ie_id) { + if(liblte_s1ap_unpack_timetowait(ptr, &msg->TimeToWait) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->TimeToWait_present = true; + } else if(LIBLTE_S1AP_IE_ID_CRITICALITYDIAGNOSTICS == ie_id) { + if(liblte_s1ap_unpack_criticalitydiagnostics(ptr, &msg->CriticalityDiagnostics) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->CriticalityDiagnostics_present = true; + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message MMEConfigurationUpdate STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_mmeconfigurationupdate( + LIBLTE_S1AP_MESSAGE_MMECONFIGURATIONUPDATE_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("MMEConfigurationUpdateIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 3; + if(!msg->MMEname_present) + n_ie--; + if(!msg->ServedGUMMEIs_present) + n_ie--; + if(!msg->RelativeMMECapacity_present) + n_ie--; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - MMEname + if(msg->MMEname_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_mmename(&msg->MMEname, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_MMENAME, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - ServedGUMMEIs + if(msg->ServedGUMMEIs_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_servedgummeis(&msg->ServedGUMMEIs, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_SERVEDGUMMEIS, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - RelativeMMECapacity + if(msg->RelativeMMECapacity_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_relativemmecapacity(&msg->RelativeMMECapacity, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_RELATIVEMMECAPACITY, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_mmeconfigurationupdate( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_MMECONFIGURATIONUPDATE_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + msg->MMEname_present = false; + msg->ServedGUMMEIs_present = false; + msg->RelativeMMECapacity_present = false; + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("MMEConfigurationUpdateIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iMMEname) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->MMEname_present = true; + } else if(LIBLTE_S1AP_IE_ID_SERVEDGUMMEIS == ie_id) { + if(liblte_s1ap_unpack_servedgummeis(ptr, &msg->ServedGUMMEIs) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->ServedGUMMEIs_present = true; + } else if(LIBLTE_S1AP_IE_ID_RELATIVEMMECAPACITY == ie_id) { + if(liblte_s1ap_unpack_relativemmecapacity(ptr, &msg->RelativeMMECapacity) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->RelativeMMECapacity_present = true; + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message MMEConfigurationUpdateAcknowledge STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_mmeconfigurationupdateacknowledge( + LIBLTE_S1AP_MESSAGE_MMECONFIGURATIONUPDATEACKNOWLEDGE_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("MMEConfigurationUpdateAcknowledgeIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 1; + if(!msg->CriticalityDiagnostics_present) + n_ie--; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - CriticalityDiagnostics + if(msg->CriticalityDiagnostics_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_criticalitydiagnostics(&msg->CriticalityDiagnostics, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_CRITICALITYDIAGNOSTICS, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_mmeconfigurationupdateacknowledge( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_MMECONFIGURATIONUPDATEACKNOWLEDGE_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + msg->CriticalityDiagnostics_present = false; + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("MMEConfigurationUpdateAcknowledgeIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iCriticalityDiagnostics) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->CriticalityDiagnostics_present = true; + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message MMEConfigurationUpdateFailure STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_mmeconfigurationupdatefailure( + LIBLTE_S1AP_MESSAGE_MMECONFIGURATIONUPDATEFAILURE_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("MMEConfigurationUpdateFailureIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 3; + if(!msg->TimeToWait_present) + n_ie--; + if(!msg->CriticalityDiagnostics_present) + n_ie--; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - Cause + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_cause(&msg->Cause, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_CAUSE, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - TimeToWait + if(msg->TimeToWait_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_timetowait(&msg->TimeToWait, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_TIMETOWAIT, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - CriticalityDiagnostics + if(msg->CriticalityDiagnostics_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_criticalitydiagnostics(&msg->CriticalityDiagnostics, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_CRITICALITYDIAGNOSTICS, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_mmeconfigurationupdatefailure( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_MMECONFIGURATIONUPDATEFAILURE_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + msg->TimeToWait_present = false; + msg->CriticalityDiagnostics_present = false; + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("MMEConfigurationUpdateFailureIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iCause) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_TIMETOWAIT == ie_id) { + if(liblte_s1ap_unpack_timetowait(ptr, &msg->TimeToWait) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->TimeToWait_present = true; + } else if(LIBLTE_S1AP_IE_ID_CRITICALITYDIAGNOSTICS == ie_id) { + if(liblte_s1ap_unpack_criticalitydiagnostics(ptr, &msg->CriticalityDiagnostics) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->CriticalityDiagnostics_present = true; + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message UplinkS1cdma2000tunneling STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_uplinks1cdma2000tunneling( + LIBLTE_S1AP_MESSAGE_UPLINKS1CDMA2000TUNNELING_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("UplinkS1cdma2000tunnelingIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 9; + if(!msg->cdma2000HORequiredIndication_present) + n_ie--; + if(!msg->cdma2000OneXSRVCCInfo_present) + n_ie--; + if(!msg->cdma2000OneXRAND_present) + n_ie--; + if(!msg->EUTRANRoundTripDelayEstimationInfo_present) + n_ie--; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - MME_UE_S1AP_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_mme_ue_s1ap_id(&msg->MME_UE_S1AP_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_MME_UE_S1AP_ID, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - eNB_UE_S1AP_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_enb_ue_s1ap_id(&msg->eNB_UE_S1AP_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_ENB_UE_S1AP_ID, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - cdma2000RATType + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_cdma2000rattype(&msg->cdma2000RATType, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_CDMA2000RATTYPE, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - cdma2000SectorID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_cdma2000sectorid(&msg->cdma2000SectorID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_CDMA2000SECTORID, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - cdma2000HORequiredIndication + if(msg->cdma2000HORequiredIndication_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_cdma2000horequiredindication(&msg->cdma2000HORequiredIndication, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_CDMA2000HOREQUIREDINDICATION, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - cdma2000OneXSRVCCInfo + if(msg->cdma2000OneXSRVCCInfo_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_cdma2000onexsrvccinfo(&msg->cdma2000OneXSRVCCInfo, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_CDMA2000ONEXSRVCCINFO, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - cdma2000OneXRAND + if(msg->cdma2000OneXRAND_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_cdma2000onexrand(&msg->cdma2000OneXRAND, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_CDMA2000ONEXRAND, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - cdma2000PDU + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_cdma2000pdu(&msg->cdma2000PDU, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_CDMA2000PDU, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - EUTRANRoundTripDelayEstimationInfo + if(msg->EUTRANRoundTripDelayEstimationInfo_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_eutranroundtripdelayestimationinfo(&msg->EUTRANRoundTripDelayEstimationInfo, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_EUTRANROUNDTRIPDELAYESTIMATIONINFO, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_uplinks1cdma2000tunneling( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_UPLINKS1CDMA2000TUNNELING_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + msg->cdma2000HORequiredIndication_present = false; + msg->cdma2000OneXSRVCCInfo_present = false; + msg->cdma2000OneXRAND_present = false; + msg->EUTRANRoundTripDelayEstimationInfo_present = false; + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("UplinkS1cdma2000tunnelingIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iMME_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_ENB_UE_S1AP_ID == ie_id) { + if(liblte_s1ap_unpack_enb_ue_s1ap_id(ptr, &msg->eNB_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_CDMA2000RATTYPE == ie_id) { + if(liblte_s1ap_unpack_cdma2000rattype(ptr, &msg->cdma2000RATType) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_CDMA2000SECTORID == ie_id) { + if(liblte_s1ap_unpack_cdma2000sectorid(ptr, &msg->cdma2000SectorID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_CDMA2000HOREQUIREDINDICATION == ie_id) { + if(liblte_s1ap_unpack_cdma2000horequiredindication(ptr, &msg->cdma2000HORequiredIndication) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->cdma2000HORequiredIndication_present = true; + } else if(LIBLTE_S1AP_IE_ID_CDMA2000ONEXSRVCCINFO == ie_id) { + if(liblte_s1ap_unpack_cdma2000onexsrvccinfo(ptr, &msg->cdma2000OneXSRVCCInfo) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->cdma2000OneXSRVCCInfo_present = true; + } else if(LIBLTE_S1AP_IE_ID_CDMA2000ONEXRAND == ie_id) { + if(liblte_s1ap_unpack_cdma2000onexrand(ptr, &msg->cdma2000OneXRAND) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->cdma2000OneXRAND_present = true; + } else if(LIBLTE_S1AP_IE_ID_CDMA2000PDU == ie_id) { + if(liblte_s1ap_unpack_cdma2000pdu(ptr, &msg->cdma2000PDU) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_EUTRANROUNDTRIPDELAYESTIMATIONINFO == ie_id) { + if(liblte_s1ap_unpack_eutranroundtripdelayestimationinfo(ptr, &msg->EUTRANRoundTripDelayEstimationInfo) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->EUTRANRoundTripDelayEstimationInfo_present = true; + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message UECapabilityInfoIndication STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_uecapabilityinfoindication( + LIBLTE_S1AP_MESSAGE_UECAPABILITYINFOINDICATION_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("UECapabilityInfoIndicationIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 3; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - MME_UE_S1AP_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_mme_ue_s1ap_id(&msg->MME_UE_S1AP_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_MME_UE_S1AP_ID, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - eNB_UE_S1AP_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_enb_ue_s1ap_id(&msg->eNB_UE_S1AP_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_ENB_UE_S1AP_ID, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - UERadioCapability + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_ueradiocapability(&msg->UERadioCapability, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_UERADIOCAPABILITY, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_uecapabilityinfoindication( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_UECAPABILITYINFOINDICATION_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("UECapabilityInfoIndicationIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iMME_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_ENB_UE_S1AP_ID == ie_id) { + if(liblte_s1ap_unpack_enb_ue_s1ap_id(ptr, &msg->eNB_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_UERADIOCAPABILITY == ie_id) { + if(liblte_s1ap_unpack_ueradiocapability(ptr, &msg->UERadioCapability) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message ENBStatusTransfer STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_enbstatustransfer( + LIBLTE_S1AP_MESSAGE_ENBSTATUSTRANSFER_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("ENBStatusTransferIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 3; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - MME_UE_S1AP_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_mme_ue_s1ap_id(&msg->MME_UE_S1AP_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_MME_UE_S1AP_ID, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - eNB_UE_S1AP_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_enb_ue_s1ap_id(&msg->eNB_UE_S1AP_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_ENB_UE_S1AP_ID, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - eNB_StatusTransfer_TransparentContainer + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_enb_statustransfer_transparentcontainer(&msg->eNB_StatusTransfer_TransparentContainer, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_ENB_STATUSTRANSFER_TRANSPARENTCONTAINER, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_enbstatustransfer( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_ENBSTATUSTRANSFER_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("ENBStatusTransferIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iMME_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_ENB_UE_S1AP_ID == ie_id) { + if(liblte_s1ap_unpack_enb_ue_s1ap_id(ptr, &msg->eNB_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_ENB_STATUSTRANSFER_TRANSPARENTCONTAINER == ie_id) { + if(liblte_s1ap_unpack_enb_statustransfer_transparentcontainer(ptr, &msg->eNB_StatusTransfer_TransparentContainer) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message MMEStatusTransfer STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_mmestatustransfer( + LIBLTE_S1AP_MESSAGE_MMESTATUSTRANSFER_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("MMEStatusTransferIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 3; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - MME_UE_S1AP_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_mme_ue_s1ap_id(&msg->MME_UE_S1AP_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_MME_UE_S1AP_ID, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - eNB_UE_S1AP_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_enb_ue_s1ap_id(&msg->eNB_UE_S1AP_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_ENB_UE_S1AP_ID, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - eNB_StatusTransfer_TransparentContainer + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_enb_statustransfer_transparentcontainer(&msg->eNB_StatusTransfer_TransparentContainer, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_ENB_STATUSTRANSFER_TRANSPARENTCONTAINER, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_mmestatustransfer( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_MMESTATUSTRANSFER_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("MMEStatusTransferIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iMME_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_ENB_UE_S1AP_ID == ie_id) { + if(liblte_s1ap_unpack_enb_ue_s1ap_id(ptr, &msg->eNB_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_ENB_STATUSTRANSFER_TRANSPARENTCONTAINER == ie_id) { + if(liblte_s1ap_unpack_enb_statustransfer_transparentcontainer(ptr, &msg->eNB_StatusTransfer_TransparentContainer) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message TraceStart STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_tracestart( + LIBLTE_S1AP_MESSAGE_TRACESTART_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("TraceStartIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 3; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - MME_UE_S1AP_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_mme_ue_s1ap_id(&msg->MME_UE_S1AP_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_MME_UE_S1AP_ID, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - eNB_UE_S1AP_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_enb_ue_s1ap_id(&msg->eNB_UE_S1AP_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_ENB_UE_S1AP_ID, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - TraceActivation + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_traceactivation(&msg->TraceActivation, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_TRACEACTIVATION, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_tracestart( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_TRACESTART_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("TraceStartIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iMME_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_ENB_UE_S1AP_ID == ie_id) { + if(liblte_s1ap_unpack_enb_ue_s1ap_id(ptr, &msg->eNB_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_TRACEACTIVATION == ie_id) { + if(liblte_s1ap_unpack_traceactivation(ptr, &msg->TraceActivation) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message TraceFailureIndication STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_tracefailureindication( + LIBLTE_S1AP_MESSAGE_TRACEFAILUREINDICATION_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("TraceFailureIndicationIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 4; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - MME_UE_S1AP_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_mme_ue_s1ap_id(&msg->MME_UE_S1AP_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_MME_UE_S1AP_ID, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - eNB_UE_S1AP_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_enb_ue_s1ap_id(&msg->eNB_UE_S1AP_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_ENB_UE_S1AP_ID, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - E_UTRAN_Trace_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_e_utran_trace_id(&msg->E_UTRAN_Trace_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_E_UTRAN_TRACE_ID, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - Cause + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_cause(&msg->Cause, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_CAUSE, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_tracefailureindication( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_TRACEFAILUREINDICATION_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("TraceFailureIndicationIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iMME_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_ENB_UE_S1AP_ID == ie_id) { + if(liblte_s1ap_unpack_enb_ue_s1ap_id(ptr, &msg->eNB_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_E_UTRAN_TRACE_ID == ie_id) { + if(liblte_s1ap_unpack_e_utran_trace_id(ptr, &msg->E_UTRAN_Trace_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_CAUSE == ie_id) { + if(liblte_s1ap_unpack_cause(ptr, &msg->Cause) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message DeactivateTrace STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_deactivatetrace( + LIBLTE_S1AP_MESSAGE_DEACTIVATETRACE_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("DeactivateTraceIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 3; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - MME_UE_S1AP_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_mme_ue_s1ap_id(&msg->MME_UE_S1AP_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_MME_UE_S1AP_ID, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - eNB_UE_S1AP_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_enb_ue_s1ap_id(&msg->eNB_UE_S1AP_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_ENB_UE_S1AP_ID, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - E_UTRAN_Trace_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_e_utran_trace_id(&msg->E_UTRAN_Trace_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_E_UTRAN_TRACE_ID, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_deactivatetrace( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_DEACTIVATETRACE_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("DeactivateTraceIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iMME_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_ENB_UE_S1AP_ID == ie_id) { + if(liblte_s1ap_unpack_enb_ue_s1ap_id(ptr, &msg->eNB_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_E_UTRAN_TRACE_ID == ie_id) { + if(liblte_s1ap_unpack_e_utran_trace_id(ptr, &msg->E_UTRAN_Trace_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message CellTrafficTrace STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_celltraffictrace( + LIBLTE_S1AP_MESSAGE_CELLTRAFFICTRACE_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("CellTrafficTraceIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 6; + if(!msg->PrivacyIndicator_present) + n_ie--; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - MME_UE_S1AP_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_mme_ue_s1ap_id(&msg->MME_UE_S1AP_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_MME_UE_S1AP_ID, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - eNB_UE_S1AP_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_enb_ue_s1ap_id(&msg->eNB_UE_S1AP_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_ENB_UE_S1AP_ID, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - E_UTRAN_Trace_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_e_utran_trace_id(&msg->E_UTRAN_Trace_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_E_UTRAN_TRACE_ID, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - EUTRAN_CGI + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_eutran_cgi(&msg->EUTRAN_CGI, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_EUTRAN_CGI, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - TraceCollectionEntityIPAddress + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_transportlayeraddress(&msg->TraceCollectionEntityIPAddress, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_TRACECOLLECTIONENTITYIPADDRESS, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - PrivacyIndicator + if(msg->PrivacyIndicator_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_privacyindicator(&msg->PrivacyIndicator, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_PRIVACYINDICATOR, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_celltraffictrace( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_CELLTRAFFICTRACE_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + msg->PrivacyIndicator_present = false; + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("CellTrafficTraceIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iMME_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_ENB_UE_S1AP_ID == ie_id) { + if(liblte_s1ap_unpack_enb_ue_s1ap_id(ptr, &msg->eNB_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_E_UTRAN_TRACE_ID == ie_id) { + if(liblte_s1ap_unpack_e_utran_trace_id(ptr, &msg->E_UTRAN_Trace_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_EUTRAN_CGI == ie_id) { + if(liblte_s1ap_unpack_eutran_cgi(ptr, &msg->EUTRAN_CGI) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_TRACECOLLECTIONENTITYIPADDRESS == ie_id) { + if(liblte_s1ap_unpack_transportlayeraddress(ptr, &msg->TraceCollectionEntityIPAddress) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_PRIVACYINDICATOR == ie_id) { + if(liblte_s1ap_unpack_privacyindicator(ptr, &msg->PrivacyIndicator) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->PrivacyIndicator_present = true; + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message LocationReportingControl STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_locationreportingcontrol( + LIBLTE_S1AP_MESSAGE_LOCATIONREPORTINGCONTROL_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("LocationReportingControlIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 3; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - MME_UE_S1AP_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_mme_ue_s1ap_id(&msg->MME_UE_S1AP_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_MME_UE_S1AP_ID, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - eNB_UE_S1AP_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_enb_ue_s1ap_id(&msg->eNB_UE_S1AP_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_ENB_UE_S1AP_ID, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - RequestType + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_requesttype(&msg->RequestType, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_REQUESTTYPE, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_locationreportingcontrol( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_LOCATIONREPORTINGCONTROL_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("LocationReportingControlIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iMME_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_ENB_UE_S1AP_ID == ie_id) { + if(liblte_s1ap_unpack_enb_ue_s1ap_id(ptr, &msg->eNB_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_REQUESTTYPE == ie_id) { + if(liblte_s1ap_unpack_requesttype(ptr, &msg->RequestType) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message LocationReportingFailureIndication STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_locationreportingfailureindication( + LIBLTE_S1AP_MESSAGE_LOCATIONREPORTINGFAILUREINDICATION_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("LocationReportingFailureIndicationIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 3; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - MME_UE_S1AP_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_mme_ue_s1ap_id(&msg->MME_UE_S1AP_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_MME_UE_S1AP_ID, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - eNB_UE_S1AP_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_enb_ue_s1ap_id(&msg->eNB_UE_S1AP_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_ENB_UE_S1AP_ID, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - Cause + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_cause(&msg->Cause, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_CAUSE, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_locationreportingfailureindication( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_LOCATIONREPORTINGFAILUREINDICATION_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("LocationReportingFailureIndicationIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iMME_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_ENB_UE_S1AP_ID == ie_id) { + if(liblte_s1ap_unpack_enb_ue_s1ap_id(ptr, &msg->eNB_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_CAUSE == ie_id) { + if(liblte_s1ap_unpack_cause(ptr, &msg->Cause) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message LocationReport STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_locationreport( + LIBLTE_S1AP_MESSAGE_LOCATIONREPORT_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("LocationReportIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 5; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - MME_UE_S1AP_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_mme_ue_s1ap_id(&msg->MME_UE_S1AP_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_MME_UE_S1AP_ID, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - eNB_UE_S1AP_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_enb_ue_s1ap_id(&msg->eNB_UE_S1AP_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_ENB_UE_S1AP_ID, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - EUTRAN_CGI + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_eutran_cgi(&msg->EUTRAN_CGI, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_EUTRAN_CGI, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - TAI + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_tai(&msg->TAI, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_TAI, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - RequestType + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_requesttype(&msg->RequestType, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_REQUESTTYPE, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_locationreport( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_LOCATIONREPORT_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("LocationReportIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iMME_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_ENB_UE_S1AP_ID == ie_id) { + if(liblte_s1ap_unpack_enb_ue_s1ap_id(ptr, &msg->eNB_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_EUTRAN_CGI == ie_id) { + if(liblte_s1ap_unpack_eutran_cgi(ptr, &msg->EUTRAN_CGI) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_TAI == ie_id) { + if(liblte_s1ap_unpack_tai(ptr, &msg->TAI) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_REQUESTTYPE == ie_id) { + if(liblte_s1ap_unpack_requesttype(ptr, &msg->RequestType) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message OverloadStart STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_overloadstart( + LIBLTE_S1AP_MESSAGE_OVERLOADSTART_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("OverloadStartIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 3; + if(!msg->GUMMEIList_present) + n_ie--; + if(!msg->TrafficLoadReductionIndication_present) + n_ie--; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - OverloadResponse + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_overloadresponse(&msg->OverloadResponse, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_OVERLOADRESPONSE, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - GUMMEIList + if(msg->GUMMEIList_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_gummeilist(&msg->GUMMEIList, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_GUMMEILIST, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - TrafficLoadReductionIndication + if(msg->TrafficLoadReductionIndication_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_trafficloadreductionindication(&msg->TrafficLoadReductionIndication, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_TRAFFICLOADREDUCTIONINDICATION, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_overloadstart( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_OVERLOADSTART_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + msg->GUMMEIList_present = false; + msg->TrafficLoadReductionIndication_present = false; + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("OverloadStartIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iOverloadResponse) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_GUMMEILIST == ie_id) { + if(liblte_s1ap_unpack_gummeilist(ptr, &msg->GUMMEIList) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->GUMMEIList_present = true; + } else if(LIBLTE_S1AP_IE_ID_TRAFFICLOADREDUCTIONINDICATION == ie_id) { + if(liblte_s1ap_unpack_trafficloadreductionindication(ptr, &msg->TrafficLoadReductionIndication) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->TrafficLoadReductionIndication_present = true; + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message OverloadStop STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_overloadstop( + LIBLTE_S1AP_MESSAGE_OVERLOADSTOP_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("OverloadStopIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 1; + if(!msg->GUMMEIList_present) + n_ie--; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - GUMMEIList + if(msg->GUMMEIList_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_gummeilist(&msg->GUMMEIList, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_GUMMEILIST, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_overloadstop( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_OVERLOADSTOP_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + msg->GUMMEIList_present = false; + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("OverloadStopIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iGUMMEIList) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->GUMMEIList_present = true; + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message WriteReplaceWarningRequest STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_writereplacewarningrequest( + LIBLTE_S1AP_MESSAGE_WRITEREPLACEWARNINGREQUEST_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("WriteReplaceWarningRequestIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 11; + if(!msg->WarningAreaList_present) + n_ie--; + if(!msg->ExtendedRepetitionPeriod_present) + n_ie--; + if(!msg->WarningType_present) + n_ie--; + if(!msg->WarningSecurityInfo_present) + n_ie--; + if(!msg->DataCodingScheme_present) + n_ie--; + if(!msg->WarningMessageContents_present) + n_ie--; + if(!msg->ConcurrentWarningMessageIndicator_present) + n_ie--; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - MessageIdentifier + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_messageidentifier(&msg->MessageIdentifier, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_MESSAGEIDENTIFIER, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - SerialNumber + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_serialnumber(&msg->SerialNumber, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_SERIALNUMBER, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - WarningAreaList + if(msg->WarningAreaList_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_warningarealist(&msg->WarningAreaList, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_WARNINGAREALIST, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - RepetitionPeriod + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_repetitionperiod(&msg->RepetitionPeriod, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_REPETITIONPERIOD, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - ExtendedRepetitionPeriod + if(msg->ExtendedRepetitionPeriod_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_extendedrepetitionperiod(&msg->ExtendedRepetitionPeriod, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_EXTENDEDREPETITIONPERIOD, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - NumberofBroadcastRequest + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_numberofbroadcastrequest(&msg->NumberofBroadcastRequest, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_NUMBEROFBROADCASTREQUEST, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - WarningType + if(msg->WarningType_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_warningtype(&msg->WarningType, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_WARNINGTYPE, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - WarningSecurityInfo + if(msg->WarningSecurityInfo_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_warningsecurityinfo(&msg->WarningSecurityInfo, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_WARNINGSECURITYINFO, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - DataCodingScheme + if(msg->DataCodingScheme_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_datacodingscheme(&msg->DataCodingScheme, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_DATACODINGSCHEME, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - WarningMessageContents + if(msg->WarningMessageContents_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_warningmessagecontents(&msg->WarningMessageContents, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_WARNINGMESSAGECONTENTS, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - ConcurrentWarningMessageIndicator + if(msg->ConcurrentWarningMessageIndicator_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_concurrentwarningmessageindicator(&msg->ConcurrentWarningMessageIndicator, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_CONCURRENTWARNINGMESSAGEINDICATOR, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_writereplacewarningrequest( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_WRITEREPLACEWARNINGREQUEST_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + msg->WarningAreaList_present = false; + msg->ExtendedRepetitionPeriod_present = false; + msg->WarningType_present = false; + msg->WarningSecurityInfo_present = false; + msg->DataCodingScheme_present = false; + msg->WarningMessageContents_present = false; + msg->ConcurrentWarningMessageIndicator_present = false; + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("WriteReplaceWarningRequestIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iMessageIdentifier) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_SERIALNUMBER == ie_id) { + if(liblte_s1ap_unpack_serialnumber(ptr, &msg->SerialNumber) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_WARNINGAREALIST == ie_id) { + if(liblte_s1ap_unpack_warningarealist(ptr, &msg->WarningAreaList) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->WarningAreaList_present = true; + } else if(LIBLTE_S1AP_IE_ID_REPETITIONPERIOD == ie_id) { + if(liblte_s1ap_unpack_repetitionperiod(ptr, &msg->RepetitionPeriod) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_EXTENDEDREPETITIONPERIOD == ie_id) { + if(liblte_s1ap_unpack_extendedrepetitionperiod(ptr, &msg->ExtendedRepetitionPeriod) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->ExtendedRepetitionPeriod_present = true; + } else if(LIBLTE_S1AP_IE_ID_NUMBEROFBROADCASTREQUEST == ie_id) { + if(liblte_s1ap_unpack_numberofbroadcastrequest(ptr, &msg->NumberofBroadcastRequest) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_WARNINGTYPE == ie_id) { + if(liblte_s1ap_unpack_warningtype(ptr, &msg->WarningType) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->WarningType_present = true; + } else if(LIBLTE_S1AP_IE_ID_WARNINGSECURITYINFO == ie_id) { + if(liblte_s1ap_unpack_warningsecurityinfo(ptr, &msg->WarningSecurityInfo) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->WarningSecurityInfo_present = true; + } else if(LIBLTE_S1AP_IE_ID_DATACODINGSCHEME == ie_id) { + if(liblte_s1ap_unpack_datacodingscheme(ptr, &msg->DataCodingScheme) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->DataCodingScheme_present = true; + } else if(LIBLTE_S1AP_IE_ID_WARNINGMESSAGECONTENTS == ie_id) { + if(liblte_s1ap_unpack_warningmessagecontents(ptr, &msg->WarningMessageContents) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->WarningMessageContents_present = true; + } else if(LIBLTE_S1AP_IE_ID_CONCURRENTWARNINGMESSAGEINDICATOR == ie_id) { + if(liblte_s1ap_unpack_concurrentwarningmessageindicator(ptr, &msg->ConcurrentWarningMessageIndicator) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->ConcurrentWarningMessageIndicator_present = true; + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message WriteReplaceWarningResponse STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_writereplacewarningresponse( + LIBLTE_S1AP_MESSAGE_WRITEREPLACEWARNINGRESPONSE_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("WriteReplaceWarningResponseIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 4; + if(!msg->BroadcastCompletedAreaList_present) + n_ie--; + if(!msg->CriticalityDiagnostics_present) + n_ie--; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - MessageIdentifier + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_messageidentifier(&msg->MessageIdentifier, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_MESSAGEIDENTIFIER, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - SerialNumber + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_serialnumber(&msg->SerialNumber, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_SERIALNUMBER, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - BroadcastCompletedAreaList + if(msg->BroadcastCompletedAreaList_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_broadcastcompletedarealist(&msg->BroadcastCompletedAreaList, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_BROADCASTCOMPLETEDAREALIST, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - CriticalityDiagnostics + if(msg->CriticalityDiagnostics_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_criticalitydiagnostics(&msg->CriticalityDiagnostics, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_CRITICALITYDIAGNOSTICS, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_writereplacewarningresponse( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_WRITEREPLACEWARNINGRESPONSE_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + msg->BroadcastCompletedAreaList_present = false; + msg->CriticalityDiagnostics_present = false; + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("WriteReplaceWarningResponseIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iMessageIdentifier) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_SERIALNUMBER == ie_id) { + if(liblte_s1ap_unpack_serialnumber(ptr, &msg->SerialNumber) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_BROADCASTCOMPLETEDAREALIST == ie_id) { + if(liblte_s1ap_unpack_broadcastcompletedarealist(ptr, &msg->BroadcastCompletedAreaList) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->BroadcastCompletedAreaList_present = true; + } else if(LIBLTE_S1AP_IE_ID_CRITICALITYDIAGNOSTICS == ie_id) { + if(liblte_s1ap_unpack_criticalitydiagnostics(ptr, &msg->CriticalityDiagnostics) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->CriticalityDiagnostics_present = true; + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message MMEDirectInformationTransfer STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_mmedirectinformationtransfer( + LIBLTE_S1AP_MESSAGE_MMEDIRECTINFORMATIONTRANSFER_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("MMEDirectInformationTransferIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 1; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - Inter_SystemInformationTransferTypeMDT + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_inter_systeminformationtransfertype(&msg->Inter_SystemInformationTransferTypeMDT, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_INTER_SYSTEMINFORMATIONTRANSFERTYPEMDT, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_mmedirectinformationtransfer( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_MMEDIRECTINFORMATIONTRANSFER_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("MMEDirectInformationTransferIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iInter_SystemInformationTransferTypeMDT) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message ENBConfigurationTransfer STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_enbconfigurationtransfer( + LIBLTE_S1AP_MESSAGE_ENBCONFIGURATIONTRANSFER_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("ENBConfigurationTransferIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 1; + if(!msg->SONConfigurationTransferECT_present) + n_ie--; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - SONConfigurationTransferECT + if(msg->SONConfigurationTransferECT_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_sonconfigurationtransfer(&msg->SONConfigurationTransferECT, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_SONCONFIGURATIONTRANSFERECT, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_enbconfigurationtransfer( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_ENBCONFIGURATIONTRANSFER_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + msg->SONConfigurationTransferECT_present = false; + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("ENBConfigurationTransferIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iSONConfigurationTransferECT) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->SONConfigurationTransferECT_present = true; + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message MMEConfigurationTransfer STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_mmeconfigurationtransfer( + LIBLTE_S1AP_MESSAGE_MMECONFIGURATIONTRANSFER_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("MMEConfigurationTransferIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 1; + if(!msg->SONConfigurationTransferMCT_present) + n_ie--; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - SONConfigurationTransferMCT + if(msg->SONConfigurationTransferMCT_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_sonconfigurationtransfer(&msg->SONConfigurationTransferMCT, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_SONCONFIGURATIONTRANSFERMCT, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_mmeconfigurationtransfer( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_MMECONFIGURATIONTRANSFER_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + msg->SONConfigurationTransferMCT_present = false; + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("MMEConfigurationTransferIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iSONConfigurationTransferMCT) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->SONConfigurationTransferMCT_present = true; + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message PrivateMessage STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_privatemessage( + LIBLTE_S1AP_MESSAGE_PRIVATEMESSAGE_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("PrivateMessageIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 0; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_privatemessage( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_PRIVATEMESSAGE_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("PrivateMessageIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message KillRequest STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_killrequest( + LIBLTE_S1AP_MESSAGE_KILLREQUEST_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("KillRequestIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 4; + if(!msg->WarningAreaList_present) + n_ie--; + if(!msg->KillAllWarningMessages_present) + n_ie--; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - MessageIdentifier + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_messageidentifier(&msg->MessageIdentifier, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_MESSAGEIDENTIFIER, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - SerialNumber + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_serialnumber(&msg->SerialNumber, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_SERIALNUMBER, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - WarningAreaList + if(msg->WarningAreaList_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_warningarealist(&msg->WarningAreaList, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_WARNINGAREALIST, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - KillAllWarningMessages + if(msg->KillAllWarningMessages_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_killallwarningmessages(&msg->KillAllWarningMessages, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_KILLALLWARNINGMESSAGES, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_killrequest( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_KILLREQUEST_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + msg->WarningAreaList_present = false; + msg->KillAllWarningMessages_present = false; + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("KillRequestIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iMessageIdentifier) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_SERIALNUMBER == ie_id) { + if(liblte_s1ap_unpack_serialnumber(ptr, &msg->SerialNumber) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_WARNINGAREALIST == ie_id) { + if(liblte_s1ap_unpack_warningarealist(ptr, &msg->WarningAreaList) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->WarningAreaList_present = true; + } else if(LIBLTE_S1AP_IE_ID_KILLALLWARNINGMESSAGES == ie_id) { + if(liblte_s1ap_unpack_killallwarningmessages(ptr, &msg->KillAllWarningMessages) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->KillAllWarningMessages_present = true; + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message KillResponse STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_killresponse( + LIBLTE_S1AP_MESSAGE_KILLRESPONSE_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("KillResponseIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 4; + if(!msg->BroadcastCancelledAreaList_present) + n_ie--; + if(!msg->CriticalityDiagnostics_present) + n_ie--; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - MessageIdentifier + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_messageidentifier(&msg->MessageIdentifier, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_MESSAGEIDENTIFIER, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - SerialNumber + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_serialnumber(&msg->SerialNumber, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_SERIALNUMBER, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - BroadcastCancelledAreaList + if(msg->BroadcastCancelledAreaList_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_broadcastcancelledarealist(&msg->BroadcastCancelledAreaList, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_BROADCASTCANCELLEDAREALIST, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - CriticalityDiagnostics + if(msg->CriticalityDiagnostics_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_criticalitydiagnostics(&msg->CriticalityDiagnostics, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_CRITICALITYDIAGNOSTICS, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_killresponse( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_KILLRESPONSE_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + msg->BroadcastCancelledAreaList_present = false; + msg->CriticalityDiagnostics_present = false; + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("KillResponseIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iMessageIdentifier) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_SERIALNUMBER == ie_id) { + if(liblte_s1ap_unpack_serialnumber(ptr, &msg->SerialNumber) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_BROADCASTCANCELLEDAREALIST == ie_id) { + if(liblte_s1ap_unpack_broadcastcancelledarealist(ptr, &msg->BroadcastCancelledAreaList) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->BroadcastCancelledAreaList_present = true; + } else if(LIBLTE_S1AP_IE_ID_CRITICALITYDIAGNOSTICS == ie_id) { + if(liblte_s1ap_unpack_criticalitydiagnostics(ptr, &msg->CriticalityDiagnostics) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->CriticalityDiagnostics_present = true; + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message PWSRestartIndication STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_pwsrestartindication( + LIBLTE_S1AP_MESSAGE_PWSRESTARTINDICATION_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("PWSRestartIndicationIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 4; + if(!msg->EmergencyAreaIDListForRestart_present) + n_ie--; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - ECGIListForRestart + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_ecgilistforrestart(&msg->ECGIListForRestart, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_ECGILISTFORRESTART, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - Global_ENB_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_global_enb_id(&msg->Global_ENB_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_GLOBAL_ENB_ID, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - TAIListForRestart + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_tailistforrestart(&msg->TAIListForRestart, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_TAILISTFORRESTART, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - EmergencyAreaIDListForRestart + if(msg->EmergencyAreaIDListForRestart_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_emergencyareaidlistforrestart(&msg->EmergencyAreaIDListForRestart, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_EMERGENCYAREAIDLISTFORRESTART, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_pwsrestartindication( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_PWSRESTARTINDICATION_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + msg->EmergencyAreaIDListForRestart_present = false; + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("PWSRestartIndicationIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iECGIListForRestart) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_GLOBAL_ENB_ID == ie_id) { + if(liblte_s1ap_unpack_global_enb_id(ptr, &msg->Global_ENB_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_TAILISTFORRESTART == ie_id) { + if(liblte_s1ap_unpack_tailistforrestart(ptr, &msg->TAIListForRestart) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_EMERGENCYAREAIDLISTFORRESTART == ie_id) { + if(liblte_s1ap_unpack_emergencyareaidlistforrestart(ptr, &msg->EmergencyAreaIDListForRestart) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->EmergencyAreaIDListForRestart_present = true; + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message DownlinkUEAssociatedLPPaTransport STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_downlinkueassociatedlppatransport( + LIBLTE_S1AP_MESSAGE_DOWNLINKUEASSOCIATEDLPPATRANSPORT_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("DownlinkUEAssociatedLPPaTransport-IEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 4; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - MME_UE_S1AP_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_mme_ue_s1ap_id(&msg->MME_UE_S1AP_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_MME_UE_S1AP_ID, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - eNB_UE_S1AP_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_enb_ue_s1ap_id(&msg->eNB_UE_S1AP_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_ENB_UE_S1AP_ID, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - Routing_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_routing_id(&msg->Routing_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_ROUTING_ID, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - LPPa_PDU + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_lppa_pdu(&msg->LPPa_PDU, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_LPPA_PDU, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_downlinkueassociatedlppatransport( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_DOWNLINKUEASSOCIATEDLPPATRANSPORT_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("DownlinkUEAssociatedLPPaTransport-IEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iMME_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_ENB_UE_S1AP_ID == ie_id) { + if(liblte_s1ap_unpack_enb_ue_s1ap_id(ptr, &msg->eNB_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_ROUTING_ID == ie_id) { + if(liblte_s1ap_unpack_routing_id(ptr, &msg->Routing_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_LPPA_PDU == ie_id) { + if(liblte_s1ap_unpack_lppa_pdu(ptr, &msg->LPPa_PDU) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message UplinkUEAssociatedLPPaTransport STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_uplinkueassociatedlppatransport( + LIBLTE_S1AP_MESSAGE_UPLINKUEASSOCIATEDLPPATRANSPORT_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("UplinkUEAssociatedLPPaTransport-IEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 4; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - MME_UE_S1AP_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_mme_ue_s1ap_id(&msg->MME_UE_S1AP_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_MME_UE_S1AP_ID, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - eNB_UE_S1AP_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_enb_ue_s1ap_id(&msg->eNB_UE_S1AP_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_ENB_UE_S1AP_ID, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - Routing_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_routing_id(&msg->Routing_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_ROUTING_ID, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - LPPa_PDU + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_lppa_pdu(&msg->LPPa_PDU, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_LPPA_PDU, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_uplinkueassociatedlppatransport( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_UPLINKUEASSOCIATEDLPPATRANSPORT_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("UplinkUEAssociatedLPPaTransport-IEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iMME_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_ENB_UE_S1AP_ID == ie_id) { + if(liblte_s1ap_unpack_enb_ue_s1ap_id(ptr, &msg->eNB_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_ROUTING_ID == ie_id) { + if(liblte_s1ap_unpack_routing_id(ptr, &msg->Routing_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_LPPA_PDU == ie_id) { + if(liblte_s1ap_unpack_lppa_pdu(ptr, &msg->LPPa_PDU) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message DownlinkNonUEAssociatedLPPaTransport STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_downlinknonueassociatedlppatransport( + LIBLTE_S1AP_MESSAGE_DOWNLINKNONUEASSOCIATEDLPPATRANSPORT_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("DownlinkNonUEAssociatedLPPaTransport-IEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 2; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - Routing_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_routing_id(&msg->Routing_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_ROUTING_ID, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - LPPa_PDU + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_lppa_pdu(&msg->LPPa_PDU, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_LPPA_PDU, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_downlinknonueassociatedlppatransport( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_DOWNLINKNONUEASSOCIATEDLPPATRANSPORT_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("DownlinkNonUEAssociatedLPPaTransport-IEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iRouting_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_LPPA_PDU == ie_id) { + if(liblte_s1ap_unpack_lppa_pdu(ptr, &msg->LPPa_PDU) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message UplinkNonUEAssociatedLPPaTransport STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_uplinknonueassociatedlppatransport( + LIBLTE_S1AP_MESSAGE_UPLINKNONUEASSOCIATEDLPPATRANSPORT_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("UplinkNonUEAssociatedLPPaTransport-IEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 2; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - Routing_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_routing_id(&msg->Routing_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_ROUTING_ID, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - LPPa_PDU + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_lppa_pdu(&msg->LPPa_PDU, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_LPPA_PDU, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_uplinknonueassociatedlppatransport( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_UPLINKNONUEASSOCIATEDLPPATRANSPORT_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("UplinkNonUEAssociatedLPPaTransport-IEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iRouting_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_LPPA_PDU == ie_id) { + if(liblte_s1ap_unpack_lppa_pdu(ptr, &msg->LPPa_PDU) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message ENBDirectInformationTransfer STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_enbdirectinformationtransfer( + LIBLTE_S1AP_MESSAGE_ENBDIRECTINFORMATIONTRANSFER_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("ENBDirectInformationTransferIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 1; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - Inter_SystemInformationTransferTypeEDT + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_inter_systeminformationtransfertype(&msg->Inter_SystemInformationTransferTypeEDT, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_INTER_SYSTEMINFORMATIONTRANSFERTYPEEDT, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_enbdirectinformationtransfer( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_ENBDIRECTINFORMATIONTRANSFER_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("ENBDirectInformationTransferIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iInter_SystemInformationTransferTypeEDT) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message E_RABDataForwardingItem STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabdataforwardingitem( + LIBLTE_S1AP_MESSAGE_E_RABDATAFORWARDINGITEM_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("E-RABDataForwardingItemIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 1; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - E_RABDataForwardingItem + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_e_rabdataforwardingitem(&msg->E_RABDataForwardingItem, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_E_RABDATAFORWARDINGITEM, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabdataforwardingitem( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_E_RABDATAFORWARDINGITEM_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("E-RABDataForwardingItemIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iE_RABDataForwardingItem) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message E_RABToBeSetupItemHOReq STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabtobesetupitemhoreq( + LIBLTE_S1AP_MESSAGE_E_RABTOBESETUPITEMHOREQ_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("E-RABToBeSetupItemHOReqIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 1; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - E_RABToBeSetupItemHOReq + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_e_rabtobesetupitemhoreq(&msg->E_RABToBeSetupItemHOReq, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_E_RABTOBESETUPITEMHOREQ, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabtobesetupitemhoreq( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_E_RABTOBESETUPITEMHOREQ_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("E-RABToBeSetupItemHOReqIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iE_RABToBeSetupItemHOReq) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message E_RABAdmittedItem STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabadmitteditem( + LIBLTE_S1AP_MESSAGE_E_RABADMITTEDITEM_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("E-RABAdmittedItemIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 1; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - E_RABAdmittedItem + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_e_rabadmitteditem(&msg->E_RABAdmittedItem, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_E_RABADMITTEDITEM, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabadmitteditem( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_E_RABADMITTEDITEM_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("E-RABAdmittedItemIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iE_RABAdmittedItem) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message E_RABFailedtoSetupItemHOReqAck STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabfailedtosetupitemhoreqack( + LIBLTE_S1AP_MESSAGE_E_RABFAILEDTOSETUPITEMHOREQACK_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("E-RABFailedtoSetupItemHOReqAckIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 1; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - E_RABFailedtoSetupItemHOReqAck + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_e_rabfailedtosetupitemhoreqack(&msg->E_RABFailedtoSetupItemHOReqAck, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_E_RABFAILEDTOSETUPITEMHOREQACK, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabfailedtosetupitemhoreqack( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_E_RABFAILEDTOSETUPITEMHOREQACK_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("E-RABFailedtoSetupItemHOReqAckIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iE_RABFailedtoSetupItemHOReqAck) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message E_RABToBeSwitchedDLItem STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabtobeswitcheddlitem( + LIBLTE_S1AP_MESSAGE_E_RABTOBESWITCHEDDLITEM_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("E-RABToBeSwitchedDLItemIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 1; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - E_RABToBeSwitchedDLItem + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_e_rabtobeswitcheddlitem(&msg->E_RABToBeSwitchedDLItem, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_E_RABTOBESWITCHEDDLITEM, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabtobeswitcheddlitem( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_E_RABTOBESWITCHEDDLITEM_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("E-RABToBeSwitchedDLItemIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iE_RABToBeSwitchedDLItem) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message E_RABToBeSwitchedULItem STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabtobeswitchedulitem( + LIBLTE_S1AP_MESSAGE_E_RABTOBESWITCHEDULITEM_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("E-RABToBeSwitchedULItemIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 1; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - E_RABToBeSwitchedULItem + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_e_rabtobeswitchedulitem(&msg->E_RABToBeSwitchedULItem, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_E_RABTOBESWITCHEDULITEM, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabtobeswitchedulitem( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_E_RABTOBESWITCHEDULITEM_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("E-RABToBeSwitchedULItemIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iE_RABToBeSwitchedULItem) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message E_RABToBeSetupItemBearerSUReq STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabtobesetupitembearersureq( + LIBLTE_S1AP_MESSAGE_E_RABTOBESETUPITEMBEARERSUREQ_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("E-RABToBeSetupItemBearerSUReqIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 1; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - E_RABToBeSetupItemBearerSUReq + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_e_rabtobesetupitembearersureq(&msg->E_RABToBeSetupItemBearerSUReq, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_E_RABTOBESETUPITEMBEARERSUREQ, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabtobesetupitembearersureq( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_E_RABTOBESETUPITEMBEARERSUREQ_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("E-RABToBeSetupItemBearerSUReqIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iE_RABToBeSetupItemBearerSUReq) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message E_RABSetupItemBearerSURes STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabsetupitembearersures( + LIBLTE_S1AP_MESSAGE_E_RABSETUPITEMBEARERSURES_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("E-RABSetupItemBearerSUResIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 1; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - E_RABSetupItemBearerSURes + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_e_rabsetupitembearersures(&msg->E_RABSetupItemBearerSURes, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_E_RABSETUPITEMBEARERSURES, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabsetupitembearersures( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_E_RABSETUPITEMBEARERSURES_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("E-RABSetupItemBearerSUResIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iE_RABSetupItemBearerSURes) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message E_RABToBeModifiedItemBearerModReq STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabtobemodifieditembearermodreq( + LIBLTE_S1AP_MESSAGE_E_RABTOBEMODIFIEDITEMBEARERMODREQ_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("E-RABToBeModifiedItemBearerModReqIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 1; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - E_RABToBeModifiedItemBearerModReq + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_e_rabtobemodifieditembearermodreq(&msg->E_RABToBeModifiedItemBearerModReq, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_E_RABTOBEMODIFIEDITEMBEARERMODREQ, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabtobemodifieditembearermodreq( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_E_RABTOBEMODIFIEDITEMBEARERMODREQ_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("E-RABToBeModifiedItemBearerModReqIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iE_RABToBeModifiedItemBearerModReq) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message E_RABModifyItemBearerModRes STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabmodifyitembearermodres( + LIBLTE_S1AP_MESSAGE_E_RABMODIFYITEMBEARERMODRES_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("E-RABModifyItemBearerModResIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 1; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - E_RABModifyItemBearerModRes + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_e_rabmodifyitembearermodres(&msg->E_RABModifyItemBearerModRes, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_E_RABMODIFYITEMBEARERMODRES, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabmodifyitembearermodres( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_E_RABMODIFYITEMBEARERMODRES_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("E-RABModifyItemBearerModResIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iE_RABModifyItemBearerModRes) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message E_RABReleaseItemBearerRelComp STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabreleaseitembearerrelcomp( + LIBLTE_S1AP_MESSAGE_E_RABRELEASEITEMBEARERRELCOMP_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("E-RABReleaseItemBearerRelCompIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 1; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - E_RABReleaseItemBearerRelComp + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_e_rabreleaseitembearerrelcomp(&msg->E_RABReleaseItemBearerRelComp, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_E_RABRELEASEITEMBEARERRELCOMP, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabreleaseitembearerrelcomp( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_E_RABRELEASEITEMBEARERRELCOMP_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("E-RABReleaseItemBearerRelCompIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iE_RABReleaseItemBearerRelComp) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message E_RABToBeSetupItemCtxtSUReq STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabtobesetupitemctxtsureq( + LIBLTE_S1AP_MESSAGE_E_RABTOBESETUPITEMCTXTSUREQ_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("E-RABToBeSetupItemCtxtSUReqIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 1; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - E_RABToBeSetupItemCtxtSUReq + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_e_rabtobesetupitemctxtsureq(&msg->E_RABToBeSetupItemCtxtSUReq, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_E_RABTOBESETUPITEMCTXTSUREQ, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabtobesetupitemctxtsureq( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_E_RABTOBESETUPITEMCTXTSUREQ_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("E-RABToBeSetupItemCtxtSUReqIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iE_RABToBeSetupItemCtxtSUReq) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message E_RABSetupItemCtxtSURes STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabsetupitemctxtsures( + LIBLTE_S1AP_MESSAGE_E_RABSETUPITEMCTXTSURES_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("E-RABSetupItemCtxtSUResIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 1; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - E_RABSetupItemCtxtSURes + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_e_rabsetupitemctxtsures(&msg->E_RABSetupItemCtxtSURes, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_E_RABSETUPITEMCTXTSURES, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabsetupitemctxtsures( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_E_RABSETUPITEMCTXTSURES_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("E-RABSetupItemCtxtSUResIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iE_RABSetupItemCtxtSURes) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message TAIItem STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_taiitem( + LIBLTE_S1AP_MESSAGE_TAIITEM_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("TAIItemIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 1; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - TAIItem + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_taiitem(&msg->TAIItem, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_TAIITEM, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_taiitem( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_TAIITEM_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("TAIItemIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iTAIItem) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message ResetAcknowledge STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_resetacknowledge( + LIBLTE_S1AP_MESSAGE_RESETACKNOWLEDGE_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("ResetAcknowledgeIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 2; + if(!msg->UE_associatedLogicalS1_ConnectionListResAck_present) + n_ie--; + if(!msg->CriticalityDiagnostics_present) + n_ie--; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - UE_associatedLogicalS1_ConnectionListResAck + if(msg->UE_associatedLogicalS1_ConnectionListResAck_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_ue_associatedlogicals1_connectionlistresack(&msg->UE_associatedLogicalS1_ConnectionListResAck, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_UE_ASSOCIATEDLOGICALS1_CONNECTIONLISTRESACK, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - CriticalityDiagnostics + if(msg->CriticalityDiagnostics_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_criticalitydiagnostics(&msg->CriticalityDiagnostics, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_CRITICALITYDIAGNOSTICS, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_resetacknowledge( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_RESETACKNOWLEDGE_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + msg->UE_associatedLogicalS1_ConnectionListResAck_present = false; + msg->CriticalityDiagnostics_present = false; + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("ResetAcknowledgeIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iUE_associatedLogicalS1_ConnectionListResAck) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->UE_associatedLogicalS1_ConnectionListResAck_present = true; + } else if(LIBLTE_S1AP_IE_ID_CRITICALITYDIAGNOSTICS == ie_id) { + if(liblte_s1ap_unpack_criticalitydiagnostics(ptr, &msg->CriticalityDiagnostics) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->CriticalityDiagnostics_present = true; + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message Reset STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_reset( + LIBLTE_S1AP_MESSAGE_RESET_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("ResetIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 2; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - Cause + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_cause(&msg->Cause, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_CAUSE, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - ResetType + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_resettype(&msg->ResetType, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_RESETTYPE, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_reset( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_RESET_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("ResetIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iCause) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_RESETTYPE == ie_id) { + if(liblte_s1ap_unpack_resettype(ptr, &msg->ResetType) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message DownlinkS1cdma2000tunneling STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_downlinks1cdma2000tunneling( + LIBLTE_S1AP_MESSAGE_DOWNLINKS1CDMA2000TUNNELING_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("DownlinkS1cdma2000tunnelingIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 6; + if(!msg->E_RABSubjecttoDataForwardingList_present) + n_ie--; + if(!msg->cdma2000HOStatus_present) + n_ie--; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - MME_UE_S1AP_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_mme_ue_s1ap_id(&msg->MME_UE_S1AP_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_MME_UE_S1AP_ID, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - eNB_UE_S1AP_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_enb_ue_s1ap_id(&msg->eNB_UE_S1AP_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_ENB_UE_S1AP_ID, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - E_RABSubjecttoDataForwardingList + if(msg->E_RABSubjecttoDataForwardingList_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_e_rabsubjecttodataforwardinglist(&msg->E_RABSubjecttoDataForwardingList, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_E_RABSUBJECTTODATAFORWARDINGLIST, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - cdma2000HOStatus + if(msg->cdma2000HOStatus_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_cdma2000hostatus(&msg->cdma2000HOStatus, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_CDMA2000HOSTATUS, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - cdma2000RATType + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_cdma2000rattype(&msg->cdma2000RATType, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_CDMA2000RATTYPE, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - cdma2000PDU + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_cdma2000pdu(&msg->cdma2000PDU, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_CDMA2000PDU, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_downlinks1cdma2000tunneling( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_DOWNLINKS1CDMA2000TUNNELING_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + msg->E_RABSubjecttoDataForwardingList_present = false; + msg->cdma2000HOStatus_present = false; + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("DownlinkS1cdma2000tunnelingIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iMME_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_ENB_UE_S1AP_ID == ie_id) { + if(liblte_s1ap_unpack_enb_ue_s1ap_id(ptr, &msg->eNB_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_E_RABSUBJECTTODATAFORWARDINGLIST == ie_id) { + if(liblte_s1ap_unpack_e_rabsubjecttodataforwardinglist(ptr, &msg->E_RABSubjecttoDataForwardingList) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->E_RABSubjecttoDataForwardingList_present = true; + } else if(LIBLTE_S1AP_IE_ID_CDMA2000HOSTATUS == ie_id) { + if(liblte_s1ap_unpack_cdma2000hostatus(ptr, &msg->cdma2000HOStatus) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->cdma2000HOStatus_present = true; + } else if(LIBLTE_S1AP_IE_ID_CDMA2000RATTYPE == ie_id) { + if(liblte_s1ap_unpack_cdma2000rattype(ptr, &msg->cdma2000RATType) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_CDMA2000PDU == ie_id) { + if(liblte_s1ap_unpack_cdma2000pdu(ptr, &msg->cdma2000PDU) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message HandoverCommand STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_handovercommand( + LIBLTE_S1AP_MESSAGE_HANDOVERCOMMAND_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("HandoverCommandIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 9; + if(!msg->NASSecurityParametersfromE_UTRAN_present) + n_ie--; + if(!msg->E_RABSubjecttoDataForwardingList_present) + n_ie--; + if(!msg->E_RABtoReleaseListHOCmd_present) + n_ie--; + if(!msg->Target_ToSource_TransparentContainer_Secondary_present) + n_ie--; + if(!msg->CriticalityDiagnostics_present) + n_ie--; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - MME_UE_S1AP_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_mme_ue_s1ap_id(&msg->MME_UE_S1AP_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_MME_UE_S1AP_ID, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - eNB_UE_S1AP_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_enb_ue_s1ap_id(&msg->eNB_UE_S1AP_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_ENB_UE_S1AP_ID, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - HandoverType + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_handovertype(&msg->HandoverType, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_HANDOVERTYPE, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - NASSecurityParametersfromE_UTRAN + if(msg->NASSecurityParametersfromE_UTRAN_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_nassecurityparametersfrome_utran(&msg->NASSecurityParametersfromE_UTRAN, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_NASSECURITYPARAMETERSFROME_UTRAN, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - E_RABSubjecttoDataForwardingList + if(msg->E_RABSubjecttoDataForwardingList_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_e_rabsubjecttodataforwardinglist(&msg->E_RABSubjecttoDataForwardingList, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_E_RABSUBJECTTODATAFORWARDINGLIST, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - E_RABtoReleaseListHOCmd + if(msg->E_RABtoReleaseListHOCmd_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_e_rablist(&msg->E_RABtoReleaseListHOCmd, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_E_RABTORELEASELISTHOCMD, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - Target_ToSource_TransparentContainer + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_target_tosource_transparentcontainer(&msg->Target_ToSource_TransparentContainer, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_TARGET_TOSOURCE_TRANSPARENTCONTAINER, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - Target_ToSource_TransparentContainer_Secondary + if(msg->Target_ToSource_TransparentContainer_Secondary_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_target_tosource_transparentcontainer(&msg->Target_ToSource_TransparentContainer_Secondary, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_TARGET_TOSOURCE_TRANSPARENTCONTAINER_SECONDARY, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - CriticalityDiagnostics + if(msg->CriticalityDiagnostics_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_criticalitydiagnostics(&msg->CriticalityDiagnostics, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_CRITICALITYDIAGNOSTICS, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_handovercommand( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_HANDOVERCOMMAND_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + msg->NASSecurityParametersfromE_UTRAN_present = false; + msg->E_RABSubjecttoDataForwardingList_present = false; + msg->E_RABtoReleaseListHOCmd_present = false; + msg->Target_ToSource_TransparentContainer_Secondary_present = false; + msg->CriticalityDiagnostics_present = false; + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("HandoverCommandIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iMME_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_ENB_UE_S1AP_ID == ie_id) { + if(liblte_s1ap_unpack_enb_ue_s1ap_id(ptr, &msg->eNB_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_HANDOVERTYPE == ie_id) { + if(liblte_s1ap_unpack_handovertype(ptr, &msg->HandoverType) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_NASSECURITYPARAMETERSFROME_UTRAN == ie_id) { + if(liblte_s1ap_unpack_nassecurityparametersfrome_utran(ptr, &msg->NASSecurityParametersfromE_UTRAN) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_E_RABSUBJECTTODATAFORWARDINGLIST == ie_id) { + if(liblte_s1ap_unpack_e_rabsubjecttodataforwardinglist(ptr, &msg->E_RABSubjecttoDataForwardingList) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->E_RABSubjecttoDataForwardingList_present = true; + } else if(LIBLTE_S1AP_IE_ID_E_RABTORELEASELISTHOCMD == ie_id) { + if(liblte_s1ap_unpack_e_rablist(ptr, &msg->E_RABtoReleaseListHOCmd) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->E_RABtoReleaseListHOCmd_present = true; + } else if(LIBLTE_S1AP_IE_ID_TARGET_TOSOURCE_TRANSPARENTCONTAINER == ie_id) { + if(liblte_s1ap_unpack_target_tosource_transparentcontainer(ptr, &msg->Target_ToSource_TransparentContainer) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_TARGET_TOSOURCE_TRANSPARENTCONTAINER_SECONDARY == ie_id) { + if(liblte_s1ap_unpack_target_tosource_transparentcontainer(ptr, &msg->Target_ToSource_TransparentContainer_Secondary) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->Target_ToSource_TransparentContainer_Secondary_present = true; + } else if(LIBLTE_S1AP_IE_ID_CRITICALITYDIAGNOSTICS == ie_id) { + if(liblte_s1ap_unpack_criticalitydiagnostics(ptr, &msg->CriticalityDiagnostics) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->CriticalityDiagnostics_present = true; + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message HandoverRequest STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_handoverrequest( + LIBLTE_S1AP_MESSAGE_HANDOVERREQUEST_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("HandoverRequestIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 19; + if(!msg->HandoverRestrictionList_present) + n_ie--; + if(!msg->TraceActivation_present) + n_ie--; + if(!msg->RequestType_present) + n_ie--; + if(!msg->SRVCCOperationPossible_present) + n_ie--; + if(!msg->NASSecurityParameterstoE_UTRAN_present) + n_ie--; + if(!msg->CSG_Id_present) + n_ie--; + if(!msg->CSGMembershipStatus_present) + n_ie--; + if(!msg->GUMMEI_ID_present) + n_ie--; + if(!msg->MME_UE_S1AP_ID_2_present) + n_ie--; + if(!msg->ManagementBasedMDTAllowed_present) + n_ie--; + if(!msg->ManagementBasedMDTPLMNList_present) + n_ie--; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - MME_UE_S1AP_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_mme_ue_s1ap_id(&msg->MME_UE_S1AP_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_MME_UE_S1AP_ID, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - HandoverType + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_handovertype(&msg->HandoverType, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_HANDOVERTYPE, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - Cause + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_cause(&msg->Cause, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_CAUSE, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - uEaggregateMaximumBitrate + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_ueaggregatemaximumbitrate(&msg->uEaggregateMaximumBitrate, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_UEAGGREGATEMAXIMUMBITRATE, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - E_RABToBeSetupListHOReq + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_e_rabtobesetuplisthoreq(&msg->E_RABToBeSetupListHOReq, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_E_RABTOBESETUPLISTHOREQ, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - Source_ToTarget_TransparentContainer + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_source_totarget_transparentcontainer(&msg->Source_ToTarget_TransparentContainer, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_SOURCE_TOTARGET_TRANSPARENTCONTAINER, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - UESecurityCapabilities + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_uesecuritycapabilities(&msg->UESecurityCapabilities, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_UESECURITYCAPABILITIES, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - HandoverRestrictionList + if(msg->HandoverRestrictionList_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_handoverrestrictionlist(&msg->HandoverRestrictionList, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_HANDOVERRESTRICTIONLIST, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - TraceActivation + if(msg->TraceActivation_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_traceactivation(&msg->TraceActivation, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_TRACEACTIVATION, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - RequestType + if(msg->RequestType_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_requesttype(&msg->RequestType, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_REQUESTTYPE, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - SRVCCOperationPossible + if(msg->SRVCCOperationPossible_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_srvccoperationpossible(&msg->SRVCCOperationPossible, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_SRVCCOPERATIONPOSSIBLE, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - SecurityContext + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_securitycontext(&msg->SecurityContext, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_SECURITYCONTEXT, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - NASSecurityParameterstoE_UTRAN + if(msg->NASSecurityParameterstoE_UTRAN_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_nassecurityparameterstoe_utran(&msg->NASSecurityParameterstoE_UTRAN, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_NASSECURITYPARAMETERSTOE_UTRAN, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - CSG_Id + if(msg->CSG_Id_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_csg_id(&msg->CSG_Id, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_CSG_ID, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - CSGMembershipStatus + if(msg->CSGMembershipStatus_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_csgmembershipstatus(&msg->CSGMembershipStatus, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_CSGMEMBERSHIPSTATUS, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - GUMMEI_ID + if(msg->GUMMEI_ID_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_gummei(&msg->GUMMEI_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_GUMMEI_ID, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - MME_UE_S1AP_ID_2 + if(msg->MME_UE_S1AP_ID_2_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_mme_ue_s1ap_id(&msg->MME_UE_S1AP_ID_2, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_MME_UE_S1AP_ID_2, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - ManagementBasedMDTAllowed + if(msg->ManagementBasedMDTAllowed_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_managementbasedmdtallowed(&msg->ManagementBasedMDTAllowed, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_MANAGEMENTBASEDMDTALLOWED, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - ManagementBasedMDTPLMNList + if(msg->ManagementBasedMDTPLMNList_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_mdtplmnlist(&msg->ManagementBasedMDTPLMNList, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_MANAGEMENTBASEDMDTPLMNLIST, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_handoverrequest( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_HANDOVERREQUEST_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + msg->HandoverRestrictionList_present = false; + msg->TraceActivation_present = false; + msg->RequestType_present = false; + msg->SRVCCOperationPossible_present = false; + msg->NASSecurityParameterstoE_UTRAN_present = false; + msg->CSG_Id_present = false; + msg->CSGMembershipStatus_present = false; + msg->GUMMEI_ID_present = false; + msg->MME_UE_S1AP_ID_2_present = false; + msg->ManagementBasedMDTAllowed_present = false; + msg->ManagementBasedMDTPLMNList_present = false; + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("HandoverRequestIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iMME_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_HANDOVERTYPE == ie_id) { + if(liblte_s1ap_unpack_handovertype(ptr, &msg->HandoverType) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_CAUSE == ie_id) { + if(liblte_s1ap_unpack_cause(ptr, &msg->Cause) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_UEAGGREGATEMAXIMUMBITRATE == ie_id) { + if(liblte_s1ap_unpack_ueaggregatemaximumbitrate(ptr, &msg->uEaggregateMaximumBitrate) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_E_RABTOBESETUPLISTHOREQ == ie_id) { + if(liblte_s1ap_unpack_e_rabtobesetuplisthoreq(ptr, &msg->E_RABToBeSetupListHOReq) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_SOURCE_TOTARGET_TRANSPARENTCONTAINER == ie_id) { + if(liblte_s1ap_unpack_source_totarget_transparentcontainer(ptr, &msg->Source_ToTarget_TransparentContainer) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_UESECURITYCAPABILITIES == ie_id) { + if(liblte_s1ap_unpack_uesecuritycapabilities(ptr, &msg->UESecurityCapabilities) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_HANDOVERRESTRICTIONLIST == ie_id) { + if(liblte_s1ap_unpack_handoverrestrictionlist(ptr, &msg->HandoverRestrictionList) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->HandoverRestrictionList_present = true; + } else if(LIBLTE_S1AP_IE_ID_TRACEACTIVATION == ie_id) { + if(liblte_s1ap_unpack_traceactivation(ptr, &msg->TraceActivation) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->TraceActivation_present = true; + } else if(LIBLTE_S1AP_IE_ID_REQUESTTYPE == ie_id) { + if(liblte_s1ap_unpack_requesttype(ptr, &msg->RequestType) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->RequestType_present = true; + } else if(LIBLTE_S1AP_IE_ID_SRVCCOPERATIONPOSSIBLE == ie_id) { + if(liblte_s1ap_unpack_srvccoperationpossible(ptr, &msg->SRVCCOperationPossible) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->SRVCCOperationPossible_present = true; + } else if(LIBLTE_S1AP_IE_ID_SECURITYCONTEXT == ie_id) { + if(liblte_s1ap_unpack_securitycontext(ptr, &msg->SecurityContext) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_NASSECURITYPARAMETERSTOE_UTRAN == ie_id) { + if(liblte_s1ap_unpack_nassecurityparameterstoe_utran(ptr, &msg->NASSecurityParameterstoE_UTRAN) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_CSG_ID == ie_id) { + if(liblte_s1ap_unpack_csg_id(ptr, &msg->CSG_Id) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->CSG_Id_present = true; + } else if(LIBLTE_S1AP_IE_ID_CSGMEMBERSHIPSTATUS == ie_id) { + if(liblte_s1ap_unpack_csgmembershipstatus(ptr, &msg->CSGMembershipStatus) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->CSGMembershipStatus_present = true; + } else if(LIBLTE_S1AP_IE_ID_GUMMEI_ID == ie_id) { + if(liblte_s1ap_unpack_gummei(ptr, &msg->GUMMEI_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->GUMMEI_ID_present = true; + } else if(LIBLTE_S1AP_IE_ID_MME_UE_S1AP_ID_2 == ie_id) { + if(liblte_s1ap_unpack_mme_ue_s1ap_id(ptr, &msg->MME_UE_S1AP_ID_2) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->MME_UE_S1AP_ID_2_present = true; + } else if(LIBLTE_S1AP_IE_ID_MANAGEMENTBASEDMDTALLOWED == ie_id) { + if(liblte_s1ap_unpack_managementbasedmdtallowed(ptr, &msg->ManagementBasedMDTAllowed) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->ManagementBasedMDTAllowed_present = true; + } else if(LIBLTE_S1AP_IE_ID_MANAGEMENTBASEDMDTPLMNLIST == ie_id) { + if(liblte_s1ap_unpack_mdtplmnlist(ptr, &msg->ManagementBasedMDTPLMNList) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->ManagementBasedMDTPLMNList_present = true; + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message PathSwitchRequest STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_pathswitchrequest( + LIBLTE_S1AP_MESSAGE_PATHSWITCHREQUEST_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("PathSwitchRequestIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 12; + if(!msg->CSG_Id_present) + n_ie--; + if(!msg->CellAccessMode_present) + n_ie--; + if(!msg->SourceMME_GUMMEI_present) + n_ie--; + if(!msg->CSGMembershipStatus_present) + n_ie--; + if(!msg->Tunnel_Information_for_BBF_present) + n_ie--; + if(!msg->LHN_ID_present) + n_ie--; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - eNB_UE_S1AP_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_enb_ue_s1ap_id(&msg->eNB_UE_S1AP_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_ENB_UE_S1AP_ID, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - E_RABToBeSwitchedDLList + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_e_rabtobeswitcheddllist(&msg->E_RABToBeSwitchedDLList, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_E_RABTOBESWITCHEDDLLIST, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - SourceMME_UE_S1AP_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_mme_ue_s1ap_id(&msg->SourceMME_UE_S1AP_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_SOURCEMME_UE_S1AP_ID, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - EUTRAN_CGI + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_eutran_cgi(&msg->EUTRAN_CGI, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_EUTRAN_CGI, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - TAI + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_tai(&msg->TAI, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_TAI, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - UESecurityCapabilities + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_uesecuritycapabilities(&msg->UESecurityCapabilities, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_UESECURITYCAPABILITIES, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - CSG_Id + if(msg->CSG_Id_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_csg_id(&msg->CSG_Id, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_CSG_ID, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - CellAccessMode + if(msg->CellAccessMode_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_cellaccessmode(&msg->CellAccessMode, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_CELLACCESSMODE, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - SourceMME_GUMMEI + if(msg->SourceMME_GUMMEI_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_gummei(&msg->SourceMME_GUMMEI, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_SOURCEMME_GUMMEI, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - CSGMembershipStatus + if(msg->CSGMembershipStatus_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_csgmembershipstatus(&msg->CSGMembershipStatus, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_CSGMEMBERSHIPSTATUS, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - Tunnel_Information_for_BBF + if(msg->Tunnel_Information_for_BBF_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_tunnelinformation(&msg->Tunnel_Information_for_BBF, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_TUNNEL_INFORMATION_FOR_BBF, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - LHN_ID + if(msg->LHN_ID_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_lhn_id(&msg->LHN_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_LHN_ID, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_pathswitchrequest( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_PATHSWITCHREQUEST_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + msg->CSG_Id_present = false; + msg->CellAccessMode_present = false; + msg->SourceMME_GUMMEI_present = false; + msg->CSGMembershipStatus_present = false; + msg->Tunnel_Information_for_BBF_present = false; + msg->LHN_ID_present = false; + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("PathSwitchRequestIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;ieNB_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_E_RABTOBESWITCHEDDLLIST == ie_id) { + if(liblte_s1ap_unpack_e_rabtobeswitcheddllist(ptr, &msg->E_RABToBeSwitchedDLList) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_SOURCEMME_UE_S1AP_ID == ie_id) { + if(liblte_s1ap_unpack_mme_ue_s1ap_id(ptr, &msg->SourceMME_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_EUTRAN_CGI == ie_id) { + if(liblte_s1ap_unpack_eutran_cgi(ptr, &msg->EUTRAN_CGI) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_TAI == ie_id) { + if(liblte_s1ap_unpack_tai(ptr, &msg->TAI) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_UESECURITYCAPABILITIES == ie_id) { + if(liblte_s1ap_unpack_uesecuritycapabilities(ptr, &msg->UESecurityCapabilities) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_CSG_ID == ie_id) { + if(liblte_s1ap_unpack_csg_id(ptr, &msg->CSG_Id) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->CSG_Id_present = true; + } else if(LIBLTE_S1AP_IE_ID_CELLACCESSMODE == ie_id) { + if(liblte_s1ap_unpack_cellaccessmode(ptr, &msg->CellAccessMode) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->CellAccessMode_present = true; + } else if(LIBLTE_S1AP_IE_ID_SOURCEMME_GUMMEI == ie_id) { + if(liblte_s1ap_unpack_gummei(ptr, &msg->SourceMME_GUMMEI) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->SourceMME_GUMMEI_present = true; + } else if(LIBLTE_S1AP_IE_ID_CSGMEMBERSHIPSTATUS == ie_id) { + if(liblte_s1ap_unpack_csgmembershipstatus(ptr, &msg->CSGMembershipStatus) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->CSGMembershipStatus_present = true; + } else if(LIBLTE_S1AP_IE_ID_TUNNEL_INFORMATION_FOR_BBF == ie_id) { + if(liblte_s1ap_unpack_tunnelinformation(ptr, &msg->Tunnel_Information_for_BBF) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->Tunnel_Information_for_BBF_present = true; + } else if(LIBLTE_S1AP_IE_ID_LHN_ID == ie_id) { + if(liblte_s1ap_unpack_lhn_id(ptr, &msg->LHN_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->LHN_ID_present = true; + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message PathSwitchRequestAcknowledge STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_pathswitchrequestacknowledge( + LIBLTE_S1AP_MESSAGE_PATHSWITCHREQUESTACKNOWLEDGE_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("PathSwitchRequestAcknowledgeIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 9; + if(!msg->uEaggregateMaximumBitrate_present) + n_ie--; + if(!msg->E_RABToBeSwitchedULList_present) + n_ie--; + if(!msg->E_RABToBeReleasedList_present) + n_ie--; + if(!msg->CriticalityDiagnostics_present) + n_ie--; + if(!msg->MME_UE_S1AP_ID_2_present) + n_ie--; + if(!msg->CSGMembershipStatus_present) + n_ie--; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - MME_UE_S1AP_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_mme_ue_s1ap_id(&msg->MME_UE_S1AP_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_MME_UE_S1AP_ID, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - eNB_UE_S1AP_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_enb_ue_s1ap_id(&msg->eNB_UE_S1AP_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_ENB_UE_S1AP_ID, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - uEaggregateMaximumBitrate + if(msg->uEaggregateMaximumBitrate_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_ueaggregatemaximumbitrate(&msg->uEaggregateMaximumBitrate, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_UEAGGREGATEMAXIMUMBITRATE, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - E_RABToBeSwitchedULList + if(msg->E_RABToBeSwitchedULList_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_e_rabtobeswitchedullist(&msg->E_RABToBeSwitchedULList, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_E_RABTOBESWITCHEDULLIST, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - E_RABToBeReleasedList + if(msg->E_RABToBeReleasedList_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_e_rablist(&msg->E_RABToBeReleasedList, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_E_RABTOBERELEASEDLIST, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - SecurityContext + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_securitycontext(&msg->SecurityContext, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_SECURITYCONTEXT, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - CriticalityDiagnostics + if(msg->CriticalityDiagnostics_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_criticalitydiagnostics(&msg->CriticalityDiagnostics, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_CRITICALITYDIAGNOSTICS, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - MME_UE_S1AP_ID_2 + if(msg->MME_UE_S1AP_ID_2_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_mme_ue_s1ap_id(&msg->MME_UE_S1AP_ID_2, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_MME_UE_S1AP_ID_2, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - CSGMembershipStatus + if(msg->CSGMembershipStatus_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_csgmembershipstatus(&msg->CSGMembershipStatus, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_CSGMEMBERSHIPSTATUS, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_pathswitchrequestacknowledge( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_PATHSWITCHREQUESTACKNOWLEDGE_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + msg->uEaggregateMaximumBitrate_present = false; + msg->E_RABToBeSwitchedULList_present = false; + msg->E_RABToBeReleasedList_present = false; + msg->CriticalityDiagnostics_present = false; + msg->MME_UE_S1AP_ID_2_present = false; + msg->CSGMembershipStatus_present = false; + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("PathSwitchRequestAcknowledgeIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iMME_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_ENB_UE_S1AP_ID == ie_id) { + if(liblte_s1ap_unpack_enb_ue_s1ap_id(ptr, &msg->eNB_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_UEAGGREGATEMAXIMUMBITRATE == ie_id) { + if(liblte_s1ap_unpack_ueaggregatemaximumbitrate(ptr, &msg->uEaggregateMaximumBitrate) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->uEaggregateMaximumBitrate_present = true; + } else if(LIBLTE_S1AP_IE_ID_E_RABTOBESWITCHEDULLIST == ie_id) { + if(liblte_s1ap_unpack_e_rabtobeswitchedullist(ptr, &msg->E_RABToBeSwitchedULList) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->E_RABToBeSwitchedULList_present = true; + } else if(LIBLTE_S1AP_IE_ID_E_RABTOBERELEASEDLIST == ie_id) { + if(liblte_s1ap_unpack_e_rablist(ptr, &msg->E_RABToBeReleasedList) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->E_RABToBeReleasedList_present = true; + } else if(LIBLTE_S1AP_IE_ID_SECURITYCONTEXT == ie_id) { + if(liblte_s1ap_unpack_securitycontext(ptr, &msg->SecurityContext) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_CRITICALITYDIAGNOSTICS == ie_id) { + if(liblte_s1ap_unpack_criticalitydiagnostics(ptr, &msg->CriticalityDiagnostics) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->CriticalityDiagnostics_present = true; + } else if(LIBLTE_S1AP_IE_ID_MME_UE_S1AP_ID_2 == ie_id) { + if(liblte_s1ap_unpack_mme_ue_s1ap_id(ptr, &msg->MME_UE_S1AP_ID_2) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->MME_UE_S1AP_ID_2_present = true; + } else if(LIBLTE_S1AP_IE_ID_CSGMEMBERSHIPSTATUS == ie_id) { + if(liblte_s1ap_unpack_csgmembershipstatus(ptr, &msg->CSGMembershipStatus) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->CSGMembershipStatus_present = true; + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message E_RABSetupRequest STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabsetuprequest( + LIBLTE_S1AP_MESSAGE_E_RABSETUPREQUEST_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("E-RABSetupRequestIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 4; + if(!msg->uEaggregateMaximumBitrate_present) + n_ie--; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - MME_UE_S1AP_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_mme_ue_s1ap_id(&msg->MME_UE_S1AP_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_MME_UE_S1AP_ID, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - eNB_UE_S1AP_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_enb_ue_s1ap_id(&msg->eNB_UE_S1AP_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_ENB_UE_S1AP_ID, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - uEaggregateMaximumBitrate + if(msg->uEaggregateMaximumBitrate_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_ueaggregatemaximumbitrate(&msg->uEaggregateMaximumBitrate, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_UEAGGREGATEMAXIMUMBITRATE, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - E_RABToBeSetupListBearerSUReq + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_e_rabtobesetuplistbearersureq(&msg->E_RABToBeSetupListBearerSUReq, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_E_RABTOBESETUPLISTBEARERSUREQ, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabsetuprequest( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_E_RABSETUPREQUEST_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + msg->uEaggregateMaximumBitrate_present = false; + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("E-RABSetupRequestIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iMME_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_ENB_UE_S1AP_ID == ie_id) { + if(liblte_s1ap_unpack_enb_ue_s1ap_id(ptr, &msg->eNB_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_UEAGGREGATEMAXIMUMBITRATE == ie_id) { + if(liblte_s1ap_unpack_ueaggregatemaximumbitrate(ptr, &msg->uEaggregateMaximumBitrate) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->uEaggregateMaximumBitrate_present = true; + } else if(LIBLTE_S1AP_IE_ID_E_RABTOBESETUPLISTBEARERSUREQ == ie_id) { + if(liblte_s1ap_unpack_e_rabtobesetuplistbearersureq(ptr, &msg->E_RABToBeSetupListBearerSUReq) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message E_RABSetupResponse STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabsetupresponse( + LIBLTE_S1AP_MESSAGE_E_RABSETUPRESPONSE_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("E-RABSetupResponseIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 5; + if(!msg->E_RABSetupListBearerSURes_present) + n_ie--; + if(!msg->E_RABFailedToSetupListBearerSURes_present) + n_ie--; + if(!msg->CriticalityDiagnostics_present) + n_ie--; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - MME_UE_S1AP_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_mme_ue_s1ap_id(&msg->MME_UE_S1AP_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_MME_UE_S1AP_ID, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - eNB_UE_S1AP_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_enb_ue_s1ap_id(&msg->eNB_UE_S1AP_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_ENB_UE_S1AP_ID, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - E_RABSetupListBearerSURes + if(msg->E_RABSetupListBearerSURes_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_e_rabsetuplistbearersures(&msg->E_RABSetupListBearerSURes, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_E_RABSETUPLISTBEARERSURES, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - E_RABFailedToSetupListBearerSURes + if(msg->E_RABFailedToSetupListBearerSURes_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_e_rablist(&msg->E_RABFailedToSetupListBearerSURes, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_E_RABFAILEDTOSETUPLISTBEARERSURES, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - CriticalityDiagnostics + if(msg->CriticalityDiagnostics_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_criticalitydiagnostics(&msg->CriticalityDiagnostics, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_CRITICALITYDIAGNOSTICS, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabsetupresponse( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_E_RABSETUPRESPONSE_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + msg->E_RABSetupListBearerSURes_present = false; + msg->E_RABFailedToSetupListBearerSURes_present = false; + msg->CriticalityDiagnostics_present = false; + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("E-RABSetupResponseIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iMME_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_ENB_UE_S1AP_ID == ie_id) { + if(liblte_s1ap_unpack_enb_ue_s1ap_id(ptr, &msg->eNB_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_E_RABSETUPLISTBEARERSURES == ie_id) { + if(liblte_s1ap_unpack_e_rabsetuplistbearersures(ptr, &msg->E_RABSetupListBearerSURes) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->E_RABSetupListBearerSURes_present = true; + } else if(LIBLTE_S1AP_IE_ID_E_RABFAILEDTOSETUPLISTBEARERSURES == ie_id) { + if(liblte_s1ap_unpack_e_rablist(ptr, &msg->E_RABFailedToSetupListBearerSURes) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->E_RABFailedToSetupListBearerSURes_present = true; + } else if(LIBLTE_S1AP_IE_ID_CRITICALITYDIAGNOSTICS == ie_id) { + if(liblte_s1ap_unpack_criticalitydiagnostics(ptr, &msg->CriticalityDiagnostics) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->CriticalityDiagnostics_present = true; + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message E_RABModifyRequest STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabmodifyrequest( + LIBLTE_S1AP_MESSAGE_E_RABMODIFYREQUEST_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("E-RABModifyRequestIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 4; + if(!msg->uEaggregateMaximumBitrate_present) + n_ie--; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - MME_UE_S1AP_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_mme_ue_s1ap_id(&msg->MME_UE_S1AP_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_MME_UE_S1AP_ID, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - eNB_UE_S1AP_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_enb_ue_s1ap_id(&msg->eNB_UE_S1AP_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_ENB_UE_S1AP_ID, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - uEaggregateMaximumBitrate + if(msg->uEaggregateMaximumBitrate_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_ueaggregatemaximumbitrate(&msg->uEaggregateMaximumBitrate, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_UEAGGREGATEMAXIMUMBITRATE, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - E_RABToBeModifiedListBearerModReq + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_e_rabtobemodifiedlistbearermodreq(&msg->E_RABToBeModifiedListBearerModReq, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_E_RABTOBEMODIFIEDLISTBEARERMODREQ, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabmodifyrequest( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_E_RABMODIFYREQUEST_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + msg->uEaggregateMaximumBitrate_present = false; + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("E-RABModifyRequestIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iMME_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_ENB_UE_S1AP_ID == ie_id) { + if(liblte_s1ap_unpack_enb_ue_s1ap_id(ptr, &msg->eNB_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_UEAGGREGATEMAXIMUMBITRATE == ie_id) { + if(liblte_s1ap_unpack_ueaggregatemaximumbitrate(ptr, &msg->uEaggregateMaximumBitrate) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->uEaggregateMaximumBitrate_present = true; + } else if(LIBLTE_S1AP_IE_ID_E_RABTOBEMODIFIEDLISTBEARERMODREQ == ie_id) { + if(liblte_s1ap_unpack_e_rabtobemodifiedlistbearermodreq(ptr, &msg->E_RABToBeModifiedListBearerModReq) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message E_RABModifyResponse STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabmodifyresponse( + LIBLTE_S1AP_MESSAGE_E_RABMODIFYRESPONSE_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("E-RABModifyResponseIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 5; + if(!msg->E_RABModifyListBearerModRes_present) + n_ie--; + if(!msg->E_RABFailedToModifyList_present) + n_ie--; + if(!msg->CriticalityDiagnostics_present) + n_ie--; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - MME_UE_S1AP_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_mme_ue_s1ap_id(&msg->MME_UE_S1AP_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_MME_UE_S1AP_ID, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - eNB_UE_S1AP_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_enb_ue_s1ap_id(&msg->eNB_UE_S1AP_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_ENB_UE_S1AP_ID, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - E_RABModifyListBearerModRes + if(msg->E_RABModifyListBearerModRes_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_e_rabmodifylistbearermodres(&msg->E_RABModifyListBearerModRes, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_E_RABMODIFYLISTBEARERMODRES, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - E_RABFailedToModifyList + if(msg->E_RABFailedToModifyList_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_e_rablist(&msg->E_RABFailedToModifyList, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_E_RABFAILEDTOMODIFYLIST, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - CriticalityDiagnostics + if(msg->CriticalityDiagnostics_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_criticalitydiagnostics(&msg->CriticalityDiagnostics, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_CRITICALITYDIAGNOSTICS, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabmodifyresponse( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_E_RABMODIFYRESPONSE_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + msg->E_RABModifyListBearerModRes_present = false; + msg->E_RABFailedToModifyList_present = false; + msg->CriticalityDiagnostics_present = false; + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("E-RABModifyResponseIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iMME_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_ENB_UE_S1AP_ID == ie_id) { + if(liblte_s1ap_unpack_enb_ue_s1ap_id(ptr, &msg->eNB_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_E_RABMODIFYLISTBEARERMODRES == ie_id) { + if(liblte_s1ap_unpack_e_rabmodifylistbearermodres(ptr, &msg->E_RABModifyListBearerModRes) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->E_RABModifyListBearerModRes_present = true; + } else if(LIBLTE_S1AP_IE_ID_E_RABFAILEDTOMODIFYLIST == ie_id) { + if(liblte_s1ap_unpack_e_rablist(ptr, &msg->E_RABFailedToModifyList) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->E_RABFailedToModifyList_present = true; + } else if(LIBLTE_S1AP_IE_ID_CRITICALITYDIAGNOSTICS == ie_id) { + if(liblte_s1ap_unpack_criticalitydiagnostics(ptr, &msg->CriticalityDiagnostics) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->CriticalityDiagnostics_present = true; + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message E_RABReleaseResponse STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_e_rabreleaseresponse( + LIBLTE_S1AP_MESSAGE_E_RABRELEASERESPONSE_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("E-RABReleaseResponseIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 6; + if(!msg->E_RABReleaseListBearerRelComp_present) + n_ie--; + if(!msg->E_RABFailedToReleaseList_present) + n_ie--; + if(!msg->CriticalityDiagnostics_present) + n_ie--; + if(!msg->UserLocationInformation_present) + n_ie--; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - MME_UE_S1AP_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_mme_ue_s1ap_id(&msg->MME_UE_S1AP_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_MME_UE_S1AP_ID, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - eNB_UE_S1AP_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_enb_ue_s1ap_id(&msg->eNB_UE_S1AP_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_ENB_UE_S1AP_ID, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - E_RABReleaseListBearerRelComp + if(msg->E_RABReleaseListBearerRelComp_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_e_rabreleaselistbearerrelcomp(&msg->E_RABReleaseListBearerRelComp, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_E_RABRELEASELISTBEARERRELCOMP, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - E_RABFailedToReleaseList + if(msg->E_RABFailedToReleaseList_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_e_rablist(&msg->E_RABFailedToReleaseList, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_E_RABFAILEDTORELEASELIST, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - CriticalityDiagnostics + if(msg->CriticalityDiagnostics_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_criticalitydiagnostics(&msg->CriticalityDiagnostics, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_CRITICALITYDIAGNOSTICS, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - UserLocationInformation + if(msg->UserLocationInformation_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_userlocationinformation(&msg->UserLocationInformation, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_USERLOCATIONINFORMATION, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_e_rabreleaseresponse( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_E_RABRELEASERESPONSE_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + msg->E_RABReleaseListBearerRelComp_present = false; + msg->E_RABFailedToReleaseList_present = false; + msg->CriticalityDiagnostics_present = false; + msg->UserLocationInformation_present = false; + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("E-RABReleaseResponseIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iMME_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_ENB_UE_S1AP_ID == ie_id) { + if(liblte_s1ap_unpack_enb_ue_s1ap_id(ptr, &msg->eNB_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_E_RABRELEASELISTBEARERRELCOMP == ie_id) { + if(liblte_s1ap_unpack_e_rabreleaselistbearerrelcomp(ptr, &msg->E_RABReleaseListBearerRelComp) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->E_RABReleaseListBearerRelComp_present = true; + } else if(LIBLTE_S1AP_IE_ID_E_RABFAILEDTORELEASELIST == ie_id) { + if(liblte_s1ap_unpack_e_rablist(ptr, &msg->E_RABFailedToReleaseList) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->E_RABFailedToReleaseList_present = true; + } else if(LIBLTE_S1AP_IE_ID_CRITICALITYDIAGNOSTICS == ie_id) { + if(liblte_s1ap_unpack_criticalitydiagnostics(ptr, &msg->CriticalityDiagnostics) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->CriticalityDiagnostics_present = true; + } else if(LIBLTE_S1AP_IE_ID_USERLOCATIONINFORMATION == ie_id) { + if(liblte_s1ap_unpack_userlocationinformation(ptr, &msg->UserLocationInformation) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->UserLocationInformation_present = true; + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message InitialContextSetupRequest STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_initialcontextsetuprequest( + LIBLTE_S1AP_MESSAGE_INITIALCONTEXTSETUPREQUEST_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("InitialContextSetupRequestIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 19; + if(!msg->TraceActivation_present) + n_ie--; + if(!msg->HandoverRestrictionList_present) + n_ie--; + if(!msg->UERadioCapability_present) + n_ie--; + if(!msg->SubscriberProfileIDforRFP_present) + n_ie--; + if(!msg->CSFallbackIndicator_present) + n_ie--; + if(!msg->SRVCCOperationPossible_present) + n_ie--; + if(!msg->CSGMembershipStatus_present) + n_ie--; + if(!msg->RegisteredLAI_present) + n_ie--; + if(!msg->GUMMEI_ID_present) + n_ie--; + if(!msg->MME_UE_S1AP_ID_2_present) + n_ie--; + if(!msg->ManagementBasedMDTAllowed_present) + n_ie--; + if(!msg->ManagementBasedMDTPLMNList_present) + n_ie--; + if(!msg->AdditionalCSFallbackIndicator_present) + n_ie--; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - MME_UE_S1AP_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_mme_ue_s1ap_id(&msg->MME_UE_S1AP_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_MME_UE_S1AP_ID, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - eNB_UE_S1AP_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_enb_ue_s1ap_id(&msg->eNB_UE_S1AP_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_ENB_UE_S1AP_ID, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - uEaggregateMaximumBitrate + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_ueaggregatemaximumbitrate(&msg->uEaggregateMaximumBitrate, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_UEAGGREGATEMAXIMUMBITRATE, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - E_RABToBeSetupListCtxtSUReq + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_e_rabtobesetuplistctxtsureq(&msg->E_RABToBeSetupListCtxtSUReq, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_E_RABTOBESETUPLISTCTXTSUREQ, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - UESecurityCapabilities + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_uesecuritycapabilities(&msg->UESecurityCapabilities, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_UESECURITYCAPABILITIES, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - SecurityKey + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_securitykey(&msg->SecurityKey, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_SECURITYKEY, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - TraceActivation + if(msg->TraceActivation_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_traceactivation(&msg->TraceActivation, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_TRACEACTIVATION, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - HandoverRestrictionList + if(msg->HandoverRestrictionList_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_handoverrestrictionlist(&msg->HandoverRestrictionList, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_HANDOVERRESTRICTIONLIST, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - UERadioCapability + if(msg->UERadioCapability_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_ueradiocapability(&msg->UERadioCapability, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_UERADIOCAPABILITY, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - SubscriberProfileIDforRFP + if(msg->SubscriberProfileIDforRFP_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_subscriberprofileidforrfp(&msg->SubscriberProfileIDforRFP, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_SUBSCRIBERPROFILEIDFORRFP, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - CSFallbackIndicator + if(msg->CSFallbackIndicator_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_csfallbackindicator(&msg->CSFallbackIndicator, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_CSFALLBACKINDICATOR, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - SRVCCOperationPossible + if(msg->SRVCCOperationPossible_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_srvccoperationpossible(&msg->SRVCCOperationPossible, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_SRVCCOPERATIONPOSSIBLE, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - CSGMembershipStatus + if(msg->CSGMembershipStatus_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_csgmembershipstatus(&msg->CSGMembershipStatus, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_CSGMEMBERSHIPSTATUS, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - RegisteredLAI + if(msg->RegisteredLAI_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_lai(&msg->RegisteredLAI, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_REGISTEREDLAI, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - GUMMEI_ID + if(msg->GUMMEI_ID_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_gummei(&msg->GUMMEI_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_GUMMEI_ID, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - MME_UE_S1AP_ID_2 + if(msg->MME_UE_S1AP_ID_2_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_mme_ue_s1ap_id(&msg->MME_UE_S1AP_ID_2, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_MME_UE_S1AP_ID_2, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - ManagementBasedMDTAllowed + if(msg->ManagementBasedMDTAllowed_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_managementbasedmdtallowed(&msg->ManagementBasedMDTAllowed, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_MANAGEMENTBASEDMDTALLOWED, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - ManagementBasedMDTPLMNList + if(msg->ManagementBasedMDTPLMNList_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_mdtplmnlist(&msg->ManagementBasedMDTPLMNList, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_MANAGEMENTBASEDMDTPLMNLIST, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - AdditionalCSFallbackIndicator + if(msg->AdditionalCSFallbackIndicator_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_additionalcsfallbackindicator(&msg->AdditionalCSFallbackIndicator, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_ADDITIONALCSFALLBACKINDICATOR, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_initialcontextsetuprequest( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_INITIALCONTEXTSETUPREQUEST_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + msg->TraceActivation_present = false; + msg->HandoverRestrictionList_present = false; + msg->UERadioCapability_present = false; + msg->SubscriberProfileIDforRFP_present = false; + msg->CSFallbackIndicator_present = false; + msg->SRVCCOperationPossible_present = false; + msg->CSGMembershipStatus_present = false; + msg->RegisteredLAI_present = false; + msg->GUMMEI_ID_present = false; + msg->MME_UE_S1AP_ID_2_present = false; + msg->ManagementBasedMDTAllowed_present = false; + msg->ManagementBasedMDTPLMNList_present = false; + msg->AdditionalCSFallbackIndicator_present = false; + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("InitialContextSetupRequestIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iMME_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_ENB_UE_S1AP_ID == ie_id) { + if(liblte_s1ap_unpack_enb_ue_s1ap_id(ptr, &msg->eNB_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_UEAGGREGATEMAXIMUMBITRATE == ie_id) { + if(liblte_s1ap_unpack_ueaggregatemaximumbitrate(ptr, &msg->uEaggregateMaximumBitrate) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_E_RABTOBESETUPLISTCTXTSUREQ == ie_id) { + if(liblte_s1ap_unpack_e_rabtobesetuplistctxtsureq(ptr, &msg->E_RABToBeSetupListCtxtSUReq) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_UESECURITYCAPABILITIES == ie_id) { + if(liblte_s1ap_unpack_uesecuritycapabilities(ptr, &msg->UESecurityCapabilities) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_SECURITYKEY == ie_id) { + if(liblte_s1ap_unpack_securitykey(ptr, &msg->SecurityKey) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_TRACEACTIVATION == ie_id) { + if(liblte_s1ap_unpack_traceactivation(ptr, &msg->TraceActivation) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->TraceActivation_present = true; + } else if(LIBLTE_S1AP_IE_ID_HANDOVERRESTRICTIONLIST == ie_id) { + if(liblte_s1ap_unpack_handoverrestrictionlist(ptr, &msg->HandoverRestrictionList) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->HandoverRestrictionList_present = true; + } else if(LIBLTE_S1AP_IE_ID_UERADIOCAPABILITY == ie_id) { + if(liblte_s1ap_unpack_ueradiocapability(ptr, &msg->UERadioCapability) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->UERadioCapability_present = true; + } else if(LIBLTE_S1AP_IE_ID_SUBSCRIBERPROFILEIDFORRFP == ie_id) { + if(liblte_s1ap_unpack_subscriberprofileidforrfp(ptr, &msg->SubscriberProfileIDforRFP) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->SubscriberProfileIDforRFP_present = true; + } else if(LIBLTE_S1AP_IE_ID_CSFALLBACKINDICATOR == ie_id) { + if(liblte_s1ap_unpack_csfallbackindicator(ptr, &msg->CSFallbackIndicator) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->CSFallbackIndicator_present = true; + } else if(LIBLTE_S1AP_IE_ID_SRVCCOPERATIONPOSSIBLE == ie_id) { + if(liblte_s1ap_unpack_srvccoperationpossible(ptr, &msg->SRVCCOperationPossible) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->SRVCCOperationPossible_present = true; + } else if(LIBLTE_S1AP_IE_ID_CSGMEMBERSHIPSTATUS == ie_id) { + if(liblte_s1ap_unpack_csgmembershipstatus(ptr, &msg->CSGMembershipStatus) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->CSGMembershipStatus_present = true; + } else if(LIBLTE_S1AP_IE_ID_REGISTEREDLAI == ie_id) { + if(liblte_s1ap_unpack_lai(ptr, &msg->RegisteredLAI) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->RegisteredLAI_present = true; + } else if(LIBLTE_S1AP_IE_ID_GUMMEI_ID == ie_id) { + if(liblte_s1ap_unpack_gummei(ptr, &msg->GUMMEI_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->GUMMEI_ID_present = true; + } else if(LIBLTE_S1AP_IE_ID_MME_UE_S1AP_ID_2 == ie_id) { + if(liblte_s1ap_unpack_mme_ue_s1ap_id(ptr, &msg->MME_UE_S1AP_ID_2) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->MME_UE_S1AP_ID_2_present = true; + } else if(LIBLTE_S1AP_IE_ID_MANAGEMENTBASEDMDTALLOWED == ie_id) { + if(liblte_s1ap_unpack_managementbasedmdtallowed(ptr, &msg->ManagementBasedMDTAllowed) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->ManagementBasedMDTAllowed_present = true; + } else if(LIBLTE_S1AP_IE_ID_MANAGEMENTBASEDMDTPLMNLIST == ie_id) { + if(liblte_s1ap_unpack_mdtplmnlist(ptr, &msg->ManagementBasedMDTPLMNList) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->ManagementBasedMDTPLMNList_present = true; + } else if(LIBLTE_S1AP_IE_ID_ADDITIONALCSFALLBACKINDICATOR == ie_id) { + if(liblte_s1ap_unpack_additionalcsfallbackindicator(ptr, &msg->AdditionalCSFallbackIndicator) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message InitialContextSetupResponse STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_initialcontextsetupresponse( + LIBLTE_S1AP_MESSAGE_INITIALCONTEXTSETUPRESPONSE_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("InitialContextSetupResponseIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 5; + if(!msg->E_RABFailedToSetupListCtxtSURes_present) + n_ie--; + if(!msg->CriticalityDiagnostics_present) + n_ie--; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - MME_UE_S1AP_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_mme_ue_s1ap_id(&msg->MME_UE_S1AP_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_MME_UE_S1AP_ID, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - eNB_UE_S1AP_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_enb_ue_s1ap_id(&msg->eNB_UE_S1AP_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_ENB_UE_S1AP_ID, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - E_RABSetupListCtxtSURes + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_e_rabsetuplistctxtsures(&msg->E_RABSetupListCtxtSURes, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_E_RABSETUPLISTCTXTSURES, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - E_RABFailedToSetupListCtxtSURes + if(msg->E_RABFailedToSetupListCtxtSURes_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_e_rablist(&msg->E_RABFailedToSetupListCtxtSURes, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_E_RABFAILEDTOSETUPLISTCTXTSURES, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - CriticalityDiagnostics + if(msg->CriticalityDiagnostics_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_criticalitydiagnostics(&msg->CriticalityDiagnostics, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_CRITICALITYDIAGNOSTICS, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_initialcontextsetupresponse( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_INITIALCONTEXTSETUPRESPONSE_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + msg->E_RABFailedToSetupListCtxtSURes_present = false; + msg->CriticalityDiagnostics_present = false; + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("InitialContextSetupResponseIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iMME_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_ENB_UE_S1AP_ID == ie_id) { + if(liblte_s1ap_unpack_enb_ue_s1ap_id(ptr, &msg->eNB_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_E_RABSETUPLISTCTXTSURES == ie_id) { + if(liblte_s1ap_unpack_e_rabsetuplistctxtsures(ptr, &msg->E_RABSetupListCtxtSURes) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_E_RABFAILEDTOSETUPLISTCTXTSURES == ie_id) { + if(liblte_s1ap_unpack_e_rablist(ptr, &msg->E_RABFailedToSetupListCtxtSURes) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->E_RABFailedToSetupListCtxtSURes_present = true; + } else if(LIBLTE_S1AP_IE_ID_CRITICALITYDIAGNOSTICS == ie_id) { + if(liblte_s1ap_unpack_criticalitydiagnostics(ptr, &msg->CriticalityDiagnostics) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->CriticalityDiagnostics_present = true; + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message Paging STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_paging( + LIBLTE_S1AP_MESSAGE_PAGING_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("PagingIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 7; + if(!msg->pagingDRX_present) + n_ie--; + if(!msg->CSG_IdList_present) + n_ie--; + if(!msg->PagingPriority_present) + n_ie--; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - UEIdentityIndexValue + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_ueidentityindexvalue(&msg->UEIdentityIndexValue, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_UEIDENTITYINDEXVALUE, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - UEPagingID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_uepagingid(&msg->UEPagingID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_UEPAGINGID, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - pagingDRX + if(msg->pagingDRX_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_pagingdrx(&msg->pagingDRX, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_PAGINGDRX, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - CNDomain + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_cndomain(&msg->CNDomain, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_CNDOMAIN, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - TAIList + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_tailist(&msg->TAIList, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_TAILIST, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - CSG_IdList + if(msg->CSG_IdList_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_csg_idlist(&msg->CSG_IdList, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_CSG_IDLIST, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - PagingPriority + if(msg->PagingPriority_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_pagingpriority(&msg->PagingPriority, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_PAGINGPRIORITY, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_paging( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_PAGING_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + msg->pagingDRX_present = false; + msg->CSG_IdList_present = false; + msg->PagingPriority_present = false; + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("PagingIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iUEIdentityIndexValue) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_UEPAGINGID == ie_id) { + if(liblte_s1ap_unpack_uepagingid(ptr, &msg->UEPagingID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_PAGINGDRX == ie_id) { + if(liblte_s1ap_unpack_pagingdrx(ptr, &msg->pagingDRX) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->pagingDRX_present = true; + } else if(LIBLTE_S1AP_IE_ID_CNDOMAIN == ie_id) { + if(liblte_s1ap_unpack_cndomain(ptr, &msg->CNDomain) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_TAILIST == ie_id) { + if(liblte_s1ap_unpack_tailist(ptr, &msg->TAIList) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_CSG_IDLIST == ie_id) { + if(liblte_s1ap_unpack_csg_idlist(ptr, &msg->CSG_IdList) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->CSG_IdList_present = true; + } else if(LIBLTE_S1AP_IE_ID_PAGINGPRIORITY == ie_id) { + if(liblte_s1ap_unpack_pagingpriority(ptr, &msg->PagingPriority) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->PagingPriority_present = true; + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* Protocol Message HandoverRequestAcknowledge STRUCT +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_handoverrequestacknowledge( + LIBLTE_S1AP_MESSAGE_HANDOVERREQUESTACKNOWLEDGE_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + + // Extension + liblte_value_2_bits(msg->ext?1:0, ptr, 1); + liblte_align_up_zero(ptr, 8); + if(msg->ext) { + liblte_log_print("HandoverRequestAcknowledgeIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_ENCODE_FAIL; + } + + // No. of ProtocolIE + uint32_t n_ie = 8; + if(!msg->E_RABFailedToSetupListHOReqAck_present) + n_ie--; + if(!msg->CSG_Id_present) + n_ie--; + if(!msg->CriticalityDiagnostics_present) + n_ie--; + if(!msg->CellAccessMode_present) + n_ie--; + liblte_value_2_bits(n_ie, ptr, 16); + + // Temp container for IEs + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr; + + // ProtocolIE - MME_UE_S1AP_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_mme_ue_s1ap_id(&msg->MME_UE_S1AP_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_MME_UE_S1AP_ID, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - eNB_UE_S1AP_ID + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_enb_ue_s1ap_id(&msg->eNB_UE_S1AP_ID, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_ENB_UE_S1AP_ID, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - E_RABAdmittedList + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_e_rabadmittedlist(&msg->E_RABAdmittedList, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_E_RABADMITTEDLIST, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - E_RABFailedToSetupListHOReqAck + if(msg->E_RABFailedToSetupListHOReqAck_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_e_rabfailedtosetuplisthoreqack(&msg->E_RABFailedToSetupListHOReqAck, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_E_RABFAILEDTOSETUPLISTHOREQACK, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - Target_ToSource_TransparentContainer + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_target_tosource_transparentcontainer(&msg->Target_ToSource_TransparentContainer, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_TARGET_TOSOURCE_TRANSPARENTCONTAINER, + LIBLTE_S1AP_CRITICALITY_REJECT, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + // ProtocolIE - CSG_Id + if(msg->CSG_Id_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_csg_id(&msg->CSG_Id, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_CSG_ID, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - CriticalityDiagnostics + if(msg->CriticalityDiagnostics_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_criticalitydiagnostics(&msg->CriticalityDiagnostics, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_CRITICALITYDIAGNOSTICS, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + // ProtocolIE - CellAccessMode + if(msg->CellAccessMode_present) { + tmp_msg.reset(); + tmp_ptr = tmp_msg.msg; + if(liblte_s1ap_pack_cellaccessmode(&msg->CellAccessMode, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + liblte_align_up_zero(&tmp_ptr, 8); + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + if(liblte_s1ap_pack_protocolie_header(tmp_msg.N_bits / 8, + LIBLTE_S1AP_IE_ID_CELLACCESSMODE, + LIBLTE_S1AP_CRITICALITY_IGNORE, + ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_handoverrequestacknowledge( + uint8_t **ptr, + LIBLTE_S1AP_MESSAGE_HANDOVERREQUESTACKNOWLEDGE_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_S1AP_CRITICALITY_ENUM crit; + uint32_t ie_id; + uint32_t len; + uint32_t n_ie; + uint32_t i; + + // Set booleans + msg->E_RABFailedToSetupListHOReqAck_present = false; + msg->CSG_Id_present = false; + msg->CriticalityDiagnostics_present = false; + msg->CellAccessMode_present = false; + + // Extension + msg->ext = liblte_bits_2_value(ptr, 1); + liblte_align_up(ptr, 8); + if(msg->ext) { + liblte_log_print("HandoverRequestAcknowledgeIEs error: S1AP ASN extensions not currently supported\n"); + return LIBLTE_ERROR_DECODE_FAIL; + } + + // No. of ProtocolIE-Container + n_ie = liblte_bits_2_value(ptr, 16); + + // Unpack ProtocolIE Fields + for(i=0;iMME_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_ENB_UE_S1AP_ID == ie_id) { + if(liblte_s1ap_unpack_enb_ue_s1ap_id(ptr, &msg->eNB_UE_S1AP_ID) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_E_RABADMITTEDLIST == ie_id) { + if(liblte_s1ap_unpack_e_rabadmittedlist(ptr, &msg->E_RABAdmittedList) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_E_RABFAILEDTOSETUPLISTHOREQACK == ie_id) { + if(liblte_s1ap_unpack_e_rabfailedtosetuplisthoreqack(ptr, &msg->E_RABFailedToSetupListHOReqAck) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->E_RABFailedToSetupListHOReqAck_present = true; + } else if(LIBLTE_S1AP_IE_ID_TARGET_TOSOURCE_TRANSPARENTCONTAINER == ie_id) { + if(liblte_s1ap_unpack_target_tosource_transparentcontainer(ptr, &msg->Target_ToSource_TransparentContainer) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + } else if(LIBLTE_S1AP_IE_ID_CSG_ID == ie_id) { + if(liblte_s1ap_unpack_csg_id(ptr, &msg->CSG_Id) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->CSG_Id_present = true; + } else if(LIBLTE_S1AP_IE_ID_CRITICALITYDIAGNOSTICS == ie_id) { + if(liblte_s1ap_unpack_criticalitydiagnostics(ptr, &msg->CriticalityDiagnostics) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->CriticalityDiagnostics_present = true; + } else if(LIBLTE_S1AP_IE_ID_CELLACCESSMODE == ie_id) { + if(liblte_s1ap_unpack_cellaccessmode(ptr, &msg->CellAccessMode) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + liblte_align_up(ptr, 8); + msg->CellAccessMode_present = true; + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* ProtocolIE-Field +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_protocolie_header( + uint32_t len, + uint32_t ie_id, + LIBLTE_S1AP_CRITICALITY_ENUM crit, + uint8_t **ptr) +{ + liblte_value_2_bits(ie_id, ptr, 16); // ProtocolIE-ID + liblte_value_2_bits(crit, ptr, 2); // Criticality + liblte_align_up_zero(ptr, 8); + if(len < 128) { // Length + liblte_value_2_bits(0, ptr, 1); + liblte_value_2_bits(len, ptr, 7); + } else if(len < 16383) { + liblte_value_2_bits(1, ptr, 1); + liblte_value_2_bits(0, ptr, 1); + liblte_value_2_bits(len, ptr, 14); + } else { + // FIXME: Unlikely to have more than 16K of octets + } + + return LIBLTE_SUCCESS; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_protocolie_header( + uint8_t **ptr, + uint32_t *ie_id, + LIBLTE_S1AP_CRITICALITY_ENUM *crit, + uint32_t *len) +{ + *ie_id = liblte_bits_2_value(ptr, 16); // ProtocolIE-ID + *crit = (LIBLTE_S1AP_CRITICALITY_ENUM)liblte_bits_2_value(ptr, 2); // Criticality + liblte_align_up(ptr, 8); + if(0 == liblte_bits_2_value(ptr, 1)) { // Length + *len = liblte_bits_2_value(ptr, 7); + } else { + if(0 == liblte_bits_2_value(ptr, 1)) { + *len = liblte_bits_2_value(ptr, 14); + } else { + // FIXME: Unlikely to have more than 16K of octets + } + } + + return LIBLTE_SUCCESS; +} + +/******************************************************************************* +/* InitiatingMessage CHOICE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_initiatingmessage( + LIBLTE_S1AP_INITIATINGMESSAGE_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr = tmp_msg.msg; + + // Message + if(msg->choice_type == LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_LOCATIONREPORTINGCONTROL) { + if(liblte_s1ap_pack_locationreportingcontrol(&msg->choice.LocationReportingControl, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(msg->choice_type == LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_DOWNLINKS1CDMA2000TUNNELING) { + if(liblte_s1ap_pack_downlinks1cdma2000tunneling(&msg->choice.DownlinkS1cdma2000tunneling, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(msg->choice_type == LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_S1SETUPREQUEST) { + if(liblte_s1ap_pack_s1setuprequest(&msg->choice.S1SetupRequest, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(msg->choice_type == LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_UECAPABILITYINFOINDICATION) { + if(liblte_s1ap_pack_uecapabilityinfoindication(&msg->choice.UECapabilityInfoIndication, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(msg->choice_type == LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_LOCATIONREPORT) { + if(liblte_s1ap_pack_locationreport(&msg->choice.LocationReport, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(msg->choice_type == LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_UPLINKNONUEASSOCIATEDLPPATRANSPORT) { + if(liblte_s1ap_pack_uplinknonueassociatedlppatransport(&msg->choice.UplinkNonUEAssociatedLPPaTransport, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(msg->choice_type == LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_UPLINKS1CDMA2000TUNNELING) { + if(liblte_s1ap_pack_uplinks1cdma2000tunneling(&msg->choice.UplinkS1cdma2000tunneling, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(msg->choice_type == LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_MMECONFIGURATIONTRANSFER) { + if(liblte_s1ap_pack_mmeconfigurationtransfer(&msg->choice.MMEConfigurationTransfer, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(msg->choice_type == LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_TRACESTART) { + if(liblte_s1ap_pack_tracestart(&msg->choice.TraceStart, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(msg->choice_type == LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_HANDOVERCANCEL) { + if(liblte_s1ap_pack_handovercancel(&msg->choice.HandoverCancel, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(msg->choice_type == LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_UERADIOCAPABILITYMATCHREQUEST) { + if(liblte_s1ap_pack_ueradiocapabilitymatchrequest(&msg->choice.UERadioCapabilityMatchRequest, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(msg->choice_type == LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_DOWNLINKNASTRANSPORT) { + if(liblte_s1ap_pack_downlinknastransport(&msg->choice.DownlinkNASTransport, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(msg->choice_type == LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_INITIALCONTEXTSETUPREQUEST) { + if(liblte_s1ap_pack_initialcontextsetuprequest(&msg->choice.InitialContextSetupRequest, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(msg->choice_type == LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_HANDOVERREQUIRED) { + if(liblte_s1ap_pack_handoverrequired(&msg->choice.HandoverRequired, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(msg->choice_type == LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_MMEDIRECTINFORMATIONTRANSFER) { + if(liblte_s1ap_pack_mmedirectinformationtransfer(&msg->choice.MMEDirectInformationTransfer, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(msg->choice_type == LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_TRACEFAILUREINDICATION) { + if(liblte_s1ap_pack_tracefailureindication(&msg->choice.TraceFailureIndication, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(msg->choice_type == LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_MMECONFIGURATIONUPDATE) { + if(liblte_s1ap_pack_mmeconfigurationupdate(&msg->choice.MMEConfigurationUpdate, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(msg->choice_type == LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_WRITEREPLACEWARNINGREQUEST) { + if(liblte_s1ap_pack_writereplacewarningrequest(&msg->choice.WriteReplaceWarningRequest, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(msg->choice_type == LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_ENBDIRECTINFORMATIONTRANSFER) { + if(liblte_s1ap_pack_enbdirectinformationtransfer(&msg->choice.ENBDirectInformationTransfer, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(msg->choice_type == LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_DOWNLINKUEASSOCIATEDLPPATRANSPORT) { + if(liblte_s1ap_pack_downlinkueassociatedlppatransport(&msg->choice.DownlinkUEAssociatedLPPaTransport, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(msg->choice_type == LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_E_RABRELEASECOMMAND) { + if(liblte_s1ap_pack_e_rabreleasecommand(&msg->choice.E_RABReleaseCommand, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(msg->choice_type == LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_NASNONDELIVERYINDICATION) { + if(liblte_s1ap_pack_nasnondeliveryindication(&msg->choice.NASNonDeliveryIndication, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(msg->choice_type == LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_ENBCONFIGURATIONUPDATE) { + if(liblte_s1ap_pack_enbconfigurationupdate(&msg->choice.ENBConfigurationUpdate, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(msg->choice_type == LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_UPLINKUEASSOCIATEDLPPATRANSPORT) { + if(liblte_s1ap_pack_uplinkueassociatedlppatransport(&msg->choice.UplinkUEAssociatedLPPaTransport, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(msg->choice_type == LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_INITIALUEMESSAGE) { + if(liblte_s1ap_pack_initialuemessage(&msg->choice.InitialUEMessage, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(msg->choice_type == LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_E_RABMODIFYREQUEST) { + if(liblte_s1ap_pack_e_rabmodifyrequest(&msg->choice.E_RABModifyRequest, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(msg->choice_type == LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_UECONTEXTMODIFICATIONREQUEST) { + if(liblte_s1ap_pack_uecontextmodificationrequest(&msg->choice.UEContextModificationRequest, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(msg->choice_type == LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_E_RABSETUPREQUEST) { + if(liblte_s1ap_pack_e_rabsetuprequest(&msg->choice.E_RABSetupRequest, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(msg->choice_type == LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_RESET) { + if(liblte_s1ap_pack_reset(&msg->choice.Reset, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(msg->choice_type == LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_OVERLOADSTART) { + if(liblte_s1ap_pack_overloadstart(&msg->choice.OverloadStart, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(msg->choice_type == LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_E_RABRELEASEINDICATION) { + if(liblte_s1ap_pack_e_rabreleaseindication(&msg->choice.E_RABReleaseIndication, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(msg->choice_type == LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_LOCATIONREPORTINGFAILUREINDICATION) { + if(liblte_s1ap_pack_locationreportingfailureindication(&msg->choice.LocationReportingFailureIndication, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(msg->choice_type == LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_DEACTIVATETRACE) { + if(liblte_s1ap_pack_deactivatetrace(&msg->choice.DeactivateTrace, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(msg->choice_type == LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_PATHSWITCHREQUEST) { + if(liblte_s1ap_pack_pathswitchrequest(&msg->choice.PathSwitchRequest, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(msg->choice_type == LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_HANDOVERREQUEST) { + if(liblte_s1ap_pack_handoverrequest(&msg->choice.HandoverRequest, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(msg->choice_type == LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_DOWNLINKNONUEASSOCIATEDLPPATRANSPORT) { + if(liblte_s1ap_pack_downlinknonueassociatedlppatransport(&msg->choice.DownlinkNonUEAssociatedLPPaTransport, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(msg->choice_type == LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_OVERLOADSTOP) { + if(liblte_s1ap_pack_overloadstop(&msg->choice.OverloadStop, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(msg->choice_type == LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_PAGING) { + if(liblte_s1ap_pack_paging(&msg->choice.Paging, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(msg->choice_type == LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_HANDOVERNOTIFY) { + if(liblte_s1ap_pack_handovernotify(&msg->choice.HandoverNotify, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(msg->choice_type == LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_PWSRESTARTINDICATION) { + if(liblte_s1ap_pack_pwsrestartindication(&msg->choice.PWSRestartIndication, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(msg->choice_type == LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_UECONTEXTRELEASEREQUEST) { + if(liblte_s1ap_pack_uecontextreleaserequest(&msg->choice.UEContextReleaseRequest, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(msg->choice_type == LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_UPLINKNASTRANSPORT) { + if(liblte_s1ap_pack_uplinknastransport(&msg->choice.UplinkNASTransport, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(msg->choice_type == LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_ENBCONFIGURATIONTRANSFER) { + if(liblte_s1ap_pack_enbconfigurationtransfer(&msg->choice.ENBConfigurationTransfer, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(msg->choice_type == LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_MMESTATUSTRANSFER) { + if(liblte_s1ap_pack_mmestatustransfer(&msg->choice.MMEStatusTransfer, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(msg->choice_type == LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_CELLTRAFFICTRACE) { + if(liblte_s1ap_pack_celltraffictrace(&msg->choice.CellTrafficTrace, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(msg->choice_type == LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_UECONTEXTRELEASECOMMAND) { + if(liblte_s1ap_pack_uecontextreleasecommand(&msg->choice.UEContextReleaseCommand, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(msg->choice_type == LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_KILLREQUEST) { + if(liblte_s1ap_pack_killrequest(&msg->choice.KillRequest, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(msg->choice_type == LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_PRIVATEMESSAGE) { + if(liblte_s1ap_pack_privatemessage(&msg->choice.PrivateMessage, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(msg->choice_type == LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_ENBSTATUSTRANSFER) { + if(liblte_s1ap_pack_enbstatustransfer(&msg->choice.ENBStatusTransfer, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(msg->choice_type == LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_ERRORINDICATION) { + if(liblte_s1ap_pack_errorindication(&msg->choice.ErrorIndication, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + + // Procedure code + liblte_value_2_bits(msg->procedureCode, ptr, 8); + + // Criticality + LIBLTE_S1AP_CRITICALITY_ENUM crit = liblte_s1ap_procedure_criticality[msg->procedureCode]; + liblte_value_2_bits(crit, ptr, 2); + liblte_align_up_zero(ptr, 8); + + // Length + uint32_t len = (tmp_msg.N_bits + 7) / 8; + if(len < 128) { + liblte_value_2_bits(0, ptr, 1); + liblte_value_2_bits(len, ptr, 7); + } else if(len < 16383) { + liblte_value_2_bits(1, ptr, 1); + liblte_value_2_bits(0, ptr, 1); + liblte_value_2_bits(len, ptr, 14); + } else { + // FIXME: Unlikely to have more than 16K of octets + } + + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_initiatingmessage( + uint8_t **ptr, + LIBLTE_S1AP_INITIATINGMESSAGE_STRUCT *msg) +{ LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + // Procedure code + msg->procedureCode = liblte_bits_2_value(ptr, 8); + + // Criticality + msg->criticality = (LIBLTE_S1AP_CRITICALITY_ENUM)liblte_bits_2_value(ptr, 2); + liblte_align_up(ptr, 8); + + // Length + uint32_t len = 0; + if(0 == liblte_bits_2_value(ptr, 1)) { + len = liblte_bits_2_value(ptr, 7); + } else { + if(0 == liblte_bits_2_value(ptr, 1)) { + len = liblte_bits_2_value(ptr, 14); + } else { + // FIXME: Unlikely to have more than 16K of octets + } + } + + // Message + if(msg->procedureCode == LIBLTE_S1AP_PROC_ID_LOCATIONREPORTINGCONTROL) { + msg->choice_type = LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_LOCATIONREPORTINGCONTROL; + if(liblte_s1ap_unpack_locationreportingcontrol(ptr, &msg->choice.LocationReportingControl) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(msg->procedureCode == LIBLTE_S1AP_PROC_ID_DOWNLINKS1CDMA2000TUNNELING) { + msg->choice_type = LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_DOWNLINKS1CDMA2000TUNNELING; + if(liblte_s1ap_unpack_downlinks1cdma2000tunneling(ptr, &msg->choice.DownlinkS1cdma2000tunneling) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(msg->procedureCode == LIBLTE_S1AP_PROC_ID_S1SETUP) { + msg->choice_type = LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_S1SETUPREQUEST; + if(liblte_s1ap_unpack_s1setuprequest(ptr, &msg->choice.S1SetupRequest) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(msg->procedureCode == LIBLTE_S1AP_PROC_ID_UECAPABILITYINFOINDICATION) { + msg->choice_type = LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_UECAPABILITYINFOINDICATION; + if(liblte_s1ap_unpack_uecapabilityinfoindication(ptr, &msg->choice.UECapabilityInfoIndication) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(msg->procedureCode == LIBLTE_S1AP_PROC_ID_LOCATIONREPORT) { + msg->choice_type = LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_LOCATIONREPORT; + if(liblte_s1ap_unpack_locationreport(ptr, &msg->choice.LocationReport) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(msg->procedureCode == LIBLTE_S1AP_PROC_ID_UPLINKNONUEASSOCIATEDLPPATRANSPORT) { + msg->choice_type = LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_UPLINKNONUEASSOCIATEDLPPATRANSPORT; + if(liblte_s1ap_unpack_uplinknonueassociatedlppatransport(ptr, &msg->choice.UplinkNonUEAssociatedLPPaTransport) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(msg->procedureCode == LIBLTE_S1AP_PROC_ID_UPLINKS1CDMA2000TUNNELING) { + msg->choice_type = LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_UPLINKS1CDMA2000TUNNELING; + if(liblte_s1ap_unpack_uplinks1cdma2000tunneling(ptr, &msg->choice.UplinkS1cdma2000tunneling) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(msg->procedureCode == LIBLTE_S1AP_PROC_ID_MMECONFIGURATIONTRANSFER) { + msg->choice_type = LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_MMECONFIGURATIONTRANSFER; + if(liblte_s1ap_unpack_mmeconfigurationtransfer(ptr, &msg->choice.MMEConfigurationTransfer) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(msg->procedureCode == LIBLTE_S1AP_PROC_ID_TRACESTART) { + msg->choice_type = LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_TRACESTART; + if(liblte_s1ap_unpack_tracestart(ptr, &msg->choice.TraceStart) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(msg->procedureCode == LIBLTE_S1AP_PROC_ID_HANDOVERCANCEL) { + msg->choice_type = LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_HANDOVERCANCEL; + if(liblte_s1ap_unpack_handovercancel(ptr, &msg->choice.HandoverCancel) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(msg->procedureCode == LIBLTE_S1AP_PROC_ID_UERADIOCAPABILITYMATCH) { + msg->choice_type = LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_UERADIOCAPABILITYMATCHREQUEST; + if(liblte_s1ap_unpack_ueradiocapabilitymatchrequest(ptr, &msg->choice.UERadioCapabilityMatchRequest) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(msg->procedureCode == LIBLTE_S1AP_PROC_ID_DOWNLINKNASTRANSPORT) { + msg->choice_type = LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_DOWNLINKNASTRANSPORT; + if(liblte_s1ap_unpack_downlinknastransport(ptr, &msg->choice.DownlinkNASTransport) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(msg->procedureCode == LIBLTE_S1AP_PROC_ID_INITIALCONTEXTSETUP) { + msg->choice_type = LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_INITIALCONTEXTSETUPREQUEST; + if(liblte_s1ap_unpack_initialcontextsetuprequest(ptr, &msg->choice.InitialContextSetupRequest) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(msg->procedureCode == LIBLTE_S1AP_PROC_ID_HANDOVERPREPARATION) { + msg->choice_type = LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_HANDOVERREQUIRED; + if(liblte_s1ap_unpack_handoverrequired(ptr, &msg->choice.HandoverRequired) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(msg->procedureCode == LIBLTE_S1AP_PROC_ID_MMEDIRECTINFORMATIONTRANSFER) { + msg->choice_type = LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_MMEDIRECTINFORMATIONTRANSFER; + if(liblte_s1ap_unpack_mmedirectinformationtransfer(ptr, &msg->choice.MMEDirectInformationTransfer) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(msg->procedureCode == LIBLTE_S1AP_PROC_ID_TRACEFAILUREINDICATION) { + msg->choice_type = LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_TRACEFAILUREINDICATION; + if(liblte_s1ap_unpack_tracefailureindication(ptr, &msg->choice.TraceFailureIndication) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(msg->procedureCode == LIBLTE_S1AP_PROC_ID_MMECONFIGURATIONUPDATE) { + msg->choice_type = LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_MMECONFIGURATIONUPDATE; + if(liblte_s1ap_unpack_mmeconfigurationupdate(ptr, &msg->choice.MMEConfigurationUpdate) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(msg->procedureCode == LIBLTE_S1AP_PROC_ID_WRITEREPLACEWARNING) { + msg->choice_type = LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_WRITEREPLACEWARNINGREQUEST; + if(liblte_s1ap_unpack_writereplacewarningrequest(ptr, &msg->choice.WriteReplaceWarningRequest) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(msg->procedureCode == LIBLTE_S1AP_PROC_ID_ENBDIRECTINFORMATIONTRANSFER) { + msg->choice_type = LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_ENBDIRECTINFORMATIONTRANSFER; + if(liblte_s1ap_unpack_enbdirectinformationtransfer(ptr, &msg->choice.ENBDirectInformationTransfer) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(msg->procedureCode == LIBLTE_S1AP_PROC_ID_DOWNLINKUEASSOCIATEDLPPATRANSPORT) { + msg->choice_type = LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_DOWNLINKUEASSOCIATEDLPPATRANSPORT; + if(liblte_s1ap_unpack_downlinkueassociatedlppatransport(ptr, &msg->choice.DownlinkUEAssociatedLPPaTransport) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(msg->procedureCode == LIBLTE_S1AP_PROC_ID_E_RABRELEASE) { + msg->choice_type = LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_E_RABRELEASECOMMAND; + if(liblte_s1ap_unpack_e_rabreleasecommand(ptr, &msg->choice.E_RABReleaseCommand) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(msg->procedureCode == LIBLTE_S1AP_PROC_ID_NASNONDELIVERYINDICATION) { + msg->choice_type = LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_NASNONDELIVERYINDICATION; + if(liblte_s1ap_unpack_nasnondeliveryindication(ptr, &msg->choice.NASNonDeliveryIndication) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(msg->procedureCode == LIBLTE_S1AP_PROC_ID_ENBCONFIGURATIONUPDATE) { + msg->choice_type = LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_ENBCONFIGURATIONUPDATE; + if(liblte_s1ap_unpack_enbconfigurationupdate(ptr, &msg->choice.ENBConfigurationUpdate) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(msg->procedureCode == LIBLTE_S1AP_PROC_ID_UPLINKUEASSOCIATEDLPPATRANSPORT) { + msg->choice_type = LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_UPLINKUEASSOCIATEDLPPATRANSPORT; + if(liblte_s1ap_unpack_uplinkueassociatedlppatransport(ptr, &msg->choice.UplinkUEAssociatedLPPaTransport) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(msg->procedureCode == LIBLTE_S1AP_PROC_ID_INITIALUEMESSAGE) { + msg->choice_type = LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_INITIALUEMESSAGE; + if(liblte_s1ap_unpack_initialuemessage(ptr, &msg->choice.InitialUEMessage) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(msg->procedureCode == LIBLTE_S1AP_PROC_ID_E_RABMODIFY) { + msg->choice_type = LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_E_RABMODIFYREQUEST; + if(liblte_s1ap_unpack_e_rabmodifyrequest(ptr, &msg->choice.E_RABModifyRequest) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(msg->procedureCode == LIBLTE_S1AP_PROC_ID_UECONTEXTMODIFICATION) { + msg->choice_type = LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_UECONTEXTMODIFICATIONREQUEST; + if(liblte_s1ap_unpack_uecontextmodificationrequest(ptr, &msg->choice.UEContextModificationRequest) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(msg->procedureCode == LIBLTE_S1AP_PROC_ID_E_RABSETUP) { + msg->choice_type = LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_E_RABSETUPREQUEST; + if(liblte_s1ap_unpack_e_rabsetuprequest(ptr, &msg->choice.E_RABSetupRequest) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(msg->procedureCode == LIBLTE_S1AP_PROC_ID_RESET) { + msg->choice_type = LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_RESET; + if(liblte_s1ap_unpack_reset(ptr, &msg->choice.Reset) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(msg->procedureCode == LIBLTE_S1AP_PROC_ID_OVERLOADSTART) { + msg->choice_type = LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_OVERLOADSTART; + if(liblte_s1ap_unpack_overloadstart(ptr, &msg->choice.OverloadStart) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(msg->procedureCode == LIBLTE_S1AP_PROC_ID_E_RABRELEASEINDICATION) { + msg->choice_type = LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_E_RABRELEASEINDICATION; + if(liblte_s1ap_unpack_e_rabreleaseindication(ptr, &msg->choice.E_RABReleaseIndication) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(msg->procedureCode == LIBLTE_S1AP_PROC_ID_LOCATIONREPORTINGFAILUREINDICATION) { + msg->choice_type = LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_LOCATIONREPORTINGFAILUREINDICATION; + if(liblte_s1ap_unpack_locationreportingfailureindication(ptr, &msg->choice.LocationReportingFailureIndication) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(msg->procedureCode == LIBLTE_S1AP_PROC_ID_DEACTIVATETRACE) { + msg->choice_type = LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_DEACTIVATETRACE; + if(liblte_s1ap_unpack_deactivatetrace(ptr, &msg->choice.DeactivateTrace) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(msg->procedureCode == LIBLTE_S1AP_PROC_ID_PATHSWITCHREQUEST) { + msg->choice_type = LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_PATHSWITCHREQUEST; + if(liblte_s1ap_unpack_pathswitchrequest(ptr, &msg->choice.PathSwitchRequest) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(msg->procedureCode == LIBLTE_S1AP_PROC_ID_HANDOVERRESOURCEALLOCATION) { + msg->choice_type = LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_HANDOVERREQUEST; + if(liblte_s1ap_unpack_handoverrequest(ptr, &msg->choice.HandoverRequest) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(msg->procedureCode == LIBLTE_S1AP_PROC_ID_DOWNLINKNONUEASSOCIATEDLPPATRANSPORT) { + msg->choice_type = LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_DOWNLINKNONUEASSOCIATEDLPPATRANSPORT; + if(liblte_s1ap_unpack_downlinknonueassociatedlppatransport(ptr, &msg->choice.DownlinkNonUEAssociatedLPPaTransport) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(msg->procedureCode == LIBLTE_S1AP_PROC_ID_OVERLOADSTOP) { + msg->choice_type = LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_OVERLOADSTOP; + if(liblte_s1ap_unpack_overloadstop(ptr, &msg->choice.OverloadStop) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(msg->procedureCode == LIBLTE_S1AP_PROC_ID_PAGING) { + msg->choice_type = LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_PAGING; + if(liblte_s1ap_unpack_paging(ptr, &msg->choice.Paging) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(msg->procedureCode == LIBLTE_S1AP_PROC_ID_HANDOVERNOTIFICATION) { + msg->choice_type = LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_HANDOVERNOTIFY; + if(liblte_s1ap_unpack_handovernotify(ptr, &msg->choice.HandoverNotify) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(msg->procedureCode == LIBLTE_S1AP_PROC_ID_PWSRESTARTINDICATION) { + msg->choice_type = LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_PWSRESTARTINDICATION; + if(liblte_s1ap_unpack_pwsrestartindication(ptr, &msg->choice.PWSRestartIndication) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(msg->procedureCode == LIBLTE_S1AP_PROC_ID_UECONTEXTRELEASEREQUEST) { + msg->choice_type = LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_UECONTEXTRELEASEREQUEST; + if(liblte_s1ap_unpack_uecontextreleaserequest(ptr, &msg->choice.UEContextReleaseRequest) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(msg->procedureCode == LIBLTE_S1AP_PROC_ID_UPLINKNASTRANSPORT) { + msg->choice_type = LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_UPLINKNASTRANSPORT; + if(liblte_s1ap_unpack_uplinknastransport(ptr, &msg->choice.UplinkNASTransport) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(msg->procedureCode == LIBLTE_S1AP_PROC_ID_ENBCONFIGURATIONTRANSFER) { + msg->choice_type = LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_ENBCONFIGURATIONTRANSFER; + if(liblte_s1ap_unpack_enbconfigurationtransfer(ptr, &msg->choice.ENBConfigurationTransfer) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(msg->procedureCode == LIBLTE_S1AP_PROC_ID_MMESTATUSTRANSFER) { + msg->choice_type = LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_MMESTATUSTRANSFER; + if(liblte_s1ap_unpack_mmestatustransfer(ptr, &msg->choice.MMEStatusTransfer) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(msg->procedureCode == LIBLTE_S1AP_PROC_ID_CELLTRAFFICTRACE) { + msg->choice_type = LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_CELLTRAFFICTRACE; + if(liblte_s1ap_unpack_celltraffictrace(ptr, &msg->choice.CellTrafficTrace) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(msg->procedureCode == LIBLTE_S1AP_PROC_ID_UECONTEXTRELEASE) { + msg->choice_type = LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_UECONTEXTRELEASECOMMAND; + if(liblte_s1ap_unpack_uecontextreleasecommand(ptr, &msg->choice.UEContextReleaseCommand) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(msg->procedureCode == LIBLTE_S1AP_PROC_ID_KILL) { + msg->choice_type = LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_KILLREQUEST; + if(liblte_s1ap_unpack_killrequest(ptr, &msg->choice.KillRequest) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(msg->procedureCode == LIBLTE_S1AP_PROC_ID_PRIVATEMESSAGE) { + msg->choice_type = LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_PRIVATEMESSAGE; + if(liblte_s1ap_unpack_privatemessage(ptr, &msg->choice.PrivateMessage) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(msg->procedureCode == LIBLTE_S1AP_PROC_ID_ENBSTATUSTRANSFER) { + msg->choice_type = LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_ENBSTATUSTRANSFER; + if(liblte_s1ap_unpack_enbstatustransfer(ptr, &msg->choice.ENBStatusTransfer) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(msg->procedureCode == LIBLTE_S1AP_PROC_ID_ERRORINDICATION) { + msg->choice_type = LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_ERRORINDICATION; + if(liblte_s1ap_unpack_errorindication(ptr, &msg->choice.ErrorIndication) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* UnsuccessfulOutcome CHOICE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_unsuccessfuloutcome( + LIBLTE_S1AP_UNSUCCESSFULOUTCOME_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr = tmp_msg.msg; + + // Message + if(msg->choice_type == LIBLTE_S1AP_UNSUCCESSFULOUTCOME_CHOICE_S1SETUPFAILURE) { + if(liblte_s1ap_pack_s1setupfailure(&msg->choice.S1SetupFailure, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(msg->choice_type == LIBLTE_S1AP_UNSUCCESSFULOUTCOME_CHOICE_PATHSWITCHREQUESTFAILURE) { + if(liblte_s1ap_pack_pathswitchrequestfailure(&msg->choice.PathSwitchRequestFailure, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(msg->choice_type == LIBLTE_S1AP_UNSUCCESSFULOUTCOME_CHOICE_UECONTEXTMODIFICATIONFAILURE) { + if(liblte_s1ap_pack_uecontextmodificationfailure(&msg->choice.UEContextModificationFailure, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(msg->choice_type == LIBLTE_S1AP_UNSUCCESSFULOUTCOME_CHOICE_INITIALCONTEXTSETUPFAILURE) { + if(liblte_s1ap_pack_initialcontextsetupfailure(&msg->choice.InitialContextSetupFailure, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(msg->choice_type == LIBLTE_S1AP_UNSUCCESSFULOUTCOME_CHOICE_ENBCONFIGURATIONUPDATEFAILURE) { + if(liblte_s1ap_pack_enbconfigurationupdatefailure(&msg->choice.ENBConfigurationUpdateFailure, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(msg->choice_type == LIBLTE_S1AP_UNSUCCESSFULOUTCOME_CHOICE_HANDOVERPREPARATIONFAILURE) { + if(liblte_s1ap_pack_handoverpreparationfailure(&msg->choice.HandoverPreparationFailure, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(msg->choice_type == LIBLTE_S1AP_UNSUCCESSFULOUTCOME_CHOICE_HANDOVERFAILURE) { + if(liblte_s1ap_pack_handoverfailure(&msg->choice.HandoverFailure, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(msg->choice_type == LIBLTE_S1AP_UNSUCCESSFULOUTCOME_CHOICE_MMECONFIGURATIONUPDATEFAILURE) { + if(liblte_s1ap_pack_mmeconfigurationupdatefailure(&msg->choice.MMEConfigurationUpdateFailure, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + + // Procedure code + liblte_value_2_bits(msg->procedureCode, ptr, 8); + + // Criticality + LIBLTE_S1AP_CRITICALITY_ENUM crit = liblte_s1ap_procedure_criticality[msg->procedureCode]; + liblte_value_2_bits(crit, ptr, 2); + liblte_align_up_zero(ptr, 8); + + // Length + uint32_t len = (tmp_msg.N_bits + 7) / 8; + if(len < 128) { + liblte_value_2_bits(0, ptr, 1); + liblte_value_2_bits(len, ptr, 7); + } else if(len < 16383) { + liblte_value_2_bits(1, ptr, 1); + liblte_value_2_bits(0, ptr, 1); + liblte_value_2_bits(len, ptr, 14); + } else { + // FIXME: Unlikely to have more than 16K of octets + } + + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_unsuccessfuloutcome( + uint8_t **ptr, + LIBLTE_S1AP_UNSUCCESSFULOUTCOME_STRUCT *msg) +{ LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + // Procedure code + msg->procedureCode = liblte_bits_2_value(ptr, 8); + + // Criticality + msg->criticality = (LIBLTE_S1AP_CRITICALITY_ENUM)liblte_bits_2_value(ptr, 2); + liblte_align_up(ptr, 8); + + // Length + uint32_t len = 0; + if(0 == liblte_bits_2_value(ptr, 1)) { + len = liblte_bits_2_value(ptr, 7); + } else { + if(0 == liblte_bits_2_value(ptr, 1)) { + len = liblte_bits_2_value(ptr, 14); + } else { + // FIXME: Unlikely to have more than 16K of octets + } + } + + // Message + if(msg->procedureCode == LIBLTE_S1AP_PROC_ID_S1SETUP) { + msg->choice_type = LIBLTE_S1AP_UNSUCCESSFULOUTCOME_CHOICE_S1SETUPFAILURE; + if(liblte_s1ap_unpack_s1setupfailure(ptr, &msg->choice.S1SetupFailure) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(msg->procedureCode == LIBLTE_S1AP_PROC_ID_PATHSWITCHREQUEST) { + msg->choice_type = LIBLTE_S1AP_UNSUCCESSFULOUTCOME_CHOICE_PATHSWITCHREQUESTFAILURE; + if(liblte_s1ap_unpack_pathswitchrequestfailure(ptr, &msg->choice.PathSwitchRequestFailure) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(msg->procedureCode == LIBLTE_S1AP_PROC_ID_UECONTEXTMODIFICATION) { + msg->choice_type = LIBLTE_S1AP_UNSUCCESSFULOUTCOME_CHOICE_UECONTEXTMODIFICATIONFAILURE; + if(liblte_s1ap_unpack_uecontextmodificationfailure(ptr, &msg->choice.UEContextModificationFailure) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(msg->procedureCode == LIBLTE_S1AP_PROC_ID_INITIALCONTEXTSETUP) { + msg->choice_type = LIBLTE_S1AP_UNSUCCESSFULOUTCOME_CHOICE_INITIALCONTEXTSETUPFAILURE; + if(liblte_s1ap_unpack_initialcontextsetupfailure(ptr, &msg->choice.InitialContextSetupFailure) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(msg->procedureCode == LIBLTE_S1AP_PROC_ID_ENBCONFIGURATIONUPDATE) { + msg->choice_type = LIBLTE_S1AP_UNSUCCESSFULOUTCOME_CHOICE_ENBCONFIGURATIONUPDATEFAILURE; + if(liblte_s1ap_unpack_enbconfigurationupdatefailure(ptr, &msg->choice.ENBConfigurationUpdateFailure) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(msg->procedureCode == LIBLTE_S1AP_PROC_ID_HANDOVERPREPARATION) { + msg->choice_type = LIBLTE_S1AP_UNSUCCESSFULOUTCOME_CHOICE_HANDOVERPREPARATIONFAILURE; + if(liblte_s1ap_unpack_handoverpreparationfailure(ptr, &msg->choice.HandoverPreparationFailure) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(msg->procedureCode == LIBLTE_S1AP_PROC_ID_HANDOVERRESOURCEALLOCATION) { + msg->choice_type = LIBLTE_S1AP_UNSUCCESSFULOUTCOME_CHOICE_HANDOVERFAILURE; + if(liblte_s1ap_unpack_handoverfailure(ptr, &msg->choice.HandoverFailure) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(msg->procedureCode == LIBLTE_S1AP_PROC_ID_MMECONFIGURATIONUPDATE) { + msg->choice_type = LIBLTE_S1AP_UNSUCCESSFULOUTCOME_CHOICE_MMECONFIGURATIONUPDATEFAILURE; + if(liblte_s1ap_unpack_mmeconfigurationupdatefailure(ptr, &msg->choice.MMEConfigurationUpdateFailure) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + +/******************************************************************************* +/* SuccessfulOutcome CHOICE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_successfuloutcome( + LIBLTE_S1AP_SUCCESSFULOUTCOME_STRUCT *msg, + uint8_t **ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + LIBLTE_BIT_MSG_STRUCT tmp_msg; + uint8_t *tmp_ptr = tmp_msg.msg; + + // Message + if(msg->choice_type == LIBLTE_S1AP_SUCCESSFULOUTCOME_CHOICE_HANDOVERREQUESTACKNOWLEDGE) { + if(liblte_s1ap_pack_handoverrequestacknowledge(&msg->choice.HandoverRequestAcknowledge, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(msg->choice_type == LIBLTE_S1AP_SUCCESSFULOUTCOME_CHOICE_UECONTEXTRELEASECOMPLETE) { + if(liblte_s1ap_pack_uecontextreleasecomplete(&msg->choice.UEContextReleaseComplete, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(msg->choice_type == LIBLTE_S1AP_SUCCESSFULOUTCOME_CHOICE_UERADIOCAPABILITYMATCHRESPONSE) { + if(liblte_s1ap_pack_ueradiocapabilitymatchresponse(&msg->choice.UERadioCapabilityMatchResponse, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(msg->choice_type == LIBLTE_S1AP_SUCCESSFULOUTCOME_CHOICE_INITIALCONTEXTSETUPRESPONSE) { + if(liblte_s1ap_pack_initialcontextsetupresponse(&msg->choice.InitialContextSetupResponse, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(msg->choice_type == LIBLTE_S1AP_SUCCESSFULOUTCOME_CHOICE_E_RABSETUPRESPONSE) { + if(liblte_s1ap_pack_e_rabsetupresponse(&msg->choice.E_RABSetupResponse, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(msg->choice_type == LIBLTE_S1AP_SUCCESSFULOUTCOME_CHOICE_PATHSWITCHREQUESTACKNOWLEDGE) { + if(liblte_s1ap_pack_pathswitchrequestacknowledge(&msg->choice.PathSwitchRequestAcknowledge, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(msg->choice_type == LIBLTE_S1AP_SUCCESSFULOUTCOME_CHOICE_MMECONFIGURATIONUPDATEACKNOWLEDGE) { + if(liblte_s1ap_pack_mmeconfigurationupdateacknowledge(&msg->choice.MMEConfigurationUpdateAcknowledge, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(msg->choice_type == LIBLTE_S1AP_SUCCESSFULOUTCOME_CHOICE_RESETACKNOWLEDGE) { + if(liblte_s1ap_pack_resetacknowledge(&msg->choice.ResetAcknowledge, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(msg->choice_type == LIBLTE_S1AP_SUCCESSFULOUTCOME_CHOICE_ENBCONFIGURATIONUPDATEACKNOWLEDGE) { + if(liblte_s1ap_pack_enbconfigurationupdateacknowledge(&msg->choice.ENBConfigurationUpdateAcknowledge, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(msg->choice_type == LIBLTE_S1AP_SUCCESSFULOUTCOME_CHOICE_E_RABMODIFYRESPONSE) { + if(liblte_s1ap_pack_e_rabmodifyresponse(&msg->choice.E_RABModifyResponse, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(msg->choice_type == LIBLTE_S1AP_SUCCESSFULOUTCOME_CHOICE_WRITEREPLACEWARNINGRESPONSE) { + if(liblte_s1ap_pack_writereplacewarningresponse(&msg->choice.WriteReplaceWarningResponse, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(msg->choice_type == LIBLTE_S1AP_SUCCESSFULOUTCOME_CHOICE_S1SETUPRESPONSE) { + if(liblte_s1ap_pack_s1setupresponse(&msg->choice.S1SetupResponse, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(msg->choice_type == LIBLTE_S1AP_SUCCESSFULOUTCOME_CHOICE_KILLRESPONSE) { + if(liblte_s1ap_pack_killresponse(&msg->choice.KillResponse, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(msg->choice_type == LIBLTE_S1AP_SUCCESSFULOUTCOME_CHOICE_UECONTEXTMODIFICATIONRESPONSE) { + if(liblte_s1ap_pack_uecontextmodificationresponse(&msg->choice.UEContextModificationResponse, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(msg->choice_type == LIBLTE_S1AP_SUCCESSFULOUTCOME_CHOICE_HANDOVERCOMMAND) { + if(liblte_s1ap_pack_handovercommand(&msg->choice.HandoverCommand, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(msg->choice_type == LIBLTE_S1AP_SUCCESSFULOUTCOME_CHOICE_HANDOVERCANCELACKNOWLEDGE) { + if(liblte_s1ap_pack_handovercancelacknowledge(&msg->choice.HandoverCancelAcknowledge, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(msg->choice_type == LIBLTE_S1AP_SUCCESSFULOUTCOME_CHOICE_E_RABRELEASERESPONSE) { + if(liblte_s1ap_pack_e_rabreleaseresponse(&msg->choice.E_RABReleaseResponse, &tmp_ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + tmp_msg.N_bits = tmp_ptr - tmp_msg.msg; + + // Procedure code + liblte_value_2_bits(msg->procedureCode, ptr, 8); + + // Criticality + LIBLTE_S1AP_CRITICALITY_ENUM crit = liblte_s1ap_procedure_criticality[msg->procedureCode]; + liblte_value_2_bits(crit, ptr, 2); + liblte_align_up_zero(ptr, 8); + + // Length + uint32_t len = (tmp_msg.N_bits + 7) / 8; + if(len < 128) { + liblte_value_2_bits(0, ptr, 1); + liblte_value_2_bits(len, ptr, 7); + } else if(len < 16383) { + liblte_value_2_bits(1, ptr, 1); + liblte_value_2_bits(0, ptr, 1); + liblte_value_2_bits(len, ptr, 14); + } else { + // FIXME: Unlikely to have more than 16K of octets + } + + memcpy(*ptr, tmp_msg.msg, tmp_msg.N_bits); + *ptr += tmp_msg.N_bits; + + err = LIBLTE_SUCCESS; + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_successfuloutcome( + uint8_t **ptr, + LIBLTE_S1AP_SUCCESSFULOUTCOME_STRUCT *msg) +{ LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(msg != NULL && + ptr != NULL) + { + // Procedure code + msg->procedureCode = liblte_bits_2_value(ptr, 8); + + // Criticality + msg->criticality = (LIBLTE_S1AP_CRITICALITY_ENUM)liblte_bits_2_value(ptr, 2); + liblte_align_up(ptr, 8); + + // Length + uint32_t len = 0; + if(0 == liblte_bits_2_value(ptr, 1)) { + len = liblte_bits_2_value(ptr, 7); + } else { + if(0 == liblte_bits_2_value(ptr, 1)) { + len = liblte_bits_2_value(ptr, 14); + } else { + // FIXME: Unlikely to have more than 16K of octets + } + } + + // Message + if(msg->procedureCode == LIBLTE_S1AP_PROC_ID_HANDOVERRESOURCEALLOCATION) { + msg->choice_type = LIBLTE_S1AP_SUCCESSFULOUTCOME_CHOICE_HANDOVERREQUESTACKNOWLEDGE; + if(liblte_s1ap_unpack_handoverrequestacknowledge(ptr, &msg->choice.HandoverRequestAcknowledge) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(msg->procedureCode == LIBLTE_S1AP_PROC_ID_UECONTEXTRELEASE) { + msg->choice_type = LIBLTE_S1AP_SUCCESSFULOUTCOME_CHOICE_UECONTEXTRELEASECOMPLETE; + if(liblte_s1ap_unpack_uecontextreleasecomplete(ptr, &msg->choice.UEContextReleaseComplete) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(msg->procedureCode == LIBLTE_S1AP_PROC_ID_UERADIOCAPABILITYMATCH) { + msg->choice_type = LIBLTE_S1AP_SUCCESSFULOUTCOME_CHOICE_UERADIOCAPABILITYMATCHRESPONSE; + if(liblte_s1ap_unpack_ueradiocapabilitymatchresponse(ptr, &msg->choice.UERadioCapabilityMatchResponse) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(msg->procedureCode == LIBLTE_S1AP_PROC_ID_INITIALCONTEXTSETUP) { + msg->choice_type = LIBLTE_S1AP_SUCCESSFULOUTCOME_CHOICE_INITIALCONTEXTSETUPRESPONSE; + if(liblte_s1ap_unpack_initialcontextsetupresponse(ptr, &msg->choice.InitialContextSetupResponse) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(msg->procedureCode == LIBLTE_S1AP_PROC_ID_E_RABSETUP) { + msg->choice_type = LIBLTE_S1AP_SUCCESSFULOUTCOME_CHOICE_E_RABSETUPRESPONSE; + if(liblte_s1ap_unpack_e_rabsetupresponse(ptr, &msg->choice.E_RABSetupResponse) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(msg->procedureCode == LIBLTE_S1AP_PROC_ID_PATHSWITCHREQUEST) { + msg->choice_type = LIBLTE_S1AP_SUCCESSFULOUTCOME_CHOICE_PATHSWITCHREQUESTACKNOWLEDGE; + if(liblte_s1ap_unpack_pathswitchrequestacknowledge(ptr, &msg->choice.PathSwitchRequestAcknowledge) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(msg->procedureCode == LIBLTE_S1AP_PROC_ID_MMECONFIGURATIONUPDATE) { + msg->choice_type = LIBLTE_S1AP_SUCCESSFULOUTCOME_CHOICE_MMECONFIGURATIONUPDATEACKNOWLEDGE; + if(liblte_s1ap_unpack_mmeconfigurationupdateacknowledge(ptr, &msg->choice.MMEConfigurationUpdateAcknowledge) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(msg->procedureCode == LIBLTE_S1AP_PROC_ID_RESET) { + msg->choice_type = LIBLTE_S1AP_SUCCESSFULOUTCOME_CHOICE_RESETACKNOWLEDGE; + if(liblte_s1ap_unpack_resetacknowledge(ptr, &msg->choice.ResetAcknowledge) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(msg->procedureCode == LIBLTE_S1AP_PROC_ID_ENBCONFIGURATIONUPDATE) { + msg->choice_type = LIBLTE_S1AP_SUCCESSFULOUTCOME_CHOICE_ENBCONFIGURATIONUPDATEACKNOWLEDGE; + if(liblte_s1ap_unpack_enbconfigurationupdateacknowledge(ptr, &msg->choice.ENBConfigurationUpdateAcknowledge) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(msg->procedureCode == LIBLTE_S1AP_PROC_ID_E_RABMODIFY) { + msg->choice_type = LIBLTE_S1AP_SUCCESSFULOUTCOME_CHOICE_E_RABMODIFYRESPONSE; + if(liblte_s1ap_unpack_e_rabmodifyresponse(ptr, &msg->choice.E_RABModifyResponse) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(msg->procedureCode == LIBLTE_S1AP_PROC_ID_WRITEREPLACEWARNING) { + msg->choice_type = LIBLTE_S1AP_SUCCESSFULOUTCOME_CHOICE_WRITEREPLACEWARNINGRESPONSE; + if(liblte_s1ap_unpack_writereplacewarningresponse(ptr, &msg->choice.WriteReplaceWarningResponse) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(msg->procedureCode == LIBLTE_S1AP_PROC_ID_S1SETUP) { + msg->choice_type = LIBLTE_S1AP_SUCCESSFULOUTCOME_CHOICE_S1SETUPRESPONSE; + if(liblte_s1ap_unpack_s1setupresponse(ptr, &msg->choice.S1SetupResponse) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(msg->procedureCode == LIBLTE_S1AP_PROC_ID_KILL) { + msg->choice_type = LIBLTE_S1AP_SUCCESSFULOUTCOME_CHOICE_KILLRESPONSE; + if(liblte_s1ap_unpack_killresponse(ptr, &msg->choice.KillResponse) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(msg->procedureCode == LIBLTE_S1AP_PROC_ID_UECONTEXTMODIFICATION) { + msg->choice_type = LIBLTE_S1AP_SUCCESSFULOUTCOME_CHOICE_UECONTEXTMODIFICATIONRESPONSE; + if(liblte_s1ap_unpack_uecontextmodificationresponse(ptr, &msg->choice.UEContextModificationResponse) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(msg->procedureCode == LIBLTE_S1AP_PROC_ID_HANDOVERPREPARATION) { + msg->choice_type = LIBLTE_S1AP_SUCCESSFULOUTCOME_CHOICE_HANDOVERCOMMAND; + if(liblte_s1ap_unpack_handovercommand(ptr, &msg->choice.HandoverCommand) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(msg->procedureCode == LIBLTE_S1AP_PROC_ID_HANDOVERCANCEL) { + msg->choice_type = LIBLTE_S1AP_SUCCESSFULOUTCOME_CHOICE_HANDOVERCANCELACKNOWLEDGE; + if(liblte_s1ap_unpack_handovercancelacknowledge(ptr, &msg->choice.HandoverCancelAcknowledge) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } else if(msg->procedureCode == LIBLTE_S1AP_PROC_ID_E_RABRELEASE) { + msg->choice_type = LIBLTE_S1AP_SUCCESSFULOUTCOME_CHOICE_E_RABRELEASERESPONSE; + if(liblte_s1ap_unpack_e_rabreleaseresponse(ptr, &msg->choice.E_RABReleaseResponse) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + err = LIBLTE_SUCCESS; + } + return err; +} + + +/******************************************************************************* +/* S1AP_PDU CHOICE +********************************************************************************/ +LIBLTE_ERROR_ENUM liblte_s1ap_pack_s1ap_pdu( + LIBLTE_S1AP_S1AP_PDU_STRUCT *s1ap_pdu, + LIBLTE_BYTE_MSG_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + LIBLTE_BIT_MSG_STRUCT bit_msg; + + if(s1ap_pdu != NULL && + msg != NULL) + { + uint8_t *p = bit_msg.msg; + uint8_t **ptr = &p; + + // Extension + liblte_value_2_bits(s1ap_pdu->ext?1:0, ptr, 1); + + // Message choice + liblte_value_2_bits(s1ap_pdu->choice_type, ptr, 2); + liblte_align_up_zero(ptr, 8); + + // Message + if(LIBLTE_S1AP_S1AP_PDU_CHOICE_INITIATINGMESSAGE == s1ap_pdu->choice_type) { + if(liblte_s1ap_pack_initiatingmessage(&s1ap_pdu->choice.initiatingMessage, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } else if(LIBLTE_S1AP_S1AP_PDU_CHOICE_SUCCESSFULOUTCOME == s1ap_pdu->choice_type) { + if(liblte_s1ap_pack_successfuloutcome(&s1ap_pdu->choice.successfulOutcome, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + }else if(LIBLTE_S1AP_S1AP_PDU_CHOICE_UNSUCCESSFULOUTCOME == s1ap_pdu->choice_type) { + if(liblte_s1ap_pack_unsuccessfuloutcome(&s1ap_pdu->choice.unsuccessfulOutcome, ptr) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_ENCODE_FAIL; + } + } + + liblte_align_up_zero(ptr, 8); + bit_msg.N_bits += (*ptr - bit_msg.msg); + + liblte_pack(&bit_msg, msg); + err = LIBLTE_SUCCESS; + + } + return err; +} + +LIBLTE_ERROR_ENUM liblte_s1ap_unpack_s1ap_pdu( + LIBLTE_BYTE_MSG_STRUCT *msg, + LIBLTE_S1AP_S1AP_PDU_STRUCT *s1ap_pdu) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + LIBLTE_BIT_MSG_STRUCT bit_msg; + + if(s1ap_pdu != NULL && + msg != NULL) + { + liblte_unpack(msg, &bit_msg); + + uint8_t *p = bit_msg.msg; + uint8_t **ptr = &p; + + // Extension + s1ap_pdu->ext = liblte_bits_2_value(ptr, 1); + + // Message choice + s1ap_pdu->choice_type = (LIBLTE_S1AP_S1AP_PDU_CHOICE_ENUM)liblte_bits_2_value(ptr, 2); + liblte_align_up(ptr, 8); + + // Message + if(LIBLTE_S1AP_S1AP_PDU_CHOICE_INITIATINGMESSAGE == s1ap_pdu->choice_type) { + if(liblte_s1ap_unpack_initiatingmessage(ptr, &s1ap_pdu->choice.initiatingMessage) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + }else if(LIBLTE_S1AP_S1AP_PDU_CHOICE_SUCCESSFULOUTCOME == s1ap_pdu->choice_type) { + if(liblte_s1ap_unpack_successfuloutcome(ptr, &s1ap_pdu->choice.successfulOutcome) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + }else if(LIBLTE_S1AP_S1AP_PDU_CHOICE_UNSUCCESSFULOUTCOME == s1ap_pdu->choice_type) { + if(liblte_s1ap_unpack_unsuccessfuloutcome(ptr, &s1ap_pdu->choice.unsuccessfulOutcome) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR_DECODE_FAIL; + } + } + + err = LIBLTE_SUCCESS; + } + return err; +} diff --git a/lib/src/common/CMakeLists.txt b/lib/src/common/CMakeLists.txt new file mode 100644 index 000000000..6f022b417 --- /dev/null +++ b/lib/src/common/CMakeLists.txt @@ -0,0 +1,27 @@ +# +# Copyright 2013-2017 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(GLOB CXX_SOURCES "*.cc") +file(GLOB C_SOURCES "*.c") +add_library(srslte_common SHARED ${C_SOURCES} ${CXX_SOURCES}) +target_include_directories(srslte_common PUBLIC ${SEC_INCLUDE_DIRS}) +target_link_libraries(srslte_common ${SEC_LIBRARIES}) +install(TARGETS srslte_common DESTINATION ${LIBRARY_DIR}) +SRSLTE_SET_PIC(srslte_common) diff --git a/lib/src/common/buffer_pool.cc b/lib/src/common/buffer_pool.cc new file mode 100644 index 000000000..e41668abf --- /dev/null +++ b/lib/src/common/buffer_pool.cc @@ -0,0 +1,65 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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 +#include "srslte/common/buffer_pool.h" +#include +#include + +namespace srslte{ + +byte_buffer_pool *byte_buffer_pool::instance = NULL; +pthread_mutex_t instance_mutex = PTHREAD_MUTEX_INITIALIZER; + +byte_buffer_pool* byte_buffer_pool::get_instance(void) +{ + pthread_mutex_lock(&instance_mutex); + if(NULL == instance) + instance = new byte_buffer_pool(); + pthread_mutex_unlock(&instance_mutex); + return instance; +} + +void byte_buffer_pool::cleanup(void) +{ + pthread_mutex_lock(&instance_mutex); + if(NULL != instance) + { + delete instance; + instance = NULL; + } + pthread_mutex_unlock(&instance_mutex); +} + + + + + + + + +} // namespace srsue diff --git a/lib/src/common/liblte_security.cc b/lib/src/common/liblte_security.cc new file mode 100644 index 000000000..95f9617cd --- /dev/null +++ b/lib/src/common/liblte_security.cc @@ -0,0 +1,1245 @@ +/******************************************************************************* + + Copyright 2014 Ben Wojtowicz + + This program 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. + + This program 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. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + +******************************************************************************* + + File: liblte_security.cc + + Description: Contains all the implementations for the LTE security + algorithm library. + + Revision History + ---------- ------------- -------------------------------------------- + 08/03/2014 Ben Wojtowicz Created file. + 09/03/2014 Ben Wojtowicz Added key generation and EIA2 and fixed MCC + and MNC packing. + +*******************************************************************************/ + +/******************************************************************************* + INCLUDES +*******************************************************************************/ + +#include "srslte/common/liblte_security.h" +#include "srslte/common/liblte_ssl.h" +#include "math.h" + +/******************************************************************************* + DEFINES +*******************************************************************************/ + + +/******************************************************************************* + TYPEDEFS +*******************************************************************************/ + +typedef struct{ + uint8 rk[11][4][4]; +}ROUND_KEY_STRUCT; + +typedef struct{ + uint8 state[4][4]; +}STATE_STRUCT; + +/******************************************************************************* + GLOBAL VARIABLES +*******************************************************************************/ + +static const uint8 S[256] = { 99,124,119,123,242,107,111,197, 48, 1,103, 43,254,215,171,118, + 202,130,201,125,250, 89, 71,240,173,212,162,175,156,164,114,192, + 183,253,147, 38, 54, 63,247,204, 52,165,229,241,113,216, 49, 21, + 4,199, 35,195, 24,150, 5,154, 7, 18,128,226,235, 39,178,117, + 9,131, 44, 26, 27,110, 90,160, 82, 59,214,179, 41,227, 47,132, + 83,209, 0,237, 32,252,177, 91,106,203,190, 57, 74, 76, 88,207, + 208,239,170,251, 67, 77, 51,133, 69,249, 2,127, 80, 60,159,168, + 81,163, 64,143,146,157, 56,245,188,182,218, 33, 16,255,243,210, + 205, 12, 19,236, 95,151, 68, 23,196,167,126, 61,100, 93, 25,115, + 96,129, 79,220, 34, 42,144,136, 70,238,184, 20,222, 94, 11,219, + 224, 50, 58, 10, 73, 6, 36, 92,194,211,172, 98,145,149,228,121, + 231,200, 55,109,141,213, 78,169,108, 86,244,234,101,122,174, 8, + 186,120, 37, 46, 28,166,180,198,232,221,116, 31, 75,189,139,138, + 112, 62,181,102, 72, 3,246, 14, 97, 53, 87,185,134,193, 29,158, + 225,248,152, 17,105,217,142,148,155, 30,135,233,206, 85, 40,223, + 140,161,137, 13,191,230, 66,104, 65,153, 45, 15,176, 84,187, 22}; + +static const uint8 X_TIME[256] = { 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, + 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, + 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94, + 96, 98,100,102,104,106,108,110,112,114,116,118,120,122,124,126, + 128,130,132,134,136,138,140,142,144,146,148,150,152,154,156,158, + 160,162,164,166,168,170,172,174,176,178,180,182,184,186,188,190, + 192,194,196,198,200,202,204,206,208,210,212,214,216,218,220,222, + 224,226,228,230,232,234,236,238,240,242,244,246,248,250,252,254, + 27, 25, 31, 29, 19, 17, 23, 21, 11, 9, 15, 13, 3, 1, 7, 5, + 59, 57, 63, 61, 51, 49, 55, 53, 43, 41, 47, 45, 35, 33, 39, 37, + 91, 89, 95, 93, 83, 81, 87, 85, 75, 73, 79, 77, 67, 65, 71, 69, + 123,121,127,125,115,113,119,117,107,105,111,109, 99, 97,103,101, + 155,153,159,157,147,145,151,149,139,137,143,141,131,129,135,133, + 187,185,191,189,179,177,183,181,171,169,175,173,163,161,167,165, + 219,217,223,221,211,209,215,213,203,201,207,205,195,193,199,197, + 251,249,255,253,243,241,247,245,235,233,239,237,227,225,231,229}; + +/******************************************************************************* + LOCAL FUNCTION PROTOTYPES +*******************************************************************************/ + +/********************************************************************* + Name: compute_OPc + + Description: Computes OPc from OP and K. + + Document Reference: 35.206 v10.0.0 Annex 3 +*********************************************************************/ +// Defines +// Enums +// Structs +// Functions +void compute_OPc(ROUND_KEY_STRUCT *rk, + uint8 *op, + uint8 *op_c); + +/********************************************************************* + Name: rijndael_key_schedule + + Description: Computes all Rijndael's internal subkeys from key. + + Document Reference: 35.206 v10.0.0 Annex 3 +*********************************************************************/ +// Defines +// Enums +// Structs +// Functions +void rijndael_key_schedule(uint8 *key, + ROUND_KEY_STRUCT *rk); + +/********************************************************************* + Name: rijndael_encrypt + + Description: Computes output using input and round keys. + + Document Reference: 35.206 v10.0.0 Annex 3 +*********************************************************************/ +// Defines +// Enums +// Structs +// Functions +void rijndael_encrypt(uint8 *input, + ROUND_KEY_STRUCT *rk, + uint8 *output); + +/********************************************************************* + Name: key_add + + Description: Round key addition function. + + Document Reference: 35.206 v10.0.0 Annex 3 +*********************************************************************/ +// Defines +// Enums +// Structs +// Functions +void key_add(STATE_STRUCT *state, + ROUND_KEY_STRUCT *rk, + uint32 round); + +/********************************************************************* + Name: byte_sub + + Description: Byte substitution transformation. + + Document Reference: 35.206 v10.0.0 Annex 3 +*********************************************************************/ +// Defines +// Enums +// Structs +// Functions +void byte_sub(STATE_STRUCT *state); + +/********************************************************************* + Name: shift_row + + Description: Row shift transformation. + + Document Reference: 35.206 v10.0.0 Annex 3 +*********************************************************************/ +// Defines +// Enums +// Structs +// Functions +void shift_row(STATE_STRUCT *state); + +/********************************************************************* + Name: mix_column + + Description: Mix column transformation. + + Document Reference: 35.206 v10.0.0 Annex 3 +*********************************************************************/ +// Defines +// Enums +// Structs +// Functions +void mix_column(STATE_STRUCT *state); + +/******************************************************************************* + FUNCTIONS +*******************************************************************************/ + +/********************************************************************* + Name: liblte_security_generate_k_asme + + Description: Generate the security key Kasme. + + Document Reference: 33.401 v10.0.0 Annex A.2 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_security_generate_k_asme(uint8 *ck, + uint8 *ik, + uint8 *ak, + uint8 *sqn, + uint16 mcc, + uint16 mnc, + uint8 *k_asme) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint32 i; + uint8 s[14]; + uint8 key[32]; + + if(ck != NULL && + ik != NULL && + ak != NULL && + sqn != NULL && + k_asme != NULL) + { + // Construct S + s[0] = 0x10; // FC + s[1] = (mcc & 0x00F0) | ((mcc & 0x0F00) >> 8); // First byte of P0 + if((mnc & 0xFF00) == 0xFF00) + { + // 2-digit MNC + s[2] = 0xF0 | (mcc & 0x000F); // Second byte of P0 + s[3] = ((mnc & 0x000F) << 4) | ((mnc & 0x00F0) >> 4); // Third byte of P0 + }else{ + // 3-digit MNC + s[2] = ((mnc & 0x000F) << 4) | (mcc & 0x000F); // Second byte of P0 + s[3] = ((mnc & 0x00F0)) | ((mnc & 0x0F00) >> 8); // Third byte of P0 + } + s[4] = 0x00; // First byte of L0 + s[5] = 0x03; // Second byte of L0 + for(i=0; i<6; i++) + { + s[6+i] = sqn[i] ^ ak[i]; // P1 + } + s[12] = 0x00; // First byte of L1 + s[13] = 0x06; // Second byte of L1 + + // Construct Key + for(i=0; i<16; i++) + { + key[i] = ck[i]; + key[16+i] = ik[i]; + } + + // Derive Kasme + sha256(key, 32, s, 14, k_asme, 0); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + Name: liblte_security_generate_k_enb + + Description: Generate the security key Kenb. + + Document Reference: 33.401 v10.0.0 Annex A.2 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_security_generate_k_enb(uint8 *k_asme, + uint32 nas_count, + uint8 *k_enb) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 s[7]; + + if(k_asme != NULL && + k_enb != NULL) + { + // Construct S + s[0] = 0x11; // FC + s[1] = (nas_count >> 24) & 0xFF; // First byte of P0 + s[2] = (nas_count >> 16) & 0xFF; // Second byte of P0 + s[3] = (nas_count >> 8) & 0xFF; // Third byte of P0 + s[4] = nas_count & 0xFF; // Fourth byte of P0 + s[5] = 0x00; // First byte of L0 + s[6] = 0x04; // Second byte of L0 + + // Derive Kenb + sha256(k_asme, 32, s, 7, k_enb, 0); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + Name: liblte_security_generate_k_nas + + Description: Generate the NAS security keys KNASenc and KNASint. + + Document Reference: 33.401 v10.0.0 Annex A.2 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_security_generate_k_nas(uint8 *k_asme, + LIBLTE_SECURITY_CIPHERING_ALGORITHM_ID_ENUM enc_alg_id, + LIBLTE_SECURITY_INTEGRITY_ALGORITHM_ID_ENUM int_alg_id, + uint8 *k_nas_enc, + uint8 *k_nas_int) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 s[7]; + + if(k_asme != NULL && + k_nas_enc != NULL && + k_nas_int != NULL) + { + // Construct S for KNASenc + s[0] = 0x15; // FC + s[1] = 0x01; // P0 + s[2] = 0x00; // First byte of L0 + s[3] = 0x01; // Second byte of L0 + s[4] = enc_alg_id; // P1 + s[5] = 0x00; // First byte of L1 + s[6] = 0x01; // Second byte of L1 + + // Derive KNASenc + sha256(k_asme, 32, s, 7, k_nas_enc, 0); + + // Construct S for KNASint + s[0] = 0x15; // FC + s[1] = 0x02; // P0 + s[2] = 0x00; // First byte of L0 + s[3] = 0x01; // Second byte of L0 + s[4] = int_alg_id; // P1 + s[5] = 0x00; // First byte of L1 + s[6] = 0x01; // Second byte of L1 + + // Derive KNASint + sha256(k_asme, 32, s, 7, k_nas_int, 0); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + Name: liblte_security_generate_k_rrc + + Description: Generate the RRC security keys KRRCenc and KRRCint. + + Document Reference: 33.401 v10.0.0 Annex A.2 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_security_generate_k_rrc(uint8 *k_enb, + LIBLTE_SECURITY_CIPHERING_ALGORITHM_ID_ENUM enc_alg_id, + LIBLTE_SECURITY_INTEGRITY_ALGORITHM_ID_ENUM int_alg_id, + uint8 *k_rrc_enc, + uint8 *k_rrc_int) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 s[7]; + + if(k_enb != NULL && + k_rrc_enc != NULL && + k_rrc_int != NULL) + { + // Construct S for KRRCenc + s[0] = 0x15; // FC + s[1] = 0x03; // P0 + s[2] = 0x00; // First byte of L0 + s[3] = 0x01; // Second byte of L0 + s[4] = enc_alg_id; // P1 + s[5] = 0x00; // First byte of L1 + s[6] = 0x01; // Second byte of L1 + + // Derive KRRCenc + sha256(k_enb, 32, s, 7, k_rrc_enc, 0); + + // Construct S for KRRCint + s[0] = 0x15; // FC + s[1] = 0x04; // P0 + s[2] = 0x00; // First byte of L0 + s[3] = 0x01; // Second byte of L0 + s[4] = int_alg_id; // P1 + s[5] = 0x00; // First byte of L1 + s[6] = 0x01; // Second byte of L1 + + // Derive KRRCint + sha256(k_enb, 32, s, 7, k_rrc_int, 0); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + Name: liblte_security_generate_k_up + + Description: Generate the user plane security keys KUPenc and + KUPint. + + Document Reference: 33.401 v10.0.0 Annex A.2 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_security_generate_k_up(uint8 *k_enb, + LIBLTE_SECURITY_CIPHERING_ALGORITHM_ID_ENUM enc_alg_id, + LIBLTE_SECURITY_INTEGRITY_ALGORITHM_ID_ENUM int_alg_id, + uint8 *k_up_enc, + uint8 *k_up_int) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 s[7]; + + if(k_enb != NULL && + k_up_enc != NULL && + k_up_int != NULL) + { + // Construct S for KUPenc + s[0] = 0x15; // FC + s[1] = 0x05; // P0 + s[2] = 0x00; // First byte of L0 + s[3] = 0x01; // Second byte of L0 + s[4] = enc_alg_id; // P1 + s[5] = 0x00; // First byte of L1 + s[6] = 0x01; // Second byte of L1 + + // Derive KUPenc + sha256(k_enb, 32, s, 7, k_up_enc, 0); + + // Construct S for KUPint + s[0] = 0x15; // FC + s[1] = 0x06; // P0 + s[2] = 0x00; // First byte of L0 + s[3] = 0x01; // Second byte of L0 + s[4] = int_alg_id; // P1 + s[5] = 0x00; // First byte of L1 + s[6] = 0x01; // Second byte of L1 + + // Derive KUPint + sha256(k_enb, 32, s, 7, k_up_int, 0); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + Name: liblte_security_128_eia2 + + Description: 128-bit integrity algorithm EIA2. + + Document Reference: 33.401 v10.0.0 Annex B.2.3 + 33.102 v10.0.0 Section 6.5.4 + RFC4493 +*********************************************************************/ +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 err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 M[msg_len+8+16]; + aes_context ctx; + uint32 i; + uint32 j; + uint32 n; + uint32 pad_bits; + uint8 const_zero[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + uint8 L[16]; + uint8 K1[16]; + uint8 K2[16]; + uint8 T[16]; + uint8 tmp[16]; + + if(key != NULL && + msg != NULL && + mac != NULL) + { + // Subkey L generation + aes_setkey_enc(&ctx, key, 128); + aes_crypt_ecb(&ctx, AES_ENCRYPT, const_zero, L); + + // Subkey K1 generation + for(i=0; i<15; i++) + { + K1[i] = (L[i] << 1) | ((L[i+1] >> 7) & 0x01); + } + K1[15] = L[15] << 1; + if(L[0] & 0x80) + { + K1[15] ^= 0x87; + } + + // Subkey K2 generation + for(i=0; i<15; i++) + { + K2[i] = (K1[i] << 1) | ((K1[i+1] >> 7) & 0x01); + } + K2[15] = K1[15] << 1; + if(K1[0] & 0x80) + { + K2[15] ^= 0x87; + } + + // Construct M + memset(M, 0, msg_len+8+16); + M[0] = (count >> 24) & 0xFF; + M[1] = (count >> 16) & 0xFF; + M[2] = (count >> 8) & 0xFF; + M[3] = count & 0xFF; + M[4] = (bearer << 3) | (direction << 2); + for(i=0; iN_bits*8+8+16]; + aes_context ctx; + uint32 i; + uint32 j; + uint32 n; + uint32 pad_bits; + uint8 const_zero[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + uint8 L[16]; + uint8 K1[16]; + uint8 K2[16]; + uint8 T[16]; + uint8 tmp[16]; + + if(key != NULL && + msg != NULL && + mac != NULL) + { + // Subkey L generation + aes_setkey_enc(&ctx, key, 128); + aes_crypt_ecb(&ctx, AES_ENCRYPT, const_zero, L); + + // Subkey K1 generation + for(i=0; i<15; i++) + { + K1[i] = (L[i] << 1) | ((L[i+1] >> 7) & 0x01); + } + K1[15] = L[15] << 1; + if(L[0] & 0x80) + { + K1[15] ^= 0x87; + } + + // Subkey K2 generation + for(i=0; i<15; i++) + { + K2[i] = (K1[i] << 1) | ((K1[i+1] >> 7) & 0x01); + } + K2[15] = K1[15] << 1; + if(K1[0] & 0x80) + { + K2[15] ^= 0x87; + } + + // Construct M + memset(M, 0, msg->N_bits*8+8+16); + M[0] = (count >> 24) & 0xFF; + M[1] = (count >> 16) & 0xFF; + M[2] = (count >> 8) & 0xFF; + M[3] = count & 0xFF; + M[4] = (bearer << 3) | (direction << 2); + for(i=0; iN_bits/8; i++) + { + M[8+i] = 0; + for(j=0; j<8; j++) + { + M[8+i] |= msg->msg[i*8+j] << (7-j); + } + } + if((msg->N_bits % 8) != 0) + { + M[8+i] = 0; + for(j=0; jN_bits % 8; j++) + { + M[8+i] |= msg->msg[i*8+j] << (7-j); + } + } + + // MAC generation + n = (uint32)(ceilf((float)(msg->N_bits+64)/(float)(128))); + for(i=0; i<16; i++) + { + T[i] = 0; + } + for(i=0; iN_bits + 64) % 128; + if(pad_bits == 0) + { + for(j=0; j<16; j++) + { + tmp[j] = T[j] ^ K1[j] ^ M[i*16 + j]; + } + aes_crypt_ecb(&ctx, AES_ENCRYPT, tmp, T); + }else{ + pad_bits = (128 - pad_bits) - 1; + M[i*16 + (15 - (pad_bits/8))] |= 0x1 << (pad_bits % 8); + for(j=0; j<16; j++) + { + tmp[j] = T[j] ^ K2[j] ^ M[i*16 + j]; + } + aes_crypt_ecb(&ctx, AES_ENCRYPT, tmp, T); + } + + for(i=0; i<4; i++) + { + mac[i] = T[i]; + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + Name: liblte_security_milenage_f1 + + Description: Milenage security function F1. Computes network + authentication code MAC-A from key K, random + challenge RAND, sequence number SQN, and + authentication management field AMF. + + Document Reference: 35.206 v10.0.0 Annex 3 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_security_milenage_f1(uint8 *k, + uint8 *op, + uint8 *rand, + uint8 *sqn, + uint8 *amf, + uint8 *mac_a) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + ROUND_KEY_STRUCT round_keys; + uint32 i; + uint8 op_c[16]; + uint8 temp[16]; + uint8 in1[16]; + uint8 out1[16]; + uint8 rijndael_input[16]; + + if(k != NULL && + rand != NULL && + sqn != NULL && + amf != NULL && + mac_a != NULL) + { + // Initialize the round keys + rijndael_key_schedule(k, &round_keys); + + // Compute OPc + compute_OPc(&round_keys, op, op_c); + + // Compute temp + for(i=0; i<16; i++) + { + rijndael_input[i] = rand[i] ^ op_c[i]; + } + rijndael_encrypt(rijndael_input, &round_keys, temp); + + // Construct in1 + for(i=0; i<6; i++) + { + in1[i] = sqn[i]; + in1[i+8] = sqn[i]; + } + for(i=0; i<2; i++) + { + in1[i+6] = amf[i]; + in1[i+14] = amf[i]; + } + + // Compute out1 + for(i=0; i<16; i++) + { + rijndael_input[(i+8) % 16] = in1[i] ^ op_c[i]; + } + for(i=0; i<16; i++) + { + rijndael_input[i] ^= temp[i]; + } + rijndael_encrypt(rijndael_input, &round_keys, out1); + for(i=0; i<16; i++) + { + out1[i] ^= op_c[i]; + } + + // Return MAC-A + for(i=0; i<8; i++) + { + mac_a[i] = out1[i]; + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + Name: liblte_security_milenage_f1_star + + Description: Milenage security function F1*. Computes resynch + authentication code MAC-S from key K, random + challenge RAND, sequence number SQN, and + authentication management field AMF. + + Document Reference: 35.206 v10.0.0 Annex 3 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_security_milenage_f1_star(uint8 *k, + uint8 *op, + uint8 *rand, + uint8 *sqn, + uint8 *amf, + uint8 *mac_s) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + ROUND_KEY_STRUCT round_keys; + uint32 i; + uint8 op_c[16]; + uint8 temp[16]; + uint8 in1[16]; + uint8 out1[16]; + uint8 rijndael_input[16]; + + if(k != NULL && + rand != NULL && + sqn != NULL && + amf != NULL && + mac_s != NULL) + { + // Initialize the round keys + rijndael_key_schedule(k, &round_keys); + + // Compute OPc + compute_OPc(&round_keys, op, op_c); + + // Compute temp + for(i=0; i<16; i++) + { + rijndael_input[i] = rand[i] ^ op_c[i]; + } + rijndael_encrypt(rijndael_input, &round_keys, temp); + + // Construct in1 + for(i=0; i<6; i++) + { + in1[i] = sqn[i]; + in1[i+8] = sqn[i]; + } + for(i=0; i<2; i++) + { + in1[i+6] = amf[i]; + in1[i+14] = amf[i]; + } + + // Compute out1 + for(i=0; i<16; i++) + { + rijndael_input[(i+8) % 16] = in1[i] ^ op_c[i]; + } + for(i=0; i<16; i++) + { + rijndael_input[i] ^= temp[i]; + } + rijndael_encrypt(rijndael_input, &round_keys, out1); + for(i=0; i<16; i++) + { + out1[i] ^= op_c[i]; + } + + // Return MAC-S + for(i=0; i<8; i++) + { + mac_s[i] = out1[i+8]; + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + Name: liblte_security_milenage_f2345 + + Description: Milenage security functions F2, F3, F4, and F5. + Computes response RES, confidentiality key CK, + integrity key IK, and anonymity key AK from random + challenge RAND. + + Document Reference: 35.206 v10.0.0 Annex 3 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_security_milenage_f2345(uint8 *k, + uint8 *op, + uint8 *rand, + uint8 *res, + uint8 *ck, + uint8 *ik, + uint8 *ak) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + ROUND_KEY_STRUCT round_keys; + uint32 i; + uint8 op_c[16]; + uint8 temp[16]; + uint8 out[16]; + uint8 rijndael_input[16]; + + if(k != NULL && + rand != NULL && + res != NULL && + ck != NULL && + ik != NULL && + ak != NULL) + { + // Initialize the round keys + rijndael_key_schedule(k, &round_keys); + + // Compute OPc + compute_OPc(&round_keys, op, op_c); + + // Compute temp + for(i=0; i<16; i++) + { + rijndael_input[i] = rand[i] ^ op_c[i]; + } + rijndael_encrypt(rijndael_input, &round_keys, temp); + + // Compute out for RES and AK + for(i=0; i<16; i++) + { + rijndael_input[i] = temp[i] ^ op_c[i]; + } + rijndael_input[15] ^= 1; + rijndael_encrypt(rijndael_input, &round_keys, out); + for(i=0; i<16; i++) + { + out[i] ^= op_c[i]; + } + + // Return RES + for(i=0; i<8; i++) + { + res[i] = out[i+8]; + } + + // Return AK + for(i=0; i<6; i++) + { + ak[i] = out[i]; + } + + // Compute out for CK + for(i=0; i<16; i++) + { + rijndael_input[(i+12) % 16] = temp[i] ^ op_c[i]; + } + rijndael_input[15] ^= 2; + rijndael_encrypt(rijndael_input, &round_keys, out); + for(i=0; i<16; i++) + { + out[i] ^= op_c[i]; + } + + // Return CK + for(i=0; i<16; i++) + { + ck[i] = out[i]; + } + + // Compute out for IK + for(i=0; i<16; i++) + { + rijndael_input[(i+8) % 16] = temp[i] ^ op_c[i]; + } + rijndael_input[15] ^= 4; + rijndael_encrypt(rijndael_input, &round_keys, out); + for(i=0; i<16; i++) + { + out[i] ^= op_c[i]; + } + + // Return IK + for(i=0; i<16; i++) + { + ik[i] = out[i]; + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + Name: liblte_security_milenage_f5_star + + Description: Milenage security function F5*. Computes resynch + anonymity key AK from key K and random challenge + RAND. + + Document Reference: 35.206 v10.0.0 Annex 3 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_security_milenage_f5_star(uint8 *k, + uint8 *op, + uint8 *rand, + uint8 *ak) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + ROUND_KEY_STRUCT round_keys; + uint32 i; + uint8 op_c[16]; + uint8 temp[16]; + uint8 out[16]; + uint8 rijndael_input[16]; + + if(k != NULL && + rand != NULL && + ak != NULL) + { + // Initialize the round keys + rijndael_key_schedule(k, &round_keys); + + // Compute OPc + compute_OPc(&round_keys, op, op_c); + + // Compute temp + for(i=0; i<16; i++) + { + rijndael_input[i] = rand[i] ^ op_c[i]; + } + rijndael_encrypt(rijndael_input, &round_keys, temp); + + // Compute out + for(i=0; i<16; i++) + { + rijndael_input[(i+4) % 16] = temp[i] ^ op_c[i]; + } + rijndael_input[15] ^= 8; + rijndael_encrypt(rijndael_input, &round_keys, out); + for(i=0; i<16; i++) + { + out[i] ^= op_c[i]; + } + + // Return AK + for(i=0; i<6; i++) + { + ak[i] = out[i]; + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/******************************************************************************* + LOCAL FUNCTIONS +*******************************************************************************/ + +/********************************************************************* + Name: compute_OPc + + Description: Computes OPc from OP and K. + + Document Reference: 35.206 v10.0.0 Annex 3 +*********************************************************************/ +void compute_OPc(ROUND_KEY_STRUCT *rk, + uint8 *op, + uint8 *op_c) +{ + uint32 i; + + rijndael_encrypt(op, rk, op_c); + for(i=0; i<16; i++) + { + op_c[i] ^= op[i]; + } +} + +/********************************************************************* + Name: rijndael_key_schedule + + Description: Computes all Rijndael's internal subkeys from key. + + Document Reference: 35.206 v10.0.0 Annex 3 +*********************************************************************/ +void rijndael_key_schedule(uint8 *key, + ROUND_KEY_STRUCT *rk) +{ + uint32 i; + uint32 j; + uint8 round_const; + + // Set first round key to key + for(i=0; i<16; i++) + { + rk->rk[0][i & 0x03][i >> 2] = key[i]; + } + + round_const = 1; + + // Compute the remaining round keys + for(i=1; i<11; i++) + { + rk->rk[i][0][0] = S[rk->rk[i-1][1][3]] ^ rk->rk[i-1][0][0] ^ round_const; + rk->rk[i][1][0] = S[rk->rk[i-1][2][3]] ^ rk->rk[i-1][1][0]; + rk->rk[i][2][0] = S[rk->rk[i-1][3][3]] ^ rk->rk[i-1][2][0]; + rk->rk[i][3][0] = S[rk->rk[i-1][0][3]] ^ rk->rk[i-1][3][0]; + + for(j=0; j<4; j++) + { + rk->rk[i][j][1] = rk->rk[i-1][j][1] ^ rk->rk[i][j][0]; + rk->rk[i][j][2] = rk->rk[i-1][j][2] ^ rk->rk[i][j][1]; + rk->rk[i][j][3] = rk->rk[i-1][j][3] ^ rk->rk[i][j][2]; + } + + round_const = X_TIME[round_const]; + } +} + +/********************************************************************* + Name: rijndael_encrypt + + Description: Computes output using input and round keys. + + Document Reference: 35.206 v10.0.0 Annex 3 +*********************************************************************/ +void rijndael_encrypt(uint8 *input, + ROUND_KEY_STRUCT *rk, + uint8 *output) +{ + STATE_STRUCT state; + uint32 i; + uint32 r; + + // Initialize and perform round 0 + for(i=0; i<16; i++) + { + state.state[i & 0x03][i >> 2] = input[i]; + } + key_add(&state, rk, 0); + + // Perform rounds 1 through 9 + for(r=1; r<=9; r++) + { + byte_sub(&state); + shift_row(&state); + mix_column(&state); + key_add(&state, rk, r); + } + + // Perform round 10 + byte_sub(&state); + shift_row(&state); + key_add(&state, rk, r); + + // Return output + for(i=0; i<16; i++) + { + output[i] = state.state[i & 0x03][i >> 2]; + } +} + +/********************************************************************* + Name: key_add + + Description: Round key addition function. + + Document Reference: 35.206 v10.0.0 Annex 3 +*********************************************************************/ +void key_add(STATE_STRUCT *state, + ROUND_KEY_STRUCT *rk, + uint32 round) +{ + uint32 i; + uint32 j; + + for(i=0; i<4; i++) + { + for(j=0; j<4; j++) + { + state->state[i][j] ^= rk->rk[round][i][j]; + } + } +} + +/********************************************************************* + Name: byte_sub + + Description: Byte substitution transformation. + + Document Reference: 35.206 v10.0.0 Annex 3 +*********************************************************************/ +void byte_sub(STATE_STRUCT *state) +{ + uint32 i; + uint32 j; + + for(i=0; i<4; i++) + { + for(j=0; j<4; j++) + { + state->state[i][j] = S[state->state[i][j]]; + } + } +} + +/********************************************************************* + Name: shift_row + + Description: Row shift transformation. + + Document Reference: 35.206 v10.0.0 Annex 3 +*********************************************************************/ +void shift_row(STATE_STRUCT *state) +{ + uint8 temp; + + // Left rotate row 1 by 1 + temp = state->state[1][0]; + state->state[1][0] = state->state[1][1]; + state->state[1][1] = state->state[1][2]; + state->state[1][2] = state->state[1][3]; + state->state[1][3] = temp; + + // Left rotate row 2 by 2 + temp = state->state[2][0]; + state->state[2][0] = state->state[2][2]; + state->state[2][2] = temp; + temp = state->state[2][1]; + state->state[2][1] = state->state[2][3]; + state->state[2][3] = temp; + + // Left rotate row 3 by 3 + temp = state->state[3][0]; + state->state[3][0] = state->state[3][3]; + state->state[3][3] = state->state[3][2]; + state->state[3][2] = state->state[3][1]; + state->state[3][1] = temp; +} + +/********************************************************************* + Name: mix_column + + Description: Mix column transformation. + + Document Reference: 35.206 v10.0.0 Annex 3 +*********************************************************************/ +void mix_column(STATE_STRUCT *state) +{ + uint32 i; + uint8 temp; + uint8 tmp0; + uint8 tmp; + + for(i=0; i<4; i++) + { + temp = state->state[0][i] ^ state->state[1][i] ^ state->state[2][i] ^ state->state[3][i]; + tmp0 = state->state[0][i]; + + tmp = X_TIME[state->state[0][i] ^ state->state[1][i]]; + state->state[0][i] ^= temp ^ tmp; + + tmp = X_TIME[state->state[1][i] ^ state->state[2][i]]; + state->state[1][i] ^= temp ^ tmp; + + tmp = X_TIME[state->state[2][i] ^ state->state[3][i]]; + state->state[2][i] ^= temp ^ tmp; + + tmp = X_TIME[state->state[3][i] ^ tmp0]; + state->state[3][i] ^= temp ^ tmp; + } +} diff --git a/lib/src/common/log_filter.cc b/lib/src/common/log_filter.cc new file mode 100644 index 000000000..12f004d5e --- /dev/null +++ b/lib/src/common/log_filter.cc @@ -0,0 +1,316 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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 +#include +#include +#include +#include +#include + +#include "srslte/common/log_filter.h" + +namespace srslte{ + +log_filter::log_filter() +{ + do_tti = false; +} + +log_filter::log_filter(std::string layer, logger *logger_, bool tti) +{ + init(layer, logger_, tti); +} + +void log_filter::init(std::string layer, logger *logger_, bool tti) +{ + service_name = layer; + logger_h = logger_; + do_tti = tti; +} + +void log_filter::all_log(srslte::LOG_LEVEL_ENUM level, + uint32_t tti, + char *msg) +{ + if(logger_h) { + std::stringstream ss; + + ss << now_time() << " "; + ss << "[" <log(s_ptr); + } +} + +void log_filter::all_log(srslte::LOG_LEVEL_ENUM level, + uint32_t tti, + char *msg, + uint8_t *hex, + int size) +{ + if(logger_h) { + std::stringstream ss; + + ss << now_time() << " "; + ss << "[" < 0) { + ss << hex_string(hex, size); + } + str_ptr s_ptr(new std::string(ss.str())); + logger_h->log(s_ptr); + } +} + +void log_filter::all_log_line(srslte::LOG_LEVEL_ENUM level, + uint32_t tti, + std::string file, + int line, + char *msg) +{ + if(logger_h) { + std::stringstream ss; + + ss << now_time() << " "; + ss << "[" <log(s_ptr); + } +} + +void log_filter::console(std::string message, ...) { + char *args_msg; + va_list args; + va_start(args, message); + if(vasprintf(&args_msg, message.c_str(), args) > 0) + printf("%s",args_msg); // Print directly to stdout + va_end(args); + free(args_msg); +} + +void log_filter::error(std::string message, ...) { + if (level >= LOG_LEVEL_ERROR) { + char *args_msg; + va_list args; + va_start(args, message); + if(vasprintf(&args_msg, message.c_str(), args) > 0) + all_log(LOG_LEVEL_ERROR, tti, args_msg); + va_end(args); + free(args_msg); + } +} +void log_filter::warning(std::string message, ...) { + if (level >= LOG_LEVEL_WARNING) { + char *args_msg; + va_list args; + va_start(args, message); + if(vasprintf(&args_msg, message.c_str(), args) > 0) + all_log(LOG_LEVEL_WARNING, tti, args_msg); + va_end(args); + free(args_msg); + } +} +void log_filter::info(std::string message, ...) { + if (level >= LOG_LEVEL_INFO) { + char *args_msg; + va_list args; + va_start(args, message); + if(vasprintf(&args_msg, message.c_str(), args) > 0) + all_log(LOG_LEVEL_INFO, tti, args_msg); + va_end(args); + free(args_msg); + } +} +void log_filter::debug(std::string message, ...) { + if (level >= LOG_LEVEL_DEBUG) { + char *args_msg; + va_list args; + va_start(args, message); + if(vasprintf(&args_msg, message.c_str(), args) > 0) + all_log(LOG_LEVEL_DEBUG, tti, args_msg); + va_end(args); + free(args_msg); + } +} + +void log_filter::error_hex(uint8_t *hex, int size, std::string message, ...) { + if (level >= LOG_LEVEL_ERROR) { + char *args_msg; + va_list args; + va_start(args, message); + if(vasprintf(&args_msg, message.c_str(), args) > 0) + all_log(LOG_LEVEL_ERROR, tti, args_msg, hex, size); + va_end(args); + free(args_msg); + } +} +void log_filter::warning_hex(uint8_t *hex, int size, std::string message, ...) { + if (level >= LOG_LEVEL_WARNING) { + char *args_msg; + va_list args; + va_start(args, message); + if(vasprintf(&args_msg, message.c_str(), args) > 0) + all_log(LOG_LEVEL_WARNING, tti, args_msg, hex, size); + va_end(args); + free(args_msg); + } +} +void log_filter::info_hex(uint8_t *hex, int size, std::string message, ...) { + if (level >= LOG_LEVEL_INFO) { + char *args_msg; + va_list args; + va_start(args, message); + if(vasprintf(&args_msg, message.c_str(), args) > 0) + all_log(LOG_LEVEL_INFO, tti, args_msg, hex, size); + va_end(args); + free(args_msg); + } +} +void log_filter::debug_hex(uint8_t *hex, int size, std::string message, ...) { + if (level >= LOG_LEVEL_DEBUG) { + char *args_msg; + va_list args; + va_start(args, message); + if(vasprintf(&args_msg, message.c_str(), args) > 0) + all_log(LOG_LEVEL_DEBUG, tti, args_msg, hex, size); + va_end(args); + free(args_msg); + } +} + +void log_filter::error_line(std::string file, int line, std::string message, ...) +{ + if (level >= LOG_LEVEL_ERROR) { + char *args_msg; + va_list args; + va_start(args, message); + if(vasprintf(&args_msg, message.c_str(), args) > 0) + all_log_line(LOG_LEVEL_ERROR, tti, file, line, args_msg); + va_end(args); + free(args_msg); + } +} + +void log_filter::warning_line(std::string file, int line, std::string message, ...) +{ + if (level >= LOG_LEVEL_WARNING) { + char *args_msg; + va_list args; + va_start(args, message); + if(vasprintf(&args_msg, message.c_str(), args) > 0) + all_log_line(LOG_LEVEL_WARNING, tti, file, line, args_msg); + va_end(args); + free(args_msg); + } +} + +void log_filter::info_line(std::string file, int line, std::string message, ...) +{ + if (level >= LOG_LEVEL_INFO) { + char *args_msg; + va_list args; + va_start(args, message); + if(vasprintf(&args_msg, message.c_str(), args) > 0) + all_log_line(LOG_LEVEL_INFO, tti, file, line, args_msg); + va_end(args); + free(args_msg); + } +} + +void log_filter::debug_line(std::string file, int line, std::string message, ...) +{ + if (level >= LOG_LEVEL_DEBUG) { + char *args_msg; + va_list args; + va_start(args, message); + if(vasprintf(&args_msg, message.c_str(), args) > 0) + all_log_line(LOG_LEVEL_DEBUG, tti, file, line, args_msg); + va_end(args); + free(args_msg); + } +} + + + +std::string log_filter::now_time() +{ + struct timeval rawtime; + struct tm * timeinfo; + char buffer[64]; + char us[16]; + + gettimeofday(&rawtime, NULL); + timeinfo = localtime(&rawtime.tv_sec); + + strftime(buffer,64,"%H:%M:%S",timeinfo); + strcat(buffer,"."); + snprintf(us,16,"%06ld",rawtime.tv_usec); + strcat(buffer,us); + + return std::string(buffer); +} + +std::string log_filter::hex_string(uint8_t *hex, int size) +{ + std::stringstream ss; + int c = 0; + + ss << std::hex << std::setfill('0'); + if(hex_limit >= 0) { + size = (size > hex_limit) ? hex_limit : size; + } + while(c < size) { + ss << " " << std::setw(4) << static_cast(c) << ": "; + int tmp = (size-c < 16) ? size-c : 16; + for(int i=0;i(hex[c++]) << " "; + } + ss << "\n"; + } + return ss.str(); +} + +} // namespace srsue diff --git a/lib/src/common/log_stdout.cc b/lib/src/common/log_stdout.cc new file mode 100644 index 000000000..2e50b755e --- /dev/null +++ b/lib/src/common/log_stdout.cc @@ -0,0 +1,290 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "srslte/common/log_stdout.h" + + +using namespace std; + +namespace srslte { + +void log_stdout::all_log(srslte::LOG_LEVEL_ENUM level, + uint32_t tti, + char *msg) +{ + std::stringstream ss; + + ss << now_time() << " "; + ss << "[" < 0) + printf("%s",args_msg); // Print directly to stdout + va_end(args); + free(args_msg); +} + +void log_stdout::error(std::string message, ...) { + if (level >= LOG_LEVEL_ERROR) { + char *args_msg; + va_list args; + va_start(args, message); + if(vasprintf(&args_msg, message.c_str(), args) > 0) + all_log(LOG_LEVEL_ERROR, tti, args_msg); + va_end(args); + free(args_msg); + } +} +void log_stdout::warning(std::string message, ...) { + if (level >= LOG_LEVEL_WARNING) { + char *args_msg; + va_list args; + va_start(args, message); + if(vasprintf(&args_msg, message.c_str(), args) > 0) + all_log(LOG_LEVEL_WARNING, tti, args_msg); + va_end(args); + free(args_msg); + } +} +void log_stdout::info(std::string message, ...) { + if (level >= LOG_LEVEL_INFO) { + char *args_msg; + va_list args; + va_start(args, message); + if(vasprintf(&args_msg, message.c_str(), args) > 0) + all_log(LOG_LEVEL_INFO, tti, args_msg); + va_end(args); + free(args_msg); + } +} +void log_stdout::debug(std::string message, ...) { + if (level >= LOG_LEVEL_DEBUG) { + char *args_msg; + va_list args; + va_start(args, message); + if(vasprintf(&args_msg, message.c_str(), args) > 0) + all_log(LOG_LEVEL_DEBUG, tti, args_msg); + va_end(args); + free(args_msg); + } +} + +void log_stdout::error_hex(uint8_t *hex, int size, std::string message, ...) { + if (level >= LOG_LEVEL_ERROR) { + char *args_msg; + va_list args; + va_start(args, message); + if(vasprintf(&args_msg, message.c_str(), args) > 0) + all_log(LOG_LEVEL_ERROR, tti, args_msg, hex, size); + va_end(args); + free(args_msg); + } +} +void log_stdout::warning_hex(uint8_t *hex, int size, std::string message, ...) { + if (level >= LOG_LEVEL_WARNING) { + char *args_msg; + va_list args; + va_start(args, message); + if(vasprintf(&args_msg, message.c_str(), args) > 0) + all_log(LOG_LEVEL_WARNING, tti, args_msg, hex, size); + va_end(args); + free(args_msg); + } +} +void log_stdout::info_hex(uint8_t *hex, int size, std::string message, ...) { + if (level >= LOG_LEVEL_INFO) { + char *args_msg; + va_list args; + va_start(args, message); + if(vasprintf(&args_msg, message.c_str(), args) > 0) + all_log(LOG_LEVEL_INFO, tti, args_msg, hex, size); + va_end(args); + free(args_msg); + } +} +void log_stdout::debug_hex(uint8_t *hex, int size, std::string message, ...) { + if (level >= LOG_LEVEL_DEBUG) { + char *args_msg; + va_list args; + va_start(args, message); + if(vasprintf(&args_msg, message.c_str(), args) > 0) + all_log(LOG_LEVEL_DEBUG, tti, args_msg, hex, size); + va_end(args); + free(args_msg); + } +} + +void log_stdout::error_line(std::string file, int line, std::string message, ...) +{ + if (level >= LOG_LEVEL_ERROR) { + char *args_msg; + va_list args; + va_start(args, message); + if(vasprintf(&args_msg, message.c_str(), args) > 0) + all_log_line(LOG_LEVEL_ERROR, tti, file, line, args_msg); + va_end(args); + free(args_msg); + } +} + +void log_stdout::warning_line(std::string file, int line, std::string message, ...) +{ + if (level >= LOG_LEVEL_WARNING) { + char *args_msg; + va_list args; + va_start(args, message); + if(vasprintf(&args_msg, message.c_str(), args) > 0) + all_log_line(LOG_LEVEL_WARNING, tti, file, line, args_msg); + va_end(args); + free(args_msg); + } +} + +void log_stdout::info_line(std::string file, int line, std::string message, ...) +{ + if (level >= LOG_LEVEL_INFO) { + char *args_msg; + va_list args; + va_start(args, message); + if(vasprintf(&args_msg, message.c_str(), args) > 0) + all_log_line(LOG_LEVEL_INFO, tti, file, line, args_msg); + va_end(args); + free(args_msg); + } +} + +void log_stdout::debug_line(std::string file, int line, std::string message, ...) +{ + if (level >= LOG_LEVEL_DEBUG) { + char *args_msg; + va_list args; + va_start(args, message); + if(vasprintf(&args_msg, message.c_str(), args) > 0) + all_log_line(LOG_LEVEL_DEBUG, tti, file, line, args_msg); + va_end(args); + free(args_msg); + } +} + + + +std::string log_stdout::now_time() +{ + struct timeval rawtime; + struct tm * timeinfo; + char buffer[64]; + char us[16]; + + gettimeofday(&rawtime, NULL); + timeinfo = localtime(&rawtime.tv_sec); + + strftime(buffer,64,"%H:%M:%S",timeinfo); + strcat(buffer,"."); + snprintf(us,16,"%ld",rawtime.tv_usec); + strcat(buffer,us); + + return std::string(buffer); +} + +std::string log_stdout::hex_string(uint8_t *hex, int size) +{ + std::stringstream ss; + int c = 0; + + ss << std::hex << std::setfill('0'); + if(hex_limit >= 0) { + size = (size > hex_limit) ? hex_limit : size; + } + while(c < size) { + ss << " " << std::setw(4) << static_cast(c) << ": "; + int tmp = (size-c < 16) ? size-c : 16; + for(int i=0;i(hex[c++]) << " "; + } + ss << "\n"; + } + return ss.str(); +} + +} + + diff --git a/lib/src/common/logger.cc b/lib/src/common/logger.cc new file mode 100644 index 000000000..b48f6e1c7 --- /dev/null +++ b/lib/src/common/logger.cc @@ -0,0 +1,103 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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/. + * + */ + + +#define LOG_BUFFER_SIZE 1024*32 + +#include "srslte/common/logger.h" + +using namespace std; + +namespace srslte{ + +logger::logger() + :inited(false) + ,not_done(true) +{} + +logger::~logger() { + not_done = false; + log("Closing log"); + if(inited) { + wait_thread_finish(); + flush(); + fclose(logfile); + } +} + +void logger::init(std::string file) { + pthread_mutex_init(&mutex, NULL); + pthread_cond_init(¬_empty, NULL); + pthread_cond_init(¬_full, NULL); + filename = file; + logfile = fopen(filename.c_str(), "w"); + if(logfile==NULL) { + printf("Error: could not create log file, no messages will be logged"); + } + start(); + inited = true; +} + +void logger::log(const char *msg) { + str_ptr s_ptr(new std::string(msg)); + log(s_ptr); +} + +void logger::log(str_ptr msg) { + pthread_mutex_lock(&mutex); + buffer.push_back(msg); + pthread_cond_signal(¬_empty); + pthread_mutex_unlock(&mutex); +} + +void logger::run_thread() { + while(not_done) { + pthread_mutex_lock(&mutex); + while(buffer.empty()) { + pthread_cond_wait(¬_empty, &mutex); + } + str_ptr s = buffer.front(); + pthread_cond_signal(¬_full); + if(logfile) + fprintf(logfile, "%s", s->c_str()); + delete s; + buffer.pop_front(); + pthread_mutex_unlock(&mutex); + } +} + +void logger::flush() { + std::deque::iterator it; + for(it=buffer.begin();it!=buffer.end();it++) + { + str_ptr s = *it; + if(logfile) + fprintf(logfile, "%s", s->c_str()); + delete s; + } +} + +} // namespace srsue diff --git a/lib/src/common/mac_pcap.cc b/lib/src/common/mac_pcap.cc new file mode 100644 index 000000000..ff30670ed --- /dev/null +++ b/lib/src/common/mac_pcap.cc @@ -0,0 +1,99 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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 +#include "srslte/srslte.h" +#include "srslte/common/pcap.h" +#include "srslte/common/mac_pcap.h" + + + +namespace srslte { + +void mac_pcap::enable(bool en) +{ + enable_write = true; +} +void mac_pcap::open(const char* filename, uint32_t ue_id) +{ + pcap_file = MAC_LTE_PCAP_Open(filename); + ue_id = ue_id; + enable_write = true; +} +void mac_pcap::close() +{ + fprintf(stdout, "Saving PCAP file\n"); + MAC_LTE_PCAP_Close(pcap_file); +} + +void mac_pcap::pack_and_write(uint8_t* pdu, uint32_t pdu_len_bytes, uint32_t reTX, bool crc_ok, uint32_t tti, + uint16_t crnti, uint8_t direction, uint8_t rnti_type) +{ + if (enable_write) { + MAC_Context_Info_t context = + { + FDD_RADIO, direction, rnti_type, + crnti, /* RNTI */ + (uint16_t)ue_id, /* UEId */ + (uint8_t)reTX, /* Retx */ + crc_ok, /* CRC Stsatus (i.e. OK) */ + (uint16_t)(tti/10), /* Sysframe number */ + (uint16_t)(tti%10) /* Subframe number */ + }; + if (pdu) { + MAC_LTE_PCAP_WritePDU(pcap_file, &context, pdu, pdu_len_bytes); + } + } +} + +void mac_pcap::write_dl_crnti(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t rnti, bool crc_ok, uint32_t tti) +{ + pack_and_write(pdu, pdu_len_bytes, 0, crc_ok, tti, rnti, DIRECTION_DOWNLINK, C_RNTI); +} +void mac_pcap::write_dl_ranti(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t rnti, bool crc_ok, uint32_t tti) +{ + pack_and_write(pdu, pdu_len_bytes, 0, crc_ok, tti, rnti, DIRECTION_DOWNLINK, RA_RNTI); +} +void mac_pcap::write_ul_crnti(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t rnti, uint32_t reTX, uint32_t tti) +{ + pack_and_write(pdu, pdu_len_bytes, reTX, true, tti, rnti, DIRECTION_UPLINK, C_RNTI); +} +void mac_pcap::write_dl_bch(uint8_t* pdu, uint32_t pdu_len_bytes, bool crc_ok, uint32_t tti) +{ + pack_and_write(pdu, pdu_len_bytes, 0, crc_ok, tti, 0, DIRECTION_DOWNLINK, NO_RNTI); +} +void mac_pcap::write_dl_pch(uint8_t* pdu, uint32_t pdu_len_bytes, bool crc_ok, uint32_t tti) +{ + pack_and_write(pdu, pdu_len_bytes, 0, crc_ok, tti, SRSLTE_PRNTI, DIRECTION_DOWNLINK, P_RNTI); +} +void mac_pcap::write_dl_sirnti(uint8_t* pdu, uint32_t pdu_len_bytes, bool crc_ok, uint32_t tti) +{ + pack_and_write(pdu, pdu_len_bytes, 0, crc_ok, tti, SRSLTE_SIRNTI, DIRECTION_DOWNLINK, SI_RNTI); +} + + +} diff --git a/lib/src/common/pdu.cc b/lib/src/common/pdu.cc new file mode 100644 index 000000000..960f7d85e --- /dev/null +++ b/lib/src/common/pdu.cc @@ -0,0 +1,1006 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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 +#include +#include + +#include "srslte/common/pdu.h" +#include "srslte/srslte.h" + +// Table 6.1.3.1-1 Buffer size levels for BSR +static uint32_t btable[64] = { + 0, 5, 10, 12, 14, 17, 19, 22, 26, 31, 36, 42, 49, 57, 67, 78, 91, 107, 125, 146, 171, 200, 234, 274, 321, 376, 440, 515, 603, 706, 826, 967, 1132, + 1326, 1552, 1817, 2127, 2490, 2915, 3413, 3995, 4667, 5476, 6411, 7505, 8787, 10287, 12043, 14099, 16507, 19325, 22624, 26487, 31009, 36304, + 42502, 49759, 58255, 68201, 79846, 93479, 109439, 128125, 150000}; + + + +namespace srslte { + + +void sch_pdu::fprint(FILE* stream) +{ + fprintf(stream, "MAC SDU for UL/DL-SCH. "); + pdu::fprint(stream); +} + +void sch_subh::fprint(FILE* stream) +{ + if (is_sdu()) { + fprintf(stream, "SDU LCHID=%d, SDU nof_bytes=%d\n", lcid, nof_bytes); + } else { + if (parent->is_ul()) { + switch(lcid) { + case CRNTI: + fprintf(stream, "C-RNTI CE\n"); + break; + case PHR_REPORT: + fprintf(stream, "PHR\n"); + break; + case TRUNC_BSR: + fprintf(stream, "Truncated BSR CE\n"); + break; + case SHORT_BSR: + fprintf(stream, "Short BSR CE\n"); + break; + case LONG_BSR: + fprintf(stream, "Long BSR CE\n"); + break; + case PADDING: + fprintf(stream, "PADDING\n"); + } + } else { + switch(lcid) { + case CON_RES_ID: + fprintf(stream, "Contention Resolution ID CE: 0x%lx\n", get_con_res_id()); + break; + case TA_CMD: + fprintf(stream, "Time Advance Command CE: %d\n", get_ta_cmd()); + break; + case DRX_CMD: + fprintf(stream, "DRX Command CE: Not implemented\n"); + break; + case PADDING: + fprintf(stream, "PADDING\n"); + } + } + } +} + +void sch_pdu::parse_packet(uint8_t *ptr) +{ + + pdu::parse_packet(ptr); + + // Correct size for last SDU + if (nof_subheaders > 0) { + uint32_t read_len = 0; + for (int i=0;i= 0) { + subheaders[nof_subheaders-1].set_payload_size(pdu_len-read_len-1); + } else { + fprintf(stderr,"Reading MAC PDU: negative payload for last subheader\n"); + } + } +} + +uint8_t* sch_pdu::write_packet() { + return write_packet(NULL); +} + +/* Writes the MAC PDU in the packet, including the MAC headers and CE payload. Section 6.1.2 */ +uint8_t* sch_pdu::write_packet(srslte::log *log_h) +{ + int init_rem_len=rem_len; + sch_subh padding; + padding.set_padding(); + + if (init_rem_len < 0) { + log_h->error("init_rem_len=%d\n", init_rem_len); + return NULL; + } + + /* If last SDU has zero payload, remove it. FIXME: Why happens this?? */ + if (subheaders[nof_subheaders-1].get_payload_size() == 0) { + del_subh(); + } + + /* Determine if we are transmitting CEs only. */ + bool ce_only = last_sdu_idx<0?true:false; + + /* Determine if we will need multi-byte padding or 1/2 bytes padding */ + bool multibyte_padding = false; + uint32_t onetwo_padding = 0; + if (rem_len > 2) { + multibyte_padding = true; + // Add 1 header for padding + rem_len--; + // Add the header for the last SDU + if (!ce_only) { + rem_len -= (subheaders[last_sdu_idx].get_header_size(false)-1); // Becuase we were assuming it was the one + } + } else if (rem_len > 0) { + onetwo_padding = rem_len; + rem_len = 0; + } + + /* Determine the header size and CE payload size */ + uint32_t header_sz = 0; + uint32_t ce_payload_sz = 0; + for (int i=0;i= sdu_offset_start) { + fprintf(stderr, "Writting PDU: header sz + ce_payload_sz >= sdu_offset_start (%d>=%d). pdu_len=%d, total_sdu_len=%d\n", + header_sz + ce_payload_sz, sdu_offset_start, pdu_len, total_sdu_len); + return NULL; + } + + /* Start writting header and CE payload before the start of the SDU payload */ + uint8_t *ptr = &buffer_tx[sdu_offset_start-header_sz-ce_payload_sz]; + uint8_t *pdu_start_ptr = ptr; + + // Add single/two byte padding first + for (uint32_t i=0;i 0) { + bzero(&pdu_start_ptr[pdu_len-rem_len], rem_len*sizeof(uint8_t)); + } + + /* Sanity check and print if error */ + if (log_h) { + log_h->debug("Wrote PDU: pdu_len=%d, header_and_ce=%d (%d+%d), nof_subh=%d, last_sdu=%d, sdu_len=%d, onepad=%d, multi=%d\n", + pdu_len, header_sz+ce_payload_sz, header_sz, ce_payload_sz, + nof_subheaders, last_sdu_idx, total_sdu_len, onetwo_padding, rem_len); + } else { + printf("Wrote PDU: pdu_len=%d, header_and_ce=%d (%d+%d), nof_subh=%d, last_sdu=%d, sdu_len=%d, onepad=%d, multi=%d, init_rem_len=%d\n", + pdu_len, header_sz+ce_payload_sz, header_sz, ce_payload_sz, + nof_subheaders, last_sdu_idx, total_sdu_len, onetwo_padding, rem_len, init_rem_len); + } + + if (rem_len + header_sz + ce_payload_sz + total_sdu_len != pdu_len) { + printf("\n------------------------------\n"); + for (int i=0;ierror("Wrote PDU: pdu_len=%d, header_and_ce=%d (%d+%d), nof_subh=%d, last_sdu=%d, sdu_len=%d, onepad=%d, multi=%d, init_rem_len=%d\n", + pdu_len, header_sz+ce_payload_sz, header_sz, ce_payload_sz, + nof_subheaders, last_sdu_idx, total_sdu_len, onetwo_padding, rem_len, init_rem_len); + + } + + return NULL; + } + + if ((int)(header_sz + ce_payload_sz) != (int) (ptr - pdu_start_ptr)) { + fprintf(stderr, "Expected a header and CE payload of %d bytes but wrote %d\n", + header_sz+ce_payload_sz,(int) (ptr - pdu_start_ptr)); + return NULL; + } + + return pdu_start_ptr; +} + +int sch_pdu::rem_size() { + return rem_len; +} + +int sch_pdu::get_pdu_len() +{ + return pdu_len; +} + +uint32_t sch_pdu::size_header_sdu(uint32_t nbytes) +{ + if (nbytes < 128) { + return 2; + } else { + return 3; + } +} +bool sch_pdu::has_space_ce(uint32_t nbytes) +{ + if (rem_len >= nbytes + 1) { + return true; + } else { + return false; + } +} + +bool sch_pdu::update_space_ce(uint32_t nbytes) +{ + if (has_space_ce(nbytes)) { + rem_len -= nbytes + 1; + return true; + } else { + return false; + } +} + +bool sch_pdu::has_space_sdu(uint32_t nbytes) +{ + int s = get_sdu_space(); + + if (s < 0) { + return false; + } else { + return (uint32_t)s >= nbytes; + } +} + +bool sch_pdu::update_space_sdu(uint32_t nbytes) +{ + int init_rem = rem_len; + if (has_space_sdu(nbytes)) { + if (last_sdu_idx < 0) { + rem_len -= (nbytes+1); + } else { + rem_len -= (nbytes+1 + (size_header_sdu(subheaders[last_sdu_idx].get_payload_size())-1)); + } + last_sdu_idx = cur_idx; + return true; + } else { + return false; + } +} + +int sch_pdu::get_sdu_space() +{ + int ret; + if (last_sdu_idx < 0) { + ret = rem_len - 1; + } else { + ret = rem_len - (size_header_sdu(subheaders[last_sdu_idx].get_payload_size())-1) - 1; + } + return ret; +} + +void sch_subh::init() +{ + lcid = 0; + nof_bytes = 0; + payload = NULL; +} + +sch_subh::cetype sch_subh::ce_type() +{ + if (lcid >= PHR_REPORT) { + return (cetype) lcid; + } else { + return SDU; + } +} + +void sch_subh::set_payload_size(uint32_t size) { + nof_bytes = size; +} + +uint32_t sch_subh::size_plus_header() { + if (is_sdu()) { + return sch_pdu::size_header_sdu(nof_bytes) + nof_bytes; + } else { + return nof_bytes + 1; + } +} + +uint32_t sch_subh::sizeof_ce(uint32_t lcid, bool is_ul) +{ + if (is_ul) { + switch(lcid) { + case PHR_REPORT: + return 1; + case CRNTI: + return 2; + case TRUNC_BSR: + return 1; + case SHORT_BSR: + return 1; + case LONG_BSR: + return 3; + 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; +} +bool sch_subh::is_sdu() +{ + return ce_type() == SDU; +} +uint16_t sch_subh::get_c_rnti() +{ + if (payload) { + return (uint16_t) payload[0]<<8 | payload[1]; + } else { + return (uint16_t) w_payload_ce[0]<<8 | w_payload_ce[1]; + } +} +uint64_t sch_subh::get_con_res_id() +{ + if (payload) { + return ((uint64_t) payload[5]) | (((uint64_t) payload[4])<<8) | (((uint64_t) payload[3])<<16) | (((uint64_t) payload[2])<<24) | + (((uint64_t) payload[1])<<32) | (((uint64_t) payload[0])<<40); + } else { + return ((uint64_t) w_payload_ce[5]) | (((uint64_t) w_payload_ce[4])<<8) | (((uint64_t) w_payload_ce[3])<<16) | (((uint64_t) w_payload_ce[2])<<24) | + (((uint64_t) w_payload_ce[1])<<32) | (((uint64_t) w_payload_ce[0])<<40); + return 0; + } +} +float sch_subh::get_phr() +{ + if (payload) { + return (float) (payload[0]&0x3f) - 23; + } else { + return (float) (w_payload_ce[0]&0x3f) - 23; + } +} + +int sch_subh::get_bsr(uint32_t buff_size[4]) +{ + if (payload) { + uint32_t nonzero_lcg = 0; + if (ce_type()==LONG_BSR) { + buff_size[0] = (payload[0]&0xFC) >> 2; + buff_size[1] = (payload[0]&0x03) << 4 | (payload[1]&0xF0) >> 4; + buff_size[2] = (payload[1]&0x0F) << 4 | (payload[1]&0xC0) >> 6; + buff_size[3] = (payload[2]&0x3F); + } else { + uint32_t nonzero_lcg = (payload[0]&0xc0) >> 6; + buff_size[nonzero_lcg%4] = payload[0]&0x3f; + } + for (int i=0;i<4;i++) { + if (buff_size[i]) { + buff_size[i] = btable[buff_size[i]%64]; + } + } + return nonzero_lcg; + } else { + return -1; + } +} + +uint8_t sch_subh::get_ta_cmd() +{ + if (payload) { + return (uint8_t) payload[0]&0x3f; + } else { + return 0; + } +} +uint32_t sch_subh::get_sdu_lcid() +{ + return lcid; +} +uint32_t sch_subh::get_payload_size() +{ + return nof_bytes; +} +uint32_t sch_subh::get_header_size(bool is_last) { + if (!is_last) { + // For all subheaders, size can be 1, 2 or 3 bytes + if (is_sdu()) { + return sch_pdu::size_header_sdu(get_payload_size()); + } else { + return 1; + } + } else { + // Last subheader (CE or SDU) has always 1 byte header + return 1; + } +} +uint8_t* sch_subh::get_sdu_ptr() +{ + return payload; +} +void sch_subh::set_padding(uint32_t padding_len) +{ + lcid = PADDING; + nof_bytes = padding_len; +} +void sch_subh::set_padding() +{ + set_padding(0); +} + + +bool sch_subh::set_bsr(uint32_t buff_size[4], sch_subh::cetype format) +{ + uint32_t nonzero_lcg=0; + for (int i=0;i<4;i++) { + if (buff_size[i]) { + nonzero_lcg=i; + } + } + 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); + } else { + w_payload_ce[0] = (nonzero_lcg&0x3)<<6 | (buff_size_table(buff_size[nonzero_lcg])&0x3f); + } + lcid = format; + ((sch_pdu*)parent)->update_space_ce(ce_size); + nof_bytes = ce_size; + return true; + } else { + return false; + } +} + +bool sch_subh::set_c_rnti(uint16_t crnti) +{ + if (((sch_pdu*)parent)->has_space_ce(2)) { + w_payload_ce[0] = (uint8_t) (crnti&0xff00)>>8; + w_payload_ce[1] = (uint8_t) (crnti&0x00ff); + lcid = CRNTI; + ((sch_pdu*)parent)->update_space_ce(2); + nof_bytes = 2; + return true; + } else { + return false; + } +} +bool sch_subh::set_con_res_id(uint64_t con_res_id) +{ + if (((sch_pdu*)parent)->has_space_ce(6)) { + w_payload_ce[0] = (uint8_t) ((con_res_id&0xff0000000000)>>40); + w_payload_ce[1] = (uint8_t) ((con_res_id&0x00ff00000000)>>32); + w_payload_ce[2] = (uint8_t) ((con_res_id&0x0000ff000000)>>24); + w_payload_ce[3] = (uint8_t) ((con_res_id&0x000000ff0000)>>16); + w_payload_ce[4] = (uint8_t) ((con_res_id&0x00000000ff00)>>8); + w_payload_ce[5] = (uint8_t) ((con_res_id&0x0000000000ff)); + lcid = CON_RES_ID; + ((sch_pdu*)parent)->update_space_ce(6); + nof_bytes = 6; + return true; + } else { + return false; + } +} +bool sch_subh::set_phr(float phr) +{ + if (((sch_pdu*)parent)->has_space_ce(1)) { + w_payload_ce[0] = phr_report_table(phr)&0x3f; + lcid = PHR_REPORT; + ((sch_pdu*)parent)->update_space_ce(1); + nof_bytes = 1; + return true; + } else { + return false; + } +} + +bool sch_subh::set_ta_cmd(uint8_t ta_cmd) +{ + if (((sch_pdu*)parent)->has_space_ce(1)) { + w_payload_ce[0] = ta_cmd&0x3f; + lcid = TA_CMD; + ((sch_pdu*)parent)->update_space_ce(1); + nof_bytes = 1; + return true; + } else { + return false; + } +} + +int sch_subh::set_sdu(uint32_t lcid_, uint32_t requested_bytes, read_pdu_interface *sdu_itf) +{ + if (((sch_pdu*)parent)->has_space_sdu(requested_bytes)) { + lcid = lcid_; + + payload = ((sch_pdu*)parent)->get_current_sdu_ptr(); + // Copy data and get final number of bytes written to the MAC PDU + uint32_t sdu_sz = sdu_itf->read_pdu(lcid, payload, requested_bytes); + + if (sdu_sz < 0 || sdu_sz > requested_bytes) { + return -1; + } + if (sdu_sz == 0) { + return 0; + } + + // Save final number of written bytes + nof_bytes = sdu_sz; + + ((sch_pdu*)parent)->add_sdu(nof_bytes); + ((sch_pdu*)parent)->update_space_sdu(nof_bytes); + return nof_bytes; + } else { + return -1; + } +} + +int sch_subh::set_sdu(uint32_t lcid_, uint32_t nof_bytes_, uint8_t *payload) +{ + if (((sch_pdu*)parent)->has_space_sdu(nof_bytes_)) { + lcid = lcid_; + + memcpy(((sch_pdu*)parent)->get_current_sdu_ptr(), payload, nof_bytes_); + + ((sch_pdu*)parent)->add_sdu(nof_bytes_); + ((sch_pdu*)parent)->update_space_sdu(nof_bytes_); + nof_bytes = nof_bytes_; + + return (int) nof_bytes; + } else { + return -1; + } +} + + +// Section 6.2.1 +void sch_subh::write_subheader(uint8_t** ptr, bool is_last) +{ + *(*ptr) = (uint8_t) (is_last?0:(1<<5)) | ((uint8_t) lcid & 0x1f); + *ptr += 1; + if (is_sdu()) { + // MAC SDU: R/R/E/LCID/F/L subheader + // 2nd and 3rd octet + if (!is_last) { + if (nof_bytes >= 128) { + *(*ptr) = (uint8_t) 1<<7 | ((nof_bytes & 0x7f00) >> 8); + *ptr += 1; + *(*ptr) = (uint8_t) (nof_bytes & 0xff); + *ptr += 1; + } else { + *(*ptr) = (uint8_t) (nof_bytes & 0x7f); + *ptr += 1; + } + } + } +} + +void sch_subh::write_payload(uint8_t** ptr) +{ + if (is_sdu()) { + // SDU is written directly during subheader creation + } else { + nof_bytes = sizeof_ce(lcid, parent->is_ul()); + memcpy(*ptr, w_payload_ce, nof_bytes*sizeof(uint8_t)); + } + *ptr += nof_bytes; +} + +bool sch_subh::read_subheader(uint8_t** ptr) +{ + // Skip R + bool e_bit = (bool) (*(*ptr) & 0x20)?true:false; + lcid = (uint8_t) *(*ptr) & 0x1f; + *ptr += 1; + if (is_sdu()) { + if (e_bit) { + F_bit = (bool) (*(*ptr) & 0x80)?true:false; + nof_bytes = (uint32_t)*(*ptr) & 0x7f; + *ptr += 1; + if (F_bit) { + nof_bytes = nof_bytes<<8 | ((uint32_t) *(*ptr) & 0xff); + *ptr += 1; + } + } else { + nof_bytes = 0; + F_bit = 0; + } + } else { + nof_bytes = sizeof_ce(lcid, parent->is_ul()); + } + return e_bit; +} +void sch_subh::read_payload(uint8_t** ptr) +{ + payload = *ptr; + *ptr += nof_bytes; +} + +uint8_t sch_subh::buff_size_table(uint32_t buffer_size) { + if (buffer_size == 0) { + return 0; + } else if (buffer_size > 150000) { + return 63; + } else { + for (int i=0;i<61;i++) { + if (buffer_size < btable[i+2]) { + return 1+i; + } + } + return 62; + } +} + +// Implements Table 9.1.8.4-1 Power headroom report mapping (36.133) +uint8_t sch_subh::phr_report_table(float phr_value) +{ + if (phr_value < -23) { + phr_value = -23; + } + if (phr_value > 40) { + phr_value = 40; + } + return (uint8_t) floor(phr_value+23); +} + + + + + + + +void rar_pdu::fprint(FILE* stream) +{ + fprintf(stream, "MAC PDU for RAR. "); + if (has_backoff_indicator) { + fprintf(stream, "Backoff Indicator %d. ", backoff_indicator); + } + pdu::fprint(stream); +} + + +void rar_subh::fprint(FILE* stream) +{ + fprintf(stream, "RAPID: %d, Temp C-RNTI: %d, TA: %d, UL Grant: ", preamble, temp_rnti, ta); + srslte_vec_fprint_hex(stream, grant, 20); +} + +rar_pdu::rar_pdu(uint32_t max_rars_) : pdu(max_rars_) +{ + backoff_indicator = 0; + has_backoff_indicator = false; +} +uint8_t rar_pdu::get_backoff() +{ + return backoff_indicator; +} +bool rar_pdu::has_backoff() +{ + return has_backoff_indicator; +} +void rar_pdu::set_backoff(uint8_t bi) +{ + has_backoff_indicator = true; + backoff_indicator = bi; +} + +// Section 6.1.5 +bool rar_pdu::write_packet(uint8_t* ptr) +{ + // Write Backoff Indicator, if any + if (has_backoff_indicator) { + *(ptr) = backoff_indicator&0xf; + if (nof_subheaders > 0) { + *(ptr) = 1<<7; + } + ptr++; + } + + // Write RAR subheaders + for (int i=0;i>4; + *(*ptr + 1) = (uint8_t) ((ta&0xf) <<4) | (grant[0]<<3) | (grant[1]<<2) | (grant[2]<<1) | grant[3]; + uint8_t *x = &grant[4]; + *(*ptr + 2) = (uint8_t) srslte_bit_pack(&x, 8); + *(*ptr + 3) = (uint8_t) srslte_bit_pack(&x, 8); + *(*ptr + 4) = (uint8_t) ((temp_rnti&0xff00) >> 8); + *(*ptr + 5) = (uint8_t) (temp_rnti&0x00ff); + *ptr += 6; +} + +void rar_subh::read_payload(uint8_t** ptr) +{ + ta = ((uint32_t) *(*ptr + 0)&0x7f)<<4 | (*(*ptr + 1)&0xf0)>>4; + grant[0] = *(*ptr + 1)&0x8?1:0; + grant[1] = *(*ptr + 1)&0x4?1:0; + grant[2] = *(*ptr + 1)&0x2?1:0; + grant[3] = *(*ptr + 1)&0x1?1:0; + uint8_t *x = &grant[4]; + srslte_bit_unpack(*(*ptr+2), &x, 8); + srslte_bit_unpack(*(*ptr+3), &x, 8); + temp_rnti = ((uint16_t) *(*ptr + 4))<<8 | *(*ptr + 5); + *ptr += 6; +} + +bool rar_subh::read_subheader(uint8_t** ptr) +{ + bool e_bit = *(*ptr) & 0x80?true:false; + bool type = *(*ptr) & 0x40?true:false; + if (type) { + preamble = *(*ptr) & 0x3f; + } else { + ((rar_pdu*)parent)->set_backoff(*(*ptr) & 0xf); + } + *ptr += 1; + return e_bit; +} + +} + + + +//int main() +//{ +// /* Test 1st message: CCCH + Short BSR + PHR */ +// uint8_t buffer[10240]; +// uint8_t ccch_payload[6] = {0x10, 0x20, 0x30, 0x40, 0x50, 0x60}; +// uint32_t bsr_st[4] = {1, 2, 3, 4}; +// srsue::sch_pdu pdu(10); +// uint8_t *ptr; + +// printf("------- CCCH + Short BSR + PHR no padding ----------\n"); +// bzero(buffer, 10240); +// pdu.init_tx(buffer, 11, true); +// printf("Available space: %d\n", pdu.rem_size()); +// pdu.new_subh(); +// pdu.get()->set_sdu(0,6,ccch_payload); +// pdu.new_subh(); +// pdu.get()->set_phr(10); +// pdu.new_subh(); +// pdu.get()->set_bsr(bsr_st, srsue::sch_subh::SHORT_BSR); +// printf("Remaining space: %d\n", pdu.rem_size()); +// ptr = pdu.write_packet(); +// srslte_vec_fprint_byte(stdout, ptr, pdu.get_pdu_len()); +// printf("\n"); + +// /* Test single SDU: SDU 15 + 1 byte header */ +// printf("------- Single SDU no padding ----------\n"); +// uint8_t dlsch_payload[15] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}; +// bzero(buffer, 10240); +// pdu.init_tx(buffer, 16, true); +// printf("Available space: %d\n", pdu.rem_size()); +// pdu.new_subh(); +// pdu.get()->set_sdu(1, 15, dlsch_payload); +// printf("Remaining space: %d\n", pdu.rem_size()); +// ptr = pdu.write_packet(); +// srslte_vec_fprint_byte(stdout, ptr, pdu.get_pdu_len()); +// printf("\n"); + +// /* Test multiple SDU + multiword padding: SDU 8 + SDU 2 byte*/ +// printf("------- Multiple SDU + multiword padding ----------\n"); +// uint8_t dlsch_payload1[8] = {1,2,3,4,5,6,7,8}; +// uint8_t dlsch_payload2[2] = {0xA, 0xB}; +// bzero(buffer, 10240); +// pdu.init_tx(buffer, 18, true); +// printf("Available space: %d\n", pdu.rem_size()); +// pdu.new_subh(); +// pdu.get()->set_sdu(2, 8, dlsch_payload1); +// pdu.new_subh(); +// pdu.get()->set_sdu(3, 2, dlsch_payload2); +// printf("Remaining space: %d\n", pdu.rem_size()); +// ptr = pdu.write_packet(); +// srslte_vec_fprint_byte(stdout, ptr, pdu.get_pdu_len()); +// printf("\n"); + +// printf("------- Multiple SDU + 2word padding ----------\n"); +// bzero(buffer, 10240); +// pdu.init_tx(buffer, 15, true); +// printf("Available space: %d\n", pdu.rem_size()); +// pdu.new_subh(); +// pdu.get()->set_sdu(2, 8, dlsch_payload1); +// pdu.new_subh(); +// pdu.get()->set_sdu(3, 2, dlsch_payload2); +// printf("Remaining space: %d\n", pdu.rem_size()); +// ptr = pdu.write_packet(); +// srslte_vec_fprint_byte(stdout, ptr, pdu.get_pdu_len()); +// printf("\n"); + +// printf("------- Multiple SDU + 1word padding ----------\n"); +// bzero(buffer, 10240); +// pdu.init_tx(buffer, 14, true); +// printf("Available space: %d\n", pdu.rem_size()); +// pdu.new_subh(); +// pdu.get()->set_sdu(2, 8, dlsch_payload1); +// pdu.new_subh(); +// pdu.get()->set_sdu(3, 2, dlsch_payload2); +// printf("Remaining space: %d\n", pdu.rem_size()); +// ptr = pdu.write_packet(); +// srslte_vec_fprint_byte(stdout, ptr, pdu.get_pdu_len()); +// printf("\n"); + +// printf("------- Multiple SDU + 0word padding ----------\n"); +// bzero(buffer, 10240); +// pdu.init_tx(buffer, 13, true); +// printf("Available space: %d\n", pdu.rem_size()); +// pdu.new_subh(); +// pdu.get()->set_sdu(2, 8, dlsch_payload1); +// pdu.new_subh(); +// pdu.get()->set_sdu(3, 2, dlsch_payload2); +// printf("Remaining space: %d\n", pdu.rem_size()); +// ptr = pdu.write_packet(); +// srslte_vec_fprint_byte(stdout, ptr, pdu.get_pdu_len()); +// printf("\n"); + +// printf("------- Multiple SDU + no space ----------\n"); +// bzero(buffer, 10240); +// pdu.init_tx(buffer, 12, true); +// printf("Available space: %d\n", pdu.rem_size()); +// pdu.new_subh(); +// pdu.get()->set_sdu(2, 8, dlsch_payload1); +// pdu.new_subh(); +// if (pdu.get()->set_sdu(3, 2, dlsch_payload2) < 0) { +// pdu.del_subh(); +// } +// printf("Remaining space: %d\n", pdu.rem_size()); +// ptr = pdu.write_packet(); +// srslte_vec_fprint_byte(stdout, ptr, pdu.get_pdu_len()); +// printf("\n"); + +// /* CE only */ +// printf("------- CE only ----------\n"); +// bzero(buffer, 10240); +// pdu.init_tx(buffer, 125, true); +// printf("Available space: %d\n", pdu.rem_size()); +// pdu.new_subh(); +// pdu.get()->set_phr(15); +// pdu.new_subh(); +// pdu.get()->set_bsr(bsr_st, srsue::sch_subh::SHORT_BSR); +// printf("Remaining space: %d\n", pdu.rem_size()); +// ptr = pdu.write_packet(); +// srslte_vec_fprint_byte(stdout, ptr, pdu.get_pdu_len()); +// printf("\n"); + +// /* Another test */ +// printf("------- Another test ----------\n"); +// uint8_t dlsch_payload3[602]; +// bzero(buffer, 10240); +// pdu.init_tx(buffer, 75, true); +// printf("Available space: %d\n", pdu.rem_size()); +// pdu.new_subh(); +// pdu.get()->set_bsr(bsr_st, srsue::sch_subh::SHORT_BSR); +// pdu.new_subh(); +// pdu.get()->set_sdu(3, 2, dlsch_payload3); +// pdu.new_subh(); +// pdu.get()->set_sdu(3, 66, dlsch_payload3); +// pdu.new_subh(); +// printf("Remaining space: %d\n", pdu.rem_size()); +// ptr = pdu.write_packet(); +// //srslte_vec_fprint_byte(stdout, ptr, pdu.get_pdu_len()); +// printf("\n"); + +// return 0; +//} + + + diff --git a/lib/src/common/pdu_queue.cc b/lib/src/common/pdu_queue.cc new file mode 100644 index 000000000..a1bf7cd59 --- /dev/null +++ b/lib/src/common/pdu_queue.cc @@ -0,0 +1,109 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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/. + * + */ + + +#define Error(fmt, ...) log_h->error_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Warning(fmt, ...) log_h->warning_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Info(fmt, ...) log_h->info_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Debug(fmt, ...) log_h->debug_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) + +#include "srslte/common/pdu_queue.h" + + +namespace srslte { + + +void pdu_queue::init(process_callback *callback_, log* log_h_) +{ + callback = callback_; + log_h = log_h_; +} + +uint8_t* pdu_queue::request(uint32_t len) +{ + if (len > MAX_PDU_LEN) { + fprintf(stderr, "Error request buffer of invalid size %d. Max bytes %d\n", len, MAX_PDU_LEN); + return NULL; + } + pdu_t *pdu = pool.allocate(); + if (!pdu) { + if (log_h) { + log_h->error("Not enough buffers for MAC PDU\n"); + } + fprintf(stderr, "Not enough buffers for MAC PDU\n"); + } + if ((void*) pdu->ptr != (void*) pdu) { + fprintf(stderr, "Fatal error in memory alignment in struct pdu_queue::pdu_t\n"); + exit(-1); + } + + return pdu->ptr; +} + +void pdu_queue::deallocate(uint8_t* pdu) +{ + if (!pool.deallocate((pdu_t*) pdu)) { + log_h->warning("Error deallocating from buffer pool: buffer not created in this pool.\n"); + } +} + +/* Demultiplexing of logical channels and dissassemble of MAC CE + * This function enqueues the packet and returns quicly because ACK + * deadline is important here. + */ +void pdu_queue::push(uint8_t *ptr, uint32_t len, uint32_t tstamp) +{ + pdu_t *pdu = (pdu_t*) ptr; + pdu->len = len; + pdu->tstamp = tstamp; + pdu_q.push(pdu); +} + +bool pdu_queue::process_pdus() +{ + bool have_data = false; + uint32_t cnt = 0; + pdu_t *pdu; + while(pdu_q.try_pop(&pdu)) { + if (callback) { + callback->process_pdu(pdu->ptr, pdu->len, pdu->tstamp); + } + if (!pool.deallocate(pdu)) { + log_h->warning("Error deallocating from buffer pool: buffer not created in this pool.\n"); + } + cnt++; + have_data = true; + } + if (cnt > 20) { + if (log_h) { + log_h->warning("PDU queue dispatched %d packets\n", cnt); + } + printf("Warning PDU queue dispatched %d packets\n", cnt); + } + return have_data; +} + +} diff --git a/lib/src/common/security.cc b/lib/src/common/security.cc new file mode 100644 index 000000000..f0ad1ce7e --- /dev/null +++ b/lib/src/common/security.cc @@ -0,0 +1,212 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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/security.h" +#include "srslte/common/liblte_security.h" +#include "srslte/common/snow_3g.h" + +namespace srslte { + +/****************************************************************************** + * Key Generation + *****************************************************************************/ + +uint8_t security_generate_k_asme( uint8_t *ck, + uint8_t *ik, + uint8_t *ak, + uint8_t *sqn, + uint16_t mcc, + uint16_t mnc, + uint8_t *k_asme) +{ + return liblte_security_generate_k_asme(ck, + ik, + ak, + sqn, + mcc, + mnc, + k_asme); +} + +uint8_t security_generate_k_enb( uint8_t *k_asme, + uint32_t nas_count, + uint8_t *k_enb) +{ + return liblte_security_generate_k_enb(k_asme, + nas_count, + k_enb); +} + +uint8_t security_generate_k_nas( uint8_t *k_asme, + CIPHERING_ALGORITHM_ID_ENUM enc_alg_id, + INTEGRITY_ALGORITHM_ID_ENUM int_alg_id, + uint8_t *k_nas_enc, + uint8_t *k_nas_int) +{ + return liblte_security_generate_k_nas( k_asme, + (LIBLTE_SECURITY_CIPHERING_ALGORITHM_ID_ENUM)enc_alg_id, + (LIBLTE_SECURITY_INTEGRITY_ALGORITHM_ID_ENUM)int_alg_id, + k_nas_enc, + k_nas_int); +} + +uint8_t security_generate_k_rrc( uint8_t *k_enb, + CIPHERING_ALGORITHM_ID_ENUM enc_alg_id, + INTEGRITY_ALGORITHM_ID_ENUM int_alg_id, + uint8_t *k_rrc_enc, + uint8_t *k_rrc_int) +{ + return liblte_security_generate_k_rrc(k_enb, + (LIBLTE_SECURITY_CIPHERING_ALGORITHM_ID_ENUM)enc_alg_id, + (LIBLTE_SECURITY_INTEGRITY_ALGORITHM_ID_ENUM)int_alg_id, + k_rrc_enc, + k_rrc_int); +} + +uint8_t security_generate_k_up( uint8_t *k_enb, + CIPHERING_ALGORITHM_ID_ENUM enc_alg_id, + INTEGRITY_ALGORITHM_ID_ENUM int_alg_id, + uint8_t *k_up_enc, + uint8_t *k_up_int) +{ + return liblte_security_generate_k_up(k_enb, + (LIBLTE_SECURITY_CIPHERING_ALGORITHM_ID_ENUM)enc_alg_id, + (LIBLTE_SECURITY_INTEGRITY_ALGORITHM_ID_ENUM)int_alg_id, + k_up_enc, + k_up_int); +} + +/****************************************************************************** + * Integrity Protection + *****************************************************************************/ + +uint8_t security_128_eia1( uint8_t *key, + uint32_t count, + uint8_t bearer, + uint8_t direction, + uint8_t *msg, + uint32_t msg_len, + uint8_t *mac) +{ + uint32_t msg_len_bits; + uint32_t i; + uint8_t *m_ptr; + + msg_len_bits = msg_len*8; + m_ptr = snow3g_f9(key, + count, + bearer, + direction, + msg, + msg_len_bits); + for(i=0; i<4; i++) { + mac[i] = m_ptr[i]; + } + return ERROR_NONE; +} + +uint8_t security_128_eia2( uint8_t *key, + uint32_t count, + uint8_t bearer, + uint8_t direction, + uint8_t *msg, + uint32_t msg_len, + uint8_t *mac) +{ + return liblte_security_128_eia2(key, + count, + bearer, + direction, + msg, + msg_len, + mac); +} + +/****************************************************************************** + * Authentication + *****************************************************************************/ + +uint8_t security_milenage_f1( uint8_t *k, + uint8_t *op, + uint8_t *rand, + uint8_t *sqn, + uint8_t *amf, + uint8_t *mac_a) +{ + return liblte_security_milenage_f1(k, + op, + rand, + sqn, + amf, + 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) +{ + return liblte_security_milenage_f1_star(k, + op, + rand, + sqn, + amf, + 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) +{ + return liblte_security_milenage_f2345(k, + op, + rand, + res, + ck, + ik, + ak); +} + +uint8_t security_milenage_f5_star( uint8_t *k, + uint8_t *op, + uint8_t *rand, + uint8_t *ak) +{ + return liblte_security_milenage_f5_star(k, + op, + rand, + ak); +} + + +} // namespace srsue diff --git a/lib/src/common/snow_3g.cc b/lib/src/common/snow_3g.cc new file mode 100644 index 000000000..3c5658623 --- /dev/null +++ b/lib/src/common/snow_3g.cc @@ -0,0 +1,577 @@ +/*------------------------------------------------------------------------ +* snow_3g.c +* +* Adapted from ETSI/SAGE specifications: +* "Specification of the 3GPP Confidentiality and +* Integrity Algorithms UEA2 & UIA2. +* Document 1: UEA2 and UIA2 Specification" +* "Specification of the 3GPP Confidentiality +* and Integrity Algorithms UEA2 & UIA2. +* Document 2: SNOW 3G Specification" +*------------------------------------------------------------------------*/ + +#include "srslte/common/snow_3g.h" + +/* LFSR */ + +u32 LFSR_S0 = 0x00; +u32 LFSR_S1 = 0x00; +u32 LFSR_S2 = 0x00; +u32 LFSR_S3 = 0x00; +u32 LFSR_S4 = 0x00; +u32 LFSR_S5 = 0x00; +u32 LFSR_S6 = 0x00; +u32 LFSR_S7 = 0x00; +u32 LFSR_S8 = 0x00; +u32 LFSR_S9 = 0x00; +u32 LFSR_S10 = 0x00; +u32 LFSR_S11 = 0x00; +u32 LFSR_S12 = 0x00; +u32 LFSR_S13 = 0x00; +u32 LFSR_S14 = 0x00; +u32 LFSR_S15 = 0x00; + +/* FSM */ + +u32 FSM_R1 = 0x00; +u32 FSM_R2 = 0x00; +u32 FSM_R3 = 0x00; + +/* Rijndael S-box SR */ + +u8 SR[256] = { +0x63,0x7C,0x77,0x7B,0xF2,0x6B,0x6F,0xC5,0x30,0x01,0x67,0x2B,0xFE,0xD7,0xAB,0x76, +0xCA,0x82,0xC9,0x7D,0xFA,0x59,0x47,0xF0,0xAD,0xD4,0xA2,0xAF,0x9C,0xA4,0x72,0xC0, +0xB7,0xFD,0x93,0x26,0x36,0x3F,0xF7,0xCC,0x34,0xA5,0xE5,0xF1,0x71,0xD8,0x31,0x15, +0x04,0xC7,0x23,0xC3,0x18,0x96,0x05,0x9A,0x07,0x12,0x80,0xE2,0xEB,0x27,0xB2,0x75, +0x09,0x83,0x2C,0x1A,0x1B,0x6E,0x5A,0xA0,0x52,0x3B,0xD6,0xB3,0x29,0xE3,0x2F,0x84, +0x53,0xD1,0x00,0xED,0x20,0xFC,0xB1,0x5B,0x6A,0xCB,0xBE,0x39,0x4A,0x4C,0x58,0xCF, +0xD0,0xEF,0xAA,0xFB,0x43,0x4D,0x33,0x85,0x45,0xF9,0x02,0x7F,0x50,0x3C,0x9F,0xA8, +0x51,0xA3,0x40,0x8F,0x92,0x9D,0x38,0xF5,0xBC,0xB6,0xDA,0x21,0x10,0xFF,0xF3,0xD2, +0xCD,0x0C,0x13,0xEC,0x5F,0x97,0x44,0x17,0xC4,0xA7,0x7E,0x3D,0x64,0x5D,0x19,0x73, +0x60,0x81,0x4F,0xDC,0x22,0x2A,0x90,0x88,0x46,0xEE,0xB8,0x14,0xDE,0x5E,0x0B,0xDB, +0xE0,0x32,0x3A,0x0A,0x49,0x06,0x24,0x5C,0xC2,0xD3,0xAC,0x62,0x91,0x95,0xE4,0x79, +0xE7,0xC8,0x37,0x6D,0x8D,0xD5,0x4E,0xA9,0x6C,0x56,0xF4,0xEA,0x65,0x7A,0xAE,0x08, +0xBA,0x78,0x25,0x2E,0x1C,0xA6,0xB4,0xC6,0xE8,0xDD,0x74,0x1F,0x4B,0xBD,0x8B,0x8A, +0x70,0x3E,0xB5,0x66,0x48,0x03,0xF6,0x0E,0x61,0x35,0x57,0xB9,0x86,0xC1,0x1D,0x9E, +0xE1,0xF8,0x98,0x11,0x69,0xD9,0x8E,0x94,0x9B,0x1E,0x87,0xE9,0xCE,0x55,0x28,0xDF, +0x8C,0xA1,0x89,0x0D,0xBF,0xE6,0x42,0x68,0x41,0x99,0x2D,0x0F,0xB0,0x54,0xBB,0x16 +}; + +/* S-box SQ */ + +u8 SQ[256] = { +0x25,0x24,0x73,0x67,0xD7,0xAE,0x5C,0x30,0xA4,0xEE,0x6E,0xCB,0x7D,0xB5,0x82,0xDB, +0xE4,0x8E,0x48,0x49,0x4F,0x5D,0x6A,0x78,0x70,0x88,0xE8,0x5F,0x5E,0x84,0x65,0xE2, +0xD8,0xE9,0xCC,0xED,0x40,0x2F,0x11,0x28,0x57,0xD2,0xAC,0xE3,0x4A,0x15,0x1B,0xB9, +0xB2,0x80,0x85,0xA6,0x2E,0x02,0x47,0x29,0x07,0x4B,0x0E,0xC1,0x51,0xAA,0x89,0xD4, +0xCA,0x01,0x46,0xB3,0xEF,0xDD,0x44,0x7B,0xC2,0x7F,0xBE,0xC3,0x9F,0x20,0x4C,0x64, +0x83,0xA2,0x68,0x42,0x13,0xB4,0x41,0xCD,0xBA,0xC6,0xBB,0x6D,0x4D,0x71,0x21,0xF4, +0x8D,0xB0,0xE5,0x93,0xFE,0x8F,0xE6,0xCF,0x43,0x45,0x31,0x22,0x37,0x36,0x96,0xFA, +0xBC,0x0F,0x08,0x52,0x1D,0x55,0x1A,0xC5,0x4E,0x23,0x69,0x7A,0x92,0xFF,0x5B,0x5A, +0xEB,0x9A,0x1C,0xA9,0xD1,0x7E,0x0D,0xFC,0x50,0x8A,0xB6,0x62,0xF5,0x0A,0xF8,0xDC, +0x03,0x3C,0x0C,0x39,0xF1,0xB8,0xF3,0x3D,0xF2,0xD5,0x97,0x66,0x81,0x32,0xA0,0x00, +0x06,0xCE,0xF6,0xEA,0xB7,0x17,0xF7,0x8C,0x79,0xD6,0xA7,0xBF,0x8B,0x3F,0x1F,0x53, +0x63,0x75,0x35,0x2C,0x60,0xFD,0x27,0xD3,0x94,0xA5,0x7C,0xA1,0x05,0x58,0x2D,0xBD, +0xD9,0xC7,0xAF,0x6B,0x54,0x0B,0xE0,0x38,0x04,0xC8,0x9D,0xE7,0x14,0xB1,0x87,0x9C, +0xDF,0x6F,0xF9,0xDA,0x2A,0xC4,0x59,0x16,0x74,0x91,0xAB,0x26,0x61,0x76,0x34,0x2B, +0xAD,0x99,0xFB,0x72,0xEC,0x33,0x12,0xDE,0x98,0x3B,0xC0,0x9B,0x3E,0x18,0x10,0x3A, +0x56,0xE1,0x77,0xC9,0x1E,0x9E,0x95,0xA3,0x90,0x19,0xA8,0x6C,0x09,0xD0,0xF0,0x86 +}; + +/* MULx. +* Input V: an 8-bit input. +* Input c: an 8-bit input. +* Output : an 8-bit output. +* See section 3.1.1 for details. +*/ + +u8 MULx(u8 V, u8 c) +{ + if ( V & 0x80 ) + return ( (V << 1) ^ c); + else + return ( V << 1); +} + +/* MULxPOW. +* Input V: an 8-bit input. +* Input i: a positive integer. +* Input c: an 8-bit input. +* Output : an 8-bit output. +* See section 3.1.2 for details. +*/ + +u8 MULxPOW(u8 V, u8 i, u8 c) +{ + if ( i == 0) + return V; + else + return MULx( MULxPOW( V, i-1, c ), c); +} + +/* The function MUL alpha. +* Input c: 8-bit input. +* Output : 32-bit output. +* See section 3.4.2 for details. +*/ + +u32 MULalpha(u8 c) +{ + return ( ( ((u32)MULxPOW(c, 23, 0xa9)) << 24 ) | + ( ((u32)MULxPOW(c, 245, 0xa9)) << 16 ) | + ( ((u32)MULxPOW(c, 48, 0xa9)) << 8 ) | + ( ((u32)MULxPOW(c, 239, 0xa9)) ) ) ; +} + +/* The function DIV alpha. +* Input c: 8-bit input. +* Output : 32-bit output. +* See section 3.4.3 for details. +*/ + +u32 DIValpha(u8 c) +{ + return ( ( ((u32)MULxPOW(c, 16, 0xa9)) << 24 ) | + ( ((u32)MULxPOW(c, 39, 0xa9)) << 16 ) | + ( ((u32)MULxPOW(c, 6, 0xa9)) << 8 ) | + ( ((u32)MULxPOW(c, 64, 0xa9)) ) ) ; +} + +/* The 32x32-bit S-Box S1 +* Input: a 32-bit input. +* Output: a 32-bit output of S1 box. +* See section 3.3.1. +*/ + +u32 S1(u32 w) +{ + u8 r0=0, r1=0, r2=0, r3=0; + u8 srw0 = SR[ (u8)((w >> 24) & 0xff) ]; + u8 srw1 = SR[ (u8)((w >> 16) & 0xff) ]; + u8 srw2 = SR[ (u8)((w >> 8) & 0xff) ]; + u8 srw3 = SR[ (u8)((w) & 0xff) ]; + r0 = ( ( MULx( srw0 , 0x1b) ) ^ + ( srw1 ) ^ + ( srw2 ) ^ + ( (MULx( srw3, 0x1b)) ^ srw3 ) + ); + r1 = ( ( ( MULx( srw0 , 0x1b) ) ^ srw0 ) ^ + ( MULx(srw1, 0x1b) ) ^ + ( srw2 ) ^ + ( srw3 ) + ); + r2 = ( ( srw0 ) ^ + ( ( MULx( srw1 , 0x1b) ) ^ srw1 ) ^ + ( MULx(srw2, 0x1b) ) ^ + ( srw3 ) + ); + r3 = ( ( srw0 ) ^ + ( srw1 ) ^ + ( ( MULx( srw2 , 0x1b) ) ^ srw2 ) ^ + ( MULx( srw3, 0x1b) ) + ); + + return ( ( ((u32)r0) << 24 ) | ( ((u32)r1) << 16 ) | ( ((u32)r2) << 8 ) | + ( ((u32)r3) ) ); +} + +/* The 32x32-bit S-Box S2 +* Input: a 32-bit input. +* Output: a 32-bit output of S2 box. +* See section 3.3.2. +*/ + +u32 S2(u32 w) +{ + u8 r0=0, r1=0, r2=0, r3=0; + u8 sqw0 = SQ[ (u8)((w >> 24) & 0xff) ]; + u8 sqw1 = SQ[ (u8)((w >> 16) & 0xff) ]; + u8 sqw2 = SQ[ (u8)((w >> 8) & 0xff) ]; + u8 sqw3 = SQ[ (u8)((w) & 0xff) ]; + r0 = ( ( MULx( sqw0 , 0x69) ) ^ + ( sqw1 ) ^ + ( sqw2 ) ^ + ( (MULx( sqw3, 0x69)) ^ sqw3 ) + ); + r1 = ( ( ( MULx( sqw0 , 0x69) ) ^ sqw0 ) ^ + ( MULx(sqw1, 0x69) ) ^ + ( sqw2 ) ^ + ( sqw3 ) + ); + r2 = ( ( sqw0 ) ^ + ( ( MULx( sqw1 , 0x69) ) ^ sqw1 ) ^ + ( MULx(sqw2, 0x69) ) ^ + ( sqw3 ) + ); + r3 = ( ( sqw0 ) ^ + ( sqw1 ) ^ + ( ( MULx( sqw2 , 0x69) ) ^ sqw2 ) ^ + ( MULx( sqw3, 0x69) ) + ); + return ( ( ((u32)r0) << 24 ) | ( ((u32)r1) << 16 ) | ( ((u32)r2) << 8 ) | + ( ((u32)r3) ) ); +} + +/* Clocking LFSR in initialization mode. +* LFSR Registers S0 to S15 are updated as the LFSR receives a single clock. +* Input F: a 32-bit word comes from output of FSM. +* See section 3.4.4. +*/ + +void ClockLFSRInitializationMode(u32 F) +{ + u32 v = ( ( (LFSR_S0 << 8) & 0xffffff00 ) ^ + ( MULalpha( (u8)((LFSR_S0>>24) & 0xff) ) ) ^ + ( LFSR_S2 ) ^ + ( (LFSR_S11 >> 8) & 0x00ffffff ) ^ + ( DIValpha( (u8)( ( LFSR_S11) & 0xff ) ) ) ^ + ( F ) + ); + LFSR_S0 = LFSR_S1; + LFSR_S1 = LFSR_S2; + LFSR_S2 = LFSR_S3; + LFSR_S3 = LFSR_S4; + LFSR_S4 = LFSR_S5; + LFSR_S5 = LFSR_S6; + LFSR_S6 = LFSR_S7; + LFSR_S7 = LFSR_S8; + LFSR_S8 = LFSR_S9; + LFSR_S9 = LFSR_S10; + LFSR_S10 = LFSR_S11; + LFSR_S11 = LFSR_S12; + LFSR_S12 = LFSR_S13; + LFSR_S13 = LFSR_S14; + LFSR_S14 = LFSR_S15; + LFSR_S15 = v; +} + +/* Clocking LFSR in keystream mode. +* LFSR Registers S0 to S15 are updated as the LFSR receives a single clock. +* See section 3.4.5. +*/ + +void ClockLFSRKeyStreamMode() +{ + u32 v = ( ( (LFSR_S0 << 8) & 0xffffff00 ) ^ + ( MULalpha( (u8)((LFSR_S0>>24) & 0xff) ) ) ^ + ( LFSR_S2 ) ^ + ( (LFSR_S11 >> 8) & 0x00ffffff ) ^ + ( DIValpha( (u8)( ( LFSR_S11) & 0xff ) ) ) + ); + LFSR_S0 = LFSR_S1; + LFSR_S1 = LFSR_S2; + LFSR_S2 = LFSR_S3; + LFSR_S3 = LFSR_S4; + LFSR_S4 = LFSR_S5; + LFSR_S5 = LFSR_S6; + LFSR_S6 = LFSR_S7; + LFSR_S7 = LFSR_S8; + LFSR_S8 = LFSR_S9; + LFSR_S9 = LFSR_S10; + LFSR_S10 = LFSR_S11; + LFSR_S11 = LFSR_S12; + LFSR_S12 = LFSR_S13; + LFSR_S13 = LFSR_S14; + LFSR_S14 = LFSR_S15; + LFSR_S15 = v; +} + +/* Clocking FSM. +* Produces a 32-bit word F. +* Updates FSM registers R1, R2, R3. +* See Section 3.4.6. +*/ + +u32 ClockFSM() +{ + u32 F = ( ( LFSR_S15 + FSM_R1 ) & 0xffffffff ) ^ FSM_R2 ; + u32 r = ( FSM_R2 + ( FSM_R3 ^ LFSR_S5 ) ) & 0xffffffff ; + FSM_R3 = S2(FSM_R2); + FSM_R2 = S1(FSM_R1); + FSM_R1 = r; + return F; +} + +/* Initialization. +* Input k[4]: Four 32-bit words making up 128-bit key. +* Input IV[4]: Four 32-bit words making 128-bit initialization variable. +* Output: All the LFSRs and FSM are initialized for key generation. +* See Section 4.1. +*/ + +void snow3g_initialize(u32 k[4], u32 IV[4]) +{ + u8 i=0; + u32 F = 0x0; + LFSR_S15 = k[3] ^ IV[0]; + LFSR_S14 = k[2]; + LFSR_S13 = k[1]; + LFSR_S12 = k[0] ^ IV[1]; + LFSR_S11 = k[3] ^ 0xffffffff; + LFSR_S10 = k[2] ^ 0xffffffff ^ IV[2]; + LFSR_S9 = k[1] ^ 0xffffffff ^ IV[3]; + LFSR_S8 = k[0] ^ 0xffffffff; + LFSR_S7 = k[3]; + LFSR_S6 = k[2]; + LFSR_S5 = k[1]; + LFSR_S4 = k[0]; + LFSR_S3 = k[3] ^ 0xffffffff; + LFSR_S2 = k[2] ^ 0xffffffff; + LFSR_S1 = k[1] ^ 0xffffffff; + LFSR_S0 = k[0] ^ 0xffffffff; + FSM_R1 = 0x0; + FSM_R2 = 0x0; + FSM_R3 = 0x0; + for(i=0;i<32;i++) + { + F = ClockFSM(); + ClockLFSRInitializationMode(F); + } +} + +/* Generation of Keystream. +* input n: number of 32-bit words of keystream. +* input z: space for the generated keystream, assumes +* memory is allocated already. +* output: generated keystream which is filled in z +* See section 4.2. +*/ + +void snow3g_generate_keystream(u32 n, u32 *ks) +{ + u32 t = 0; + u32 F = 0x0; + ClockFSM(); /* Clock FSM once. Discard the output. */ + ClockLFSRKeyStreamMode(); /* Clock LFSR in keystream mode once. */ + for ( t=0; t> 24) & 0xff; + data[4*i+1] ^= (u8) (KS[i] >> 16) & 0xff; + data[4*i+2] ^= (u8) (KS[i] >> 8) & 0xff; + data[4*i+3] ^= (u8) (KS[i] ) & 0xff; + } + + free(KS); + + /* zero last bits of data in case its length is not byte-aligned + this is an addition to the C reference code, which did not handle it */ + if (lastbits) + data[length/8] &= 256 - (1<>i ) & 0x1 ) + result ^= MUL64xPOW(V,i,c); + } + return result; +} + +/* mask8bit. + * Input n: an integer in 1-7. + * Output : an 8 bit mask. + * Prepares an 8 bit mask with required number of 1 bits on the MSB side. + */ +u8 mask8bit(int n) +{ + return 0xFF ^ ((1<<(8-n)) - 1); +} + +/* f9. + * Input key: 128 bit Integrity Key. + * Input count:32-bit Count, Frame dependent input. + * Input fresh: 32-bit Random number. + * Input dir:1 bit, direction of transmission (in the LSB). + * Input data: length number of bits, input bit stream. + * Input length: 64 bit Length, i.e., the number of bits to be MAC'd. + * Output : 32 bit block used as MAC + * Generates 32-bit MAC using UIA2 algorithm as defined in Section 4. + */ +u8* snow3g_f9( u8* key, u32 count, u32 fresh, u32 dir, u8 *data, u64 length) +{ + u32 K[4],IV[4], z[5]; + u32 i=0, D; + static u8 MAC_I[4] = {0,0,0,0}; /* static memory for the result */ + u64 EVAL; + u64 V; + u64 P; + u64 Q; + u64 c; + + u64 M_D_2; + int rem_bits = 0; + + /* Load the Integrity Key for SNOW3G initialization as in section 4.4. */ + for (i=0; i<4; i++) + K[3-i] = (key[4*i] << 24) ^ (key[4*i+1] << 16) ^ + (key[4*i+2] << 8) ^ (key[4*i+3]); + + /* Prepare the Initialization Vector (IV) for SNOW3G initialization as + in section 4.4. */ + IV[3] = count; + IV[2] = fresh; + IV[1] = count ^ ( dir << 31 ) ; + IV[0] = fresh ^ (dir << 15); + + z[0] = z[1] = z[2] = z[3] = z[4] = 0; + + /* Run SNOW 3G to produce 5 keystream words z_1, z_2, z_3, z_4 and z_5. */ + snow3g_initialize(K, IV); + snow3g_generate_keystream(5, z); + + P = (u64)z[0] << 32 | (u64)z[1]; + Q = (u64)z[2] << 32 | (u64)z[3]; + + /* Calculation */ + if ((length % 64) == 0) + D = (length>>6) + 1; + else + D = (length>>6) + 2; + EVAL = 0; + c = 0x1b; + + /* for 0 <= i <= D-3 */ + for (i=0; i 7) + { + M_D_2 |= (u64)data[8*(D-2)+i] << (8*(7-i)); + rem_bits -= 8; + i++; + } + if (rem_bits > 0) + M_D_2 |= (u64)(data[8*(D-2)+i] & mask8bit(rem_bits)) << (8*(7-i)); + + V = EVAL ^ M_D_2; + EVAL = MUL64(V,P,c); + + /* for D-1 */ + EVAL ^= length; + + /* Multiply by Q */ + EVAL = MUL64(EVAL,Q,c); + + /* XOR with z_5: this is a modification to the reference C code, + which forgot to XOR z[5] */ + for (i=0; i<4; i++) + /* + MAC_I[i] = (mac32 >> (8*(3-i))) & 0xff; + */ + MAC_I[i] = ((EVAL >> (56-(i*8))) ^ (z[4] >> (24-(i*8)))) & 0xff; + + return MAC_I; +} diff --git a/lib/src/common/task_dispatcher.cc b/lib/src/common/task_dispatcher.cc new file mode 100644 index 000000000..df27a023a --- /dev/null +++ b/lib/src/common/task_dispatcher.cc @@ -0,0 +1,75 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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/task_dispatcher.h" +#include + +namespace srslte { + +task_dispatcher::task_dispatcher(uint32_t max_pending_tasks) +{ + pthread_cond_init(&cvar, NULL); + pthread_mutex_init(&mutex, NULL); +} + +task_dispatcher::~task_dispatcher() +{ + running = false; + pthread_cond_signal(&cvar); + wait_thread_finish(); + pthread_cond_destroy(&cvar); + pthread_mutex_destroy(&mutex); +} + +void task_dispatcher::push_task(uint32_t task_code) +{ + pthread_mutex_lock(&mutex); + pending_tasks.push(task_code); + pthread_cond_signal(&cvar); + pthread_mutex_unlock(&mutex); +} + +void task_dispatcher::run_thread() +{ + running = true; + while(running) { + uint32_t task = 0; + pthread_mutex_lock(&mutex); + while(pending_tasks.empty()) { + pthread_cond_wait(&cvar, &mutex); + } + task = (uint32_t) pending_tasks.front(); + pending_tasks.pop(); + pthread_mutex_unlock(&mutex); + if (running) { + run_task(task); + } + } +} + + +} \ No newline at end of file diff --git a/lib/src/common/thread_pool.cc b/lib/src/common/thread_pool.cc new file mode 100644 index 000000000..6f4fa5d8b --- /dev/null +++ b/lib/src/common/thread_pool.cc @@ -0,0 +1,289 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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 +#include +#include "srslte/common/thread_pool.h" + +#define DEBUG 0 +#define debug_thread(fmt, ...) do { if(DEBUG) printf(fmt, __VA_ARGS__); } while(0) + +#define USE_QUEUE + +namespace srslte { + + +void thread_pool::worker::setup(uint32_t id, thread_pool *parent, uint32_t prio, uint32_t mask) +{ + my_id = id; + my_parent = parent; + if(mask == 255) + { + start(prio); + } + else + { + start_cpu_mask(prio,mask); + } + +} + +void thread_pool::worker::run_thread() +{ + running = true; + while(running) { + wait_to_start(); + if (running) { + work_imp(); + finished(); + } + } +} + +uint32_t thread_pool::worker::get_id() +{ + return my_id; +} + +void thread_pool::worker::stop() +{ + running = false; + pthread_cond_signal(&my_parent->cvar[my_id]); + wait_thread_finish(); +} + +thread_pool::thread_pool(uint32_t max_workers_) : + workers(max_workers_), + status(max_workers_), + cvar(max_workers_), + mutex(max_workers_) + +{ + max_workers = max_workers_; + for (uint32_t i=0;i= nof_workers) { + nof_workers = id+1; + } + pthread_mutex_lock(&mutex_queue); + workers[id] = obj; + available_workers.push(obj); + obj->setup(id, this, prio, mask); + pthread_cond_signal(&cvar_queue); + pthread_mutex_unlock(&mutex_queue); + } +} + +void thread_pool::stop() +{ + /* Stop any thread waiting for available worker */ + running = false; + + /* Now stop all workers */ + for (uint32_t i=0;istop(); + // Need to call start to wake it up + start_worker(i); + workers[i]->wait_thread_finish(); + } + pthread_cond_destroy(&cvar[i]); + pthread_mutex_destroy(&mutex[i]); + } + pthread_cond_destroy(&cvar_queue); + pthread_mutex_destroy(&mutex_queue); +} + + +void thread_pool::worker::release() +{ + finished(); +} + +void thread_pool::worker::wait_to_start() +{ + + debug_thread("wait_to_start() id=%d, status=%d, enter\n", my_id, my_parent->status[my_id]); + + pthread_mutex_lock(&my_parent->mutex[my_id]); + while(my_parent->status[my_id] != START_WORK && running) { + pthread_cond_wait(&my_parent->cvar[my_id], &my_parent->mutex[my_id]); + } + my_parent->status[my_id] = WORKING; + pthread_mutex_unlock(&my_parent->mutex[my_id]); + + debug_thread("wait_to_start() id=%d, status=%d, exit\n", my_id, my_parent->status[my_id]); +} + +void thread_pool::worker::finished() +{ +#ifdef USE_QUEUE + pthread_mutex_lock(&my_parent->mutex[my_id]); + my_parent->status[my_id] = IDLE; + pthread_mutex_unlock(&my_parent->mutex[my_id]); + + pthread_mutex_lock(&my_parent->mutex_queue); + pthread_cond_signal(&my_parent->cvar_queue); + pthread_mutex_unlock(&my_parent->mutex_queue); +#else + pthread_mutex_lock(&my_parent->mutex[my_id]); + my_parent->status[my_id] = IDLE; + pthread_cond_signal(&my_parent->cvar[my_id]); + pthread_mutex_unlock(&my_parent->mutex[my_id]); +#endif +} + + +thread_pool::worker* thread_pool::wait_worker() +{ + return wait_worker(0); +} + +bool thread_pool::find_finished_worker(uint32_t tti, uint32_t *id) { + for(uint32_t i=0;i +#include +#include +#include +#include +#include + +#include "srslte/common/threads.h" + +bool threads_new_rt(pthread_t *thread, void *(*start_routine) (void*), void *arg) { + return threads_new_rt_prio(thread, start_routine, arg, -1); +} + +bool threads_new_rt_prio(pthread_t *thread, void *(*start_routine) (void*), void *arg, int prio_offset) { + return threads_new_rt_cpu(thread, start_routine, arg, -1, prio_offset); +} + +bool threads_new_rt_mask(pthread_t *thread, void *(*start_routine) (void*), void *arg,int mask, int prio_offset){ +return threads_new_rt_cpu(thread, start_routine, arg, mask*100, prio_offset);// we multiply mask by 100 to distinguish it from a single cpu core id +} + +bool threads_new_rt_cpu(pthread_t *thread, void *(*start_routine) (void*), void *arg, int cpu, int prio_offset) { + bool ret = false; + + pthread_attr_t attr; + struct sched_param param; + cpu_set_t cpuset; + if (prio_offset >= 0) { + param.sched_priority = sched_get_priority_max(SCHED_FIFO) - prio_offset; + pthread_attr_init(&attr); + if (pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED)) { + perror("pthread_attr_setinheritsched"); + } + if (pthread_attr_setschedpolicy(&attr, SCHED_FIFO)) { + perror("pthread_attr_setschedpolicy"); + } + if (pthread_attr_setschedparam(&attr, ¶m)) { + perror("pthread_attr_setschedparam"); + fprintf(stderr, "Error not enough privileges to set Scheduling priority\n"); + } + } + if(cpu > 0) { + if(cpu > 50) { + int mask; + mask = cpu/100; + + CPU_ZERO(&cpuset); + for(int i = 0; i < 8;i++){ + if(((mask >> i) & 0x01) == 1){ + CPU_SET((size_t) i , &cpuset); + } + } + } else { + CPU_ZERO(&cpuset); + CPU_SET((size_t) cpu, &cpuset); + } + + if(pthread_attr_setaffinity_np(&attr, sizeof(cpu_set_t), &cpuset)) { + perror("pthread_attr_setaffinity_np"); + } + } + + int err = pthread_create(thread, prio_offset >= 0 ? &attr : NULL, start_routine, arg); + if (err) { + if (EPERM == err) { + perror("Warning: Failed to create thread with real-time priority. Creating it with normal priority"); + err = pthread_create(thread, NULL, start_routine, arg); + if (err) { + perror("pthread_create"); + } else { + ret = true; + } + } else { + perror("pthread_create"); + } + } else { + ret = true; + } + if (prio_offset >= 0) { + pthread_attr_destroy(&attr); + } + return ret; +} + +void threads_print_self() { + pthread_t thread; + cpu_set_t cpuset; + struct sched_param param; + int policy; + const char *p; + int s,j; + + thread = pthread_self(); + + s = pthread_getaffinity_np(thread, sizeof(cpu_set_t), &cpuset); + if (s != 0) { + printf("error pthread_getaffinity_np: %s\n",strerror(s)); + } + + printf("Set returned by pthread_getaffinity_np() contained:\n"); + for (j = 0; j < CPU_SETSIZE; j++) { + if (CPU_ISSET(j, &cpuset)) { + printf(" CPU %d\n", j); + } + } + + s = pthread_getschedparam(thread, &policy, ¶m); + if (s != 0) { + printf("error pthread_getaffinity_np: %s\n", strerror(s)); + } + + switch(policy) { + case SCHED_FIFO: + p = "SCHED_FIFO"; + break; + case SCHED_RR: + p = "SCHED_RR"; + break; + default: + p = "Other"; + break; + } + + printf("Sched policy is %s. Priority is %d\n",p,param.sched_priority); +} diff --git a/lib/src/common/tti_sync_cv.cc b/lib/src/common/tti_sync_cv.cc new file mode 100644 index 000000000..a3fc7ce4b --- /dev/null +++ b/lib/src/common/tti_sync_cv.cc @@ -0,0 +1,78 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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 + +#include "srslte/common/tti_sync_cv.h" + + +namespace srslte { + + tti_sync_cv::tti_sync_cv(uint32_t modulus): tti_sync(modulus) + { + pthread_mutex_init(&mutex, NULL); + pthread_cond_init(&cond, NULL); + } + + tti_sync_cv::~tti_sync_cv() + { + pthread_cond_destroy(&cond); + pthread_mutex_destroy(&mutex); + } + + uint32_t tti_sync_cv::wait() + { + pthread_mutex_lock(&mutex); + while(wait_condition()) { + pthread_cond_wait(&cond, &mutex); + } + uint32_t x = consumer_cntr; + increase_consumer(); + pthread_mutex_unlock(&mutex); + return x; + } + + void tti_sync_cv::resync() + { + consumer_cntr = producer_cntr; + } + + void tti_sync_cv::set_producer_cntr(uint32_t producer_cntr) + { + pthread_mutex_lock(&mutex); + init_counters(producer_cntr); + pthread_cond_signal(&cond); + pthread_mutex_unlock(&mutex); + } + + void tti_sync_cv::increase() + { + pthread_mutex_lock(&mutex); + increase_producer(); + pthread_cond_signal(&cond); + pthread_mutex_unlock(&mutex); + } +} diff --git a/srslte/lib/version.c b/lib/src/common/version.c similarity index 100% rename from srslte/lib/version.c rename to lib/src/common/version.c diff --git a/srslte/lib/CMakeLists.txt b/lib/src/phy/CMakeLists.txt similarity index 54% rename from srslte/lib/CMakeLists.txt rename to lib/src/phy/CMakeLists.txt index e94a4dd8b..47f72d2dc 100644 --- a/srslte/lib/CMakeLists.txt +++ b/lib/src/phy/CMakeLists.txt @@ -1,7 +1,7 @@ # -# Copyright 2013-2015 Software Radio Systems Limited +# Copyright 2013-2017 Software Radio Systems Limited # -# This file is part of the srsLTE library. +# 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 @@ -36,10 +36,9 @@ add_subdirectory(scrambling) add_subdirectory(ue) add_subdirectory(enb) -set(srslte_srcs version.c - $ +set(srslte_srcs $ $ - $ + $ $ $ $ @@ -55,48 +54,77 @@ set(srslte_srcs version.c $ ) -add_library(srslte SHARED ${srslte_srcs}) -target_link_libraries(srslte pthread m) -set_target_properties(srslte PROPERTIES - VERSION ${SRSLTE_VERSION_MAJOR}.${SRSLTE_VERSION_MINOR}) +add_library(srslte_phy SHARED ${srslte_srcs}) +target_link_libraries(srslte_phy pthread m) +set_target_properties(srslte_phy PROPERTIES + VERSION ${SRSLTE_VERSION_MAJOR}.${SRSLTE_VERSION_MINOR}) if(NOT DisableMEX) - add_library(srslte_static STATIC ${srslte_srcs}) + add_library(srslte_phy_static STATIC ${srslte_srcs}) endif(NOT DisableMEX) +find_package(MKL) if(MKL_FOUND) - if(StaticMKL) - target_link_libraries(srslte ${MKL_STATIC_LIBRARIES}) - if(NOT DisableMEX) - target_link_libraries(srslte_static ${MKL_STATIC_LIBRARIES}) - endif(NOT DisableMEX) - else(StaticMKL) - target_link_libraries(srslte ${MKL_LIBRARIES}) - if(NOT DisableMEX) - target_link_libraries(srslte_static ${MKL_LIBRARIES}) - endif(NOT DisableMEX) - endif(StaticMKL) + include_directories(${MKL_INCLUDE_DIRS}) + link_directories(${MKL_LIBRARY_DIRS}) else(MKL_FOUND) - target_link_libraries(srslte ${FFTW3F_LIBRARIES}) + find_package(FFTW3F REQUIRED) + if(FFTW3F_FOUND) + include_directories(${FFTW3F_INCLUDE_DIRS}) + link_directories(${FFTW3F_LIBRARY_DIRS}) + endif(FFTW3F_FOUND) +endif(MKL_FOUND) + + +if(MKL_FOUND) + if(STATIC_MKL) + target_link_libraries(srslte_phy ${MKL_STATIC_LIBRARIES}) + if(NOT DisableMEX) + target_link_libraries(srslte_phy_static ${MKL_STATIC_LIBRARIES}) + endif(NOT DisableMEX) + else(STATIC_MKL) + target_link_libraries(srslte_phy ${MKL_LIBRARIES}) + if(NOT DisableMEX) + target_link_libraries(srslte_phy_static ${MKL_LIBRARIES}) + endif(NOT DisableMEX) + endif(STATIC_MKL) +else(MKL_FOUND) + target_link_libraries(srslte_phy ${FFTW3F_LIBRARIES}) if(NOT DisableMEX) - target_link_libraries(srslte_static ${FFTW3F_LIBRARIES}) + target_link_libraries(srslte_phy_static ${FFTW3F_LIBRARIES}) endif(NOT DisableMEX) endif(MKL_FOUND) ## This linkage is required for the examples and tests only if(RF_FOUND) - target_link_libraries(srslte srslte_rf) + target_link_libraries(srslte_phy srslte_rf) if(UHD_FOUND) - target_link_libraries(srslte ${UHD_LIBRARIES}) + target_link_libraries(srslte_phy ${UHD_LIBRARIES}) endif(UHD_FOUND) if(BLADERF_FOUND) - target_link_libraries(srslte ${BLADERF_LIBRARIES}) + target_link_libraries(srslte_phy ${BLADERF_LIBRARIES}) endif(BLADERF_FOUND) + + if(LIMESDR_FOUND) + target_link_libraries(srslte_phy ${LIMESDR_LIBRARIES}) + endif(LIMESDR_FOUND) + + if(SOAPYSDR_FOUND) + target_link_libraries(srslte_phy ${SOAPYSDR_LIBRARIES}) + endif(SOAPYSDR_FOUND) + endif(RF_FOUND) -INSTALL(TARGETS srslte DESTINATION ${LIBRARY_DIR}) -SRSLTE_SET_PIC(srslte) +if(VOLK_FOUND) + target_link_libraries(srslte_phy ${VOLK_LIBRARIES}) + if(NOT DisableMEX) + target_link_libraries(srslte_phy_static ${VOLK_LIBRARIES}) + endif(NOT DisableMEX) +endif(VOLK_FOUND) + +install(TARGETS srslte_phy DESTINATION ${LIBRARY_DIR}) +SRSLTE_SET_PIC(srslte_phy) diff --git a/srslte/lib/agc/CMakeLists.txt b/lib/src/phy/agc/CMakeLists.txt similarity index 88% rename from srslte/lib/agc/CMakeLists.txt rename to lib/src/phy/agc/CMakeLists.txt index c97f5d5d2..79a7a1dcb 100644 --- a/srslte/lib/agc/CMakeLists.txt +++ b/lib/src/phy/agc/CMakeLists.txt @@ -1,7 +1,7 @@ # -# Copyright 2013-2015 Software Radio Systems Limited +# Copyright 2013-2017 Software Radio Systems Limited # -# This file is part of the srsLTE library. +# 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 diff --git a/srslte/lib/agc/agc.c b/lib/src/phy/agc/agc.c similarity index 97% rename from srslte/lib/agc/agc.c rename to lib/src/phy/agc/agc.c index 3d971427a..3134de729 100644 --- a/srslte/lib/agc/agc.c +++ b/lib/src/phy/agc/agc.c @@ -31,11 +31,11 @@ #include #include -#include "srslte/utils/debug.h" +#include "srslte/phy/utils/debug.h" -#include "srslte/agc/agc.h" -#include "srslte/utils/vector.h" -#include "srslte/utils/debug.h" +#include "srslte/phy/agc/agc.h" +#include "srslte/phy/utils/vector.h" +#include "srslte/phy/utils/debug.h" int srslte_agc_init (srslte_agc_t *q, srslte_agc_mode_t mode) { return srslte_agc_init_acc(q, mode, 0); diff --git a/srslte/lib/ch_estimation/CMakeLists.txt b/lib/src/phy/ch_estimation/CMakeLists.txt similarity index 89% rename from srslte/lib/ch_estimation/CMakeLists.txt rename to lib/src/phy/ch_estimation/CMakeLists.txt index 24dbeed36..067a41d69 100644 --- a/srslte/lib/ch_estimation/CMakeLists.txt +++ b/lib/src/phy/ch_estimation/CMakeLists.txt @@ -1,7 +1,7 @@ # -# Copyright 2013-2015 Software Radio Systems Limited +# Copyright 2013-2017 Software Radio Systems Limited # -# This file is part of the srsLTE library. +# 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 diff --git a/srslte/lib/ch_estimation/chest_common.c b/lib/src/phy/ch_estimation/chest_common.c similarity index 94% rename from srslte/lib/ch_estimation/chest_common.c rename to lib/src/phy/ch_estimation/chest_common.c index dfb92f974..2ef80130d 100644 --- a/srslte/lib/ch_estimation/chest_common.c +++ b/lib/src/phy/ch_estimation/chest_common.c @@ -33,9 +33,9 @@ #include #include -#include "srslte/ch_estimation/chest_common.h" -#include "srslte/utils/vector.h" -#include "srslte/utils/convolution.h" +#include "srslte/phy/ch_estimation/chest_common.h" +#include "srslte/phy/utils/vector.h" +#include "srslte/phy/utils/convolution.h" void srslte_chest_set_triangle_filter(float *fil, int filter_len) { diff --git a/srslte/lib/ch_estimation/chest_dl.c b/lib/src/phy/ch_estimation/chest_dl.c similarity index 98% rename from srslte/lib/ch_estimation/chest_dl.c rename to lib/src/phy/ch_estimation/chest_dl.c index f198344f0..690721b3c 100644 --- a/srslte/lib/ch_estimation/chest_dl.c +++ b/lib/src/phy/ch_estimation/chest_dl.c @@ -35,9 +35,9 @@ #include "srslte/config.h" -#include "srslte/ch_estimation/chest_dl.h" -#include "srslte/utils/vector.h" -#include "srslte/utils/convolution.h" +#include "srslte/phy/ch_estimation/chest_dl.h" +#include "srslte/phy/utils/vector.h" +#include "srslte/phy/utils/convolution.h" //#define DEFAULT_FILTER_LEN 3 @@ -418,10 +418,10 @@ float srslte_chest_dl_get_rsrq(srslte_chest_dl_t *q) { } float srslte_chest_dl_get_rsrp(srslte_chest_dl_t *q) { - // return sum of power received from all tx ports + // Note: use only port 0 but average across antennas float n = 0; for (int i=0;ilast_nof_antennas;i++) { - n += srslte_vec_acc_ff(q->rsrp[i], q->cell.nof_ports); + n += q->rsrp[i][0]; } return n/q->last_nof_antennas; } diff --git a/srslte/lib/ch_estimation/chest_ul.c b/lib/src/phy/ch_estimation/chest_ul.c similarity index 98% rename from srslte/lib/ch_estimation/chest_ul.c rename to lib/src/phy/ch_estimation/chest_ul.c index 9f86b69ee..9996fc9c3 100644 --- a/srslte/lib/ch_estimation/chest_ul.c +++ b/lib/src/phy/ch_estimation/chest_ul.c @@ -35,10 +35,10 @@ #include "srslte/config.h" -#include "srslte/dft/dft_precoding.h" -#include "srslte/ch_estimation/chest_ul.h" -#include "srslte/utils/vector.h" -#include "srslte/utils/convolution.h" +#include "srslte/phy/dft/dft_precoding.h" +#include "srslte/phy/ch_estimation/chest_ul.h" +#include "srslte/phy/utils/vector.h" +#include "srslte/phy/utils/convolution.h" #define NOF_REFS_SYM (q->cell.nof_prb*SRSLTE_NRE) #define NOF_REFS_SF (NOF_REFS_SYM*2) // 2 reference symbols per subframe diff --git a/srslte/lib/ch_estimation/refsignal_dl.c b/lib/src/phy/ch_estimation/refsignal_dl.c similarity index 97% rename from srslte/lib/ch_estimation/refsignal_dl.c rename to lib/src/phy/ch_estimation/refsignal_dl.c index c0d6767a2..ec0f0b4e0 100644 --- a/srslte/lib/ch_estimation/refsignal_dl.c +++ b/lib/src/phy/ch_estimation/refsignal_dl.c @@ -31,11 +31,11 @@ #include #include -#include "srslte/common/phy_common.h" -#include "srslte/ch_estimation/refsignal_dl.h" -#include "srslte/utils/vector.h" -#include "srslte/utils/debug.h" -#include "srslte/common/sequence.h" +#include "srslte/phy/common/phy_common.h" +#include "srslte/phy/ch_estimation/refsignal_dl.h" +#include "srslte/phy/utils/vector.h" +#include "srslte/phy/utils/debug.h" +#include "srslte/phy/common/sequence.h" uint32_t srslte_refsignal_cs_v(uint32_t port_id, uint32_t ref_symbol_idx) { diff --git a/srslte/lib/ch_estimation/refsignal_ul.c b/lib/src/phy/ch_estimation/refsignal_ul.c similarity index 99% rename from srslte/lib/ch_estimation/refsignal_ul.c rename to lib/src/phy/ch_estimation/refsignal_ul.c index 143bf53f4..609ef52d0 100644 --- a/srslte/lib/ch_estimation/refsignal_ul.c +++ b/lib/src/phy/ch_estimation/refsignal_ul.c @@ -30,12 +30,12 @@ #include #include -#include "srslte/common/phy_common.h" -#include "srslte/ch_estimation/refsignal_ul.h" -#include "srslte/utils/vector.h" -#include "srslte/utils/debug.h" -#include "srslte/common/sequence.h" -#include "srslte/dft/dft_precoding.h" +#include "srslte/phy/common/phy_common.h" +#include "srslte/phy/ch_estimation/refsignal_ul.h" +#include "srslte/phy/utils/vector.h" +#include "srslte/phy/utils/debug.h" +#include "srslte/phy/common/sequence.h" +#include "srslte/phy/dft/dft_precoding.h" #include "ul_rs_tables.h" diff --git a/srslte/lib/ch_estimation/test/CMakeLists.txt b/lib/src/phy/ch_estimation/test/CMakeLists.txt similarity index 87% rename from srslte/lib/ch_estimation/test/CMakeLists.txt rename to lib/src/phy/ch_estimation/test/CMakeLists.txt index 84b66b3aa..fd293c273 100644 --- a/srslte/lib/ch_estimation/test/CMakeLists.txt +++ b/lib/src/phy/ch_estimation/test/CMakeLists.txt @@ -1,7 +1,7 @@ # -# Copyright 2013-2015 Software Radio Systems Limited +# Copyright 2013-2017 Software Radio Systems Limited # -# This file is part of the srsLTE library. +# 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 @@ -23,7 +23,7 @@ ######################################################################## add_executable(chest_test_dl chest_test_dl.c) -target_link_libraries(chest_test_dl srslte) +target_link_libraries(chest_test_dl srslte_phy) add_test(chest_test_dl_cellid0 chest_test_dl -c 0) add_test(chest_test_dl_cellid1 chest_test_dl -c 1) @@ -39,10 +39,10 @@ add_test(chest_test_dl_cellid2 chest_test_dl -c 2 -r 50) ######################################################################## add_executable(chest_test_ul chest_test_ul.c) -target_link_libraries(chest_test_ul srslte) +target_link_libraries(chest_test_ul srslte_phy) add_executable(refsignal_ul_test_all refsignal_ul_test.c) -target_link_libraries(refsignal_ul_test_all srslte) +target_link_libraries(refsignal_ul_test_all srslte_phy) add_test(chest_test_ul_cellid0 chest_test_ul -c 0 -r 50) add_test(chest_test_ul_cellid1 chest_test_ul -c 1 -r 50) diff --git a/srslte/lib/ch_estimation/test/chest_test_dl.c b/lib/src/phy/ch_estimation/test/chest_test_dl.c similarity index 100% rename from srslte/lib/ch_estimation/test/chest_test_dl.c rename to lib/src/phy/ch_estimation/test/chest_test_dl.c diff --git a/srslte/lib/ch_estimation/test/chest_test_dl_mex.c b/lib/src/phy/ch_estimation/test/chest_test_dl_mex.c similarity index 100% rename from srslte/lib/ch_estimation/test/chest_test_dl_mex.c rename to lib/src/phy/ch_estimation/test/chest_test_dl_mex.c diff --git a/srslte/lib/ch_estimation/test/chest_test_dl_mex.mexa64 b/lib/src/phy/ch_estimation/test/chest_test_dl_mex.mexa64 similarity index 100% rename from srslte/lib/ch_estimation/test/chest_test_dl_mex.mexa64 rename to lib/src/phy/ch_estimation/test/chest_test_dl_mex.mexa64 diff --git a/srslte/lib/ch_estimation/test/chest_test_ul.c b/lib/src/phy/ch_estimation/test/chest_test_ul.c similarity index 100% rename from srslte/lib/ch_estimation/test/chest_test_ul.c rename to lib/src/phy/ch_estimation/test/chest_test_ul.c diff --git a/srslte/lib/ch_estimation/test/chest_test_ul_mex.c b/lib/src/phy/ch_estimation/test/chest_test_ul_mex.c similarity index 100% rename from srslte/lib/ch_estimation/test/chest_test_ul_mex.c rename to lib/src/phy/ch_estimation/test/chest_test_ul_mex.c diff --git a/srslte/lib/ch_estimation/test/refsignal_pusch_mex.c b/lib/src/phy/ch_estimation/test/refsignal_pusch_mex.c similarity index 100% rename from srslte/lib/ch_estimation/test/refsignal_pusch_mex.c rename to lib/src/phy/ch_estimation/test/refsignal_pusch_mex.c diff --git a/srslte/lib/ch_estimation/test/refsignal_srs_mex.c b/lib/src/phy/ch_estimation/test/refsignal_srs_mex.c similarity index 100% rename from srslte/lib/ch_estimation/test/refsignal_srs_mex.c rename to lib/src/phy/ch_estimation/test/refsignal_srs_mex.c diff --git a/srslte/lib/ch_estimation/test/refsignal_ul_test.c b/lib/src/phy/ch_estimation/test/refsignal_ul_test.c similarity index 100% rename from srslte/lib/ch_estimation/test/refsignal_ul_test.c rename to lib/src/phy/ch_estimation/test/refsignal_ul_test.c diff --git a/srslte/lib/ch_estimation/ul_rs_tables.h b/lib/src/phy/ch_estimation/ul_rs_tables.h similarity index 100% rename from srslte/lib/ch_estimation/ul_rs_tables.h rename to lib/src/phy/ch_estimation/ul_rs_tables.h diff --git a/srslte/lib/channel/CMakeLists.txt b/lib/src/phy/channel/CMakeLists.txt similarity index 89% rename from srslte/lib/channel/CMakeLists.txt rename to lib/src/phy/channel/CMakeLists.txt index a14a67c89..19f8fe93e 100644 --- a/srslte/lib/channel/CMakeLists.txt +++ b/lib/src/phy/channel/CMakeLists.txt @@ -1,7 +1,7 @@ # -# Copyright 2013-2015 Software Radio Systems Limited +# Copyright 2013-2017 Software Radio Systems Limited # -# This file is part of the srsLTE library. +# 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 diff --git a/srslte/lib/channel/ch_awgn.c b/lib/src/phy/channel/ch_awgn.c similarity index 97% rename from srslte/lib/channel/ch_awgn.c rename to lib/src/phy/channel/ch_awgn.c index 25a8db7f1..d88a91abc 100644 --- a/srslte/lib/channel/ch_awgn.c +++ b/lib/src/phy/channel/ch_awgn.c @@ -31,7 +31,7 @@ #include #include "gauss.h" -#include "srslte/channel/ch_awgn.h" +#include "srslte/phy/channel/ch_awgn.h" float srslte_ch_awgn_get_variance(float ebno_db, float rate) { float esno_db = ebno_db + 10 * log10f(rate); diff --git a/srslte/lib/channel/gauss.c b/lib/src/phy/channel/gauss.c similarity index 100% rename from srslte/lib/channel/gauss.c rename to lib/src/phy/channel/gauss.c diff --git a/srslte/lib/channel/gauss.h b/lib/src/phy/channel/gauss.h similarity index 100% rename from srslte/lib/channel/gauss.h rename to lib/src/phy/channel/gauss.h diff --git a/lib/src/phy/common/CMakeLists.txt b/lib/src/phy/common/CMakeLists.txt new file mode 100644 index 000000000..6b282e7d6 --- /dev/null +++ b/lib/src/phy/common/CMakeLists.txt @@ -0,0 +1,23 @@ +# +# Copyright 2013-2017 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(GLOB SOURCES "*.c") +add_library(srslte_phy_common OBJECT ${SOURCES}) +SRSLTE_SET_PIC(srslte_phy_common) diff --git a/srslte/lib/common/phy_common.c b/lib/src/phy/common/phy_common.c similarity index 99% rename from srslte/lib/common/phy_common.c rename to lib/src/phy/common/phy_common.c index e4a7d8d20..8386ae18b 100644 --- a/srslte/lib/common/phy_common.c +++ b/lib/src/phy/common/phy_common.c @@ -31,8 +31,8 @@ #include #include -#include "srslte/common/phy_common.h" -#include "srslte/common/sequence.h" +#include "srslte/phy/common/phy_common.h" +#include "srslte/phy/common/sequence.h" #ifdef FORCE_STANDARD_RATE static bool use_standard_rates = true; diff --git a/srslte/lib/common/sequence.c b/lib/src/phy/common/sequence.c similarity index 96% rename from srslte/lib/common/sequence.c rename to lib/src/phy/common/sequence.c index 5b2af5351..2a863bcee 100644 --- a/srslte/lib/common/sequence.c +++ b/lib/src/phy/common/sequence.c @@ -29,9 +29,9 @@ #include #include -#include "srslte/common/sequence.h" -#include "srslte/utils/vector.h" -#include "srslte/utils/bit.h" +#include "srslte/phy/common/sequence.h" +#include "srslte/phy/utils/vector.h" +#include "srslte/phy/utils/bit.h" #define Nc 1600 diff --git a/srslte/lib/common/timestamp.c b/lib/src/phy/common/timestamp.c similarity index 98% rename from srslte/lib/common/timestamp.c rename to lib/src/phy/common/timestamp.c index ffa028ce5..8c2fbe39f 100644 --- a/srslte/lib/common/timestamp.c +++ b/lib/src/phy/common/timestamp.c @@ -24,7 +24,7 @@ * */ -#include "srslte/common/timestamp.h" +#include "srslte/phy/common/timestamp.h" #include "math.h" int srslte_timestamp_init(srslte_timestamp_t *t, time_t full_secs, double frac_secs){ diff --git a/srslte/lib/dft/CMakeLists.txt b/lib/src/phy/dft/CMakeLists.txt similarity index 89% rename from srslte/lib/dft/CMakeLists.txt rename to lib/src/phy/dft/CMakeLists.txt index 036e802ee..516ff817f 100644 --- a/srslte/lib/dft/CMakeLists.txt +++ b/lib/src/phy/dft/CMakeLists.txt @@ -1,7 +1,7 @@ # -# Copyright 2013-2015 Software Radio Systems Limited +# Copyright 2013-2017 Software Radio Systems Limited # -# This file is part of the srsLTE library. +# 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 diff --git a/srslte/lib/dft/dft_fftw.c b/lib/src/phy/dft/dft_fftw.c similarity index 98% rename from srslte/lib/dft/dft_fftw.c rename to lib/src/phy/dft/dft_fftw.c index d6dc55b84..347e04547 100644 --- a/srslte/lib/dft/dft_fftw.c +++ b/lib/src/phy/dft/dft_fftw.c @@ -30,8 +30,8 @@ #include #include -#include "srslte/dft/dft.h" -#include "srslte/utils/vector.h" +#include "srslte/phy/dft/dft.h" +#include "srslte/phy/utils/vector.h" #define dft_ceil(a,b) ((a-1)/b+1) #define dft_floor(a,b) (a/b) diff --git a/srslte/lib/dft/dft_precoding.c b/lib/src/phy/dft/dft_precoding.c similarity index 95% rename from srslte/lib/dft/dft_precoding.c rename to lib/src/phy/dft/dft_precoding.c index bc285d8f6..3bec5b96e 100644 --- a/srslte/lib/dft/dft_precoding.c +++ b/lib/src/phy/dft/dft_precoding.c @@ -33,11 +33,11 @@ #include #include -#include "srslte/common/phy_common.h" -#include "srslte/utils/debug.h" -#include "srslte/utils/vector.h" -#include "srslte/dft/dft.h" -#include "srslte/dft/dft_precoding.h" +#include "srslte/phy/common/phy_common.h" +#include "srslte/phy/utils/debug.h" +#include "srslte/phy/utils/vector.h" +#include "srslte/phy/dft/dft.h" +#include "srslte/phy/dft/dft_precoding.h" /* Create DFT plans for transform precoding */ int srslte_dft_precoding_init(srslte_dft_precoding_t *q, uint32_t max_prb) diff --git a/srslte/lib/dft/ofdm.c b/lib/src/phy/dft/ofdm.c similarity index 97% rename from srslte/lib/dft/ofdm.c rename to lib/src/phy/dft/ofdm.c index 856ff28da..69b7e9161 100644 --- a/srslte/lib/dft/ofdm.c +++ b/lib/src/phy/dft/ofdm.c @@ -30,11 +30,11 @@ #include #include -#include "srslte/common/phy_common.h" -#include "srslte/dft/dft.h" -#include "srslte/dft/ofdm.h" -#include "srslte/utils/debug.h" -#include "srslte/utils/vector.h" +#include "srslte/phy/common/phy_common.h" +#include "srslte/phy/dft/dft.h" +#include "srslte/phy/dft/ofdm.h" +#include "srslte/phy/utils/debug.h" +#include "srslte/phy/utils/vector.h" int srslte_ofdm_init_(srslte_ofdm_t *q, srslte_cp_t cp, int symbol_sz, int nof_prb, srslte_dft_dir_t dir) { diff --git a/srslte/lib/dft/test/CMakeLists.txt b/lib/src/phy/dft/test/CMakeLists.txt similarity index 88% rename from srslte/lib/dft/test/CMakeLists.txt rename to lib/src/phy/dft/test/CMakeLists.txt index 0fc781cfd..f781dede8 100644 --- a/srslte/lib/dft/test/CMakeLists.txt +++ b/lib/src/phy/dft/test/CMakeLists.txt @@ -1,7 +1,7 @@ # -# Copyright 2013-2015 Software Radio Systems Limited +# Copyright 2013-2017 Software Radio Systems Limited # -# This file is part of the srsLTE library. +# 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 @@ -23,7 +23,7 @@ ######################################################################## add_executable(ofdm_test ofdm_test.c) -target_link_libraries(ofdm_test srslte) +target_link_libraries(ofdm_test srslte_phy) add_test(ofdm_normal ofdm_test) add_test(ofdm_extended ofdm_test -e) diff --git a/srslte/lib/dft/test/ofdm_test.c b/lib/src/phy/dft/test/ofdm_test.c similarity index 100% rename from srslte/lib/dft/test/ofdm_test.c rename to lib/src/phy/dft/test/ofdm_test.c diff --git a/srslte/lib/enb/CMakeLists.txt b/lib/src/phy/enb/CMakeLists.txt similarity index 88% rename from srslte/lib/enb/CMakeLists.txt rename to lib/src/phy/enb/CMakeLists.txt index abd38a7d0..0ac7e5a90 100644 --- a/srslte/lib/enb/CMakeLists.txt +++ b/lib/src/phy/enb/CMakeLists.txt @@ -1,7 +1,7 @@ # -# Copyright 2013-2015 Software Radio Systems Limited +# Copyright 2013-2017 Software Radio Systems Limited # -# This file is part of the srsLTE library. +# 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 diff --git a/srslte/lib/enb/enb_dl.c b/lib/src/phy/enb/enb_dl.c similarity index 99% rename from srslte/lib/enb/enb_dl.c rename to lib/src/phy/enb/enb_dl.c index 33809015d..4cc33d3b8 100644 --- a/srslte/lib/enb/enb_dl.c +++ b/lib/src/phy/enb/enb_dl.c @@ -24,7 +24,7 @@ * */ -#include "srslte/enb/enb_dl.h" +#include "srslte/phy/enb/enb_dl.h" #include #include diff --git a/srslte/lib/enb/enb_ul.c b/lib/src/phy/enb/enb_ul.c similarity index 99% rename from srslte/lib/enb/enb_ul.c rename to lib/src/phy/enb/enb_ul.c index f536e33f8..9c294ac43 100644 --- a/srslte/lib/enb/enb_ul.c +++ b/lib/src/phy/enb/enb_ul.c @@ -24,7 +24,7 @@ * */ -#include "srslte/enb/enb_ul.h" +#include "srslte/phy/enb/enb_ul.h" #include #include diff --git a/srslte/lib/fec/CMakeLists.txt b/lib/src/phy/fec/CMakeLists.txt similarity index 89% rename from srslte/lib/fec/CMakeLists.txt rename to lib/src/phy/fec/CMakeLists.txt index 2543881e0..d304e2c37 100644 --- a/srslte/lib/fec/CMakeLists.txt +++ b/lib/src/phy/fec/CMakeLists.txt @@ -1,7 +1,7 @@ # -# Copyright 2013-2015 Software Radio Systems Limited +# Copyright 2013-2017 Software Radio Systems Limited # -# This file is part of the srsLTE library. +# 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 diff --git a/srslte/lib/fec/cbsegm.c b/lib/src/phy/fec/cbsegm.c similarity index 97% rename from srslte/lib/fec/cbsegm.c rename to lib/src/phy/fec/cbsegm.c index bbd2c174a..6370abca0 100644 --- a/srslte/lib/fec/cbsegm.c +++ b/lib/src/phy/fec/cbsegm.c @@ -27,9 +27,9 @@ #include #include -#include "srslte/fec/turbodecoder_gen.h" -#include "srslte/fec/cbsegm.h" -#include "srslte/utils/debug.h" +#include "srslte/phy/fec/turbodecoder_gen.h" +#include "srslte/phy/fec/cbsegm.h" +#include "srslte/phy/utils/debug.h" const uint32_t tc_cb_sizes[SRSLTE_NOF_TC_CB_SIZES] = { 40, 48, 56, 64, 72, 80, 88, 96, 104, 112, 120, diff --git a/srslte/lib/fec/convcoder.c b/lib/src/phy/fec/convcoder.c similarity index 97% rename from srslte/lib/fec/convcoder.c rename to lib/src/phy/fec/convcoder.c index e5f486556..260ce1e33 100644 --- a/srslte/lib/fec/convcoder.c +++ b/lib/src/phy/fec/convcoder.c @@ -30,7 +30,7 @@ #include #include -#include "srslte/fec/convcoder.h" +#include "srslte/phy/fec/convcoder.h" #include "parity.h" int srslte_convcoder_encode(srslte_convcoder_t *q, uint8_t *input, uint8_t *output, uint32_t frame_length) { diff --git a/srslte/lib/fec/crc.c b/lib/src/phy/fec/crc.c similarity index 98% rename from srslte/lib/fec/crc.c rename to lib/src/phy/fec/crc.c index e77366fcd..a2f6d7931 100644 --- a/srslte/lib/fec/crc.c +++ b/lib/src/phy/fec/crc.c @@ -28,8 +28,8 @@ #include #include -#include "srslte/utils/bit.h" -#include "srslte/fec/crc.h" +#include "srslte/phy/utils/bit.h" +#include "srslte/phy/fec/crc.h" void gen_crc_table(srslte_crc_t *h) { diff --git a/srslte/lib/fec/parity.c b/lib/src/phy/fec/parity.c similarity index 100% rename from srslte/lib/fec/parity.c rename to lib/src/phy/fec/parity.c diff --git a/srslte/lib/fec/parity.h b/lib/src/phy/fec/parity.h similarity index 100% rename from srslte/lib/fec/parity.h rename to lib/src/phy/fec/parity.h diff --git a/srslte/lib/fec/rm_conv.c b/lib/src/phy/fec/rm_conv.c similarity index 99% rename from srslte/lib/fec/rm_conv.c rename to lib/src/phy/fec/rm_conv.c index f994c96fa..ddf38d274 100644 --- a/srslte/lib/fec/rm_conv.c +++ b/lib/src/phy/fec/rm_conv.c @@ -28,7 +28,7 @@ #include #include -#include "srslte/fec/rm_conv.h" +#include "srslte/phy/fec/rm_conv.h" #define NCOLS 32 #define NROWS_MAX NCOLS diff --git a/srslte/lib/fec/rm_turbo.c b/lib/src/phy/fec/rm_turbo.c similarity index 99% rename from srslte/lib/fec/rm_turbo.c rename to lib/src/phy/fec/rm_turbo.c index d3d934115..0840c206a 100644 --- a/srslte/lib/fec/rm_turbo.c +++ b/lib/src/phy/fec/rm_turbo.c @@ -31,10 +31,10 @@ #include #include -#include "srslte/fec/rm_turbo.h" -#include "srslte/utils/bit.h" -#include "srslte/utils/vector.h" -#include "srslte/fec/cbsegm.h" +#include "srslte/phy/fec/rm_turbo.h" +#include "srslte/phy/utils/bit.h" +#include "srslte/phy/utils/vector.h" +#include "srslte/phy/fec/cbsegm.h" #ifdef DEBUG_MODE #warning FIXME: Disabling SSE/AVX turbo rate matching diff --git a/srslte/lib/fec/softbuffer.c b/lib/src/phy/fec/softbuffer.c similarity index 94% rename from srslte/lib/fec/softbuffer.c rename to lib/src/phy/fec/softbuffer.c index 46eaaef69..8efa937cb 100644 --- a/srslte/lib/fec/softbuffer.c +++ b/lib/src/phy/fec/softbuffer.c @@ -33,13 +33,13 @@ #include #include -#include "srslte/common/phy_common.h" -#include "srslte/phch/ra.h" -#include "srslte/fec/turbodecoder_gen.h" -#include "srslte/fec/rm_turbo.h" -#include "srslte/fec/softbuffer.h" -#include "srslte/utils/vector.h" -#include "srslte/utils/debug.h" +#include "srslte/phy/common/phy_common.h" +#include "srslte/phy/phch/ra.h" +#include "srslte/phy/fec/turbodecoder_gen.h" +#include "srslte/phy/fec/rm_turbo.h" +#include "srslte/phy/fec/softbuffer.h" +#include "srslte/phy/utils/vector.h" +#include "srslte/phy/utils/debug.h" #define MAX_PDSCH_RE(cp) (2 * SRSLTE_CP_NSYMB(cp) * 12) diff --git a/srslte/lib/fec/tc_interl_lte.c b/lib/src/phy/fec/tc_interl_lte.c similarity index 92% rename from srslte/lib/fec/tc_interl_lte.c rename to lib/src/phy/fec/tc_interl_lte.c index 2124b9819..06ba7a753 100644 --- a/srslte/lib/fec/tc_interl_lte.c +++ b/lib/src/phy/fec/tc_interl_lte.c @@ -28,11 +28,11 @@ #include #include -#include "srslte/common/phy_common.h" -#include "srslte/fec/tc_interl.h" -#include "srslte/fec/turbocoder.h" -#include "srslte/fec/cbsegm.h" -#include "srslte/utils/debug.h" +#include "srslte/phy/common/phy_common.h" +#include "srslte/phy/fec/tc_interl.h" +#include "srslte/phy/fec/turbocoder.h" +#include "srslte/phy/fec/cbsegm.h" +#include "srslte/phy/utils/debug.h" /************************************************ * diff --git a/srslte/lib/fec/tc_interl_umts.c b/lib/src/phy/fec/tc_interl_umts.c similarity index 94% rename from srslte/lib/fec/tc_interl_umts.c rename to lib/src/phy/fec/tc_interl_umts.c index 914e59ba2..d7f9ecdb7 100644 --- a/srslte/lib/fec/tc_interl_umts.c +++ b/lib/src/phy/fec/tc_interl_umts.c @@ -29,8 +29,8 @@ #include #include -#include "srslte/fec/tc_interl.h" -#include "srslte/fec/turbocoder.h" +#include "srslte/phy/fec/tc_interl.h" +#include "srslte/phy/fec/turbocoder.h" #define TURBO_SRSLTE_TCOD_RATE 3 diff --git a/srslte/lib/fec/test/CMakeLists.txt b/lib/src/phy/fec/test/CMakeLists.txt similarity index 88% rename from srslte/lib/fec/test/CMakeLists.txt rename to lib/src/phy/fec/test/CMakeLists.txt index 52d653150..b8046c3bb 100644 --- a/srslte/lib/fec/test/CMakeLists.txt +++ b/lib/src/phy/fec/test/CMakeLists.txt @@ -1,7 +1,7 @@ # -# Copyright 2013-2015 Software Radio Systems Limited +# Copyright 2013-2017 Software Radio Systems Limited # -# This file is part of the srsLTE library. +# 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 @@ -24,10 +24,10 @@ ######################################################################## add_executable(rm_conv_test rm_conv_test.c) -target_link_libraries(rm_conv_test srslte) +target_link_libraries(rm_conv_test srslte_phy) add_executable(rm_turbo_test rm_turbo_test.c) -target_link_libraries(rm_turbo_test srslte) +target_link_libraries(rm_turbo_test srslte_phy) add_test(rm_conv_test_1 rm_conv_test -t 480 -r 1920) add_test(rm_conv_test_2 rm_conv_test -t 1920 -r 480) @@ -39,7 +39,7 @@ add_test(rm_turbo_test_2 rm_turbo_test -e 8192) # Turbo Coder TEST ######################################################################## add_executable(turbodecoder_test turbodecoder_test.c) -target_link_libraries(turbodecoder_test srslte) +target_link_libraries(turbodecoder_test srslte_phy) add_test(turbodecoder_test_504_1 turbodecoder_test -n 100 -s 1 -l 504 -e 1.0 -t) add_test(turbodecoder_test_504_2 turbodecoder_test -n 100 -s 1 -l 504 -e 2.0 -t) @@ -47,7 +47,7 @@ add_test(turbodecoder_test_6114_1_5 turbodecoder_test -n 100 -s 1 -l 6144 -e 1.5 add_test(turbodecoder_test_known turbodecoder_test -n 1 -s 1 -k -e 0.5) add_executable(turbocoder_test turbocoder_test.c) -target_link_libraries(turbocoder_test srslte) +target_link_libraries(turbocoder_test srslte_phy) add_test(turbocoder_test_all turbocoder_test) ######################################################################## @@ -55,7 +55,7 @@ add_test(turbocoder_test_all turbocoder_test) ######################################################################## add_executable(viterbi_test viterbi_test.c) -target_link_libraries(viterbi_test srslte) +target_link_libraries(viterbi_test srslte_phy) add_test(viterbi_40_0 viterbi_test -n 1000 -s 1 -l 40 -t -e 0.0) add_test(viterbi_40_2 viterbi_test -n 1000 -s 1 -l 40 -t -e 2.0) @@ -72,7 +72,7 @@ add_test(viterbi_1000_4 viterbi_test -n 100 -s 1 -l 1000 -t -e 4.5) ######################################################################## add_executable(crc_test crc_test.c) -target_link_libraries(crc_test srslte) +target_link_libraries(crc_test srslte_phy) add_test(crc_24A crc_test -n 5001 -l 24 -p 0x1864CFB -s 1) add_test(crc_24B crc_test -n 5001 -l 24 -p 0x1800063 -s 1) diff --git a/srslte/lib/fec/test/crc_test.c b/lib/src/phy/fec/test/crc_test.c similarity index 100% rename from srslte/lib/fec/test/crc_test.c rename to lib/src/phy/fec/test/crc_test.c diff --git a/srslte/lib/fec/test/crc_test.h b/lib/src/phy/fec/test/crc_test.h similarity index 98% rename from srslte/lib/fec/test/crc_test.h rename to lib/src/phy/fec/test/crc_test.h index 39968aeff..3123133b9 100644 --- a/srslte/lib/fec/test/crc_test.h +++ b/lib/src/phy/fec/test/crc_test.h @@ -26,7 +26,7 @@ #include -#include "srslte/fec/crc.h" +#include "srslte/phy/fec/crc.h" typedef struct { int n; diff --git a/srslte/lib/fec/test/rm_conv_test.c b/lib/src/phy/fec/test/rm_conv_test.c similarity index 100% rename from srslte/lib/fec/test/rm_conv_test.c rename to lib/src/phy/fec/test/rm_conv_test.c diff --git a/srslte/lib/fec/test/rm_turbo_rx_mex.c b/lib/src/phy/fec/test/rm_turbo_rx_mex.c similarity index 100% rename from srslte/lib/fec/test/rm_turbo_rx_mex.c rename to lib/src/phy/fec/test/rm_turbo_rx_mex.c diff --git a/srslte/lib/fec/test/rm_turbo_test.c b/lib/src/phy/fec/test/rm_turbo_test.c similarity index 100% rename from srslte/lib/fec/test/rm_turbo_test.c rename to lib/src/phy/fec/test/rm_turbo_test.c diff --git a/srslte/lib/fec/test/turbocoder_test.c b/lib/src/phy/fec/test/turbocoder_test.c similarity index 100% rename from srslte/lib/fec/test/turbocoder_test.c rename to lib/src/phy/fec/test/turbocoder_test.c diff --git a/srslte/lib/fec/test/turbodecoder_test.c b/lib/src/phy/fec/test/turbodecoder_test.c similarity index 100% rename from srslte/lib/fec/test/turbodecoder_test.c rename to lib/src/phy/fec/test/turbodecoder_test.c diff --git a/srslte/lib/fec/test/turbodecoder_test.h b/lib/src/phy/fec/test/turbodecoder_test.h similarity index 100% rename from srslte/lib/fec/test/turbodecoder_test.h rename to lib/src/phy/fec/test/turbodecoder_test.h diff --git a/srslte/lib/fec/test/turbodecoder_test_mex.c b/lib/src/phy/fec/test/turbodecoder_test_mex.c similarity index 100% rename from srslte/lib/fec/test/turbodecoder_test_mex.c rename to lib/src/phy/fec/test/turbodecoder_test_mex.c diff --git a/srslte/lib/fec/test/viterbi_test.c b/lib/src/phy/fec/test/viterbi_test.c similarity index 99% rename from srslte/lib/fec/test/viterbi_test.c rename to lib/src/phy/fec/test/viterbi_test.c index 3d3e7f64a..f619b50b9 100644 --- a/srslte/lib/fec/test/viterbi_test.c +++ b/lib/src/phy/fec/test/viterbi_test.c @@ -213,7 +213,7 @@ int main(int argc, char **argv) { gettimeofday(&t[1], NULL); int M = 1; - srslte_vec_fprint_b(stdout, data_tx, frame_length); + //srslte_vec_fprint_b(stdout, data_tx, frame_length); for (int i=0;i #include -#include "srslte/fec/cbsegm.h" -#include "srslte/fec/turbocoder.h" -#include "srslte/utils/bit.h" -#include "srslte/utils/vector.h" +#include "srslte/phy/fec/cbsegm.h" +#include "srslte/phy/fec/turbocoder.h" +#include "srslte/phy/utils/bit.h" +#include "srslte/phy/utils/vector.h" #define NOF_REGS 3 diff --git a/srslte/lib/fec/turbodecoder.c b/lib/src/phy/fec/turbodecoder.c similarity index 94% rename from srslte/lib/fec/turbodecoder.c rename to lib/src/phy/fec/turbodecoder.c index bb8c51c4f..145c88d6d 100644 --- a/srslte/lib/fec/turbodecoder.c +++ b/lib/src/phy/fec/turbodecoder.c @@ -30,15 +30,15 @@ #include #include -#include "srslte/fec/turbodecoder.h" -#include "srslte/fec/turbodecoder_gen.h" +#include "srslte/phy/fec/turbodecoder.h" +#include "srslte/phy/fec/turbodecoder_gen.h" #ifdef LV_HAVE_SSE -#include "srslte/fec/turbodecoder_sse.h" +#include "srslte/phy/fec/turbodecoder_sse.h" #endif -#include "srslte/utils/vector.h" +#include "srslte/phy/utils/vector.h" int srslte_tdec_init(srslte_tdec_t * h, uint32_t max_long_cb) { diff --git a/srslte/lib/fec/turbodecoder_gen.c b/lib/src/phy/fec/turbodecoder_gen.c similarity index 95% rename from srslte/lib/fec/turbodecoder_gen.c rename to lib/src/phy/fec/turbodecoder_gen.c index 9a70a4f7f..396d94caa 100644 --- a/srslte/lib/fec/turbodecoder_gen.c +++ b/lib/src/phy/fec/turbodecoder_gen.c @@ -31,8 +31,8 @@ #include #include -#include "srslte/fec/turbodecoder_gen.h" -#include "srslte/utils/vector.h" +#include "srslte/phy/fec/turbodecoder_gen.h" +#include "srslte/phy/utils/vector.h" #define NUMSTATES 8 #define NINPUTS 2 diff --git a/srslte/lib/fec/turbodecoder_sse.c b/lib/src/phy/fec/turbodecoder_sse.c similarity index 96% rename from srslte/lib/fec/turbodecoder_sse.c rename to lib/src/phy/fec/turbodecoder_sse.c index 849323cc5..91d96c287 100644 --- a/srslte/lib/fec/turbodecoder_sse.c +++ b/lib/src/phy/fec/turbodecoder_sse.c @@ -31,8 +31,8 @@ #include #include -#include "srslte/fec/turbodecoder_sse.h" -#include "srslte/utils/vector.h" +#include "srslte/phy/fec/turbodecoder_sse.h" +#include "srslte/phy/utils/vector.h" #include diff --git a/srslte/lib/fec/viterbi.c b/lib/src/phy/fec/viterbi.c similarity index 62% rename from srslte/lib/fec/viterbi.c rename to lib/src/phy/fec/viterbi.c index 0eb2e6d0a..cdff3216f 100644 --- a/srslte/lib/fec/viterbi.c +++ b/lib/src/phy/fec/viterbi.c @@ -31,8 +31,8 @@ #include #include -#include "srslte/utils/vector.h" -#include "srslte/fec/viterbi.h" +#include "srslte/phy/utils/vector.h" +#include "srslte/phy/fec/viterbi.h" #include "parity.h" #include "viterbi37.h" @@ -42,6 +42,7 @@ #define DEFAULT_GAIN 100 + //#undef LV_HAVE_SSE int decode37(void *o, uint8_t *symbols, uint8_t *data, uint32_t frame_length) { @@ -119,6 +120,96 @@ void free37_sse(void *o) { #endif + + +#ifdef LV_HAVE_AVX +int decode37_avx2(void *o, uint8_t *symbols, uint8_t *data, uint32_t frame_length) { + srslte_viterbi_t *q = o; + + uint32_t best_state; + + if (frame_length > q->framebits) { + fprintf(stderr, "Initialized decoder for max frame length %d bits\n", + q->framebits); + return -1; + } + + /* Initialize Viterbi decoder */ + init_viterbi37_avx2(q->ptr, q->tail_biting?-1:0); + + /* Decode block */ + if (q->tail_biting) { + for (int i=0;itmp[i*3*frame_length], symbols, 3*frame_length*sizeof(uint8_t)); + } + update_viterbi37_blk_avx2(q->ptr, q->tmp, TB_ITER*frame_length, &best_state); + chainback_viterbi37_avx2(q->ptr, q->tmp, TB_ITER*frame_length, best_state); + memcpy(data, &q->tmp[((int) (TB_ITER/2))*frame_length], frame_length*sizeof(uint8_t)); + } else { + update_viterbi37_blk_avx2(q->ptr, symbols, frame_length+q->K-1, NULL); + chainback_viterbi37_avx2(q->ptr, data, frame_length, 0); + } + + return q->framebits; +} + +void free37_avx2(void *o) { + srslte_viterbi_t *q = o; + if (q->symbols_uc) { + free(q->symbols_uc); + } + if (q->tmp) { + free(q->tmp); + } + delete_viterbi37_avx2(q->ptr); +} + +#endif + +#ifdef HAVE_NEON +int decode37_neon(void *o, uint8_t *symbols, uint8_t *data, uint32_t frame_length) { + srslte_viterbi_t *q = o; + + uint32_t best_state; + + if (frame_length > q->framebits) { + fprintf(stderr, "Initialized decoder for max frame length %d bits\n", + q->framebits); + return -1; + } + + /* Initialize Viterbi decoder */ + init_viterbi37_neon(q->ptr, q->tail_biting?-1:0); + + /* Decode block */ + if (q->tail_biting) { + for (int i=0;itmp[i*3*frame_length], symbols, 3*frame_length*sizeof(uint8_t)); + } + update_viterbi37_blk_neon(q->ptr, q->tmp, TB_ITER*frame_length, &best_state); + chainback_viterbi37_neon(q->ptr, q->tmp, TB_ITER*frame_length, best_state); + memcpy(data, &q->tmp[((int) (TB_ITER/2))*frame_length], frame_length*sizeof(uint8_t)); + } else { + update_viterbi37_blk_neon(q->ptr, symbols, frame_length+q->K-1, NULL); + chainback_viterbi37_neon(q->ptr, data, frame_length, 0); + } + + return q->framebits; +} + +void free37_neon(void *o) { + srslte_viterbi_t *q = o; + if (q->symbols_uc) { + free(q->symbols_uc); + } + if (q->tmp) { + free(q->tmp); + } + delete_viterbi37_neon(q->ptr); +} + +#endif + void free37(void *o) { srslte_viterbi_t *q = o; if (q->symbols_uc) { @@ -203,6 +294,82 @@ int init37_sse(srslte_viterbi_t *q, int poly[3], uint32_t framebits, bool tail_b } #endif +#ifdef HAVE_NEON +int init37_neon(srslte_viterbi_t *q, int poly[3], uint32_t framebits, bool tail_biting) { + q->K = 7; + q->R = 3; + q->framebits = framebits; + q->gain_quant_s = 4; + q->gain_quant = DEFAULT_GAIN; + q->tail_biting = tail_biting; + q->decode = decode37_neon; + q->free = free37_neon; + q->decode_f = NULL; + printf("USING NEON VITERBI***************\n"); + q->symbols_uc = srslte_vec_malloc(3 * (q->framebits + q->K - 1) * sizeof(uint8_t)); + if (!q->symbols_uc) { + perror("malloc"); + return -1; + } + if (q->tail_biting) { + q->tmp = srslte_vec_malloc(TB_ITER*3*(q->framebits + q->K - 1) * sizeof(uint8_t)); + if (!q->tmp) { + perror("malloc"); + free37(q); + return -1; + } + } else { + q->tmp = NULL; + } + + if ((q->ptr = create_viterbi37_neon(poly, TB_ITER*framebits)) == NULL) { + fprintf(stderr, "create_viterbi37 failed\n"); + free37(q); + return -1; + } else { + return 0; + } +} +#endif + + +#ifdef LV_HAVE_AVX +int init37_avx2(srslte_viterbi_t *q, int poly[3], uint32_t framebits, bool tail_biting) { + q->K = 7; + q->R = 3; + q->framebits = framebits; + q->gain_quant_s = 4; + q->gain_quant = DEFAULT_GAIN; + q->tail_biting = tail_biting; + q->decode = decode37_avx2; + q->free = free37_avx2; + q->decode_f = NULL; + q->symbols_uc = srslte_vec_malloc(3 * (q->framebits + q->K - 1) * sizeof(uint8_t)); + if (!q->symbols_uc) { + perror("malloc"); + return -1; + } + if (q->tail_biting) { + q->tmp = srslte_vec_malloc(TB_ITER*3*(q->framebits + q->K - 1) * sizeof(uint8_t)); + if (!q->tmp) { + perror("malloc"); + free37(q); + return -1; + } + } else { + q->tmp = NULL; + } + + if ((q->ptr = create_viterbi37_avx2(poly, TB_ITER*framebits)) == NULL) { + fprintf(stderr, "create_viterbi37 failed\n"); + free37(q); + return -1; + } else { + return 0; + } +} +#endif + void srslte_viterbi_set_gain_quant(srslte_viterbi_t *q, float gain_quant) { q->gain_quant = gain_quant; } @@ -216,9 +383,17 @@ int srslte_viterbi_init(srslte_viterbi_t *q, srslte_viterbi_type_t type, int pol switch (type) { case SRSLTE_VITERBI_37: #ifdef LV_HAVE_SSE - return init37_sse(q, poly, max_frame_length, tail_bitting); + #ifdef LV_HAVE_AVX + return init37_avx2(q, poly, max_frame_length, tail_bitting); + #else + return init37_sse(q, poly, max_frame_length, tail_bitting); + #endif #else + #ifdef HAVE_NEON + return init37_neon(q, poly, max_frame_length, tail_bitting); + #else return init37(q, poly, max_frame_length, tail_bitting); + #endif #endif default: fprintf(stderr, "Decoder not implemented\n"); @@ -233,6 +408,13 @@ int srslte_viterbi_init_sse(srslte_viterbi_t *q, srslte_viterbi_type_t type, int } #endif +#ifdef LV_HAVE_AVX +int srslte_viterbi_init_avx2(srslte_viterbi_t *q, srslte_viterbi_type_t type, int poly[3], uint32_t max_frame_length, bool tail_bitting) +{ + return init37_avx2(q, poly, max_frame_length, tail_bitting); +} +#endif + void srslte_viterbi_free(srslte_viterbi_t *q) { if (q->free) { q->free(q); diff --git a/srslte/lib/fec/viterbi37.h b/lib/src/phy/fec/viterbi37.h similarity index 62% rename from srslte/lib/fec/viterbi37.h rename to lib/src/phy/fec/viterbi37.h index f5f304858..574f4fd87 100644 --- a/srslte/lib/fec/viterbi37.h +++ b/lib/src/phy/fec/viterbi37.h @@ -65,3 +65,48 @@ int update_viterbi37_blk_sse(void *p, uint8_t *syms, uint32_t nbits, uint32_t *best_state); + +void *create_viterbi37_neon(int polys[3], + uint32_t len); + +int init_viterbi37_neon(void *p, + int starting_state); + + +void reset_blk_neon(void *p, int nbits); + +int chainback_viterbi37_neon(void *p, + uint8_t *data, + uint32_t nbits, + uint32_t endstate); + +void delete_viterbi37_neon(void *p); + +int update_viterbi37_blk_neon(void *p, + uint8_t *syms, + uint32_t nbits, + uint32_t *best_state); + + +void *create_viterbi37_avx2(int polys[3], + uint32_t len); + +int init_viterbi37_avx2(void *p, + int starting_state); + + +void reset_blk_avx2(void *p, int nbits); + +int chainback_viterbi37_avx2(void *p, + uint8_t *data, + uint32_t nbits, + uint32_t endstate); + +void delete_viterbi37_avx2(void *p); + +int update_viterbi37_blk_avx2(void *p, + uint8_t *syms, + uint32_t nbits, + uint32_t *best_state); + + diff --git a/lib/src/phy/fec/viterbi37_avx2.c b/lib/src/phy/fec/viterbi37_avx2.c new file mode 100644 index 000000000..bb8e90d10 --- /dev/null +++ b/lib/src/phy/fec/viterbi37_avx2.c @@ -0,0 +1,339 @@ +/* Adapted Phil Karn's r=1/3 k=9 viterbi decoder to r=1/3 k=7 + * + * K=15 r=1/6 Viterbi decoder for x86 SSE2 + * Copyright Mar 2004, Phil Karn, KA9Q + * May be used under the terms of the GNU Lesser General Public License (LGPL) + */ + +#include +#include +#include +#include +#include +#include "parity.h" + +//#define DEBUG + +#ifdef LV_HAVE_SSE + +#include +#include +#include +#include +#define _mm256_set_m128i(v0, v1) _mm256_insertf128_si256(_mm256_castsi128_si256(v1), (v0), 1) + +#define _mm256_setr_m128i(v0, v1) _mm256_set_m128i((v1), (v0)) + +typedef union { + unsigned char c[64]; + __m128i v[4]; +} metric_t; +typedef union { + unsigned int w[2]; + unsigned char c[8]; + unsigned short s[4]; + __m64 v; +} decision_t; + +union branchtab27 { + unsigned char c[32]; + __m256i v; +} Branchtab37_sse2[3]; + +int firstGo; +/* State info for instance of Viterbi decoder */ +struct v37 { + metric_t metrics1; /* path metric buffer 1 */ + metric_t metrics2; /* path metric buffer 2 */ + decision_t *dp; /* Pointer to current decision */ + metric_t *old_metrics,*new_metrics; /* Pointers to path metrics, swapped on every bit */ + decision_t *decisions; /* Beginning of decisions for block */ + uint32_t len; +}; + +void set_viterbi37_polynomial_avx2(int polys[3]) { + int state; + + for(state=0;state < 32;state++){ + Branchtab37_sse2[0].c[state] = (polys[0] < 0) ^ parity((2*state) & polys[0]) ? 255:0; + Branchtab37_sse2[1].c[state] = (polys[1] < 0) ^ parity((2*state) & polys[1]) ? 255:0; + Branchtab37_sse2[2].c[state] = (polys[2] < 0) ^ parity((2*state) & polys[2]) ? 255:0; + } +} + +void clear_v37_avx2(struct v37 *vp) { + bzero(vp->decisions, sizeof(decision_t)*vp->len); + vp->dp = NULL; + bzero(&vp->metrics1, sizeof(metric_t)); + bzero(&vp->metrics2, sizeof(metric_t)); + vp->old_metrics = NULL; + vp->new_metrics = NULL; +} + + +/* Initialize Viterbi decoder for start of new frame */ +int init_viterbi37_avx2(void *p, int starting_state) { + struct v37 *vp = p; + uint32_t i; + firstGo = 1; + for(i=0;i<64;i++) + vp->metrics1.c[i] = 63; + + clear_v37_avx2(vp); + + vp->old_metrics = &vp->metrics1; + vp->new_metrics = &vp->metrics2; + vp->dp = vp->decisions; + if (starting_state != -1) { + vp->old_metrics->c[starting_state & 63] = 0; /* Bias known start state */ + } + return 0; +} + +/* Create a new instance of a Viterbi decoder */ +void *create_viterbi37_avx2(int polys[3], uint32_t len) { + void *p; + struct v37 *vp; + + set_viterbi37_polynomial_avx2(polys); + + /* Ordinary malloc() only returns 8-byte alignment, we need 16 */ + if(posix_memalign(&p, sizeof(__m128i),sizeof(struct v37))) + return NULL; + + vp = (struct v37 *)p; + if(posix_memalign(&p, sizeof(__m128i),(len+6)*sizeof(decision_t))) { + free(vp); + return NULL; + } + vp->decisions = (decision_t *)p; + vp->len = len+6; + return vp; +} + + +/* Viterbi chainback */ +int chainback_viterbi37_avx2( + void *p, + uint8_t *data, /* Decoded output data */ + uint32_t nbits, /* Number of data bits */ + uint32_t endstate) { /* Terminal encoder state */ + struct v37 *vp = p; + + if (p == NULL) + return -1; + + decision_t *d = (decision_t *)vp->decisions; + + /* Make room beyond the end of the encoder register so we can + * accumulate a full byte of decoded data + */ + endstate %= 64; + endstate <<= 2; + + /* The store into data[] only needs to be done every 8 bits. + * But this avoids a conditional branch, and the writes will + * combine in the cache anyway + */ + d += 6; /* Look past tail */ + while(nbits--) { + int k; + + k = (d[nbits].c[(endstate>>2)/8] >> ((endstate>>2)%8)) & 1; + endstate = (endstate >> 1) | (k << 7); + data[nbits] = k; + //printf("nbits=%d, endstate=%3d, k=%d, w[0]=%d, w[1]=%d, c=%d\n", nbits, endstate, k, d[nbits].s[1]&1, d[nbits].s[2]&1, d[nbits].c[(endstate>>2)/8]&1); + } + return 0; +} + +/* Delete instance of a Viterbi decoder */ +void delete_viterbi37_avx2(void *p){ + struct v37 *vp = p; + + if(vp != NULL){ + free(vp->decisions); + free(vp); + } +} +void printer_256i(char *s, __m256i val) { + + printf("%s: ", s); + + uint8_t *x = (uint8_t*) &val; + for (int i=0;i<32;i++) { + printf("%3d, ", x[i]); + } + printf("\n"); +} + +void printer_128i(char *s, __m128i val) { + + printf("%s: ", s); + + uint8_t *x = (uint8_t*) &val; + for (int i=0;i<16;i++) { + printf("%3d, ", x[i]); + } + printf("\n"); +} + +void printer_m64(char *s, __m64 val) { + + printf("%s: ", s); + + uint8_t *x = (uint8_t*) &val; + for (int i=0;i<8;i++) { + printf("%3d, ", x[i]); + } + printf("\n"); +} + + +void update_viterbi37_blk_avx2(void *p,unsigned char *syms,int nbits, uint32_t *best_state) { + struct v37 *vp = p; + decision_t *d; + + if(p == NULL) + return; + +#ifdef DEBUG + printf("["); +#endif + + d = (decision_t *) vp->dp; + + for (int s=0;sold_metrics->v[1], vp->old_metrics->v[0]); + m0 = _mm256_add_epi8(temp,metric); + m2 = _mm256_add_epi8(temp,m_metric); + + temp = _mm256_set_m128i( vp->old_metrics->v[3], vp->old_metrics->v[2]); + m3 = _mm256_add_epi8(temp,metric); + m1 = _mm256_add_epi8(temp,m_metric); + + /* Compare and select, using modulo arithmetic */ + decision0 = _mm256_cmpgt_epi8(_mm256_sub_epi8(m0,m1),_mm256_setzero_si256()); + decision1 =_mm256_cmpgt_epi8(_mm256_sub_epi8(m2,m3),_mm256_setzero_si256()); + survivor0 = _mm256_or_si256(_mm256_and_si256(decision0,m1),_mm256_andnot_si256(decision0,m0)); + survivor1 = _mm256_or_si256(_mm256_and_si256(decision1,m3),_mm256_andnot_si256(decision1,m2)); + + unsigned int x = _mm256_movemask_epi8(_mm256_unpackhi_epi8(decision0,decision1)); + unsigned int y = _mm256_movemask_epi8(_mm256_unpacklo_epi8(decision0,decision1)); + + d->s[0] = (short) y; + d->s[1] = (short) x; + d->s[2] = (short) (y >>16); + d->s[3] = (short)(x>> 16); + + + __m256i unpack; + unpack = _mm256_unpacklo_epi8(survivor0,survivor1); + vp->new_metrics->v[0] =_mm256_castsi256_si128(unpack); + + vp->new_metrics->v[1] = _mm256_extractf128_si256(unpack,1); + + unpack = _mm256_unpackhi_epi8(survivor0,survivor1); + + vp->new_metrics->v[2] =_mm256_castsi256_si128(unpack); + vp->new_metrics->v[3] = _mm256_extractf128_si256(unpack,1); + + __m128i temp1 = vp->new_metrics->v[1]; + + vp->new_metrics->v[1] = vp->new_metrics->v[2]; + vp->new_metrics->v[2] = temp1; + + // See if we need to normalize + if (vp->new_metrics->c[0] > 100) { + int i; + uint8_t adjust; + __m128i adjustv; + union { __m128i v; signed short w[8]; } t; + + adjustv = vp->new_metrics->v[0]; + for(i=1;i<4;i++) { + adjustv = _mm_min_epu8(adjustv,vp->new_metrics->v[i]); + } + + adjustv = _mm_min_epu8(adjustv,_mm_srli_si128(adjustv,8)); + adjustv = _mm_min_epu8(adjustv,_mm_srli_si128(adjustv,4)); + adjustv = _mm_min_epu8(adjustv,_mm_srli_si128(adjustv,2)); + + t.v = adjustv; + adjust = t.w[0]; + adjustv = _mm_set1_epi8(adjust); + + /* We cannot use a saturated subtract, because we often have to adjust by more than SHRT_MAX + * This is okay since it can't overflow anyway + */ + for(i=0;i<4;i++) + vp->new_metrics->v[i] = _mm_sub_epi8(vp->new_metrics->v[i],adjustv); + + } + + firstGo = 0; + d++; + /* Swap pointers to old and new metrics */ + tmp = vp->old_metrics; + vp->old_metrics = vp->new_metrics; + vp->new_metrics = tmp; + } + + if (best_state) { + uint32_t i, bst=0; + uint8_t minmetric=UINT8_MAX; + for (i=0;i<64;i++) { + if (vp->old_metrics->c[i] <= minmetric) { + bst = i; + minmetric = vp->old_metrics->c[i]; + } + } + *best_state = bst; + } + + #ifdef DEBUG + printf("];\n===========================================\n"); +#endif + + vp->dp = d; +} + +#endif + + + diff --git a/lib/src/phy/fec/viterbi37_neon.c b/lib/src/phy/fec/viterbi37_neon.c new file mode 100644 index 000000000..452dba567 --- /dev/null +++ b/lib/src/phy/fec/viterbi37_neon.c @@ -0,0 +1,354 @@ +/* Adapted Phil Karn's r=1/3 k=9 viterbi decoder to r=1/3 k=7 + * + * K=15 r=1/6 Viterbi decoder for ARM NEON + * Copyright Mar 2004, Phil Karn, KA9Q + * May be used under the terms of the GNU Lesser General Public License (LGPL) + */ + +#include +#include +#include +#include +#include +#include "parity.h" + +//#define DEBUG +//#define HAVE_NEON +#ifdef HAVE_NEON + +#include + +typedef union { + unsigned char c[64]; + uint8x16_t v[4]; +} metric_t; + + +typedef union { + unsigned long w[2]; + unsigned char c[8]; + unsigned short s[4]; + uint8x8_t v[1]; +} decision_t; + + +union branchtab27{ + unsigned char c[32]; + uint8x16_t v[2]; +} Branchtab37_neon[3]; + + int8_t __attribute__((aligned(16))) xr[8]; + uint8x8_t mask_and; + int8x8_t mask_shift; + + +int firstGo; +/* State info for instance of Viterbi decoder */ +struct v37 { + metric_t metrics1; /* path metric buffer 1 */ + metric_t metrics2; /* path metric buffer 2 */ + decision_t *dp; /* Pointer to current decision */ + metric_t *old_metrics,*new_metrics; /* Pointers to path metrics, swapped on every bit */ + decision_t *decisions; /* Beginning of decisions for block */ + uint32_t len; +}; + +void set_viterbi37_polynomial_neon(int polys[3]) { + int state; + + for(state=0;state < 32;state++){ + Branchtab37_neon[0].c[state] = (polys[0] < 0) ^ parity((2*state) & polys[0]) ? 255:0; + Branchtab37_neon[1].c[state] = (polys[1] < 0) ^ parity((2*state) & polys[1]) ? 255:0; + Branchtab37_neon[2].c[state] = (polys[2] < 0) ^ parity((2*state) & polys[2]) ? 255:0; + } +} + +void clear_v37_neon(struct v37 *vp) { + bzero(vp->decisions, sizeof(decision_t)*vp->len); + vp->dp = NULL; + bzero(&vp->metrics1, sizeof(metric_t)); + bzero(&vp->metrics2, sizeof(metric_t)); + vp->old_metrics = NULL; + vp->new_metrics = NULL; +} + + +/* Initialize Viterbi decoder for start of new frame */ +int init_viterbi37_neon(void *p, int starting_state) { + struct v37 *vp = p; + uint32_t i; + firstGo = 1; + for(i=0;i<64;i++) + vp->metrics1.c[i] = 63; + + clear_v37_neon(vp); + for(int i = 0; i <8;i++) + xr[i] = i-7; + + mask_and = vdup_n_u8(0x80); + mask_shift = vld1_s8(xr); + + + vp->old_metrics = &vp->metrics1; + vp->new_metrics = &vp->metrics2; + vp->dp = vp->decisions; + if (starting_state != -1) { + vp->old_metrics->c[starting_state & 63] = 0; /* Bias known start state */ + } + return 0; +} + +/* Create a new instance of a Viterbi decoder */ +void *create_viterbi37_neon(int polys[3], uint32_t len) { + void *p; + struct v37 *vp; + + set_viterbi37_polynomial_neon(polys); + + /* Ordinary malloc() only returns 8-byte alignment, we need 16 */ + if(posix_memalign(&p, sizeof(uint8x16_t),sizeof(struct v37))) + return NULL; + + vp = (struct v37 *)p; + if(posix_memalign(&p, sizeof(uint8x16_t),(len+6)*sizeof(decision_t))) { + free(vp); + return NULL; + } + vp->decisions = (decision_t *)p; + vp->len = len+6; + return vp; +} + + +/* Viterbi chainback */ +int chainback_viterbi37_neon( + void *p, + uint8_t *data, /* Decoded output data */ + uint32_t nbits, /* Number of data bits */ + uint32_t endstate) { /* Terminal encoder state */ + struct v37 *vp = p; + + if (p == NULL) + return -1; + + decision_t *d = (decision_t *)vp->decisions; + + /* Make room beyond the end of the encoder register so we can + * accumulate a full byte of decoded data + */ + endstate %= 64; + endstate <<= 2; + + /* The store into data[] only needs to be done every 8 bits. + * But this avoids a conditional branch, and the writes will + * combine in the cache anyway + */ + d += 6; /* Look past tail */ + while(nbits--) { + int k; + + k = (d[nbits].c[(endstate>>2)/8] >> ((endstate>>2)%8)) & 1; + endstate = (endstate >> 1) | (k << 7); + data[nbits] = k; + //printf("nbits=%d, endstate=%3d, k=%d, w[0]=%d, w[1]=%d, c=%d\n", nbits, endstate, k, d[nbits].s[1]&1, d[nbits].s[2]&1, d[nbits].c[(endstate>>2)/8]&1); + } + return 0; +} + +/* Delete instance of a Viterbi decoder */ +void delete_viterbi37_neon(void *p){ + struct v37 *vp = p; + + if(vp != NULL){ + free(vp->decisions); + free(vp); + } +} + +void print_uint8x16_t(char *s, uint8x16_t val) { + + printf("%s: ", s); + + uint8_t *x = (uint8_t*) &val; + for (int i=0;i<16;i++) { + printf("%3d, ", x[i]); + } + printf("\n"); +} + +int movemask_neon(uint8x16_t movemask_low_in) +{ + uint8x8_t lo = vget_low_u8(movemask_low_in); + uint8x8_t hi = vget_high_u8(movemask_low_in); + lo = vand_u8(lo, mask_and); + lo = vshl_u8(lo, mask_shift); + hi = vand_u8(hi, mask_and); + hi = vshl_u8(hi, mask_shift); + + lo = vpadd_u8(lo, lo); + lo = vpadd_u8(lo, lo); + lo = vpadd_u8(lo, lo); + + hi = vpadd_u8(hi, hi); + hi = vpadd_u8(hi, hi); + hi = vpadd_u8(hi, hi); + + return ((hi[0] << 8) | (lo[0] & 0xFF)); +} + +void update_viterbi37_blk_neon(void *p,unsigned char *syms,int nbits, uint32_t *best_state) { + struct v37 *vp = p; + decision_t *d; + + uint8_t thirtyone; + thirtyone = 31; + if(p == NULL) + return; + +#ifdef DEBUG + printf("["); +#endif + + d = (decision_t *) vp->dp; + + for (int s=0;sold_metrics->v[i],metric); + m3 = vaddq_u8(vp->old_metrics->v[2+i],metric); + m1 = vaddq_u8(vp->old_metrics->v[2+i],m_metric); + m2 = vaddq_u8(vp->old_metrics->v[i],m_metric); + + /* Compare and select, using modulo arithmetic */ + + + decision0 = (uint8x16_t)vcgtq_s8(vsubq_s8((int8x16_t)m0,(int8x16_t)m1),vdupq_n_s8(0)); + decision1 = (uint8x16_t)vcgtq_s8(vsubq_s8((int8x16_t)m2,(int8x16_t)m3),vdupq_n_s8(0)); + survivor0 = vorrq_u8(vandq_u8(decision0,m1),vandq_u8(vmvnq_u8(decision0),m0)); + survivor1 = vorrq_u8 (vandq_u8(decision1,m3),vandq_u8(vmvnq_u8(decision1),m2) ); + + ////// equal to _mm_unpacklo_epi8 ////////// + uint8x8_t a1 = vget_low_u8(decision0); + uint8x8_t b1 = vget_low_u8(decision1); + uint8x8x2_t result = vzip_u8(a1, b1); + uint8x16_t movemask_low_in = vcombine_u8(result.val[0], result.val[1]); + ///////////////////////////////////////// + + + ////////equal to _mm_movemask_epi8 //////// + d->s[2*i] = movemask_neon(movemask_low_in); + + ///////equal to _mm_unpackhi_epi8//////////// + a1 = vget_high_u8(decision0); + b1 = vget_high_u8(decision1); + result = vzip_u8(a1, b1); + uint8x16_t movemask_hi_in = vcombine_u8(result.val[0], result.val[1]); + + + + ////////equal to _mm_movemask////////////// + d->s[2*i+1] = movemask_neon(movemask_hi_in); + + + a1 = vget_low_u8(survivor0); + b1 = vget_low_u8(survivor1); + result = vzip_u8(a1, b1); + vp->new_metrics->v[2*i] = vcombine_u8(result.val[0], result.val[1]); + + + a1 = vget_high_u8(survivor0); + b1 = vget_high_u8(survivor1); + result = vzip_u8(a1, b1); + vp->new_metrics->v[2*i+1] = vcombine_u8(result.val[0], result.val[1]); + + + + } + + // See if we need to normalize + if (vp->new_metrics->c[0] > 100) { + int i; + uint8_t adjust; + uint8x16_t adjustv; + + union { uint8x16_t v; signed short w[8]; } t; + + adjustv = vp->new_metrics->v[0]; + for(i=1;i<4;i++) + { + adjustv = vminq_u8(vp->new_metrics->v[i],adjustv); + } + + adjustv = vminq_u8(adjustv,vextq_u8(adjustv, vdupq_n_u8(0), (8))); + adjustv = vminq_u8(adjustv,vextq_u8(adjustv, vdupq_n_u8(0), (4))); + adjustv = vminq_u8(adjustv,vextq_u8(adjustv, vdupq_n_u8(0), (2))); + t.v = adjustv; + adjust = t.w[0]; + adjustv = vld1q_dup_u8(&adjust); + + /* We cannot use a saturated subtract, because we often have to adjust by more than SHRT_MAX + * This is okay since it can't overflow anyway + */ + for(i=0;i<4;i++) + { + vp->new_metrics->v[i] = vsubq_u8(vp->new_metrics->v[i],adjustv); + } + + } + d++; + /* Swap pointers to old and new metrics */ + tmp = vp->old_metrics; + vp->old_metrics = vp->new_metrics; + vp->new_metrics = tmp; + //firstGo = 0; + } + + if (best_state) { + uint32_t i, bst=0; + uint8_t minmetric=UINT8_MAX; + for (i=0;i<64;i++) { + if (vp->old_metrics->c[i] <= minmetric) { + bst = i; + minmetric = vp->old_metrics->c[i]; + } + } + *best_state = bst; + } + + #ifdef DEBUG + printf("];\n===========================================\n"); +#endif + + vp->dp = d; +} + +#endif + + + diff --git a/srslte/lib/fec/viterbi37_port.c b/lib/src/phy/fec/viterbi37_port.c similarity index 100% rename from srslte/lib/fec/viterbi37_port.c rename to lib/src/phy/fec/viterbi37_port.c diff --git a/srslte/lib/fec/viterbi37_sse.c b/lib/src/phy/fec/viterbi37_sse.c similarity index 100% rename from srslte/lib/fec/viterbi37_sse.c rename to lib/src/phy/fec/viterbi37_sse.c diff --git a/srslte/lib/io/CMakeLists.txt b/lib/src/phy/io/CMakeLists.txt similarity index 88% rename from srslte/lib/io/CMakeLists.txt rename to lib/src/phy/io/CMakeLists.txt index b913ef941..01e3a3dea 100644 --- a/srslte/lib/io/CMakeLists.txt +++ b/lib/src/phy/io/CMakeLists.txt @@ -1,7 +1,7 @@ # -# Copyright 2013-2015 Software Radio Systems Limited +# Copyright 2013-2017 Software Radio Systems Limited # -# This file is part of the srsLTE library. +# 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 diff --git a/srslte/lib/io/binsource.c b/lib/src/phy/io/binsource.c similarity index 97% rename from srslte/lib/io/binsource.c rename to lib/src/phy/io/binsource.c index 8b789a9b4..f78bfc49b 100644 --- a/srslte/lib/io/binsource.c +++ b/lib/src/phy/io/binsource.c @@ -29,8 +29,8 @@ #include #include -#include "srslte/io/binsource.h" -#include "srslte/utils/bit.h" +#include "srslte/phy/io/binsource.h" +#include "srslte/phy/utils/bit.h" #define DIV(a,b) ((a-1)/b+1) diff --git a/srslte/lib/io/filesink.c b/lib/src/phy/io/filesink.c similarity index 98% rename from srslte/lib/io/filesink.c rename to lib/src/phy/io/filesink.c index c84b172ed..6f163f468 100644 --- a/srslte/lib/io/filesink.c +++ b/lib/src/phy/io/filesink.c @@ -31,7 +31,7 @@ #include -#include "srslte/io/filesink.h" +#include "srslte/phy/io/filesink.h" int srslte_filesink_init(srslte_filesink_t *q, char *filename, srslte_datatype_t type) { bzero(q, sizeof(srslte_filesink_t)); diff --git a/srslte/lib/io/filesource.c b/lib/src/phy/io/filesource.c similarity index 98% rename from srslte/lib/io/filesource.c rename to lib/src/phy/io/filesource.c index 5d4ccd845..4010f8da4 100644 --- a/srslte/lib/io/filesource.c +++ b/lib/src/phy/io/filesource.c @@ -29,7 +29,7 @@ #include #include -#include "srslte/io/filesource.h" +#include "srslte/phy/io/filesource.h" int srslte_filesource_init(srslte_filesource_t *q, char *filename, srslte_datatype_t type) { bzero(q, sizeof(srslte_filesource_t)); diff --git a/srslte/lib/io/netsink.c b/lib/src/phy/io/netsink.c similarity index 98% rename from srslte/lib/io/netsink.c rename to lib/src/phy/io/netsink.c index 0a4c8110d..ac01df9d2 100644 --- a/srslte/lib/io/netsink.c +++ b/lib/src/phy/io/netsink.c @@ -36,7 +36,7 @@ #include -#include "srslte/io/netsink.h" +#include "srslte/phy/io/netsink.h" int srslte_netsink_init(srslte_netsink_t *q, const char *address, uint16_t port, srslte_netsink_type_t type) { bzero(q, sizeof(srslte_netsink_t)); diff --git a/srslte/lib/io/netsource.c b/lib/src/phy/io/netsource.c similarity index 98% rename from srslte/lib/io/netsource.c rename to lib/src/phy/io/netsource.c index 4e81331f4..62fe6734b 100644 --- a/srslte/lib/io/netsource.c +++ b/lib/src/phy/io/netsource.c @@ -34,7 +34,7 @@ #include #include -#include "srslte/io/netsource.h" +#include "srslte/phy/io/netsource.h" int srslte_netsource_init(srslte_netsource_t *q, const char *address, uint16_t port, srslte_netsource_type_t type) { bzero(q, sizeof(srslte_netsource_t)); diff --git a/srslte/lib/mimo/CMakeLists.txt b/lib/src/phy/mimo/CMakeLists.txt similarity index 89% rename from srslte/lib/mimo/CMakeLists.txt rename to lib/src/phy/mimo/CMakeLists.txt index 92ea2470d..826baae09 100644 --- a/srslte/lib/mimo/CMakeLists.txt +++ b/lib/src/phy/mimo/CMakeLists.txt @@ -1,7 +1,7 @@ # -# Copyright 2013-2015 Software Radio Systems Limited +# Copyright 2013-2017 Software Radio Systems Limited # -# This file is part of the srsLTE library. +# 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 diff --git a/srslte/lib/mimo/layermap.c b/lib/src/phy/mimo/layermap.c similarity index 98% rename from srslte/lib/mimo/layermap.c rename to lib/src/phy/mimo/layermap.c index 982e00f5b..868bf2f6a 100644 --- a/srslte/lib/mimo/layermap.c +++ b/lib/src/phy/mimo/layermap.c @@ -29,8 +29,8 @@ #include #include -#include "srslte/common/phy_common.h" -#include "srslte/mimo/layermap.h" +#include "srslte/phy/common/phy_common.h" +#include "srslte/phy/mimo/layermap.h" diff --git a/srslte/lib/mimo/precoding.c b/lib/src/phy/mimo/precoding.c similarity index 99% rename from srslte/lib/mimo/precoding.c rename to lib/src/phy/mimo/precoding.c index 289c6a981..8781dbad2 100644 --- a/srslte/lib/mimo/precoding.c +++ b/lib/src/phy/mimo/precoding.c @@ -30,9 +30,9 @@ #include #include -#include "srslte/common/phy_common.h" -#include "srslte/mimo/precoding.h" -#include "srslte/utils/vector.h" +#include "srslte/phy/common/phy_common.h" +#include "srslte/phy/mimo/precoding.h" +#include "srslte/phy/utils/vector.h" #ifdef LV_HAVE_SSE #include diff --git a/srslte/lib/mimo/test/CMakeLists.txt b/lib/src/phy/mimo/test/CMakeLists.txt similarity index 91% rename from srslte/lib/mimo/test/CMakeLists.txt rename to lib/src/phy/mimo/test/CMakeLists.txt index 9fe369779..e0e5578d5 100644 --- a/srslte/lib/mimo/test/CMakeLists.txt +++ b/lib/src/phy/mimo/test/CMakeLists.txt @@ -1,7 +1,7 @@ # -# Copyright 2013-2015 Software Radio Systems Limited +# Copyright 2013-2017 Software Radio Systems Limited # -# This file is part of the srsLTE library. +# 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 @@ -23,7 +23,7 @@ ######################################################################## add_executable(layermap_test layermap_test.c) -target_link_libraries(layermap_test srslte) +target_link_libraries(layermap_test srslte_phy) add_test(layermap_single layermap_test -n 1000 -m single -c 1 -l 1) @@ -46,7 +46,7 @@ add_test(layermap_multiplex_24 layermap_test -n 1000 -m multiplex -c 2 -l 4) ######################################################################## add_executable(precoding_test precoder_test.c) -target_link_libraries(precoding_test srslte) +target_link_libraries(precoding_test srslte_phy) add_test(precoding_single precoding_test -n 1000 -m single) add_test(precoding_diversity2 precoding_test -n 1000 -m diversity -l 2 -p 2) diff --git a/srslte/lib/mimo/test/layermap_test.c b/lib/src/phy/mimo/test/layermap_test.c similarity index 100% rename from srslte/lib/mimo/test/layermap_test.c rename to lib/src/phy/mimo/test/layermap_test.c diff --git a/srslte/lib/mimo/test/precoder_mex.c b/lib/src/phy/mimo/test/precoder_mex.c similarity index 100% rename from srslte/lib/mimo/test/precoder_mex.c rename to lib/src/phy/mimo/test/precoder_mex.c diff --git a/srslte/lib/mimo/test/precoder_test.c b/lib/src/phy/mimo/test/precoder_test.c similarity index 100% rename from srslte/lib/mimo/test/precoder_test.c rename to lib/src/phy/mimo/test/precoder_test.c diff --git a/srslte/lib/mimo/test/predecoder_mex.c b/lib/src/phy/mimo/test/predecoder_mex.c similarity index 100% rename from srslte/lib/mimo/test/predecoder_mex.c rename to lib/src/phy/mimo/test/predecoder_mex.c diff --git a/srslte/lib/modem/CMakeLists.txt b/lib/src/phy/modem/CMakeLists.txt similarity index 89% rename from srslte/lib/modem/CMakeLists.txt rename to lib/src/phy/modem/CMakeLists.txt index 01d609913..654446610 100644 --- a/srslte/lib/modem/CMakeLists.txt +++ b/lib/src/phy/modem/CMakeLists.txt @@ -1,7 +1,7 @@ # -# Copyright 2013-2015 Software Radio Systems Limited +# Copyright 2013-2017 Software Radio Systems Limited # -# This file is part of the srsLTE library. +# 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 diff --git a/srslte/lib/modem/demod_hard.c b/lib/src/phy/modem/demod_hard.c similarity index 97% rename from srslte/lib/modem/demod_hard.c rename to lib/src/phy/modem/demod_hard.c index cfbfc26ff..76f54236d 100644 --- a/srslte/lib/modem/demod_hard.c +++ b/lib/src/phy/modem/demod_hard.c @@ -28,7 +28,7 @@ #include #include -#include "srslte/modem/demod_hard.h" +#include "srslte/phy/modem/demod_hard.h" #include "hard_demod_lte.h" diff --git a/srslte/lib/modem/demod_soft.c b/lib/src/phy/modem/demod_soft.c similarity index 98% rename from srslte/lib/modem/demod_soft.c rename to lib/src/phy/modem/demod_soft.c index ca3c504cf..259a12271 100644 --- a/srslte/lib/modem/demod_soft.c +++ b/lib/src/phy/modem/demod_soft.c @@ -28,9 +28,9 @@ #include #include -#include "srslte/utils/vector.h" -#include "srslte/utils/bit.h" -#include "srslte/modem/demod_soft.h" +#include "srslte/phy/utils/vector.h" +#include "srslte/phy/utils/bit.h" +#include "srslte/phy/modem/demod_soft.h" // AVX implementation not useful for integers. Wait for AVX2 diff --git a/srslte/lib/modem/hard_demod_lte.c b/lib/src/phy/modem/hard_demod_lte.c similarity index 99% rename from srslte/lib/modem/hard_demod_lte.c rename to lib/src/phy/modem/hard_demod_lte.c index da0f1d23e..c1cf36283 100644 --- a/srslte/lib/modem/hard_demod_lte.c +++ b/lib/src/phy/modem/hard_demod_lte.c @@ -29,7 +29,7 @@ #include #include -#include "srslte/modem/demod_hard.h" +#include "srslte/phy/modem/demod_hard.h" #include "hard_demod_lte.h" diff --git a/srslte/lib/modem/hard_demod_lte.h b/lib/src/phy/modem/hard_demod_lte.h similarity index 100% rename from srslte/lib/modem/hard_demod_lte.h rename to lib/src/phy/modem/hard_demod_lte.h diff --git a/srslte/lib/modem/lte_tables.c b/lib/src/phy/modem/lte_tables.c similarity index 99% rename from srslte/lib/modem/lte_tables.c rename to lib/src/phy/modem/lte_tables.c index bc221f55d..d15fa36fb 100644 --- a/srslte/lib/modem/lte_tables.c +++ b/lib/src/phy/modem/lte_tables.c @@ -30,7 +30,7 @@ #include #include -#include "srslte/modem/modem_table.h" +#include "srslte/phy/modem/modem_table.h" #include "lte_tables.h" /** diff --git a/srslte/lib/modem/lte_tables.h b/lib/src/phy/modem/lte_tables.h similarity index 100% rename from srslte/lib/modem/lte_tables.h rename to lib/src/phy/modem/lte_tables.h diff --git a/srslte/lib/modem/mod.c b/lib/src/phy/modem/mod.c similarity index 98% rename from srslte/lib/modem/mod.c rename to lib/src/phy/modem/mod.c index 309a92f43..b72fdd133 100644 --- a/srslte/lib/modem/mod.c +++ b/lib/src/phy/modem/mod.c @@ -30,8 +30,8 @@ #include #include -#include "srslte/utils/bit.h" -#include "srslte/modem/mod.h" +#include "srslte/phy/utils/bit.h" +#include "srslte/phy/modem/mod.h" /** Low-level API */ diff --git a/srslte/lib/modem/modem_table.c b/lib/src/phy/modem/modem_table.c similarity index 97% rename from srslte/lib/modem/modem_table.c rename to lib/src/phy/modem/modem_table.c index 6c3b8a0c5..c19e52e77 100644 --- a/srslte/lib/modem/modem_table.c +++ b/lib/src/phy/modem/modem_table.c @@ -32,9 +32,9 @@ #include #include -#include "srslte/common/phy_common.h" -#include "srslte/modem/modem_table.h" -#include "srslte/utils/vector.h" +#include "srslte/phy/common/phy_common.h" +#include "srslte/phy/modem/modem_table.h" +#include "srslte/phy/utils/vector.h" #include "lte_tables.h" /** Internal functions */ diff --git a/srslte/lib/modem/test/CMakeLists.txt b/lib/src/phy/modem/test/CMakeLists.txt similarity index 87% rename from srslte/lib/modem/test/CMakeLists.txt rename to lib/src/phy/modem/test/CMakeLists.txt index f3bff6175..4d28d2fca 100644 --- a/srslte/lib/modem/test/CMakeLists.txt +++ b/lib/src/phy/modem/test/CMakeLists.txt @@ -1,7 +1,7 @@ # -# Copyright 2013-2015 Software Radio Systems Limited +# Copyright 2013-2017 Software Radio Systems Limited # -# This file is part of the srsLTE library. +# 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 @@ -23,7 +23,7 @@ ######################################################################## add_executable(modem_test modem_test.c) -target_link_libraries(modem_test srslte) +target_link_libraries(modem_test srslte_phy) add_test(modem_bpsk modem_test -n 1024 -m 1) add_test(modem_qpsk modem_test -n 1024 -m 2) @@ -36,7 +36,7 @@ add_test(modem_qam16_soft modem_test -n 1024 -m 4) add_test(modem_qam64_soft modem_test -n 1008 -m 6) add_executable(soft_demod_test soft_demod_test.c) -target_link_libraries(soft_demod_test srslte) +target_link_libraries(soft_demod_test srslte_phy) diff --git a/srslte/lib/modem/test/modem_test.c b/lib/src/phy/modem/test/modem_test.c similarity index 100% rename from srslte/lib/modem/test/modem_test.c rename to lib/src/phy/modem/test/modem_test.c diff --git a/srslte/lib/modem/test/soft_demod_test.c b/lib/src/phy/modem/test/soft_demod_test.c similarity index 100% rename from srslte/lib/modem/test/soft_demod_test.c rename to lib/src/phy/modem/test/soft_demod_test.c diff --git a/srslte/lib/phch/CMakeLists.txt b/lib/src/phy/phch/CMakeLists.txt similarity index 89% rename from srslte/lib/phch/CMakeLists.txt rename to lib/src/phy/phch/CMakeLists.txt index bc07d53d2..b6c511bd5 100644 --- a/srslte/lib/phch/CMakeLists.txt +++ b/lib/src/phy/phch/CMakeLists.txt @@ -1,7 +1,7 @@ # -# Copyright 2013-2015 Software Radio Systems Limited +# Copyright 2013-2017 Software Radio Systems Limited # -# This file is part of the srsLTE library. +# 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 diff --git a/srslte/lib/phch/cqi.c b/lib/src/phy/phch/cqi.c similarity index 97% rename from srslte/lib/phch/cqi.c rename to lib/src/phy/phch/cqi.c index 5ac536341..a684db8c9 100644 --- a/srslte/lib/phch/cqi.c +++ b/lib/src/phy/phch/cqi.c @@ -33,11 +33,11 @@ #include #include -#include "srslte/phch/cqi.h" -#include "srslte/common/phy_common.h" -#include "srslte/utils/bit.h" -#include "srslte/utils/vector.h" -#include "srslte/utils/debug.h" +#include "srslte/phy/phch/cqi.h" +#include "srslte/phy/common/phy_common.h" +#include "srslte/phy/utils/bit.h" +#include "srslte/phy/utils/vector.h" +#include "srslte/phy/utils/debug.h" /******************************************************* * PACKING FUNCTIONS * diff --git a/srslte/lib/phch/dci.c b/lib/src/phy/phch/dci.c similarity index 97% rename from srslte/lib/phch/dci.c rename to lib/src/phy/phch/dci.c index df986867d..96c446259 100644 --- a/srslte/lib/phch/dci.c +++ b/lib/src/phy/phch/dci.c @@ -33,15 +33,15 @@ #include #include -#include "srslte/phch/dci.h" -#include "srslte/common/phy_common.h" -#include "srslte/utils/bit.h" -#include "srslte/utils/vector.h" -#include "srslte/utils/debug.h" +#include "srslte/phy/phch/dci.h" +#include "srslte/phy/common/phy_common.h" +#include "srslte/phy/utils/bit.h" +#include "srslte/phy/utils/vector.h" +#include "srslte/phy/utils/debug.h" #include "dci_sz_table.h" -int harq_pid_len = 3; +#define HARQ_PID_LEN 3 /* Unpacks a DCI message and configures the DL grant object */ @@ -240,7 +240,7 @@ uint32_t dci_format0_sizeof_(uint32_t nof_prb) { uint32_t dci_format1A_sizeof(uint32_t nof_prb) { uint32_t n; - n = 1 + 1 + riv_nbits(nof_prb) + 5 + harq_pid_len + 1 + 2 + 2; + n = 1 + 1 + riv_nbits(nof_prb) + 5 + HARQ_PID_LEN + 1 + 2 + 2; while (n < dci_format0_sizeof_(nof_prb)) { n++; } @@ -260,7 +260,7 @@ uint32_t dci_format0_sizeof(uint32_t nof_prb) { uint32_t dci_format1_sizeof(uint32_t nof_prb) { - uint32_t n = (uint32_t) ceilf((float) nof_prb / srslte_ra_type0_P(nof_prb)) + 5 + harq_pid_len + 1 + 2 + uint32_t n = (uint32_t) ceilf((float) nof_prb / srslte_ra_type0_P(nof_prb)) + 5 + HARQ_PID_LEN + 1 + 2 + 2; if (nof_prb > 10) { n++; @@ -316,7 +316,7 @@ uint32_t precoding_bits_f2(uint32_t nof_ports) { } uint32_t dci_format2_sizeof(uint32_t nof_prb, uint32_t nof_ports) { - uint32_t n = (uint32_t) ceilf((float) nof_prb / srslte_ra_type0_P(nof_prb))+2+harq_pid_len+1+2*(5+1+2)+precoding_bits_f2(nof_ports); + uint32_t n = (uint32_t) ceilf((float) nof_prb / srslte_ra_type0_P(nof_prb))+2+HARQ_PID_LEN+1+2*(5+1+2)+precoding_bits_f2(nof_ports); if (nof_prb > 10) { n++; } @@ -336,7 +336,7 @@ uint32_t precoding_bits_f2a(uint32_t nof_ports) { } uint32_t dci_format2A_sizeof(uint32_t nof_prb, uint32_t nof_ports) { - uint32_t n = (uint32_t) ceilf((float) nof_prb / srslte_ra_type0_P(nof_prb))+2+harq_pid_len+1+2*(5+1+2)+precoding_bits_f2a(nof_ports); + uint32_t n = (uint32_t) ceilf((float) nof_prb / srslte_ra_type0_P(nof_prb))+2+HARQ_PID_LEN+1+2*(5+1+2)+precoding_bits_f2a(nof_ports); if (nof_prb > 10) { n++; } @@ -348,7 +348,7 @@ uint32_t dci_format2A_sizeof(uint32_t nof_prb, uint32_t nof_ports) { } uint32_t dci_format2B_sizeof(uint32_t nof_prb, uint32_t nof_ports) { - uint32_t n = (uint32_t) ceilf((float) nof_prb / srslte_ra_type0_P(nof_prb))+2+harq_pid_len+1+2*(5+1+2); + uint32_t n = (uint32_t) ceilf((float) nof_prb / srslte_ra_type0_P(nof_prb))+2+HARQ_PID_LEN+1+2*(5+1+2); if (nof_prb > 10) { n++; } @@ -556,7 +556,7 @@ int dci_format1_pack(srslte_ra_dl_dci_t *data, srslte_dci_msg_t *msg, uint32_t n srslte_bit_unpack(data->mcs_idx, &y, 5); /* harq process number */ - srslte_bit_unpack(data->harq_process, &y, harq_pid_len); + srslte_bit_unpack(data->harq_process, &y, HARQ_PID_LEN); *y++ = data->ndi; @@ -615,7 +615,7 @@ int dci_format1_unpack(srslte_dci_msg_t *msg, srslte_ra_dl_dci_t *data, uint32_t data->mcs_idx = srslte_bit_pack(&y, 5); /* harq process number */ - data->harq_process = srslte_bit_pack(&y, harq_pid_len); + data->harq_process = srslte_bit_pack(&y, HARQ_PID_LEN); data->ndi = *y++ ? true : false; // rv version @@ -688,7 +688,7 @@ int dci_format1As_pack(srslte_ra_dl_dci_t *data, srslte_dci_msg_t *msg, uint32_t // in format1A, MCS = TBS according to 7.1.7.2 of 36.213 srslte_bit_unpack(data->mcs_idx, &y, 5); - srslte_bit_unpack(data->harq_process, &y, harq_pid_len); + srslte_bit_unpack(data->harq_process, &y, HARQ_PID_LEN); if (crc_is_crnti) { if (nof_prb >= 50 && data->type2_alloc.mode == SRSLTE_RA_TYPE2_DIST) { @@ -789,7 +789,7 @@ int dci_format1As_unpack(srslte_dci_msg_t *msg, srslte_ra_dl_dci_t *data, uint32 // unpack MCS data->mcs_idx = srslte_bit_pack(&y, 5); - data->harq_process = srslte_bit_pack(&y, harq_pid_len); + data->harq_process = srslte_bit_pack(&y, HARQ_PID_LEN); if (!crc_is_crnti) { if (nof_prb >= 50 && data->type2_alloc.mode == SRSLTE_RA_TYPE2_DIST) { @@ -850,7 +850,7 @@ int dci_format1B_unpack(srslte_dci_msg_t *msg, srslte_ra_dl_dci_t *data, uint32_ // unpack MCS, Harq pid and ndi data->mcs_idx = srslte_bit_pack(&y, 5); - data->harq_process = srslte_bit_pack(&y, harq_pid_len); + data->harq_process = srslte_bit_pack(&y, HARQ_PID_LEN); data->ndi = *y++ ? true : false; data->rv_idx = srslte_bit_pack(&y, 2); @@ -993,7 +993,7 @@ int dci_format1D_unpack(srslte_dci_msg_t *msg, srslte_ra_dl_dci_t *data, uint32_ // unpack MCS, Harq pid and ndi data->mcs_idx = srslte_bit_pack(&y, 5); - data->harq_process = srslte_bit_pack(&y, harq_pid_len); + data->harq_process = srslte_bit_pack(&y, HARQ_PID_LEN); data->ndi = *y++ ? true : false; data->rv_idx = srslte_bit_pack(&y, 2); @@ -1043,7 +1043,7 @@ int dci_format2AB_pack(srslte_ra_dl_dci_t *data, srslte_dci_msg_t *msg, uint32_t y+=2; /* harq process number */ - srslte_bit_unpack(data->harq_process, &y, harq_pid_len); + srslte_bit_unpack(data->harq_process, &y, HARQ_PID_LEN); // Transpor block to codeword swap flag if (msg->format == SRSLTE_DCI_FORMAT2B) { @@ -1114,7 +1114,7 @@ int dci_format2AB_unpack(srslte_dci_msg_t *msg, srslte_ra_dl_dci_t *data, uint32 y+=2; /* harq process number */ - data->harq_process = srslte_bit_pack(&y, harq_pid_len); + data->harq_process = srslte_bit_pack(&y, HARQ_PID_LEN); // Transpor block to codeword swap flag if (msg->format == SRSLTE_DCI_FORMAT2B) { diff --git a/srslte/lib/phch/dci_sz_table.h b/lib/src/phy/phch/dci_sz_table.h similarity index 100% rename from srslte/lib/phch/dci_sz_table.h rename to lib/src/phy/phch/dci_sz_table.h diff --git a/srslte/lib/phch/pbch.c b/lib/src/phy/phch/pbch.c similarity index 98% rename from srslte/lib/phch/pbch.c rename to lib/src/phy/phch/pbch.c index d1dd0026a..bff7b0619 100644 --- a/srslte/lib/phch/pbch.c +++ b/lib/src/phy/phch/pbch.c @@ -34,11 +34,11 @@ #include #include "prb_dl.h" -#include "srslte/phch/pbch.h" -#include "srslte/common/phy_common.h" -#include "srslte/utils/bit.h" -#include "srslte/utils/vector.h" -#include "srslte/utils/debug.h" +#include "srslte/phy/phch/pbch.h" +#include "srslte/phy/common/phy_common.h" +#include "srslte/phy/utils/bit.h" +#include "srslte/phy/utils/vector.h" +#include "srslte/phy/utils/debug.h" #define PBCH_RE_CP_NORM 240 #define PBCH_RE_CP_EXT 216 diff --git a/srslte/lib/phch/pcfich.c b/lib/src/phy/phch/pcfich.c similarity index 97% rename from srslte/lib/phch/pcfich.c rename to lib/src/phy/phch/pcfich.c index a8290f6fc..ec1e13abc 100644 --- a/srslte/lib/phch/pcfich.c +++ b/lib/src/phy/phch/pcfich.c @@ -33,12 +33,12 @@ #include #include -#include "srslte/phch/regs.h" -#include "srslte/phch/pcfich.h" -#include "srslte/common/phy_common.h" -#include "srslte/utils/bit.h" -#include "srslte/utils/vector.h" -#include "srslte/utils/debug.h" +#include "srslte/phy/phch/regs.h" +#include "srslte/phy/phch/pcfich.h" +#include "srslte/phy/common/phy_common.h" +#include "srslte/phy/utils/bit.h" +#include "srslte/phy/utils/vector.h" +#include "srslte/phy/utils/debug.h" // Table 5.3.4-1 static uint8_t cfi_table[4][PCFICH_CFI_LEN] = { diff --git a/srslte/lib/phch/pdcch.c b/lib/src/phy/phch/pdcch.c similarity index 97% rename from srslte/lib/phch/pdcch.c rename to lib/src/phy/phch/pdcch.c index 8b1d3ab52..cfdb19621 100644 --- a/srslte/lib/phch/pdcch.c +++ b/lib/src/phy/phch/pdcch.c @@ -32,13 +32,13 @@ #include #include -#include "srslte/phch/dci.h" -#include "srslte/phch/regs.h" -#include "srslte/phch/pdcch.h" -#include "srslte/common/phy_common.h" -#include "srslte/utils/bit.h" -#include "srslte/utils/vector.h" -#include "srslte/utils/debug.h" +#include "srslte/phy/phch/dci.h" +#include "srslte/phy/phch/regs.h" +#include "srslte/phy/phch/pdcch.h" +#include "srslte/phy/common/phy_common.h" +#include "srslte/phy/utils/bit.h" +#include "srslte/phy/utils/vector.h" +#include "srslte/phy/utils/debug.h" #define PDCCH_NOF_FORMATS 4 #define PDCCH_FORMAT_NOF_CCE(i) (1<= 0; l--) { L = (1 << l); - // For all possible ncce offset - for (i = 0; i < SRSLTE_MIN(nof_cce / L, S[l]/PDCCH_FORMAT_NOF_CCE(l)); i++) { + // For all candidates as given in table 9.1.1-1 + for (i = 0; i < nof_candidates[l]; i++) { if (nof_cce >= L) { - ncce = L * ((Yk + i) % (nof_cce / L)); + ncce = L * ((Yk + i) % (nof_cce / L)); + // Check if candidate fits in c vector and in CCE region if (k < max_candidates && ncce + L <= nof_cce) { c[k].L = l; diff --git a/srslte/lib/phch/pdsch.c b/lib/src/phy/phch/pdsch.c similarity index 98% rename from srslte/lib/phch/pdsch.c rename to lib/src/phy/phch/pdsch.c index 9a2281753..1b61cd5f4 100644 --- a/srslte/lib/phch/pdsch.c +++ b/lib/src/phy/phch/pdsch.c @@ -34,12 +34,12 @@ #include #include "prb_dl.h" -#include "srslte/phch/pdsch.h" -#include "srslte/phch/sch.h" -#include "srslte/common/phy_common.h" -#include "srslte/utils/bit.h" -#include "srslte/utils/debug.h" -#include "srslte/utils/vector.h" +#include "srslte/phy/phch/pdsch.h" +#include "srslte/phy/phch/sch.h" +#include "srslte/phy/common/phy_common.h" +#include "srslte/phy/utils/bit.h" +#include "srslte/phy/utils/debug.h" +#include "srslte/phy/utils/vector.h" #define MAX_PDSCH_RE(cp) (2 * SRSLTE_CP_NSYMB(cp) * 12) @@ -542,7 +542,7 @@ int srslte_pdsch_encode(srslte_pdsch_t *q, if (srslte_sequence_pdsch(&seq, rnti, 0, 2 * cfg->sf_idx, q->cell.id, cfg->nbits.nof_bits)) { return SRSLTE_ERROR; } - srslte_scrambling_bytes(&q->users[rnti]->seq[cfg->sf_idx], (uint8_t*) q->e, cfg->nbits.nof_bits); + srslte_scrambling_bytes(&seq, (uint8_t*) q->e, cfg->nbits.nof_bits); srslte_sequence_free(&seq); } else { srslte_scrambling_bytes(&q->users[rnti]->seq[cfg->sf_idx], (uint8_t*) q->e, cfg->nbits.nof_bits); diff --git a/srslte/lib/phch/phich.c b/lib/src/phy/phch/phich.c similarity index 98% rename from srslte/lib/phch/phich.c rename to lib/src/phy/phch/phich.c index f7e6d7d29..7de2f5d37 100644 --- a/srslte/lib/phch/phich.c +++ b/lib/src/phy/phch/phich.c @@ -33,12 +33,12 @@ #include #include -#include "srslte/phch/regs.h" -#include "srslte/phch/phich.h" -#include "srslte/common/phy_common.h" -#include "srslte/utils/bit.h" -#include "srslte/utils/vector.h" -#include "srslte/utils/debug.h" +#include "srslte/phy/phch/regs.h" +#include "srslte/phy/phch/phich.h" +#include "srslte/phy/common/phy_common.h" +#include "srslte/phy/utils/bit.h" +#include "srslte/phy/utils/vector.h" +#include "srslte/phy/utils/debug.h" /** Table 6.9.1-2 */ const cf_t w_normal[SRSLTE_PHICH_NORM_NSEQUENCES][4] = { { 1, 1, 1, 1 }, diff --git a/srslte/lib/phch/prach.c b/lib/src/phy/phch/prach.c similarity index 99% rename from srslte/lib/phch/prach.c rename to lib/src/phy/phch/prach.c index 61a851705..5a2169fd9 100644 --- a/srslte/lib/phch/prach.c +++ b/lib/src/phy/phch/prach.c @@ -27,10 +27,10 @@ #include #include -#include "srslte/common/phy_common.h" -#include "srslte/phch/prach.h" -#include "srslte/utils/debug.h" -#include "srslte/utils/vector.h" +#include "srslte/phy/common/phy_common.h" +#include "srslte/phy/phch/prach.h" +#include "srslte/phy/utils/debug.h" +#include "srslte/phy/utils/vector.h" float save_corr[4096]; diff --git a/srslte/lib/phch/prb_dl.c b/lib/src/phy/phch/prb_dl.c similarity index 98% rename from srslte/lib/phch/prb_dl.c rename to lib/src/phy/phch/prb_dl.c index 8b81e130e..ac8d6f346 100644 --- a/srslte/lib/phch/prb_dl.c +++ b/lib/src/phy/phch/prb_dl.c @@ -29,7 +29,7 @@ #include #include "prb_dl.h" -#include "srslte/common/phy_common.h" +#include "srslte/phy/common/phy_common.h" //#define DEBUG_IDX diff --git a/srslte/lib/phch/prb_dl.h b/lib/src/phy/phch/prb_dl.h similarity index 100% rename from srslte/lib/phch/prb_dl.h rename to lib/src/phy/phch/prb_dl.h diff --git a/srslte/lib/phch/pucch.c b/lib/src/phy/phch/pucch.c similarity index 98% rename from srslte/lib/phch/pucch.c rename to lib/src/phy/phch/pucch.c index 443dd57bd..c58f69871 100644 --- a/srslte/lib/phch/pucch.c +++ b/lib/src/phy/phch/pucch.c @@ -34,15 +34,15 @@ #include #include -#include "srslte/ch_estimation/refsignal_ul.h" -#include "srslte/phch/pucch.h" -#include "srslte/common/sequence.h" -#include "srslte/common/phy_common.h" -#include "srslte/mimo/precoding.h" -#include "srslte/scrambling/scrambling.h" -#include "srslte/utils/debug.h" -#include "srslte/utils/vector.h" -#include "srslte/modem/demod_soft.h" +#include "srslte/phy/ch_estimation/refsignal_ul.h" +#include "srslte/phy/phch/pucch.h" +#include "srslte/phy/common/sequence.h" +#include "srslte/phy/common/phy_common.h" +#include "srslte/phy/mimo/precoding.h" +#include "srslte/phy/scrambling/scrambling.h" +#include "srslte/phy/utils/debug.h" +#include "srslte/phy/utils/vector.h" +#include "srslte/phy/modem/demod_soft.h" #define MAX_PUSCH_RE(cp) (2 * SRSLTE_CP_NSYMB(cp) * 12) diff --git a/srslte/lib/phch/pusch.c b/lib/src/phy/phch/pusch.c similarity index 98% rename from srslte/lib/phch/pusch.c rename to lib/src/phy/phch/pusch.c index f82173f54..65ab08411 100644 --- a/srslte/lib/phch/pusch.c +++ b/lib/src/phy/phch/pusch.c @@ -33,15 +33,15 @@ #include #include -#include "srslte/ch_estimation/refsignal_ul.h" -#include "srslte/phch/pusch.h" -#include "srslte/phch/pusch_cfg.h" -#include "srslte/phch/uci.h" -#include "srslte/common/phy_common.h" -#include "srslte/utils/bit.h" -#include "srslte/utils/debug.h" -#include "srslte/utils/vector.h" -#include "srslte/dft/dft_precoding.h" +#include "srslte/phy/ch_estimation/refsignal_ul.h" +#include "srslte/phy/phch/pusch.h" +#include "srslte/phy/phch/pusch_cfg.h" +#include "srslte/phy/phch/uci.h" +#include "srslte/phy/common/phy_common.h" +#include "srslte/phy/utils/bit.h" +#include "srslte/phy/utils/debug.h" +#include "srslte/phy/utils/vector.h" +#include "srslte/phy/dft/dft_precoding.h" #define MAX_PUSCH_RE(cp) (2 * SRSLTE_CP_NSYMB(cp) * 12) diff --git a/srslte/lib/phch/ra.c b/lib/src/phy/phch/ra.c similarity index 99% rename from srslte/lib/phch/ra.c rename to lib/src/phy/phch/ra.c index 678b61cc9..cd07e997f 100644 --- a/srslte/lib/phch/ra.c +++ b/lib/src/phy/phch/ra.c @@ -28,12 +28,12 @@ #include #include #include -#include "srslte/common/phy_common.h" -#include "srslte/utils/bit.h" -#include "srslte/utils/vector.h" -#include "srslte/utils/debug.h" -#include "srslte/phch/ra.h" -#include "srslte/utils/bit.h" +#include "srslte/phy/common/phy_common.h" +#include "srslte/phy/utils/bit.h" +#include "srslte/phy/utils/vector.h" +#include "srslte/phy/utils/debug.h" +#include "srslte/phy/phch/ra.h" +#include "srslte/phy/utils/bit.h" #include "tbs_tables.h" diff --git a/srslte/lib/phch/regs.c b/lib/src/phy/phch/regs.c similarity index 99% rename from srslte/lib/phch/regs.c rename to lib/src/phy/phch/regs.c index 8ada33e7f..6d6c8ab2e 100644 --- a/srslte/lib/phch/regs.c +++ b/lib/src/phy/phch/regs.c @@ -29,9 +29,9 @@ #include #include -#include "srslte/common/phy_common.h" -#include "srslte/phch/regs.h" -#include "srslte/utils/debug.h" +#include "srslte/phy/common/phy_common.h" +#include "srslte/phy/phch/regs.h" +#include "srslte/phy/utils/debug.h" #define REG_IDX(r, i, n) r->k[i]+r->l*n*SRSLTE_NRE diff --git a/srslte/lib/phch/sch.c b/lib/src/phy/phch/sch.c similarity index 98% rename from srslte/lib/phch/sch.c rename to lib/src/phy/phch/sch.c index 3b521f794..b7a5cfc28 100644 --- a/srslte/lib/phch/sch.c +++ b/lib/src/phy/phch/sch.c @@ -33,14 +33,14 @@ #include #include -#include "srslte/phch/pdsch.h" -#include "srslte/phch/pusch.h" -#include "srslte/phch/sch.h" -#include "srslte/phch/uci.h" -#include "srslte/common/phy_common.h" -#include "srslte/utils/bit.h" -#include "srslte/utils/debug.h" -#include "srslte/utils/vector.h" +#include "srslte/phy/phch/pdsch.h" +#include "srslte/phy/phch/pusch.h" +#include "srslte/phy/phch/sch.h" +#include "srslte/phy/phch/uci.h" +#include "srslte/phy/common/phy_common.h" +#include "srslte/phy/utils/bit.h" +#include "srslte/phy/utils/debug.h" +#include "srslte/phy/utils/vector.h" #define SRSLTE_PDSCH_MAX_TDEC_ITERS 4 diff --git a/srslte/lib/phch/sequences.c b/lib/src/phy/phch/sequences.c similarity index 96% rename from srslte/lib/phch/sequences.c rename to lib/src/phy/phch/sequences.c index c731f526b..2816709b4 100644 --- a/srslte/lib/phch/sequences.c +++ b/lib/src/phy/phch/sequences.c @@ -26,8 +26,8 @@ #include -#include "srslte/common/phy_common.h" -#include "srslte/common/sequence.h" +#include "srslte/phy/common/phy_common.h" +#include "srslte/phy/common/sequence.h" /** * 36.211 6.6.1 diff --git a/srslte/lib/phch/tbs_tables.h b/lib/src/phy/phch/tbs_tables.h similarity index 100% rename from srslte/lib/phch/tbs_tables.h rename to lib/src/phy/phch/tbs_tables.h diff --git a/srslte/lib/phch/test/CMakeLists.txt b/lib/src/phy/phch/test/CMakeLists.txt similarity index 87% rename from srslte/lib/phch/test/CMakeLists.txt rename to lib/src/phy/phch/test/CMakeLists.txt index b4b7e0836..d86302f68 100644 --- a/srslte/lib/phch/test/CMakeLists.txt +++ b/lib/src/phy/phch/test/CMakeLists.txt @@ -1,7 +1,7 @@ # -# Copyright 2013-2015 Software Radio Systems Limited +# Copyright 2013-2017 Software Radio Systems Limited # -# This file is part of the srsLTE library. +# 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 @@ -23,7 +23,7 @@ ######################################################################## add_executable(pbch_test pbch_test.c) -target_link_libraries(pbch_test srslte) +target_link_libraries(pbch_test srslte_phy) add_test(pbch_test_6 pbch_test -p 1 -n 6 -c 100) add_test(pbch_test_62 pbch_test -p 2 -n 6 -c 100) @@ -38,7 +38,7 @@ add_test(pbch_test_504 pbch_test -p 4 -n 50 -c 50) ######################################################################## add_executable(pcfich_test pcfich_test.c) -target_link_libraries(pcfich_test srslte) +target_link_libraries(pcfich_test srslte_phy) add_test(pcfich_test_6 pcfich_test -p 1 -n 6) add_test(pcfich_test_62 pcfich_test -p 2 -n 6) @@ -52,7 +52,7 @@ add_test(pcfich_test_104 pcfich_test -p 4 -n 10) ######################################################################## add_executable(phich_test phich_test.c) -target_link_libraries(phich_test srslte) +target_link_libraries(phich_test srslte_phy) add_test(phich_test_6 phich_test -p 1 -n 6) add_test(phich_test_62 phich_test -p 2 -n 6) @@ -71,7 +71,7 @@ add_test(phich_test_104 phich_test -p 4 -n 10 -e -l -g 1/2) ######################################################################## add_executable(pdcch_test pdcch_test.c) -target_link_libraries(pdcch_test srslte) +target_link_libraries(pdcch_test srslte_phy) add_test(pdcch_test pdcch_test) @@ -80,7 +80,7 @@ add_test(pdcch_test pdcch_test) ######################################################################## add_executable(pdsch_test pdsch_test.c) -target_link_libraries(pdsch_test srslte) +target_link_libraries(pdsch_test srslte_phy) add_test(pdsch_test_qpsk pdsch_test -m 10 -n 50 -r 1) add_test(pdsch_test_qam16 pdsch_test -m 20 -n 100) @@ -92,19 +92,19 @@ add_test(pdsch_test_qam64 pdsch_test -m 28 -n 100) ######################################################################## add_executable(pbch_file_test pbch_file_test.c) -target_link_libraries(pbch_file_test srslte) +target_link_libraries(pbch_file_test srslte_phy) add_executable(pcfich_file_test pcfich_file_test.c) -target_link_libraries(pcfich_file_test srslte) +target_link_libraries(pcfich_file_test srslte_phy) add_executable(phich_file_test phich_file_test.c) -target_link_libraries(phich_file_test srslte) +target_link_libraries(phich_file_test srslte_phy) add_executable(pdcch_file_test pdcch_file_test.c) -target_link_libraries(pdcch_file_test srslte) +target_link_libraries(pdcch_file_test srslte_phy) add_executable(pdsch_pdcch_file_test pdsch_pdcch_file_test.c) -target_link_libraries(pdsch_pdcch_file_test srslte) +target_link_libraries(pdsch_pdcch_file_test srslte_phy) add_test(pbch_file_test pbch_file_test -i ${CMAKE_CURRENT_SOURCE_DIR}/signal.1.92M.dat) add_test(pcfich_file_test pcfich_file_test -c 150 -n 50 -p 2 -i ${CMAKE_CURRENT_SOURCE_DIR}/signal.10M.dat) @@ -117,7 +117,7 @@ add_test(pdsch_pdcch_file_test pdsch_pdcch_file_test -c 1 -f 3 -n 6 -p 1 -i ${CM ######################################################################## add_executable(pusch_test pusch_test.c) -target_link_libraries(pusch_test srslte) +target_link_libraries(pusch_test srslte_phy) add_test(pusch_test pusch_test) @@ -126,7 +126,7 @@ add_test(pusch_test pusch_test) ######################################################################## add_executable(pucch_test pucch_test.c) -target_link_libraries(pucch_test srslte) +target_link_libraries(pucch_test srslte_phy) add_test(pucch_test pucch_test) @@ -135,7 +135,7 @@ add_test(pucch_test pucch_test) ######################################################################## add_executable(prach_test prach_test.c) -target_link_libraries(prach_test srslte) +target_link_libraries(prach_test srslte_phy) add_test(prach prach_test) @@ -159,7 +159,7 @@ add_test(prach_zc2 prach_test -z 2) add_test(prach_zc3 prach_test -z 3) add_executable(prach_test_multi prach_test_multi.c) -target_link_libraries(prach_test_multi srslte) +target_link_libraries(prach_test_multi srslte_phy) add_test(prach_test_multi prach_test_multi) @@ -171,5 +171,5 @@ add_test(prach_test_multi_n4 prach_test_multi -n 4) if(UHD_FOUND) add_executable(prach_test_usrp prach_test_usrp.c) - target_link_libraries(prach_test_usrp srslte pthread) + target_link_libraries(prach_test_usrp srslte_phy pthread) endif(UHD_FOUND) diff --git a/srslte/lib/phch/test/dlsch_encode_test_mex.c b/lib/src/phy/phch/test/dlsch_encode_test_mex.c similarity index 100% rename from srslte/lib/phch/test/dlsch_encode_test_mex.c rename to lib/src/phy/phch/test/dlsch_encode_test_mex.c diff --git a/srslte/lib/phch/test/pbch_file_test.c b/lib/src/phy/phch/test/pbch_file_test.c similarity index 100% rename from srslte/lib/phch/test/pbch_file_test.c rename to lib/src/phy/phch/test/pbch_file_test.c diff --git a/srslte/lib/phch/test/pbch_test.c b/lib/src/phy/phch/test/pbch_test.c similarity index 100% rename from srslte/lib/phch/test/pbch_test.c rename to lib/src/phy/phch/test/pbch_test.c diff --git a/srslte/lib/phch/test/pbch_test_mex.c b/lib/src/phy/phch/test/pbch_test_mex.c similarity index 100% rename from srslte/lib/phch/test/pbch_test_mex.c rename to lib/src/phy/phch/test/pbch_test_mex.c diff --git a/srslte/lib/phch/test/pcfich_file_test.c b/lib/src/phy/phch/test/pcfich_file_test.c similarity index 100% rename from srslte/lib/phch/test/pcfich_file_test.c rename to lib/src/phy/phch/test/pcfich_file_test.c diff --git a/srslte/lib/phch/test/pcfich_test.c b/lib/src/phy/phch/test/pcfich_test.c similarity index 100% rename from srslte/lib/phch/test/pcfich_test.c rename to lib/src/phy/phch/test/pcfich_test.c diff --git a/srslte/lib/phch/test/pcfich_test_mex.c b/lib/src/phy/phch/test/pcfich_test_mex.c similarity index 100% rename from srslte/lib/phch/test/pcfich_test_mex.c rename to lib/src/phy/phch/test/pcfich_test_mex.c diff --git a/srslte/lib/phch/test/pdcch_file_test.c b/lib/src/phy/phch/test/pdcch_file_test.c similarity index 100% rename from srslte/lib/phch/test/pdcch_file_test.c rename to lib/src/phy/phch/test/pdcch_file_test.c diff --git a/srslte/lib/phch/test/pdcch_test.c b/lib/src/phy/phch/test/pdcch_test.c similarity index 100% rename from srslte/lib/phch/test/pdcch_test.c rename to lib/src/phy/phch/test/pdcch_test.c diff --git a/srslte/lib/phch/test/pdcch_test_mex.c b/lib/src/phy/phch/test/pdcch_test_mex.c similarity index 100% rename from srslte/lib/phch/test/pdcch_test_mex.c rename to lib/src/phy/phch/test/pdcch_test_mex.c diff --git a/srslte/lib/phch/test/pdsch_pdcch_file_test.c b/lib/src/phy/phch/test/pdsch_pdcch_file_test.c similarity index 100% rename from srslte/lib/phch/test/pdsch_pdcch_file_test.c rename to lib/src/phy/phch/test/pdsch_pdcch_file_test.c diff --git a/srslte/lib/phch/test/pdsch_test.c b/lib/src/phy/phch/test/pdsch_test.c similarity index 100% rename from srslte/lib/phch/test/pdsch_test.c rename to lib/src/phy/phch/test/pdsch_test.c diff --git a/srslte/lib/phch/test/pdsch_test_mex.c b/lib/src/phy/phch/test/pdsch_test_mex.c similarity index 100% rename from srslte/lib/phch/test/pdsch_test_mex.c rename to lib/src/phy/phch/test/pdsch_test_mex.c diff --git a/srslte/lib/phch/test/phich_file_test.c b/lib/src/phy/phch/test/phich_file_test.c similarity index 100% rename from srslte/lib/phch/test/phich_file_test.c rename to lib/src/phy/phch/test/phich_file_test.c diff --git a/srslte/lib/phch/test/phich_test.c b/lib/src/phy/phch/test/phich_test.c similarity index 100% rename from srslte/lib/phch/test/phich_test.c rename to lib/src/phy/phch/test/phich_test.c diff --git a/srslte/lib/phch/test/phich_test_mex.c b/lib/src/phy/phch/test/phich_test_mex.c similarity index 100% rename from srslte/lib/phch/test/phich_test_mex.c rename to lib/src/phy/phch/test/phich_test_mex.c diff --git a/srslte/lib/phch/test/prach_detect_test_mex.c b/lib/src/phy/phch/test/prach_detect_test_mex.c similarity index 100% rename from srslte/lib/phch/test/prach_detect_test_mex.c rename to lib/src/phy/phch/test/prach_detect_test_mex.c diff --git a/srslte/lib/phch/test/prach_test.c b/lib/src/phy/phch/test/prach_test.c similarity index 100% rename from srslte/lib/phch/test/prach_test.c rename to lib/src/phy/phch/test/prach_test.c diff --git a/srslte/lib/phch/test/prach_test_mex.c b/lib/src/phy/phch/test/prach_test_mex.c similarity index 100% rename from srslte/lib/phch/test/prach_test_mex.c rename to lib/src/phy/phch/test/prach_test_mex.c diff --git a/srslte/lib/phch/test/prach_test_multi.c b/lib/src/phy/phch/test/prach_test_multi.c similarity index 98% rename from srslte/lib/phch/test/prach_test_multi.c rename to lib/src/phy/phch/test/prach_test_multi.c index aa4d9a915..9e3dc1c97 100644 --- a/srslte/lib/phch/test/prach_test_multi.c +++ b/lib/src/phy/phch/test/prach_test_multi.c @@ -32,7 +32,7 @@ #include #include -#include "srslte/phch/prach.h" +#include "srslte/phy/phch/prach.h" #define MAX_LEN 70176 diff --git a/srslte/lib/phch/test/prach_test_usrp.c b/lib/src/phy/phch/test/prach_test_usrp.c similarity index 99% rename from srslte/lib/phch/test/prach_test_usrp.c rename to lib/src/phy/phch/test/prach_test_usrp.c index 0cd85e39d..f5f1a9e5c 100644 --- a/srslte/lib/phch/test/prach_test_usrp.c +++ b/lib/src/phy/phch/test/prach_test_usrp.c @@ -33,7 +33,7 @@ #include #include -#include "srslte/rf/rf.h" +#include "srslte/phy/rf/rf.h" #include "srslte/srslte.h" #define MAX_LEN 70176 diff --git a/srslte/lib/phch/test/pucch_encode_test_mex.c b/lib/src/phy/phch/test/pucch_encode_test_mex.c similarity index 100% rename from srslte/lib/phch/test/pucch_encode_test_mex.c rename to lib/src/phy/phch/test/pucch_encode_test_mex.c diff --git a/srslte/lib/phch/test/pucch_test.c b/lib/src/phy/phch/test/pucch_test.c similarity index 100% rename from srslte/lib/phch/test/pucch_test.c rename to lib/src/phy/phch/test/pucch_test.c diff --git a/srslte/lib/phch/test/pucch_test_mex.c b/lib/src/phy/phch/test/pucch_test_mex.c similarity index 100% rename from srslte/lib/phch/test/pucch_test_mex.c rename to lib/src/phy/phch/test/pucch_test_mex.c diff --git a/srslte/lib/phch/test/pusch_encode_test_mex.c b/lib/src/phy/phch/test/pusch_encode_test_mex.c similarity index 100% rename from srslte/lib/phch/test/pusch_encode_test_mex.c rename to lib/src/phy/phch/test/pusch_encode_test_mex.c diff --git a/srslte/lib/phch/test/pusch_test.c b/lib/src/phy/phch/test/pusch_test.c similarity index 100% rename from srslte/lib/phch/test/pusch_test.c rename to lib/src/phy/phch/test/pusch_test.c diff --git a/srslte/lib/phch/test/pusch_test_mex.c b/lib/src/phy/phch/test/pusch_test_mex.c similarity index 100% rename from srslte/lib/phch/test/pusch_test_mex.c rename to lib/src/phy/phch/test/pusch_test_mex.c diff --git a/srslte/lib/phch/test/signal.1.92M.amar.dat b/lib/src/phy/phch/test/signal.1.92M.amar.dat similarity index 100% rename from srslte/lib/phch/test/signal.1.92M.amar.dat rename to lib/src/phy/phch/test/signal.1.92M.amar.dat diff --git a/srslte/lib/phch/test/signal.1.92M.dat b/lib/src/phy/phch/test/signal.1.92M.dat similarity index 100% rename from srslte/lib/phch/test/signal.1.92M.dat rename to lib/src/phy/phch/test/signal.1.92M.dat diff --git a/srslte/lib/phch/test/signal.10M.dat b/lib/src/phy/phch/test/signal.10M.dat similarity index 100% rename from srslte/lib/phch/test/signal.10M.dat rename to lib/src/phy/phch/test/signal.10M.dat diff --git a/srslte/lib/phch/test/ulsch_encode_test_mex.c b/lib/src/phy/phch/test/ulsch_encode_test_mex.c similarity index 100% rename from srslte/lib/phch/test/ulsch_encode_test_mex.c rename to lib/src/phy/phch/test/ulsch_encode_test_mex.c diff --git a/srslte/lib/phch/uci.c b/lib/src/phy/phch/uci.c similarity index 98% rename from srslte/lib/phch/uci.c rename to lib/src/phy/phch/uci.c index 60ce417f5..821e5be5f 100644 --- a/srslte/lib/phch/uci.c +++ b/lib/src/phy/phch/uci.c @@ -33,15 +33,15 @@ #include #include -#include "srslte/phch/uci.h" -#include "srslte/fec/cbsegm.h" -#include "srslte/fec/convcoder.h" -#include "srslte/fec/crc.h" -#include "srslte/fec/rm_conv.h" -#include "srslte/common/phy_common.h" -#include "srslte/utils/vector.h" -#include "srslte/utils/bit.h" -#include "srslte/utils/debug.h" +#include "srslte/phy/phch/uci.h" +#include "srslte/phy/fec/cbsegm.h" +#include "srslte/phy/fec/convcoder.h" +#include "srslte/phy/fec/crc.h" +#include "srslte/phy/fec/rm_conv.h" +#include "srslte/phy/common/phy_common.h" +#include "srslte/phy/utils/vector.h" +#include "srslte/phy/utils/bit.h" +#include "srslte/phy/utils/debug.h" /* Table 5.2.2.6.4-1: Basis sequence for (32, O) code */ diff --git a/srslte/lib/resampling/CMakeLists.txt b/lib/src/phy/resampling/CMakeLists.txt similarity index 89% rename from srslte/lib/resampling/CMakeLists.txt rename to lib/src/phy/resampling/CMakeLists.txt index 75b1b1e3c..f12d301f7 100644 --- a/srslte/lib/resampling/CMakeLists.txt +++ b/lib/src/phy/resampling/CMakeLists.txt @@ -1,7 +1,7 @@ # -# Copyright 2013-2015 Software Radio Systems Limited +# Copyright 2013-2017 Software Radio Systems Limited # -# This file is part of the srsLTE library. +# 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 diff --git a/srslte/lib/resampling/decim.c b/lib/src/phy/resampling/decim.c similarity index 94% rename from srslte/lib/resampling/decim.c rename to lib/src/phy/resampling/decim.c index 78e017646..eba486a28 100644 --- a/srslte/lib/resampling/decim.c +++ b/lib/src/phy/resampling/decim.c @@ -26,8 +26,8 @@ #include #include -#include "srslte/resampling/decim.h" -#include "srslte/utils/debug.h" +#include "srslte/phy/resampling/decim.h" +#include "srslte/phy/utils/debug.h" /* Performs integer linear decimation by a factor of M */ diff --git a/srslte/lib/resampling/interp.c b/lib/src/phy/resampling/interp.c similarity index 98% rename from srslte/lib/resampling/interp.c rename to lib/src/phy/resampling/interp.c index c844461ca..553caf4b7 100644 --- a/srslte/lib/resampling/interp.c +++ b/lib/src/phy/resampling/interp.c @@ -29,9 +29,9 @@ #include #include -#include "srslte/resampling/interp.h" -#include "srslte/utils/vector.h" -#include "srslte/utils/debug.h" +#include "srslte/phy/resampling/interp.h" +#include "srslte/phy/utils/vector.h" +#include "srslte/phy/utils/debug.h" /*************** STATIC FUNCTIONS ***********************/ diff --git a/srslte/lib/resampling/resample_arb.c b/lib/src/phy/resampling/resample_arb.c similarity index 98% rename from srslte/lib/resampling/resample_arb.c rename to lib/src/phy/resampling/resample_arb.c index c7f10d2c2..7bdb4deec 100644 --- a/srslte/lib/resampling/resample_arb.c +++ b/lib/src/phy/resampling/resample_arb.c @@ -26,8 +26,8 @@ #include #include -#include "srslte/resampling/resample_arb.h" -#include "srslte/utils/debug.h" +#include "srslte/phy/resampling/resample_arb.h" +#include "srslte/phy/utils/debug.h" float srslte_resample_arb_polyfilt[SRSLTE_RESAMPLE_ARB_N][SRSLTE_RESAMPLE_ARB_M] = {{0,0.002400347599485495,-0.006922416132556366,0.0179104136912176,0.99453086623794,-0.008521087756729117,0.0008598969867484128,0.0004992625165376107}, diff --git a/srslte/lib/resampling/test/CMakeLists.txt b/lib/src/phy/resampling/test/CMakeLists.txt similarity index 83% rename from srslte/lib/resampling/test/CMakeLists.txt rename to lib/src/phy/resampling/test/CMakeLists.txt index 058b4cbdd..f0314b643 100644 --- a/srslte/lib/resampling/test/CMakeLists.txt +++ b/lib/src/phy/resampling/test/CMakeLists.txt @@ -1,7 +1,7 @@ # -# Copyright 2013-2015 Software Radio Systems Limited +# Copyright 2013-2017 Software Radio Systems Limited # -# This file is part of the srsLTE library. +# 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 @@ -23,10 +23,10 @@ ######################################################################## add_executable(resample_arb_test resample_arb_test.c) -target_link_libraries(resample_arb_test srslte) +target_link_libraries(resample_arb_test srslte_phy) add_executable(resample_arb_bench resample_arb_bench.c) -target_link_libraries(resample_arb_bench srslte) +target_link_libraries(resample_arb_bench srslte_phy) add_test(resample resample_arb_test) diff --git a/srslte/lib/resampling/test/resample_arb_bench.c b/lib/src/phy/resampling/test/resample_arb_bench.c similarity index 97% rename from srslte/lib/resampling/test/resample_arb_bench.c rename to lib/src/phy/resampling/test/resample_arb_bench.c index c3a260b09..48879d036 100644 --- a/srslte/lib/resampling/test/resample_arb_bench.c +++ b/lib/src/phy/resampling/test/resample_arb_bench.c @@ -32,7 +32,7 @@ #include #include "srslte/srslte.h" -#include "srslte/resampling/resample_arb.h" +#include "srslte/phy/resampling/resample_arb.h" diff --git a/srslte/lib/resampling/test/resample_arb_test.c b/lib/src/phy/resampling/test/resample_arb_test.c similarity index 97% rename from srslte/lib/resampling/test/resample_arb_test.c rename to lib/src/phy/resampling/test/resample_arb_test.c index ad861e842..cf740da00 100644 --- a/srslte/lib/resampling/test/resample_arb_test.c +++ b/lib/src/phy/resampling/test/resample_arb_test.c @@ -32,7 +32,7 @@ #include #include "srslte/srslte.h" -#include "srslte/resampling/resample_arb.h" +#include "srslte/phy/resampling/resample_arb.h" diff --git a/srslte/lib/rf/CMakeLists.txt b/lib/src/phy/rf/CMakeLists.txt similarity index 81% rename from srslte/lib/rf/CMakeLists.txt rename to lib/src/phy/rf/CMakeLists.txt index 22b1fb1c3..651ac331a 100644 --- a/srslte/lib/rf/CMakeLists.txt +++ b/lib/src/phy/rf/CMakeLists.txt @@ -1,7 +1,7 @@ # -# Copyright 2013-2015 Software Radio Systems Limited +# Copyright 2013-2017 Software Radio Systems Limited # -# This file is part of the srsLTE library. +# 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 @@ -33,6 +33,12 @@ if(RF_FOUND) list(APPEND SOURCES_RF rf_blade_imp.c) endif (BLADERF_FOUND) + if (SOAPYSDR_FOUND) + add_definitions(-DENABLE_SOAPYSDR) + list(APPEND SOURCES_RF rf_soapy_imp.c) + endif (SOAPYSDR_FOUND) + + add_library(srslte_rf SHARED ${SOURCES_RF}) @@ -44,6 +50,11 @@ if(RF_FOUND) target_link_libraries(srslte_rf ${BLADERF_LIBRARIES}) endif (BLADERF_FOUND) + if (SOAPYSDR_FOUND) + target_link_libraries(srslte_rf ${SOAPYSDR_LIBRARIES}) + endif (SOAPYSDR_FOUND) + + INSTALL(TARGETS srslte_rf DESTINATION ${LIBRARY_DIR}) SRSLTE_SET_PIC(srslte_rf) endif(RF_FOUND) diff --git a/srslte/lib/rf/rf_blade_imp.c b/lib/src/phy/rf/rf_blade_imp.c similarity index 99% rename from srslte/lib/rf/rf_blade_imp.c rename to lib/src/phy/rf/rf_blade_imp.c index 8cc19c881..f3dd471f6 100644 --- a/srslte/lib/rf/rf_blade_imp.c +++ b/lib/src/phy/rf/rf_blade_imp.c @@ -32,7 +32,7 @@ #include "srslte/srslte.h" #include "rf_blade_imp.h" -#include "srslte/rf/rf.h" +#include "srslte/phy/rf/rf.h" #define CONVERT_BUFFER_SIZE 240*1024 diff --git a/srslte/lib/rf/rf_blade_imp.h b/lib/src/phy/rf/rf_blade_imp.h similarity index 99% rename from srslte/lib/rf/rf_blade_imp.h rename to lib/src/phy/rf/rf_blade_imp.h index f40ee374e..07e9bb7cf 100644 --- a/srslte/lib/rf/rf_blade_imp.h +++ b/lib/src/phy/rf/rf_blade_imp.h @@ -26,7 +26,7 @@ #include "srslte/config.h" -#include "srslte/rf/rf.h" +#include "srslte/phy/rf/rf.h" #define DEVNAME "bladerf" diff --git a/srslte/lib/rf/rf_dev.h b/lib/src/phy/rf/rf_dev.h similarity index 85% rename from srslte/lib/rf/rf_dev.h rename to lib/src/phy/rf/rf_dev.h index 293f158b1..e1b761419 100644 --- a/srslte/lib/rf/rf_dev.h +++ b/lib/src/phy/rf/rf_dev.h @@ -140,6 +140,44 @@ static rf_dev_t dev_blade = { }; #endif +#ifdef ENABLE_SOAPYSDR + +#include "rf_soapy_imp.h" + +static rf_dev_t dev_soapy = { + "soapy", + rf_soapy_devname, + rf_soapy_rx_wait_lo_locked, + rf_soapy_start_rx_stream, + rf_soapy_stop_rx_stream, + rf_soapy_flush_buffer, + rf_soapy_has_rssi, + rf_soapy_get_rssi, + rf_soapy_suppress_stdout, + rf_soapy_register_error_handler, + rf_soapy_open, + rf_soapy_open_multi, + rf_soapy_close, + rf_soapy_set_master_clock_rate, + rf_soapy_is_master_clock_dynamic, + rf_soapy_set_rx_srate, + rf_soapy_set_rx_gain, + rf_soapy_set_tx_gain, + rf_soapy_get_rx_gain, + rf_soapy_get_tx_gain, + rf_soapy_set_rx_freq, + rf_soapy_set_tx_srate, + rf_soapy_set_tx_freq, + rf_soapy_get_time, + rf_soapy_recv_with_time, + rf_soapy_recv_with_time_multi, + rf_soapy_send_timed, + rf_soapy_set_tx_cal, + rf_soapy_set_rx_cal +}; + +#endif + //#define ENABLE_DUMMY_DEV #ifdef ENABLE_DUMMY_DEV @@ -183,9 +221,13 @@ static rf_dev_t dev_dummy = { #endif static rf_dev_t *available_devices[] = { + #ifdef ENABLE_UHD &dev_uhd, #endif +#ifdef ENABLE_SOAPYSDR + &dev_soapy, +#endif #ifdef ENABLE_BLADERF &dev_blade, #endif diff --git a/srslte/lib/rf/rf_imp.c b/lib/src/phy/rf/rf_imp.c similarity index 99% rename from srslte/lib/rf/rf_imp.c rename to lib/src/phy/rf/rf_imp.c index eca353ffa..92b8143da 100644 --- a/srslte/lib/rf/rf_imp.c +++ b/lib/src/phy/rf/rf_imp.c @@ -26,7 +26,7 @@ #include -#include "srslte/rf/rf.h" +#include "srslte/phy/rf/rf.h" #include "srslte/srslte.h" #include "rf_dev.h" diff --git a/lib/src/phy/rf/rf_soapy_imp.c b/lib/src/phy/rf/rf_soapy_imp.c new file mode 100644 index 000000000..8fcf57c24 --- /dev/null +++ b/lib/src/phy/rf/rf_soapy_imp.c @@ -0,0 +1,435 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsLTE library. + * + * 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 +#include +#include +#include + +#include "srslte/srslte.h" +#include "rf_soapy_imp.h" +#include "srslte/phy/rf/rf.h" + +#include +#include + +typedef struct { + SoapySDRKwargs args; + SoapySDRDevice *device; + SoapySDRRange *ranges; + SoapySDRStream *rxStream; + SoapySDRStream *txStream; +} rf_soapy_handler_t; + + +int soapy_error(void *h) +{ + return 0; +} + + +void rf_soapy_get_freq_range(void *h) +{ + +} + + +void rf_soapy_suppress_handler(const char *x) +{ + // not supported +} + + +void rf_soapy_msg_handler(const char *msg) +{ + // not supported +} + + +void rf_soapy_suppress_stdout(void *h) +{ + // not supported +} + + +void rf_soapy_register_error_handler(void *notused, srslte_rf_error_handler_t new_handler) +{ + // not supported +} + + +char* rf_soapy_devname(void* h) +{ + return "soapy"; +} + +bool rf_soapy_rx_wait_lo_locked(void *h) +{ + printf("TODO: implement rf_soapy_rx_wait_lo_locked()\n"); + return true; +} + + +void rf_soapy_set_tx_cal(void *h, srslte_rf_cal_t *cal) +{ + printf("TODO: implement rf_soapy_rx_wait_lo_locked()\n"); + // not supported +} + + +void rf_soapy_set_rx_cal(void *h, srslte_rf_cal_t *cal) +{ + printf("TODO: implement rf_soapy_set_rx_cal()\n"); +} + + +int rf_soapy_start_rx_stream(void *h) +{ + rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h; + + if (SoapySDRDevice_activateStream(handler->device, handler->rxStream, 0, 0, 0) != 0) + return SRSLTE_ERROR; + + return SRSLTE_SUCCESS; +} + + +int rf_soapy_start_tx_stream(void *h) +{ + rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h; + if (SoapySDRDevice_setupStream(handler->device, &(handler->txStream), SOAPY_SDR_TX, SOAPY_SDR_CF32, NULL, 0, NULL) != 0) { + printf("setupStream fail: %s\n", SoapySDRDevice_lastError()); + return SRSLTE_ERROR; + } + + if(SoapySDRDevice_activateStream(handler->device, handler->txStream, 0, 0, 0) != 0) + return SRSLTE_ERROR; + + return SRSLTE_SUCCESS; +} + + +int rf_soapy_stop_rx_stream(void *h) +{ + rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h; + if (SoapySDRDevice_deactivateStream(handler->device, handler->rxStream, 0, 0) != 0) + return SRSLTE_ERROR; + + return SRSLTE_SUCCESS; +} + + +int rf_soapy_stop_tx_stream(void *h) +{ + rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h; + if(SoapySDRDevice_deactivateStream(handler->device, handler->txStream, 0, 0) != 0) + return SRSLTE_ERROR; + + return SRSLTE_SUCCESS; +} + + +void rf_soapy_flush_buffer(void *h) +{ + int n; + cf_t tmp1[1024]; + cf_t tmp2[1024]; + void *data[2] = {tmp1, tmp2}; + do { + n = rf_soapy_recv_with_time_multi(h, data, 1024, 0, NULL, NULL); + } while (n > 0); +} + + +bool rf_soapy_has_rssi(void *h) +{ + printf("TODO: implement rf_soapy_has_rssi()\n"); + return false; +} + + +float rf_soapy_get_rssi(void *h) +{ + printf("TODO: implement rf_soapy_get_rssi()\n"); + return 0.0; +} + + +//TODO: add multi-channel support +int rf_soapy_open_multi(char *args, void **h, uint32_t nof_rx_antennas) +{ + size_t length; + const SoapySDRKwargs *soapy_args = SoapySDRDevice_enumerate(NULL, &length); + + if (length == 0) { + printf("No Soapy devices found.\n"); + return SRSLTE_ERROR; + } + + for (size_t i = 0; i < length; i++) { + printf("Soapy Has Found device #%d: ", (int)i); + for (size_t j = 0; j < soapy_args[i].size; j++) + { + printf("%s=%s, ", soapy_args[i].keys[j], soapy_args[i].vals[j]); + } + printf("\n"); + } + + SoapySDRDevice *sdr = SoapySDRDevice_make(&(soapy_args[0])); + if (sdr == NULL) { + printf("failed to create SOAPY object\n"); + return SRSLTE_ERROR; + } + + // create handler + rf_soapy_handler_t *handler = (rf_soapy_handler_t*) malloc(sizeof(rf_soapy_handler_t)); + bzero(handler, sizeof(rf_soapy_handler_t)); + *h = handler; + handler->device = sdr; + + if (SoapySDRDevice_setupStream(handler->device, &(handler->rxStream), SOAPY_SDR_RX, SOAPY_SDR_CF32, NULL, 0, NULL) != 0) { + printf("setupStream fail: %s\n", SoapySDRDevice_lastError()); + return SRSLTE_ERROR; + } + + return SRSLTE_SUCCESS; +} + + +int rf_soapy_open(char *args, void **h) +{ + return rf_soapy_open_multi(args, h, 1); +} + + +int rf_soapy_close(void *h) +{ + rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h; + if (handler->txStream) { + rf_soapy_stop_tx_stream(handler); + SoapySDRDevice_closeStream(handler->device, handler->txStream); + } + + if (handler->rxStream) { + rf_soapy_stop_rx_stream(handler); + SoapySDRDevice_closeStream(handler->device, handler->rxStream); + } + + SoapySDRDevice_unmake(handler->device); + free(handler); + + return SRSLTE_SUCCESS; +} + +void rf_soapy_set_master_clock_rate(void *h, double rate) +{ + // Allow the soapy to automatically set the appropriate clock rate + // TODO: implement this function +} + + +bool rf_soapy_is_master_clock_dynamic(void *h) +{ + printf("TODO: implement rf_soapy_is_master_clock_dynamic()\n"); + return false; +} + + +double rf_soapy_set_rx_srate(void *h, double rate) +{ + rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h; + if (SoapySDRDevice_setSampleRate(handler->device, SOAPY_SDR_RX, 0, rate) != 0) { + printf("setSampleRate fail: %s\n", SoapySDRDevice_lastError()); + return SRSLTE_ERROR; + } + return SoapySDRDevice_getSampleRate(handler->device, SOAPY_SDR_RX,0); +} + +double rf_soapy_set_tx_srate(void *h, double rate) +{ + rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h; + if (SoapySDRDevice_setSampleRate(handler->device, SOAPY_SDR_TX, 0, rate) != 0) { + printf("setSampleRate fail: %s\n", SoapySDRDevice_lastError()); + return SRSLTE_ERROR; + } + return SoapySDRDevice_getSampleRate(handler->device, SOAPY_SDR_TX,0); +} + + +double rf_soapy_set_rx_gain(void *h, double gain) +{ + rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h; + if (SoapySDRDevice_setGain(handler->device, SOAPY_SDR_RX, 0, gain) != 0) + { + printf("setGain fail: %s\n", SoapySDRDevice_lastError()); + return SRSLTE_ERROR; + } + return rf_soapy_get_rx_gain(h); +} + + +double rf_soapy_set_tx_gain(void *h, double gain) +{ + rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h; + if (SoapySDRDevice_setGain(handler->device, SOAPY_SDR_TX, 0, gain) != 0) + { + printf("setGain fail: %s\n", SoapySDRDevice_lastError()); + return SRSLTE_ERROR; + } + return rf_soapy_get_rx_gain(h); +} + + +double rf_soapy_get_rx_gain(void *h) +{ + rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h; + return SoapySDRDevice_getGain(handler->device,SOAPY_SDR_RX,0); +} + + +double rf_soapy_get_tx_gain(void *h) +{ + rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h; + return SoapySDRDevice_getGain(handler->device,SOAPY_SDR_TX,0); +} + + +double rf_soapy_set_rx_freq(void *h, double freq) +{ + rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h; + if (SoapySDRDevice_setFrequency(handler->device, SOAPY_SDR_RX, 0, freq, NULL) != 0) + { + printf("setFrequency fail: %s\n", SoapySDRDevice_lastError()); + return SRSLTE_ERROR; + } + + return SoapySDRDevice_getFrequency(handler->device, SOAPY_SDR_RX, 0); +} + +double rf_soapy_set_tx_freq(void *h, double freq) +{ + rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h; + if (SoapySDRDevice_setFrequency(handler->device, SOAPY_SDR_TX, 0, freq, NULL) != 0) + { + printf("setFrequency fail: %s\n", SoapySDRDevice_lastError()); + return SRSLTE_ERROR; + } + return SoapySDRDevice_getFrequency(handler->device, SOAPY_SDR_RX, 0); +} + + +void rf_soapy_get_time(void *h, time_t *secs, double *frac_secs) { + +} + +//TODO: add multi-channel support +int rf_soapy_recv_with_time_multi(void *h, + void **data, + uint32_t nsamples, + bool blocking, + time_t *secs, + double *frac_secs) +{ + rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h; + //void *buffs[] = {buff}; //array of buffers + + int flags; //flags set by receive operation + + int num_channels = 1; // temp + + int trials = 0; + int ret = 0; + long long timeNs; //timestamp for receive buffer + int n = 0; + do { + size_t rx_samples = nsamples; + + if (rx_samples > nsamples - n) + { + rx_samples = nsamples - n; + } + void *buffs_ptr[4]; + for (int i=0; idevice, handler->rxStream, buffs_ptr , rx_samples, &flags, &timeNs, 1000000); + if(ret < 0) { + // continue when getting overflows + if (ret == SOAPY_SDR_OVERFLOW) { + fprintf(stderr, "O"); + fflush(stderr); + continue; + } else { + return SRSLTE_ERROR; + } + } + + n += ret; + trials++; + } while (n < nsamples && trials < 100); + + + //*secs = timeNs / 1000000000; + //*frac_secs = (timeNs % 1000000000)/1000000000; + // printf("ret=%d, flags=%d, timeNs=%lld\n", ret, flags, timeNs); + return n; +} + +int rf_soapy_recv_with_time(void *h, + void *data, + uint32_t nsamples, + bool blocking, + time_t *secs, + double *frac_secs) +{ + return rf_soapy_recv_with_time_multi(h, &data, nsamples, blocking, secs, frac_secs); +} + + +int rf_soapy_send_timed(void *h, + void *data, + int nsamples, + time_t secs, + double frac_secs, + bool has_time_spec, + bool blocking, + bool is_start_of_burst, + bool is_end_of_burst) +{ + int flags; + long long timeNs; + rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h; + timeNs = secs * 1000000000; + timeNs = timeNs + (frac_secs * 1000000000); + int ret = SoapySDRDevice_writeStream(handler->device, handler->txStream, data, nsamples, &flags, timeNs, 100000); + if(ret != nsamples) + return SRSLTE_ERROR; + + return ret; +} diff --git a/lib/src/phy/rf/rf_soapy_imp.h b/lib/src/phy/rf/rf_soapy_imp.h new file mode 100644 index 000000000..23b59a8b3 --- /dev/null +++ b/lib/src/phy/rf/rf_soapy_imp.h @@ -0,0 +1,118 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsLTE library. + * + * 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 +#include +#include "srslte/config.h" +#include "srslte/phy/rf/rf.h" + + +SRSLTE_API int rf_soapy_open(char *args, + void **handler); + +SRSLTE_API int rf_soapy_open_multi(char *args, + void **handler, + uint32_t nof_rx_antennas); + +SRSLTE_API char* rf_soapy_devname(void *h); + +SRSLTE_API int rf_soapy_close(void *h); + +SRSLTE_API void rf_soapy_set_tx_cal(void *h, srslte_rf_cal_t *cal); + +SRSLTE_API void rf_soapy_set_rx_cal(void *h, srslte_rf_cal_t *cal); + +SRSLTE_API int rf_soapy_start_rx_stream(void *h); + +SRSLTE_API int rf_soapy_stop_rx_stream(void *h); + +SRSLTE_API void rf_soapy_flush_buffer(void *h); + +SRSLTE_API bool rf_soapy_has_rssi(void *h); + +SRSLTE_API float rf_soapy_get_rssi(void *h); + +SRSLTE_API bool rf_soapy_rx_wait_lo_locked(void *h); + +SRSLTE_API void rf_soapy_set_master_clock_rate(void *h, + double rate); + +SRSLTE_API bool rf_soapy_is_master_clock_dynamic(void *h); + +SRSLTE_API double rf_soapy_set_rx_srate(void *h, + double freq); + +SRSLTE_API double rf_soapy_set_rx_gain(void *h, + double gain); + +SRSLTE_API double rf_soapy_get_rx_gain(void *h); + +SRSLTE_API double rf_soapy_set_tx_gain(void *h, + double gain); + +SRSLTE_API double rf_soapy_get_tx_gain(void *h); + +SRSLTE_API void rf_soapy_suppress_stdout(void *h); + +SRSLTE_API void rf_soapy_register_error_handler(void *h, srslte_rf_error_handler_t error_handler); + +SRSLTE_API double rf_soapy_set_rx_freq(void *h, + double freq); + +SRSLTE_API int rf_soapy_recv_with_time(void *h, + void *data, + uint32_t nsamples, + bool blocking, + time_t *secs, + double *frac_secs); + +SRSLTE_API int rf_soapy_recv_with_time_multi(void *h, + void **data, + uint32_t nsamples, + bool blocking, + time_t *secs, + double *frac_secs); + +SRSLTE_API double rf_soapy_set_tx_srate(void *h, + double freq); + +SRSLTE_API double rf_soapy_set_tx_freq(void *h, + double freq); + +SRSLTE_API void rf_soapy_get_time(void *h, + time_t *secs, + double *frac_secs); + +SRSLTE_API int rf_soapy_send_timed(void *h, + void *data, + int nsamples, + time_t secs, + double frac_secs, + bool has_time_spec, + bool blocking, + bool is_start_of_burst, + bool is_end_of_burst); + diff --git a/srslte/lib/rf/rf_uhd_imp.c b/lib/src/phy/rf/rf_uhd_imp.c similarity index 98% rename from srslte/lib/rf/rf_uhd_imp.c rename to lib/src/phy/rf/rf_uhd_imp.c index 5b109710f..319093994 100644 --- a/srslte/lib/rf/rf_uhd_imp.c +++ b/lib/src/phy/rf/rf_uhd_imp.c @@ -32,7 +32,7 @@ #include "srslte/srslte.h" #include "rf_uhd_imp.h" -#include "srslte/rf/rf.h" +#include "srslte/phy/rf/rf.h" #include "uhd_c_api.h" typedef struct { @@ -100,7 +100,7 @@ static void* async_thread(void *h) { uhd_async_metadata_make(&md); while(handler->async_thread_running) { bool valid; - uhd_error err = uhd_tx_streamer_recv_async_msg(handler->tx_stream, &md, 10.0, &valid); + uhd_error err = uhd_tx_streamer_recv_async_msg(handler->tx_stream, &md, 0.5, &valid); if (err == UHD_ERROR_NONE) { if (valid) { uhd_async_metadata_event_code_t event_code; @@ -318,6 +318,9 @@ int rf_uhd_open_multi(char *args, void **h, uint32_t nof_rx_antennas) args = ""; } handler->devname = NULL; + + // Initialize handler + handler->uhd_error_handler = NULL; bzero(zero_mem, sizeof(cf_t)*64*1024); @@ -376,6 +379,7 @@ int rf_uhd_open_multi(char *args, void **h, uint32_t nof_rx_antennas) if (strstr(args, "clock=external")) { uhd_usrp_set_clock_source(handler->usrp, "external", 0); } else if (strstr(args, "clock=gpsdo")) { + printf("Using GPSDO clock\n"); uhd_usrp_set_clock_source(handler->usrp, "gpsdo", 0); } @@ -388,10 +392,10 @@ int rf_uhd_open_multi(char *args, void **h, uint32_t nof_rx_antennas) size_t channel[4] = {0, 1, 2, 3}; uhd_stream_args_t stream_args = { .cpu_format = "fc32", - .otw_format = "sc12", + .otw_format = "sc16", .args = "", .channel_list = channel, - .n_channels = nof_rx_antennas + .n_channels = 1 }; handler->nof_rx_channels = nof_rx_antennas; diff --git a/srslte/lib/rf/rf_uhd_imp.h b/lib/src/phy/rf/rf_uhd_imp.h similarity index 99% rename from srslte/lib/rf/rf_uhd_imp.h rename to lib/src/phy/rf/rf_uhd_imp.h index edab6ea51..7c26f015c 100644 --- a/srslte/lib/rf/rf_uhd_imp.h +++ b/lib/src/phy/rf/rf_uhd_imp.h @@ -28,7 +28,7 @@ #include #include "srslte/config.h" -#include "srslte/rf/rf.h" +#include "srslte/phy/rf/rf.h" #define DEVNAME_B200 "uhd_b200" #define DEVNAME_X300 "uhd_x300" diff --git a/srslte/lib/rf/rf_utils.c b/lib/src/phy/rf/rf_utils.c similarity index 99% rename from srslte/lib/rf/rf_utils.c rename to lib/src/phy/rf/rf_utils.c index 10c6b53df..f4a2c6790 100644 --- a/srslte/lib/rf/rf_utils.c +++ b/lib/src/phy/rf/rf_utils.c @@ -36,8 +36,8 @@ #include "srslte/srslte.h" -#include "srslte/rf/rf.h" -#include "srslte/rf/rf_utils.h" +#include "srslte/phy/rf/rf.h" +#include "srslte/phy/rf/rf_utils.h" int rf_rssi_scan(srslte_rf_t *rf, float *freqs, float *rssi, int nof_bands, double fs, int nsamp) { int i, j; diff --git a/srslte/lib/rf/uhd_c_api.cpp b/lib/src/phy/rf/uhd_c_api.cpp similarity index 97% rename from srslte/lib/rf/uhd_c_api.cpp rename to lib/src/phy/rf/uhd_c_api.cpp index 93792722d..c0fb6bfd3 100644 --- a/srslte/lib/rf/uhd_c_api.cpp +++ b/lib/src/phy/rf/uhd_c_api.cpp @@ -5,7 +5,7 @@ #include extern "C" { -#include "srslte/rf/rf.h" +#include "srslte/phy/rf/rf.h" #include "uhd_c_api.h" } diff --git a/lib/src/phy/rf/uhd_c_api.h b/lib/src/phy/rf/uhd_c_api.h new file mode 100644 index 000000000..15bb5f33c --- /dev/null +++ b/lib/src/phy/rf/uhd_c_api.h @@ -0,0 +1,36 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2017 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of srsLTE. + * + * srsUE 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. + * + * srsUE 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 +#include "srslte/config.h" +#include "srslte/phy/rf/rf.h" + +/* Declare functions not currently provided by the C-API */ +SRSLTE_API void rf_uhd_register_msg_handler_c(void (*new_handler)(const char*)); +SRSLTE_API void uhd_tx_metadata_set_time_spec(uhd_tx_metadata_handle *md, time_t secs, double frac_secs); +SRSLTE_API void uhd_tx_metadata_set_start(uhd_tx_metadata_handle *md, bool is_start_of_burst); +SRSLTE_API void uhd_tx_metadata_set_end(uhd_tx_metadata_handle *md, bool is_end_of_burst); +SRSLTE_API void uhd_tx_metadata_add_time_spec(uhd_tx_metadata_handle *md, double frac_secs); diff --git a/srslte/lib/scrambling/CMakeLists.txt b/lib/src/phy/scrambling/CMakeLists.txt similarity index 89% rename from srslte/lib/scrambling/CMakeLists.txt rename to lib/src/phy/scrambling/CMakeLists.txt index b0dc7452a..1f9e10353 100644 --- a/srslte/lib/scrambling/CMakeLists.txt +++ b/lib/src/phy/scrambling/CMakeLists.txt @@ -1,7 +1,7 @@ # -# Copyright 2013-2015 Software Radio Systems Limited +# Copyright 2013-2017 Software Radio Systems Limited # -# This file is part of the srsLTE library. +# 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 diff --git a/srslte/lib/scrambling/scrambling.c b/lib/src/phy/scrambling/scrambling.c similarity index 96% rename from srslte/lib/scrambling/scrambling.c rename to lib/src/phy/scrambling/scrambling.c index f8f423ffb..bb5637814 100644 --- a/srslte/lib/scrambling/scrambling.c +++ b/lib/src/phy/scrambling/scrambling.c @@ -28,9 +28,9 @@ #include #include #include -#include "srslte/utils/bit.h" -#include "srslte/utils/vector.h" -#include "srslte/scrambling/scrambling.h" +#include "srslte/phy/utils/bit.h" +#include "srslte/phy/utils/vector.h" +#include "srslte/phy/scrambling/scrambling.h" void srslte_scrambling_f(srslte_sequence_t *s, float *data) { srslte_scrambling_f_offset(s, data, 0, s->len); diff --git a/srslte/lib/scrambling/test/CMakeLists.txt b/lib/src/phy/scrambling/test/CMakeLists.txt similarity index 89% rename from srslte/lib/scrambling/test/CMakeLists.txt rename to lib/src/phy/scrambling/test/CMakeLists.txt index 4f658e31f..8dd63d4a2 100644 --- a/srslte/lib/scrambling/test/CMakeLists.txt +++ b/lib/src/phy/scrambling/test/CMakeLists.txt @@ -1,7 +1,7 @@ # -# Copyright 2013-2015 Software Radio Systems Limited +# Copyright 2013-2017 Software Radio Systems Limited # -# This file is part of the srsLTE library. +# 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 @@ -23,7 +23,7 @@ ######################################################################## add_executable(scrambling_test scrambling_test.c) -target_link_libraries(scrambling_test srslte) +target_link_libraries(scrambling_test srslte_phy) add_test(scrambling_pbch_bit scrambling_test -s PBCH -c 50) add_test(scrambling_pbch_float scrambling_test -s PBCH -c 50 -f) diff --git a/srslte/lib/scrambling/test/scrambling_test.c b/lib/src/phy/scrambling/test/scrambling_test.c similarity index 100% rename from srslte/lib/scrambling/test/scrambling_test.c rename to lib/src/phy/scrambling/test/scrambling_test.c diff --git a/srslte/lib/sync/CMakeLists.txt b/lib/src/phy/sync/CMakeLists.txt similarity index 89% rename from srslte/lib/sync/CMakeLists.txt rename to lib/src/phy/sync/CMakeLists.txt index 2aff1e93e..709b6a45b 100644 --- a/srslte/lib/sync/CMakeLists.txt +++ b/lib/src/phy/sync/CMakeLists.txt @@ -1,7 +1,7 @@ # -# Copyright 2013-2015 Software Radio Systems Limited +# Copyright 2013-2017 Software Radio Systems Limited # -# This file is part of the srsLTE library. +# 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 diff --git a/srslte/lib/sync/cfo.c b/lib/src/phy/sync/cfo.c similarity index 94% rename from srslte/lib/sync/cfo.c rename to lib/src/phy/sync/cfo.c index f9304576a..456015164 100644 --- a/srslte/lib/sync/cfo.c +++ b/lib/src/phy/sync/cfo.c @@ -28,10 +28,10 @@ #include #include -#include "srslte/utils/cexptab.h" -#include "srslte/sync/cfo.h" -#include "srslte/utils/vector.h" -#include "srslte/utils/debug.h" +#include "srslte/phy/utils/cexptab.h" +#include "srslte/phy/sync/cfo.h" +#include "srslte/phy/utils/vector.h" +#include "srslte/phy/utils/debug.h" int srslte_cfo_init(srslte_cfo_t *h, uint32_t nsamples) { int ret = SRSLTE_ERROR; diff --git a/srslte/lib/sync/cp.c b/lib/src/phy/sync/cp.c similarity index 95% rename from srslte/lib/sync/cp.c rename to lib/src/phy/sync/cp.c index ca415c466..c745aca85 100644 --- a/srslte/lib/sync/cp.c +++ b/lib/src/phy/sync/cp.c @@ -26,9 +26,9 @@ #include -#include "srslte/sync/cp.h" -#include "srslte/utils/vector.h" -#include "srslte/utils/debug.h" +#include "srslte/phy/sync/cp.h" +#include "srslte/phy/utils/vector.h" +#include "srslte/phy/utils/debug.h" int srslte_cp_synch_init(srslte_cp_synch_t *q, uint32_t symbol_sz) { diff --git a/srslte/lib/sync/find_sss.c b/lib/src/phy/sync/find_sss.c similarity index 98% rename from srslte/lib/sync/find_sss.c rename to lib/src/phy/sync/find_sss.c index 9c9478ac0..2afeced42 100644 --- a/srslte/lib/sync/find_sss.c +++ b/lib/src/phy/sync/find_sss.c @@ -29,8 +29,8 @@ #include #include -#include "srslte/utils/vector.h" -#include "srslte/sync/sss.h" +#include "srslte/phy/utils/vector.h" +#include "srslte/phy/sync/sss.h" #define MAX_M 3 diff --git a/srslte/lib/sync/gen_sss.c b/lib/src/phy/sync/gen_sss.c similarity index 99% rename from srslte/lib/sync/gen_sss.c rename to lib/src/phy/sync/gen_sss.c index b210dbfde..421d9e9e6 100644 --- a/srslte/lib/sync/gen_sss.c +++ b/lib/src/phy/sync/gen_sss.c @@ -27,7 +27,7 @@ #include -#include "srslte/sync/sss.h" +#include "srslte/phy/sync/sss.h" /** * @brief Function documentation: initSSStables() diff --git a/srslte/lib/sync/pss.c b/lib/src/phy/sync/pss.c similarity index 85% rename from srslte/lib/sync/pss.c rename to lib/src/phy/sync/pss.c index 647baa838..2ad166bc0 100644 --- a/srslte/lib/sync/pss.c +++ b/lib/src/phy/sync/pss.c @@ -31,11 +31,11 @@ #include #include -#include "srslte/sync/pss.h" -#include "srslte/dft/dft.h" -#include "srslte/utils/vector.h" -#include "srslte/utils/convolution.h" -#include "srslte/utils/debug.h" +#include "srslte/phy/sync/pss.h" +#include "srslte/phy/dft/dft.h" +#include "srslte/phy/utils/vector.h" +#include "srslte/phy/utils/convolution.h" +#include "srslte/phy/utils/debug.h" int srslte_pss_synch_init_N_id_2(cf_t *pss_signal_freq, cf_t *pss_signal_time, @@ -84,29 +84,48 @@ int srslte_pss_synch_init_fft(srslte_pss_synch_t *q, uint32_t frame_size, uint32 return srslte_pss_synch_init_fft_offset(q, frame_size, fft_size, 0); } +int srslte_pss_synch_init_fft_offset(srslte_pss_synch_t *q, uint32_t frame_size, uint32_t fft_size, int offset) { + return srslte_pss_synch_init_fft_offset_decim(q, frame_size, fft_size, offset, 1); +} + /* Initializes the PSS synchronization object. * * It correlates a signal of frame_size samples with the PSS sequence in the frequency * domain. The PSS sequence is transformed using fft_size samples. */ -int srslte_pss_synch_init_fft_offset(srslte_pss_synch_t *q, uint32_t frame_size, uint32_t fft_size, int offset) { - int ret = SRSLTE_ERROR_INVALID_INPUTS; +int srslte_pss_synch_init_fft_offset_decim(srslte_pss_synch_t *q, uint32_t frame_size, uint32_t fft_size, int offset, int decimate) { + + int ret = SRSLTE_ERROR_INVALID_INPUTS; if (q != NULL) { ret = SRSLTE_ERROR; uint32_t N_id_2; - uint32_t buffer_size; + uint32_t buffer_size; bzero(q, sizeof(srslte_pss_synch_t)); - q->N_id_2 = 10; + q->N_id_2 = 10; + q->ema_alpha = 0.2; + + q->decimate = decimate; + fft_size = fft_size/q->decimate; + frame_size = frame_size/q->decimate; + q->fft_size = fft_size; q->frame_size = frame_size; - q->ema_alpha = 0.2; buffer_size = fft_size + frame_size + 1; - + + if(q->decimate > 1) + { + int filter_order = 3; + srslte_filt_decim_cc_init(&q->filter,q->decimate,filter_order); + q->filter.filter_output = srslte_vec_malloc((buffer_size) * sizeof(cf_t)); + q->filter.downsampled_input = srslte_vec_malloc((buffer_size + filter_order) * sizeof(cf_t)); + printf("decimation for the PSS search is %d \n",q->decimate); + } + if (srslte_dft_plan(&q->dftp_input, fft_size, SRSLTE_DFT_FORWARD, SRSLTE_DFT_COMPLEX)) { fprintf(stderr, "Error creating DFT plan \n"); goto clean_and_exit; @@ -115,7 +134,7 @@ int srslte_pss_synch_init_fft_offset(srslte_pss_synch_t *q, uint32_t frame_size, srslte_dft_plan_set_dc(&q->dftp_input, true); srslte_dft_plan_set_norm(&q->dftp_input, true); - q->tmp_input = srslte_vec_malloc(buffer_size * sizeof(cf_t)); + q->tmp_input = srslte_vec_malloc((buffer_size + frame_size*(q->decimate - 1)) * sizeof(cf_t)); if (!q->tmp_input) { fprintf(stderr, "Error allocating memory\n"); goto clean_and_exit; @@ -159,10 +178,20 @@ int srslte_pss_synch_init_fft_offset(srslte_pss_synch_t *q, uint32_t frame_size, } #ifdef CONVOLUTION_FFT + + + for(N_id_2 = 0; N_id_2<3; N_id_2++) + q->pss_signal_freq_full[N_id_2] = srslte_vec_malloc(buffer_size * sizeof(cf_t)); + if (srslte_conv_fft_cc_init(&q->conv_fft, frame_size, fft_size)) { fprintf(stderr, "Error initiating convolution FFT\n"); goto clean_and_exit; } + for(int i =0; i< 3; i++) + { + srslte_dft_run_c(&q->conv_fft.filter_plan, q->pss_signal_time[i], q->pss_signal_freq_full[i]); + } + #endif srslte_pss_synch_reset(q); @@ -175,8 +204,10 @@ clean_and_exit: srslte_pss_synch_free(q); } return ret; + } + void srslte_pss_synch_free(srslte_pss_synch_t *q) { uint32_t i; @@ -185,6 +216,9 @@ void srslte_pss_synch_free(srslte_pss_synch_t *q) { if (q->pss_signal_time[i]) { free(q->pss_signal_time[i]); } + if(q->pss_signal_freq_full[i]){ + free(q->pss_signal_freq_full[i]); + } } #ifdef CONVOLUTION_FFT srslte_conv_fft_cc_free(&q->conv_fft); @@ -204,6 +238,14 @@ void srslte_pss_synch_free(srslte_pss_synch_t *q) { } srslte_dft_plan_free(&q->dftp_input); + + if(q->decimate > 1) + { + srslte_filt_decim_cc_free(&q->filter); + free(q->filter.filter_output); + free(q->filter.downsampled_input); + } + bzero(q, sizeof(srslte_pss_synch_t)); } @@ -314,8 +356,17 @@ int srslte_pss_synch_find_pss(srslte_pss_synch_t *q, cf_t *input, float *corr_pe */ if (q->frame_size >= q->fft_size) { #ifdef CONVOLUTION_FFT - memcpy(q->tmp_input, input, q->frame_size * sizeof(cf_t)); - conv_output_len = srslte_conv_fft_cc_run(&q->conv_fft, q->tmp_input, q->pss_signal_time[q->N_id_2], q->conv_output); + memcpy(q->tmp_input, input, (q->frame_size * q->decimate) * sizeof(cf_t)); + if(q->decimate > 1) + { + srslte_filt_decim_cc_execute(&(q->filter), q->tmp_input, q->filter.downsampled_input, q->filter.filter_output , (q->frame_size * q->decimate)); + conv_output_len = srslte_conv_fft_cc_run_opt(&q->conv_fft, q->filter.filter_output,q->pss_signal_freq_full[q->N_id_2], q->conv_output); + } + else + { + conv_output_len = srslte_conv_fft_cc_run_opt(&q->conv_fft, q->tmp_input, q->pss_signal_freq_full[q->N_id_2], q->conv_output); + } + #else conv_output_len = srslte_conv_cc(input, q->pss_signal_time[q->N_id_2], q->conv_output, q->frame_size, q->fft_size); #endif @@ -387,6 +438,14 @@ int srslte_pss_synch_find_pss(srslte_pss_synch_t *q, cf_t *input, float *corr_pe *corr_peak_value = q->conv_output_avg[corr_peak_pos]; } #endif + + if(q->decimate >1) + { + int decimation_correction = (q->filter.num_taps - 2); + corr_peak_pos = corr_peak_pos - decimation_correction; + corr_peak_pos = corr_peak_pos*q->decimate; + } + if (q->frame_size >= q->fft_size) { ret = (int) corr_peak_pos; diff --git a/srslte/lib/sync/sfo.c b/lib/src/phy/sync/sfo.c similarity index 97% rename from srslte/lib/sync/sfo.c rename to lib/src/phy/sync/sfo.c index a238e0dd2..7e630038b 100644 --- a/srslte/lib/sync/sfo.c +++ b/lib/src/phy/sync/sfo.c @@ -27,7 +27,7 @@ #include #include -#include "srslte/sync/sfo.h" +#include "srslte/phy/sync/sfo.h" /* Estimate SFO based on the array of time estimates t0 * of length len. The parameter period is the time between t0 samples diff --git a/srslte/lib/sync/sss.c b/lib/src/phy/sync/sss.c similarity index 96% rename from srslte/lib/sync/sss.c rename to lib/src/phy/sync/sss.c index 27818866a..3586e04de 100644 --- a/srslte/lib/sync/sss.c +++ b/lib/src/phy/sync/sss.c @@ -31,10 +31,10 @@ #include #include -#include "srslte/sync/sss.h" -#include "srslte/dft/dft.h" -#include "srslte/utils/convolution.h" -#include "srslte/utils/vector.h" +#include "srslte/phy/sync/sss.h" +#include "srslte/phy/dft/dft.h" +#include "srslte/phy/utils/convolution.h" +#include "srslte/phy/utils/vector.h" void generate_sss_all_tables(srslte_sss_tables_t *tables, uint32_t N_id_2); void convert_tables(srslte_sss_fc_tables_t *fc_tables, srslte_sss_tables_t *in); diff --git a/srslte/lib/sync/sync.c b/lib/src/phy/sync/sync.c similarity index 94% rename from srslte/lib/sync/sync.c rename to lib/src/phy/sync/sync.c index f7ddddd84..fb77e1b25 100644 --- a/srslte/lib/sync/sync.c +++ b/lib/src/phy/sync/sync.c @@ -29,11 +29,11 @@ #include #include -#include "srslte/utils/debug.h" -#include "srslte/common/phy_common.h" -#include "srslte/sync/sync.h" -#include "srslte/utils/vector.h" -#include "srslte/sync/cfo.h" +#include "srslte/phy/utils/debug.h" +#include "srslte/phy/common/phy_common.h" +#include "srslte/phy/sync/sync.h" +#include "srslte/phy/utils/vector.h" +#include "srslte/phy/sync/cfo.h" #define MEANPEAK_EMA_ALPHA 0.1 #define CFO_EMA_ALPHA 0.1 @@ -47,7 +47,13 @@ static bool fft_size_isvalid(uint32_t fft_size) { } } -int srslte_sync_init(srslte_sync_t *q, uint32_t frame_size, uint32_t max_offset, uint32_t fft_size) { + + +int srslte_sync_init(srslte_sync_t *q, uint32_t frame_size, uint32_t max_offset, uint32_t fft_size) +{ + return srslte_sync_init_decim(q, frame_size, max_offset, fft_size, 1); +} +int srslte_sync_init_decim(srslte_sync_t *q, uint32_t frame_size, uint32_t max_offset, uint32_t fft_size, int decimate) { int ret = SRSLTE_ERROR_INVALID_INPUTS; @@ -56,7 +62,6 @@ int srslte_sync_init(srslte_sync_t *q, uint32_t frame_size, uint32_t max_offset, fft_size_isvalid(fft_size)) { ret = SRSLTE_ERROR; - bzero(q, sizeof(srslte_sync_t)); q->detect_cp = true; q->sss_en = true; @@ -105,8 +110,12 @@ int srslte_sync_init(srslte_sync_t *q, uint32_t frame_size, uint32_t max_offset, } srslte_sync_set_cp(q, SRSLTE_CP_NORM); + q->decimate = decimate; + if(!decimate) + decimate = 1; + - if (srslte_pss_synch_init_fft(&q->pss, max_offset, fft_size)) { + if (srslte_pss_synch_init_fft_offset_decim(&q->pss, max_offset, fft_size,0,decimate)) { fprintf(stderr, "Error initializing PSS object\n"); goto clean_exit; } @@ -457,8 +466,13 @@ srslte_sync_find_ret_t srslte_sync_find(srslte_sync_t *q, cf_t *input, uint32_t } else { srslte_pss_synch_set_N_id_2(&q->pss, q->N_id_2); peak_pos = srslte_pss_synch_find_pss(&q->pss, &input_cfo[find_offset], &q->peak_value); + // this compensates for the constant time shift caused by the low pass filter + if(q->decimate && peak_pos < 0) + { + peak_pos = 0 ;//peak_pos + q->decimate*(2);// replace 2 with q->filter_size -2; + } if (peak_pos < 0) { - fprintf(stderr, "Error calling finding PSS sequence\n"); + fprintf(stderr, "Error calling finding PSS sequence at : %d \n", peak_pos); return SRSLTE_ERROR; } } diff --git a/srslte/lib/sync/test/CMakeLists.txt b/lib/src/phy/sync/test/CMakeLists.txt similarity index 89% rename from srslte/lib/sync/test/CMakeLists.txt rename to lib/src/phy/sync/test/CMakeLists.txt index c39d7978c..fd5c628b4 100644 --- a/srslte/lib/sync/test/CMakeLists.txt +++ b/lib/src/phy/sync/test/CMakeLists.txt @@ -1,7 +1,7 @@ # -# Copyright 2013-2015 Software Radio Systems Limited +# Copyright 2013-2017 Software Radio Systems Limited # -# This file is part of the srsLTE library. +# 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 @@ -25,11 +25,11 @@ find_package(SRSGUI) ######################################################################## add_executable(pss_file pss_file.c) -target_link_libraries(pss_file srslte) +target_link_libraries(pss_file srslte_phy) if(UHD_FOUND) add_executable(pss_usrp pss_usrp.c) - target_link_libraries(pss_usrp srslte) + target_link_libraries(pss_usrp srslte_phy) endif(UHD_FOUND) @@ -48,7 +48,7 @@ endif(SRSGUI_FOUND) ######################################################################## add_executable(sync_test sync_test.c) -target_link_libraries(sync_test srslte) +target_link_libraries(sync_test srslte_phy) add_test(sync_test_100 sync_test -o 100 -c 501) add_test(sync_test_400 sync_test -o 400 -c 2) @@ -65,7 +65,7 @@ add_test(sync_test_400_e sync_test -o 400 -e -p 50 -c 123) ######################################################################## add_executable(cfo_test cfo_test.c) -target_link_libraries(cfo_test srslte) +target_link_libraries(cfo_test srslte_phy) add_test(cfo_test_1 cfo_test -f 0.12345 -n 1000) add_test(cfo_test_2 cfo_test -f 0.99849 -n 1000) diff --git a/srslte/lib/sync/test/cfo_test.c b/lib/src/phy/sync/test/cfo_test.c similarity index 100% rename from srslte/lib/sync/test/cfo_test.c rename to lib/src/phy/sync/test/cfo_test.c diff --git a/srslte/lib/sync/test/cp_mex.c b/lib/src/phy/sync/test/cp_mex.c similarity index 100% rename from srslte/lib/sync/test/cp_mex.c rename to lib/src/phy/sync/test/cp_mex.c diff --git a/srslte/lib/sync/test/pss_file.c b/lib/src/phy/sync/test/pss_file.c similarity index 100% rename from srslte/lib/sync/test/pss_file.c rename to lib/src/phy/sync/test/pss_file.c diff --git a/srslte/lib/sync/test/pss_mex.c b/lib/src/phy/sync/test/pss_mex.c similarity index 100% rename from srslte/lib/sync/test/pss_mex.c rename to lib/src/phy/sync/test/pss_mex.c diff --git a/srslte/lib/sync/test/pss_usrp.c b/lib/src/phy/sync/test/pss_usrp.c similarity index 99% rename from srslte/lib/sync/test/pss_usrp.c rename to lib/src/phy/sync/test/pss_usrp.c index 74d9c8dea..8e8377b83 100644 --- a/srslte/lib/sync/test/pss_usrp.c +++ b/lib/src/phy/sync/test/pss_usrp.c @@ -35,7 +35,7 @@ #include #include "srslte/srslte.h" -#include "srslte/rf/rf.h" +#include "srslte/phy/rf/rf.h" #ifndef DISABLE_GRAPHICS diff --git a/srslte/lib/sync/test/sss_mex.c b/lib/src/phy/sync/test/sss_mex.c similarity index 100% rename from srslte/lib/sync/test/sss_mex.c rename to lib/src/phy/sync/test/sss_mex.c diff --git a/srslte/lib/sync/test/sync_test.c b/lib/src/phy/sync/test/sync_test.c similarity index 100% rename from srslte/lib/sync/test/sync_test.c rename to lib/src/phy/sync/test/sync_test.c diff --git a/srslte/lib/ue/CMakeLists.txt b/lib/src/phy/ue/CMakeLists.txt similarity index 88% rename from srslte/lib/ue/CMakeLists.txt rename to lib/src/phy/ue/CMakeLists.txt index fba91255d..f366f4f4f 100644 --- a/srslte/lib/ue/CMakeLists.txt +++ b/lib/src/phy/ue/CMakeLists.txt @@ -1,7 +1,7 @@ # -# Copyright 2013-2015 Software Radio Systems Limited +# Copyright 2013-2017 Software Radio Systems Limited # -# This file is part of the srsLTE library. +# 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 diff --git a/srslte/lib/ue/ue_cell_search.c b/lib/src/phy/ue/ue_cell_search.c similarity index 98% rename from srslte/lib/ue/ue_cell_search.c rename to lib/src/phy/ue/ue_cell_search.c index 868af36b9..f8c38a1bb 100644 --- a/srslte/lib/ue/ue_cell_search.c +++ b/lib/src/phy/ue/ue_cell_search.c @@ -30,10 +30,10 @@ #include #include -#include "srslte/ue/ue_cell_search.h" +#include "srslte/phy/ue/ue_cell_search.h" -#include "srslte/utils/debug.h" -#include "srslte/utils/vector.h" +#include "srslte/phy/utils/debug.h" +#include "srslte/phy/utils/vector.h" int srslte_ue_cellsearch_init(srslte_ue_cellsearch_t * q, uint32_t max_frames, int (recv_callback)(void*, void*, uint32_t,srslte_timestamp_t*), diff --git a/srslte/lib/ue/ue_dl.c b/lib/src/phy/ue/ue_dl.c similarity index 99% rename from srslte/lib/ue/ue_dl.c rename to lib/src/phy/ue/ue_dl.c index f75c69fa2..7201f96c2 100644 --- a/srslte/lib/ue/ue_dl.c +++ b/lib/src/phy/ue/ue_dl.c @@ -24,7 +24,7 @@ * */ -#include "srslte/ue/ue_dl.h" +#include "srslte/phy/ue/ue_dl.h" #include #include diff --git a/srslte/lib/ue/ue_mib.c b/lib/src/phy/ue/ue_mib.c similarity index 98% rename from srslte/lib/ue/ue_mib.c rename to lib/src/phy/ue/ue_mib.c index 9b5b4e9ef..34c2bc2e3 100644 --- a/srslte/lib/ue/ue_mib.c +++ b/lib/src/phy/ue/ue_mib.c @@ -30,10 +30,10 @@ #include #include -#include "srslte/ue/ue_mib.h" +#include "srslte/phy/ue/ue_mib.h" -#include "srslte/utils/debug.h" -#include "srslte/utils/vector.h" +#include "srslte/phy/utils/debug.h" +#include "srslte/phy/utils/vector.h" int srslte_ue_mib_init(srslte_ue_mib_t * q, srslte_cell_t cell) diff --git a/srslte/lib/ue/ue_sync.c b/lib/src/phy/ue/ue_sync.c similarity index 94% rename from srslte/lib/ue/ue_sync.c rename to lib/src/phy/ue/ue_sync.c index 42aab49e2..b5b2be3d0 100644 --- a/srslte/lib/ue/ue_sync.c +++ b/lib/src/phy/ue/ue_sync.c @@ -31,11 +31,11 @@ #include -#include "srslte/ue/ue_sync.h" +#include "srslte/phy/ue/ue_sync.h" -#include "srslte/io/filesource.h" -#include "srslte/utils/debug.h" -#include "srslte/utils/vector.h" +#include "srslte/phy/io/filesource.h" +#include "srslte/phy/utils/debug.h" +#include "srslte/phy/utils/vector.h" #define MAX_TIME_OFFSET 128 @@ -78,8 +78,17 @@ int srslte_ue_sync_init_file(srslte_ue_sync_t *q, uint32_t nof_prb, char *file_n } INFO("Offseting input file by %d samples and %.1f kHz\n", offset_time, offset_freq/1000); - - srslte_filesource_read(&q->file_source, dummy_offset_buffer, offset_time); + + if (offset_time) { + cf_t *file_offset_buffer = srslte_vec_malloc(offset_time * sizeof(cf_t)); + if (!file_offset_buffer) { + perror("malloc"); + goto clean_exit; + } + srslte_filesource_read(&q->file_source, file_offset_buffer, offset_time); + free(file_offset_buffer); + } + srslte_ue_sync_reset(q); ret = SRSLTE_SUCCESS; @@ -128,6 +137,18 @@ int srslte_ue_sync_init_multi(srslte_ue_sync_t *q, int (recv_callback)(void*, cf_t*[SRSLTE_MAX_PORTS], uint32_t,srslte_timestamp_t*), uint32_t nof_rx_antennas, void *stream_handler) + +{ + + return srslte_ue_sync_init_multi_decim(q, cell,recv_callback ,nof_rx_antennas,stream_handler,1); +} + +int srslte_ue_sync_init_multi_decim(srslte_ue_sync_t *q, + srslte_cell_t cell, + int (recv_callback)(void*, cf_t*[SRSLTE_MAX_PORTS], uint32_t,srslte_timestamp_t*), + uint32_t nof_rx_antennas, + void *stream_handler, + int decimate) { int ret = SRSLTE_ERROR_INVALID_INPUTS; @@ -138,9 +159,9 @@ int srslte_ue_sync_init_multi(srslte_ue_sync_t *q, recv_callback != NULL) { ret = SRSLTE_ERROR; - + //int decimate = q->decimate; bzero(q, sizeof(srslte_ue_sync_t)); - + q->decimate = decimate; q->stream = stream_handler; q->recv_callback = recv_callback; q->nof_rx_antennas = nof_rx_antennas; @@ -169,8 +190,14 @@ int srslte_ue_sync_init_multi(srslte_ue_sync_t *q, } q->frame_len = q->nof_recv_sf*q->sf_len; - - if(srslte_sync_init(&q->sfind, q->frame_len, q->frame_len, q->fft_size)) { + + if(q->fft_size < 700 && q->decimate) + { + q->decimate = 1; + } + + + if(srslte_sync_init_decim(&q->sfind, q->frame_len, q->frame_len, q->fft_size,q->decimate)) { fprintf(stderr, "Error initiating sync find\n"); goto clean_exit; } diff --git a/srslte/lib/ue/ue_ul.c b/lib/src/phy/ue/ue_ul.c similarity index 99% rename from srslte/lib/ue/ue_ul.c rename to lib/src/phy/ue/ue_ul.c index b14b45673..08edcafe0 100644 --- a/srslte/lib/ue/ue_ul.c +++ b/lib/src/phy/ue/ue_ul.c @@ -28,7 +28,7 @@ #include #include -#include "srslte/ue/ue_ul.h" +#include "srslte/phy/ue/ue_ul.h" #define CURRENT_FFTSIZE srslte_symbol_sz(q->cell.nof_prb) #define CURRENT_SFLEN SRSLTE_SF_LEN(CURRENT_FFTSIZE) diff --git a/srslte/lib/utils/CMakeLists.txt b/lib/src/phy/utils/CMakeLists.txt similarity index 90% rename from srslte/lib/utils/CMakeLists.txt rename to lib/src/phy/utils/CMakeLists.txt index 46785ffb3..5e82da2ef 100644 --- a/srslte/lib/utils/CMakeLists.txt +++ b/lib/src/phy/utils/CMakeLists.txt @@ -1,7 +1,7 @@ # -# Copyright 2013-2015 Software Radio Systems Limited +# Copyright 2013-2017 Software Radio Systems Limited # -# This file is part of the srsLTE library. +# 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 diff --git a/srslte/lib/utils/bit.c b/lib/src/phy/utils/bit.c similarity index 99% rename from srslte/lib/utils/bit.c rename to lib/src/phy/utils/bit.c index c6a9ef6cc..a5fcb400f 100644 --- a/srslte/lib/utils/bit.c +++ b/lib/src/phy/utils/bit.c @@ -31,7 +31,7 @@ #include #include -#include "srslte/utils/bit.h" +#include "srslte/phy/utils/bit.h" void srslte_bit_interleave(uint8_t *input, uint8_t *output, uint16_t *interleaver, uint32_t nof_bits) { srslte_bit_interleave_w_offset(input, output, interleaver, nof_bits, 0); diff --git a/srslte/lib/utils/cexptab.c b/lib/src/phy/utils/cexptab.c similarity index 98% rename from srslte/lib/utils/cexptab.c rename to lib/src/phy/utils/cexptab.c index 1d0548add..47ff8ef96 100644 --- a/srslte/lib/utils/cexptab.c +++ b/lib/src/phy/utils/cexptab.c @@ -30,7 +30,7 @@ #include #include -#include "srslte/utils/cexptab.h" +#include "srslte/phy/utils/cexptab.h" int srslte_cexptab_init(srslte_cexptab_t *h, uint32_t size) { uint32_t i; diff --git a/srslte/lib/utils/convolution.c b/lib/src/phy/utils/convolution.c similarity index 90% rename from srslte/lib/utils/convolution.c rename to lib/src/phy/utils/convolution.c index c3cd383ed..d3b852b76 100644 --- a/srslte/lib/utils/convolution.c +++ b/lib/src/phy/utils/convolution.c @@ -28,9 +28,9 @@ #include #include -#include "srslte/dft/dft.h" -#include "srslte/utils/vector.h" -#include "srslte/utils/convolution.h" +#include "srslte/phy/dft/dft.h" +#include "srslte/phy/utils/vector.h" +#include "srslte/phy/utils/convolution.h" int srslte_conv_fft_cc_init(srslte_conv_fft_cc_t *q, uint32_t input_len, uint32_t filter_len) { @@ -40,6 +40,8 @@ int srslte_conv_fft_cc_init(srslte_conv_fft_cc_t *q, uint32_t input_len, uint32_ q->input_fft = srslte_vec_malloc(sizeof(cf_t)*q->output_len); q->filter_fft = srslte_vec_malloc(sizeof(cf_t)*q->output_len); q->output_fft = srslte_vec_malloc(sizeof(cf_t)*q->output_len); + + if (!q->input_fft || !q->filter_fft || !q->output_fft) { return SRSLTE_ERROR; } @@ -58,6 +60,7 @@ int srslte_conv_fft_cc_init(srslte_conv_fft_cc_t *q, uint32_t input_len, uint32_ srslte_dft_plan_set_norm(&q->input_plan, true); srslte_dft_plan_set_norm(&q->filter_plan, true); srslte_dft_plan_set_norm(&q->output_plan, false); + return SRSLTE_SUCCESS; } @@ -71,6 +74,7 @@ void srslte_conv_fft_cc_free(srslte_conv_fft_cc_t *q) { if (q->output_fft) { free(q->output_fft); } + srslte_dft_plan_free(&q->input_plan); srslte_dft_plan_free(&q->filter_plan); srslte_dft_plan_free(&q->output_plan); @@ -79,16 +83,21 @@ void srslte_conv_fft_cc_free(srslte_conv_fft_cc_t *q) { } -uint32_t srslte_conv_fft_cc_run(srslte_conv_fft_cc_t *q, cf_t *input, cf_t *filter, cf_t *output) { +uint32_t srslte_conv_fft_cc_run_opt(srslte_conv_fft_cc_t *q, cf_t *input, cf_t *filter_freq, cf_t *output) +{ + srslte_dft_run_c(&q->input_plan, input, q->input_fft); + srslte_vec_prod_ccc(q->input_fft, filter_freq, q->output_fft, q->output_len); + srslte_dft_run_c(&q->output_plan, q->output_fft, output); - srslte_dft_run_c(&q->input_plan, input, q->input_fft); + return (q->output_len-1); // divide output length by dec factor + +} + +uint32_t srslte_conv_fft_cc_run(srslte_conv_fft_cc_t *q, cf_t *input, cf_t *filter, cf_t *output) { + srslte_dft_run_c(&q->filter_plan, filter, q->filter_fft); - srslte_vec_prod_ccc(q->input_fft,q->filter_fft,q->output_fft,q->output_len); - - srslte_dft_run_c(&q->output_plan, q->output_fft, output); - - return q->output_len-1; + return srslte_conv_fft_cc_run_opt(q, input, q->filter_fft, output); } diff --git a/srslte/lib/utils/debug.c b/lib/src/phy/utils/debug.c similarity index 96% rename from srslte/lib/utils/debug.c rename to lib/src/phy/utils/debug.c index e863b5735..423abee6c 100644 --- a/srslte/lib/utils/debug.c +++ b/lib/src/phy/utils/debug.c @@ -24,7 +24,7 @@ * */ -#include "srslte/utils/debug.h" +#include "srslte/phy/utils/debug.h" int srslte_verbose = 0; diff --git a/lib/src/phy/utils/filter.c b/lib/src/phy/utils/filter.c new file mode 100644 index 000000000..7fa9635f5 --- /dev/null +++ b/lib/src/phy/utils/filter.c @@ -0,0 +1,126 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsLTE library. + * + * 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/phy/utils/filter.h" +#define SRSLTE_NUM_FILTERS 8 +#define SRSLTE_MAX_FILTER_SIZE 11 + +float srslte_filt_decim2[SRSLTE_NUM_FILTERS][SRSLTE_MAX_FILTER_SIZE] = +{ + {0.0167364016736, 0.48326359832636, 0.48326359832636, 0.01673640167364,0,0,0,0,0,0,0}, + {0.000000000000000, 0.203712369200737, 0.592575261598526, 0.203712369200737, 0.000000000000000,0,0,0,0,0,0}, + {-0.007776312719103, 0.064454645578710, 0.443321667140393, 0.443321667140393, 0.064454645578710, -0.007776312719103,0,0,0,0,0}, + {-0.008721828105097, 0.000000000000000, 0.251842786534672, 0.513758083140849, 0.251842786534672, 0.000000000000000, -0.008721828105097,0,0,0,0}, + {-0.005164298061200, -0.022882524920256, 0.096755650536968, 0.431291172444487, 0.431291172444487, 0.096755650536968, -0.022882524920256, -0.005164298061200,0,0,0}, + {-0.000000000000000, -0.022663985459553, 0.000000000000000, 0.273977082565524, 0.497373805788057, 0.273977082565524, 0.000000000000000, -0.022663985459553, -0.000000000000000,0,0}, + { 0.003971846362414, -0.011976365116169, -0.041119498116286, 0.114687063714704, 0.434436953155337, 0.434436953155337, 0.114687063714704, -0.041119498116286, -0.011976365116169, 0.003971846362414,0}, + {0.005060317124845, -0.000000000000000, -0.041942879431345, 0.000000000000000, 0.288484826302638, 0.496795472007725, 0.288484826302638, 0.000000000000000, -0.041942879431345, -0.000000000000000, 0.005060317124845} + }; + +float srslte_filt_decim3[SRSLTE_NUM_FILTERS][SRSLTE_MAX_FILTER_SIZE] = +{ + {0.032388663967611, 0.467611336032389, 0.467611336032389, 0.032388663967611,0,0,0,0,0,0,0}, + {0.016883339167609, 0.227925078762723, 0.510383164139335, 0.227925078762723, 0.016883339167609,0,0,0,0,0,0}, + {0.006703633822959, 0.111127306155495, 0.382169060021546, 0.382169060021546, 0.111127306155495, 0.006703633822959,0,0,0,0,0}, + {0.000000000000000, 0.050666848023938, 0.251699825667307, 0.395266652617510, 0.251699825667307, 0.050666848023938, 0.000000000000000,0,0,0,0}, + {-0.004018779518049, 0.017806838679915, 0.150587600493065, 0.335624340345069, 0.335624340345069, 0.150587600493065, 0.017806838679915, -0.004018779518049,0,0,0}, + {-0.005814396641997, 0.000000000000000, 0.078494354666956, 0.251550893097387, 0.351538297755307, 0.251550893097387, 0.078494354666956, 0.000000000000000, -0.005814396641997,0,0}, + { -0.005798226803038, -0.008741738083915, 0.030013771222565, 0.167423798937736, 0.317102394726653, 0.317102394726653, 0.167423798937736, 0.030013771222565, -0.008741738083915, -0.005798226803038,0}, + {-0.004444793932295, -0.011657318166992, 0.000000000000000, 0.094750202492597, 0.253394317761931, 0.335915183689516, 0.253394317761931, 0.094750202492597, 0.000000000000000, -0.011657318166992, -0.004444793932295}, + +}; + + +float srslte_filt_decim4[SRSLTE_NUM_FILTERS][SRSLTE_MAX_FILTER_SIZE] = +{ + { 0.038579006748772, 0.461420993251228, 0.461420993251228, 0.038579006748772,0,0,0,0,0,0,0}, + {0.024553834015017, 0.234389464237986, 0.482113403493995, 0.234389464237986, 0.024553834015017,0,0,0,0,0,0}, + {0.015196373491712, 0.125956465856097, 0.358847160652191, 0.358847160652191, 0.125956465856097, 0.015196373491712,0,0,0,0,0}, + {0.008485920061584, 0.069755250084282, 0.245030941778248, 0.353455776151771, 0.245030941778248, 0.069755250084282, 0.008485920061584,0,0,0,0}, + {0.003560172702629, 0.038083722795699, 0.161031852333115, 0.297324252168557, 0.297324252168557, 0.161031852333115, 0.038083722795699, 0.003560172702629,0,0,0}, + {0.000000000000000, 0.019096925170212, 0.101875313412667, 0.230856124287772, 0.296343274258697, 0.230856124287772, 0.101875313412667, 0.019096925170212, 0.000000000000000,0,0}, + {-0.002426023829880, 0.007315224335493, 0.060635381185575, 0.169119131895270, 0.265356286413542, 0.265356286413542, 0.169119131895270, 0.060635381185575 , 0.007315224335493, -0.002426023829880,0}, + {-0.003871323167475, 0.000000000000000, 0.032087799410030, 0.116708621643743, 0.220701186106900, 0.268747432013603, 0.220701186106900, 0.116708621643743 , 0.032087799410030, 0.000000000000000,-0.003871323167475} +}; + + +void srslte_filt_decim_cc_init(srslte_filt_cc_t *q, int factor, int order) +{ + q->factor = factor; + q->num_taps = order + 1; + q->is_decimator = true; + q->taps = malloc(q->num_taps * sizeof(float)); + + switch(q->factor) + { + case 2: + for(int i = 0; i <(q->num_taps); i++) + q->taps[i] = srslte_filt_decim2[(q->num_taps) - 4][i]; + break; + case 3: + for(int i = 0; i <(q->num_taps); i++) + q->taps[i] = srslte_filt_decim3[(q->num_taps) - 4][i]; + break; + case 4: + for(int i = 0; i <(q->num_taps); i++) + q->taps[i] = srslte_filt_decim4[(q->num_taps) - 4][i]; + break; + default: + + break; + } + + for(int x = 0; x<(q->num_taps);x++) + { + printf("tap : %f.9\n" ,q->taps[x]); + } +} + +void srslte_filt_decim_cc_free(srslte_filt_cc_t *q) +{ + free(q->taps); +} + +void srslte_filt_decim_cc_execute(srslte_filt_cc_t *q, cf_t *input, cf_t *downsampled_input, cf_t *output, int size) +{ + // we assume that "downsampled_input" made size (input/2 + order) so as to have prepended zeros // + srslte_downsample_cc(input, downsampled_input + (q->num_taps - 1), q->factor, size); + + for(int i = 0;i < size/q->factor;i++) + { + output[i] = srslte_vec_dot_prod_cfc(&(downsampled_input[i]), q->taps, q->num_taps); + } + + +} + +/* Performs integer linear downsamling by a factor of M */ +void srslte_downsample_cc(cf_t *input, cf_t *output, int M, int size) { + int i; + for (i=0;i #include -#include "srslte/utils/ringbuffer.h" -#include "srslte/utils/vector.h" +#include "srslte/phy/utils/ringbuffer.h" +#include "srslte/phy/utils/vector.h" int srslte_ringbuffer_init(srslte_ringbuffer_t *q, int capacity) { diff --git a/srslte/lib/utils/test/CMakeLists.txt b/lib/src/phy/utils/test/CMakeLists.txt similarity index 90% rename from srslte/lib/utils/test/CMakeLists.txt rename to lib/src/phy/utils/test/CMakeLists.txt index 611d40fad..494c20c16 100644 --- a/srslte/lib/utils/test/CMakeLists.txt +++ b/lib/src/phy/utils/test/CMakeLists.txt @@ -1,7 +1,7 @@ # -# Copyright 2013-2015 Software Radio Systems Limited +# Copyright 2013-2017 Software Radio Systems Limited # -# This file is part of the srsLTE library. +# 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 @@ -23,7 +23,7 @@ ######################################################################## add_executable(dft_test dft_test.c) -target_link_libraries(dft_test srslte) +target_link_libraries(dft_test srslte_phy) add_test(dft_test dft_test) add_test(dft_reverse dft_test -b) # Backwards first diff --git a/srslte/lib/utils/test/dft_test.c b/lib/src/phy/utils/test/dft_test.c similarity index 99% rename from srslte/lib/utils/test/dft_test.c rename to lib/src/phy/utils/test/dft_test.c index 27000efa3..fd5a308a7 100644 --- a/srslte/lib/utils/test/dft_test.c +++ b/lib/src/phy/utils/test/dft_test.c @@ -32,7 +32,7 @@ #include #include -#include "srslte/dft/dft.h" +#include "srslte/phy/dft/dft.h" diff --git a/srslte/lib/utils/vector.c b/lib/src/phy/utils/vector.c similarity index 90% rename from srslte/lib/utils/vector.c rename to lib/src/phy/utils/vector.c index 334600200..3146c760d 100644 --- a/srslte/lib/utils/vector.c +++ b/lib/src/phy/utils/vector.c @@ -31,9 +31,20 @@ #include #include -#include "srslte/utils/vector.h" -#include "srslte/utils/vector_simd.h" -#include "srslte/utils/bit.h" +#include "srslte/phy/utils/vector.h" +#include "srslte/phy/utils/vector_simd.h" +#include "srslte/phy/utils/bit.h" + +#ifdef HAVE_VOLK +#include "volk/volk.h" +#endif + +#ifdef DEBUG_MODE +#warning FIXME: Disabling SSE/AVX vector code +#undef LV_HAVE_SSE +#undef LV_HAVE_AVX +#endif + int srslte_vec_acc_ii(int *x, uint32_t len) { int i; @@ -90,13 +101,17 @@ void srslte_vec_sub_fff(float *x, float *y, float *z, uint32_t len) { } void srslte_vec_sub_sss(short *x, short *y, short *z, uint32_t len) { -#ifndef LV_HAVE_SSE - int i; +#ifdef LV_HAVE_AVX + srslte_vec_sub_sss_avx(x, y, z, len); +#else +#ifdef LV_HAVE_SSE + srslte_vec_sub_sss_sse(x, y, z, len); +#else + int i; for (i=0;i #include -#include "srslte/utils/vector_simd.h" +#include "srslte/phy/utils/vector_simd.h" #include #include @@ -40,9 +40,12 @@ #include #endif +#ifdef LV_HAVE_AVX +#include +#endif -int srslte_vec_dot_prod_sss_simd(short *x, short *y, uint32_t len) +int srslte_vec_dot_prod_sss_sse(short *x, short *y, uint32_t len) { int result = 0; #ifdef LV_HAVE_SSE @@ -57,7 +60,7 @@ int srslte_vec_dot_prod_sss_simd(short *x, short *y, uint32_t len) __m128i xVal, yVal, zVal; for(;number < points; number++){ - xVal = _mm_loadu_si128(xPtr); + xVal = _mm_load_si128(xPtr); yVal = _mm_loadu_si128(yPtr); zVal = _mm_mullo_epi16(xVal, yVal); @@ -83,7 +86,48 @@ int srslte_vec_dot_prod_sss_simd(short *x, short *y, uint32_t len) return result; } -void srslte_vec_sum_sss_simd(short *x, short *y, short *z, uint32_t len) + +int srslte_vec_dot_prod_sss_avx(short *x, short *y, uint32_t len) +{ + int result = 0; +#ifdef LV_HAVE_AVX + unsigned int number = 0; + const unsigned int points = len / 16; + + const __m256i* xPtr = (const __m256i*) x; + const __m256i* yPtr = (const __m256i*) y; + + __m256i dotProdVal = _mm256_setzero_si256(); + + __m256i xVal, yVal, zVal; + for(;number < points; number++){ + + xVal = _mm256_load_si256(xPtr); + yVal = _mm256_loadu_si256(yPtr); + zVal = _mm256_mullo_epi16(xVal, yVal); + dotProdVal = _mm256_add_epi16(dotProdVal, zVal); + xPtr ++; + yPtr ++; + } + + short dotProdVector[16]; + _mm256_store_si256((__m256i*) dotProdVector, dotProdVal); + for (int i=0;i<16;i++) { + result += dotProdVector[i]; + } + + number = points * 16; + for(;number < len; number++){ + result += (x[number] * y[number]); + } + +#endif + return result; +} + + + +void srslte_vec_sum_sss_sse(short *x, short *y, short *z, uint32_t len) { #ifdef LV_HAVE_SSE unsigned int number = 0; @@ -116,7 +160,40 @@ void srslte_vec_sum_sss_simd(short *x, short *y, short *z, uint32_t len) } -void srslte_vec_sub_sss_simd(short *x, short *y, short *z, uint32_t len) +void srslte_vec_sum_sss_avx(short *x, short *y, short *z, uint32_t len) +{ +#ifdef LV_HAVE_SSE + unsigned int number = 0; + const unsigned int points = len / 16; + + const __m256i* xPtr = (const __m256i*) x; + const __m256i* yPtr = (const __m256i*) y; + __m256i* zPtr = (__m256i*) z; + + __m256i xVal, yVal, zVal; + for(;number < points; number++){ + + xVal = _mm256_load_si256(xPtr); + yVal = _mm256_loadu_si256(yPtr); + + zVal = _mm256_add_epi16(xVal, yVal); + _mm256_store_si256(zPtr, zVal); + + xPtr ++; + yPtr ++; + zPtr ++; + } + + number = points * 16; + for(;number < len; number++){ + z[number] = x[number] + y[number]; + } +#endif + +} + + +void srslte_vec_sub_sss_sse(short *x, short *y, short *z, uint32_t len) { #ifdef LV_HAVE_SSE unsigned int number = 0; @@ -148,7 +225,42 @@ void srslte_vec_sub_sss_simd(short *x, short *y, short *z, uint32_t len) #endif } -void srslte_vec_prod_sss_simd(short *x, short *y, short *z, uint32_t len) +void srslte_vec_sub_sss_avx(short *x, short *y, short *z, uint32_t len) +{ +#ifdef LV_HAVE_AVX + unsigned int number = 0; + const unsigned int points = len / 16; + + const __m256i* xPtr = (const __m256i*) x; + const __m256i* yPtr = (const __m256i*) y; + __m256i* zPtr = (__m256i*) z; + + __m256i xVal, yVal, zVal; + for(;number < points; number++){ + + xVal = _mm256_load_si256(xPtr); + yVal = _mm256_loadu_si256(yPtr); + + zVal = _mm256_sub_epi16(xVal, yVal); + + _mm256_store_si256(zPtr, zVal); + + xPtr ++; + yPtr ++; + zPtr ++; + } + + number = points * 16; + for(;number < len; number++){ + z[number] = x[number] - y[number]; + } + #endif +} + + + + +void srslte_vec_prod_sss_sse(short *x, short *y, short *z, uint32_t len) { #ifdef LV_HAVE_SSE unsigned int number = 0; @@ -180,7 +292,44 @@ void srslte_vec_prod_sss_simd(short *x, short *y, short *z, uint32_t len) #endif } -void srslte_vec_sc_div2_sss_simd(short *x, int k, short *z, uint32_t len) +void srslte_vec_prod_sss_avx(short *x, short *y, short *z, uint32_t len) +{ +#ifdef LV_HAVE_SSE + unsigned int number = 0; + const unsigned int points = len / 16; + + const __m256i* xPtr = (const __m256i*) x; + const __m256i* yPtr = (const __m256i*) y; + __m256i* zPtr = (__m256i*) z; + + __m256i xVal, yVal, zVal; + for(;number < points; number++){ + + xVal = _mm256_loadu_si256(xPtr); + yVal = _mm256_loadu_si256(yPtr); + + zVal = _mm256_mullo_epi16(xVal, yVal); + + _mm256_storeu_si256(zPtr, zVal); + + xPtr ++; + yPtr ++; + zPtr ++; + } + + number = points * 16; + for(;number < len; number++){ + z[number] = x[number] * y[number]; + } +#endif +} + + + + + + +void srslte_vec_sc_div2_sss_sse(short *x, int k, short *z, uint32_t len) { #ifdef LV_HAVE_SSE unsigned int number = 0; @@ -210,8 +359,40 @@ void srslte_vec_sc_div2_sss_simd(short *x, int k, short *z, uint32_t len) #endif } +void srslte_vec_sc_div2_sss_avx(short *x, int k, short *z, uint32_t len) +{ +#ifdef LV_HAVE_AVX + unsigned int number = 0; + const unsigned int points = len / 16; + + const __m256i* xPtr = (const __m256i*) x; + __m256i* zPtr = (__m256i*) z; + + __m256i xVal, zVal; + for(;number < points; number++){ + + xVal = _mm256_load_si256(xPtr); + + zVal = _mm256_srai_epi16(xVal, k); + + _mm256_store_si256(zPtr, zVal); + + xPtr ++; + zPtr ++; + } + + number = points * 16; + short divn = (1< + +namespace srslte { + +bool radio::init(char *args, char *devname) +{ + if (srslte_rf_open_devname(&rf_device, devname, args)) { + fprintf(stderr, "Error opening RF device\n"); + return false; + } + + tx_adv_negative = false; + agc_enabled = false; + burst_preamble_samples = 0; + burst_preamble_time_rounded = 0; + cur_tx_srate = 0; + is_start_of_burst = true; + + // Suppress radio stdout + srslte_rf_suppress_stdout(&rf_device); + + tx_adv_auto = true; + // Set default preamble length each known device + // We distinguish by device family, maybe we should calibrate per device + if (strstr(srslte_rf_name(&rf_device), "uhd")) { + burst_preamble_sec = uhd_default_burst_preamble_sec; + } else if (strstr(srslte_rf_name(&rf_device), "bladerf")) { + burst_preamble_sec = blade_default_burst_preamble_sec; + } else { + printf("\nWarning burst preamble is not calibrated for device %s. Set a value manually\n\n", srslte_rf_name(&rf_device)); + } + + return true; +} + +void radio::stop() +{ + srslte_rf_close(&rf_device); +} + +void radio::set_manual_calibration(rf_cal_t* calibration) +{ + srslte_rf_cal_t tx_cal; + tx_cal.dc_gain = calibration->tx_corr_dc_gain; + tx_cal.dc_phase = calibration->tx_corr_dc_phase; + tx_cal.iq_i = calibration->tx_corr_iq_i; + tx_cal.iq_q = calibration->tx_corr_iq_q; + srslte_rf_set_tx_cal(&rf_device, &tx_cal); +} + +void radio::set_tx_rx_gain_offset(float offset) { + srslte_rf_set_tx_rx_gain_offset(&rf_device, offset); +} + +void radio::set_burst_preamble(double preamble_us) +{ + burst_preamble_sec = (double) preamble_us/1e6; +} + +void radio::set_tx_adv(int nsamples) +{ + tx_adv_auto = false; + tx_adv_nsamples = nsamples; + if (!nsamples) { + tx_adv_sec = 0; + } + +} + +void radio::set_tx_adv_neg(bool tx_adv_is_neg) { + tx_adv_negative = tx_adv_is_neg; +} + +void radio::tx_offset(int offset_) +{ + offset = offset_; +} + +bool radio::start_agc(bool tx_gain_same_rx) +{ + if (srslte_rf_start_gain_thread(&rf_device, tx_gain_same_rx)) { + fprintf(stderr, "Error opening RF device\n"); + return false; + } + + agc_enabled = true; + + return true; +} +bool radio::rx_at(void* buffer, uint32_t nof_samples, srslte_timestamp_t rx_time) +{ + fprintf(stderr, "Not implemented\n"); + return false; +} + +bool radio::rx_now(void* buffer, uint32_t nof_samples, srslte_timestamp_t* rxd_time) +{ + if (srslte_rf_recv_with_time(&rf_device, buffer, nof_samples, true, + rxd_time?&rxd_time->full_secs:NULL, rxd_time?&rxd_time->frac_secs:NULL) > 0) { + return true; + } else { + return false; + } +} + +void radio::get_time(srslte_timestamp_t *now) { + srslte_rf_get_time(&rf_device, &now->full_secs, &now->frac_secs); +} + +// TODO: Use Calibrated values for this +float radio::set_tx_power(float power) +{ + if (power > 10) { + power = 10; + } + if (power < -50) { + power = -50; + } + float gain = power + 74; + srslte_rf_set_tx_gain(&rf_device, gain); + return gain; +} + +float radio::get_max_tx_power() +{ + return 10; +} + +float radio::get_rssi() +{ + return srslte_rf_get_rssi(&rf_device); +} + +bool radio::has_rssi() +{ + return srslte_rf_has_rssi(&rf_device); +} + +bool radio::tx(void* buffer, uint32_t nof_samples, srslte_timestamp_t tx_time) +{ + if (!tx_adv_negative) { + srslte_timestamp_sub(&tx_time, 0, tx_adv_sec); + } else { + srslte_timestamp_add(&tx_time, 0, tx_adv_sec); + } + + if (is_start_of_burst) { + if (burst_preamble_samples != 0) { + srslte_timestamp_t tx_time_pad; + srslte_timestamp_copy(&tx_time_pad, &tx_time); + srslte_timestamp_sub(&tx_time_pad, 0, burst_preamble_time_rounded); + save_trace(1, &tx_time_pad); + srslte_rf_send_timed2(&rf_device, zeros, burst_preamble_samples, tx_time_pad.full_secs, tx_time_pad.frac_secs, true, false); + is_start_of_burst = false; + } + } + + // Save possible end of burst time + srslte_timestamp_copy(&end_of_burst_time, &tx_time); + srslte_timestamp_add(&end_of_burst_time, 0, (double) nof_samples/cur_tx_srate); + + save_trace(0, &tx_time); + int ret = srslte_rf_send_timed2(&rf_device, buffer, nof_samples+offset, tx_time.full_secs, tx_time.frac_secs, is_start_of_burst, false); + offset = 0; + is_start_of_burst = false; + if (ret > 0) { + return true; + } else { + return false; + } +} + +uint32_t radio::get_tti_len() +{ + return sf_len; +} + +void radio::set_tti_len(uint32_t sf_len_) +{ + sf_len = sf_len_; +} + +void radio::tx_end() +{ + if (!is_start_of_burst) { + save_trace(2, &end_of_burst_time); + srslte_rf_send_timed2(&rf_device, zeros, 0, end_of_burst_time.full_secs, end_of_burst_time.frac_secs, false, true); + is_start_of_burst = true; + } +} + +void radio::start_trace() { + trace_enabled = true; +} + +void radio::set_tti(uint32_t tti_) { + tti = tti_; +} + +void radio::write_trace(std::string filename) +{ + tr_local_time.writeToBinary(filename + ".local"); + tr_is_eob.writeToBinary(filename + ".eob"); + tr_usrp_time.writeToBinary(filename + ".usrp"); + tr_tx_time.writeToBinary(filename + ".tx"); +} + +void radio::save_trace(uint32_t is_eob, srslte_timestamp_t *tx_time) { + if (trace_enabled) { + tr_local_time.push_cur_time_us(tti); + srslte_timestamp_t usrp_time; + srslte_rf_get_time(&rf_device, &usrp_time.full_secs, &usrp_time.frac_secs); + tr_usrp_time.push(tti, srslte_timestamp_uint32(&usrp_time)); + tr_tx_time.push(tti, srslte_timestamp_uint32(tx_time)); + tr_is_eob.push(tti, is_eob); + } +} + +void radio::set_rx_freq(float freq) +{ + rx_freq = srslte_rf_set_rx_freq(&rf_device, freq); +} + +void radio::set_rx_gain(float gain) +{ + srslte_rf_set_rx_gain(&rf_device, gain); +} + +double radio::set_rx_gain_th(float gain) +{ + return srslte_rf_set_rx_gain_th(&rf_device, gain); +} + +void radio::set_master_clock_rate(float rate) +{ + srslte_rf_set_master_clock_rate(&rf_device, rate); +} + +void radio::set_rx_srate(float srate) +{ + srslte_rf_set_rx_srate(&rf_device, srate); +} + +void radio::set_tx_freq(float freq) +{ + tx_freq = srslte_rf_set_tx_freq(&rf_device, freq); +} + +void radio::set_tx_gain(float gain) +{ + srslte_rf_set_tx_gain(&rf_device, gain); +} + +float radio::get_rx_freq() +{ + return rx_freq; +} + +float radio::get_tx_freq() +{ + return tx_freq; +} + +float radio::get_tx_gain() +{ + return srslte_rf_get_tx_gain(&rf_device); +} + +float radio::get_rx_gain() +{ + return srslte_rf_get_rx_gain(&rf_device); +} + +void radio::set_tx_srate(float srate) +{ + cur_tx_srate = srslte_rf_set_tx_srate(&rf_device, srate); + burst_preamble_samples = (uint32_t) (cur_tx_srate * burst_preamble_sec); + if (burst_preamble_samples > burst_preamble_max_samples) { + burst_preamble_samples = burst_preamble_max_samples; + fprintf(stderr, "Error setting TX srate %.1f MHz. Maximum frequency for zero prepadding is 30.72 MHz\n", srate*1e-6); + } + burst_preamble_time_rounded = (double) burst_preamble_samples/cur_tx_srate; + + + int nsamples=0; + /* Set time advance for each known device if in auto mode */ + if (tx_adv_auto) { + + /* This values have been calibrated using the prach_test_usrp tool in srsLTE */ + + if (!strcmp(srslte_rf_name(&rf_device), "uhd_b200")) { + + double srate_khz = round(cur_tx_srate/1e3); + if (srate_khz == 1.92e3) { + nsamples = 54; + } else if (srate_khz == 3.84e3) { + nsamples = 69; + } else if (srate_khz == 5.76e3) { + nsamples = 93; + } else if (srate_khz == 11.52e3) { + nsamples = 120; + } else if (srate_khz == 15.36e3) { + nsamples = 131; + } else if (srate_khz == 23.04e3) { + nsamples = 175; + } else { + /* Interpolate from known values */ + printf("\nWarning TX/RX time offset for sampling rate %.0f KHz not calibrated. Using interpolated value\n\n", cur_tx_srate); + nsamples = cur_tx_srate*(uhd_default_tx_adv_samples * (1/cur_tx_srate) + uhd_default_tx_adv_offset_sec); + } + } else if (!strcmp(srslte_rf_name(&rf_device), "uhd_x300")) { + + double srate_khz = round(cur_tx_srate/1e3); + if (srate_khz == 1.92e3) { + nsamples = 50; + } else if (srate_khz == 3.84e3) { + nsamples = 65; + } else if (srate_khz == 5.76e3) { + nsamples = 75; + } else if (srate_khz == 11.52e3) { + nsamples = 89; + } else if (srate_khz == 15.36e3) { + nsamples = 86; + } else if (srate_khz == 23.04e3) { + nsamples = 119; + } else { + /* Interpolate from known values */ + printf("\nWarning TX/RX time offset for sampling rate %.0f KHz not calibrated. Using interpolated value\n\n", cur_tx_srate); + nsamples = cur_tx_srate*(uhd_default_tx_adv_samples * (1/cur_tx_srate) + uhd_default_tx_adv_offset_sec); + } + } else if (!strcmp(srslte_rf_name(&rf_device), "bladerf")) { + + double srate_khz = round(cur_tx_srate/1e3); + if (srate_khz == 1.92e3) { + nsamples = 16; + } else if (srate_khz == 3.84e3) { + nsamples = 18; + } else if (srate_khz == 5.76e3) { + nsamples = 16; + } else if (srate_khz == 11.52e3) { + nsamples = 21; + } else if (srate_khz == 15.36e3) { + nsamples = 14; + } else if (srate_khz == 23.04e3) { + nsamples = 21; + } else { + /* Interpolate from known values */ + printf("\nWarning TX/RX time offset for sampling rate %.0f KHz not calibrated. Using interpolated value\n\n", cur_tx_srate); + tx_adv_sec = blade_default_tx_adv_samples * (1/cur_tx_srate) + blade_default_tx_adv_offset_sec; + } + } else { + printf("\nWarning TX/RX time offset has not been calibrated for device %s. Set a value manually\n\n", srslte_rf_name(&rf_device)); + } + } else { + nsamples = tx_adv_nsamples; + printf("Setting manual TX/RX offset to %d samples\n", nsamples); + } + + // Calculate TX advance in seconds from samples and sampling rate + tx_adv_sec = nsamples/cur_tx_srate; + + printf("Setting TX/RX offset %d samples, %.2f us\n", nsamples, tx_adv_sec*1e6); +} + +void radio::start_rx() +{ + srslte_rf_start_rx_stream(&rf_device); +} + +void radio::stop_rx() +{ + srslte_rf_stop_rx_stream(&rf_device); +} + +void radio::register_error_handler(srslte_rf_error_handler_t h) +{ + srslte_rf_register_error_handler(&rf_device, h); +} + + +} + diff --git a/lib/src/radio/radio_multi.cc b/lib/src/radio/radio_multi.cc new file mode 100644 index 000000000..c8de57f46 --- /dev/null +++ b/lib/src/radio/radio_multi.cc @@ -0,0 +1,49 @@ +#include "srslte/radio/radio_multi.h" + +namespace srslte { + +bool radio_multi::init_multi(uint32_t nof_rx_antennas, char* args, char* devname) +{ + if (srslte_rf_open_devname_multi(&rf_device, devname, args, nof_rx_antennas)) { + fprintf(stderr, "Error opening RF device\n"); + return false; + } + + tx_adv_negative = false; + agc_enabled = false; + burst_preamble_samples = 0; + burst_preamble_time_rounded = 0; + cur_tx_srate = 0; + is_start_of_burst = true; + + + tx_adv_auto = true; + // Set default preamble length each known device + // We distinguish by device family, maybe we should calibrate per device + if (strstr(srslte_rf_name(&rf_device), "uhd")) { + burst_preamble_sec = uhd_default_burst_preamble_sec; + } else if (strstr(srslte_rf_name(&rf_device), "bladerf")) { + burst_preamble_sec = blade_default_burst_preamble_sec; + } else { + printf("\nWarning burst preamble is not calibrated for device %s. Set a value manually\n\n", srslte_rf_name(&rf_device)); + } + + return true; +} + +bool radio_multi::rx_now(cf_t *buffer[SRSLTE_MAX_PORTS], uint32_t nof_samples, srslte_timestamp_t* rxd_time) +{ + void *ptr[SRSLTE_MAX_PORTS]; + for (int i=0;ifull_secs:NULL, rxd_time?&rxd_time->frac_secs:NULL) > 0) { + return true; + } else { + return false; + } +} + + +} \ No newline at end of file diff --git a/lib/src/upper/CMakeLists.txt b/lib/src/upper/CMakeLists.txt new file mode 100644 index 000000000..e1a0507e3 --- /dev/null +++ b/lib/src/upper/CMakeLists.txt @@ -0,0 +1,25 @@ +# +# Copyright 2013-2017 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(GLOB SOURCES "*.cc") +add_library(srslte_upper SHARED ${SOURCES}) +target_link_libraries(srslte_upper srslte_common srslte_asn1) +install(TARGETS srslte_upper DESTINATION ${LIBRARY_DIR}) +SRSLTE_SET_PIC(srslte_upper) diff --git a/lib/src/upper/gw.cc b/lib/src/upper/gw.cc new file mode 100644 index 000000000..beb003c51 --- /dev/null +++ b/lib/src/upper/gw.cc @@ -0,0 +1,288 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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/upper/gw.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +namespace srslte { + +gw::gw() + :if_up(false) +{} + +void gw::init(srsue::pdcp_interface_gw *pdcp_, srsue::rrc_interface_gw *rrc_, srsue::ue_interface *ue_, log *gw_log_) +{ + pool = byte_buffer_pool::get_instance(); + pdcp = pdcp_; + rrc = rrc_; + ue = ue_; + gw_log = gw_log_; + run_enable = true; + + gettimeofday(&metrics_time[1], NULL); + dl_tput_bytes = 0; + ul_tput_bytes = 0; +} + +void gw::stop() +{ + if(run_enable) + { + run_enable = false; + if(if_up) + { + close(tun_fd); + + // Wait thread to exit gracefully otherwise might leave a mutex locked + int cnt=0; + while(running && cnt<100) { + usleep(10000); + cnt++; + } + if (running) { + thread_cancel(); + } + wait_thread_finish(); + } + + // TODO: tear down TUN device? + } +} + +void gw::get_metrics(gw_metrics_t &m) +{ + + gettimeofday(&metrics_time[2], NULL); + get_time_interval(metrics_time); + double secs = (double) metrics_time[0].tv_sec+metrics_time[0].tv_usec*1e-6; + + m.dl_tput_mbps = (dl_tput_bytes*8/(double)1e6)/secs; + m.ul_tput_mbps = (ul_tput_bytes*8/(double)1e6)/secs; + gw_log->info("RX throughput: %4.6f Mbps. TX throughput: %4.6f Mbps.\n", + m.dl_tput_mbps, m.ul_tput_mbps); + + memcpy(&metrics_time[1], &metrics_time[2], sizeof(struct timeval)); + dl_tput_bytes = 0; + ul_tput_bytes = 0; +} + +/******************************************************************************* + PDCP interface +*******************************************************************************/ +void gw::write_pdu(uint32_t lcid, byte_buffer_t *pdu) +{ + gw_log->info_hex(pdu->msg, pdu->N_bytes, "RX PDU"); + gw_log->info("RX PDU. Stack latency: %ld us\n", pdu->get_latency_us()); + dl_tput_bytes += pdu->N_bytes; + if(!if_up) + { + gw_log->warning("TUN/TAP not up - dropping gw RX message\n"); + }else{ + int n = write(tun_fd, pdu->msg, pdu->N_bytes); + if(n > 0 && (pdu->N_bytes != (uint32_t)n)) + { + gw_log->warning("DL TUN/TAP write failure\n"); + } + } + pool->deallocate(pdu); +} + +/******************************************************************************* + NAS interface +*******************************************************************************/ +error_t gw::setup_if_addr(uint32_t ip_addr, char *err_str) +{ + if(!if_up) + { + if(init_if(err_str)) + { + gw_log->error("init_if failed\n"); + return(ERROR_CANT_START); + } + } + + // Setup the IP address + sock = socket(AF_INET, SOCK_DGRAM, 0); + ifr.ifr_addr.sa_family = AF_INET; + ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr = htonl(ip_addr); + if(0 > ioctl(sock, SIOCSIFADDR, &ifr)) + { + err_str = strerror(errno); + gw_log->debug("Failed to set socket address: %s\n", err_str); + close(tun_fd); + return(ERROR_CANT_START); + } + ifr.ifr_netmask.sa_family = AF_INET; + ((struct sockaddr_in *)&ifr.ifr_netmask)->sin_addr.s_addr = inet_addr("255.255.255.0"); + if(0 > ioctl(sock, SIOCSIFNETMASK, &ifr)) + { + err_str = strerror(errno); + gw_log->debug("Failed to set socket netmask: %s\n", err_str); + close(tun_fd); + return(ERROR_CANT_START); + } + + // Setup a thread to receive packets from the TUN device + start(GW_THREAD_PRIO); + + return(ERROR_NONE); +} + +error_t gw::init_if(char *err_str) +{ + if(if_up) + { + return(ERROR_ALREADY_STARTED); + } + + char dev[IFNAMSIZ] = "tun_srsue"; + + // Construct the TUN device + tun_fd = open("/dev/net/tun", O_RDWR); + gw_log->info("TUN file descriptor = %d\n", tun_fd); + if(0 > tun_fd) + { + err_str = strerror(errno); + gw_log->debug("Failed to open TUN device: %s\n", err_str); + return(ERROR_CANT_START); + } + memset(&ifr, 0, sizeof(ifr)); + ifr.ifr_flags = IFF_TUN | IFF_NO_PI; + strncpy(ifr.ifr_ifrn.ifrn_name, dev, IFNAMSIZ); + if(0 > ioctl(tun_fd, TUNSETIFF, &ifr)) + { + err_str = strerror(errno); + gw_log->debug("Failed to set TUN device name: %s\n", err_str); + close(tun_fd); + return(ERROR_CANT_START); + } + + // Bring up the interface + sock = socket(AF_INET, SOCK_DGRAM, 0); + if(0 > ioctl(sock, SIOCGIFFLAGS, &ifr)) + { + err_str = strerror(errno); + gw_log->debug("Failed to bring up socket: %s\n", err_str); + close(tun_fd); + return(ERROR_CANT_START); + } + ifr.ifr_flags |= IFF_UP | IFF_RUNNING; + if(0 > ioctl(sock, SIOCSIFFLAGS, &ifr)) + { + err_str = strerror(errno); + gw_log->debug("Failed to set socket flags: %s\n", err_str); + close(tun_fd); + return(ERROR_CANT_START); + } + + if_up = true; + + return(ERROR_NONE); +} + +/********************/ +/* GW Receive */ +/********************/ +void gw::run_thread() +{ + struct iphdr *ip_pkt; + uint32 idx = 0; + int32 N_bytes; + byte_buffer_t *pdu = pool_allocate; + + gw_log->info("GW IP packet receiver thread run_enable\n"); + + running = true; + while(run_enable) + { + if (SRSLTE_MAX_BUFFER_SIZE_BYTES-SRSLTE_BUFFER_HEADER_OFFSET > idx) { + N_bytes = read(tun_fd, &pdu->msg[idx], SRSLTE_MAX_BUFFER_SIZE_BYTES-SRSLTE_BUFFER_HEADER_OFFSET - idx); + } else { + gw_log->error("GW pdu buffer full - gw receive thread exiting.\n"); + gw_log->console("GW pdu buffer full - gw receive thread exiting.\n"); + break; + } + gw_log->debug("Read %d bytes from TUN fd=%d, idx=%d\n", N_bytes, tun_fd, idx); + if(N_bytes > 0) + { + pdu->N_bytes = idx + N_bytes; + ip_pkt = (struct iphdr*)pdu->msg; + + // Warning: Accept only IPv4 packets + if (ip_pkt->version == 4) { + // Check if entire packet was received + if(ntohs(ip_pkt->tot_len) == pdu->N_bytes) + { + gw_log->info_hex(pdu->msg, pdu->N_bytes, "TX PDU"); + + while(run_enable && (!rrc->rrc_connected() || !rrc->have_drb())) { + rrc->rrc_connect(); + usleep(1000); + } + + if (!run_enable) { + break; + } + + // Send PDU directly to PDCP + pdu->set_timestamp(); + ul_tput_bytes += pdu->N_bytes; + pdcp->write_sdu(RB_ID_DRB1, pdu); + + do { + pdu = pool_allocate; + if (!pdu) { + printf("Not enough buffers in pool\n"); + usleep(100000); + } + } while(!pdu); + idx = 0; + }else{ + idx += N_bytes; + } + } + }else{ + gw_log->error("Failed to read from TUN interface - gw receive thread exiting.\n"); + gw_log->console("Failed to read from TUN interface - gw receive thread exiting.\n"); + break; + } + } + running = false; + gw_log->info("GW IP receiver thread exiting.\n"); +} + +} // namespace srsue diff --git a/lib/src/upper/pdcp.cc b/lib/src/upper/pdcp.cc new file mode 100644 index 000000000..e729118ce --- /dev/null +++ b/lib/src/upper/pdcp.cc @@ -0,0 +1,130 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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/upper/pdcp.h" + +namespace srslte { + +pdcp::pdcp() +{} + +void pdcp::init(srsue::rlc_interface_pdcp *rlc_, srsue::rrc_interface_pdcp *rrc_, srsue::gw_interface_pdcp *gw_, log *pdcp_log_, uint8_t direction_) +{ + rlc = rlc_; + rrc = rrc_; + gw = gw_; + pdcp_log = pdcp_log_; + direction = direction_; + + pdcp_array[0].init(rlc, rrc, gw, pdcp_log, RB_ID_SRB0, direction); // SRB0 +} + +void pdcp::stop() +{} + +void pdcp::reset() +{ + for(uint32_t i=0;i= SRSLTE_N_RADIO_BEARERS) { + pdcp_log->error("Radio bearer id must be in [0:%d] - %d\n", SRSLTE_N_RADIO_BEARERS, lcid); + return; + } + if (!pdcp_array[lcid].is_active()) { + pdcp_array[lcid].init(rlc, rrc, gw, pdcp_log, lcid, direction, cnfg); + pdcp_log->info("Added bearer %s\n", rb_id_text[lcid]); + } else { + pdcp_log->warning("Bearer %s already configured. Reconfiguration not supported\n", rb_id_text[lcid]); + } +} + +void pdcp::config_security(uint32_t lcid, + uint8_t *k_rrc_enc, + uint8_t *k_rrc_int, + CIPHERING_ALGORITHM_ID_ENUM cipher_algo, + INTEGRITY_ALGORITHM_ID_ENUM integ_algo) +{ + if(valid_lcid(lcid)) + pdcp_array[lcid].config_security(k_rrc_enc, k_rrc_int, cipher_algo, integ_algo); +} + +/******************************************************************************* + RLC interface +*******************************************************************************/ +void pdcp::write_pdu(uint32_t lcid, byte_buffer_t *pdu) +{ + if(valid_lcid(lcid)) + pdcp_array[lcid].write_pdu(pdu); +} + +void pdcp::write_pdu_bcch_bch(byte_buffer_t *sdu) +{ + rrc->write_pdu_bcch_bch(sdu); +} +void pdcp::write_pdu_bcch_dlsch(byte_buffer_t *sdu) +{ + rrc->write_pdu_bcch_dlsch(sdu); +} + +void pdcp::write_pdu_pcch(byte_buffer_t *sdu) +{ + rrc->write_pdu_pcch(sdu); +} + +/******************************************************************************* + Helpers +*******************************************************************************/ +bool pdcp::valid_lcid(uint32_t lcid) +{ + if(lcid < 0 || lcid >= SRSLTE_N_RADIO_BEARERS) { + pdcp_log->error("Radio bearer id must be in [0:%d] - %d", SRSLTE_N_RADIO_BEARERS, lcid); + return false; + } + if(!pdcp_array[lcid].is_active()) { + pdcp_log->error("PDCP entity for logical channel %d has not been activated\n", lcid); + return false; + } + return true; +} + +} // namespace srsue diff --git a/lib/src/upper/pdcp_entity.cc b/lib/src/upper/pdcp_entity.cc new file mode 100644 index 000000000..23fe8768d --- /dev/null +++ b/lib/src/upper/pdcp_entity.cc @@ -0,0 +1,284 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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/upper/pdcp_entity.h" +#include "srslte/common/security.h" + +namespace srslte { + +pdcp_entity::pdcp_entity() + :active(false) + ,tx_count(0) + ,rx_count(0) + ,do_security(false) + ,sn_len(12) +{ + pool = byte_buffer_pool::get_instance(); +} + +void pdcp_entity::init(srsue::rlc_interface_pdcp *rlc_, + srsue::rrc_interface_pdcp *rrc_, + srsue::gw_interface_pdcp *gw_, + srslte::log *log_, + uint32_t lcid_, + u_int8_t direction_, + LIBLTE_RRC_PDCP_CONFIG_STRUCT *cnfg) +{ + rlc = rlc_; + rrc = rrc_; + gw = gw_; + log = log_; + lcid = lcid_; + direction = direction_; + active = true; + + tx_count = 0; + rx_count = 0; + do_security = false; + + if(cnfg) + { + if(cnfg->rlc_um_pdcp_sn_size_present) { + if(LIBLTE_RRC_PDCP_SN_SIZE_7_BITS == cnfg->rlc_um_pdcp_sn_size) { + sn_len = 7; + } + } + // TODO: handle remainder of cnfg + } + log->debug("Init %s\n", rb_id_text[lcid]); +} + +void pdcp_entity::reset() +{ + active = false; + if(log) + log->debug("Reset %s\n", rb_id_text[lcid]); +} + +bool pdcp_entity::is_active() +{ + return active; +} + +// RRC interface +void pdcp_entity::write_sdu(byte_buffer_t *sdu) +{ + log->info_hex(sdu->msg, sdu->N_bytes, "TX %s SDU, do_security = %s", rb_id_text[lcid], (do_security)?"true":"false"); + + // Handle SRB messages + switch(lcid) + { + case RB_ID_SRB0: + rlc->write_sdu(lcid, sdu); + break; + case RB_ID_SRB1: // Intentional fall-through + case RB_ID_SRB2: + pdcp_pack_control_pdu(tx_count, sdu); + if(do_security) + { + integrity_generate(&k_rrc_int[16], + tx_count, + lcid-1, + direction, + sdu->msg, + sdu->N_bytes-4, + &sdu->msg[sdu->N_bytes-4]); + } + tx_count++; + rlc->write_sdu(lcid, sdu); + + break; + } + + // Handle DRB messages + if(lcid >= RB_ID_DRB1) + { + if(12 == sn_len) + { + pdcp_pack_data_pdu_long_sn(tx_count++, sdu); + } else { + pdcp_pack_data_pdu_short_sn(tx_count++, sdu); + } + rlc->write_sdu(lcid, sdu); + } +} + +void pdcp_entity::config_security(uint8_t *k_rrc_enc_, + uint8_t *k_rrc_int_, + CIPHERING_ALGORITHM_ID_ENUM cipher_algo_, + INTEGRITY_ALGORITHM_ID_ENUM integ_algo_) +{ + do_security = true; + for(int i=0; i<32; i++) + { + k_rrc_enc[i] = k_rrc_enc_[i]; + k_rrc_int[i] = k_rrc_int_[i]; + } + cipher_algo = cipher_algo_; + integ_algo = integ_algo_; +} + +// RLC interface +void pdcp_entity::write_pdu(byte_buffer_t *pdu) +{ + // Handle SRB messages + switch(lcid) + { + case RB_ID_SRB0: + // Simply pass on to RRC + log->info_hex(pdu->msg, pdu->N_bytes, "RX %s PDU", rb_id_text[lcid]); + rrc->write_pdu(RB_ID_SRB0, pdu); + break; + case RB_ID_SRB1: // Intentional fall-through + case RB_ID_SRB2: + uint32_t sn; + log->info_hex(pdu->msg, pdu->N_bytes, "RX %s PDU", rb_id_text[lcid]); + pdcp_unpack_control_pdu(pdu, &sn); + log->info_hex(pdu->msg, pdu->N_bytes, "RX %s SDU SN: %d", + rb_id_text[lcid], sn); + rrc->write_pdu(lcid, pdu); + break; + } + + // Handle DRB messages + if(lcid >= RB_ID_DRB1) + { + uint32_t sn; + if(12 == sn_len) + { + pdcp_unpack_data_pdu_long_sn(pdu, &sn); + } else { + pdcp_unpack_data_pdu_short_sn(pdu, &sn); + } + log->info_hex(pdu->msg, pdu->N_bytes, "RX %s PDU: %d", rb_id_text[lcid], sn); + gw->write_pdu(lcid, pdu); + } +} + +void pdcp_entity::integrity_generate( uint8_t *key_128, + uint32_t count, + uint8_t rb_id, + uint8_t direction, + uint8_t *msg, + uint32_t msg_len, + uint8_t *mac) +{ + switch(integ_algo) + { + case INTEGRITY_ALGORITHM_ID_EIA0: + break; + case INTEGRITY_ALGORITHM_ID_128_EIA1: + security_128_eia1(key_128, + count, + rb_id, + direction, + msg, + msg_len, + mac); + break; + case INTEGRITY_ALGORITHM_ID_128_EIA2: + security_128_eia2(key_128, + count, + rb_id, + direction, + msg, + msg_len, + mac); + break; + default: + break; + } +} + +/**************************************************************************** + * Pack/Unpack helper functions + * Ref: 3GPP TS 36.323 v10.1.0 + ***************************************************************************/ + +void pdcp_pack_control_pdu(uint32_t sn, byte_buffer_t *sdu) +{ + // Make room and add header + sdu->msg--; + sdu->N_bytes++; + *sdu->msg = sn & 0x1F; + + // Add MAC + sdu->msg[sdu->N_bytes++] = (PDCP_CONTROL_MAC_I >> 24) & 0xFF; + sdu->msg[sdu->N_bytes++] = (PDCP_CONTROL_MAC_I >> 16) & 0xFF; + sdu->msg[sdu->N_bytes++] = (PDCP_CONTROL_MAC_I >> 8) & 0xFF; + sdu->msg[sdu->N_bytes++] = PDCP_CONTROL_MAC_I & 0xFF; + +} + +void pdcp_unpack_control_pdu(byte_buffer_t *pdu, uint32_t *sn) +{ + // Strip header + *sn = *pdu->msg & 0x1F; + pdu->msg++; + pdu->N_bytes--; + + // Strip MAC + pdu->N_bytes -= 4; + + // TODO: integrity check MAC +} + +void pdcp_pack_data_pdu_short_sn(uint32_t sn, byte_buffer_t *sdu) +{ + // Make room and add header + sdu->msg--; + sdu->N_bytes++; + sdu->msg[0] = (PDCP_D_C_DATA_PDU << 7) | (sn & 0x7F); +} + +void pdcp_unpack_data_pdu_short_sn(byte_buffer_t *sdu, uint32_t *sn) +{ + // Strip header + *sn = sdu->msg[0] & 0x7F; + sdu->msg++; + sdu->N_bytes--; +} + +void pdcp_pack_data_pdu_long_sn(uint32_t sn, byte_buffer_t *sdu) +{ + // Make room and add header + sdu->msg -= 2; + sdu->N_bytes += 2; + sdu->msg[0] = (PDCP_D_C_DATA_PDU << 7) | ((sn >> 8) & 0x0F); + sdu->msg[1] = sn & 0xFF; +} + +void pdcp_unpack_data_pdu_long_sn(byte_buffer_t *sdu, uint32_t *sn) +{ + // Strip header + *sn = (sdu->msg[0] & 0x0F) << 8; + *sn |= sdu->msg[1]; + sdu->msg += 2; + sdu->N_bytes -= 2; +} + +} diff --git a/lib/src/upper/rlc.cc b/lib/src/upper/rlc.cc new file mode 100644 index 000000000..becb15c37 --- /dev/null +++ b/lib/src/upper/rlc.cc @@ -0,0 +1,262 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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 PARTICRXAR 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/upper/rlc.h" +#include "srslte/upper/rlc_tm.h" +#include "srslte/upper/rlc_um.h" +#include "srslte/upper/rlc_am.h" + +namespace srslte { + +rlc::rlc() +{ + pool = byte_buffer_pool::get_instance(); +} + +void rlc::init(srsue::pdcp_interface_rlc *pdcp_, + srsue::rrc_interface_rlc *rrc_, + srsue::ue_interface *ue_, + log *rlc_log_, + mac_interface_timers *mac_timers_) +{ + pdcp = pdcp_; + rrc = rrc_; + ue = ue_; + rlc_log = rlc_log_; + mac_timers = mac_timers_; + + gettimeofday(&metrics_time[1], NULL); + reset_metrics(); + + rlc_array[0].init(RLC_MODE_TM, rlc_log, RB_ID_SRB0, pdcp, rrc, mac_timers); // SRB0 +} + +void rlc::reset_metrics() +{ + bzero(dl_tput_bytes, sizeof(long)*SRSLTE_N_RADIO_BEARERS); + bzero(ul_tput_bytes, sizeof(long)*SRSLTE_N_RADIO_BEARERS); +} + +void rlc::stop() +{ + reset(); +} + +void rlc::get_metrics(rlc_metrics_t &m) +{ + + gettimeofday(&metrics_time[2], NULL); + get_time_interval(metrics_time); + double secs = (double)metrics_time[0].tv_sec + metrics_time[0].tv_usec*1e-6; + + m.dl_tput_mbps = 0; + m.ul_tput_mbps = 0; + for (int i=0;iinfo("LCID=%d, RX throughput: %4.6f Mbps. TX throughput: %4.6f Mbps.\n", + i, + (dl_tput_bytes[i]*8/(double)1e6)/secs, + (ul_tput_bytes[i]*8/(double)1e6)/secs); + } + } + + memcpy(&metrics_time[1], &metrics_time[2], sizeof(struct timeval)); + reset_metrics(); +} + +void rlc::reset() +{ + for(uint32_t i=0; iinfo_hex(payload, nof_bytes, "BCCH BCH message received."); + dl_tput_bytes[0] += nof_bytes; + byte_buffer_t *buf = pool_allocate; + memcpy(buf->msg, payload, nof_bytes); + buf->N_bytes = nof_bytes; + buf->set_timestamp(); + pdcp->write_pdu_bcch_bch(buf); +} + +void rlc::write_pdu_bcch_dlsch(uint8_t *payload, uint32_t nof_bytes) +{ + rlc_log->info_hex(payload, nof_bytes, "BCCH TXSCH message received."); + dl_tput_bytes[0] += nof_bytes; + byte_buffer_t *buf = pool_allocate; + memcpy(buf->msg, payload, nof_bytes); + buf->N_bytes = nof_bytes; + buf->set_timestamp(); + pdcp->write_pdu_bcch_dlsch(buf); +} + +void rlc::write_pdu_pcch(uint8_t *payload, uint32_t nof_bytes) +{ + rlc_log->info_hex(payload, nof_bytes, "PCCH message received."); + dl_tput_bytes[0] += nof_bytes; + byte_buffer_t *buf = pool_allocate; + memcpy(buf->msg, payload, nof_bytes); + buf->N_bytes = nof_bytes; + buf->set_timestamp(); + pdcp->write_pdu_pcch(buf); +} + +/******************************************************************************* + RRC interface +*******************************************************************************/ +void rlc::add_bearer(uint32_t lcid) +{ + // No config provided - use defaults for lcid + LIBLTE_RRC_RLC_CONFIG_STRUCT cnfg; + if(RB_ID_SRB1 == lcid || RB_ID_SRB2 == lcid) + { + if (!rlc_array[lcid].active()) { + cnfg.rlc_mode = LIBLTE_RRC_RLC_MODE_AM; + cnfg.ul_am_rlc.t_poll_retx = LIBLTE_RRC_T_POLL_RETRANSMIT_MS45; + cnfg.ul_am_rlc.poll_pdu = LIBLTE_RRC_POLL_PDU_INFINITY; + cnfg.ul_am_rlc.poll_byte = LIBLTE_RRC_POLL_BYTE_INFINITY; + cnfg.ul_am_rlc.max_retx_thresh = LIBLTE_RRC_MAX_RETX_THRESHOLD_T4; + cnfg.dl_am_rlc.t_reordering = LIBLTE_RRC_T_REORDERING_MS35; + cnfg.dl_am_rlc.t_status_prohibit = LIBLTE_RRC_T_STATUS_PROHIBIT_MS0; + add_bearer(lcid, &cnfg); + } else { + rlc_log->warning("Bearer %s already configured. Reconfiguration not supported\n", rb_id_text[lcid]); + } + }else{ + rlc_log->error("Radio bearer %s does not support default RLC configuration.", + rb_id_text[lcid]); + } +} + +void rlc::add_bearer(uint32_t lcid, LIBLTE_RRC_RLC_CONFIG_STRUCT *cnfg) +{ + if(lcid < 0 || lcid >= SRSLTE_N_RADIO_BEARERS) { + rlc_log->error("Radio bearer id must be in [0:%d] - %d\n", SRSLTE_N_RADIO_BEARERS, lcid); + return; + } + + + if (!rlc_array[lcid].active()) { + rlc_log->info("Adding radio bearer %s with mode %s\n", + rb_id_text[lcid], liblte_rrc_rlc_mode_text[cnfg->rlc_mode]); + switch(cnfg->rlc_mode) + { + case LIBLTE_RRC_RLC_MODE_AM: + rlc_array[lcid].init(RLC_MODE_AM, rlc_log, lcid, pdcp, rrc, mac_timers); + break; + case LIBLTE_RRC_RLC_MODE_UM_BI: + rlc_array[lcid].init(RLC_MODE_UM, rlc_log, lcid, pdcp, rrc, mac_timers); + break; + case LIBLTE_RRC_RLC_MODE_UM_UNI_DL: + rlc_array[lcid].init(RLC_MODE_UM, rlc_log, lcid, pdcp, rrc, mac_timers); + break; + case LIBLTE_RRC_RLC_MODE_UM_UNI_UL: + rlc_array[lcid].init(RLC_MODE_UM, rlc_log, lcid, pdcp, rrc, mac_timers); + break; + default: + rlc_log->error("Cannot add RLC entity - invalid mode\n"); + return; + } + } else { + rlc_log->warning("Bearer %s already created.\n", rb_id_text[lcid]); + } + rlc_array[lcid].configure(cnfg); + +} + +/******************************************************************************* + Helpers +*******************************************************************************/ +bool rlc::valid_lcid(uint32_t lcid) +{ + if(lcid < 0 || lcid >= SRSLTE_N_RADIO_BEARERS) { + return false; + } + if(!rlc_array[lcid].active()) { + return false; + } + return true; +} + + +} // namespace srsue diff --git a/lib/src/upper/rlc_am.cc b/lib/src/upper/rlc_am.cc new file mode 100644 index 000000000..f044c73c9 --- /dev/null +++ b/lib/src/upper/rlc_am.cc @@ -0,0 +1,1485 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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/upper/rlc_am.h" + +#include +#include + +#define MOD 1024 +#define RX_MOD_BASE(x) (x-vr_r)%1024 +#define TX_MOD_BASE(x) (x-vt_a)%1024 + +namespace srslte { + +rlc_am::rlc_am() : tx_sdu_queue(16) +{ + tx_sdu = NULL; + rx_sdu = NULL; + pool = byte_buffer_pool::get_instance(); + + pthread_mutex_init(&mutex, NULL); + + vt_a = 0; + vt_ms = RLC_AM_WINDOW_SIZE; + vt_s = 0; + poll_sn = 0; + + vr_r = 0; + vr_mr = RLC_AM_WINDOW_SIZE; + vr_x = 0; + vr_ms = 0; + vr_h = 0; + + pdu_without_poll = 0; + byte_without_poll = 0; + + poll_received = false; + do_status = false; +} + +void rlc_am::init(srslte::log *log_, + uint32_t lcid_, + srsue::pdcp_interface_rlc *pdcp_, + srsue::rrc_interface_rlc *rrc_, + srslte::mac_interface_timers *mac_timers) +{ + log = log_; + lcid = lcid_; + pdcp = pdcp_; + rrc = rrc_; +} + +void rlc_am::configure(LIBLTE_RRC_RLC_CONFIG_STRUCT *cnfg) +{ + t_poll_retx = liblte_rrc_t_poll_retransmit_num[cnfg->ul_am_rlc.t_poll_retx]; + poll_pdu = liblte_rrc_poll_pdu_num[cnfg->ul_am_rlc.poll_pdu]; + poll_byte = liblte_rrc_poll_byte_num[cnfg->ul_am_rlc.poll_byte]*1000; // KB + max_retx_thresh = liblte_rrc_max_retx_threshold_num[cnfg->ul_am_rlc.max_retx_thresh]; + + t_reordering = liblte_rrc_t_reordering_num[cnfg->dl_am_rlc.t_reordering]; + t_status_prohibit = liblte_rrc_t_status_prohibit_num[cnfg->dl_am_rlc.t_status_prohibit]; + + log->info("%s configured: t_poll_retx=%d, poll_pdu=%d, poll_byte=%d, max_retx_thresh=%d, " + "t_reordering=%d, t_status_prohibit=%d\n", + rb_id_text[lcid], t_poll_retx, poll_pdu, poll_byte, max_retx_thresh, + t_reordering, t_status_prohibit); +} + + +void rlc_am::empty_queue() { + // Drop all messages in TX SDU queue + byte_buffer_t *buf; + while(tx_sdu_queue.size() > 0) { + tx_sdu_queue.read(&buf); + pool->deallocate(buf); + } +} + +void rlc_am::reset() +{ + // Empty tx_sdu_queue before locking the mutex + empty_queue(); + + pthread_mutex_lock(&mutex); + reordering_timeout.reset(); + if(tx_sdu) + tx_sdu->reset(); + if(rx_sdu) + rx_sdu->reset(); + + vt_a = 0; + vt_ms = RLC_AM_WINDOW_SIZE; + vt_s = 0; + poll_sn = 0; + + vr_r = 0; + vr_mr = RLC_AM_WINDOW_SIZE; + vr_x = 0; + vr_ms = 0; + vr_h = 0; + + pdu_without_poll = 0; + byte_without_poll = 0; + + poll_received = false; + do_status = false; + + // Drop all messages in RX segments + std::map::iterator rxsegsit; + std::list::iterator segit; + for(rxsegsit = rx_segments.begin(); rxsegsit != rx_segments.end(); rxsegsit++) { + std::list l = rxsegsit->second.segments; + for(segit = l.begin(); segit != l.end(); segit++) { + pool->deallocate(segit->buf); + } + l.clear(); + } + rx_segments.clear(); + + // Drop all messages in RX window + std::map::iterator rxit; + for(rxit = rx_window.begin(); rxit != rx_window.end(); rxit++) { + pool->deallocate(rxit->second.buf); + } + rx_window.clear(); + + // Drop all messages in TX window + std::map::iterator txit; + for(txit = tx_window.begin(); txit != tx_window.end(); txit++) { + pool->deallocate(txit->second.buf); + } + tx_window.clear(); + + // Drop all messages in RETX queue + retx_queue.clear(); + pthread_mutex_unlock(&mutex); +} + +rlc_mode_t rlc_am::get_mode() +{ + return RLC_MODE_AM; +} + +uint32_t rlc_am::get_bearer() +{ + return lcid; +} + +/**************************************************************************** + * PDCP interface + ***************************************************************************/ + +void rlc_am::write_sdu(byte_buffer_t *sdu) +{ + log->info_hex(sdu->msg, sdu->N_bytes, "%s Tx SDU", rb_id_text[lcid]); + tx_sdu_queue.write(sdu); +} + +/**************************************************************************** + * MAC interface + ***************************************************************************/ + +uint32_t rlc_am::get_total_buffer_state() +{ + pthread_mutex_lock(&mutex); + uint32_t n_bytes = 0; + uint32_t n_sdus = 0; + + // Bytes needed for status report + check_reordering_timeout(); + if(do_status && !status_prohibited()) { + n_bytes += prepare_status(); + log->debug("Buffer state - status report: %d bytes\n", n_bytes); + } + + // Bytes needed for retx + if(retx_queue.size() > 0) { + rlc_amd_retx_t retx = retx_queue.front(); + log->debug("Buffer state - retx - SN: %d, Segment: %s, %d:%d\n", retx.sn, retx.is_segment ? "true" : "false", retx.so_start, retx.so_end); + if(tx_window.end() != tx_window.find(retx.sn)) { + n_bytes += required_buffer_size(retx); + log->debug("Buffer state - retx: %d bytes\n", n_bytes); + } + } + + // Bytes needed for tx SDUs + n_sdus = tx_sdu_queue.size(); + n_bytes += tx_sdu_queue.size_bytes(); + if(tx_sdu) + { + n_sdus++; + n_bytes += tx_sdu->N_bytes; + } + + // Room needed for header extensions? (integer rounding) + if(n_sdus > 1) + n_bytes += ((n_sdus-1)*1.5)+0.5; + + // Room needed for fixed header? + if(n_bytes > 0) { + n_bytes += 2; + log->debug("Buffer state - tx SDUs: %d bytes\n", n_bytes); + } + + pthread_mutex_unlock(&mutex); + return n_bytes; +} + +uint32_t rlc_am::get_buffer_state() +{ + pthread_mutex_lock(&mutex); + uint32_t n_bytes = 0; + uint32_t n_sdus = 0; + + // Bytes needed for status report + check_reordering_timeout(); + if(do_status && !status_prohibited()) { + n_bytes = prepare_status(); + log->debug("Buffer state - status report: %d bytes\n", n_bytes); + goto unlock_and_return; + } + + // Bytes needed for retx + if(retx_queue.size() > 0) { + rlc_amd_retx_t retx = retx_queue.front(); + log->debug("Buffer state - retx - SN: %d, Segment: %s, %d:%d\n", retx.sn, retx.is_segment ? "true" : "false", retx.so_start, retx.so_end); + if(tx_window.end() != tx_window.find(retx.sn)) { + n_bytes = required_buffer_size(retx); + log->debug("Buffer state - retx: %d bytes\n", n_bytes); + goto unlock_and_return; + } + } + + // Bytes needed for tx SDUs + if(tx_window.size() < RLC_AM_WINDOW_SIZE) { + n_sdus = tx_sdu_queue.size(); + n_bytes = tx_sdu_queue.size_bytes(); + if(tx_sdu) + { + n_sdus++; + n_bytes += tx_sdu->N_bytes; + } + } + + // Room needed for header extensions? (integer rounding) + if(n_sdus > 1) + n_bytes += ((n_sdus-1)*1.5)+0.5; + + // Room needed for fixed header? + if(n_bytes > 0) { + n_bytes += 2; + log->debug("Buffer state - tx SDUs: %d bytes\n", n_bytes); + } + +unlock_and_return: + pthread_mutex_unlock(&mutex); + return n_bytes; +} + +int rlc_am::read_pdu(uint8_t *payload, uint32_t nof_bytes) +{ + pthread_mutex_lock(&mutex); + + log->debug("MAC opportunity - %d bytes\n", nof_bytes); + + // Tx STATUS if requested + if(do_status && !status_prohibited()) { + pthread_mutex_unlock(&mutex); + return build_status_pdu(payload, nof_bytes); + } + // RETX if required + if(retx_queue.size() > 0) { + pthread_mutex_unlock(&mutex); + return build_retx_pdu(payload, nof_bytes); + } + + pthread_mutex_unlock(&mutex); + + // Build a PDU from SDUs + return build_data_pdu(payload, nof_bytes); +} + +void rlc_am::write_pdu(uint8_t *payload, uint32_t nof_bytes) +{ + if(nof_bytes < 1) + return; + pthread_mutex_lock(&mutex); + + if(rlc_am_is_control_pdu(payload)) { + handle_control_pdu(payload, nof_bytes); + } else { + rlc_amd_pdu_header_t header; + rlc_am_read_data_pdu_header(&payload, &nof_bytes, &header); + if(header.rf) { + handle_data_pdu_segment(payload, nof_bytes, header); + }else{ + handle_data_pdu(payload, nof_bytes, header); + } + } + pthread_mutex_unlock(&mutex); +} + +/**************************************************************************** + * Timer checks + ***************************************************************************/ + +bool rlc_am::status_prohibited() +{ + return (status_prohibit_timeout.is_running() && !status_prohibit_timeout.expired()); +} + +bool rlc_am::poll_retx() +{ + return (poll_retx_timeout.is_running() && poll_retx_timeout.expired()); +} + +void rlc_am::check_reordering_timeout() +{ + if(reordering_timeout.is_running() && reordering_timeout.expired()) + { + reordering_timeout.reset(); + log->debug("%s reordering timeout expiry - updating vr_ms\n", rb_id_text[lcid]); + + // 36.322 v10 Section 5.1.3.2.4 + vr_ms = vr_x; + std::map::iterator it = rx_window.find(vr_ms); + while(rx_window.end() != it) + { + vr_ms = (vr_ms + 1)%MOD; + it = rx_window.find(vr_ms); + } + if(poll_received) + do_status = true; + + if(RX_MOD_BASE(vr_h) > RX_MOD_BASE(vr_ms)) + { + reordering_timeout.start(t_reordering); + vr_x = vr_h; + } + + debug_state(); + } +} + +/**************************************************************************** + * Helpers + ***************************************************************************/ + +bool rlc_am::poll_required() +{ + if(poll_pdu > 0 && pdu_without_poll > (uint32_t)poll_pdu) + return true; + if(poll_byte > 0 && byte_without_poll > (uint32_t)poll_byte) + return true; + if(poll_retx()) + return true; + return false; +} + +int rlc_am::prepare_status() +{ + status.N_nack = 0; + status.ack_sn = vr_ms; + + // We don't use segment NACKs - just NACK the full PDU + + uint32_t i = vr_r; + while(RX_MOD_BASE(i) < RX_MOD_BASE(vr_ms)) + { + if(rx_window.find(i) == rx_window.end()) + status.nacks[status.N_nack++].nack_sn = i; + i = (i + 1)%MOD; + } + + return rlc_am_packed_length(&status); +} + +int rlc_am::build_status_pdu(uint8_t *payload, uint32_t nof_bytes) +{ + int pdu_len = rlc_am_packed_length(&status); + if(pdu_len > 0 && nof_bytes >= (uint32_t)pdu_len) + { + log->info("%s Tx status PDU - %s\n", + rb_id_text[lcid], rlc_am_to_string(&status).c_str()); + + do_status = false; + poll_received = false; + + if(t_status_prohibit > 0) + status_prohibit_timeout.start(t_status_prohibit); + debug_state(); + return rlc_am_write_status_pdu(&status, payload); + }else{ + log->warning("%s Cannot tx status PDU - %d bytes available, %d bytes required\n", + rb_id_text[lcid], nof_bytes, pdu_len); + return 0; + } +} + +int rlc_am::build_retx_pdu(uint8_t *payload, uint32_t nof_bytes) +{ + rlc_amd_retx_t retx = retx_queue.front(); + + // Sanity check - drop any retx SNs not present in tx_window + while(tx_window.end() == tx_window.find(retx.sn)) { + retx_queue.pop_front(); + retx = retx_queue.front(); + } + + // Is resegmentation needed? + if(retx.is_segment || required_buffer_size(retx) > (int)nof_bytes) { + log->debug("%s build_retx_pdu - resegmentation required\n", rb_id_text[lcid]); + return build_segment(payload, nof_bytes, retx); + } + + // Update & write header + rlc_amd_pdu_header_t new_header = tx_window[retx.sn].header; + new_header.p = 0; + if(poll_required()) + { + new_header.p = 1; + poll_sn = vt_s; + pdu_without_poll = 0; + byte_without_poll = 0; + poll_retx_timeout.start(t_poll_retx); + } + + uint8_t *ptr = payload; + rlc_am_write_data_pdu_header(&new_header, &ptr); + memcpy(ptr, tx_window[retx.sn].buf->msg, tx_window[retx.sn].buf->N_bytes); + + retx_queue.pop_front(); + tx_window[retx.sn].retx_count++; + if(tx_window[retx.sn].retx_count >= max_retx_thresh) + rrc->max_retx_attempted(); + log->info("%s Retx PDU scheduled for tx. SN: %d, retx count: %d\n", + rb_id_text[lcid], retx.sn, tx_window[retx.sn].retx_count); + + debug_state(); + return (ptr-payload) + tx_window[retx.sn].buf->N_bytes; +} + +int rlc_am::build_segment(uint8_t *payload, uint32_t nof_bytes, rlc_amd_retx_t retx) +{ + if(!retx.is_segment){ + retx.so_start = 0; + retx.so_end = tx_window[retx.sn].buf->N_bytes; + } + + // Construct new header + rlc_amd_pdu_header_t new_header; + rlc_amd_pdu_header_t old_header = tx_window[retx.sn].header; + + new_header.dc = RLC_DC_FIELD_DATA_PDU; + new_header.rf = 1; + new_header.p = 0; + new_header.fi = RLC_FI_FIELD_NOT_START_OR_END_ALIGNED; + new_header.sn = old_header.sn; + new_header.lsf = 0; + new_header.so = retx.so_start; + new_header.N_li = 0; + + uint32_t head_len = 0; + uint32_t pdu_space = 0; + + head_len = rlc_am_packed_length(&new_header); + if(nof_bytes <= head_len) + { + log->warning("%s Cannot build a PDU segment - %d bytes available, %d bytes required for header\n", + rb_id_text[lcid], nof_bytes, head_len); + return 0; + } + pdu_space = nof_bytes-head_len; + if(pdu_space < (retx.so_end-retx.so_start)) + retx.so_end = retx.so_start+pdu_space; + + // Need to rebuild the li table & update fi based on so_start and so_end + if(retx.so_start == 0 && rlc_am_start_aligned(old_header.fi)) + new_header.fi &= RLC_FI_FIELD_NOT_END_ALIGNED; // segment is start aligned + + uint32_t lower = 0; + uint32_t upper = 0; + uint32_t li = 0; + + for(uint32_t i=0; i= retx.so_end) + break; + + upper += old_header.li[i]; + + head_len = rlc_am_packed_length(&new_header); + pdu_space = nof_bytes-head_len; + if(pdu_space < (retx.so_end-retx.so_start)) + retx.so_end = retx.so_start+pdu_space; + + if(upper > retx.so_start && lower < retx.so_end) { // Current SDU is needed + li = upper - lower; + if(upper > retx.so_end) + li -= upper - retx.so_end; + if(lower < retx.so_start) + li -= retx.so_start - lower; + if(lower > 0 && lower == retx.so_start) + new_header.fi &= RLC_FI_FIELD_NOT_END_ALIGNED; // segment start is aligned with this SDU + if(upper == retx.so_end) { + new_header.fi &= RLC_FI_FIELD_NOT_START_ALIGNED; // segment end is aligned with this SDU + } + new_header.li[new_header.N_li++] = li; + } + + lower += old_header.li[i]; + } + + // Update retx_queue + if(tx_window[retx.sn].buf->N_bytes == retx.so_end) { + retx_queue.pop_front(); + new_header.lsf = 1; + if(rlc_am_end_aligned(old_header.fi)) + new_header.fi &= RLC_FI_FIELD_NOT_START_ALIGNED; // segment is end aligned + } else if(retx_queue.front().so_end == retx.so_end) { + retx_queue.pop_front(); + } else { + retx_queue.front().is_segment = true; + retx_queue.front().so_start = retx.so_end; + if(new_header.N_li > 0) + new_header.N_li--; + } + + // Write header and pdu + uint8_t *ptr = payload; + rlc_am_write_data_pdu_header(&new_header, &ptr); + uint8_t* data = &tx_window[retx.sn].buf->msg[retx.so_start]; + uint32_t len = retx.so_end - retx.so_start; + memcpy(ptr, data, len); + + log->info("%s Retx PDU segment scheduled for tx. SN: %d, SO: %d\n", + rb_id_text[lcid], retx.sn, retx.so_start); + + debug_state(); + int pdu_len = (ptr-payload) + len; + if(pdu_len > (int)nof_bytes) { + log->error("%s Retx PDU segment length error. Available: %d, Used: %d\n", + rb_id_text[lcid], nof_bytes, pdu_len); + log->debug("%s Retx PDU segment length error. Header len: %d, Payload len: %d, N_li: %d\n", + rb_id_text[lcid], (ptr-payload), len, new_header.N_li); + } + return pdu_len; + +} + +int rlc_am::build_data_pdu(uint8_t *payload, uint32_t nof_bytes) +{ + if(!tx_sdu && tx_sdu_queue.size() == 0) + { + log->info("No data available to be sent\n"); + return 0; + } + + byte_buffer_t *pdu = pool_allocate; + if (!pdu) { + log->console("Fatal Error: Could not allocate PDU in build_data_pdu()\n"); + exit(-1); + } + rlc_amd_pdu_header_t header; + header.dc = RLC_DC_FIELD_DATA_PDU; + header.rf = 0; + header.p = 0; + header.fi = RLC_FI_FIELD_START_AND_END_ALIGNED; + header.sn = vt_s; + header.lsf = 0; + header.so = 0; + header.N_li = 0; + + uint32_t head_len = rlc_am_packed_length(&header); + uint32_t to_move = 0; + uint32_t last_li = 0; + uint32_t pdu_space = nof_bytes; + uint8_t *pdu_ptr = pdu->msg; + + if(pdu_space <= head_len) + { + log->warning("%s Cannot build a PDU - %d bytes available, %d bytes required for header\n", + rb_id_text[lcid], nof_bytes, head_len); + pool->deallocate(pdu); + return 0; + } + + log->debug("%s Building PDU - pdu_space: %d, head_len: %d \n", + rb_id_text[lcid], pdu_space, head_len); + + // Check for SDU segment + if(tx_sdu) + { + to_move = ((pdu_space-head_len) >= tx_sdu->N_bytes) ? tx_sdu->N_bytes : pdu_space-head_len; + memcpy(pdu_ptr, tx_sdu->msg, to_move); + last_li = to_move; + pdu_ptr += to_move; + pdu->N_bytes += to_move; + tx_sdu->N_bytes -= to_move; + tx_sdu->msg += to_move; + if(tx_sdu->N_bytes == 0) + { + log->info("%s Complete SDU scheduled for tx. Stack latency: %ld us\n", + rb_id_text[lcid], tx_sdu->get_latency_us()); + pool->deallocate(tx_sdu); + tx_sdu = NULL; + } + if(pdu_space > to_move) + pdu_space -= to_move; + else + pdu_space = 0; + header.fi |= RLC_FI_FIELD_NOT_START_ALIGNED; // First byte does not correspond to first byte of SDU + + log->debug("%s Building PDU - added SDU segment (len:%d) - pdu_space: %d, head_len: %d \n", + rb_id_text[lcid], to_move, pdu_space, head_len); + } + + // Pull SDUs from queue + while(pdu_space > head_len && tx_sdu_queue.size() > 0) + { + if(last_li > 0) + header.li[header.N_li++] = last_li; + head_len = rlc_am_packed_length(&header); + if(head_len >= pdu_space) { + header.N_li--; + break; + } + tx_sdu_queue.read(&tx_sdu); + to_move = ((pdu_space-head_len) >= tx_sdu->N_bytes) ? tx_sdu->N_bytes : pdu_space-head_len; + memcpy(pdu_ptr, tx_sdu->msg, to_move); + last_li = to_move; + pdu_ptr += to_move; + pdu->N_bytes += to_move; + tx_sdu->N_bytes -= to_move; + tx_sdu->msg += to_move; + if(tx_sdu->N_bytes == 0) + { + log->info("%s Complete SDU scheduled for tx. Stack latency: %ld us\n", + rb_id_text[lcid], tx_sdu->get_latency_us()); + pool->deallocate(tx_sdu); + tx_sdu = NULL; + } + if(pdu_space > to_move) + pdu_space -= to_move; + else + pdu_space = 0; + + log->debug("%s Building PDU - added SDU segment (len:%d) - pdu_space: %d, head_len: %d \n", + rb_id_text[lcid], to_move, pdu_space, head_len); + } + + if(tx_sdu) + header.fi |= RLC_FI_FIELD_NOT_END_ALIGNED; // Last byte does not correspond to last byte of SDU + + // Set Poll bit + pdu_without_poll++; + byte_without_poll += (pdu->N_bytes + head_len); + log->debug("%s pdu_without_poll: %d\n", rb_id_text[lcid], pdu_without_poll); + log->debug("%s byte_without_poll: %d\n", rb_id_text[lcid], byte_without_poll); + if(poll_required()) + { + log->debug("%s setting poll bit to request status\n", rb_id_text[lcid]); + header.p = 1; + poll_sn = vt_s; + pdu_without_poll = 0; + byte_without_poll = 0; + poll_retx_timeout.start(t_poll_retx); + } + + // Set SN + header.sn = vt_s; + vt_s = (vt_s + 1)%MOD; + log->info("%s PDU scheduled for tx. SN: %d\n", rb_id_text[lcid], header.sn); + + // Place PDU in tx_window, write header and TX + tx_window[header.sn].buf = pdu; + tx_window[header.sn].header = header; + tx_window[header.sn].is_acked = false; + tx_window[header.sn].retx_count = 0; + + uint8_t *ptr = payload; + rlc_am_write_data_pdu_header(&header, &ptr); + memcpy(ptr, pdu->msg, pdu->N_bytes); + + debug_state(); + return (ptr-payload) + pdu->N_bytes; +} + +void rlc_am::handle_data_pdu(uint8_t *payload, uint32_t nof_bytes, rlc_amd_pdu_header_t header) +{ + std::map::iterator it; + + log->info_hex(payload, nof_bytes, "%s Rx data PDU SN: %d", + rb_id_text[lcid], header.sn); + + if(!inside_rx_window(header.sn)) { + if(header.p) { + log->info("%s Status packet requested through polling bit\n", rb_id_text[lcid]); + do_status = true; + } + log->info("%s SN: %d outside rx window [%d:%d] - discarding\n", + rb_id_text[lcid], header.sn, vr_r, vr_mr); + return; + } + + it = rx_window.find(header.sn); + if(rx_window.end() != it) { + if(header.p) { + log->info("%s Status packet requested through polling bit\n", rb_id_text[lcid]); + do_status = true; + } + log->info("%s Discarding duplicate SN: %d\n", + rb_id_text[lcid], header.sn); + return; + } + + // Write to rx window + rlc_amd_rx_pdu_t pdu; + pdu.buf = pool_allocate; + if (!pdu.buf) { + log->console("Fatal Error: Could not allocate PDU in handle_data_pdu()\n"); + exit(-1); + } + + memcpy(pdu.buf->msg, payload, nof_bytes); + pdu.buf->N_bytes = nof_bytes; + pdu.header = header; + + rx_window[header.sn] = pdu; + + // Update vr_h + if(RX_MOD_BASE(header.sn) >= RX_MOD_BASE(vr_h)) + vr_h = (header.sn + 1)%MOD; + + // Update vr_ms + it = rx_window.find(vr_ms); + while(rx_window.end() != it) + { + vr_ms = (vr_ms + 1)%MOD; + it = rx_window.find(vr_ms); + } + + // Check poll bit + if(header.p) + { + log->info("%s Status packet requested through polling bit\n", rb_id_text[lcid]); + poll_received = true; + + // 36.322 v10 Section 5.2.3 + if(RX_MOD_BASE(header.sn) < RX_MOD_BASE(vr_ms) || + RX_MOD_BASE(header.sn) >= RX_MOD_BASE(vr_mr)) + { + do_status = true; + } + // else delay for reordering timer + } + + // Reassemble and deliver SDUs + reassemble_rx_sdus(); + + // Update reordering variables and timers (36.322 v10.0.0 Section 5.1.3.2.3) + if(reordering_timeout.is_running()) + { + if( + vr_x == vr_r || + (RX_MOD_BASE(vr_x) < RX_MOD_BASE(vr_r) || + (RX_MOD_BASE(vr_x) > RX_MOD_BASE(vr_mr) && + vr_x != vr_mr)) + ) + { + reordering_timeout.reset(); + } + } + if(!reordering_timeout.is_running()) + { + if(RX_MOD_BASE(vr_h) > RX_MOD_BASE(vr_r)) + { + reordering_timeout.start(t_reordering); + vr_x = vr_h; + } + } + + debug_state(); +} + +void rlc_am::handle_data_pdu_segment(uint8_t *payload, uint32_t nof_bytes, rlc_amd_pdu_header_t header) +{ + std::map::iterator it; + + log->info_hex(payload, nof_bytes, "%s Rx data PDU segment. SN: %d, SO: %d", + rb_id_text[lcid], header.sn, header.so); + + // Check inside rx window + if(!inside_rx_window(header.sn)) { + if(header.p) { + log->info("%s Status packet requested through polling bit\n", rb_id_text[lcid]); + do_status = true; + } + log->info("%s SN: %d outside rx window [%d:%d] - discarding\n", + rb_id_text[lcid], header.sn, vr_r, vr_mr); + return; + } + + rlc_amd_rx_pdu_t segment; + segment.buf = pool_allocate; + if (!segment.buf) { + log->console("Fatal Error: Could not allocate PDU in handle_data_pdu_segment()\n"); + exit(-1); + } + memcpy(segment.buf->msg, payload, nof_bytes); + segment.buf->N_bytes = nof_bytes; + segment.header = header; + + // Check if we already have a segment from the same PDU + it = rx_segments.find(header.sn); + if(rx_segments.end() != it) { + + if(header.p) { + log->info("%s Status packet requested through polling bit\n", rb_id_text[lcid]); + do_status = true; + } + + // Add segment to PDU list and check for complete + if(add_segment_and_check(&it->second, &segment)) { + std::list::iterator segit; + std::list seglist = it->second.segments; + for(segit = seglist.begin(); segit != seglist.end(); segit++) { + pool->deallocate(segit->buf); + } + seglist.clear(); + rx_segments.erase(it); + } + + } else { + + // Create new PDU segment list and write to rx_segments + rlc_amd_rx_pdu_segments_t pdu; + pdu.segments.push_back(segment); + rx_segments[header.sn] = pdu; + + + // Update vr_h + if(RX_MOD_BASE(header.sn) >= RX_MOD_BASE(vr_h)) + vr_h = (header.sn + 1)%MOD; + + // Check poll bit + if(header.p) + { + log->info("%s Status packet requested through polling bit\n", rb_id_text[lcid]); + poll_received = true; + + // 36.322 v10 Section 5.2.3 + if(RX_MOD_BASE(header.sn) < RX_MOD_BASE(vr_ms) || + RX_MOD_BASE(header.sn) >= RX_MOD_BASE(vr_mr)) + { + do_status = true; + } + // else delay for reordering timer + } + } + + debug_state(); +} + +void rlc_am::handle_control_pdu(uint8_t *payload, uint32_t nof_bytes) +{ + log->info_hex(payload, nof_bytes, "%s Rx control PDU", rb_id_text[lcid]); + + rlc_status_pdu_t status; + rlc_am_read_status_pdu(payload, nof_bytes, &status); + + log->info("%s Rx Status PDU: %s\n", rb_id_text[lcid], rlc_am_to_string(&status).c_str()); + + poll_retx_timeout.reset(); + + // Handle ACKs and NACKs + bool update_vt_a = true; + uint32_t i = vt_a; + while(TX_MOD_BASE(i) < TX_MOD_BASE(status.ack_sn) && + TX_MOD_BASE(i) < TX_MOD_BASE(vt_s)) + { + std::map::iterator it; + + bool nack = false; + for(uint32_t j=0;jsecond.buf->N_bytes; + + if(status.nacks[j].has_so) { + if(status.nacks[j].so_start < it->second.buf->N_bytes && + status.nacks[j].so_end <= it->second.buf->N_bytes) { + retx.is_segment = true; + retx.so_start = status.nacks[j].so_start; + if(status.nacks[j].so_end == 0x7FFF) { + retx.so_end = it->second.buf->N_bytes; + }else{ + retx.so_end = status.nacks[j].so_end + 1; + } + } else { + log->warning("%s invalid segment NACK received for SN %d. so_start: %d, so_end: %d, N_bytes: %d\n", + rb_id_text[lcid], i, status.nacks[j].so_start, status.nacks[j].so_end, it->second.buf->N_bytes); + } + } + + retx.sn = i; + retx_queue.push_back(retx); + } + } + } + } + + if(!nack) { + //ACKed SNs get marked and removed from tx_window if possible + it = tx_window.find(i); + if(tx_window.end() != it) + { + tx_window[i].is_acked = true; + if(update_vt_a) + { + pool->deallocate(tx_window[i].buf); + tx_window.erase(i); + vt_a = (vt_a + 1)%MOD; + vt_ms = (vt_ms + 1)%MOD; + } + } + } + i = (i+1)%MOD; + } + + debug_state(); +} + +void rlc_am::reassemble_rx_sdus() +{ + if(!rx_sdu) { + rx_sdu = pool_allocate; + if (!rx_sdu) { + log->console("Fatal Error: Could not allocate PDU in reassemble_rx_sdus() (1)\n"); + exit(-1); + } + } + // Iterate through rx_window, assembling and delivering SDUs + while(rx_window.end() != rx_window.find(vr_r)) + { + // Handle any SDU segments + for(uint32_t i=0; imsg[rx_sdu->N_bytes], rx_window[vr_r].buf->msg, len); + rx_sdu->N_bytes += len; + rx_window[vr_r].buf->msg += len; + rx_window[vr_r].buf->N_bytes -= len; + log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU", rb_id_text[lcid]); + rx_sdu->set_timestamp(); + pdcp->write_pdu(lcid, rx_sdu); + rx_sdu = pool_allocate; + if (!rx_sdu) { + log->console("Fatal Error: Could not allocate PDU in reassemble_rx_sdus() (2)\n"); + exit(-1); + } + + } + + // Handle last segment + memcpy(&rx_sdu->msg[rx_sdu->N_bytes], rx_window[vr_r].buf->msg, rx_window[vr_r].buf->N_bytes); + rx_sdu->N_bytes += rx_window[vr_r].buf->N_bytes; + if(rlc_am_end_aligned(rx_window[vr_r].header.fi)) + { + log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU", rb_id_text[lcid]); + rx_sdu->set_timestamp(); + pdcp->write_pdu(lcid, rx_sdu); + rx_sdu = pool_allocate; + if (!rx_sdu) { + log->console("Fatal Error: Could not allocate PDU in reassemble_rx_sdus() (3)\n"); + exit(-1); + } + } + + // Move the rx_window + pool->deallocate(rx_window[vr_r].buf); + rx_window.erase(vr_r); + vr_r = (vr_r + 1)%MOD; + vr_mr = (vr_mr + 1)%MOD; + } +} + +bool rlc_am::inside_tx_window(uint16_t sn) +{ + if(RX_MOD_BASE(sn) >= RX_MOD_BASE(vt_a) && + RX_MOD_BASE(sn) < RX_MOD_BASE(vt_ms)) + { + return true; + }else{ + return false; + } +} + +bool rlc_am::inside_rx_window(uint16_t sn) +{ + if(RX_MOD_BASE(sn) >= RX_MOD_BASE(vr_r) && + RX_MOD_BASE(sn) < RX_MOD_BASE(vr_mr)) + { + return true; + }else{ + return false; + } +} + +void rlc_am::debug_state() +{ + log->debug("%s vt_a = %d, vt_ms = %d, vt_s = %d, poll_sn = %d " + "vr_r = %d, vr_mr = %d, vr_x = %d, vr_ms = %d, vr_h = %d\n", + rb_id_text[lcid], vt_a, vt_ms, vt_s, poll_sn, + vr_r, vr_mr, vr_x, vr_ms, vr_h); + +} + +bool rlc_am::add_segment_and_check(rlc_amd_rx_pdu_segments_t *pdu, rlc_amd_rx_pdu_t *segment) +{ + // Ordered insert + std::list::iterator tmpit; + std::list::iterator it = pdu->segments.begin(); + while(it != pdu->segments.end() && it->header.so < segment->header.so) + it++; + pdu->segments.insert(it, *segment); + + // Check for complete + uint32_t so = 0; + for(it = pdu->segments.begin(); it != pdu->segments.end(); it++) { + if(so != it->header.so) + return false; + so += it->buf->N_bytes; + } + if(!pdu->segments.back().header.lsf) + return false; + + // We have all segments of the PDU - reconstruct and handle + rlc_amd_pdu_header_t header; + header.dc = RLC_DC_FIELD_DATA_PDU; + header.rf = 0; + header.p = 0; + header.fi = RLC_FI_FIELD_START_AND_END_ALIGNED; + header.sn = pdu->segments.front().header.sn; + header.lsf = 0; + header.so = 0; + header.N_li = 0; + + // Reconstruct fi field + header.fi |= (pdu->segments.front().header.fi & RLC_FI_FIELD_NOT_START_ALIGNED); + header.fi |= (pdu->segments.back().header.fi & RLC_FI_FIELD_NOT_END_ALIGNED); + + // Reconstruct li fields + uint16_t count = 0; + uint16_t carryover = 0; + for(it = pdu->segments.begin(); it != pdu->segments.end(); it++) { + if(it->header.N_li > 0) { + header.li[header.N_li++] = it->header.li[0] + carryover; + count += it->header.li[0]; + for(uint32_t i=1; iheader.N_li; i++) { + header.li[header.N_li++] = it->header.li[i]; + count += it->header.li[i]; + } + } + carryover = it->buf->N_bytes - count; + tmpit = it; + if(rlc_am_end_aligned(it->header.fi) && ++tmpit != pdu->segments.end()) { + header.li[header.N_li++] = carryover; + carryover = 0; + } + count = 0; + } + + // Copy data + byte_buffer_t *full_pdu = pool_allocate; + if (!full_pdu) { + log->console("Fatal Error: Could not allocate PDU in add_segment_and_check()\n"); + exit(-1); + } + for(it = pdu->segments.begin(); it != pdu->segments.end(); it++) { + memcpy(&full_pdu->msg[full_pdu->N_bytes], it->buf->msg, it->buf->N_bytes); + full_pdu->N_bytes += it->buf->N_bytes; + } + + handle_data_pdu(full_pdu->msg, full_pdu->N_bytes, header); + return true; +} + +int rlc_am::required_buffer_size(rlc_amd_retx_t retx) +{ + if(!retx.is_segment){ + return rlc_am_packed_length(&tx_window[retx.sn].header) + tx_window[retx.sn].buf->N_bytes; + } + + // Construct new header + rlc_amd_pdu_header_t new_header; + rlc_amd_pdu_header_t old_header = tx_window[retx.sn].header; + + new_header.dc = RLC_DC_FIELD_DATA_PDU; + new_header.rf = 1; + new_header.p = 0; + new_header.fi = RLC_FI_FIELD_NOT_START_OR_END_ALIGNED; + new_header.sn = old_header.sn; + new_header.lsf = 0; + new_header.so = retx.so_start; + new_header.N_li = 0; + + uint32_t head_len = 0; + + // Need to rebuild the li table & update fi based on so_start and so_end + if(retx.so_start != 0 && rlc_am_start_aligned(old_header.fi)) + new_header.fi &= RLC_FI_FIELD_NOT_END_ALIGNED; // segment is start aligned + + uint32_t lower = 0; + uint32_t upper = 0; + uint32_t li = 0; + + for(uint32_t i=0; i= retx.so_end) + break; + + upper += old_header.li[i]; + + head_len = rlc_am_packed_length(&new_header); + + if(upper > retx.so_start && lower < retx.so_end) { // Current SDU is needed + li = upper - lower; + if(upper > retx.so_end) + li -= upper - retx.so_end; + if(lower < retx.so_start) + li -= retx.so_start - lower; + if(lower > 0 && lower == retx.so_start) + new_header.fi &= RLC_FI_FIELD_NOT_END_ALIGNED; // segment start is aligned with this SDU + if(upper == retx.so_end) { + new_header.fi &= RLC_FI_FIELD_NOT_START_ALIGNED; // segment end is aligned with this SDU + } + new_header.li[new_header.N_li++] = li; + } + + lower += old_header.li[i]; + } + +// if(tx_window[retx.sn].buf->N_bytes != retx.so_end) { +// if(new_header.N_li > 0) +// new_header.N_li--; // No li for last segment +// } + + return rlc_am_packed_length(&new_header) + (retx.so_end-retx.so_start); +} + +bool rlc_am::retx_queue_has_sn(uint32_t sn) +{ + std::deque::iterator q_it; + for(q_it = retx_queue.begin(); q_it != retx_queue.end(); q_it++) { + if(q_it->sn == sn) + return true; + } + return false; +} + +/**************************************************************************** + * Header pack/unpack helper functions + * Ref: 3GPP TS 36.322 v10.0.0 Section 6.2.1 + ***************************************************************************/ + +// Read header from pdu struct, don't strip header +void rlc_am_read_data_pdu_header(byte_buffer_t *pdu, rlc_amd_pdu_header_t *header) +{ + uint8_t *ptr = pdu->msg; + uint32_t n = 0; + rlc_am_read_data_pdu_header(&ptr, &n, header); +} + +// Read header from raw pointer, strip header +void rlc_am_read_data_pdu_header(uint8_t **payload, uint32_t *nof_bytes, rlc_amd_pdu_header_t *header) +{ + uint8_t ext; + uint8_t *ptr = *payload; + + header->dc = (rlc_dc_field_t)((*ptr >> 7) & 0x01); + + if(RLC_DC_FIELD_DATA_PDU == header->dc) + { + // Fixed part + header->rf = ((*ptr >> 6) & 0x01); + header->p = ((*ptr >> 5) & 0x01); + header->fi = (rlc_fi_field_t)((*ptr >> 3) & 0x03); + ext = ((*ptr >> 2) & 0x01); + header->sn = (*ptr & 0x03) << 8; // 2 bits SN + ptr++; + header->sn |= (*ptr & 0xFF); // 8 bits SN + ptr++; + + if(header->rf) + { + header->lsf = ((*ptr >> 7) & 0x01); + header->so = (*ptr & 0x7F) << 8; // 7 bits of SO + ptr++; + header->so |= (*ptr & 0xFF); // 8 bits of SO + ptr++; + } + + // Extension part + header->N_li = 0; + while(ext) + { + if(header->N_li%2 == 0) + { + ext = ((*ptr >> 7) & 0x01); + header->li[header->N_li] = (*ptr & 0x7F) << 4; // 7 bits of LI + ptr++; + header->li[header->N_li] |= (*ptr & 0xF0) >> 4; // 4 bits of LI + header->N_li++; + } + else + { + ext = (*ptr >> 3) & 0x01; + header->li[header->N_li] = (*ptr & 0x07) << 8; // 3 bits of LI + ptr++; + header->li[header->N_li] |= (*ptr & 0xFF); // 8 bits of LI + header->N_li++; + ptr++; + } + } + + // Account for padding if N_li is odd + if(header->N_li%2 == 1) + ptr++; + + *nof_bytes -= ptr-*payload; + *payload = ptr; + } +} + +// Write header to pdu struct +void rlc_am_write_data_pdu_header(rlc_amd_pdu_header_t *header, byte_buffer_t *pdu) +{ + uint8_t *ptr = pdu->msg; + rlc_am_write_data_pdu_header(header, &ptr); + pdu->N_bytes += ptr - pdu->msg; +} + +// Write header to pointer & move pointer +void rlc_am_write_data_pdu_header(rlc_amd_pdu_header_t *header, uint8_t **payload) +{ + uint32_t i; + uint8_t ext = (header->N_li > 0) ? 1 : 0; + + uint8_t *ptr = *payload; + + // Fixed part + *ptr = (header->dc & 0x01) << 7; + *ptr |= (header->rf & 0x01) << 6; + *ptr |= (header->p & 0x01) << 5; + *ptr |= (header->fi & 0x03) << 3; + *ptr |= (ext & 0x01) << 2; + + *ptr |= (header->sn & 0x300) >> 8; // 2 bits SN + ptr++; + *ptr = (header->sn & 0xFF); // 8 bits SN + ptr++; + + // Segment part + if(header->rf) + { + *ptr = (header->lsf & 0x01) << 7; + *ptr |= (header->so & 0x7F00) >> 8; // 7 bits of SO + ptr++; + *ptr = (header->so & 0x00FF); // 8 bits of SO + ptr++; + } + + // Extension part + i = 0; + while(i < header->N_li) + { + ext = ((i+1) == header->N_li) ? 0 : 1; + *ptr = (ext & 0x01) << 7; // 1 bit header + *ptr |= (header->li[i] & 0x7F0) >> 4; // 7 bits of LI + ptr++; + *ptr = (header->li[i] & 0x00F) << 4; // 4 bits of LI + i++; + if(i < header->N_li) + { + ext = ((i+1) == header->N_li) ? 0 : 1; + *ptr |= (ext & 0x01) << 3; // 1 bit header + *ptr |= (header->li[i] & 0x700) >> 8; // 3 bits of LI + ptr++; + *ptr = (header->li[i] & 0x0FF); // 8 bits of LI + ptr++; + i++; + } + } + // Pad if N_li is odd + if(header->N_li%2 == 1) + ptr++; + + *payload = ptr; +} + +void rlc_am_read_status_pdu(byte_buffer_t *pdu, rlc_status_pdu_t *status) +{ + rlc_am_read_status_pdu(pdu->msg, pdu->N_bytes, status); +} + +void rlc_am_read_status_pdu(uint8_t *payload, uint32_t nof_bytes, rlc_status_pdu_t *status) +{ + uint32_t i; + uint8_t ext1, ext2; + bit_buffer_t tmp; + uint8_t *ptr = tmp.msg; + + srslte_bit_unpack_vector(payload, tmp.msg, nof_bytes*8); + tmp.N_bits = nof_bytes*8; + + rlc_dc_field_t dc = (rlc_dc_field_t)srslte_bit_pack(&ptr, 1); + + if(RLC_DC_FIELD_CONTROL_PDU == dc) + { + uint8_t cpt = srslte_bit_pack(&ptr, 3); // 3-bit Control PDU Type (0 == status) + if(0 == cpt) + { + status->ack_sn = srslte_bit_pack(&ptr, 10); // 10 bits ACK_SN + ext1 = srslte_bit_pack(&ptr, 1); // 1 bits E1 + status->N_nack = 0; + while(ext1) + { + status->nacks[status->N_nack].nack_sn = srslte_bit_pack(&ptr, 10); + ext1 = srslte_bit_pack(&ptr, 1); // 1 bits E1 + ext2 = srslte_bit_pack(&ptr, 1); // 1 bits E2 + if(ext2) + { + status->nacks[status->N_nack].has_so = true; + status->nacks[status->N_nack].so_start = srslte_bit_pack(&ptr, 15); + status->nacks[status->N_nack].so_end = srslte_bit_pack(&ptr, 15); + } + status->N_nack++; + } + } + } +} + +void rlc_am_write_status_pdu(rlc_status_pdu_t *status, byte_buffer_t *pdu ) +{ + pdu->N_bytes = rlc_am_write_status_pdu(status, pdu->msg); +} + +int rlc_am_write_status_pdu(rlc_status_pdu_t *status, uint8_t *payload) +{ + uint32_t i; + uint8_t ext1; + bit_buffer_t tmp; + uint8_t *ptr = tmp.msg; + + srslte_bit_unpack(RLC_DC_FIELD_CONTROL_PDU, &ptr, 1); // D/C + srslte_bit_unpack(0, &ptr, 3); // CPT (0 == STATUS) + srslte_bit_unpack(status->ack_sn, &ptr, 10); // 10 bit ACK_SN + ext1 = (status->N_nack == 0) ? 0 : 1; + srslte_bit_unpack(ext1, &ptr, 1); // E1 + for(i=0;iN_nack;i++) + { + srslte_bit_unpack(status->nacks[i].nack_sn, &ptr, 10); // 10 bit NACK_SN + ext1 = ((status->N_nack-1) == i) ? 0 : 1; + srslte_bit_unpack(ext1, &ptr, 1); // E1 + if(status->nacks[i].has_so) { + srslte_bit_unpack(1 , &ptr, 1); // E2 + srslte_bit_unpack(status->nacks[i].so_start , &ptr, 15); + srslte_bit_unpack(status->nacks[i].so_end , &ptr, 15); + }else{ + srslte_bit_unpack(0 , &ptr, 1); // E2 + } + } + + // Pad + tmp.N_bits = ptr - tmp.msg; + uint8_t n_pad = 8 - (tmp.N_bits%8); + srslte_bit_unpack(0, &ptr, n_pad); + tmp.N_bits = ptr - tmp.msg; + + // Pack bits + srslte_bit_pack_vector(tmp.msg, payload, tmp.N_bits); + return tmp.N_bits/8; +} + +uint32_t rlc_am_packed_length(rlc_amd_pdu_header_t *header) +{ + uint32_t len = 2; // Fixed part is 2 bytes + if(header->rf) len += 2; // Segment header is 2 bytes + len += header->N_li * 1.5 + 0.5; // Extension part - integer rounding up + return len; +} + +uint32_t rlc_am_packed_length(rlc_status_pdu_t *status) +{ + uint32_t i; + uint32_t len_bits = 15; // Fixed part is 15 bits + for(i=0;iN_nack;i++) + { + if(status->nacks[i].has_so) { + len_bits += 42; // 10 bits SN, 2 bits ext, 15 bits so_start, 15 bits so_end + }else{ + len_bits += 12; // 10 bits SN, 2 bits ext + } + } + + return (len_bits+7)/8; // Convert to bytes - integer rounding up +} + +bool rlc_am_is_control_pdu(byte_buffer_t *pdu) +{ + return rlc_am_is_control_pdu(pdu->msg); +} + +bool rlc_am_is_control_pdu(uint8_t *payload) +{ + return ((*(payload) >> 7) & 0x01) == RLC_DC_FIELD_CONTROL_PDU; +} + +bool rlc_am_is_pdu_segment(uint8_t *payload) +{ + return ((*(payload) >> 6) & 0x01) == 1; +} + +std::string rlc_am_to_string(rlc_status_pdu_t *status) +{ + std::stringstream ss; + ss << "ACK_SN = " << status->ack_sn; + ss << ", N_nack = " << status->N_nack; + if(status->N_nack > 0) + { + ss << ", NACK_SN = "; + for(uint32_t i=0; iN_nack; i++) + { + if(status->nacks[i].has_so) { + ss << "[" << status->nacks[i].nack_sn << " " << status->nacks[i].so_start \ + << ":" << status->nacks[i].so_end << "]"; + }else{ + ss << "[" << status->nacks[i].nack_sn << "]"; + } + } + } + return ss.str(); +} + +bool rlc_am_start_aligned(uint8_t fi) +{ + return (fi == RLC_FI_FIELD_START_AND_END_ALIGNED || fi == RLC_FI_FIELD_NOT_END_ALIGNED); +} + +bool rlc_am_end_aligned(uint8_t fi) +{ + return (fi == RLC_FI_FIELD_START_AND_END_ALIGNED || fi == RLC_FI_FIELD_NOT_START_ALIGNED); +} + +} // namespace srsue diff --git a/lib/src/upper/rlc_entity.cc b/lib/src/upper/rlc_entity.cc new file mode 100644 index 000000000..ace991b10 --- /dev/null +++ b/lib/src/upper/rlc_entity.cc @@ -0,0 +1,137 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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/upper/rlc_entity.h" + +namespace srslte { + +rlc_entity::rlc_entity() + :rlc(NULL) +{ +} + +void rlc_entity::init(rlc_mode_t mode, + log *rlc_entity_log_, + uint32_t lcid_, + srsue::pdcp_interface_rlc *pdcp_, + srsue::rrc_interface_rlc *rrc_, + mac_interface_timers *mac_timers_) +{ + tm.reset(); + um.reset(); + am.reset(); + + switch(mode) + { + case RLC_MODE_TM: + rlc = &tm; + break; + case RLC_MODE_UM: + rlc = &um; + break; + case RLC_MODE_AM: + rlc = &am; + break; + default: + rlc_entity_log_->error("Invalid RLC mode - defaulting to TM\n"); + rlc = &tm; + break; + } + + rlc->init(rlc_entity_log_, lcid_, pdcp_, rrc_, mac_timers_); +} + +void rlc_entity::configure(LIBLTE_RRC_RLC_CONFIG_STRUCT *cnfg) +{ + if(rlc) + rlc->configure(cnfg); +} + +void rlc_entity::reset() +{ + rlc->reset(); + rlc = NULL; +} + +bool rlc_entity::active() +{ + return (rlc != NULL); +} + +rlc_mode_t rlc_entity::get_mode() +{ + if(rlc) + return rlc->get_mode(); + else + return RLC_MODE_TM; +} + +uint32_t rlc_entity::get_bearer() +{ + if(rlc) + return rlc->get_bearer(); + else + return 0; +} + +// PDCP interface +void rlc_entity::write_sdu(byte_buffer_t *sdu) +{ + if(rlc) + rlc->write_sdu(sdu); +} + +// MAC interface +uint32_t rlc_entity::get_buffer_state() +{ + if(rlc) + return rlc->get_buffer_state(); + else + return 0; +} + +uint32_t rlc_entity::get_total_buffer_state() +{ + if(rlc) + return rlc->get_total_buffer_state(); + else + return 0; +} + +int rlc_entity::read_pdu(uint8_t *payload, uint32_t nof_bytes) +{ + if(rlc) + return rlc->read_pdu(payload, nof_bytes); + else + return 0; +} +void rlc_entity::write_pdu(uint8_t *payload, uint32_t nof_bytes) +{ + if(rlc) + rlc->write_pdu(payload, nof_bytes); +} + +} // namespace srsue diff --git a/lib/src/upper/rlc_tm.cc b/lib/src/upper/rlc_tm.cc new file mode 100644 index 000000000..a515a77a5 --- /dev/null +++ b/lib/src/upper/rlc_tm.cc @@ -0,0 +1,125 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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/upper/rlc_tm.h" + +namespace srslte { + +rlc_tm::rlc_tm() : ul_queue(16) +{ + pool = byte_buffer_pool::get_instance(); +} + +void rlc_tm::init(srslte::log *log_, + uint32_t lcid_, + srsue::pdcp_interface_rlc *pdcp_, + srsue::rrc_interface_rlc *rrc_, + mac_interface_timers *mac_timers) +{ + log = log_; + lcid = lcid_; + pdcp = pdcp_; + rrc = rrc_; +} + +void rlc_tm::configure(LIBLTE_RRC_RLC_CONFIG_STRUCT *cnfg) +{ + log->error("Attempted to configure TM RLC entity"); +} + +void rlc_tm::empty_queue() +{ + // Drop all messages in TX queue + byte_buffer_t *buf; + while(ul_queue.size() > 0) { + ul_queue.read(&buf); + pool->deallocate(buf); + } +} + +void rlc_tm::reset() +{ + empty_queue(); +} + +rlc_mode_t rlc_tm::get_mode() +{ + return RLC_MODE_TM; +} + +uint32_t rlc_tm::get_bearer() +{ + return lcid; +} + +// PDCP interface +void rlc_tm::write_sdu(byte_buffer_t *sdu) +{ + log->info_hex(sdu->msg, sdu->N_bytes, "%s Tx SDU", rb_id_text[lcid]); + ul_queue.write(sdu); +} + +// MAC interface +uint32_t rlc_tm::get_buffer_state() +{ + return ul_queue.size_bytes(); +} + +uint32_t rlc_tm::get_total_buffer_state() +{ + return get_buffer_state(); +} + +int rlc_tm::read_pdu(uint8_t *payload, uint32_t nof_bytes) +{ + uint32_t pdu_size = ul_queue.size_tail_bytes(); + if(pdu_size > nof_bytes) + { + log->error("TX %s PDU size larger than MAC opportunity\n", rb_id_text[lcid]); + return 0; + } + byte_buffer_t *buf; + ul_queue.read(&buf); + pdu_size = buf->N_bytes; + memcpy(payload, buf->msg, buf->N_bytes); + log->info("%s Complete SDU scheduled for tx. Stack latency: %ld us\n", + rb_id_text[lcid], buf->get_latency_us()); + pool->deallocate(buf); + log->info_hex(payload, pdu_size, "TX %s, %s PDU", rb_id_text[lcid], rlc_mode_text[RLC_MODE_TM]); + return pdu_size; +} + +void rlc_tm:: write_pdu(uint8_t *payload, uint32_t nof_bytes) +{ + byte_buffer_t *buf = pool_allocate; + memcpy(buf->msg, payload, nof_bytes); + buf->N_bytes = nof_bytes; + buf->set_timestamp(); + pdcp->write_pdu(lcid, buf); +} + +} // namespace srsue diff --git a/lib/src/upper/rlc_um.cc b/lib/src/upper/rlc_um.cc new file mode 100644 index 000000000..78fc0a68b --- /dev/null +++ b/lib/src/upper/rlc_um.cc @@ -0,0 +1,701 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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/upper/rlc_um.h" + +#define RX_MOD_BASE(x) (x-vr_uh-rx_window_size)%rx_mod + +namespace srslte { + +rlc_um::rlc_um() : tx_sdu_queue(16) +{ + tx_sdu = NULL; + rx_sdu = NULL; + pool = byte_buffer_pool::get_instance(); + + pthread_mutex_init(&mutex, NULL); + + vt_us = 0; + vr_ur = 0; + vr_ux = 0; + vr_uh = 0; + + vr_ur_in_rx_sdu = 0; + + mac_timers = NULL; + + pdu_lost = false; +} + +void rlc_um::init(srslte::log *log_, + uint32_t lcid_, + srsue::pdcp_interface_rlc *pdcp_, + srsue::rrc_interface_rlc *rrc_, + srslte::mac_interface_timers *mac_timers_) +{ + log = log_; + lcid = lcid_; + pdcp = pdcp_; + rrc = rrc_; + mac_timers = mac_timers_; + reordering_timeout_id = mac_timers->get_unique_id(); +} + +void rlc_um::configure(LIBLTE_RRC_RLC_CONFIG_STRUCT *cnfg) +{ + switch(cnfg->rlc_mode) + { + case LIBLTE_RRC_RLC_MODE_UM_BI: + t_reordering = liblte_rrc_t_reordering_num[cnfg->dl_um_bi_rlc.t_reordering]; + rx_sn_field_length = (rlc_umd_sn_size_t)cnfg->dl_um_bi_rlc.sn_field_len; + rx_window_size = (RLC_UMD_SN_SIZE_5_BITS == rx_sn_field_length) ? 16 : 512; + rx_mod = (RLC_UMD_SN_SIZE_5_BITS == rx_sn_field_length) ? 32 : 1024; + tx_sn_field_length = (rlc_umd_sn_size_t)cnfg->ul_um_bi_rlc.sn_field_len; + tx_mod = (RLC_UMD_SN_SIZE_5_BITS == tx_sn_field_length) ? 32 : 1024; + log->info("%s configured in %s mode: " + "t_reordering=%d ms, rx_sn_field_length=%u bits, tx_sn_field_length=%u bits\n", + rb_id_text[lcid], liblte_rrc_rlc_mode_text[cnfg->rlc_mode], + t_reordering, + rlc_umd_sn_size_num[rx_sn_field_length], + rlc_umd_sn_size_num[tx_sn_field_length]); + break; + case LIBLTE_RRC_RLC_MODE_UM_UNI_UL: + tx_sn_field_length = (rlc_umd_sn_size_t)cnfg->ul_um_uni_rlc.sn_field_len; + tx_mod = (RLC_UMD_SN_SIZE_5_BITS == tx_sn_field_length) ? 32 : 1024; + log->info("%s configured in %s mode: tx_sn_field_length=%u bits\n", + rb_id_text[lcid], liblte_rrc_rlc_mode_text[cnfg->rlc_mode], + rlc_umd_sn_size_num[tx_sn_field_length]); + break; + case LIBLTE_RRC_RLC_MODE_UM_UNI_DL: + t_reordering = liblte_rrc_t_reordering_num[cnfg->dl_um_uni_rlc.t_reordering]; + rx_sn_field_length = (rlc_umd_sn_size_t)cnfg->dl_um_uni_rlc.sn_field_len; + rx_window_size = (RLC_UMD_SN_SIZE_5_BITS == rx_sn_field_length) ? 16 : 512; + rx_mod = (RLC_UMD_SN_SIZE_5_BITS == rx_sn_field_length) ? 32 : 1024; + log->info("%s configured in %s mode: " + "t_reordering=%d ms, rx_sn_field_length=%u bits\n", + rb_id_text[lcid], liblte_rrc_rlc_mode_text[cnfg->rlc_mode], + liblte_rrc_t_reordering_num[t_reordering], + rlc_umd_sn_size_num[rx_sn_field_length]); + break; + default: + log->error("RLC configuration mode not recognized\n"); + } +} + +void rlc_um::empty_queue() { + // Drop all messages in TX SDU queue + byte_buffer_t *buf; + while(tx_sdu_queue.size() > 0) { + tx_sdu_queue.read(&buf); + pool->deallocate(buf); + } +} + +void rlc_um::reset() +{ + + // Empty tx_sdu_queue before locking the mutex + empty_queue(); + + pthread_mutex_lock(&mutex); + vt_us = 0; + vr_ur = 0; + vr_ux = 0; + vr_uh = 0; + pdu_lost = false; + if(rx_sdu) + rx_sdu->reset(); + if(tx_sdu) + tx_sdu->reset(); + if(mac_timers) + mac_timers->get(reordering_timeout_id)->stop(); + + // Drop all messages in RX window + std::map::iterator it; + for(it = rx_window.begin(); it != rx_window.end(); it++) { + pool->deallocate(it->second.buf); + } + rx_window.clear(); + pthread_mutex_unlock(&mutex); +} + +rlc_mode_t rlc_um::get_mode() +{ + return RLC_MODE_UM; +} + +uint32_t rlc_um::get_bearer() +{ + return lcid; +} + +/**************************************************************************** + * PDCP interface + ***************************************************************************/ + +void rlc_um::write_sdu(byte_buffer_t *sdu) +{ + log->info_hex(sdu->msg, sdu->N_bytes, "%s Tx SDU", rb_id_text[lcid]); + tx_sdu_queue.write(sdu); +} + +/**************************************************************************** + * MAC interface + ***************************************************************************/ + +uint32_t rlc_um::get_buffer_state() +{ + // Bytes needed for tx SDUs + uint32_t n_sdus = tx_sdu_queue.size(); + uint32_t n_bytes = tx_sdu_queue.size_bytes(); + if(tx_sdu) + { + n_sdus++; + n_bytes += tx_sdu->N_bytes; + } + + // Room needed for header extensions? (integer rounding) + if(n_sdus > 1) + n_bytes += ((n_sdus-1)*1.5)+0.5; + + // Room needed for fixed header? + if(n_bytes > 0) + n_bytes += 2; + + return n_bytes; +} + +uint32_t rlc_um::get_total_buffer_state() +{ + return get_buffer_state(); +} + +int rlc_um::read_pdu(uint8_t *payload, uint32_t nof_bytes) +{ + log->debug("MAC opportunity - %d bytes\n", nof_bytes); + pthread_mutex_lock(&mutex); + int r = build_data_pdu(payload, nof_bytes); + pthread_mutex_unlock(&mutex); + return r; +} + +void rlc_um::write_pdu(uint8_t *payload, uint32_t nof_bytes) +{ + pthread_mutex_lock(&mutex); + handle_data_pdu(payload, nof_bytes); + pthread_mutex_unlock(&mutex); +} + +/**************************************************************************** + * Timeout callback interface + ***************************************************************************/ + +void rlc_um::timer_expired(uint32_t timeout_id) +{ + if(reordering_timeout_id == timeout_id) + { + pthread_mutex_lock(&mutex); + + // 36.322 v10 Section 5.1.2.2.4 + log->info("%s reordering timeout expiry - updating vr_ur and reassembling\n", + rb_id_text[lcid]); + + log->warning("Lost PDU SN: %d\n", vr_ur); + pdu_lost = true; + rx_sdu->reset(); + while(RX_MOD_BASE(vr_ur) < RX_MOD_BASE(vr_ux)) + { + vr_ur = (vr_ur + 1)%rx_mod; + log->debug("Entering Reassemble from timeout id=%d\n", timeout_id); + reassemble_rx_sdus(); + log->debug("Finished reassemble from timeout id=%d\n", timeout_id); + } + mac_timers->get(reordering_timeout_id)->stop(); + if(RX_MOD_BASE(vr_uh) > RX_MOD_BASE(vr_ur)) + { + mac_timers->get(reordering_timeout_id)->set(this, t_reordering); + mac_timers->get(reordering_timeout_id)->run(); + vr_ux = vr_uh; + } + + debug_state(); + pthread_mutex_unlock(&mutex); + } +} + +bool rlc_um::reordering_timeout_running() +{ + return mac_timers->get(reordering_timeout_id)->is_running(); +} + +/**************************************************************************** + * Helpers + ***************************************************************************/ + +int rlc_um::build_data_pdu(uint8_t *payload, uint32_t nof_bytes) +{ + if(!tx_sdu && tx_sdu_queue.size() == 0) + { + log->info("No data available to be sent\n"); + return 0; + } + + byte_buffer_t *pdu = pool_allocate; + if(!pdu || pdu->N_bytes != 0) + { + log->error("Failed to allocate PDU buffer\n"); + return 0; + } + rlc_umd_pdu_header_t header; + header.fi = RLC_FI_FIELD_START_AND_END_ALIGNED; + header.sn = vt_us; + header.N_li = 0; + header.sn_size = tx_sn_field_length; + + uint32_t to_move = 0; + uint32_t last_li = 0; + uint8_t *pdu_ptr = pdu->msg; + + int head_len = rlc_um_packed_length(&header); + int pdu_space = nof_bytes; + + if(pdu_space <= head_len) + { + log->warning("%s Cannot build a PDU - %d bytes available, %d bytes required for header\n", + rb_id_text[lcid], nof_bytes, head_len); + return 0; + } + + // Check for SDU segment + if(tx_sdu) + { + uint32_t space = pdu_space-head_len; + to_move = space >= tx_sdu->N_bytes ? tx_sdu->N_bytes : space; + log->debug("%s adding remainder of SDU segment - %d bytes of %d remaining\n", + rb_id_text[lcid], to_move, tx_sdu->N_bytes); + memcpy(pdu_ptr, tx_sdu->msg, to_move); + last_li = to_move; + pdu_ptr += to_move; + pdu->N_bytes += to_move; + tx_sdu->N_bytes -= to_move; + tx_sdu->msg += to_move; + if(tx_sdu->N_bytes == 0) + { + log->info("%s Complete SDU scheduled for tx. Stack latency: %ld us\n", + rb_id_text[lcid], tx_sdu->get_latency_us()); + pool->deallocate(tx_sdu); + tx_sdu = NULL; + } + pdu_space -= to_move; + header.fi |= RLC_FI_FIELD_NOT_START_ALIGNED; // First byte does not correspond to first byte of SDU + } + + // Pull SDUs from queue + while(pdu_space > head_len && tx_sdu_queue.size() > 0) + { + log->debug("pdu_space=%d, head_len=%d\n", pdu_space, head_len); + if(last_li > 0) + header.li[header.N_li++] = last_li; + head_len = rlc_um_packed_length(&header); + tx_sdu_queue.read(&tx_sdu); + uint32_t space = pdu_space-head_len; + to_move = space >= tx_sdu->N_bytes ? tx_sdu->N_bytes : space; + log->debug("%s adding new SDU segment - %d bytes of %d remaining\n", + rb_id_text[lcid], to_move, tx_sdu->N_bytes); + memcpy(pdu_ptr, tx_sdu->msg, to_move); + last_li = to_move; + pdu_ptr += to_move; + pdu->N_bytes += to_move; + tx_sdu->N_bytes -= to_move; + tx_sdu->msg += to_move; + if(tx_sdu->N_bytes == 0) + { + log->info("%s Complete SDU scheduled for tx. Stack latency: %ld us\n", + rb_id_text[lcid], tx_sdu->get_latency_us()); + pool->deallocate(tx_sdu); + tx_sdu = NULL; + } + pdu_space -= to_move; + } + + if(tx_sdu) + header.fi |= RLC_FI_FIELD_NOT_END_ALIGNED; // Last byte does not correspond to last byte of SDU + + // Set SN + header.sn = vt_us; + vt_us = (vt_us + 1)%tx_mod; + + // Add header and TX + log->debug("%s packing PDU with length %d\n", rb_id_text[lcid], pdu->N_bytes); + rlc_um_write_data_pdu_header(&header, pdu); + memcpy(payload, pdu->msg, pdu->N_bytes); + uint32_t ret = pdu->N_bytes; + log->debug("%sreturning length %d\n", rb_id_text[lcid], pdu->N_bytes); + pool->deallocate(pdu); + + debug_state(); + return ret; +} + +void rlc_um::handle_data_pdu(uint8_t *payload, uint32_t nof_bytes) +{ + std::map::iterator it; + rlc_umd_pdu_header_t header; + rlc_um_read_data_pdu_header(payload, nof_bytes, rx_sn_field_length, &header); + + log->info_hex(payload, nof_bytes, "RX %s Rx data PDU SN: %d", + rb_id_text[lcid], header.sn); + + if(RX_MOD_BASE(header.sn) >= RX_MOD_BASE(vr_uh-rx_window_size) && + RX_MOD_BASE(header.sn) < RX_MOD_BASE(vr_ur)) + { + log->info("%s SN: %d outside rx window [%d:%d] - discarding\n", + rb_id_text[lcid], header.sn, vr_ur, vr_uh); + return; + } + it = rx_window.find(header.sn); + if(rx_window.end() != it) + { + log->info("%s Discarding duplicate SN: %d\n", + rb_id_text[lcid], header.sn); + return; + } + + // Write to rx window + rlc_umd_pdu_t pdu; + pdu.buf = pool_allocate; + if (!pdu.buf) { + log->error("Discarting packet: no space in buffer pool\n"); + return; + } + memcpy(pdu.buf->msg, payload, nof_bytes); + pdu.buf->N_bytes = nof_bytes; + //Strip header from PDU + int header_len = rlc_um_packed_length(&header); + pdu.buf->msg += header_len; + pdu.buf->N_bytes -= header_len; + pdu.header = header; + rx_window[header.sn] = pdu; + + // Update vr_uh + if(!inside_reordering_window(header.sn)) + vr_uh = (header.sn + 1)%rx_mod; + + // Reassemble and deliver SDUs, while updating vr_ur + log->debug("Entering Reassemble from received PDU\n"); + reassemble_rx_sdus(); + log->debug("Finished reassemble from received PDU\n"); + + // Update reordering variables and timers + if(mac_timers->get(reordering_timeout_id)->is_running()) + { + if(RX_MOD_BASE(vr_ux) <= RX_MOD_BASE(vr_ur) || + (!inside_reordering_window(vr_ux) && vr_ux != vr_uh)) + { + mac_timers->get(reordering_timeout_id)->stop(); + } + } + if(!mac_timers->get(reordering_timeout_id)->is_running()) + { + if(RX_MOD_BASE(vr_uh) > RX_MOD_BASE(vr_ur)) + { + mac_timers->get(reordering_timeout_id)->set(this, t_reordering); + mac_timers->get(reordering_timeout_id)->run(); + vr_ux = vr_uh; + } + } + + debug_state(); +} + +void rlc_um::reassemble_rx_sdus() +{ + if(!rx_sdu) + rx_sdu = pool_allocate; + + // First catch up with lower edge of reordering window + while(!inside_reordering_window(vr_ur)) + { + if(rx_window.end() == rx_window.find(vr_ur)) + { + rx_sdu->reset(); + }else{ + // Handle any SDU segments + for(uint32_t i=0; imsg[rx_sdu->N_bytes], rx_window[vr_ur].buf->msg, len); + rx_sdu->N_bytes += len; + rx_window[vr_ur].buf->msg += len; + rx_window[vr_ur].buf->N_bytes -= len; + if((pdu_lost && !rlc_um_start_aligned(rx_window[vr_ur].header.fi)) || (vr_ur != ((vr_ur_in_rx_sdu+1)%rx_mod))) { + log->warning("Dropping remainder of lost PDU (lower edge middle segments, vr_ur=%d, vr_ur_in_rx_sdu=%d)\n", vr_ur, vr_ur_in_rx_sdu); + rx_sdu->reset(); + } else { + log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU vr_ur=%d, i=%d (lower edge middle segments)", rb_id_text[lcid], vr_ur, i); + rx_sdu->set_timestamp(); + pdcp->write_pdu(lcid, rx_sdu); + rx_sdu = pool_allocate; + } + pdu_lost = false; + } + + // Handle last segment + memcpy(&rx_sdu->msg[rx_sdu->N_bytes], rx_window[vr_ur].buf->msg, rx_window[vr_ur].buf->N_bytes); + rx_sdu->N_bytes += rx_window[vr_ur].buf->N_bytes; + log->debug("Writting last segment in SDU buffer. Lower edge vr_ur=%d, Buffer size=%d, segment size=%d\n", + vr_ur, rx_sdu->N_bytes, rx_window[vr_ur].buf->N_bytes); + vr_ur_in_rx_sdu = vr_ur; + if(rlc_um_end_aligned(rx_window[vr_ur].header.fi)) + { + if(pdu_lost && !rlc_um_start_aligned(rx_window[vr_ur].header.fi)) { + log->warning("Dropping remainder of lost PDU (lower edge last segments)\n"); + rx_sdu->reset(); + } else { + log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU vr_ur=%d (lower edge last segments)", rb_id_text[lcid], vr_ur); + rx_sdu->set_timestamp(); + pdcp->write_pdu(lcid, rx_sdu); + rx_sdu = pool_allocate; + } + pdu_lost = false; + } + + // Clean up rx_window + pool->deallocate(rx_window[vr_ur].buf); + rx_window.erase(vr_ur); + } + + vr_ur = (vr_ur + 1)%rx_mod; + } + + + // Now update vr_ur until we reach an SN we haven't yet received + while(rx_window.end() != rx_window.find(vr_ur)) + { + // Handle any SDU segments + for(uint32_t i=0; imsg[rx_sdu->N_bytes], rx_window[vr_ur].buf->msg, len); + log->debug("Concatenating %d bytes in to current length %d. rx_window remaining bytes=%d, vr_ur_in_rx_sdu=%d, vr_ur=%d, rx_mod=%d, last_mod=%d\n", + len, rx_sdu->N_bytes, rx_window[vr_ur].buf->N_bytes, vr_ur_in_rx_sdu, vr_ur, rx_mod, (vr_ur_in_rx_sdu+1)%rx_mod); + rx_sdu->N_bytes += len; + rx_window[vr_ur].buf->msg += len; + rx_window[vr_ur].buf->N_bytes -= len; + if((pdu_lost && !rlc_um_start_aligned(rx_window[vr_ur].header.fi)) || (vr_ur != ((vr_ur_in_rx_sdu+1)%rx_mod))) { + log->warning("Dropping remainder of lost PDU (update vr_ur middle segments, vr_ur=%d, vr_ur_in_rx_sdu=%d)\n", vr_ur, vr_ur_in_rx_sdu); + rx_sdu->reset(); + } else { + log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU vr_ur=%d, i=%d, (update vr_ur middle segments)", rb_id_text[lcid], vr_ur, i); + rx_sdu->set_timestamp(); + pdcp->write_pdu(lcid, rx_sdu); + rx_sdu = pool_allocate; + } + pdu_lost = false; + } + + // Handle last segment + memcpy(&rx_sdu->msg[rx_sdu->N_bytes], rx_window[vr_ur].buf->msg, rx_window[vr_ur].buf->N_bytes); + rx_sdu->N_bytes += rx_window[vr_ur].buf->N_bytes; + log->debug("Writting last segment in SDU buffer. Updating vr_ur=%d, Buffer size=%d, segment size=%d\n", + vr_ur, rx_sdu->N_bytes, rx_window[vr_ur].buf->N_bytes); + vr_ur_in_rx_sdu = vr_ur; + if(rlc_um_end_aligned(rx_window[vr_ur].header.fi)) + { + if(pdu_lost && !rlc_um_start_aligned(rx_window[vr_ur].header.fi)) { + log->warning("Dropping remainder of lost PDU (update vr_ur last segments)\n"); + rx_sdu->reset(); + } else { + log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU vr_ur=%d (update vr_ur last segments)", rb_id_text[lcid], vr_ur); + rx_sdu->set_timestamp(); + pdcp->write_pdu(lcid, rx_sdu); + rx_sdu = pool_allocate; + } + pdu_lost = false; + } + + // Clean up rx_window + pool->deallocate(rx_window[vr_ur].buf); + rx_window.erase(vr_ur); + + vr_ur = (vr_ur + 1)%rx_mod; + } +} + +bool rlc_um::inside_reordering_window(uint16_t sn) +{ + if(RX_MOD_BASE(sn) >= RX_MOD_BASE(vr_uh-rx_window_size) && + RX_MOD_BASE(sn) < RX_MOD_BASE(vr_uh)) + { + return true; + }else{ + return false; + } +} + +void rlc_um::debug_state() +{ + log->debug("%s vt_us = %d, vr_ur = %d, vr_ux = %d, vr_uh = %d \n", + rb_id_text[lcid], vt_us, vr_ur, vr_ux, vr_uh); + +} + +/**************************************************************************** + * Header pack/unpack helper functions + * Ref: 3GPP TS 36.322 v10.0.0 Section 6.2.1 + ***************************************************************************/ + +void rlc_um_read_data_pdu_header(byte_buffer_t *pdu, rlc_umd_sn_size_t sn_size, rlc_umd_pdu_header_t *header) +{ + rlc_um_read_data_pdu_header(pdu->msg, pdu->N_bytes, sn_size, header); +} + +void rlc_um_read_data_pdu_header(uint8_t *payload, uint32_t nof_bytes, rlc_umd_sn_size_t sn_size, rlc_umd_pdu_header_t *header) +{ + uint8_t ext; + uint8_t *ptr = payload; + + // Fixed part + if(RLC_UMD_SN_SIZE_5_BITS == sn_size) + { + header->fi = (rlc_fi_field_t)((*ptr >> 6) & 0x03); // 2 bits FI + ext = ((*ptr >> 5) & 0x01); // 1 bit EXT + header->sn = *ptr & 0x1F; // 5 bits SN + ptr++; + }else{ + header->fi = (rlc_fi_field_t)((*ptr >> 3) & 0x03); // 2 bits FI + ext = ((*ptr >> 2) & 0x01); // 1 bit EXT + header->sn = (*ptr & 0x03) << 8; // 2 bits SN + ptr++; + header->sn |= (*ptr & 0xFF); // 8 bits SN + ptr++; + } + + header->sn_size = sn_size; + + // Extension part + header->N_li = 0; + while(ext) + { + if(header->N_li%2 == 0) + { + ext = ((*ptr >> 7) & 0x01); + header->li[header->N_li] = (*ptr & 0x7F) << 4; // 7 bits of LI + ptr++; + header->li[header->N_li] |= (*ptr & 0xF0) >> 4; // 4 bits of LI + header->N_li++; + } + else + { + ext = (*ptr >> 3) & 0x01; + header->li[header->N_li] = (*ptr & 0x07) << 8; // 3 bits of LI + ptr++; + header->li[header->N_li] |= (*ptr & 0xFF); // 8 bits of LI + header->N_li++; + ptr++; + } + } +} + +void rlc_um_write_data_pdu_header(rlc_umd_pdu_header_t *header, byte_buffer_t *pdu) +{ + uint32_t i; + uint8_t ext = (header->N_li > 0) ? 1 : 0; + + // Make room for the header + uint32_t len = rlc_um_packed_length(header); + pdu->msg -= len; + uint8_t *ptr = pdu->msg; + + // Fixed part + if(RLC_UMD_SN_SIZE_5_BITS == header->sn_size) + { + *ptr = (header->fi & 0x03) << 6; // 2 bits FI + *ptr |= (ext & 0x01) << 5; // 1 bit EXT + *ptr |= header->sn & 0x1F; // 5 bits SN + ptr++; + }else{ + *ptr = (header->fi & 0x03) << 3; // 3 Reserved bits | 2 bits FI + *ptr |= (ext & 0x01) << 2; // 1 bit EXT + *ptr |= (header->sn & 0x300) >> 8; // 2 bits SN + ptr++; + *ptr = (header->sn & 0xFF); // 8 bits SN + ptr++; + } + + // Extension part + i = 0; + while(i < header->N_li) + { + ext = ((i+1) == header->N_li) ? 0 : 1; + *ptr = (ext & 0x01) << 7; // 1 bit header + *ptr |= (header->li[i] & 0x7F0) >> 4; // 7 bits of LI + ptr++; + *ptr = (header->li[i] & 0x00F) << 4; // 4 bits of LI + i++; + if(i < header->N_li) + { + ext = ((i+1) == header->N_li) ? 0 : 1; + *ptr |= (ext & 0x01) << 3; // 1 bit header + *ptr |= (header->li[i] & 0x700) >> 8; // 3 bits of LI + ptr++; + *ptr = (header->li[i] & 0x0FF); // 8 bits of LI + ptr++; + i++; + } + } + // Pad if N_li is odd + if(header->N_li%2 == 1) + ptr++; + + pdu->N_bytes += ptr-pdu->msg; +} + +uint32_t rlc_um_packed_length(rlc_umd_pdu_header_t *header) +{ + uint32_t len = 0; + if(RLC_UMD_SN_SIZE_5_BITS == header->sn_size) + { + len += 1; // Fixed part is 1 byte + }else{ + len += 2; // Fixed part is 2 bytes + } + len += header->N_li * 1.5 + 0.5; // Extension part - integer rounding up + return len; +} + +bool rlc_um_start_aligned(uint8_t fi) +{ + return (fi == RLC_FI_FIELD_START_AND_END_ALIGNED || fi == RLC_FI_FIELD_NOT_END_ALIGNED); +} + +bool rlc_um_end_aligned(uint8_t fi) +{ + return (fi == RLC_FI_FIELD_START_AND_END_ALIGNED || fi == RLC_FI_FIELD_NOT_START_ALIGNED); +} + +} // namespace srsue diff --git a/lib/test/CMakeLists.txt b/lib/test/CMakeLists.txt new file mode 100644 index 000000000..a1af8153c --- /dev/null +++ b/lib/test/CMakeLists.txt @@ -0,0 +1,22 @@ +# +# Copyright 2013-2017 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/. +# + +add_subdirectory(common) +add_subdirectory(upper) diff --git a/lib/test/common/CMakeLists.txt b/lib/test/common/CMakeLists.txt new file mode 100644 index 000000000..3faa2ff59 --- /dev/null +++ b/lib/test/common/CMakeLists.txt @@ -0,0 +1,38 @@ +# +# Copyright 2013-2017 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/. +# + +####################################################################### +# LOGGER TEST +####################################################################### +add_executable(logger_test logger_test.cc) +target_link_libraries(logger_test srslte_phy srslte_common srslte_phy ${SEC_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) +add_test(logger_test logger_test) + +add_executable(msg_queue_test msg_queue_test.cc) +target_link_libraries(msg_queue_test srslte_phy srslte_common ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) +add_test(msg_queue_test msg_queue_test) + +add_executable(log_filter_test log_filter_test.cc) +target_link_libraries(log_filter_test srslte_phy srslte_common srslte_phy ${SEC_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) + +add_executable(timeout_test timeout_test.cc) +target_link_libraries(timeout_test srslte_phy ${CMAKE_THREAD_LIBS_INIT}) + +add_executable(bcd_helpers_test bcd_helpers_test.cc) diff --git a/lib/test/common/bcd_helpers_test.cc b/lib/test/common/bcd_helpers_test.cc new file mode 100644 index 000000000..c8c563150 --- /dev/null +++ b/lib/test/common/bcd_helpers_test.cc @@ -0,0 +1,67 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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 +#include "srslte/common/bcd_helpers.h" + +using namespace srslte; + +int main(int argc, char **argv) +{ + std::string mcc_str = "001"; + std::string mnc_str = "001"; + uint16_t mcc; + uint16_t mnc; + + // String to code + + assert(string_to_mcc(mcc_str, &mcc)); + assert(mcc == 0xF001); + + assert(string_to_mnc(mnc_str, &mnc)); + assert(mnc == 0xF001); + + mnc_str = "01"; + assert(string_to_mnc(mnc_str, &mnc)); + assert(mnc == 0xFF01); + + // Code to string + + mcc_str = ""; + mnc_str = ""; + mcc = 0xF001; + mnc = 0xF001; + + assert(mcc_to_string(mcc, &mcc_str)); + assert(mcc_str.compare("001") == 0); + + assert(mnc_to_string(mnc, &mnc_str)); + assert(mnc_str.compare("001") == 0); + + mnc = 0xFF01; + assert(mnc_to_string(mnc, &mnc_str)); + assert(mnc_str.compare("01") == 0); +} diff --git a/lib/test/common/log_filter_test.cc b/lib/test/common/log_filter_test.cc new file mode 100644 index 000000000..d48821dac --- /dev/null +++ b/lib/test/common/log_filter_test.cc @@ -0,0 +1,134 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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/. + * + */ + +#define NTHREADS 100 +#define NMSGS 100 + +#include +#include "srslte/common/log_filter.h" + +using namespace srslte; + +typedef struct { + logger *l; + int thread_id; +}args_t; + +void* thread_loop(void *a) { + args_t *args = (args_t*)a; + char buf[100]; + + sprintf(buf, "LAYER%d", args->thread_id); + log_filter filter(buf, args->l); + filter.set_level(LOG_LEVEL_INFO); + + for(int i=0;ithread_id, i); + filter.warning("Thread %d: %d", args->thread_id, i); + filter.info("Thread %d: %d", args->thread_id, i); + filter.debug("Thread %d: %d", args->thread_id, i); + } + return NULL; +} + +void* thread_loop_hex(void *a) { + args_t *args = (args_t*)a; + char buf[100]; + uint8_t hex[100]; + + for(int i=0;i<100;i++) + hex[i] = i & 0xFF; + sprintf(buf, "LAYER%d", args->thread_id); + log_filter filter(buf, args->l); + filter.set_level(LOG_LEVEL_DEBUG); + filter.set_hex_limit(32); + + for(int i=0;ithread_id, i); + filter.warning_hex(hex, 100, "Thread %d: %d", args->thread_id, i); + filter.info_hex(hex, 100, "Thread %d: %d", args->thread_id, i); + filter.debug_hex(hex, 100, "Thread %d: %d", args->thread_id, i); + } + return NULL; +} + +void write(std::string filename) { + logger l; + l.init(filename); + pthread_t threads[NTHREADS]; + args_t args[NTHREADS]; + for(int i=0;i +#include +#include "srslte/common/logger.h" + +using namespace srslte; + +typedef struct { + logger *l; + int thread_id; +}args_t; + +void* thread_loop(void *a) { + args_t *args = (args_t*)a; + char buf[100]; + for(int i=0;ithread_id, i); + args->l->log(buf); + } + return NULL; +} + +void write(std::string filename) { + logger l; + l.init(filename); + pthread_t threads[NTHREADS]; + args_t args[NTHREADS]; + for(int i=0;i +#include "srslte/common/msg_queue.h" + +using namespace srslte; + +typedef struct { + msg_queue *q; +}args_t; + +void* write_thread(void *a) { + args_t *args = (args_t*)a; + for(uint32_t i=0;imsg, &i, 4); + b->N_bytes = 4; + args->q->write(b); + } + return NULL; +} + +int main(int argc, char **argv) { + bool result; + msg_queue q; + byte_buffer_t *b; + pthread_t thread; + args_t args; + u_int32_t r; + + result = true; + args.q = &q; + + pthread_create(&thread, NULL, &write_thread, &args); + + for(uint32_t i=0;imsg, 4); + delete b; + if(r != i) + result = false; + } + + pthread_join(thread, NULL); + + if(result) { + printf("Passed\n"); + exit(0); + }else{ + printf("Failed\n;"); + exit(1); + } +} diff --git a/lib/test/common/timeout_test.cc b/lib/test/common/timeout_test.cc new file mode 100644 index 000000000..0c2593102 --- /dev/null +++ b/lib/test/common/timeout_test.cc @@ -0,0 +1,92 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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 +#include +#include "srslte/common/timeout.h" + +using namespace srslte; + +class callback + : public timeout_callback +{ +public: + callback() { + finished = false; + pthread_mutex_init(&mutex, NULL); + pthread_cond_init(&cvar, NULL); + } + + void timeout_expired(uint32_t timeout_id) + { + pthread_mutex_lock(&mutex); + finished = true; + pthread_cond_signal(&cvar); + pthread_mutex_unlock(&mutex); + } + void wait() + { + pthread_mutex_lock(&mutex); + while(!finished) { + pthread_cond_wait(&cvar, &mutex); + } + pthread_mutex_unlock(&mutex); + } + struct timeval start_time[3]; +private: + bool finished; + pthread_cond_t cvar; + pthread_mutex_t mutex; +}; + +int main(int argc, char **argv) { + bool result; + uint32_t id = 0; + uint32_t duration_msec = 5; + + callback c; + timeout t; + + gettimeofday(&c.start_time[1], NULL); + t.start(duration_msec, 0, &c); + c.wait(); + gettimeofday(&c.start_time[2], NULL); + get_time_interval(c.start_time); + uint32_t diff_ms = c.start_time[0].tv_usec*1e-3; + printf("Target duration: %dms, started: %ld:%ld, ended: %ld:%ld, actual duration %dms\n", + duration_msec, c.start_time[1].tv_sec, c.start_time[1].tv_usec, c.start_time[2].tv_sec, c.start_time[2].tv_usec, diff_ms); + + result = (diff_ms == duration_msec); + + if(result) { + printf("Passed\n"); + exit(0); + }else{ + printf("Failed\n;"); + exit(1); + } +} diff --git a/lib/test/upper/CMakeLists.txt b/lib/test/upper/CMakeLists.txt new file mode 100644 index 000000000..82072c004 --- /dev/null +++ b/lib/test/upper/CMakeLists.txt @@ -0,0 +1,50 @@ +# +# Copyright 2013-2017 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/. +# + +add_executable(rlc_am_data_test rlc_am_data_test.cc) +target_link_libraries(rlc_am_data_test srslte_upper srslte_phy srslte_common) +add_test(rlc_am_data_test rlc_am_data_test) + +add_executable(rlc_am_control_test rlc_am_control_test.cc) +target_link_libraries(rlc_am_control_test srslte_upper srslte_phy) +add_test(rlc_am_control_test rlc_am_control_test) + +add_executable(rlc_am_test rlc_am_test.cc) +target_link_libraries(rlc_am_test srslte_upper srslte_phy srslte_common) +add_test(rlc_am_test rlc_am_test) + +add_executable(rlc_um_data_test rlc_um_data_test.cc) +target_link_libraries(rlc_um_data_test srslte_upper srslte_phy srslte_common) +add_test(rlc_um_data_test rlc_um_data_test) + +add_executable(rlc_um_test rlc_um_test.cc) +target_link_libraries(rlc_um_test srslte_upper srslte_phy) +add_test(rlc_um_test rlc_um_test) + + +######################################################################## +# Option to run command after build (useful for remote builds) +######################################################################## +if (NOT ${BUILD_CMD} STREQUAL "") + message(STATUS "Added custom post-build command: ${BUILD_CMD}") + add_custom_command(TARGET ip_test POST_BUILD COMMAND ${BUILD_CMD}) +else(NOT ${BUILD_CMD} STREQUAL "") + message(STATUS "No post-build command defined") +endif (NOT ${BUILD_CMD} STREQUAL "") diff --git a/lib/test/upper/rlc_am_control_test.cc b/lib/test/upper/rlc_am_control_test.cc new file mode 100644 index 000000000..874b256d1 --- /dev/null +++ b/lib/test/upper/rlc_am_control_test.cc @@ -0,0 +1,70 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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 +#include +#include "srslte/upper/rlc_am.h" + +// Simple status PDU +uint8_t pdu1[] = {0x00, 0x78}; +uint32_t PDU1_LEN = 2; + +// Status PDU with 4 NACKs +uint8_t pdu2[] = {0x00 ,0x22 ,0x00 ,0x40 ,0x0C ,0x01 ,0xC0 ,0x20}; +uint32_t PDU2_LEN = 8; + +int main(int argc, char **argv) { + srslte::rlc_status_pdu_t s; + srslte::byte_buffer_t b1,b2; + + memcpy(b1.msg, &pdu1[0], PDU1_LEN); + b1.N_bytes = PDU1_LEN; + rlc_am_read_status_pdu(&b1, &s); + assert(s.ack_sn == 30); + assert(s.N_nack == 0); + rlc_am_write_status_pdu(&s, &b2); + assert(b2.N_bytes == PDU1_LEN); + for(uint32_t i=0;i +#include +#include "srslte/upper/rlc_am.h" + +// Fixed header only +uint8_t pdu1[] = {0x88, 0x06}; +uint32_t PDU1_LEN = 2; + +// Fixed + 2 LI fields (each 1500) +uint8_t pdu2[] = {0x8C, 0x00, 0xDD, 0xC5, 0xDC}; +uint32_t PDU2_LEN = 5; + +// Fixed + 3 LI fields (each 1500) +uint8_t pdu3[] = {0x8C, 0x00, 0xDD, 0xCD, 0xDC, 0x5D, 0xC0}; +uint32_t PDU3_LEN = 7; + +using namespace srslte; + +int main(int argc, char **argv) { + srslte::rlc_amd_pdu_header_t h; + srslte::byte_buffer_t b1,b2; + + memcpy(b1.msg, &pdu1[0], PDU1_LEN); + b1.N_bytes = PDU1_LEN; + rlc_am_read_data_pdu_header(&b1, &h); + assert(RLC_DC_FIELD_DATA_PDU == h.dc); + assert(0x01 == h.fi); + assert(0 == h.N_li); + assert(0 == h.lsf); + assert(0 == h.p); + assert(0 == h.rf); + assert(0 == h.so); + assert(6 == h.sn); + rlc_am_write_data_pdu_header(&h, &b2); + assert(b2.N_bytes == PDU1_LEN); + for(uint32_t i=0;i +#include "srslte/common/log_stdout.h" +#include "srslte/upper/rlc_am.h" +#include +#define NBUFS 5 + +using namespace srsue; +using namespace srslte; + +class mac_dummy_timers + :public srslte::mac_interface_timers +{ +public: + srslte::timers::timer* get(uint32_t timer_id) + { + return &t; + } + uint32_t get_unique_id(){return 0;} + +private: + srslte::timers::timer t; +}; + +class rlc_am_tester + :public pdcp_interface_rlc + ,public rrc_interface_rlc +{ +public: + rlc_am_tester(){n_sdus = 0;} + + // PDCP interface + void write_pdu(uint32_t lcid, byte_buffer_t *sdu) + { + assert(lcid == 1); + sdus[n_sdus++] = sdu; + } + void write_pdu_bcch_bch(byte_buffer_t *sdu) {} + void write_pdu_bcch_dlsch(byte_buffer_t *sdu) {} + void write_pdu_pcch(byte_buffer_t *sdu) {} + + // RRC interface + void max_retx_attempted(){} + + byte_buffer_t *sdus[10]; + int n_sdus; +}; + +void basic_test() +{ + srslte::log_stdout log1("RLC_AM_1"); + srslte::log_stdout log2("RLC_AM_2"); + log1.set_level(srslte::LOG_LEVEL_DEBUG); + log2.set_level(srslte::LOG_LEVEL_DEBUG); + log1.set_hex_limit(-1); + log2.set_hex_limit(-1); + rlc_am_tester tester; + mac_dummy_timers timers; + + rlc_am rlc1; + rlc_am rlc2; + + int len; + + log1.set_level(srslte::LOG_LEVEL_DEBUG); + log2.set_level(srslte::LOG_LEVEL_DEBUG); + + rlc1.init(&log1, 1, &tester, &tester, &timers); + rlc2.init(&log2, 1, &tester, &tester, &timers); + + LIBLTE_RRC_RLC_CONFIG_STRUCT cnfg; + cnfg.rlc_mode = LIBLTE_RRC_RLC_MODE_AM; + cnfg.dl_am_rlc.t_reordering = LIBLTE_RRC_T_REORDERING_MS5; + cnfg.dl_am_rlc.t_status_prohibit = LIBLTE_RRC_T_STATUS_PROHIBIT_MS5; + cnfg.ul_am_rlc.max_retx_thresh = LIBLTE_RRC_MAX_RETX_THRESHOLD_T4; + cnfg.ul_am_rlc.poll_byte = LIBLTE_RRC_POLL_BYTE_KB25; + cnfg.ul_am_rlc.poll_pdu = LIBLTE_RRC_POLL_PDU_P4; + + rlc1.configure(&cnfg); + rlc2.configure(&cnfg); + + // Push 5 SDUs into RLC1 + byte_buffer_t sdu_bufs[NBUFS]; + for(int i=0;iN_bytes == 1); + assert(*(tester.sdus[i]->msg) == i); + } +} + +void concat_test() +{ + srslte::log_stdout log1("RLC_AM_1"); + srslte::log_stdout log2("RLC_AM_2"); + log1.set_level(srslte::LOG_LEVEL_DEBUG); + log2.set_level(srslte::LOG_LEVEL_DEBUG); + log1.set_hex_limit(-1); + log2.set_hex_limit(-1); + rlc_am_tester tester; + mac_dummy_timers timers; + + rlc_am rlc1; + rlc_am rlc2; + + int len; + + log1.set_level(srslte::LOG_LEVEL_DEBUG); + log2.set_level(srslte::LOG_LEVEL_DEBUG); + + rlc1.init(&log1, 1, &tester, &tester, &timers); + rlc2.init(&log2, 1, &tester, &tester, &timers); + + LIBLTE_RRC_RLC_CONFIG_STRUCT cnfg; + cnfg.rlc_mode = LIBLTE_RRC_RLC_MODE_AM; + cnfg.dl_am_rlc.t_reordering = LIBLTE_RRC_T_REORDERING_MS5; + cnfg.dl_am_rlc.t_status_prohibit = LIBLTE_RRC_T_STATUS_PROHIBIT_MS5; + cnfg.ul_am_rlc.max_retx_thresh = LIBLTE_RRC_MAX_RETX_THRESHOLD_T4; + cnfg.ul_am_rlc.poll_byte = LIBLTE_RRC_POLL_BYTE_KB25; + cnfg.ul_am_rlc.poll_pdu = LIBLTE_RRC_POLL_PDU_P4; + + rlc1.configure(&cnfg); + rlc2.configure(&cnfg); + + // Push 5 SDUs into RLC1 + byte_buffer_t sdu_bufs[NBUFS]; + for(int i=0;iN_bytes == 1); + assert(*(tester.sdus[i]->msg) == i); + } +} + +void segment_test() +{ + srslte::log_stdout log1("RLC_AM_1"); + srslte::log_stdout log2("RLC_AM_2"); + log1.set_level(srslte::LOG_LEVEL_DEBUG); + log2.set_level(srslte::LOG_LEVEL_DEBUG); + log1.set_hex_limit(-1); + log2.set_hex_limit(-1); + rlc_am_tester tester; + mac_dummy_timers timers; + + rlc_am rlc1; + rlc_am rlc2; + + int len; + + log1.set_level(srslte::LOG_LEVEL_DEBUG); + log2.set_level(srslte::LOG_LEVEL_DEBUG); + + rlc1.init(&log1, 1, &tester, &tester, &timers); + rlc2.init(&log2, 1, &tester, &tester, &timers); + + LIBLTE_RRC_RLC_CONFIG_STRUCT cnfg; + cnfg.rlc_mode = LIBLTE_RRC_RLC_MODE_AM; + cnfg.dl_am_rlc.t_reordering = LIBLTE_RRC_T_REORDERING_MS5; + cnfg.dl_am_rlc.t_status_prohibit = LIBLTE_RRC_T_STATUS_PROHIBIT_MS5; + cnfg.ul_am_rlc.max_retx_thresh = LIBLTE_RRC_MAX_RETX_THRESHOLD_T4; + cnfg.ul_am_rlc.poll_byte = LIBLTE_RRC_POLL_BYTE_KB25; + cnfg.ul_am_rlc.poll_pdu = LIBLTE_RRC_POLL_PDU_P4; + + rlc1.configure(&cnfg); + rlc2.configure(&cnfg); + + // Push 5 SDUs into RLC1 + byte_buffer_t sdu_bufs[NBUFS]; + for(int i=0;i 0){ + len = rlc1.read_pdu(pdu_bufs[n_pdus].msg, 10); // 2 header + payload + pdu_bufs[n_pdus++].N_bytes = len; + } + + assert(0 == rlc1.get_buffer_state()); + + // Write PDUs into RLC2 + for(int i=0;iN_bytes == 10); + for(int j=0;j<10;j++) + assert(tester.sdus[i]->msg[j] == j); + } +} + +void retx_test() +{ + srslte::log_stdout log1("RLC_AM_1"); + srslte::log_stdout log2("RLC_AM_2"); + log1.set_level(srslte::LOG_LEVEL_DEBUG); + log2.set_level(srslte::LOG_LEVEL_DEBUG); + log1.set_hex_limit(-1); + log2.set_hex_limit(-1); + rlc_am_tester tester; + mac_dummy_timers timers; + + rlc_am rlc1; + rlc_am rlc2; + + int len; + + log1.set_level(srslte::LOG_LEVEL_DEBUG); + log2.set_level(srslte::LOG_LEVEL_DEBUG); + + rlc1.init(&log1, 1, &tester, &tester, &timers); + rlc2.init(&log2, 1, &tester, &tester, &timers); + + LIBLTE_RRC_RLC_CONFIG_STRUCT cnfg; + cnfg.rlc_mode = LIBLTE_RRC_RLC_MODE_AM; + cnfg.dl_am_rlc.t_reordering = LIBLTE_RRC_T_REORDERING_MS5; + cnfg.dl_am_rlc.t_status_prohibit = LIBLTE_RRC_T_STATUS_PROHIBIT_MS5; + cnfg.ul_am_rlc.max_retx_thresh = LIBLTE_RRC_MAX_RETX_THRESHOLD_T4; + cnfg.ul_am_rlc.poll_byte = LIBLTE_RRC_POLL_BYTE_KB25; + cnfg.ul_am_rlc.poll_pdu = LIBLTE_RRC_POLL_PDU_P4; + + rlc1.configure(&cnfg); + rlc2.configure(&cnfg); + + // Push 5 SDUs into RLC1 + byte_buffer_t sdu_bufs[NBUFS]; + for(int i=0;iN_bytes == 1); + assert(*(tester.sdus[i]->msg) == i); + } +} + +void resegment_test_1() +{ + // SDUs: | 10 | 10 | 10 | 10 | 10 | + // PDUs: | 10 | 10 | 10 | 10 | 10 | + // Retx PDU segments: | 5 | 5| + + srslte::log_stdout log1("RLC_AM_1"); + srslte::log_stdout log2("RLC_AM_2"); + log1.set_level(srslte::LOG_LEVEL_DEBUG); + log2.set_level(srslte::LOG_LEVEL_DEBUG); + log1.set_hex_limit(-1); + log2.set_hex_limit(-1); + rlc_am_tester tester; + mac_dummy_timers timers; + + rlc_am rlc1; + rlc_am rlc2; + + int len; + + log1.set_level(srslte::LOG_LEVEL_DEBUG); + log2.set_level(srslte::LOG_LEVEL_DEBUG); + + rlc1.init(&log1, 1, &tester, &tester, &timers); + rlc2.init(&log2, 1, &tester, &tester, &timers); + + LIBLTE_RRC_RLC_CONFIG_STRUCT cnfg; + cnfg.rlc_mode = LIBLTE_RRC_RLC_MODE_AM; + cnfg.dl_am_rlc.t_reordering = LIBLTE_RRC_T_REORDERING_MS5; + cnfg.dl_am_rlc.t_status_prohibit = LIBLTE_RRC_T_STATUS_PROHIBIT_MS5; + cnfg.ul_am_rlc.max_retx_thresh = LIBLTE_RRC_MAX_RETX_THRESHOLD_T4; + cnfg.ul_am_rlc.poll_byte = LIBLTE_RRC_POLL_BYTE_KB25; + cnfg.ul_am_rlc.poll_pdu = LIBLTE_RRC_POLL_PDU_P4; + + rlc1.configure(&cnfg); + rlc2.configure(&cnfg); + + // Push 5 SDUs into RLC1 + byte_buffer_t sdu_bufs[NBUFS]; + for(int i=0;iN_bytes == 10); + for(int j=0;j<10;j++) + assert(tester.sdus[i]->msg[j] == j); + } +} + +void resegment_test_2() +{ + + // SDUs: | 10 | 10 | 10 | 10 | 10 | + // PDUs: | 5 | 10 | 20 | 10 | 5 | + // Retx PDU segments: | 10 | 10 | + + srslte::log_stdout log1("RLC_AM_1"); + srslte::log_stdout log2("RLC_AM_2"); + log1.set_level(srslte::LOG_LEVEL_DEBUG); + log2.set_level(srslte::LOG_LEVEL_DEBUG); + log1.set_hex_limit(-1); + log2.set_hex_limit(-1); + rlc_am_tester tester; + mac_dummy_timers timers; + + rlc_am rlc1; + rlc_am rlc2; + + int len; + + log1.set_level(srslte::LOG_LEVEL_DEBUG); + log2.set_level(srslte::LOG_LEVEL_DEBUG); + + rlc1.init(&log1, 1, &tester, &tester, &timers); + rlc2.init(&log2, 1, &tester, &tester, &timers); + + LIBLTE_RRC_RLC_CONFIG_STRUCT cnfg; + cnfg.rlc_mode = LIBLTE_RRC_RLC_MODE_AM; + cnfg.dl_am_rlc.t_reordering = LIBLTE_RRC_T_REORDERING_MS5; + cnfg.dl_am_rlc.t_status_prohibit = LIBLTE_RRC_T_STATUS_PROHIBIT_MS5; + cnfg.ul_am_rlc.max_retx_thresh = LIBLTE_RRC_MAX_RETX_THRESHOLD_T4; + cnfg.ul_am_rlc.poll_byte = LIBLTE_RRC_POLL_BYTE_KB25; + cnfg.ul_am_rlc.poll_pdu = LIBLTE_RRC_POLL_PDU_P4; + + rlc1.configure(&cnfg); + rlc2.configure(&cnfg); + + // Push 5 SDUs into RLC1 + byte_buffer_t sdu_bufs[NBUFS]; + for(int i=0;iN_bytes == 10); + for(int j=0;j<10;j++) + assert(tester.sdus[i]->msg[j] == j); + } +} + +void resegment_test_3() +{ + + // SDUs: | 10 | 10 | 10 | 10 | 10 | + // PDUs: | 5 | 5| 20 | 10 | 10 | + // Retx PDU segments: | 10 | 10 | + + srslte::log_stdout log1("RLC_AM_1"); + srslte::log_stdout log2("RLC_AM_2"); + log1.set_level(srslte::LOG_LEVEL_DEBUG); + log2.set_level(srslte::LOG_LEVEL_DEBUG); + log1.set_hex_limit(-1); + log2.set_hex_limit(-1); + rlc_am_tester tester; + mac_dummy_timers timers; + + rlc_am rlc1; + rlc_am rlc2; + + int len; + + log1.set_level(srslte::LOG_LEVEL_DEBUG); + log2.set_level(srslte::LOG_LEVEL_DEBUG); + + rlc1.init(&log1, 1, &tester, &tester, &timers); + rlc2.init(&log2, 1, &tester, &tester, &timers); + + LIBLTE_RRC_RLC_CONFIG_STRUCT cnfg; + cnfg.rlc_mode = LIBLTE_RRC_RLC_MODE_AM; + cnfg.dl_am_rlc.t_reordering = LIBLTE_RRC_T_REORDERING_MS5; + cnfg.dl_am_rlc.t_status_prohibit = LIBLTE_RRC_T_STATUS_PROHIBIT_MS5; + cnfg.ul_am_rlc.max_retx_thresh = LIBLTE_RRC_MAX_RETX_THRESHOLD_T4; + cnfg.ul_am_rlc.poll_byte = LIBLTE_RRC_POLL_BYTE_KB25; + cnfg.ul_am_rlc.poll_pdu = LIBLTE_RRC_POLL_PDU_P4; + + rlc1.configure(&cnfg); + rlc2.configure(&cnfg); + + // Push 5 SDUs into RLC1 + byte_buffer_t sdu_bufs[NBUFS]; + for(int i=0;iN_bytes == 10); + for(int j=0;j<10;j++) + assert(tester.sdus[i]->msg[j] == j); + } +} + +void resegment_test_4() +{ + + // SDUs: | 10 | 10 | 10 | 10 | 10 | + // PDUs: | 5 | 5| 30 | 5 | 5| + // Retx PDU segments: | 15 | 15 | + + srslte::log_stdout log1("RLC_AM_1"); + srslte::log_stdout log2("RLC_AM_2"); + log1.set_level(srslte::LOG_LEVEL_DEBUG); + log2.set_level(srslte::LOG_LEVEL_DEBUG); + log1.set_hex_limit(-1); + log2.set_hex_limit(-1); + rlc_am_tester tester; + mac_dummy_timers timers; + + rlc_am rlc1; + rlc_am rlc2; + + int len; + + log1.set_level(srslte::LOG_LEVEL_DEBUG); + log2.set_level(srslte::LOG_LEVEL_DEBUG); + + rlc1.init(&log1, 1, &tester, &tester, &timers); + rlc2.init(&log2, 1, &tester, &tester, &timers); + + LIBLTE_RRC_RLC_CONFIG_STRUCT cnfg; + cnfg.rlc_mode = LIBLTE_RRC_RLC_MODE_AM; + cnfg.dl_am_rlc.t_reordering = LIBLTE_RRC_T_REORDERING_MS5; + cnfg.dl_am_rlc.t_status_prohibit = LIBLTE_RRC_T_STATUS_PROHIBIT_MS5; + cnfg.ul_am_rlc.max_retx_thresh = LIBLTE_RRC_MAX_RETX_THRESHOLD_T4; + cnfg.ul_am_rlc.poll_byte = LIBLTE_RRC_POLL_BYTE_KB25; + cnfg.ul_am_rlc.poll_pdu = LIBLTE_RRC_POLL_PDU_P4; + + rlc1.configure(&cnfg); + rlc2.configure(&cnfg); + + // Push 5 SDUs into RLC1 + byte_buffer_t sdu_bufs[NBUFS]; + for(int i=0;iN_bytes == 10); + for(int j=0;j<10;j++) + assert(tester.sdus[i]->msg[j] == j); + } +} + +void resegment_test_5() +{ + + // SDUs: | 10 | 10 | 10 | 10 | 10 | + // PDUs: |2|3| 40 |3|2| + // Retx PDU segments: | 20 | 20 | + + srslte::log_stdout log1("RLC_AM_1"); + srslte::log_stdout log2("RLC_AM_2"); + log1.set_level(srslte::LOG_LEVEL_DEBUG); + log2.set_level(srslte::LOG_LEVEL_DEBUG); + log1.set_hex_limit(-1); + log2.set_hex_limit(-1); + rlc_am_tester tester; + mac_dummy_timers timers; + + rlc_am rlc1; + rlc_am rlc2; + + int len; + + log1.set_level(srslte::LOG_LEVEL_DEBUG); + log2.set_level(srslte::LOG_LEVEL_DEBUG); + + rlc1.init(&log1, 1, &tester, &tester, &timers); + rlc2.init(&log2, 1, &tester, &tester, &timers); + + LIBLTE_RRC_RLC_CONFIG_STRUCT cnfg; + cnfg.rlc_mode = LIBLTE_RRC_RLC_MODE_AM; + cnfg.dl_am_rlc.t_reordering = LIBLTE_RRC_T_REORDERING_MS5; + cnfg.dl_am_rlc.t_status_prohibit = LIBLTE_RRC_T_STATUS_PROHIBIT_MS5; + cnfg.ul_am_rlc.max_retx_thresh = LIBLTE_RRC_MAX_RETX_THRESHOLD_T4; + cnfg.ul_am_rlc.poll_byte = LIBLTE_RRC_POLL_BYTE_KB25; + cnfg.ul_am_rlc.poll_pdu = LIBLTE_RRC_POLL_PDU_P4; + + rlc1.configure(&cnfg); + rlc2.configure(&cnfg); + + // Push 5 SDUs into RLC1 + byte_buffer_t sdu_bufs[NBUFS]; + for(int i=0;iN_bytes == 10); + for(int j=0;j<10;j++) + assert(tester.sdus[i]->msg[j] == j); + } +} + +void resegment_test_6() +{ + // SDUs: |10|10|10| 54 | 54 | 54 | 54 | 54 | 54 | + // PDUs: |10|10|10| 270 | 54 | + // Retx PDU segments: | 120 | 150 | + + srslte::log_stdout log1("RLC_AM_1"); + srslte::log_stdout log2("RLC_AM_2"); + log1.set_level(srslte::LOG_LEVEL_DEBUG); + log2.set_level(srslte::LOG_LEVEL_DEBUG); + log1.set_hex_limit(-1); + log2.set_hex_limit(-1); + rlc_am_tester tester; + mac_dummy_timers timers; + + rlc_am rlc1; + rlc_am rlc2; + + int len; + + log1.set_level(srslte::LOG_LEVEL_DEBUG); + log2.set_level(srslte::LOG_LEVEL_DEBUG); + + rlc1.init(&log1, 1, &tester, &tester, &timers); + rlc2.init(&log2, 1, &tester, &tester, &timers); + + LIBLTE_RRC_RLC_CONFIG_STRUCT cnfg; + cnfg.rlc_mode = LIBLTE_RRC_RLC_MODE_AM; + cnfg.dl_am_rlc.t_reordering = LIBLTE_RRC_T_REORDERING_MS5; + cnfg.dl_am_rlc.t_status_prohibit = LIBLTE_RRC_T_STATUS_PROHIBIT_MS5; + cnfg.ul_am_rlc.max_retx_thresh = LIBLTE_RRC_MAX_RETX_THRESHOLD_T4; + cnfg.ul_am_rlc.poll_byte = LIBLTE_RRC_POLL_BYTE_KB25; + cnfg.ul_am_rlc.poll_pdu = LIBLTE_RRC_POLL_PDU_P4; + + rlc1.configure(&cnfg); + rlc2.configure(&cnfg); + + // Push SDUs into RLC1 + byte_buffer_t sdu_bufs[9]; + for(int i=0;i<3;i++) + { + for(int j=0;j<10;j++) + sdu_bufs[i].msg[j] = j; + sdu_bufs[i].N_bytes = 10; + rlc1.write_sdu(&sdu_bufs[i]); + } + for(int i=3;i<9;i++) + { + for(int j=0;j<54;j++) + sdu_bufs[i].msg[j] = j; + sdu_bufs[i].N_bytes = 54; + rlc1.write_sdu(&sdu_bufs[i]); + } + + assert(368 == rlc1.get_buffer_state()); + + // Read PDUs from RLC1 (10, 10, 10, 270, 54) + byte_buffer_t pdu_bufs[5]; + for(int i=0;i<3;i++) { + len = rlc1.read_pdu(pdu_bufs[i].msg, 12); + pdu_bufs[i].N_bytes = len; + } + len = rlc1.read_pdu(pdu_bufs[3].msg, 278); + pdu_bufs[3].N_bytes = len; + len = rlc1.read_pdu(pdu_bufs[4].msg, 56); + pdu_bufs[4].N_bytes = len; + + assert(0 == rlc1.get_buffer_state()); + + // Write PDUs into RLC2 (skip SN 3) + for(int i=0;i<5;i++) + { + if(i != 3) + rlc2.write_pdu(pdu_bufs[i].msg, pdu_bufs[i].N_bytes); + } + + // Sleep to let reordering timeout expire + usleep(10000); + + assert(4 == rlc2.get_buffer_state()); + + // Read status PDU from RLC2 + byte_buffer_t status_buf; + len = rlc2.read_pdu(status_buf.msg, 10); // 10 bytes is enough to hold the status + status_buf.N_bytes = len; + + // Write status PDU to RLC1 + rlc1.write_pdu(status_buf.msg, status_buf.N_bytes); + + assert(278 == rlc1.get_buffer_state()); + + // Read the retx PDU from RLC1 and force resegmentation + byte_buffer_t retx1; + len = rlc1.read_pdu(retx1.msg, 127); + retx1.N_bytes = len; + + // Write the retx PDU to RLC2 + rlc2.write_pdu(retx1.msg, retx1.N_bytes); + + assert(157 == rlc1.get_buffer_state()); + + // Read the remaining segment + byte_buffer_t retx2; + len = rlc1.read_pdu(retx2.msg, 157); + retx2.N_bytes = len; + + // Write the retx PDU to RLC2 + rlc2.write_pdu(retx2.msg, retx2.N_bytes); + + assert(tester.n_sdus == 9); + for(int i=0;i<3;i++) + { + assert(tester.sdus[i]->N_bytes == 10); + for(int j=0;j<10;j++) + assert(tester.sdus[i]->msg[j] == j); + } + for(int i=3;i<9;i++) + { + assert(tester.sdus[i]->N_bytes == 54); + for(int j=0;j<54;j++) + assert(tester.sdus[i]->msg[j] == j); + } +} + +int main(int argc, char **argv) { + basic_test(); + byte_buffer_pool::get_instance()->cleanup(); + concat_test(); + byte_buffer_pool::get_instance()->cleanup(); + segment_test(); + byte_buffer_pool::get_instance()->cleanup(); + retx_test(); + byte_buffer_pool::get_instance()->cleanup(); + resegment_test_1(); + byte_buffer_pool::get_instance()->cleanup(); + resegment_test_2(); + byte_buffer_pool::get_instance()->cleanup(); + resegment_test_3(); + byte_buffer_pool::get_instance()->cleanup(); + resegment_test_4(); + byte_buffer_pool::get_instance()->cleanup(); + resegment_test_5(); + byte_buffer_pool::get_instance()->cleanup(); + resegment_test_6(); +} diff --git a/lib/test/upper/rlc_um_data_test.cc b/lib/test/upper/rlc_um_data_test.cc new file mode 100644 index 000000000..bde751bdc --- /dev/null +++ b/lib/test/upper/rlc_um_data_test.cc @@ -0,0 +1,71 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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 +#include "srslte/upper/rlc_um.h" +#include + +// Fixed header only +uint8_t pdu1[] = {0x18 ,0xE2}; +uint32_t PDU1_LEN = 2; + +// Fixed + 1 LI field (value 104) +uint8_t pdu2[] = {0x1C ,0xE1 ,0x06 ,0x80}; +uint32_t PDU2_LEN = 4; + +using namespace srsue; + +int main(int argc, char **argv) { + srslte::rlc_umd_pdu_header_t h; + srslte::byte_buffer_t b1,b2; + + memcpy(b1.msg, &pdu1[0], PDU1_LEN); + b1.N_bytes = PDU1_LEN; + rlc_um_read_data_pdu_header(&b1, srslte::RLC_UMD_SN_SIZE_10_BITS, &h); + assert(0x03 == h.fi); + assert(0 == h.N_li); + assert(226 == h.sn); + rlc_um_write_data_pdu_header(&h, &b2); + assert(b2.N_bytes == PDU1_LEN); + for(uint32_t i=0;i +#include "srslte/common/log_stdout.h" +#include "srslte/upper/rlc_um.h" +#include + +#define NBUFS 5 + +using namespace srslte; +using namespace srsue; + +class mac_dummy_timers + :public srslte::mac_interface_timers +{ +public: + srslte::timers::timer* get(uint32_t timer_id) + { + return &t; + } + uint32_t get_unique_id(){return 0;} + void step() + { + t.step(); + } + +private: + srslte::timers::timer t; +}; + +class rlc_um_tester + :public pdcp_interface_rlc + ,public rrc_interface_rlc +{ +public: + rlc_um_tester(){n_sdus = 0;} + + // PDCP interface + void write_pdu(uint32_t lcid, byte_buffer_t *sdu) + { + assert(lcid == 3); + sdus[n_sdus++] = sdu; + } + void write_pdu_bcch_bch(byte_buffer_t *sdu) {} + void write_pdu_bcch_dlsch(byte_buffer_t *sdu) {} + void write_pdu_pcch(byte_buffer_t *sdu) {} + + // RRC interface + void max_retx_attempted(){} + + byte_buffer_t *sdus[5]; + int n_sdus; +}; + +void basic_test() +{ + srslte::log_stdout log1("RLC_UM_1"); + srslte::log_stdout log2("RLC_UM_2"); + log1.set_level(srslte::LOG_LEVEL_DEBUG); + log2.set_level(srslte::LOG_LEVEL_DEBUG); + log1.set_hex_limit(-1); + log2.set_hex_limit(-1); + rlc_um_tester tester; + mac_dummy_timers timers; + + rlc_um rlc1; + rlc_um rlc2; + + int len; + + log1.set_level(srslte::LOG_LEVEL_DEBUG); + log2.set_level(srslte::LOG_LEVEL_DEBUG); + + rlc1.init(&log1, 3, &tester, &tester, &timers); + rlc2.init(&log2, 3, &tester, &tester, &timers); + + LIBLTE_RRC_RLC_CONFIG_STRUCT cnfg; + cnfg.rlc_mode = LIBLTE_RRC_RLC_MODE_UM_BI; + cnfg.dl_um_bi_rlc.t_reordering = LIBLTE_RRC_T_REORDERING_MS5; + cnfg.dl_um_bi_rlc.sn_field_len = LIBLTE_RRC_SN_FIELD_LENGTH_SIZE10; + cnfg.ul_um_bi_rlc.sn_field_len = LIBLTE_RRC_SN_FIELD_LENGTH_SIZE10; + + rlc1.configure(&cnfg); + rlc2.configure(&cnfg); + + // Push 5 SDUs into RLC1 + byte_buffer_t sdu_bufs[NBUFS]; + for(int i=0;iN_bytes == 1); + assert(*(tester.sdus[i]->msg) == i); + } +} + +void loss_test() +{ + srslte::log_stdout log1("RLC_UM_1"); + srslte::log_stdout log2("RLC_UM_2"); + log1.set_level(srslte::LOG_LEVEL_DEBUG); + log2.set_level(srslte::LOG_LEVEL_DEBUG); + log1.set_hex_limit(-1); + log2.set_hex_limit(-1); + rlc_um_tester tester; + mac_dummy_timers timers; + + rlc_um rlc1; + rlc_um rlc2; + + int len; + + log1.set_level(srslte::LOG_LEVEL_DEBUG); + log2.set_level(srslte::LOG_LEVEL_DEBUG); + + rlc1.init(&log1, 3, &tester, &tester, &timers); + rlc2.init(&log2, 3, &tester, &tester, &timers); + + LIBLTE_RRC_RLC_CONFIG_STRUCT cnfg; + cnfg.rlc_mode = LIBLTE_RRC_RLC_MODE_UM_BI; + cnfg.dl_um_bi_rlc.t_reordering = LIBLTE_RRC_T_REORDERING_MS5; + cnfg.dl_um_bi_rlc.sn_field_len = LIBLTE_RRC_SN_FIELD_LENGTH_SIZE10; + cnfg.ul_um_bi_rlc.sn_field_len = LIBLTE_RRC_SN_FIELD_LENGTH_SIZE10; + + rlc1.configure(&cnfg); + rlc2.configure(&cnfg); + + // Push 5 SDUs into RLC1 + byte_buffer_t sdu_bufs[NBUFS]; + for(int i=0;iis_expired()) + timers.get(1)->step(); + + assert(NBUFS-1 == tester.n_sdus); +} + +int main(int argc, char **argv) { + basic_test(); + byte_buffer_pool::get_instance()->cleanup(); + loss_test(); + byte_buffer_pool::get_instance()->cleanup(); +} diff --git a/srsenb/CMakeLists.txt b/srsenb/CMakeLists.txt new file mode 100644 index 000000000..7fa60301a --- /dev/null +++ b/srsenb/CMakeLists.txt @@ -0,0 +1,50 @@ +# +# Copyright 2013-2017 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/. +# + +find_package(LibConfig REQUIRED) +find_package(SCTP REQUIRED) + +if(STATIC_LIBCONFIGPP) + set(LIBCONFIGPP_LIBRARIES "${LIBCONFIGPP_STATIC_LIBRARY_PATH}") +endif(STATIC_LIBCONFIGPP) + +if(NOT Boost_FOUND) + message(FATAL_ERROR "Boost required to compile srsENB") +endif() + +######################################################################## +# Setup the include and linker paths +######################################################################## +include_directories( + ${Boost_INCLUDE_DIRS} + ${SEC_INCLUDE_DIRS} + ${PROJECT_SOURCE_DIR}/srsenb/hdr +) + +link_directories( + ${Boost_LIBRARY_DIRS} + ${SEC_LIBRARY_DIRS} +) + +######################################################################## +# Add subdirectories +######################################################################## +add_subdirectory(src) +add_subdirectory(test) diff --git a/srsenb/drb.conf.example b/srsenb/drb.conf.example new file mode 100644 index 000000000..2d649bc53 --- /dev/null +++ b/srsenb/drb.conf.example @@ -0,0 +1,56 @@ + +// All times are in ms. Use -1 for infinity, where available + +qci_config = ( + +{ + qci=7; + pdcp_config = { + discard_timer = 100; + pdcp_sn_size = 12; + } + rlc_config = { + ul_um = { + sn_field_length = 10; + }; + dl_um = { + sn_field_length = 10; + t_reordering = 80; + }; + }; + logical_channel_config = { + priority = 11; + prioritized_bit_rate = -1; + bucket_size_duration = 100; + log_chan_group = 3; + }; +}, +{ + qci=9; + pdcp_config = { + discard_timer = -1; + status_report_required = false; + } + rlc_config = { + ul_am = { + t_poll_retx = 200; + poll_pdu = 16; + poll_byte = -1; + max_retx_thresh = 8; + }; + dl_am = { + t_reordering = 80; + t_status_prohibit = 35; + }; + }; + logical_channel_config = { + priority = 3; + prioritized_bit_rate = 8; + bucket_size_duration = 50; + log_chan_group = 3; + }; +} + +); + + diff --git a/srsenb/enb.conf.example b/srsenb/enb.conf.example new file mode 100644 index 000000000..1c361f390 --- /dev/null +++ b/srsenb/enb.conf.example @@ -0,0 +1,165 @@ +##################################################################### +# srsENB configuration file +##################################################################### + +##################################################################### +# eNB configuration +# +# enb_id: 20-bit eNB identifier. +# cell_id: 8-bit cell identifier. +# tac: 16-bit Tracking Area Code. +# mcc: Mobile Country Code +# mnc: Mobile Network Code +# mme_addr: IP address of MME for S1 connnection +# gtp_bind_addr: Local IP address to bind for GTP connection +# +##################################################################### +[enb] +enb_id = 0x19B +cell_id = 0x01 +phy_cell_id = 1 +tac = 0x0007 +mcc = 001 +mnc = 01 +mme_addr = 127.0.1.100 +gtp_bind_addr = 127.0.1.1 +n_prb = 25 + +##################################################################### +# eNB configuration files +# +# sib_config: SIB1, SIB2 and SIB3 configuration file +# rr_config: Radio Resources configuration file +# drb_config: DRB configuration file +##################################################################### +[enb_files] +sib_config = sib.conf +rr_config = rr.conf +drb_config = drb.conf + +##################################################################### +# RF configuration +# +# dl_earfcn: EARFCN code for DL +# tx_gain: Transmit gain (dB). +# rx_gain: Optional receive gain (dB). If disabled, AGC if enabled +# +# Optional parameters: +# device_name: Device driver family. Supported options: "auto" (uses first found), "UHD" or "bladeRF" +# device_args: Arguments for the device driver. Options are "auto" or any string. +# Default for UHD: "recv_frame_size=9232,send_frame_size=9232" +# Default for bladeRF: "" +# #time_adv_nsamples: Transmission time advance (in number of samples) to compensate for RF delay +# from antenna to timestamp insertion. +# Default "auto". B210 USRP: 100 samples, bladeRF: 27. +# burst_preamble_us: Preamble length to transmit before start of burst. +# Default "auto". B210 USRP: 400 us, bladeRF: 0 us. +##################################################################### +[rf] +dl_earfcn = 3400 +tx_gain = 70 +rx_gain = 50 + +#device_name = auto +#device_args = auto +#time_adv_nsamples = auto +#burst_preamble_us = auto + + +##################################################################### +# MAC-layer packet capture configuration +# +# Packets are captured to file in the compact format decoded by +# the Wireshark mac-lte-framed dissector and with DLT 147. +# To use the dissector, edit the preferences for DLT_USER to +# add an entry with DLT=147, Payload Protocol=mac-lte-framed. +# For more information see: https://wiki.wireshark.org/MAC-LTE +# +# enable: Enable MAC layer packet captures (true/false) +# filename: File path to use for packet captures +##################################################################### +[pcap] +enable = false +filename = /tmp/enb.pcap + +##################################################################### +# Log configuration +# +# Log levels can be set for individual layers. "all_level" sets log +# level for all layers unless otherwise configured. +# Format: e.g. phy_level = info +# +# In the same way, packet hex dumps can be limited for each level. +# "all_hex_limit" sets the hex limit for all layers unless otherwise +# configured. +# Format: e.g. phy_hex_limit = 32 +# +# Logging layers: phy, mac, rlc, pdcp, rrc, nas, gtpu, usim, all +# Logging levels: debug, info, warning, error, none +# +# filename: File path to use for log output +##################################################################### +[log] +all_level = info +all_hex_limit = 32 +filename = /tmp/enb.log + +[gui] +enable = false + +##################################################################### +# Scheduler configuration options +# +# pdsch_mcs: Optional fixed PDSCH MCS (ignores reported CQIs if specified) +# pdsch_max_mcs: Optional PDSCH MCS limit +# pusch_mcs: Optional fixed PUSCH MCS (ignores reported CQIs if specified) +# pusch_max_mcs: Optional PUSCH MCS limit +# #nof_ctrl_symbols: Number of control symbols +# +##################################################################### +[scheduler] +#pdsch_mcs = -1 +#pdsch_max_mcs = -1 +#pusch_mcs = -1 +pusch_max_mcs = 16 +nof_ctrl_symbols = 2 + +##################################################################### +# Expert configuration options +# +# pdsch_max_its: Maximum number of turbo decoder iterations (Default 4) +# nof_phy_threads: Selects the number of PHY threads (maximum 4, minimum 1, default 2) +# metrics_period_secs: Sets the period at which metrics are requested from the UE. +# pregenerate_signals: Pregenerate uplink signals after attach. Improves CPU performance. +# tx_amplitude: Transmit amplitude factor (set 0-1 to reduce PAPR) +# link_failure_nof_err: Number of PUSCH failures after which a radio-link failure is triggered. +# a link failure is when SNR<0 and CRC=KO +# max_prach_offset_us: Maximum allowed RACH offset (in us) +# +##################################################################### +[expert] +#pdsch_max_its = 4 +#nof_phy_threads = 2 +#pregenerate_signals = false +#tx_amplitude = 0.8 +#link_failure_nof_err = 50 +#rrc_inactivity_timer = 5000 +#max_prach_offset_us = 30 + +##################################################################### +# Manual RF calibration +# +# Applies DC offset and IQ imbalance to TX and RX modules. +# Currently this configuration is only used if the detected device is a bladeRF +# +# tx_corr_dc_gain: TX DC offset gain correction +# tx_corr_dc_phase: TX DC offset phase correction +# tx_corr_iq_i: TX IQ imbalance inphase correction +# tx_corr_iq_q: TX IQ imbalance quadrature correction +# same can be configured for rx_* +##################################################################### +[rf_calibration] +tx_corr_dc_gain = 20 +tx_corr_dc_phase = 184 +tx_corr_iq_i = 19 +tx_corr_iq_q = 97 diff --git a/srsenb/hdr/CMakeLists.txt b/srsenb/hdr/CMakeLists.txt new file mode 100644 index 000000000..83b16737b --- /dev/null +++ b/srsenb/hdr/CMakeLists.txt @@ -0,0 +1,5 @@ + +configure_file( + ${CMAKE_CURRENT_SOURCE_DIR}/version.h.in + ${PROJECT_BINARY_DIR}/version.h +) diff --git a/srsenb/hdr/cfg_parser.h b/srsenb/hdr/cfg_parser.h new file mode 100644 index 000000000..56b5e6e63 --- /dev/null +++ b/srsenb/hdr/cfg_parser.h @@ -0,0 +1,41 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2017 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of srsLTE. + * + * srsUE 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. + * + * srsUE 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 CFG_PARSER_H +#define CFG_PARSER_H + +#include "enb.h" + +namespace srsenb { +class cfg_parser +{ +public: + void parse_sibs(all_args_t *args, rrc_cfg_t *rrc_cfg, phy_cfg_t *phy_config_common); +}; + +} + +#endif // CFG_PARSER_H diff --git a/srsenb/hdr/enb.h b/srsenb/hdr/enb.h new file mode 100644 index 000000000..8db5c85b6 --- /dev/null +++ b/srsenb/hdr/enb.h @@ -0,0 +1,210 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2017 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of srsLTE. + * + * srsUE 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. + * + * srsUE 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: enb.h + * Description: Top-level eNodeB class. Creates and links all + * layers and helpers. + *****************************************************************************/ + +#ifndef ENB_H +#define ENB_H + +#include +#include +#include + +#include "phy/phy.h" +#include "mac/mac.h" +#include "upper/rrc.h" +#include "upper/gtpu.h" +#include "upper/s1ap.h" +#include "upper/rlc.h" +#include "upper/pdcp.h" + +#include "srslte/radio/radio.h" + +#include "srslte/common/bcd_helpers.h" +#include "srslte/common/buffer_pool.h" +#include "srslte/interfaces/ue_interfaces.h" +#include "srslte/common/logger.h" +#include "srslte/common/log_filter.h" +#include "srslte/common/mac_pcap.h" +#include "srslte/interfaces/sched_interface.h" +#include "srslte/interfaces/enb_metrics_interface.h" + +namespace srsenb { + +/******************************************************************************* + eNodeB Parameters +*******************************************************************************/ + +typedef struct { + s1ap_args_t s1ap; + uint32_t n_prb; + uint32_t pci; +}enb_args_t; + +typedef struct { + std::string sib_config; + std::string rr_config; + std::string drb_config; +} enb_files_t; + +typedef struct { + uint32_t dl_earfcn; + uint32_t ul_earfcn; + float dl_freq; + float ul_freq; + float rx_gain; + float tx_gain; + std::string device_name; + std::string device_args; + std::string time_adv_nsamples; + std::string burst_preamble; +}rf_args_t; + +typedef struct { + bool enable; + std::string filename; +}pcap_args_t; + +typedef struct { + std::string phy_level; + std::string mac_level; + std::string rlc_level; + std::string pdcp_level; + std::string rrc_level; + std::string gtpu_level; + std::string s1ap_level; + std::string all_level; + int phy_hex_limit; + int mac_hex_limit; + int rlc_hex_limit; + int pdcp_hex_limit; + int rrc_hex_limit; + int gtpu_hex_limit; + int s1ap_hex_limit; + int all_hex_limit; + std::string filename; +}log_args_t; + +typedef struct { + bool enable; +}gui_args_t; + +typedef struct { + phy_args_t phy; + mac_args_t mac; + uint32_t rrc_inactivity_timer; + float metrics_period_secs; +}expert_args_t; + +typedef struct { + enb_args_t enb; + enb_files_t enb_files; + rf_args_t rf; + rf_cal_t rf_cal; + pcap_args_t pcap; + log_args_t log; + gui_args_t gui; + expert_args_t expert; +}all_args_t; + +/******************************************************************************* + Main UE class +*******************************************************************************/ + +class enb + :public enb_metrics_interface +{ +public: + static enb* get_instance(void); + static void cleanup(void); + + bool init(all_args_t *args_); + void stop(); + void start_plot(); + + static void rf_msg(srslte_rf_error_t error); + void handle_rf_msg(srslte_rf_error_t error); + + // eNodeB metrics interface + bool get_metrics(enb_metrics_t &m); + + void pregenerate_signals(bool enable); + + +private: + static enb *instance; + enb(); + virtual ~enb(); + + srslte::radio radio; + srsenb::phy phy; + srsenb::mac mac; + srslte::mac_pcap mac_pcap; + srsenb::rlc rlc; + srsenb::pdcp pdcp; + srsenb::rrc rrc; + srsenb::gtpu gtpu; + srsenb::s1ap s1ap; + + srslte::logger logger; + srslte::log_filter rf_log; + std::vector phy_log; + srslte::log_filter mac_log; + srslte::log_filter rlc_log; + srslte::log_filter pdcp_log; + srslte::log_filter rrc_log; + srslte::log_filter gtpu_log; + srslte::log_filter s1ap_log; + + srslte::byte_buffer_pool *pool; + + all_args_t *args; + bool started; + rf_metrics_t rf_metrics; + + srslte::LOG_LEVEL_ENUM level(std::string l); + + bool check_srslte_version(); + int parse_sib1(std::string filename, LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1_STRUCT *data); + int parse_sib2(std::string filename, LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT *data); + int parse_sib3(std::string filename, LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_3_STRUCT *data); + int parse_sib4(std::string filename, LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_4_STRUCT *data); + int parse_sib9(std::string filename, LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_9_STRUCT *data); + int parse_sibs(all_args_t *args, rrc_cfg_t *rrc_cfg, phy_cfg_t *phy_config_common); + int parse_rr(all_args_t *args, rrc_cfg_t *rrc_cfg); + int parse_drb(all_args_t *args, rrc_cfg_t *rrc_cfg); + bool sib_is_present(LIBLTE_RRC_SCHEDULING_INFO_STRUCT *sched_info, uint32_t nof_sched_info, LIBLTE_RRC_SIB_TYPE_ENUM sib_num); + int parse_cell_cfg(all_args_t *args, srslte_cell_t *cell); +}; + +} // namespace srsenb + +#endif // UE_H + diff --git a/srsenb/hdr/mac/mac.h b/srsenb/hdr/mac/mac.h new file mode 100644 index 000000000..97be1825b --- /dev/null +++ b/srsenb/hdr/mac/mac.h @@ -0,0 +1,231 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2017 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of srsLTE. + * + * srsUE 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. + * + * srsUE 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 MAC_H +#define MAC_H + +#include +#include "srslte/common/log.h" +#include "srslte/common/timers.h" +#include "srslte/interfaces/enb_interfaces.h" +#include "srslte/interfaces/sched_interface.h" +#include "srslte/common/tti_sync_cv.h" +#include "srslte/common/threads.h" +#include "srslte/common/tti_sync_cv.h" +#include "srslte/common/mac_pcap.h" +#include "mac/scheduler.h" +#include "mac/scheduler_metric.h" +#include "srslte/interfaces/enb_metrics_interface.h" +#include "mac/ue.h" + +namespace srsenb { + +class pdu_process_handler +{ +public: + virtual bool process_pdus() = 0; +}; + +typedef struct { + sched_interface::sched_args_t sched; + int link_failure_nof_err; +} mac_args_t; + +class mac + :public mac_interface_phy, + public mac_interface_rlc, + public mac_interface_rrc, + public srslte::mac_interface_timers, + public pdu_process_handler +{ +public: + mac(); + bool init(mac_args_t *args, srslte_cell_t *cell, phy_interface_mac *phy, rlc_interface_mac *rlc, rrc_interface_mac *rrc, srslte::log *log_h); + void stop(); + + void start_pcap(srslte::mac_pcap* pcap_); + + /******** Interface from PHY (PHY -> MAC) ****************/ + int sr_detected(uint32_t tti, uint16_t rnti); + int rach_detected(uint32_t tti, uint32_t preamble_idx, uint32_t time_adv); + + int cqi_info(uint32_t tti, uint16_t rnti, uint32_t cqi_value); + int snr_info(uint32_t tti, uint16_t rnti, float snr); + int ack_info(uint32_t tti, uint16_t rnti, bool ack); + int crc_info(uint32_t tti, uint16_t rnti, uint32_t nof_bytes, bool crc_res); + + int get_dl_sched(uint32_t tti, dl_sched_t *dl_sched_res); + int get_ul_sched(uint32_t tti, ul_sched_t *ul_sched_res); + + void rl_failure(uint16_t rnti); + void rl_ok(uint16_t rnti); + void tti_clock(); + + /******** Interface from RRC (RRC -> MAC) ****************/ + /* Provides cell configuration including SIB periodicity, etc. */ + int cell_cfg(sched_interface::cell_cfg_t *cell_cfg); + void reset(); + + /* Manages UE scheduling context */ + int ue_cfg(uint16_t rnti, sched_interface::ue_cfg_t *cfg); + int ue_rem(uint16_t rnti); + + // Indicates that the PHY config dedicated has been enabled or not + void phy_config_enabled(uint16_t rnti, bool enabled); + + /* Manages UE bearers and associated configuration */ + int bearer_ue_cfg(uint16_t rnti, uint32_t lc_id, sched_interface::ue_bearer_cfg_t *cfg); + int bearer_ue_rem(uint16_t rnti, uint32_t lc_id); + int rlc_buffer_state(uint16_t rnti, uint32_t lc_id, uint32_t tx_queue, uint32_t retx_queue); + + bool process_pdus(); + + void timer_expired(uint32_t timer_id); + + srslte::timers::timer* get(uint32_t timer_id); + u_int32_t get_unique_id(); + + uint32_t get_current_tti(); + void get_metrics(mac_metrics_t metrics[ENB_METRICS_MAX_USERS]); + + enum { + HARQ_RTT, + TIME_ALIGNMENT, + CONTENTION_TIMER, + BSR_TIMER_PERIODIC, + BSR_TIMER_RETX, + PHR_TIMER_PERIODIC, + PHR_TIMER_PROHIBIT, + NOF_MAC_TIMERS + } mac_timers_t; + + static const int MAC_NOF_UPPER_TIMERS = 20; + +private: + + void log_step_ul(uint32_t tti); + void log_step_dl(uint32_t tti); + + static const int MAX_LOCATIONS = 20; + static const uint32_t cfi = 3; + srslte_dci_location_t locations[MAX_LOCATIONS]; + + static const int MAC_PDU_THREAD_PRIO = 3; + + + + // Interaction with PHY + phy_interface_mac *phy_h; + rlc_interface_mac *rlc_h; + rrc_interface_mac *rrc_h; + srslte::log *log_h; + + srslte_cell_t cell; + mac_args_t args; + + uint32_t tti; + bool started; + + /* Scheduler unit */ + sched scheduler; + dl_metric_rr sched_metric_dl_rr; + ul_metric_rr sched_metric_ul_rr; + + /* Map of active UEs */ + std::map ue_db; + uint16_t last_rnti; + + uint8_t* assemble_rar(sched_interface::dl_sched_rar_grant_t *grants, uint32_t nof_grants, int rar_idx, uint32_t pdu_len); + uint8_t* assemble_si(uint32_t index); + + const static int rar_payload_len = 128; + std::vector rar_pdu_msg; + uint8_t rar_payload[sched_interface::MAX_RAR_LIST][rar_payload_len]; + + typedef struct { + uint32_t preamble_idx; + uint32_t ta_cmd; + uint16_t temp_crnti; + } pending_rar_t; + + const static int MAX_PENDING_RARS = 64; + pending_rar_t pending_rars[MAX_PENDING_RARS]; + + const static int NOF_BCCH_DLSCH_MSG=sched_interface::MAX_SIBS; + uint8_t bcch_dlsch_payload[sched_interface::MAX_SIB_PAYLOAD_LEN]; + + const static int pcch_payload_buffer_len = 1024; + uint8_t pcch_payload_buffer[pcch_payload_buffer_len]; + srslte_softbuffer_tx_t bcch_softbuffer_tx[NOF_BCCH_DLSCH_MSG]; + srslte_softbuffer_tx_t pcch_softbuffer_tx; + srslte_softbuffer_tx_t rar_softbuffer_tx; + + /* Functions for MAC Timers */ + srslte::timers timers_db; + void setup_timers(); + + // pointer to MAC PCAP object + srslte::mac_pcap* pcap; + + + /* Class to run upper-layer timers with normal priority */ + class upper_timers : public thread { + public: + upper_timers() : timers_db(MAC_NOF_UPPER_TIMERS),ttisync(10240) {start();} + void tti_clock(); + void stop(); + void reset(); + srslte::timers::timer* get(uint32_t timer_id); + uint32_t get_unique_id(); + private: + void run_thread(); + srslte::timers timers_db; + srslte::tti_sync_cv ttisync; + bool running; + }; + upper_timers upper_timers_thread; + + /* Class to process MAC PDUs from DEMUX unit */ + class pdu_process : public thread { + public: + pdu_process(pdu_process_handler *h); + void notify(); + void stop(); + private: + void run_thread(); + bool running; + bool have_data; + pthread_mutex_t mutex; + pthread_cond_t cvar; + pdu_process_handler *handler; + }; + pdu_process pdu_process_thread; + +}; + +} // namespace srsue + +#endif // MAC_H diff --git a/srsenb/hdr/mac/mac_metrics.h b/srsenb/hdr/mac/mac_metrics.h new file mode 100644 index 000000000..4e3452ae1 --- /dev/null +++ b/srsenb/hdr/mac/mac_metrics.h @@ -0,0 +1,51 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2017 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of srsLTE. + * + * srsUE 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. + * + * srsUE 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 ENB_MAC_METRICS_H +#define ENB_MAC_METRICS_H + + +namespace srsenb { + +// MAC metrics per user + +struct mac_metrics_t +{ + uint16_t rnti; + int tx_pkts; + int tx_errors; + int tx_brate; + int rx_pkts; + int rx_errors; + int rx_brate; + int ul_buffer; + int dl_buffer; + float phr; +}; + +} // namespace srsenb + +#endif // ENB_MAC_METRICS_H diff --git a/srsenb/hdr/mac/scheduler.h b/srsenb/hdr/mac/scheduler.h new file mode 100644 index 000000000..74ca8cc95 --- /dev/null +++ b/srsenb/hdr/mac/scheduler.h @@ -0,0 +1,227 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2017 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of srsLTE. + * + * srsUE 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. + * + * srsUE 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 SCHED_H +#define SCHED_H + +#include +#include "srslte/common/log.h" +#include "srslte/interfaces/enb_interfaces.h" +#include "srslte/interfaces/sched_interface.h" +#include "scheduler_ue.h" +#include "scheduler_harq.h" +#include + +namespace srsenb { + + +class sched : public sched_interface +{ + + +public: + + + /************************************************************* + * + * Scheduling metric interface definition + * + ************************************************************/ + + class metric_dl + { + public: + + /* Virtual methods for user metric calculation */ + virtual void new_tti(std::map &ue_db, uint32_t start_rb, uint32_t nof_rb, uint32_t nof_ctrl_symbols, uint32_t tti) = 0; + virtual dl_harq_proc* get_user_allocation(sched_ue *user) = 0; + }; + + + class metric_ul + { + public: + + /* Virtual methods for user metric calculation */ + virtual void new_tti(std::map &ue_db, uint32_t nof_rb, uint32_t tti) = 0; + virtual ul_harq_proc* get_user_allocation(sched_ue *user) = 0; + virtual void update_allocation(ul_harq_proc::ul_alloc_t alloc) = 0; + }; + + + + /************************************************************* + * + * FAPI-like Interface + * + ************************************************************/ + + sched(); + + void init(rrc_interface_mac *rrc, srslte::log *log); + void set_metric(metric_dl *dl_metric, metric_ul *ul_metric); + int cell_cfg(cell_cfg_t *cell_cfg); + void set_sched_cfg(sched_args_t *sched_cfg); + int reset(); + + int ue_cfg(uint16_t rnti, ue_cfg_t *ue_cfg); + int ue_rem(uint16_t rnti); + bool ue_exists(uint16_t rnti); + + void phy_config_enabled(uint16_t rnti, bool enabled); + + int bearer_ue_cfg(uint16_t rnti, uint32_t lc_id, ue_bearer_cfg_t *cfg); + int bearer_ue_rem(uint16_t rnti, uint32_t lc_id); + + uint32_t get_ul_buffer(uint16_t rnti); + uint32_t get_dl_buffer(uint16_t rnti); + + int dl_rlc_buffer_state(uint16_t rnti, uint32_t lc_id, uint32_t tx_queue, uint32_t retx_queue); + int dl_mac_buffer_state(uint16_t rnti, uint32_t ce_code); + + int dl_ack_info(uint32_t tti, uint16_t rnti, bool ack); + int dl_rach_info(uint32_t tti, uint32_t ra_id, uint16_t rnti, uint32_t estimated_size); + int dl_cqi_info(uint32_t tti, uint16_t rnti, uint32_t cqi_value); + + int ul_crc_info(uint32_t tti, uint16_t rnti, bool crc); + int ul_sr_info(uint32_t tti, uint16_t rnti); + int ul_bsr(uint16_t rnti, uint32_t lcid, uint32_t bsr); + int ul_recv_len(uint16_t rnti, uint32_t lcid, uint32_t len); + int ul_phr(uint16_t rnti, int phr); + int ul_cqi_info(uint32_t tti, uint16_t rnti, uint32_t cqi, uint32_t ul_ch_code); + + int dl_sched(uint32_t tti, dl_sched_res_t *sched_result); + int ul_sched(uint32_t tti, ul_sched_res_t *sched_result); + + + /* Custom TPC functions + */ + void tpc_inc(uint16_t rnti); + void tpc_dec(uint16_t rnti); + + + + static uint32_t get_rvidx(uint32_t retx_idx) { + const static int rv_idx[4] = {0, 2, 3, 1}; + return rv_idx[retx_idx%4]; + } + + + + static void generate_cce_location(srslte_regs_t *regs, sched_ue::sched_dci_cce_t *location, + uint32_t cfi, uint32_t sf_idx = 0, uint16_t rnti = 0); + +private: + + metric_dl *dl_metric; + metric_ul *ul_metric; + srslte::log *log_h; + rrc_interface_mac *rrc; + + cell_cfg_t cfg; + sched_args_t sched_cfg; + + const static int MAX_PRB = 100; + const static int MAX_RBG = 25; + const static int MAX_CCE = 128; + + // This is for computing DCI locations + srslte_regs_t regs; + bool used_cce[MAX_CCE]; + + typedef struct { + int buf_rar; + uint16_t rnti; + uint32_t ra_id; + uint32_t rar_tti; + } sched_rar_t; + + typedef struct { + bool is_in_window; + uint32_t window_start; + uint32_t n_tx; + } sched_sib_t; + + + int dl_sched_bc(dl_sched_bc_t bc[MAX_BC_LIST]); + int dl_sched_rar(dl_sched_rar_t rar[MAX_RAR_LIST]); + int dl_sched_data(dl_sched_data_t data[MAX_DATA_LIST]); + + + int generate_format1a(uint32_t rb_start, uint32_t l_crb, uint32_t tbs, uint32_t rv, srslte_ra_dl_dci_t *dci); + bool generate_dci(srslte_dci_location_t *sched_location, sched_ue::sched_dci_cce_t *locations, uint32_t aggr_level, sched_ue *user = NULL); + + + std::map ue_db; + + sched_sib_t pending_sibs[MAX_SIBS]; + + + typedef struct { + bool enabled; + uint16_t rnti; + uint32_t L; + uint32_t n_prb; + uint32_t mcs; + } pending_msg3_t; + + const static int SCHED_MAX_PENDING_RAR = 8; + sched_rar_t pending_rar[SCHED_MAX_PENDING_RAR]; + pending_msg3_t pending_msg3[10]; + + // Allowed DCI locations for SIB and RAR per CFI + sched_ue::sched_dci_cce_t common_locations[3]; + sched_ue::sched_dci_cce_t rar_locations[3][10]; + + uint32_t bc_aggr_level; + uint32_t rar_aggr_level; + + uint32_t pdsch_re[10]; + uint32_t avail_rbg; + uint32_t P; + uint32_t start_rbg; + uint32_t si_n_rbg; + uint32_t rar_n_rb; + uint32_t nof_rbg; + uint32_t sf_idx; + uint32_t sfn; + uint32_t current_tti; + uint32_t current_cfi; + + bool configured; + + pthread_mutex_t mutex; + + +}; + + + + + +} + +#endif diff --git a/srsenb/hdr/mac/scheduler_harq.h b/srsenb/hdr/mac/scheduler_harq.h new file mode 100644 index 000000000..9a38306ae --- /dev/null +++ b/srsenb/hdr/mac/scheduler_harq.h @@ -0,0 +1,127 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2017 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of srsLTE. + * + * srsUE 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. + * + * srsUE 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 SCHED_HARQ_H +#define SCHED_HARQ_H + +#include +#include "srslte/common/log.h" +#include "srslte/interfaces/sched_interface.h" + +namespace srsenb { + +class harq_proc +{ +public: + void config(uint32_t id, uint32_t max_retx, srslte::log* log_h); + void set_max_retx(uint32_t max_retx); + void reset(); + uint32_t get_id(); + bool is_empty(); + + void new_retx(uint32_t tti, int *mcs, int *tbs); + + bool get_ack(); + void set_ack(bool ack); + + uint32_t nof_tx(); + uint32_t nof_retx(); + uint32_t get_tti(); + bool get_ndi(); + +protected: + + void new_tx_common(uint32_t tti, int mcs, int tbs); + bool has_pending_retx_common(); + + bool ack; + bool active; + bool ndi; + uint32_t id; + uint32_t max_retx; + uint32_t n_rtx; + uint32_t tx_cnt; + int tti; + int last_mcs; + int last_tbs; + + srslte::log* log_h; + + private: + bool ack_received; +}; + +class dl_harq_proc : public harq_proc +{ +public: + void new_tx(uint32_t tti, int mcs, int tbs, uint32_t n_cce); + uint32_t get_rbgmask(); + void set_rbgmask(uint32_t new_mask); + bool has_pending_retx(uint32_t tti); + int get_tbs(); + uint32_t get_n_cce(); +private: + uint32_t rbgmask; + uint32_t nof_rbg; + uint32_t n_cce; +}; + +class ul_harq_proc : public harq_proc +{ +public: + + typedef struct { + uint32_t RB_start; + uint32_t L; + } ul_alloc_t; + + void new_tx(uint32_t tti, int mcs, int tbs); + + ul_alloc_t get_alloc(); + void set_alloc(ul_alloc_t alloc); + void same_alloc(); + bool is_adaptive_retx(); + + bool has_pending_ack(); + uint32_t get_pending_data(); + + void set_rar_mcs(uint32_t mcs); + bool get_rar_mcs(int* mcs); + +private: + ul_alloc_t allocation; + bool need_ack; + int pending_data; + uint32_t rar_mcs; + bool has_rar_mcs; + bool is_adaptive; + bool is_msg3; +}; + +} + + +#endif diff --git a/srsenb/hdr/mac/scheduler_metric.h b/srsenb/hdr/mac/scheduler_metric.h new file mode 100644 index 000000000..b9d515ade --- /dev/null +++ b/srsenb/hdr/mac/scheduler_metric.h @@ -0,0 +1,88 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2017 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of srsLTE. + * + * srsUE 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. + * + * srsUE 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 SCHED_METRIC_H +#define SCHED_METRIC_H + +#include "mac/scheduler.h" + +namespace srsenb { + +class dl_metric_rr : public sched::metric_dl +{ +public: + void new_tti(std::map &ue_db, uint32_t start_rb, uint32_t nof_rb, uint32_t nof_ctrl_symbols, uint32_t tti); + dl_harq_proc* get_user_allocation(sched_ue *user); +private: + + const static int MAX_RBG = 25; + + bool new_allocation(uint32_t nof_rbg, uint32_t* rbgmask); + void update_allocation(uint32_t new_mask); + bool allocation_is_valid(uint32_t mask); + + + uint32_t get_required_rbg(sched_ue *user, uint32_t tti); + uint32_t count_rbg(uint32_t mask); + uint32_t calc_rbg_mask(bool mask[25]); + + bool used_rb[MAX_RBG]; + + uint32_t nof_users_with_data; + + uint32_t current_tti; + uint32_t total_rb; + uint32_t used_rb_mask; + uint32_t nof_ctrl_symbols; + uint32_t available_rb; +}; + +class ul_metric_rr : public sched::metric_ul +{ +public: + void new_tti(std::map &ue_db, uint32_t nof_rb, uint32_t tti); + ul_harq_proc* get_user_allocation(sched_ue *user); + void update_allocation(ul_harq_proc::ul_alloc_t alloc); +private: + + const static int MAX_PRB = 100; + + bool new_allocation(uint32_t L, ul_harq_proc::ul_alloc_t *alloc); + bool allocation_is_valid(ul_harq_proc::ul_alloc_t alloc); + + uint32_t nof_users_with_data; + + bool used_rb[MAX_PRB]; + uint32_t current_tti; + uint32_t nof_rb; + uint32_t available_rb; +}; + + +} + +#endif + diff --git a/srsenb/hdr/mac/scheduler_ue.h b/srsenb/hdr/mac/scheduler_ue.h new file mode 100644 index 000000000..fa38b2396 --- /dev/null +++ b/srsenb/hdr/mac/scheduler_ue.h @@ -0,0 +1,181 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2017 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of srsLTE. + * + * srsUE 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. + * + * srsUE 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 SCHED_UE_H +#define SCHED_UE_H + +#include +#include "srslte/common/log.h" +#include "srslte/interfaces/sched_interface.h" + +#include "scheduler_harq.h" + +namespace srsenb { + +class sched_ue { + +public: + + // used by sched_metric + uint32_t ue_idx; + + typedef struct { + uint32_t cce_start[4][6]; + uint32_t nof_loc[4]; + } sched_dci_cce_t; + + /************************************************************* + * + * FAPI-like Interface + * + ************************************************************/ + sched_ue(); + void reset(); + void phy_config_enabled(uint32_t tti, bool enabled); + void set_cfg(uint16_t rnti, sched_interface::ue_cfg_t* cfg, sched_interface::cell_cfg_t *cell_cfg, + srslte_regs_t *regs, srslte::log *log_h); + + void set_bearer_cfg(uint32_t lc_id, srsenb::sched_interface::ue_bearer_cfg_t* cfg); + void rem_bearer(uint32_t lc_id); + + void dl_buffer_state(uint8_t lc_id, uint32_t tx_queue, uint32_t retx_queue); + void ul_buffer_state(uint8_t lc_id, uint32_t bsr); + void ul_phr(int phr); + void mac_buffer_state(uint32_t ce_code); + void ul_recv_len(uint32_t lcid, uint32_t len); + void set_ul_cqi(uint32_t tti, uint32_t cqi, uint32_t ul_ch_code); + void set_dl_cqi(uint32_t tti, uint32_t cqi); + int set_ack_info(uint32_t tti, bool ack); + void set_ul_crc(uint32_t tti, bool crc_res); + +/******************************************************* + * Custom functions + *******************************************************/ + + void tpc_inc(); + void tpc_dec(); + + void set_max_mcs(int mcs_ul, int mcs_dl); + void set_fixed_mcs(int mcs_ul, int mcs_dl); + + + +/******************************************************* + * Functions used by scheduler metric objects + *******************************************************/ + + uint32_t get_required_prb_dl(uint32_t req_bytes, uint32_t nof_ctrl_symbols); + uint32_t get_required_prb_ul(uint32_t req_bytes); + + uint32_t get_pending_dl_new_data(uint32_t tti); + uint32_t get_pending_ul_new_data(uint32_t tti); + + dl_harq_proc *get_pending_dl_harq(uint32_t tti); + dl_harq_proc *get_empty_dl_harq(); + ul_harq_proc *get_ul_harq(uint32_t tti); + +/******************************************************* + * Functions used by the scheduler object + *******************************************************/ + + void set_sr(); + void unset_sr(); + + int generate_format1(dl_harq_proc *h, sched_interface::dl_sched_data_t *data, uint32_t tti, uint32_t cfi); + int generate_format0(ul_harq_proc *h, sched_interface::ul_sched_data_t *data, uint32_t tti, bool cqi_request); + + uint32_t get_aggr_level(uint32_t nof_bits); + sched_dci_cce_t *get_locations(uint32_t current_cfi, uint32_t sf_idx); + + bool needs_cqi(uint32_t tti, bool will_send = false); + uint32_t get_max_retx(); + + bool get_pucch_sched(uint32_t current_tti, uint32_t prb_idx[2], uint32_t *L); + bool pucch_sr_collision(uint32_t current_tti, uint32_t n_cce); + +private: + + typedef struct { + sched_interface::ue_bearer_cfg_t cfg; + int buf_tx; + int buf_retx; + int bsr; + } ue_bearer_t; + + bool is_sr_triggered(); + uint32_t get_pending_ul_old_data(); + int alloc_pdu(int tbs, sched_interface::dl_sched_pdu_t* pdu); + + static uint32_t format1_count_prb(uint32_t bitmask, uint32_t cell_nof_prb); + static int cqi_to_tbs(uint32_t cqi, uint32_t nof_prb, uint32_t nof_re, uint32_t max_mcs, uint32_t *mcs); + static int alloc_tbs(uint32_t cqi, uint32_t nof_prb, uint32_t nof_re, uint32_t req_bytes, uint32_t max_mcs, int *mcs); + + static bool bearer_is_ul(ue_bearer_t *lch); + static bool bearer_is_dl(ue_bearer_t *lch); + + bool is_first_dl_tx(); + + + sched_interface::ue_cfg_t cfg; + srslte_cell_t cell; + srslte::log* log_h; + + /* Buffer states */ + bool sr; + int buf_mac; + int buf_ul; + ue_bearer_t lch[sched_interface::MAX_LC]; + + int power_headroom; + uint32_t dl_cqi; + uint32_t dl_cqi_tti; + uint32_t cqi_request_tti; + uint32_t ul_cqi; + uint32_t ul_cqi_tti; + uint16_t rnti; + uint32_t max_mcs_dl; + uint32_t max_mcs_ul; + int fixed_mcs_ul; + int fixed_mcs_dl; + + int next_tpc_pusch; + int next_tpc_pucch; + + // Allowed DCI locations per CFI and per subframe + sched_dci_cce_t dci_locations[3][10]; + + const static int SCHED_MAX_HARQ_PROC = 8; + dl_harq_proc dl_harq[SCHED_MAX_HARQ_PROC]; + ul_harq_proc ul_harq[SCHED_MAX_HARQ_PROC]; + + bool phy_config_dedicated_enabled; + +}; + +} + + +#endif diff --git a/srsenb/hdr/mac/ue.h b/srsenb/hdr/mac/ue.h new file mode 100644 index 000000000..bb3597a04 --- /dev/null +++ b/srsenb/hdr/mac/ue.h @@ -0,0 +1,142 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2017 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of srsLTE. + * + * srsUE 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. + * + * srsUE 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 UE_H +#define UE_H + +#include "srslte/common/log.h" +#include "srslte/common/pdu.h" +#include "srslte/common/mac_pcap.h" +#include "srslte/common/pdu_queue.h" +#include "srslte/interfaces/enb_interfaces.h" +#include "srslte/interfaces/sched_interface.h" +#include +#include "mac/mac_metrics.h" + +namespace srsenb { + +class ue : public srslte::read_pdu_interface, + public srslte::pdu_queue::process_callback +{ +public: + + ue() : mac_msg_dl(20), mac_msg_ul(20), pdus(128) { + rlc = NULL; + log_h = NULL; + rnti = 0; + pcap = NULL; + nof_failures = 0; + phr_counter = 0; + is_phy_added = false; + for (int i=0;i +#include +#include + +#include "srslte/interfaces/enb_metrics_interface.h" + +namespace srsenb { + +class metrics_stdout +{ +public: + metrics_stdout(); + + bool init(enb_metrics_interface *u, float report_period_secs=1.0); + void stop(); + void toggle_print(bool b); + static void* metrics_thread_start(void *m); + void metrics_thread_run(); + +private: + void print_metrics(); + void print_disconnect(); + std::string float_to_string(float f, int digits); + std::string float_to_eng_string(float f, int digits); + std::string int_to_eng_string(int f, int digits); + + enb_metrics_interface *enb_; + + bool started; + bool do_print; + pthread_t metrics_thread; + enb_metrics_t metrics; + float metrics_report_period; // seconds + uint8_t n_reports; +}; + +} // namespace srsenb + +#endif // METRICS_STDOUT_H diff --git a/srsenb/hdr/parser.h b/srsenb/hdr/parser.h new file mode 100644 index 000000000..492249e18 --- /dev/null +++ b/srsenb/hdr/parser.h @@ -0,0 +1,310 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2017 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of srsLTE. + * + * srsUE 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. + * + * srsUE 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 PARSER_H +#define PARSER_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +namespace srsenb { + +using namespace libconfig; + +class parser +{ +public: + + class field_itf + { + public: + virtual ~field_itf(){} + virtual int parse(Setting &root) = 0; + virtual const char* get_name() = 0; + }; + + template + class field_enum_str : public field_itf + { + public: + field_enum_str(const char* name_, T *store_ptr_, const char (*value_str_)[20], uint32_t nof_items_, bool *enabled_value_ = NULL) + { + name = name_; + store_ptr = store_ptr_; + value_str = value_str_; + nof_items = nof_items_; + enabled_value = enabled_value_; + } + + const char* get_name() { + return name; + } + + int parse(Setting &root) + { + std::string val; + if (root.exists(name)) { + + if (enabled_value) { + *enabled_value = true; + } + + if (root.lookupValue(name, val)) { + bool found = false; + // find value + for (uint32_t i=0;i + class field_enum_num : public field_itf + { + public: + field_enum_num(const char* name_, T *store_ptr_, const S *value_str_, uint32_t nof_items_, bool *enabled_value_ = NULL) + { + name = name_; + store_ptr = store_ptr_; + value_str = value_str_; + nof_items = nof_items_; + enabled_value = enabled_value_; + } + + const char* get_name() { + return name; + } + + int parse(Setting &root) + { + S val; + if (root.exists(name)) { + + if (enabled_value) { + *enabled_value = true; + } + if (parser::lookupValue(root, name, &val)) { + bool found = false; + // find value + for (uint32_t i=0;i + class field : public field_itf + { + public: + field(const char* name_, T *store_ptr_, bool *enabled_value_ = NULL) + { + name = name_; + store_ptr = store_ptr_; + enabled_value = enabled_value_; + } + + const char* get_name() { + return name; + } + + int parse(Setting &root) + { + if (root.exists(name)) { + if (enabled_value) { + *enabled_value = true; + } + if (!parser::lookupValue(root, name, store_ptr)) { + return -1; + } else { + return 0; + } + } else { + if (enabled_value) { + *enabled_value = false; + return 0; + } else { + return -1; + } + } + } + private: + const char* name; + T *store_ptr; + bool *enabled_value; + }; + + class section + { + public: + section(std::string name); + ~section(); + void set_optional(bool *enabled_value); + void add_subsection(section *s); + void add_field(field_itf *f); + int parse(Setting &root); + private: + std::string name; + bool *enabled_value; + std::list sub_sections; + std::list fields; + }; + + + parser(std::string filename); + int parse(); + void add_section(section *s); + + static int parse_section(std::string filename, section *s); + + static bool lookupValue(Setting &root, const char *name, std::string *val) { + return root.lookupValue(name, *val); + } + static bool lookupValue(Setting &root, const char *name, uint8_t *val) { + uint32_t t; + bool r = root.lookupValue(name, t); + *val = (uint8_t) t; + return r; + } + static bool lookupValue(Setting &root, const char *name, uint16_t *val) { + uint32_t t; + bool r = root.lookupValue(name, t); + *val = (uint16_t) t; + return r; + } + static bool lookupValue(Setting &root, const char *name, uint32_t *val) { + uint32_t t; + bool r = root.lookupValue(name, t); + *val = t; + return r; + } + static bool lookupValue(Setting &root, const char *name, int8_t *val) { + int32_t t; + bool r = root.lookupValue(name, t); + *val = (int8_t) t; + return r; + } + static bool lookupValue(Setting &root, const char *name, int16_t *val) { + int32_t t; + bool r = root.lookupValue(name, t); + *val = (int16_t) t; + return r; + } + static bool lookupValue(Setting &root, const char *name, int32_t *val) { + int32_t t; + bool r = root.lookupValue(name, t); + *val = t; + return r; + } + static bool lookupValue(Setting &root, const char *name, double *val) { + double t; + bool r = root.lookupValue(name, t); + *val = t; + return r; + } + static bool lookupValue(Setting &root, const char *name, bool *val) { + bool t; + bool r = root.lookupValue(name, t); + *val = t; + return r; + } + + +private: + std::list sections; + std::string filename; +}; +} +#endif // PARSER_H diff --git a/srsenb/hdr/phy/phch_common.h b/srsenb/hdr/phy/phch_common.h new file mode 100644 index 000000000..ae396ae0e --- /dev/null +++ b/srsenb/hdr/phy/phch_common.h @@ -0,0 +1,109 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2017 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of srsLTE. + * + * srsUE 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. + * + * srsUE 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 ENBPHCHCOMMON_H +#define ENBPHCHCOMMON_H + +#include +#include "srslte/interfaces/enb_interfaces.h" +#include "srslte/interfaces/enb_metrics_interface.h" + +#include "srslte/common/log.h" +#include "srslte/common/threads.h" +#include "srslte/common/thread_pool.h" +#include "srslte/radio/radio.h" + +namespace srsenb { + +typedef struct { + float max_prach_offset_us; + int pusch_max_its; + float tx_amplitude; + int nof_phy_threads; + std::string equalizer_mode; + float estimator_fil_w; + bool pregenerate_signals; +} phy_args_t; + +class phch_common +{ +public: + + + phch_common(uint32_t max_mutex_) : tx_mutex(max_mutex_) { + max_mutex = max_mutex_; + params.max_prach_offset_us = 20; + } + + bool init(srslte_cell_t *cell, srslte::radio *radio_handler, mac_interface_phy *mac); + void reset(); + void stop(); + + void set_nof_mutex(uint32_t nof_mutex); + + void worker_end(uint32_t tx_mutex_cnt, cf_t *buffer, uint32_t nof_samples, srslte_timestamp_t tx_time); + + // Common objects + srslte_cell_t cell; + srslte_refsignal_dmrs_pusch_cfg_t pusch_cfg; + srslte_pusch_hopping_cfg_t hopping_cfg; + srslte_pucch_cfg_t pucch_cfg; + phy_args_t params; + + srslte::radio *radio; + mac_interface_phy *mac; + + // Common objects for schedulign grants + mac_interface_phy::ul_sched_t ul_grants[10]; + mac_interface_phy::dl_sched_t dl_grants[10]; + + // Map of pending ACKs for each user + typedef struct { + bool is_pending[10]; + uint16_t n_pdcch[10]; + } pending_ack_t; + std::map pending_ack; + + void ack_add_rnti(uint16_t rnti); + void ack_rem_rnti(uint16_t rnti); + void ack_clear(uint32_t sf_idx); + void ack_set_pending(uint32_t sf_idx, uint16_t rnti, uint32_t n_pdcch); + bool ack_is_pending(uint32_t sf_idx, uint16_t rnti, uint32_t *last_n_pdcch = NULL); + +private: + std::vector tx_mutex; + bool is_first_tx; + bool is_first_of_burst; + + uint32_t nof_workers; + uint32_t nof_mutex; + uint32_t max_mutex; + +}; + +} // namespace srsenb + +#endif // UEPHY_H diff --git a/srsenb/hdr/phy/phch_worker.h b/srsenb/hdr/phy/phch_worker.h new file mode 100644 index 000000000..2f0f80f41 --- /dev/null +++ b/srsenb/hdr/phy/phch_worker.h @@ -0,0 +1,123 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2017 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of srsLTE. + * + * srsUE 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. + * + * srsUE 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 ENBPHYWORKER_H +#define ENBPHYWORKER_H + +#include + +#include "srslte/srslte.h" +#include "phy/phch_common.h" + +#define LOG_EXECTIME + +namespace srsenb { + +class phch_worker : public srslte::thread_pool::worker +{ +public: + + phch_worker(); + void init(phch_common *phy, srslte::log *log_h); + void reset(); + + cf_t *get_buffer_rx(); + void set_time(uint32_t tti, uint32_t tx_mutex_cnt, srslte_timestamp_t tx_time); + + int add_rnti(uint16_t rnti); + void rem_rnti(uint16_t rnti); + uint32_t get_nof_rnti(); + + /* These are used by the GUI plotting tools */ + int read_ce_abs(float *ce_abs); + int read_pusch_d(cf_t *pusch_d); + void start_plot(); + + + void set_config_dedicated(uint16_t rnti, + srslte_uci_cfg_t *uci_cfg, + srslte_pucch_sched_t *pucch_sched, + srslte_refsignal_srs_cfg_t *srs_cfg, + uint32_t I_sr, bool pucch_cqi, uint32_t pmi_idx, bool pucch_cqi_ack); + + uint32_t get_metrics(phy_metrics_t metrics[ENB_METRICS_MAX_USERS]); + +private: + + const static float PUSCH_RL_SNR_DB_TH = 1.0; + const static float PUCCH_RL_CORR_TH = 0.1; + + void work_imp(); + + int encode_pdsch(srslte_enb_dl_pdsch_t *grants, uint32_t nof_grants, uint32_t sf_idx); + int decode_pusch(srslte_enb_ul_pusch_t *grants, uint32_t nof_pusch, uint32_t tti_rx); + int encode_phich(srslte_enb_dl_phich_t *acks, uint32_t nof_acks, uint32_t sf_idx); + int encode_pdcch_dl(srslte_enb_dl_pdsch_t *grants, uint32_t nof_grants, uint32_t sf_idx); + int encode_pdcch_ul(srslte_enb_ul_pusch_t *grants, uint32_t nof_grants, uint32_t sf_idx); + int decode_pucch(uint32_t tti_rx); + + + /* Common objects */ + srslte::log *log_h; + phch_common *phy; + bool initiated; + cf_t *signal_buffer_rx; + cf_t *signal_buffer_tx; + uint32_t tti_rx, tti_tx, tti_sched_ul, sf_rx, sf_tx, sf_sched_ul, tx_mutex_cnt; + + srslte_enb_dl_t enb_dl; + srslte_enb_ul_t enb_ul; + + srslte_timestamp_t tx_time; + + // Class to store user information + class ue { + public: + ue() : I_sr(0), I_sr_en(false), cqi_en(false), pucch_cqi_ack(false), pmi_idx(0), has_grant_tti(0) {bzero(&metrics, sizeof(phy_metrics_t));} + uint32_t I_sr; + uint32_t pmi_idx; + bool I_sr_en; + bool cqi_en; + bool pucch_cqi_ack; + int has_grant_tti; + uint32_t rnti; + srslte_enb_ul_phich_info_t phich_info; + void metrics_read(phy_metrics_t *metrics); + void metrics_dl(uint32_t mcs); + void metrics_ul(uint32_t mcs, float rssi, float sinr, uint32_t turbo_iters); + private: + phy_metrics_t metrics; + }; + std::map ue_db; + + // mutex to protect worker_imp() from configuration interface + pthread_mutex_t mutex; +}; + +} // namespace srsenb + +#endif // ENBPHYWORKER_H + diff --git a/srsenb/hdr/phy/phy.h b/srsenb/hdr/phy/phy.h new file mode 100644 index 000000000..9ab1efd74 --- /dev/null +++ b/srsenb/hdr/phy/phy.h @@ -0,0 +1,100 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2017 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of srsLTE. + * + * srsUE 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. + * + * srsUE 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 ENBPHY_H +#define ENBPHY_H + +#include "srslte/common/log.h" +#include "phy/txrx.h" +#include "phy/phch_worker.h" +#include "phy/phch_common.h" +#include "srslte/radio/radio.h" +#include "srslte/interfaces/enb_interfaces.h" +#include "srslte/common/task_dispatcher.h" +#include "srslte/common/trace.h" +#include "srslte/interfaces/enb_metrics_interface.h" + +namespace srsenb { + +typedef struct { + srslte_cell_t cell; + LIBLTE_RRC_PRACH_CONFIG_SIB_STRUCT prach_cnfg; + LIBLTE_RRC_PDSCH_CONFIG_COMMON_STRUCT pdsch_cnfg; + LIBLTE_RRC_PUSCH_CONFIG_COMMON_STRUCT pusch_cnfg; + LIBLTE_RRC_PUCCH_CONFIG_COMMON_STRUCT pucch_cnfg; + LIBLTE_RRC_SRS_UL_CONFIG_COMMON_STRUCT srs_ul_cnfg; +} phy_cfg_t; + +class phy : public phy_interface_mac, + public phy_interface_rrc +{ +public: + + phy(); + bool init(phy_args_t *args, phy_cfg_t *common_cfg, srslte::radio *radio_handler, mac_interface_phy *mac, srslte::log* log_h); + bool init(phy_args_t *args, phy_cfg_t *common_cfg, srslte::radio *radio_handler, mac_interface_phy *mac, std::vector log_vec); + void stop(); + + /* MAC->PHY interface */ + int add_rnti(uint16_t rnti); + void rem_rnti(uint16_t rnti); + + static uint32_t tti_to_SFN(uint32_t tti); + static uint32_t tti_to_subf(uint32_t tti); + + void start_plot(); + void set_config_dedicated(uint16_t rnti, LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT* dedicated); + + void get_metrics(phy_metrics_t metrics[ENB_METRICS_MAX_USERS]); + +private: + + uint32_t nof_workers; + + const static int MAX_WORKERS = 4; + const static int DEFAULT_WORKERS = 2; + + const static int PRACH_WORKER_THREAD_PRIO = 80; + const static int SF_RECV_THREAD_PRIO = 1; + const static int WORKERS_THREAD_PRIO = 0; + + srslte::radio *radio_handler; + + srslte::thread_pool workers_pool; + std::vector workers; + phch_common workers_common; + prach_worker prach; + txrx tx_rx; + + srslte_prach_cfg_t prach_cfg; + + void parse_config(phy_cfg_t* cfg); + +}; + +} // namespace srsenb + +#endif // UEPHY_H diff --git a/srsenb/hdr/phy/phy_metrics.h b/srsenb/hdr/phy/phy_metrics.h new file mode 100644 index 000000000..ad3b96698 --- /dev/null +++ b/srsenb/hdr/phy/phy_metrics.h @@ -0,0 +1,59 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2017 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of srsLTE. + * + * srsUE 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. + * + * srsUE 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 ENB_PHY_METRICS_H +#define ENB_PHY_METRICS_H + + +namespace srsenb { + +// PHY metrics per user + +struct ul_metrics_t +{ + float n; + float sinr; + float rssi; + float turbo_iters; + float mcs; + int n_samples; +}; + +struct dl_metrics_t +{ + float mcs; + int n_samples; +}; + +struct phy_metrics_t +{ + dl_metrics_t dl; + ul_metrics_t ul; +}; + +} // namespace srsenb + +#endif // ENB_PHY_METRICS_H diff --git a/srsenb/hdr/phy/prach_worker.h b/srsenb/hdr/phy/prach_worker.h new file mode 100644 index 000000000..d1bc7c13f --- /dev/null +++ b/srsenb/hdr/phy/prach_worker.h @@ -0,0 +1,75 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2017 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of srsLTE. + * + * srsUE 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. + * + * srsUE 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 PRACH_WORKER_H +#define PRACH_WORKER_H + +#include "srslte/interfaces/enb_interfaces.h" +#include "srslte/common/log.h" +#include "srslte/common/threads.h" + +namespace srsenb { + +class prach_worker : thread +{ +public: + prach_worker() : initiated(false),max_prach_offset_us(0) {} + + int init(srslte_cell_t *cell, srslte_prach_cfg_t *prach_cfg, mac_interface_phy *mac, srslte::log *log_h, int priority); + int new_tti(uint32_t tti, cf_t *buffer); + void set_max_prach_offset_us(float delay_us); + void stop(); + +private: + void run_thread(); + int run_tti(uint32_t tti); + + uint32_t prach_nof_det; + uint32_t prach_indices[165]; + float prach_offsets[165]; + float prach_p2avg[165]; + + srslte_cell_t cell; + srslte_prach_cfg_t prach_cfg; + srslte_prach_t prach; + + pthread_mutex_t mutex; + pthread_cond_t cvar; + + cf_t *signal_buffer_rx; + + srslte::log* log_h; + mac_interface_phy *mac; + float max_prach_offset_us; + bool initiated; + uint32_t pending_tti; + int processed_tti; + bool running; + uint32_t nof_sf; + uint32_t sf_cnt; +}; +} +#endif // PRACH_WORKER_H diff --git a/srsenb/hdr/phy/txrx.h b/srsenb/hdr/phy/txrx.h new file mode 100644 index 000000000..035f81f9c --- /dev/null +++ b/srsenb/hdr/phy/txrx.h @@ -0,0 +1,76 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2017 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of srsLTE. + * + * srsUE 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. + * + * srsUE 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 ENBTXRX_H +#define ENBTXRX_H + +#include "srslte/common/log.h" +#include "srslte/common/threads.h" +#include "srslte/common/thread_pool.h" +#include "srslte/radio/radio.h" +#include "phy/phch_common.h" +#include "phy/prach_worker.h" + +namespace srsenb { + +typedef _Complex float cf_t; + +class txrx : public thread +{ +public: + txrx(); + bool init(srslte::radio *radio_handler, + srslte::thread_pool *_workers_pool, + phch_common *worker_com, + prach_worker *prach, + srslte::log *log_h, + uint32_t prio); + void stop(); + + const static int MUTEX_X_WORKER = 4; + +private: + + void run_thread(); + + srslte::radio *radio_h; + srslte::log *log_h; + srslte::thread_pool *workers_pool; + prach_worker *prach; + phch_common *worker_com; + + uint32_t tx_mutex_cnt; + uint32_t nof_tx_mutex; + + // Main system TTI counter + uint32_t tti; + + bool running; +}; + +} // namespace srsenb + +#endif // UEPHY_H diff --git a/srsenb/hdr/upper/common_enb.h b/srsenb/hdr/upper/common_enb.h new file mode 100644 index 000000000..9f15b69ae --- /dev/null +++ b/srsenb/hdr/upper/common_enb.h @@ -0,0 +1,158 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2017 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of srsLTE. + * + * srsUE 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. + * + * srsUE 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 COMMON_ENB_H +#define COMMON_ENB_H + +/******************************************************************************* + INCLUDES +*******************************************************************************/ + +#include + +namespace srsenb { + +#define ENB_METRICS_MAX_USERS 64 + +#define SRSENB_RRC_MAX_N_PLMN_IDENTITIES 6 + +#define SRSENB_N_SRB 3 +#define SRSENB_N_DRB 8 +#define SRSENB_N_RADIO_BEARERS 11 + +// Cat 3 UE - Max number of DL-SCH transport block bits received within a TTI +// 3GPP 36.306 Table 4.1.1 +#define SRSENB_MAX_BUFFER_SIZE_BITS 102048 +#define SRSENB_MAX_BUFFER_SIZE_BYTES 12756 +#define SRSENB_BUFFER_HEADER_OFFSET 1024 + +/****************************************************************************** + * Convert PLMN to BCD-coded MCC and MNC. + * Digits are represented by 4-bit nibbles. Unused nibbles are filled with 0xF. + * MNC 001 represented as 0xF001 + * MNC 01 represented as 0xFF01 + * PLMN encoded as per TS 36.413 sec 9.2.3.8 + *****************************************************************************/ +inline void s1ap_plmn_to_mccmnc(uint32_t plmn, uint16_t *mcc, uint16_t *mnc) +{ + uint8_t nibbles[6]; + nibbles[0] = (plmn & 0xF00000) >> 20; + nibbles[1] = (plmn & 0x0F0000) >> 16; + nibbles[2] = (plmn & 0x00F000) >> 12; + nibbles[3] = (plmn & 0x000F00) >> 8; + nibbles[4] = (plmn & 0x0000F0) >> 4; + nibbles[5] = (plmn & 0x00000F); + + *mcc = 0xF000; + *mnc = 0xF000; + *mcc |= nibbles[1] << 8; // MCC digit 1 + *mcc |= nibbles[0] << 4; // MCC digit 2 + *mcc |= nibbles[3]; // MCC digit 3 + + if(nibbles[2] == 0xF) { + // 2-digit MNC + *mnc |= 0x0F00; // MNC digit 1 + *mnc |= nibbles[5] << 4; // MNC digit 2 + *mnc |= nibbles[4]; // MNC digit 3 + } else { + // 3-digit MNC + *mnc |= nibbles[5] << 8; // MNC digit 1 + *mnc |= nibbles[4] << 4; // MNC digit 2 + *mnc |= nibbles[2] ; // MNC digit 3 + } +} + +/****************************************************************************** + * Convert BCD-coded MCC and MNC to PLMN. + * Digits are represented by 4-bit nibbles. Unused nibbles are filled with 0xF. + * MNC 001 represented as 0xF001 + * MNC 01 represented as 0xFF01 + * PLMN encoded as per TS 36.413 sec 9.2.3.8 + *****************************************************************************/ +inline void s1ap_mccmnc_to_plmn(uint16_t mcc, uint16_t mnc, uint32_t *plmn) +{ + uint8_t nibbles[6]; + nibbles[1] = (mcc & 0x0F00) >> 8; // MCC digit 1 + nibbles[0] = (mcc & 0x00F0) >> 4; // MCC digit 2 + nibbles[3] = (mcc & 0x000F); // MCC digit 3 + + if((mnc & 0xFF00) == 0xFF00) { + // 2-digit MNC + nibbles[2] = 0x0F; // MNC digit 1 + nibbles[5] = (mnc & 0x00F0) >> 4; // MNC digit 2 + nibbles[4] = (mnc & 0x000F); // MNC digit 3 + } else { + // 3-digit MNC + nibbles[5] = (mnc & 0x0F00) >> 8; // MNC digit 1 + nibbles[4] = (mnc & 0x00F0) >> 4; // MNC digit 2 + nibbles[2] = (mnc & 0x000F); // MNC digit 3 + } + + *plmn = 0x000000; + *plmn |= nibbles[0] << 20; + *plmn |= nibbles[1] << 16; + *plmn |= nibbles[2] << 12; + *plmn |= nibbles[3] << 8; + *plmn |= nibbles[4] << 4; + *plmn |= nibbles[5]; +} + +/****************************************************************************** + * 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) +{ + *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) +{ + buf[0] = (i >> 24) & 0xFF; + buf[1] = (i >> 16) & 0xFF; + buf[2] = (i >> 8) & 0xFF; + buf[3] = i & 0xFF; +} + +inline void uint8_to_uint16(uint8_t *buf, uint16_t *i) +{ + *i = (uint32_t)buf[0] << 8 | + (uint32_t)buf[1]; +} + +inline void uint16_to_uint8(uint16_t i, uint8_t *buf) +{ + buf[0] = (i >> 8) & 0xFF; + buf[1] = i & 0xFF; +} + +} // namespace srsenb + +#endif // COMMON_ENB_H diff --git a/srsenb/hdr/upper/gtpu.h b/srsenb/hdr/upper/gtpu.h new file mode 100644 index 000000000..9ad9441fa --- /dev/null +++ b/srsenb/hdr/upper/gtpu.h @@ -0,0 +1,128 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2017 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of srsLTE. + * + * srsUE 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. + * + * srsUE 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 +#include + +#include "srslte/common/buffer_pool.h" +#include "srslte/common/log.h" +#include "upper/common_enb.h" +#include "srslte/common/threads.h" +#include "srslte/srslte.h" +#include "srslte/interfaces/enb_interfaces.h" + +#ifndef GTPU_H +#define GTPU_H + +namespace srsenb { + +/**************************************************************************** + * GTPU Header + * Ref: 3GPP TS 29.281 v10.1.0 Section 5 + * + * | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | + * + * 1 | Version |PT | * | E | S |PN | + * 2 | Message Type | + * 3 | Length (1st Octet) | + * 4 | Length (2nd Octet) | + * 5 | TEID (1st Octet) | + * 6 | TEID (2nd Octet) | + * 7 | TEID (3rd Octet) | + * 8 | TEID (4th Octet) | + ***************************************************************************/ + +#define GTPU_HEADER_LEN 8 + +typedef struct{ + uint8_t flags; // Only support 0x30 - v1, PT1 (GTP), no other flags + uint8_t message_type; // Only support 0xFF - T-PDU type + uint16_t length; + uint32_t teid; +}gtpu_header_t; + +class gtpu + :public gtpu_interface_rrc + ,public gtpu_interface_pdcp + ,public thread +{ +public: + + bool init(std::string gtp_bind_addr_, std::string mme_addr_, pdcp_interface_gtpu *pdcp_, srslte::log *gtpu_log_); + void stop(); + + // gtpu_interface_rrc + void add_bearer(uint16_t rnti, uint32_t lcid, uint32_t teid_out, uint32_t *teid_in); + void rem_bearer(uint16_t rnti, uint32_t lcid); + void rem_user(uint16_t rnti); + + // gtpu_interface_pdcp + void write_pdu(uint16_t rnti, uint32_t lcid, srslte::byte_buffer_t *pdu); + + +private: + static const int THREAD_PRIO = 7; + static const int GTPU_PORT = 2152; + srslte::byte_buffer_pool *pool; + bool running; + bool run_enable; + + std::string gtp_bind_addr; + std::string mme_addr; + srsenb::pdcp_interface_gtpu *pdcp; + srslte::log *gtpu_log; + + typedef struct{ + uint32_t teids_in[SRSENB_N_RADIO_BEARERS]; + uint32_t teids_out[SRSENB_N_RADIO_BEARERS]; + }bearer_map; + std::map rnti_bearers; + + srslte_netsink_t snk; + srslte_netsource_t src; + + void run_thread(); + + pthread_mutex_t mutex; + + /**************************************************************************** + * Header pack/unpack helper functions + * Ref: 3GPP TS 29.281 v10.1.0 Section 5 + ***************************************************************************/ + bool gtpu_write_header(gtpu_header_t *header, srslte::byte_buffer_t *pdu); + bool gtpu_read_header(srslte::byte_buffer_t *pdu, gtpu_header_t *header); + + /**************************************************************************** + * TEID to RNIT/LCID helper functions + ***************************************************************************/ + void teidin_to_rntilcid(uint32_t teidin, uint16_t *rnti, uint16_t *lcid); + void rntilcid_to_teidin(uint16_t rnti, uint16_t lcid, uint32_t *teidin); +}; + + +} // namespace srsenb + +#endif // GTPU_H diff --git a/srsenb/hdr/upper/pdcp.h b/srsenb/hdr/upper/pdcp.h new file mode 100644 index 000000000..44c59b8e6 --- /dev/null +++ b/srsenb/hdr/upper/pdcp.h @@ -0,0 +1,114 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2017 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of srsLTE. + * + * srsUE 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. + * + * srsUE 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 +#include "srslte/interfaces/ue_interfaces.h" +#include "srslte/interfaces/enb_interfaces.h" +#include "srslte/upper/pdcp.h" + +#ifndef PDCP_ENB_H +#define PDCP_ENB_H + +namespace srsenb { + +class pdcp : public pdcp_interface_rlc, + public pdcp_interface_gtpu, + public pdcp_interface_rrc +{ +public: + + void init(rlc_interface_pdcp *rlc_, rrc_interface_pdcp *rrc_, gtpu_interface_pdcp *gtpu_, srslte::log *pdcp_log_); + void stop(); + + // pdcp_interface_rlc + void write_pdu(uint16_t rnti, uint32_t lcid, srslte::byte_buffer_t *sdu); + + // pdcp_interface_rrc + void reset(uint16_t rnti); + void add_user(uint16_t rnti); + void rem_user(uint16_t rnti); + void write_sdu(uint16_t rnti, uint32_t lcid, srslte::byte_buffer_t *sdu); + void add_bearer(uint16_t rnti, uint32_t lcid, LIBLTE_RRC_PDCP_CONFIG_STRUCT *cnfg=NULL); + void config_security(uint16_t rnti, + uint32_t lcid, + uint8_t *k_rrc_enc_, + uint8_t *k_rrc_int_, + srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo_, + srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo_); + +private: + + class user_interface_rlc : public srsue::rlc_interface_pdcp + { + public: + uint16_t rnti; + srsenb::rlc_interface_pdcp *rlc; + // rlc_interface_pdcp + void write_sdu(uint32_t lcid, srslte::byte_buffer_t *sdu); + }; + + class user_interface_gtpu : public srsue::gw_interface_pdcp + { + public: + uint16_t rnti; + srsenb::gtpu_interface_pdcp *gtpu; + // gw_interface_pdcp + void write_pdu(uint32_t lcid, srslte::byte_buffer_t *pdu); + }; + + class user_interface_rrc : public srsue::rrc_interface_pdcp + { + public: + uint16_t rnti; + srsenb::rrc_interface_pdcp *rrc; + // rrc_interface_pdcp + void write_pdu(uint32_t lcid, srslte::byte_buffer_t *pdu); + void write_pdu_bcch_bch(srslte::byte_buffer_t *pdu); + void write_pdu_bcch_dlsch(srslte::byte_buffer_t *pdu); + void write_pdu_pcch(srslte::byte_buffer_t *pdu); + }; + + class user_interface + { + public: + user_interface_rlc rlc_itf; + user_interface_gtpu gtpu_itf; + user_interface_rrc rrc_itf; + srslte::pdcp *pdcp; + }; + + std::map users; + + rlc_interface_pdcp *rlc; + rrc_interface_pdcp *rrc; + gtpu_interface_pdcp *gtpu; + srslte::log *log_h; + srslte::byte_buffer_pool *pool; +}; + +} + +#endif // PDCP_ENB_H diff --git a/srsenb/hdr/upper/rlc.h b/srsenb/hdr/upper/rlc.h new file mode 100644 index 000000000..c979f6af8 --- /dev/null +++ b/srsenb/hdr/upper/rlc.h @@ -0,0 +1,96 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2017 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of srsLTE. + * + * srsUE 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. + * + * srsUE 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 +#include "srslte/interfaces/ue_interfaces.h" +#include "srslte/interfaces/enb_interfaces.h" +#include "srslte/upper/rlc.h" + +#ifndef RLC_ENB_H +#define RLC_ENB_H + +namespace srsenb { + +class rlc : public rlc_interface_mac, + public rlc_interface_rrc, + public rlc_interface_pdcp +{ +public: + + void init(pdcp_interface_rlc *pdcp_, rrc_interface_rlc *rrc_, mac_interface_rlc *mac_, + srslte::mac_interface_timers *mac_timers_, srslte::log *log_h); + void stop(); + + // rlc_interface_rrc + void reset(uint16_t rnti); + void clear_buffer(uint16_t rnti); + void add_user(uint16_t rnti); + void rem_user(uint16_t rnti); + void add_bearer(uint16_t rnti, uint32_t lcid); + void add_bearer(uint16_t rnti, uint32_t lcid, LIBLTE_RRC_RLC_CONFIG_STRUCT *cnfg); + + // rlc_interface_pdcp + void write_sdu(uint16_t rnti, uint32_t lcid, srslte::byte_buffer_t *sdu); + + // rlc_interface_mac + int read_pdu(uint16_t rnti, uint32_t lcid, uint8_t *payload, uint32_t nof_bytes); + void read_pdu_bcch_dlsch(uint32_t sib_index, uint8_t *payload); + void write_pdu(uint16_t rnti, uint32_t lcid, uint8_t *payload, uint32_t nof_bytes); + void read_pdu_pcch(uint8_t *payload, uint32_t buffer_size); + +private: + + class user_interface : public srsue::pdcp_interface_rlc, + public srsue::rrc_interface_rlc, + public srsue::ue_interface + { + public: + void write_pdu(uint32_t lcid, srslte::byte_buffer_t *sdu); + void write_pdu_bcch_bch(srslte::byte_buffer_t *sdu); + void write_pdu_bcch_dlsch(srslte::byte_buffer_t *sdu); + void write_pdu_pcch(srslte::byte_buffer_t *sdu); + void max_retx_attempted(); + uint16_t rnti; + + srsenb::pdcp_interface_rlc *pdcp; + srsenb::rrc_interface_rlc *rrc; + srslte::rlc *rlc; + srsenb::rlc *parent; + }; + + std::map users; + + mac_interface_rlc *mac; + pdcp_interface_rlc *pdcp; + rrc_interface_rlc *rrc; + srslte::log *log_h; + srslte::byte_buffer_pool *pool; + srslte::mac_interface_timers *mac_timers; +}; + +} + +#endif // RLC_H diff --git a/srsenb/hdr/upper/rrc.h b/srsenb/hdr/upper/rrc.h new file mode 100644 index 000000000..49a02d0b9 --- /dev/null +++ b/srsenb/hdr/upper/rrc.h @@ -0,0 +1,341 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2017 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of srsLTE. + * + * srsUE 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. + * + * srsUE 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 RRC_H +#define RRC_H + +#include +#include +#include "srslte/common/buffer_pool.h" +#include "srslte/common/common.h" +#include "srslte/common/block_queue.h" +#include "srslte/common/threads.h" +#include "srslte/common/timeout.h" +#include "srslte/common/log.h" +#include "srslte/interfaces/enb_interfaces.h" +#include "upper/common_enb.h" +#include "rrc_metrics.h" + +namespace srsenb { + +typedef struct { + uint32_t period; + LIBLTE_RRC_DSR_TRANS_MAX_ENUM dsr_max; + uint32_t nof_prb; + uint32_t sf_mapping[80]; + uint32_t nof_subframes; +} rrc_cfg_sr_t; + +typedef enum { + RRC_CFG_CQI_MODE_PERIODIC = 0, + RRC_CFG_CQI_MODE_APERIODIC, + RRC_CFG_CQI_MODE_N_ITEMS +} rrc_cfg_cqi_mode_t; + +static const char rrc_cfg_cqi_mode_text[RRC_CFG_CQI_MODE_N_ITEMS][20] = {"periodic", "aperiodic"}; + +typedef struct { + uint32_t sf_mapping[80]; + uint32_t nof_subframes; + uint32_t nof_prb; + uint32_t period; + bool simultaneousAckCQI; + rrc_cfg_cqi_mode_t mode; +} rrc_cfg_cqi_t; + +typedef struct { + bool configured; + LIBLTE_RRC_UL_SPECIFIC_PARAMETERS_STRUCT lc_cfg; + LIBLTE_RRC_PDCP_CONFIG_STRUCT pdcp_cfg; + LIBLTE_RRC_RLC_CONFIG_STRUCT rlc_cfg; +} rrc_cfg_qci_t; + +#define MAX_NOF_QCI 10 + +typedef struct { + LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_STRUCT sibs[LIBLTE_RRC_MAX_SIB]; + LIBLTE_RRC_MAC_MAIN_CONFIG_STRUCT mac_cnfg; + LIBLTE_RRC_PUSCH_CONFIG_DEDICATED_STRUCT pusch_cfg; + rrc_cfg_sr_t sr_cfg; + rrc_cfg_cqi_t cqi_cfg; + rrc_cfg_qci_t qci_cfg[MAX_NOF_QCI]; + srslte_cell_t cell; + uint32_t inactivity_timeout_ms; +}rrc_cfg_t; + +static const char rrc_state_text[RRC_STATE_N_ITEMS][100] = {"IDLE", + "WAIT FOR CON SETUP COMPLETE", + "WAIT FOR SECURITY MODE COMPLETE", + "WAIT FOR UE CAPABILITIY INFORMATION", + "WAIT FOR CON RECONF COMPLETE", + "RRC CONNECTED" + "RELEASE REQUEST"}; + +class rrc : public rrc_interface_pdcp, + public rrc_interface_mac, + public rrc_interface_rlc, + public rrc_interface_s1ap, + public thread +{ +public: + + rrc() : act_monitor(this), cnotifier(NULL) {} + + void init(rrc_cfg_t *cfg, + phy_interface_rrc *phy, + mac_interface_rrc *mac, + rlc_interface_rrc *rlc, + pdcp_interface_rrc *pdcp, + s1ap_interface_rrc *s1ap, + gtpu_interface_rrc *gtpu, + srslte::log *log_rrc); + + void stop(); + void get_metrics(rrc_metrics_t &m); + + // rrc_interface_mac + void rl_failure(uint16_t rnti); + void add_user(uint16_t rnti); + void upd_user(uint16_t new_rnti, uint16_t old_rnti); + void set_activity_user(uint16_t rnti); + bool is_paging_opportunity(uint32_t tti, uint32_t *payload_len); + + // rrc_interface_rlc + void read_pdu_bcch_dlsch(uint32_t sib_idx, uint8_t *payload); + void read_pdu_pcch(uint8_t *payload, uint32_t buffer_size); + void max_retx_attempted(uint16_t rnti); + + // rrc_interface_s1ap + void write_dl_info(uint16_t rnti, srslte::byte_buffer_t *sdu); + void release_complete(uint16_t rnti); + bool setup_ue_ctxt(uint16_t rnti, LIBLTE_S1AP_MESSAGE_INITIALCONTEXTSETUPREQUEST_STRUCT *msg); + bool setup_ue_erabs(uint16_t rnti, LIBLTE_S1AP_MESSAGE_E_RABSETUPREQUEST_STRUCT *msg); + bool release_erabs(uint32_t rnti); + void add_paging_id(uint32_t ueid, LIBLTE_S1AP_UEPAGINGID_STRUCT UEPagingID); + + // rrc_interface_pdcp + void write_pdu(uint16_t rnti, uint32_t lcid, srslte::byte_buffer_t *pdu); + + void parse_sibs(); + uint32_t get_nof_users(); + + // Notifier for user connect + class connect_notifier { + public: + virtual void user_connected(uint16_t rnti) = 0; + }; + void set_connect_notifer(connect_notifier *cnotifier); + + class activity_monitor : public thread + { + public: + activity_monitor(rrc* parent_); + void stop(); + private: + rrc* parent; + bool running; + void run_thread(); + }; + + class ue + { + public: + ue(); + bool is_connected(); + bool is_idle(); + bool is_timeout(); + void set_activity(); + + rrc_state_t get_state(); + + void send_connection_setup(bool is_setup = true); + void send_connection_reest(); + void send_connection_release(); + void send_connection_reest_rej(); + void send_connection_reconf(srslte::byte_buffer_t *sdu); + void send_connection_reconf_new_bearer(LIBLTE_S1AP_E_RABTOBESETUPLISTBEARERSUREQ_STRUCT *e); + void send_connection_reconf_upd(srslte::byte_buffer_t *pdu); + void send_security_mode_command(); + void send_ue_cap_enquiry(); + void parse_ul_dcch(uint32_t lcid, srslte::byte_buffer_t* pdu); + + void handle_rrc_con_req(LIBLTE_RRC_CONNECTION_REQUEST_STRUCT *msg); + void handle_rrc_con_reest_req(LIBLTE_RRC_CONNECTION_REESTABLISHMENT_REQUEST_STRUCT *msg); + void handle_rrc_con_setup_complete(LIBLTE_RRC_CONNECTION_SETUP_COMPLETE_STRUCT *msg, srslte::byte_buffer_t *pdu); + void handle_security_mode_complete(LIBLTE_RRC_SECURITY_MODE_COMPLETE_STRUCT *msg); + void handle_security_mode_failure(LIBLTE_RRC_SECURITY_MODE_FAILURE_STRUCT *msg); + void handle_ue_cap_info(LIBLTE_RRC_UE_CAPABILITY_INFORMATION_STRUCT *msg); + + void set_bitrates(LIBLTE_S1AP_UEAGGREGATEMAXIMUMBITRATE_STRUCT *rates); + void set_security_capabilities(LIBLTE_S1AP_UESECURITYCAPABILITIES_STRUCT *caps); + void set_security_key(uint8_t* key, uint32_t length); + + bool setup_erabs(LIBLTE_S1AP_E_RABTOBESETUPLISTCTXTSUREQ_STRUCT *e); + bool setup_erabs(LIBLTE_S1AP_E_RABTOBESETUPLISTBEARERSUREQ_STRUCT *e); + bool release_erabs(); + + void notify_s1ap_ue_ctxt_setup_complete(); + void notify_s1ap_ue_erab_setup_response(LIBLTE_S1AP_E_RABTOBESETUPLISTBEARERSUREQ_STRUCT *e); + + int sr_allocate(uint32_t period, uint32_t *I_sr, uint32_t *N_pucch_sr); + void sr_get(uint32_t *I_sr, uint32_t *N_pucch_sr); + int sr_free(); + + int cqi_allocate(uint32_t period, uint32_t *pmi_idx, uint32_t *n_pucch); + void cqi_get(uint32_t *pmi_idx, uint32_t *n_pucch); + int cqi_free(); + + void send_dl_ccch(LIBLTE_RRC_DL_CCCH_MSG_STRUCT *dl_ccch_msg); + void send_dl_dcch(LIBLTE_RRC_DL_DCCH_MSG_STRUCT *dl_dcch_msg, srslte::byte_buffer_t *pdu = NULL); + + uint16_t rnti; + rrc *parent; + + bool connect_notified; + + private: + + struct timeval t_last_activity; + + // S-TMSI for this UE + bool has_tmsi; + uint32_t m_tmsi; + uint8_t mmec; + + uint8_t transaction_id; + rrc_state_t state; + + std::map srbs; + std::map drbs; + + uint8_t k_enb[32]; // Provided by MME + uint8_t k_rrc_enc[32]; + uint8_t k_rrc_int[32]; + uint8_t k_up_enc[32]; + uint8_t k_up_int[32]; // Not used: only for relay nodes (3GPP 33.401 Annex A.7) + + srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo; + srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo; + + LIBLTE_S1AP_UEAGGREGATEMAXIMUMBITRATE_STRUCT bitrates; + LIBLTE_S1AP_UESECURITYCAPABILITIES_STRUCT security_capabilities; + LIBLTE_RRC_UE_EUTRA_CAPABILITY_STRUCT eutra_capabilities; + + typedef struct { + uint8_t id; + LIBLTE_S1AP_E_RABLEVELQOSPARAMETERS_STRUCT qos_params; + LIBLTE_S1AP_TRANSPORTLAYERADDRESS_STRUCT address; + uint32_t teid_out; + uint32_t teid_in; + }erab_t; + std::map erabs; + int sr_sched_sf_idx; + int sr_sched_prb_idx; + bool sr_allocated; + uint32_t sr_N_pucch; + uint32_t sr_I; + uint32_t cqi_pucch; + uint32_t cqi_idx; + bool cqi_allocated; + int cqi_sched_sf_idx; + bool cqi_sched_prb_idx; + int get_drbid_config(LIBLTE_RRC_DRB_TO_ADD_MOD_STRUCT *drb, int drbid); + }; + + +private: + + std::map users; + + std::map pending_paging; + + activity_monitor act_monitor; + + LIBLTE_BYTE_MSG_STRUCT sib_buffer[LIBLTE_RRC_MAX_SIB]; + + // user connect notifier + connect_notifier *cnotifier; + + void rem_user(uint16_t rnti); + uint32_t generate_sibs(); + void config_mac(); + void parse_ul_dcch(uint16_t rnti, uint32_t lcid, srslte::byte_buffer_t *pdu); + void parse_ul_ccch(uint16_t rnti, srslte::byte_buffer_t *pdu); + void configure_security(uint16_t rnti, + uint32_t lcid, + uint8_t *k_rrc_enc, + uint8_t *k_rrc_int, + uint8_t *k_up_enc, + uint8_t *k_up_int, + srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo, + srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo); + + srslte::byte_buffer_pool *pool; + srslte::bit_buffer_t bit_buf; + srslte::bit_buffer_t bit_buf_paging; + srslte::byte_buffer_t erab_info; + + phy_interface_rrc *phy; + mac_interface_rrc *mac; + rlc_interface_rrc *rlc; + pdcp_interface_rrc *pdcp; + gtpu_interface_rrc *gtpu; + s1ap_interface_rrc *s1ap; + srslte::log *rrc_log; + + typedef struct{ + uint16_t rnti; + uint32_t lcid; + srslte::byte_buffer_t* pdu; + }rrc_pdu; + + const static uint32_t LCID_REM_USER = 0xffff0001; + + bool running; + static const int RRC_THREAD_PRIO = 7; + srslte::block_queue rx_pdu_queue; + + typedef struct { + uint32_t nof_users[100][80]; + } sr_sched_t; + + sr_sched_t sr_sched; + sr_sched_t cqi_sched; + + rrc_cfg_t cfg; + uint32_t nof_si_messages; + LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT sib2; + + void run_thread(); + void rem_user_thread(uint16_t rnti); + pthread_mutex_t user_mutex; + + pthread_mutex_t paging_mutex; +}; + +} // namespace srsenb + +#endif // RRC_H diff --git a/srsenb/hdr/upper/rrc_metrics.h b/srsenb/hdr/upper/rrc_metrics.h new file mode 100644 index 000000000..bce3ec95f --- /dev/null +++ b/srsenb/hdr/upper/rrc_metrics.h @@ -0,0 +1,58 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2017 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of srsLTE. + * + * srsUE 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. + * + * srsUE 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 ENB_RRC_METRICS_H +#define ENB_RRC_METRICS_H + +#include "upper/common_enb.h" + +namespace srsenb { + +typedef enum{ + RRC_STATE_IDLE = 0, + RRC_STATE_WAIT_FOR_CON_SETUP_COMPLETE, + RRC_STATE_WAIT_FOR_SECURITY_MODE_COMPLETE, + RRC_STATE_WAIT_FOR_UE_CAP_INFO, + RRC_STATE_WAIT_FOR_CON_RECONF_COMPLETE, + RRC_STATE_REGISTERED, + RRC_STATE_RELEASE_REQUEST, + RRC_STATE_N_ITEMS, +}rrc_state_t; + +struct rrc_ue_metrics_t +{ + rrc_state_t state; +}; + +struct rrc_metrics_t +{ + uint16_t n_ues; + rrc_ue_metrics_t ues[ENB_METRICS_MAX_USERS]; +}; + +} // namespace srsenb + +#endif // ENB_S1AP_METRICS_H diff --git a/srsenb/hdr/upper/s1ap.h b/srsenb/hdr/upper/s1ap.h new file mode 100644 index 000000000..02e5e207e --- /dev/null +++ b/srsenb/hdr/upper/s1ap.h @@ -0,0 +1,151 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2017 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of srsLTE. + * + * srsUE 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. + * + * srsUE 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 S1AP_H +#define S1AP_H + +#include + +#include "srslte/common/buffer_pool.h" +#include "srslte/common/log.h" +#include "srslte/common/common.h" +#include "srslte/common/msg_queue.h" +#include "srslte/common/threads.h" +#include "srslte/interfaces/enb_interfaces.h" +#include "upper/common_enb.h" + +#include "srslte/asn1/liblte_s1ap.h" +#include "s1ap_metrics.h" + +namespace srsenb { + +typedef struct { + uint32_t enb_id; // 20-bit id (lsb bits) + uint8_t cell_id; // 8-bit cell id + uint16_t tac; // 16-bit tac + uint16_t mcc; // BCD-coded with 0xF filler + uint16_t mnc; // BCD-coded with 0xF filler + std::string mme_addr; + std::string gtp_bind_addr; + std::string enb_name; +}s1ap_args_t; + +typedef struct { + uint32_t rnti; + uint32_t eNB_UE_S1AP_ID; + uint32_t MME_UE_S1AP_ID; + bool release_requested; + uint16_t stream_id; +}ue_ctxt_t; + +class s1ap + :public s1ap_interface_rrc + ,public thread +{ +public: + bool init(s1ap_args_t args_, rrc_interface_s1ap *rrc_, srslte::log *s1ap_log_); + void stop(); + void get_metrics(s1ap_metrics_t &m); + + void run_thread(); + + // RRC interface + void initial_ue(uint16_t rnti, srslte::byte_buffer_t *pdu); + void initial_ue(uint16_t rnti, srslte::byte_buffer_t *pdu, uint32_t m_tmsi, uint8_t mmec); + void write_pdu(uint16_t rnti, srslte::byte_buffer_t *pdu); + bool user_exists(uint16_t rnti); + void user_inactivity(uint16_t rnti); + bool user_link_lost(uint16_t rnti); + void release_eutran(uint16_t rnti); + void ue_ctxt_setup_complete(uint16_t rnti, LIBLTE_S1AP_MESSAGE_INITIALCONTEXTSETUPRESPONSE_STRUCT *res); + void ue_erab_setup_complete(uint16_t rnti, LIBLTE_S1AP_MESSAGE_E_RABSETUPRESPONSE_STRUCT *res); + //void ue_capabilities(uint16_t rnti, LIBLTE_RRC_UE_EUTRA_CAPABILITY_STRUCT *caps); + +private: + static const int S1AP_THREAD_PRIO = 7; + static const int MME_PORT = 36412; + static const int ADDR_FAMILY = AF_INET; + static const int SOCK_TYPE = SOCK_STREAM; + static const int PROTO = IPPROTO_SCTP; + static const int PPID = 18; + static const int NONUE_STREAM_ID = 0; + + rrc_interface_s1ap *rrc; + s1ap_args_t args; + srslte::log *s1ap_log; + srslte::byte_buffer_pool *pool; + + bool mme_connected; + bool running; + int socket_fd; // SCTP socket file descriptor + struct sockaddr_in mme_addr; // MME address + uint32_t next_eNB_UE_S1AP_ID; // Next ENB-side UE identifier + uint16_t next_ue_stream_id; // Next UE SCTP stream identifier + + // Protocol IEs sent with every UL S1AP message + LIBLTE_S1AP_TAI_STRUCT tai; + LIBLTE_S1AP_EUTRAN_CGI_STRUCT eutran_cgi; + + LIBLTE_S1AP_MESSAGE_S1SETUPRESPONSE_STRUCT s1setupresponse; + + std::map ue_ctxt_map; + std::map enbid_to_rnti_map; + + void build_tai_cgi(); + bool connect_mme(); + bool setup_s1(); + + bool handle_s1ap_rx_pdu(srslte::byte_buffer_t *pdu); + bool handle_initiatingmessage(LIBLTE_S1AP_INITIATINGMESSAGE_STRUCT *msg); + bool handle_successfuloutcome(LIBLTE_S1AP_SUCCESSFULOUTCOME_STRUCT *msg); + bool handle_unsuccessfuloutcome(LIBLTE_S1AP_UNSUCCESSFULOUTCOME_STRUCT *msg); + bool handle_paging(LIBLTE_S1AP_MESSAGE_PAGING_STRUCT *msg); + + bool handle_s1setupresponse(LIBLTE_S1AP_MESSAGE_S1SETUPRESPONSE_STRUCT *msg); + bool handle_dlnastransport(LIBLTE_S1AP_MESSAGE_DOWNLINKNASTRANSPORT_STRUCT *msg); + bool handle_initialctxtsetuprequest(LIBLTE_S1AP_MESSAGE_INITIALCONTEXTSETUPREQUEST_STRUCT *msg); + bool handle_uectxtreleasecommand(LIBLTE_S1AP_MESSAGE_UECONTEXTRELEASECOMMAND_STRUCT *msg); + bool handle_s1setupfailure(LIBLTE_S1AP_MESSAGE_S1SETUPFAILURE_STRUCT *msg); + bool handle_erabsetuprequest(LIBLTE_S1AP_MESSAGE_E_RABSETUPREQUEST_STRUCT *msg); + + bool send_initialuemessage(uint16_t rnti, srslte::byte_buffer_t *pdu, bool has_tmsi, uint32_t m_tmsi=0, uint8_t mmec=0); + bool send_ulnastransport(uint16_t rnti, srslte::byte_buffer_t *pdu); + bool send_uectxtreleaserequest(uint16_t rnti, LIBLTE_S1AP_CAUSE_STRUCT *cause); + bool send_uectxtreleasecomplete(uint16_t rnti, uint32_t mme_ue_id, uint32_t enb_ue_id); + bool send_initial_ctxt_setup_response(uint16_t rnti, LIBLTE_S1AP_MESSAGE_INITIALCONTEXTSETUPRESPONSE_STRUCT *res_); + bool send_initial_ctxt_setup_failure(uint16_t rnti); + bool send_erab_setup_response(uint16_t rnti, LIBLTE_S1AP_MESSAGE_E_RABSETUPRESPONSE_STRUCT *res_); + //bool send_ue_capabilities(uint16_t rnti, LIBLTE_RRC_UE_EUTRA_CAPABILITY_STRUCT *caps) + + bool find_mme_ue_id(uint32_t mme_ue_id, uint16_t *rnti, uint32_t *enb_ue_id); + std::string get_cause(LIBLTE_S1AP_CAUSE_STRUCT *c); + +}; + +} // namespace srsenb + + +#endif // S1AP_H diff --git a/srsenb/hdr/upper/s1ap_metrics.h b/srsenb/hdr/upper/s1ap_metrics.h new file mode 100644 index 000000000..f77dc699c --- /dev/null +++ b/srsenb/hdr/upper/s1ap_metrics.h @@ -0,0 +1,46 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2017 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of srsLTE. + * + * srsUE 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. + * + * srsUE 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 ENB_S1AP_METRICS_H +#define ENB_S1AP_METRICS_H + + +namespace srsenb { + +typedef enum{ + S1AP_ATTACHING = 0, // Attempting to create S1 connection + S1AP_READY, // S1 connected + S1AP_ERROR // Failure +}S1AP_STATUS_ENUM; + +struct s1ap_metrics_t +{ + S1AP_STATUS_ENUM status; +}; + +} // namespace srsenb + +#endif // ENB_S1AP_METRICS_H diff --git a/srsenb/rr.conf.example b/srsenb/rr.conf.example new file mode 100644 index 000000000..33a625359 --- /dev/null +++ b/srsenb/rr.conf.example @@ -0,0 +1,50 @@ +mac_cnfg = +{ + phr_cnfg = + { + dl_pathloss_change = "3dB"; // Valid: 1, 3, 6 or INFINITY + periodic_phr_timer = 50; + prohibit_phr_timer = 0; + }; + ulsch_cnfg = + { + max_harq_tx = 4; + periodic_bsr_timer = 5; // in ms + retx_bsr_timer = 320; // in ms + }; + + time_alignment_timer = -1; // -1 is infinity +}; + +phy_cnfg = +{ + phich_cnfg = + { + duration = "Normal"; + resources = "1/6"; + }; + + pusch_cnfg_ded = + { + beta_offset_ack_idx = 10; + beta_offset_ri_idx = 5; + beta_offset_cqi_idx = 5; + }; + + // PUCCH-SR resources are scheduled on time-frequeny domain first, then multiplexed in the same resource. + sched_request_cnfg = + { + dsr_trans_max = 64; + period = 20; // in ms + subframe = [1]; // vector of subframe indices allowed for SR transmissions + nof_prb = 2; // number of PRBs on each extreme used for SR (total prb is twice this number) + }; + cqi_report_cnfg = + { + mode = "periodic"; + simultaneousAckCQI = true; + period = 40; // in ms + subframe = [0]; + nof_prb = 2; + }; +}; diff --git a/srsenb/sib.conf.example b/srsenb/sib.conf.example new file mode 100644 index 000000000..1ccfe5465 --- /dev/null +++ b/srsenb/sib.conf.example @@ -0,0 +1,116 @@ +sib1 = +{ + intra_freq_reselection = "Allowed"; + q_rx_lev_min = -130; + //p_max = 3; + cell_barred = "Not Barred" + si_window_length = 20; + sched_info = + ( + { + si_periodicity = 16; + si_mapping_info = []; // comma-separated array of SIB-indexes (from 3 to 13). + // Leave empty or commented to just scheduler sib2 + } + ); + system_info_value_tag = 0; +}; + +sib2 = +{ + rr_config_common_sib = + { + rach_cnfg = + { + num_ra_preambles = 52; + preamble_init_rx_target_pwr = -108; + pwr_ramping_step = 6; // in dB + preamble_trans_max = 7; + ra_resp_win_size = 10; // in ms + mac_con_res_timer = 64; // in ms + max_harq_msg3_tx = 4; + }; + bcch_cnfg = + { + modification_period_coeff = 16; // in ms + }; + pcch_cnfg = + { + default_paging_cycle = 32; // in rf + nB = "1"; + }; + prach_cnfg = + { + root_sequence_index = 128; + prach_cnfg_info = + { + high_speed_flag = false; + prach_config_index = 3; + prach_freq_offset = 0; + zero_correlation_zone_config = 11; + }; + }; + pdsch_cnfg = + { + p_b = 0; + rs_power = -4; + }; + pusch_cnfg = + { + n_sb = 1; + hopping_mode = "inter-subframe"; + pusch_hopping_offset = 2; + enable_64_qam = false; + ul_rs = + { + cyclic_shift = 0; + group_assignment_pusch = 0; + group_hopping_enabled = false; + sequence_hopping_enabled = false; + }; + }; + pucch_cnfg = + { + delta_pucch_shift = 1; + n_rb_cqi = 1; + n_cs_an = 0; + n1_pucch_an = 2; + }; + ul_pwr_ctrl = + { + p0_nominal_pusch = -108; + alpha = 1.0; + p0_nominal_pucch = -88; + delta_flist_pucch = + { + format_1 = 2; + format_1b = 3; + format_2 = 0; + format_2a = 0; + format_2b = 0; + }; + delta_preamble_msg3 = 4; + }; + ul_cp_length = "Normal"; + }; + + ue_timers_and_constants = + { + t300 = 2000; // in ms + t301 = 100; // in ms + t310 = 1000; // in ms + n310 = 1; + t311 = 1000; // in ms + n311 = 1; + }; + + freqInfo = + { + ul_carrier_freq_present = true; + ul_bw_present = true; + additional_spectrum_emission = 1; + }; + + time_alignment_timer = "INFINITY"; // use "sf500", "sf750", etc. +}; + diff --git a/srsenb/src/CMakeLists.txt b/srsenb/src/CMakeLists.txt new file mode 100644 index 000000000..199650fac --- /dev/null +++ b/srsenb/src/CMakeLists.txt @@ -0,0 +1,44 @@ + +add_subdirectory(phy) +add_subdirectory(mac) +add_subdirectory(upper) + + +# Link libstdc++ and libgcc +if(STATIC_LIB) + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static-libstdc++ -static-libgcc") +endif(STATIC_LIB) + + +if (RPATH) + SET(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE) +endif (RPATH) + + +add_executable(srsenb main.cc enb.cc parser.cc enb_cfg_parser.cc metrics_stdout.cc) +target_link_libraries(srsenb srsenb_upper + srsenb_mac + srsenb_phy + srslte_common + srslte_phy + srslte_upper + srslte_radio + ${CMAKE_THREAD_LIBS_INIT} + ${Boost_LIBRARIES} + ${SEC_LIBRARIES} + ${LIBCONFIGPP_LIBRARIES} + ${SCTP_LIBRARIES}) + +if (RPATH) + set_target_properties(srsenb PROPERTIES INSTALL_RPATH ".") +endif (RPATH) + +######################################################################## +# Option to run command after build (useful for remote builds) +######################################################################## +if (NOT ${BUILDENB_CMD} STREQUAL "") + message(STATUS "Added custom post-build-ENB command: ${BUILDENB_CMD}") + add_custom_command(TARGET srsenb POST_BUILD COMMAND ${BUILDENB_CMD}) +else(NOT ${BUILDENB_CMD} STREQUAL "") + message(STATUS "No post-build-ENB command defined") +endif (NOT ${BUILDENB_CMD} STREQUAL "") diff --git a/srsenb/src/enb.cc b/srsenb/src/enb.cc new file mode 100644 index 000000000..9a747dba6 --- /dev/null +++ b/srsenb/src/enb.cc @@ -0,0 +1,307 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2017 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of srsLTE. + * + * srsUE 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. + * + * srsUE 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 +#include +#include "enb.h" + +namespace srsenb { + +enb* enb::instance = NULL; +boost::mutex enb_instance_mutex; + + +enb* enb::get_instance(void) +{ + boost::mutex::scoped_lock lock(enb_instance_mutex); + if(NULL == instance) { + instance = new enb(); + } + return(instance); +} +void enb::cleanup(void) +{ + boost::mutex::scoped_lock lock(enb_instance_mutex); + if(NULL != instance) { + delete instance; + instance = NULL; + } +} + +enb::enb() + :started(false) +{ + pool = srslte::byte_buffer_pool::get_instance(); +} + +enb::~enb() +{ + srslte::byte_buffer_pool::cleanup(); +} + +bool enb::init(all_args_t *args_) +{ + args = args_; + + logger.init(args->log.filename); + rf_log.init("RF ", &logger); + + // Create array of pointers to phy_logs + for (int i=0;iexpert.phy.nof_phy_threads;i++) { + srslte::log_filter *mylog = new srslte::log_filter; + char tmp[16]; + sprintf(tmp, "PHY%d",i); + mylog->init(tmp, &logger, true); + phy_log.push_back((void*) mylog); + } + mac_log.init("MAC ", &logger, true); + rlc_log.init("RLC ", &logger); + pdcp_log.init("PDCP", &logger); + rrc_log.init("RRC ", &logger); + gtpu_log.init("GTPU", &logger); + s1ap_log.init("S1AP", &logger); + + // Init logs + logger.log("\n\n"); + rf_log.set_level(srslte::LOG_LEVEL_INFO); + for (int i=0;iexpert.phy.nof_phy_threads;i++) { + ((srslte::log_filter*) phy_log[i])->set_level(level(args->log.phy_level)); + } + mac_log.set_level(level(args->log.mac_level)); + rlc_log.set_level(level(args->log.rlc_level)); + pdcp_log.set_level(level(args->log.pdcp_level)); + rrc_log.set_level(level(args->log.rrc_level)); + gtpu_log.set_level(level(args->log.gtpu_level)); + s1ap_log.set_level(level(args->log.s1ap_level)); + + for (int i=0;iexpert.phy.nof_phy_threads;i++) { + ((srslte::log_filter*) phy_log[i])->set_hex_limit(args->log.phy_hex_limit); + } + mac_log.set_hex_limit(args->log.mac_hex_limit); + rlc_log.set_hex_limit(args->log.rlc_hex_limit); + pdcp_log.set_hex_limit(args->log.pdcp_hex_limit); + rrc_log.set_hex_limit(args->log.rrc_hex_limit); + gtpu_log.set_hex_limit(args->log.gtpu_hex_limit); + s1ap_log.set_hex_limit(args->log.s1ap_hex_limit); + + // Set up pcap and trace + if(args->pcap.enable) + { + mac_pcap.open(args->pcap.filename.c_str()); + mac.start_pcap(&mac_pcap); + } + + // Init layers + + /* Start Radio */ + char *dev_name = NULL; + if (args->rf.device_name.compare("auto")) { + dev_name = (char*) args->rf.device_name.c_str(); + } + + char *dev_args = NULL; + if (args->rf.device_args.compare("auto")) { + dev_args = (char*) args->rf.device_args.c_str(); + } + + if(!radio.init(dev_args, dev_name)) + { + printf("Failed to find device %s with args %s\n", + args->rf.device_name.c_str(), args->rf.device_args.c_str()); + return false; + } + + // Set RF options + if (args->rf.time_adv_nsamples.compare("auto")) { + radio.set_tx_adv(atoi(args->rf.time_adv_nsamples.c_str())); + } + if (args->rf.burst_preamble.compare("auto")) { + radio.set_burst_preamble(atof(args->rf.burst_preamble.c_str())); + } + + radio.set_manual_calibration(&args->rf_cal); + + radio.set_rx_gain(args->rf.rx_gain); + radio.set_tx_gain(args->rf.tx_gain); + + if (args->rf.dl_freq < 0) { + args->rf.dl_freq = 1e6*srslte_band_fd(args->rf.dl_earfcn); + if (args->rf.dl_freq < 0) { + fprintf(stderr, "Error getting DL frequency for EARFCN=%d\n", args->rf.dl_earfcn); + return false; + } + } + if (args->rf.ul_freq < 0) { + if (args->rf.ul_earfcn == 0) { + args->rf.ul_earfcn = srslte_band_ul_earfcn(args->rf.dl_earfcn); + } + args->rf.ul_freq = 1e6*srslte_band_fu(args->rf.ul_earfcn); + if (args->rf.ul_freq < 0) { + fprintf(stderr, "Error getting UL frequency for EARFCN=%d\n", args->rf.dl_earfcn); + return false; + } + } + ((srslte::log_filter*) phy_log[0])->console("Setting frequency: DL=%.1f Mhz, UL=%.1f MHz\n", args->rf.dl_freq/1e6, args->rf.ul_freq/1e6); + + radio.set_tx_freq(args->rf.dl_freq); + radio.set_rx_freq(args->rf.ul_freq); + + radio.register_error_handler(rf_msg); + + srslte_cell_t cell_cfg; + phy_cfg_t phy_cfg; + rrc_cfg_t rrc_cfg; + + if (parse_cell_cfg(args, &cell_cfg)) { + fprintf(stderr, "Error parsing Cell configuration\n"); + return false; + } + if (parse_sibs(args, &rrc_cfg, &phy_cfg)) { + fprintf(stderr, "Error parsing SIB configuration\n"); + return false; + } + if (parse_rr(args, &rrc_cfg)) { + fprintf(stderr, "Error parsing Radio Resources configuration\n"); + return false; + } + if (parse_drb(args, &rrc_cfg)) { + fprintf(stderr, "Error parsing DRB configuration\n"); + return false; + } + rrc_cfg.inactivity_timeout_ms = args->expert.rrc_inactivity_timer; + + // Copy cell struct to rrc and phy + memcpy(&rrc_cfg.cell, &cell_cfg, sizeof(srslte_cell_t)); + memcpy(&phy_cfg.cell, &cell_cfg, sizeof(srslte_cell_t)); + + // Init all layers + phy.init(&args->expert.phy, &phy_cfg, &radio, &mac, phy_log); + mac.init(&args->expert.mac, &cell_cfg, &phy, &rlc, &rrc, &mac_log); + rlc.init(&pdcp, &rrc, &mac, &mac, &rlc_log); + pdcp.init(&rlc, &rrc, >pu, &pdcp_log); + rrc.init(&rrc_cfg, &phy, &mac, &rlc, &pdcp, &s1ap, >pu, &rrc_log); + s1ap.init(args->enb.s1ap, &rrc, &s1ap_log); + gtpu.init(args->enb.s1ap.gtp_bind_addr, args->enb.s1ap.mme_addr, &pdcp, >pu_log); + + started = true; + return true; +} + +void enb::pregenerate_signals(bool enable) +{ + //phy.enable_pregen_signals(enable); +} + +void enb::stop() +{ + if(started) + { + mac.stop(); + phy.stop(); + usleep(1e5); + + rlc.stop(); + pdcp.stop(); + gtpu.stop(); + rrc.stop(); + + usleep(1e5); + if(args->pcap.enable) + { + mac_pcap.close(); + } + radio.stop(); + started = false; + } +} + +void enb::start_plot() { + phy.start_plot(); +} + +bool enb::get_metrics(enb_metrics_t &m) +{ + m.rf = rf_metrics; + bzero(&rf_metrics, sizeof(rf_metrics_t)); + rf_metrics.rf_error = false; // Reset error flag + + phy.get_metrics(m.phy); + mac.get_metrics(m.mac); + rrc.get_metrics(m.rrc); + s1ap.get_metrics(m.s1ap); + + m.running = started; + return true; +} + +void enb::rf_msg(srslte_rf_error_t error) +{ + enb *u = enb::get_instance(); + u->handle_rf_msg(error); +} + +void enb::handle_rf_msg(srslte_rf_error_t error) +{ + if(error.type == srslte_rf_error_t::SRSLTE_RF_ERROR_OVERFLOW) { + rf_metrics.rf_o++; + rf_metrics.rf_error = true; + rf_log.warning("Overflow\n"); + }else if(error.type == srslte_rf_error_t::SRSLTE_RF_ERROR_UNDERFLOW) { + rf_metrics.rf_u++; + rf_metrics.rf_error = true; + rf_log.warning("Underflow\n"); + } else if(error.type == srslte_rf_error_t::SRSLTE_RF_ERROR_LATE) { + rf_metrics.rf_l++; + rf_metrics.rf_error = true; + rf_log.warning("Late\n"); + } else if (error.type == srslte_rf_error_t::SRSLTE_RF_ERROR_OTHER) { + std::string str(error.msg); + str.erase(std::remove(str.begin(), str.end(), '\n'), str.end()); + str.erase(std::remove(str.begin(), str.end(), '\r'), str.end()); + str.push_back('\n'); + rf_log.info(str); + } +} + +srslte::LOG_LEVEL_ENUM enb::level(std::string l) +{ + boost::to_upper(l); + if("NONE" == l){ + return srslte::LOG_LEVEL_NONE; + }else if("ERROR" == l){ + return srslte::LOG_LEVEL_ERROR; + }else if("WARNING" == l){ + return srslte::LOG_LEVEL_WARNING; + }else if("INFO" == l){ + return srslte::LOG_LEVEL_INFO; + }else if("DEBUG" == l){ + return srslte::LOG_LEVEL_DEBUG; + }else{ + return srslte::LOG_LEVEL_NONE; + } +} + +} // namespace srsenb diff --git a/srsenb/src/enb_cfg_parser.cc b/srsenb/src/enb_cfg_parser.cc new file mode 100644 index 000000000..3beb85a65 --- /dev/null +++ b/srsenb/src/enb_cfg_parser.cc @@ -0,0 +1,1125 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2017 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of srsLTE. + * + * srsUE 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. + * + * srsUE 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/asn1/liblte_common.h" +#include "srslte/asn1/liblte_rrc.h" +#include "cfg_parser.h" +#include "srslte/srslte.h" + +#include "parser.h" +#include "enb_cfg_parser.h" + +namespace srsenb { + +int enb::parse_cell_cfg(all_args_t *args, srslte_cell_t *cell) { + cell->id = args->enb.pci; + cell->cp = SRSLTE_CP_NORM; + cell->nof_ports = 1; + cell->nof_prb = args->enb.n_prb; + + LIBLTE_RRC_PHICH_CONFIG_STRUCT phichcfg; + + parser::section phy_cnfg("phy_cnfg"); + parser::section phich_cnfg("phich_cnfg"); + phy_cnfg.add_subsection(&phich_cnfg); + phich_cnfg.add_field( + new parser::field_enum_str + ("duration", &phichcfg.dur, liblte_rrc_phich_duration_text, LIBLTE_RRC_PHICH_DURATION_N_ITEMS) + ); + phich_cnfg.add_field( + new parser::field_enum_str + ("resources", &phichcfg.res, liblte_rrc_phich_resource_text, LIBLTE_RRC_PHICH_RESOURCE_N_ITEMS) + ); + parser::parse_section(args->enb_files.rr_config, &phy_cnfg); + + cell->phich_length = (srslte_phich_length_t) phichcfg.dur; + cell->phich_resources = (srslte_phich_resources_t) phichcfg.res; + + if (!srslte_cell_isvalid(cell)) { + fprintf(stderr, "Invalid cell parameters: nof_prb=%d, cell_id=%d\n", args->enb.n_prb, args->enb.s1ap.cell_id); + return -1; + } + + return 0; +} + +int field_sched_info::parse(libconfig::Setting &root) +{ + data->N_sched_info = root.getLength(); + for (uint32_t i=0;iN_sched_info;i++) { + uint32_t periodicity = 0; + if (!root[i].lookupValue("si_periodicity", periodicity)) { + fprintf(stderr, "Missing field si_periodicity in sched_info=%d\n", i); + return -1; + } + int k=0; + while(ksched_info[i].si_periodicity = (LIBLTE_RRC_SI_PERIODICITY_ENUM) k; + if (root[i].exists("si_mapping_info")) { + data->sched_info[i].N_sib_mapping_info = root[i]["si_mapping_info"].getLength(); + if (data->sched_info[i].N_sib_mapping_info < LIBLTE_RRC_MAX_SIB) { + for (uint32_t j=0;jsched_info[i].N_sib_mapping_info;j++) { + uint32_t sib_index = root[i]["si_mapping_info"][j]; + if (sib_index >= 3 && sib_index <= 13) { + data->sched_info[i].sib_mapping_info[j].sib_type = (LIBLTE_RRC_SIB_TYPE_ENUM) (sib_index-3); + } else { + fprintf(stderr, "Invalid SIB index %d for si_mapping_info=%d in sched_info=%d\n", sib_index, j, i); + return -1; + } + } + } else { + fprintf(stderr, "Number of si_mapping_info values exceeds maximum (%d)\n", LIBLTE_RRC_MAX_SIB); + return -1; + } + } else { + data->sched_info[i].N_sib_mapping_info = 0; + } + } + return 0; +} + + +int field_intra_neigh_cell_list::parse(libconfig::Setting &root) +{ + data->intra_freq_neigh_cell_list_size = root.getLength(); + for (uint32_t i=0;iintra_freq_neigh_cell_list_size && iintra_freq_neigh_cell_list[i].q_offset_range = (LIBLTE_RRC_Q_OFFSET_RANGE_ENUM) k; + + int phys_cell_id = 0; + if (!root[i].lookupValue("phys_cell_id", phys_cell_id)) { + fprintf(stderr, "Missing field phys_cell_id in neigh_cell=%d\n", i); + return -1; + } + data->intra_freq_neigh_cell_list[i].phys_cell_id = (uint16) phys_cell_id; + } + return 0; +} + +int field_intra_black_cell_list::parse(libconfig::Setting &root) +{ + data->intra_freq_black_cell_list_size = root.getLength(); + for (uint32_t i=0;iintra_freq_black_cell_list_size && iintra_freq_black_cell_list[i].range = (LIBLTE_RRC_PHYS_CELL_ID_RANGE_ENUM) k; + + int start = 0; + if (!root[i].lookupValue("start", start)) { + fprintf(stderr, "Missing field start in black_cell=%d\n", i); + return -1; + } + data->intra_freq_black_cell_list[i].start = (uint16) start; + } + return 0; +} + + +int enb::parse_sib1(std::string filename, LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1_STRUCT *data) +{ + parser::section sib1("sib1"); + + sib1.add_field( + new parser::field_enum_str + ("intra_freq_reselection", &data->intra_freq_reselection, liblte_rrc_intra_freq_reselection_text, LIBLTE_RRC_INTRA_FREQ_RESELECTION_N_ITEMS) + ); + sib1.add_field( + new parser::field("q_rx_lev_min", &data->q_rx_lev_min) + ); + sib1.add_field( + new parser::field("p_max", &data->p_max, &data->p_max_present) + ); + sib1.add_field( + new parser::field_enum_str + ("cell_barred", &data->cell_barred, liblte_rrc_cell_barred_text, LIBLTE_RRC_CELL_BARRED_N_ITEMS) + ); + sib1.add_field( + new parser::field_enum_num + ("si_window_length", &data->si_window_length, liblte_rrc_si_window_length_num, LIBLTE_RRC_SI_WINDOW_LENGTH_N_ITEMS) + ); + sib1.add_field( + new parser::field("system_info_value_tag", &data->system_info_value_tag) + ); + + // sched_info subsection uses a custom field class + parser::section sched_info("sched_info"); + sib1.add_subsection(&sched_info); + sched_info.add_field(new field_sched_info(data)); + + // Run parser with single section + return parser::parse_section(filename, &sib1); +} + +int enb::parse_sib2(std::string filename, LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT *data) +{ + parser::section sib2("sib2"); + + sib2.add_field( + new parser::field_enum_str + ("time_alignment_timer", &data->time_alignment_timer, + liblte_rrc_time_alignment_timer_text, LIBLTE_RRC_TIME_ALIGNMENT_TIMER_N_ITEMS) + ); + + parser::section freqinfo("freqInfo"); + sib2.add_subsection(&freqinfo); + freqinfo.add_field( + new parser::field + ("additional_spectrum_emission", &data->additional_spectrum_emission) + ); + freqinfo.add_field( + new parser::field ("ul_carrier_freq_present", &data->arfcn_value_eutra.present) + ); + freqinfo.add_field( + new parser::field ("ul_bw_present", &data->ul_bw.present) + ); + + // AC barring configuration + parser::section acbarring("ac_barring"); + sib2.add_subsection(&acbarring); + acbarring.set_optional(&data->ac_barring_info_present); + + acbarring.add_field( + new parser::field("ac_barring_for_emergency", &data->ac_barring_for_emergency) + ); + + parser::section acbarring_signalling("ac_barring_for_mo_signalling"); + acbarring.add_subsection(&acbarring_signalling); + acbarring_signalling.set_optional(&data->ac_barring_for_mo_signalling.enabled); + + acbarring_signalling.add_field( + new parser::field_enum_num + ("factor", &data->ac_barring_for_mo_signalling.factor, + liblte_rrc_ac_barring_factor_num, LIBLTE_RRC_AC_BARRING_FACTOR_N_ITEMS) + ); + acbarring_signalling.add_field( + new parser::field_enum_num + ("time", &data->ac_barring_for_mo_signalling.time, + liblte_rrc_ac_barring_time_num, LIBLTE_RRC_AC_BARRING_FACTOR_N_ITEMS) + ); + acbarring_signalling.add_field( + new parser::field("for_special_ac", &data->ac_barring_for_mo_signalling.for_special_ac) + ); + + parser::section acbarring_data("ac_barring_for_mo_data"); + acbarring.add_subsection(&acbarring_data); + acbarring_data.set_optional(&data->ac_barring_for_mo_data.enabled); + + acbarring_data.add_field( + new parser::field_enum_num + ("factor", &data->ac_barring_for_mo_data.factor, + liblte_rrc_ac_barring_factor_num, LIBLTE_RRC_AC_BARRING_FACTOR_N_ITEMS) + ); + acbarring_data.add_field( + new parser::field_enum_num + ("time", &data->ac_barring_for_mo_data.time, + liblte_rrc_ac_barring_time_num, LIBLTE_RRC_AC_BARRING_FACTOR_N_ITEMS) + ); + acbarring_data.add_field( + new parser::field("for_special_ac", &data->ac_barring_for_mo_data.for_special_ac) + ); + + + // UE timers and constants + parser::section uetimers("ue_timers_and_constants"); + sib2.add_subsection(&uetimers); + uetimers.add_field( + new parser::field_enum_num + ("t300", &data->ue_timers_and_constants.t300, liblte_rrc_t300_num, LIBLTE_RRC_T300_N_ITEMS) + ); + uetimers.add_field( + new parser::field_enum_num + ("t301", &data->ue_timers_and_constants.t301, liblte_rrc_t301_num, LIBLTE_RRC_T301_N_ITEMS) + ); + uetimers.add_field( + new parser::field_enum_num + ("t310", &data->ue_timers_and_constants.t310, liblte_rrc_t310_num, LIBLTE_RRC_T310_N_ITEMS) + ); + uetimers.add_field( + new parser::field_enum_num + ("n310", &data->ue_timers_and_constants.n310, liblte_rrc_n310_num, LIBLTE_RRC_N310_N_ITEMS) + ); + uetimers.add_field( + new parser::field_enum_num + ("t311", &data->ue_timers_and_constants.t311, liblte_rrc_t311_num, LIBLTE_RRC_T311_N_ITEMS) + ); + uetimers.add_field( + new parser::field_enum_num + ("n311", &data->ue_timers_and_constants.n311, liblte_rrc_n311_num, LIBLTE_RRC_N311_N_ITEMS) + ); + + + + + // Radio-resource configuration section + parser::section rr_config("rr_config_common_sib"); + sib2.add_subsection(&rr_config); + + rr_config.add_field( + new parser::field_enum_str + ("ul_cp_length", &data->rr_config_common_sib.ul_cp_length, + liblte_rrc_ul_cp_length_text, LIBLTE_RRC_UL_CP_LENGTH_N_ITEMS) + ); + + // RACH configuration + parser::section rach_cnfg("rach_cnfg"); + rr_config.add_subsection(&rach_cnfg); + + rach_cnfg.add_field( + new parser::field_enum_num + ("num_ra_preambles", &data->rr_config_common_sib.rach_cnfg.num_ra_preambles, + liblte_rrc_number_of_ra_preambles_num, LIBLTE_RRC_NUMBER_OF_RA_PREAMBLES_N_ITEMS) + ); + rach_cnfg.add_field( + new parser::field_enum_num + ("preamble_init_rx_target_pwr", &data->rr_config_common_sib.rach_cnfg.preamble_init_rx_target_pwr, + liblte_rrc_preamble_initial_received_target_power_num, LIBLTE_RRC_PREAMBLE_INITIAL_RECEIVED_TARGET_POWER_N_ITEMS) + ); + rach_cnfg.add_field( + new parser::field_enum_num + ("pwr_ramping_step", &data->rr_config_common_sib.rach_cnfg.pwr_ramping_step, + liblte_rrc_power_ramping_step_num, LIBLTE_RRC_POWER_RAMPING_STEP_N_ITEMS) + ); + rach_cnfg.add_field( + new parser::field_enum_num + ("preamble_trans_max", &data->rr_config_common_sib.rach_cnfg.preamble_trans_max, + liblte_rrc_preamble_trans_max_num, LIBLTE_RRC_PREAMBLE_TRANS_MAX_N_ITEMS) + ); + rach_cnfg.add_field( + new parser::field_enum_num + ("ra_resp_win_size", &data->rr_config_common_sib.rach_cnfg.ra_resp_win_size, + liblte_rrc_ra_response_window_size_num, LIBLTE_RRC_RA_RESPONSE_WINDOW_SIZE_N_ITEMS) + ); + rach_cnfg.add_field( + new parser::field_enum_num + ("mac_con_res_timer", &data->rr_config_common_sib.rach_cnfg.mac_con_res_timer, + liblte_rrc_mac_contention_resolution_timer_num, LIBLTE_RRC_MAC_CONTENTION_RESOLUTION_TIMER_N_ITEMS) + ); + rach_cnfg.add_field( + new parser::field("max_harq_msg3_tx", &data->rr_config_common_sib.rach_cnfg.max_harq_msg3_tx) + ); + + parser::section groupa_cnfg("preambles_group_a_cnfg"); + rach_cnfg.add_subsection(&groupa_cnfg); + groupa_cnfg.set_optional(&data->rr_config_common_sib.rach_cnfg.preambles_group_a_cnfg.present); + groupa_cnfg.add_field( + new parser::field_enum_num + ("size_of_ra", &data->rr_config_common_sib.rach_cnfg.preambles_group_a_cnfg.size_of_ra, + liblte_rrc_size_of_ra_preambles_group_a_num, LIBLTE_RRC_SIZE_OF_RA_PREAMBLES_GROUP_A_N_ITEMS) + ); + groupa_cnfg.add_field( + new parser::field_enum_num + ("msg_size", &data->rr_config_common_sib.rach_cnfg.preambles_group_a_cnfg.msg_size, + liblte_rrc_message_size_group_a_num, LIBLTE_RRC_MESSAGE_SIZE_GROUP_A_N_ITEMS) + ); + groupa_cnfg.add_field( + new parser::field_enum_num + ("msg_pwr_offset_group_b", &data->rr_config_common_sib.rach_cnfg.preambles_group_a_cnfg.msg_pwr_offset_group_b, + liblte_rrc_message_power_offset_group_b_num, LIBLTE_RRC_MESSAGE_POWER_OFFSET_GROUP_B_N_ITEMS) + ); + + + + // BCCH configuration + parser::section bcch_cnfg("bcch_cnfg"); + rr_config.add_subsection(&bcch_cnfg); + bcch_cnfg.add_field( + new parser::field_enum_num + ("modification_period_coeff", &data->rr_config_common_sib.bcch_cnfg.modification_period_coeff, + liblte_rrc_modification_period_coeff_num, LIBLTE_RRC_MODIFICATION_PERIOD_COEFF_N_ITEMS) + ); + + // PCCH configuration + parser::section pcch_cnfg("pcch_cnfg"); + rr_config.add_subsection(&pcch_cnfg); + pcch_cnfg.add_field( + new parser::field_enum_num + ("default_paging_cycle", &data->rr_config_common_sib.pcch_cnfg.default_paging_cycle, + liblte_rrc_default_paging_cycle_num, LIBLTE_RRC_DEFAULT_PAGING_CYCLE_N_ITEMS) + ); + pcch_cnfg.add_field( + new parser::field_enum_str + ("nB", &data->rr_config_common_sib.pcch_cnfg.nB, + liblte_rrc_nb_text, LIBLTE_RRC_NB_N_ITEMS) + ); + + // PRACH configuration + parser::section prach_cnfg("prach_cnfg"); + rr_config.add_subsection(&prach_cnfg); + prach_cnfg.add_field( + new parser::field("root_sequence_index", &data->rr_config_common_sib.prach_cnfg.root_sequence_index) + ); + parser::section prach_cnfg_info("prach_cnfg_info"); + prach_cnfg.add_subsection(&prach_cnfg_info); + prach_cnfg_info.add_field( + new parser::field("high_speed_flag", &data->rr_config_common_sib.prach_cnfg.prach_cnfg_info.high_speed_flag) + ); + prach_cnfg_info.add_field( + new parser::field("prach_config_index", &data->rr_config_common_sib.prach_cnfg.prach_cnfg_info.prach_config_index) + ); + prach_cnfg_info.add_field( + new parser::field("prach_freq_offset", &data->rr_config_common_sib.prach_cnfg.prach_cnfg_info.prach_freq_offset) + ); + prach_cnfg_info.add_field( + new parser::field("zero_correlation_zone_config", &data->rr_config_common_sib.prach_cnfg.prach_cnfg_info.zero_correlation_zone_config) + ); + + // PDSCH configuration + parser::section pdsch_cnfg("pdsch_cnfg"); + rr_config.add_subsection(&pdsch_cnfg); + pdsch_cnfg.add_field( + new parser::field("p_b", &data->rr_config_common_sib.pdsch_cnfg.p_b) + ); + pdsch_cnfg.add_field( + new parser::field("rs_power", &data->rr_config_common_sib.pdsch_cnfg.rs_power) + ); + + // PUSCH configuration + parser::section pusch_cnfg("pusch_cnfg"); + rr_config.add_subsection(&pusch_cnfg); + pusch_cnfg.add_field( + new parser::field("n_sb", &data->rr_config_common_sib.pusch_cnfg.n_sb) + ); + pusch_cnfg.add_field( + new parser::field_enum_str + ("hopping_mode", &data->rr_config_common_sib.pusch_cnfg.hopping_mode, + liblte_rrc_hopping_mode_text, LIBLTE_RRC_HOOPPING_MODE_N_ITEMS) + ); + pusch_cnfg.add_field( + new parser::field + ("pusch_hopping_offset", &data->rr_config_common_sib.pusch_cnfg.pusch_hopping_offset) + ); + pusch_cnfg.add_field( + new parser::field + ("enable_64_qam", &data->rr_config_common_sib.pusch_cnfg.enable_64_qam) + ); + + // PUSCH-ULRS configuration + parser::section ulrs_cnfg("ul_rs"); + pusch_cnfg.add_subsection(&ulrs_cnfg); + ulrs_cnfg.add_field( + new parser::field + ("cyclic_shift", &data->rr_config_common_sib.pusch_cnfg.ul_rs.cyclic_shift) + ); + ulrs_cnfg.add_field( + new parser::field + ("group_assignment_pusch", &data->rr_config_common_sib.pusch_cnfg.ul_rs.group_assignment_pusch) + ); + ulrs_cnfg.add_field( + new parser::field + ("group_hopping_enabled", &data->rr_config_common_sib.pusch_cnfg.ul_rs.group_hopping_enabled) + ); + ulrs_cnfg.add_field( + new parser::field + ("sequence_hopping_enabled", &data->rr_config_common_sib.pusch_cnfg.ul_rs.sequence_hopping_enabled) + ); + + // PUCCH configuration + parser::section pucch_cnfg("pucch_cnfg"); + rr_config.add_subsection(&pucch_cnfg); + pucch_cnfg.add_field( + new parser::field_enum_num + ("delta_pucch_shift", &data->rr_config_common_sib.pucch_cnfg.delta_pucch_shift, + liblte_rrc_delta_pucch_shift_num,LIBLTE_RRC_DELTA_PUCCH_SHIFT_N_ITEMS) + ); + pucch_cnfg.add_field( + new parser::field + ("n_rb_cqi", &data->rr_config_common_sib.pucch_cnfg.n_rb_cqi) + ); + pucch_cnfg.add_field( + new parser::field + ("n_cs_an", &data->rr_config_common_sib.pucch_cnfg.n_cs_an) + ); + pucch_cnfg.add_field( + new parser::field + ("n1_pucch_an", &data->rr_config_common_sib.pucch_cnfg.n1_pucch_an) + ); + + // UL PWR Ctrl configuration + parser::section ul_pwr_ctrl("ul_pwr_ctrl"); + rr_config.add_subsection(&ul_pwr_ctrl); + ul_pwr_ctrl.add_field( + new parser::field + ("p0_nominal_pusch", &data->rr_config_common_sib.ul_pwr_ctrl.p0_nominal_pusch) + ); + ul_pwr_ctrl.add_field( + new parser::field_enum_num + ("alpha", &data->rr_config_common_sib.ul_pwr_ctrl.alpha, + liblte_rrc_ul_power_control_alpha_num, LIBLTE_RRC_UL_POWER_CONTROL_ALPHA_N_ITEMS) + ); + ul_pwr_ctrl.add_field( + new parser::field + ("p0_nominal_pucch", &data->rr_config_common_sib.ul_pwr_ctrl.p0_nominal_pucch) + ); + ul_pwr_ctrl.add_field( + new parser::field + ("delta_preamble_msg3", &data->rr_config_common_sib.ul_pwr_ctrl.delta_preamble_msg3) + ); + + // Delta Flist PUCCH + parser::section delta_flist("delta_flist_pucch"); + ul_pwr_ctrl.add_subsection(&delta_flist); + delta_flist.add_field( + new parser::field_enum_num + ("format_1", &data->rr_config_common_sib.ul_pwr_ctrl.delta_flist_pucch.format_1, + liblte_rrc_delta_f_pucch_format_1_num, LIBLTE_RRC_DELTA_F_PUCCH_FORMAT_1_N_ITEMS) + ); + delta_flist.add_field( + new parser::field_enum_num + ("format_1b", &data->rr_config_common_sib.ul_pwr_ctrl.delta_flist_pucch.format_1b, + liblte_rrc_delta_f_pucch_format_1b_num, LIBLTE_RRC_DELTA_F_PUCCH_FORMAT_1B_N_ITEMS) + ); + delta_flist.add_field( + new parser::field_enum_num + ("format_2", &data->rr_config_common_sib.ul_pwr_ctrl.delta_flist_pucch.format_2, + liblte_rrc_delta_f_pucch_format_2_num, LIBLTE_RRC_DELTA_F_PUCCH_FORMAT_2_N_ITEMS) + ); + delta_flist.add_field( + new parser::field_enum_num + ("format_2a", &data->rr_config_common_sib.ul_pwr_ctrl.delta_flist_pucch.format_2a, + liblte_rrc_delta_f_pucch_format_2a_num, LIBLTE_RRC_DELTA_F_PUCCH_FORMAT_2A_N_ITEMS) + ); + delta_flist.add_field( + new parser::field_enum_num + ("format_2b", &data->rr_config_common_sib.ul_pwr_ctrl.delta_flist_pucch.format_2b, + liblte_rrc_delta_f_pucch_format_2b_num, LIBLTE_RRC_DELTA_F_PUCCH_FORMAT_2B_N_ITEMS) + ); + + // Run parser with single section + return parser::parse_section(filename, &sib2); +} + +int enb::parse_sib3(std::string filename, LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_3_STRUCT *data) +{ + parser::section sib3("sib3"); + + // CellReselectionInfoCommon + parser::section resel_common("cell_reselection_common"); + sib3.add_subsection(&resel_common); + + resel_common.add_field( + new parser::field_enum_num + ("q_hyst", &data->q_hyst, + liblte_rrc_q_hyst_num, LIBLTE_RRC_Q_HYST_N_ITEMS) + ); + + parser::section speed_resel("speed_state_resel_params"); + resel_common.add_subsection(&speed_resel); + resel_common.set_optional(&data->speed_state_resel_params.present); + + + parser::section q_hyst_sf("q_hyst_sf"); + speed_resel.add_subsection(&q_hyst_sf); + q_hyst_sf.add_field( + new parser::field_enum_num + ("medium", &data->speed_state_resel_params.q_hyst_sf.medium, + liblte_rrc_sf_medium_num, LIBLTE_RRC_SF_MEDIUM_N_ITEMS) + ); + q_hyst_sf.add_field( + new parser::field_enum_num + ("high", &data->speed_state_resel_params.q_hyst_sf.high, + liblte_rrc_sf_high_num, LIBLTE_RRC_SF_HIGH_N_ITEMS) + ); + + + parser::section mob_params("mobility_state_params"); + speed_resel.add_subsection(&mob_params); + mob_params.add_field( + new parser::field_enum_num + ("t_eval", &data->speed_state_resel_params.mobility_state_params.t_eval, + liblte_rrc_t_evaluation_num, LIBLTE_RRC_T_EVALUATION_N_ITEMS) + ); + mob_params.add_field( + new parser::field_enum_num + ("t_hyst_normal", &data->speed_state_resel_params.mobility_state_params.t_hyst_normal, + liblte_rrc_t_hyst_normal_num, LIBLTE_RRC_T_HYST_NORMAL_N_ITEMS) + ); + mob_params.add_field( + new parser::field + ("n_cell_change_medium", &data->speed_state_resel_params.mobility_state_params.n_cell_change_medium) + ); + mob_params.add_field( + new parser::field + ("n_cell_change_high", &data->speed_state_resel_params.mobility_state_params.n_cell_change_high) + ); + + // CellReselectionServingFreqInfo + parser::section resel_serving("cell_reselection_serving"); + sib3.add_subsection(&resel_serving); + + resel_serving.add_field( + new parser::field ("s_non_intra_search", &data->s_non_intra_search, &data->s_non_intra_search_present) + ); + resel_serving.add_field( + new parser::field("thresh_serving_low", &data->thresh_serving_low) + ); + resel_serving.add_field( + new parser::field("cell_resel_prio", &data->cell_resel_prio) + ); + + + // intraFreqCellReselectionInfo + parser::section intra_freq("intra_freq_reselection"); + sib3.add_subsection(&intra_freq); + + intra_freq.add_field( + new parser::field("q_rx_lev_min", &data->q_rx_lev_min) + ); + intra_freq.add_field( + new parser::field("p_max", &data->p_max, &data->p_max_present) + ); + intra_freq.add_field( + new parser::field("s_intra_search", &data->s_intra_search, &data->s_intra_search_present) + ); + intra_freq.add_field( + new parser::field_enum_num + ("allowed_meas_bw", &data->allowed_meas_bw, + liblte_rrc_allowed_meas_bandwidth_num, LIBLTE_RRC_ALLOWED_MEAS_BANDWIDTH_N_ITEMS, + &data->allowed_meas_bw_present) + ); + intra_freq.add_field( + new parser::field("presence_ant_port_1", &data->presence_ant_port_1) + ); + intra_freq.add_field( + new parser::field("neigh_cell_cnfg", &data->neigh_cell_cnfg) + ); + intra_freq.add_field( + new parser::field("t_resel_eutra", &data->t_resel_eutra) + ); + parser::section t_resel_eutra_sf("t_resel_eutra_sf"); + intra_freq.add_subsection(&t_resel_eutra_sf); + t_resel_eutra_sf.set_optional(&data->t_resel_eutra_sf_present); + + t_resel_eutra_sf.add_field( + new parser::field_enum_num + ("sf_medium", &data->t_resel_eutra_sf.sf_medium, + liblte_rrc_sssf_medium_num, LIBLTE_RRC_SSSF_MEDIUM_N_ITEMS) + ); + t_resel_eutra_sf.add_field( + new parser::field_enum_num + ("sf_high", &data->t_resel_eutra_sf.sf_high, + liblte_rrc_sssf_high_num, LIBLTE_RRC_SSSF_HIGH_N_ITEMS) + ); + + // Run parser with single section + return parser::parse_section(filename, &sib3); +} + +int enb::parse_sib4(std::string filename, LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_4_STRUCT *data) +{ + parser::section sib4("sib4"); + + // csg-PhysCellIdRange + parser::section csg_range("csg_phys_cell_id_range"); + sib4.add_subsection(&csg_range); + csg_range.set_optional(&data->csg_phys_cell_id_range_present); + csg_range.add_field( + new parser::field_enum_num + ("range", &data->csg_phys_cell_id_range.range, + liblte_rrc_phys_cell_id_range_num, LIBLTE_RRC_PHYS_CELL_ID_RANGE_N_ITEMS) + ); + csg_range.add_field( + new parser::field("start", &data->csg_phys_cell_id_range.start) + ); + + // intraFreqNeighCellList + parser::section intra_neigh("intra_freq_neigh_cell_list"); + sib4.add_subsection(&intra_neigh); + bool dummy_bool = false; + intra_neigh.set_optional(&dummy_bool); + intra_neigh.add_field(new field_intra_neigh_cell_list(data)); + + // intraFreqBlackCellList + parser::section intra_black("intra_freq_black_cell_list"); + sib4.add_subsection(&intra_black); + intra_black.set_optional(&dummy_bool); + intra_black.add_field(new field_intra_black_cell_list(data)); + + // Run parser with single section + return parser::parse_section(filename, &sib4); +} + + +uint32_t HexToBytes(const std::string& str, uint8_t *char_value, uint32_t buff_len) { + uint32_t i=0; + for (i = 0; i < str.length() && i("hnb_name", &hnb_name, &name_enabled)); + sib9.add_field(new parser::field("hex_value", &hex_value, &hex_enabled)); + + // Run parser with single section + if (!parser::parse_section(filename, &sib9)) { + data->hnb_name_present = true; + if (name_enabled) { + strncpy((char*) data->hnb_name, hnb_name.c_str(), 48); + data->hnb_name_size = strnlen(hnb_name.c_str(), 48); + } else if (hex_enabled) { + data->hnb_name_size = HexToBytes(hex_value, data->hnb_name, 48); + } else { + data->hnb_name_present = false; + } + return 0; + } else { + return -1; + } +} + +int enb::parse_sibs(all_args_t *args, rrc_cfg_t *rrc_cfg, phy_cfg_t *phy_config_common) +{ + LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1_STRUCT *sib1 = &rrc_cfg->sibs[0].sib.sib1; + rrc_cfg->sibs[0].sib_type = LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1; + LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT *sib2 = &rrc_cfg->sibs[1].sib.sib2; + rrc_cfg->sibs[1].sib_type = LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2; + LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_3_STRUCT *sib3 = &rrc_cfg->sibs[2].sib.sib3; + rrc_cfg->sibs[2].sib_type = LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_3; + LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_4_STRUCT *sib4 = &rrc_cfg->sibs[3].sib.sib4; + rrc_cfg->sibs[3].sib_type = LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_4; + LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_9_STRUCT *sib9 = &rrc_cfg->sibs[8].sib.sib9; + rrc_cfg->sibs[8].sib_type = LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_9; + + + // Read SIB1 configuration from file + bzero(sib1, sizeof(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1_STRUCT)); + if (parse_sib1(args->enb_files.sib_config, sib1)) { + return -1; + } + + // Fill rest of data from enb config + sib1->cell_id = args->enb.s1ap.enb_id; + sib1->tracking_area_code = args->enb.s1ap.tac; + sib1->freq_band_indicator = srslte_band_get_band(args->rf.dl_earfcn); + sib1->N_plmn_ids = 1; + sib1->plmn_id[0].id.mcc = args->enb.s1ap.mcc; + sib1->plmn_id[0].id.mnc = args->enb.s1ap.mnc; + sib1->plmn_id[0].resv_for_oper = LIBLTE_RRC_NOT_RESV_FOR_OPER; + sib1->cell_barred = LIBLTE_RRC_CELL_NOT_BARRED; + sib1->q_rx_lev_min_offset = 0; + + // Generate SIB2 + bzero(sib2, sizeof(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT)); + if (parse_sib2(args->enb_files.sib_config, sib2)) { + return -1; + } + + // SRS not yet supported + sib2->rr_config_common_sib.srs_ul_cnfg.present = false; + if (sib2->ul_bw.present) { + switch(args->enb.n_prb) { + case 6: + sib2->ul_bw.bw = LIBLTE_RRC_UL_BW_N6; + break; + case 15: + sib2->ul_bw.bw = LIBLTE_RRC_UL_BW_N15; + break; + case 25: + sib2->ul_bw.bw = LIBLTE_RRC_UL_BW_N25; + break; + case 50: + sib2->ul_bw.bw = LIBLTE_RRC_UL_BW_N50; + break; + case 75: + sib2->ul_bw.bw = LIBLTE_RRC_UL_BW_N75; + break; + case 100: + sib2->ul_bw.bw = LIBLTE_RRC_UL_BW_N100; + break; + } + } + if (sib2->arfcn_value_eutra.present) { + sib2->arfcn_value_eutra.value = args->rf.ul_earfcn; + } + + // Generate SIB3 if defined in mapping info + if (sib_is_present(sib1->sched_info, sib1->N_sched_info, LIBLTE_RRC_SIB_TYPE_3)) { + bzero(sib3, sizeof(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_3_STRUCT)); + if (parse_sib3(args->enb_files.sib_config, sib3)) { + return -1; + } + } + + // Generate SIB4 if defined in mapping info + if (sib_is_present(sib1->sched_info, sib1->N_sched_info, LIBLTE_RRC_SIB_TYPE_4)) { + bzero(sib4, sizeof(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_4_STRUCT)); + if (parse_sib4(args->enb_files.sib_config, sib4)) { + return -1; + } + } + + // Generate SIB9 if defined in mapping info + if (sib_is_present(sib1->sched_info, sib1->N_sched_info, LIBLTE_RRC_SIB_TYPE_9)) { + bzero(sib9, sizeof(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_9_STRUCT)); + if (parse_sib9(args->enb_files.sib_config, sib9)) { + return -1; + } + } + + // Copy PHY common configuration + bzero(phy_config_common, sizeof(phy_cfg_t)); + memcpy(&phy_config_common->prach_cnfg, &sib2->rr_config_common_sib.prach_cnfg, sizeof(LIBLTE_RRC_PRACH_CONFIG_SIB_STRUCT)); + memcpy(&phy_config_common->pdsch_cnfg, &sib2->rr_config_common_sib.pdsch_cnfg, sizeof(LIBLTE_RRC_PDSCH_CONFIG_COMMON_STRUCT)); + memcpy(&phy_config_common->pusch_cnfg, &sib2->rr_config_common_sib.pusch_cnfg, sizeof(LIBLTE_RRC_PUSCH_CONFIG_COMMON_STRUCT)); + memcpy(&phy_config_common->pucch_cnfg, &sib2->rr_config_common_sib.pucch_cnfg, sizeof(LIBLTE_RRC_PUCCH_CONFIG_COMMON_STRUCT)); + memcpy(&phy_config_common->srs_ul_cnfg, &sib2->rr_config_common_sib.srs_ul_cnfg, sizeof(LIBLTE_RRC_SRS_UL_CONFIG_COMMON_STRUCT)); + + return 0; +} + +bool enb::sib_is_present(LIBLTE_RRC_SCHEDULING_INFO_STRUCT *sched_info, uint32_t nof_sched_info, LIBLTE_RRC_SIB_TYPE_ENUM sib_num) +{ + for (uint32_t i=0;imac_cnfg.phr_cnfg.setup_present); + phr_cnfg.add_field( + new parser::field_enum_str + ("dl_pathloss_change", &rrc_cfg->mac_cnfg.phr_cnfg.dl_pathloss_change, + liblte_rrc_dl_pathloss_change_text, LIBLTE_RRC_DL_PATHLOSS_CHANGE_N_ITEMS) + ); + phr_cnfg.add_field( + new parser::field_enum_num + ("periodic_phr_timer", &rrc_cfg->mac_cnfg.phr_cnfg.periodic_phr_timer, + liblte_rrc_periodic_phr_timer_num, LIBLTE_RRC_PERIODIC_PHR_TIMER_N_ITEMS) + ); + phr_cnfg.add_field( + new parser::field_enum_num + ("prohibit_phr_timer", &rrc_cfg->mac_cnfg.phr_cnfg.prohibit_phr_timer, + liblte_rrc_prohibit_phr_timer_num, LIBLTE_RRC_PROHIBIT_PHR_TIMER_N_ITEMS) + ); + + parser::section ulsch_cnfg("ulsch_cnfg"); + mac_cnfg.add_subsection(&ulsch_cnfg); + + rrc_cfg->mac_cnfg.ulsch_cnfg.tti_bundling = false; + ulsch_cnfg.add_field( + new parser::field_enum_num + ("max_harq_tx", &rrc_cfg->mac_cnfg.ulsch_cnfg.max_harq_tx, + liblte_rrc_max_harq_tx_num, LIBLTE_RRC_MAX_HARQ_TX_N_ITEMS, + &rrc_cfg->mac_cnfg.ulsch_cnfg.max_harq_tx_present) + ); + ulsch_cnfg.add_field( + new parser::field_enum_num + ("periodic_bsr_timer", &rrc_cfg->mac_cnfg.ulsch_cnfg.periodic_bsr_timer, + liblte_rrc_periodic_bsr_timer_num, LIBLTE_RRC_PERIODIC_BSR_TIMER_N_ITEMS, + &rrc_cfg->mac_cnfg.ulsch_cnfg.periodic_bsr_timer_present) + ); + + ulsch_cnfg.add_field( + new parser::field_enum_num + ("retx_bsr_timer", &rrc_cfg->mac_cnfg.ulsch_cnfg.retx_bsr_timer, + liblte_rrc_retransmission_bsr_timer_num, LIBLTE_RRC_RETRANSMISSION_BSR_TIMER_N_ITEMS) + ); + + mac_cnfg.add_field( + new parser::field_enum_num + ("time_alignment_timer", &rrc_cfg->mac_cnfg.time_alignment_timer, + liblte_rrc_time_alignment_timer_num, LIBLTE_RRC_TIME_ALIGNMENT_TIMER_N_ITEMS) + ); + + + /* PHY config section */ + parser::section phy_cfg("phy_cnfg"); + + parser::section pusch_cnfg_ded("pusch_cnfg_ded"); + phy_cfg.add_subsection(&pusch_cnfg_ded); + + pusch_cnfg_ded.add_field(new parser::field ("beta_offset_ack_idx", &rrc_cfg->pusch_cfg.beta_offset_ack_idx)); + pusch_cnfg_ded.add_field(new parser::field ("beta_offset_ri_idx", &rrc_cfg->pusch_cfg.beta_offset_ri_idx)); + pusch_cnfg_ded.add_field(new parser::field ("beta_offset_cqi_idx", &rrc_cfg->pusch_cfg.beta_offset_cqi_idx)); + + parser::section sched_request_cnfg("sched_request_cnfg"); + phy_cfg.add_subsection(&sched_request_cnfg); + + sched_request_cnfg.add_field( + new parser::field_enum_num + ("dsr_trans_max", &rrc_cfg->sr_cfg.dsr_max, + liblte_rrc_dsr_trans_max_num, LIBLTE_RRC_DSR_TRANS_MAX_N_ITEMS) + ); + sched_request_cnfg.add_field(new parser::field ("period", &rrc_cfg->sr_cfg.period)); + sched_request_cnfg.add_field(new parser::field ("nof_prb", &rrc_cfg->sr_cfg.nof_prb)); + sched_request_cnfg.add_field(new field_sf_mapping(rrc_cfg->sr_cfg.sf_mapping, &rrc_cfg->sr_cfg.nof_subframes)); + + parser::section cqi_report_cnfg("cqi_report_cnfg"); + phy_cfg.add_subsection(&cqi_report_cnfg); + + cqi_report_cnfg.add_field( + new parser::field_enum_str + ("mode", &rrc_cfg->cqi_cfg.mode, + rrc_cfg_cqi_mode_text, RRC_CFG_CQI_MODE_N_ITEMS) + ); + cqi_report_cnfg.add_field(new parser::field ("period", &rrc_cfg->cqi_cfg.period)); + cqi_report_cnfg.add_field(new parser::field ("nof_prb", &rrc_cfg->cqi_cfg.nof_prb)); + cqi_report_cnfg.add_field(new parser::field ("simultaneousAckCQI", &rrc_cfg->cqi_cfg.simultaneousAckCQI)); + cqi_report_cnfg.add_field(new field_sf_mapping(rrc_cfg->cqi_cfg.sf_mapping, &rrc_cfg->cqi_cfg.nof_subframes)); + + // Run parser with two sections + parser p(args->enb_files.rr_config); + p.add_section(&mac_cnfg); + p.add_section(&phy_cfg); + return p.parse(); +} + +int field_sf_mapping::parse(libconfig::Setting &root) +{ + *nof_subframes = root["subframe"].getLength(); + for (uint32_t i=0;i<*nof_subframes;i++) { + sf_mapping[i] = root["subframe"][i]; + } + return 0; +} + + + + + + + +int enb::parse_drb(all_args_t* args, rrc_cfg_t* rrc_cfg) +{ + parser::section qci("qci_config"); + qci.add_field(new field_qci(rrc_cfg->qci_cfg)); + return parser::parse_section(args->enb_files.drb_config, &qci); +} + +int field_qci::parse(libconfig::Setting &root) +{ + uint32_t nof_qci = root.getLength(); + + bzero(cfg, sizeof(rrc_cfg_qci_t)*MAX_NOF_QCI); + + for (uint32_t i=0;i discard_timer + ("discard_timer", &cfg[qci].pdcp_cfg.discard_timer, + liblte_rrc_discard_timer_num, LIBLTE_RRC_DISCARD_TIMER_N_ITEMS); + if (discard_timer.parse(q["pdcp_config"])) { + cfg[qci].pdcp_cfg.discard_timer_present = false; + } else { + cfg[qci].pdcp_cfg.discard_timer_present = true; + } + + parser::field_enum_num pdcp_sn_size + ("pdcp_sn_size", &cfg[qci].pdcp_cfg.rlc_um_pdcp_sn_size, + liblte_rrc_pdcp_sn_size_num, LIBLTE_RRC_PDCP_SN_SIZE_N_ITEMS); + + if (pdcp_sn_size.parse(q["pdcp_config"])) { + cfg[qci].pdcp_cfg.rlc_um_pdcp_sn_size_present = false; + } else { + cfg[qci].pdcp_cfg.rlc_um_pdcp_sn_size_present = true; + } + + if (q["pdcp_config"].lookupValue("status_report_required", cfg[qci].pdcp_cfg.rlc_am_status_report_required)) { + cfg[qci].pdcp_cfg.rlc_am_status_report_required_present = true; + } else { + cfg[qci].pdcp_cfg.rlc_am_status_report_required_present = false; + } + + // Parse RLC section + if (q["rlc_config"].exists("ul_am")) { + cfg[qci].rlc_cfg.rlc_mode = LIBLTE_RRC_RLC_MODE_AM; + } else if (q["rlc_config"].exists("ul_um") && q["rlc_config"].exists("dl_um")) { + cfg[qci].rlc_cfg.rlc_mode = LIBLTE_RRC_RLC_MODE_UM_BI; + } else if (q["rlc_config"].exists("ul_um") && !q["rlc_config"].exists("dl_um")) { + cfg[qci].rlc_cfg.rlc_mode = LIBLTE_RRC_RLC_MODE_UM_UNI_UL; + } else if (!q["rlc_config"].exists("ul_um") && q["rlc_config"].exists("dl_um")) { + cfg[qci].rlc_cfg.rlc_mode = LIBLTE_RRC_RLC_MODE_UM_UNI_DL; + } else { + fprintf(stderr, "Invalid combination of UL/DL UM/AM for qci=%d\n", qci); + return -1; + } + + // Parse RLC-UM section + if (q["rlc_config"].exists("ul_um")) { + + LIBLTE_RRC_UL_UM_RLC_STRUCT *rlc_cfg = &cfg[qci].rlc_cfg.ul_um_bi_rlc; + if (cfg[qci].rlc_cfg.rlc_mode == LIBLTE_RRC_RLC_MODE_UM_UNI_UL) { + rlc_cfg = &cfg[qci].rlc_cfg.ul_um_bi_rlc; + } + + parser::field_enum_num sn_field_len + ("sn_field_length", &rlc_cfg->sn_field_len, + liblte_rrc_sn_field_length_num, LIBLTE_RRC_SN_FIELD_LENGTH_N_ITEMS); + sn_field_len.parse(q["rlc_config"]["ul_um"]); + } + + if (q["rlc_config"].exists("dl_um")) { + + LIBLTE_RRC_DL_UM_RLC_STRUCT *rlc_cfg = &cfg[qci].rlc_cfg.dl_um_bi_rlc; + if (cfg[qci].rlc_cfg.rlc_mode == LIBLTE_RRC_RLC_MODE_UM_UNI_DL) { + rlc_cfg = &cfg[qci].rlc_cfg.dl_um_bi_rlc; + } + + parser::field_enum_num sn_field_len + ("sn_field_length", &rlc_cfg->sn_field_len, + liblte_rrc_sn_field_length_num, LIBLTE_RRC_SN_FIELD_LENGTH_N_ITEMS); + sn_field_len.parse(q["rlc_config"]["dl_um"]); + + parser::field_enum_num t_reordering + ("t_reordering", &rlc_cfg->t_reordering, + liblte_rrc_t_reordering_num, LIBLTE_RRC_T_REORDERING_N_ITEMS); + t_reordering.parse(q["rlc_config"]["dl_um"]); + } + + // Parse RLC-AM section + if (q["rlc_config"].exists("ul_am")) { + LIBLTE_RRC_UL_AM_RLC_STRUCT *rlc_cfg = &cfg[qci].rlc_cfg.ul_am_rlc; + + parser::field_enum_num t_poll_retx + ("t_poll_retx", &rlc_cfg->t_poll_retx, + liblte_rrc_t_poll_retransmit_num, LIBLTE_RRC_T_POLL_RETRANSMIT_N_ITEMS); + t_poll_retx.parse(q["rlc_config"]["ul_am"]); + + parser::field_enum_num poll_pdu + ("poll_pdu", &rlc_cfg->poll_pdu, + liblte_rrc_poll_pdu_num, LIBLTE_RRC_POLL_PDU_N_ITEMS); + poll_pdu.parse(q["rlc_config"]["ul_am"]); + + parser::field_enum_num poll_byte + ("poll_byte", &rlc_cfg->poll_byte, + liblte_rrc_poll_byte_num, LIBLTE_RRC_POLL_BYTE_N_ITEMS); + poll_byte.parse(q["rlc_config"]["ul_am"]); + + parser::field_enum_num max_retx_thresh + ("max_retx_thresh", &rlc_cfg->max_retx_thresh, + liblte_rrc_max_retx_threshold_num, LIBLTE_RRC_MAX_RETX_THRESHOLD_N_ITEMS); + max_retx_thresh.parse(q["rlc_config"]["ul_am"]); + } + + if (q["rlc_config"].exists("dl_am")) { + LIBLTE_RRC_DL_AM_RLC_STRUCT *rlc_cfg = &cfg[qci].rlc_cfg.dl_am_rlc; + + parser::field_enum_num t_reordering + ("t_reordering", &rlc_cfg->t_reordering, + liblte_rrc_t_reordering_num, LIBLTE_RRC_T_REORDERING_N_ITEMS); + t_reordering.parse(q["rlc_config"]["dl_am"]); + + parser::field_enum_num t_status_prohibit + ("t_status_prohibit", &rlc_cfg->t_status_prohibit, + liblte_rrc_t_status_prohibit_num, LIBLTE_RRC_T_STATUS_PROHIBIT_N_ITEMS); + t_status_prohibit.parse(q["rlc_config"]["dl_am"]); + } + + + // Parse logical channel configuration section + if (!q.exists("logical_channel_config")) { + fprintf(stderr, "Error section logical_channel_config not found for qci=%d\n", qci); + return -1; + } + LIBLTE_RRC_UL_SPECIFIC_PARAMETERS_STRUCT *lc_cfg = &cfg[qci].lc_cfg; + + parser::field priority ("priority", &lc_cfg->priority); + priority.parse(q["logical_channel_config"]); + + parser::field_enum_num prioritized_bit_rate + ("prioritized_bit_rate", &lc_cfg->prioritized_bit_rate, + liblte_rrc_prioritized_bit_rate_num, LIBLTE_RRC_PRIORITIZED_BIT_RATE_N_ITEMS); + prioritized_bit_rate.parse(q["logical_channel_config"]); + + parser::field_enum_num bucket_size_duration + ("bucket_size_duration", &lc_cfg->bucket_size_duration, + liblte_rrc_bucket_size_duration_num, LIBLTE_RRC_BUCKET_SIZE_DURATION_N_ITEMS); + bucket_size_duration.parse(q["logical_channel_config"]); + + parser::field log_chan_group ("log_chan_group", &lc_cfg->log_chan_group); + if (log_chan_group.parse(q["logical_channel_config"])) { + lc_cfg->log_chan_group_present = false; + } else { + lc_cfg->log_chan_group_present = true; + } + + + + + cfg[qci].configured = true; + } + + return 0; +} + +} diff --git a/srsenb/src/enb_cfg_parser.h b/srsenb/src/enb_cfg_parser.h new file mode 100644 index 000000000..d68fb87d8 --- /dev/null +++ b/srsenb/src/enb_cfg_parser.h @@ -0,0 +1,120 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2017 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of srsLTE. + * + * srsUE 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. + * + * srsUE 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 ENB_CFG_PARSER_SIB1_H +#define ENB_CFG_PARSER_SIB1_H + +#include +#include +#include +#include +#include +#include +#include "parser.h" + +#include "upper/rrc.h" +#include "srslte/asn1/liblte_rrc.h" + +namespace srsenb { + +using namespace libconfig; + +class field_sched_info : public parser::field_itf +{ +public: + field_sched_info(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1_STRUCT *data_) { data = data_; } + ~field_sched_info() {} + int parse(Setting &root); + const char* get_name() { + return "sched_info"; + } + +private: + LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1_STRUCT *data; +}; + +class field_intra_neigh_cell_list : public parser::field_itf +{ +public: + field_intra_neigh_cell_list(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_4_STRUCT *data_) { data = data_; } + ~field_intra_neigh_cell_list(){} + int parse(Setting &root); + const char* get_name() { + return "intra_neigh_cell_list"; + } + +private: + LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_4_STRUCT *data; +}; + +class field_intra_black_cell_list : public parser::field_itf +{ +public: + field_intra_black_cell_list(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_4_STRUCT *data_) { data = data_; } + ~field_intra_black_cell_list(){} + int parse(Setting &root); + const char* get_name() { + return "intra_black_cell_list"; + } + +private: + LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_4_STRUCT *data; +}; + +class field_sf_mapping : public parser::field_itf +{ +public: + field_sf_mapping(uint32_t *sf_mapping_, uint32_t *nof_subframes_) { sf_mapping = sf_mapping_; nof_subframes = nof_subframes_; } + ~field_sf_mapping(){} + int parse(Setting &root); + const char* get_name() { + return "sf_mapping"; + } + +private: + uint32_t *sf_mapping; + uint32_t *nof_subframes; +}; + +class field_qci : public parser::field_itf +{ +public: + field_qci(rrc_cfg_qci_t *cfg_) { cfg = cfg_; } + ~field_qci(){} + const char* get_name() { + return "field_cqi"; + } + + int parse(Setting &root); +private: + rrc_cfg_qci_t *cfg; +}; + + +} + +#endif + diff --git a/srsenb/src/mac/CMakeLists.txt b/srsenb/src/mac/CMakeLists.txt new file mode 100644 index 000000000..4369d11a4 --- /dev/null +++ b/srsenb/src/mac/CMakeLists.txt @@ -0,0 +1,5 @@ +file(GLOB SOURCES "*.cc") +add_library(srsenb_mac SHARED ${SOURCES}) +target_link_libraries(srsenb_mac) + + diff --git a/srsenb/src/mac/mac.cc b/srsenb/src/mac/mac.cc new file mode 100644 index 000000000..8bf88a662 --- /dev/null +++ b/srsenb/src/mac/mac.cc @@ -0,0 +1,757 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2017 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of srsLTE. + * + * srsUE 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. + * + * srsUE 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/. + * + */ + +#define Error(fmt, ...) log_h->error_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Warning(fmt, ...) log_h->warning_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Info(fmt, ...) log_h->info_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Debug(fmt, ...) log_h->debug_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) + +#include +#include +#include +#include + +#include "srslte/common/log.h" +#include "mac/mac.h" + +//#define WRITE_SIB_PCAP + +namespace srsenb { + +mac::mac() : timers_db((uint32_t) NOF_MAC_TIMERS), + rar_pdu_msg(sched_interface::MAX_RAR_LIST), + pdu_process_thread(this) +{ + started = false; + pcap = NULL; +} + +bool mac::init(mac_args_t *args_, srslte_cell_t *cell_, phy_interface_mac *phy, rlc_interface_mac *rlc, rrc_interface_mac *rrc, srslte::log *log_h_) +{ + started = false; + + if (cell_ && phy && rlc && log_h_ && args_) { + phy_h = phy; + rlc_h = rlc; + rrc_h = rrc; + log_h = log_h_; + + memcpy(&args, args_, sizeof(mac_args_t)); + memcpy(&cell, cell_, sizeof(srslte_cell_t)); + + scheduler.init(rrc, log_h); + // Set default scheduler (RR) + scheduler.set_metric(&sched_metric_dl_rr, &sched_metric_ul_rr); + + // Set default scheduler configuration + scheduler.set_sched_cfg(&args.sched); + + // Init softbuffer for SI messages + for (int i=0;iadd_rnti(SRSLTE_SIRNTI); + + /* Setup P-RNTI in PHY */ + phy_h->add_rnti(SRSLTE_PRNTI); + + /* Setup RA-RNTI in PHY */ + for (int i=0;i<10;i++) { + phy_h->add_rnti(1+i); + } +} + +uint32_t mac::get_unique_id() +{ + return upper_timers_thread.get_unique_id(); +} + +/* Front-end to upper-layer timers */ +srslte::timers::timer* mac::get(uint32_t timer_id) +{ + return upper_timers_thread.get(timer_id); +} + + +void mac::start_pcap(srslte::mac_pcap* pcap_) +{ + pcap = pcap_; + // Set pcap in all UEs for UL messages + for(std::map::iterator iter=ue_db.begin(); iter!=ue_db.end(); ++iter) { + ue *u = iter->second; + u->start_pcap(pcap); + } +} + +/******************************************************** + * + * RLC interface + * + *******************************************************/ +int mac::rlc_buffer_state(uint16_t rnti, uint32_t lc_id, uint32_t tx_queue, uint32_t retx_queue) +{ + if (ue_db.count(rnti)) { + return scheduler.dl_rlc_buffer_state(rnti, lc_id, tx_queue, retx_queue); + } else { + Error("User rnti=0x%x not found\n", rnti); + return -1; + } +} + +int mac::bearer_ue_cfg(uint16_t rnti, uint32_t lc_id, sched_interface::ue_bearer_cfg_t* cfg) +{ + if (ue_db.count(rnti)) { + return scheduler.bearer_ue_cfg(rnti, lc_id, cfg); + } else { + Error("User rnti=0x%x not found\n", rnti); + return -1; + } +} + +int mac::bearer_ue_rem(uint16_t rnti, uint32_t lc_id) +{ + if (ue_db.count(rnti)) { + return scheduler.bearer_ue_rem(rnti, lc_id); + } else { + Error("User rnti=0x%x not found\n", rnti); + return -1; + } +} + +void mac::phy_config_enabled(uint16_t rnti, bool enabled) +{ + scheduler.phy_config_enabled(rnti, enabled); +} + +// Update UE configuration +int mac::ue_cfg(uint16_t rnti, sched_interface::ue_cfg_t* cfg) +{ + if (ue_db.count(rnti)) { + + // Add RNTI to the PHY (pregerate signals) now instead of after PRACH + if (!ue_db[rnti]->is_phy_added) { + ue_db[rnti]->is_phy_added = true; + Info("Registering rnti=0x%x to PHY...\n", rnti); + // Register new user in PHY + if (phy_h->add_rnti(rnti)) { + Error("Registering new ue rnti=0x%x to PHY\n", rnti); + } + Info("Done registering rnti=0x%x to PHY...\n", rnti); + } + + // Update Scheduler configuration + if (scheduler.ue_cfg(rnti, cfg)) { + Error("Registering new UE rnti=0x%x to SCHED\n", rnti); + return -1; + } + return 0; + } else { + Error("User rnti=0x%x not found\n", rnti); + return -1; + } +} + +// Removes UE from DB +int mac::ue_rem(uint16_t rnti) +{ + if (ue_db.count(rnti)) { + scheduler.ue_rem(rnti); + phy_h->rem_rnti(rnti); + delete ue_db[rnti]; + ue_db.erase(rnti); + Info("User rnti=0x%x removed from MAC/PHY\n", rnti); + return 0; + } else { + Error("User rnti=0x%x not found\n", rnti); + return -1; + } +} + +int mac::cell_cfg(sched_interface::cell_cfg_t* cell_cfg) +{ + return scheduler.cell_cfg(cell_cfg); +} + +void mac::get_metrics(mac_metrics_t metrics[ENB_METRICS_MAX_USERS]) +{ + int cnt=0; + for(std::map::iterator iter=ue_db.begin(); iter!=ue_db.end(); ++iter) { + ue *u = iter->second; + u->metrics_read(&metrics[cnt]); + cnt++; + } +} + + + + +/******************************************************** + * + * PHY interface + * + *******************************************************/ + +void mac::rl_failure(uint16_t rnti) +{ + if (ue_db.count(rnti)) { + uint32_t nof_fails = ue_db[rnti]->rl_failure(); + if (nof_fails >= (uint32_t) args.link_failure_nof_err && args.link_failure_nof_err > 0) { + Info("Detected PUSCH failure for rnti=0x%x\n", rnti); + rrc_h->rl_failure(rnti); + ue_db[rnti]->rl_failure_reset(); + } + } else { + Error("User rnti=0x%x not found\n", rnti); + } +} + +void mac::rl_ok(uint16_t rnti) +{ + if (ue_db.count(rnti)) { + ue_db[rnti]->rl_failure_reset(); + } else { + Error("User rnti=0x%x not found\n", rnti); + } +} + +int mac::ack_info(uint32_t tti, uint16_t rnti, bool ack) +{ + log_h->step(tti); + uint32_t nof_bytes = scheduler.dl_ack_info(tti, rnti, ack); + ue_db[rnti]->metrics_tx(ack, nof_bytes); + + if (ack) { + if (nof_bytes > 64) { // do not count RLC status messages only + rrc_h->set_activity_user(rnti); + log_h->debug("DL activity rnti=0x%x, n_bytes=%d\n", rnti, nof_bytes); + } + } + return 0; +} + +int mac::crc_info(uint32_t tti, uint16_t rnti, uint32_t nof_bytes, bool crc) +{ + log_h->step(tti); + + if (ue_db.count(rnti)) { + ue_db[rnti]->set_tti(tti); + + ue_db[rnti]->metrics_rx(crc, nof_bytes); + + // push the pdu through the queue if received correctly + if (crc) { + ue_db[rnti]->push_pdu(tti, nof_bytes); + pdu_process_thread.notify(); + if (nof_bytes > 64) { // do not count RLC status messages only + rrc_h->set_activity_user(rnti); + log_h->debug("UL activity rnti=0x%x, n_bytes=%d\n", rnti, nof_bytes); + } + } else { + ue_db[rnti]->deallocate_pdu(tti); + } + + return scheduler.ul_crc_info(tti, rnti, crc); + } else { + Error("User rnti=0x%x not found\n", rnti); + return -1; + } +} + +int mac::cqi_info(uint32_t tti, uint16_t rnti, uint32_t cqi_value) +{ + log_h->step(tti); + + if (ue_db.count(rnti)) { + scheduler.dl_cqi_info(tti, rnti, cqi_value); + } else { + Error("User rnti=0x%x not found\n", rnti); + return -1; + } + return 0; +} + +int mac::snr_info(uint32_t tti, uint16_t rnti, float snr) +{ + log_h->step(tti); + + if (ue_db.count(rnti)) { + uint32_t cqi = srslte_cqi_from_snr(snr); + scheduler.ul_cqi_info(tti, rnti, cqi, 0); + } else { + Error("User rnti=0x%x not found\n", rnti); + return -1; + } + return 0; +} + +int mac::sr_detected(uint32_t tti, uint16_t rnti) +{ + log_h->step(tti); + + if (ue_db.count(rnti)) { + scheduler.ul_sr_info(tti, rnti); + } else { + Error("User rnti=0x%x not found\n", rnti); + return -1; + } + return 0; +} + +int mac::rach_detected(uint32_t tti, uint32_t preamble_idx, uint32_t time_adv) +{ + log_h->step(tti); + + // Find empty slot for pending rars + uint32_t ra_id=0; + while(pending_rars[ra_id].temp_crnti && ra_idconfig(last_rnti, cell.nof_prb, &scheduler, rrc_h, rlc_h, log_h); + + // Set PCAP if available + if (pcap) { + ue_db[last_rnti]->start_pcap(pcap); + } + // Save RA info + pending_rars[ra_id].preamble_idx = preamble_idx; + pending_rars[ra_id].ta_cmd = time_adv; + pending_rars[ra_id].temp_crnti = last_rnti; + + // Add new user to the scheduler so that it can RX/TX SRB0 + sched_interface::ue_cfg_t uecfg; + bzero(&uecfg, sizeof(sched_interface::ue_cfg_t)); + uecfg.ue_bearers[0].direction = srsenb::sched_interface::ue_bearer_cfg_t::BOTH; + if (scheduler.ue_cfg(last_rnti, &uecfg)) { + Error("Registering new user rnti=0x%x to SCHED\n", last_rnti); + return -1; + } + + // Register new user in RRC + rrc_h->add_user(last_rnti); + + // Trigger scheduler RACH + scheduler.dl_rach_info(tti, ra_id, last_rnti, 7); + + log_h->info("RACH: tti=%d, preamble=%d, offset=%d, temp_crnti=0x%x\n", + tti, preamble_idx, time_adv, last_rnti); + log_h->console("RACH: tti=%d, preamble=%d, offset=%d, temp_crnti=0x%x\n", + tti, preamble_idx, time_adv, last_rnti); + + // Increae RNTI counter + last_rnti++; + if (last_rnti >= 60000) { + last_rnti = 70; + } + return 0; +} + +int mac::get_dl_sched(uint32_t tti, dl_sched_t *dl_sched_res) +{ + log_step_dl(tti); + + if (!started) { + return 0; + } + + if (!dl_sched_res) { + return SRSLTE_ERROR_INVALID_INPUTS; + } + + // Run scheduler with current info + sched_interface::dl_sched_res_t sched_result; + bzero(&sched_result, sizeof(sched_interface::dl_sched_res_t)); + if (scheduler.dl_sched(tti, &sched_result) < 0) { + Error("Running scheduler\n"); + return SRSLTE_ERROR; + } + + int n = 0; + + // Copy data grants + for (uint32_t i=0;isched_grants[n].rnti = rnti; + memcpy(&dl_sched_res->sched_grants[n].grant, &sched_result.data[i].dci, sizeof(srslte_ra_dl_dci_t)); + memcpy(&dl_sched_res->sched_grants[n].location, &sched_result.data[i].dci_location, sizeof(srslte_dci_location_t)); + + dl_sched_res->sched_grants[n].softbuffer = ue_db[rnti]->get_tx_softbuffer(sched_result.data[i].dci.harq_process); + + // Get PDU if it's a new transmission + if (sched_result.data[i].nof_pdu_elems > 0) { + dl_sched_res->sched_grants[n].data = ue_db[rnti]->generate_pdu(sched_result.data[i].pdu, + sched_result.data[i].nof_pdu_elems, + sched_result.data[i].tbs); + srslte_softbuffer_tx_reset_tbs(dl_sched_res->sched_grants[n].softbuffer, sched_result.data[i].tbs); + + if (pcap) { + pcap->write_dl_crnti(dl_sched_res->sched_grants[n].data, sched_result.data[i].tbs, rnti, true, tti); + } + + } else { + dl_sched_res->sched_grants[n].data = NULL; + } + n++; + } + + // Copy RAR grants + for (uint32_t i=0;isched_grants[n].rnti = sched_result.rar[i].rarnti; + memcpy(&dl_sched_res->sched_grants[n].grant, &sched_result.rar[i].dci, sizeof(srslte_ra_dl_dci_t)); + memcpy(&dl_sched_res->sched_grants[n].location, &sched_result.rar[i].dci_location, sizeof(srslte_dci_location_t)); + + // Set softbuffer (there are no retx in RAR but a softbuffer is required) + dl_sched_res->sched_grants[n].softbuffer = &rar_softbuffer_tx; + srslte_softbuffer_tx_reset_tbs(&rar_softbuffer_tx, sched_result.rar[i].tbs); // TBS is usually 54-bit + + // Assemble PDU + dl_sched_res->sched_grants[n].data = assemble_rar(sched_result.rar[i].grants, sched_result.rar[i].nof_grants, i, sched_result.rar[i].tbs); + + + if (pcap) { + pcap->write_dl_ranti(dl_sched_res->sched_grants[n].data, sched_result.data[i].tbs, dl_sched_res->sched_grants[n].rnti, true, tti); + } + + n++; + } + + // Copy SI and Paging grants + for (uint32_t i=0;isched_grants[n].rnti = (sched_result.bc[i].type == sched_interface::dl_sched_bc_t::BCCH ) ? SRSLTE_SIRNTI : SRSLTE_PRNTI; + memcpy(&dl_sched_res->sched_grants[n].grant, &sched_result.bc[i].dci, sizeof(srslte_ra_dl_dci_t)); + memcpy(&dl_sched_res->sched_grants[n].location, &sched_result.bc[i].dci_location, sizeof(srslte_dci_location_t)); + + // Set softbuffer + if (sched_result.bc[i].type == sched_interface::dl_sched_bc_t::BCCH) { + dl_sched_res->sched_grants[n].softbuffer = &bcch_softbuffer_tx[sched_result.bc[i].index]; + if (sched_result.bc[i].dci.rv_idx == 0) { + srslte_softbuffer_tx_reset_tbs(dl_sched_res->sched_grants[n].softbuffer, sched_result.bc[i].tbs*8); + } + dl_sched_res->sched_grants[n].data = assemble_si(sched_result.bc[i].index); +#ifdef WRITE_SIB_PCAP + if (pcap) { + pcap->write_dl_sirnti(dl_sched_res->sched_grants[n].data, sched_result.bc[i].tbs, true, tti); + } +#endif + } else { + dl_sched_res->sched_grants[n].softbuffer = &pcch_softbuffer_tx; + srslte_softbuffer_tx_reset_tbs(dl_sched_res->sched_grants[n].softbuffer, sched_result.bc[i].tbs*8); + dl_sched_res->sched_grants[n].data = pcch_payload_buffer; + rlc_h->read_pdu_pcch(pcch_payload_buffer, pcch_payload_buffer_len); + + if (pcap) { + pcap->write_dl_pch(dl_sched_res->sched_grants[n].data, sched_result.bc[i].tbs, true, tti); + } + } + + n++; + } + + dl_sched_res->nof_grants = n; + + // Number of CCH symbols + dl_sched_res->cfi = sched_result.cfi; + + return SRSLTE_SUCCESS; +} + +uint8_t* mac::assemble_rar(sched_interface::dl_sched_rar_grant_t* grants, uint32_t nof_grants, int rar_idx, uint32_t pdu_len) +{ + uint8_t grant_buffer[64]; + if (pdu_len < rar_payload_len) { + srslte::rar_pdu *pdu = &rar_pdu_msg[rar_idx]; + pdu->init_tx(rar_payload[rar_idx], pdu_len); + for (uint32_t i=0;inew_subh()) { + /* Search pending RAR */ + int idx = grants[i].ra_id; + pdu->get()->set_rapid(pending_rars[idx].preamble_idx); + pdu->get()->set_ta_cmd(pending_rars[idx].ta_cmd); + pdu->get()->set_temp_crnti(pending_rars[idx].temp_crnti); + pdu->get()->set_sched_grant(grant_buffer); + bzero(&pending_rars[idx], sizeof(pending_rar_t)); + } + } + pdu->write_packet(rar_payload[rar_idx]); + return rar_payload[rar_idx]; + } else { + Error("Assembling RAR: pdu_len > rar_payload_len (%d>%d)\n", pdu_len, rar_payload_len); + return NULL; + } +} + +uint8_t* mac::assemble_si(uint32_t index) +{ + rlc_h->read_pdu_bcch_dlsch(index, bcch_dlsch_payload); + return bcch_dlsch_payload; +} + +int mac::get_ul_sched(uint32_t tti, ul_sched_t *ul_sched_res) +{ + + log_step_ul(tti); + + if (!started) { + return 0; + } + + if (!ul_sched_res) { + return SRSLTE_ERROR_INVALID_INPUTS; + } + + // Run scheduler with current info + sched_interface::ul_sched_res_t sched_result; + bzero(&sched_result, sizeof(sched_interface::ul_sched_res_t)); + if (scheduler.ul_sched(tti, &sched_result)<0) { + Error("Running scheduler\n"); + return SRSLTE_ERROR; + } + + // Copy DCI grants + ul_sched_res->nof_grants = 0; + int n = 0; + for (uint32_t i=0;i 0) { + // Get UE + uint16_t rnti = sched_result.pusch[i].rnti; + + // Copy grant info + ul_sched_res->sched_grants[n].rnti = rnti; + ul_sched_res->sched_grants[n].current_tx_nb = sched_result.pusch[i].current_tx_nb; + ul_sched_res->sched_grants[n].needs_pdcch = sched_result.pusch[i].needs_pdcch; + memcpy(&ul_sched_res->sched_grants[n].grant, &sched_result.pusch[i].dci, sizeof(srslte_ra_ul_dci_t)); + memcpy(&ul_sched_res->sched_grants[n].location, &sched_result.pusch[i].dci_location, sizeof(srslte_dci_location_t)); + + ul_sched_res->sched_grants[n].softbuffer = ue_db[rnti]->get_rx_softbuffer(tti); + + if (sched_result.pusch[n].current_tx_nb == 0) { + srslte_softbuffer_rx_reset_tbs(ul_sched_res->sched_grants[n].softbuffer, sched_result.pusch[i].tbs*8); + } + ul_sched_res->sched_grants[n].data = ue_db[rnti]->request_buffer(tti, sched_result.pusch[i].tbs); + ul_sched_res->nof_grants++; + n++; + + } else { + Warning("Grant %d for rnti=0x%x has zero TBS\n", i, sched_result.pusch[i].rnti); + } + } + + // Copy PHICH actions + for (uint32_t i=0;iphich[i].ack = sched_result.phich[i].phich == sched_interface::ul_sched_phich_t::ACK; + ul_sched_res->phich[i].rnti = sched_result.phich[i].rnti; + } + ul_sched_res->nof_phich = sched_result.nof_phich_elems; + return SRSLTE_SUCCESS; +} + +void mac::log_step_ul(uint32_t tti) +{ + int tti_ul = tti-8; + if (tti_ul < 0) { + tti_ul += 10240; + } + log_h->step(tti_ul); +} + +void mac::log_step_dl(uint32_t tti) +{ + int tti_dl = tti-4; + if (tti_dl < 0) { + tti_dl += 10240; + } + log_h->step(tti_dl); +} + +void mac::tti_clock() +{ + upper_timers_thread.tti_clock(); +} + +/******************************************************** + * + * Class to run upper-layer timers with normal priority + * + *******************************************************/ +void mac::upper_timers::run_thread() +{ + running=true; + ttisync.set_producer_cntr(0); + ttisync.resync(); + while(running) { + ttisync.wait(); + timers_db.step_all(); + } +} +srslte::timers::timer* mac::upper_timers::get(uint32_t timer_id) +{ + return timers_db.get(timer_id%MAC_NOF_UPPER_TIMERS); +} + +uint32_t mac::upper_timers::get_unique_id() +{ + return timers_db.get_unique_id(); +} + +void mac::upper_timers::stop() +{ + running=false; + ttisync.increase(); + wait_thread_finish(); +} +void mac::upper_timers::reset() +{ + timers_db.stop_all(); +} + +void mac::upper_timers::tti_clock() +{ + ttisync.increase(); +} + + + +/******************************************************** + * + * Class that runs a thread to process DL MAC PDUs from + * DEMU unit + * + *******************************************************/ +mac::pdu_process::pdu_process(pdu_process_handler *h) +{ + handler = h; + pthread_mutex_init(&mutex, NULL); + pthread_cond_init(&cvar, NULL); + have_data = false; + start(MAC_PDU_THREAD_PRIO); +} + +void mac::pdu_process::stop() +{ + pthread_mutex_lock(&mutex); + running = false; + pthread_cond_signal(&cvar); + pthread_mutex_unlock(&mutex); + + wait_thread_finish(); +} + +void mac::pdu_process::notify() +{ + pthread_mutex_lock(&mutex); + have_data = true; + pthread_cond_signal(&cvar); + pthread_mutex_unlock(&mutex); +} + +void mac::pdu_process::run_thread() +{ + running = true; + while(running) { + have_data = handler->process_pdus(); + if (!have_data) { + pthread_mutex_lock(&mutex); + while(!have_data && running) { + pthread_cond_wait(&cvar, &mutex); + } + pthread_mutex_unlock(&mutex); + } + } +} + +bool mac::process_pdus() +{ + bool ret = false; + for(std::map::iterator iter=ue_db.begin(); iter!=ue_db.end(); ++iter) { + ue *u = iter->second; + uint16_t rnti = iter->first; + ret = ret | u->process_pdus(); + } + return ret; +} + + + + + +} + + + diff --git a/srsenb/src/mac/scheduler.cc b/srsenb/src/mac/scheduler.cc new file mode 100644 index 000000000..5a9a8a6e5 --- /dev/null +++ b/srsenb/src/mac/scheduler.cc @@ -0,0 +1,938 @@ + +#include + +#include "srslte/srslte.h" +#include "srslte/common/pdu.h" +#include "mac/scheduler.h" + +#define Error(fmt, ...) log_h->error_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Warning(fmt, ...) log_h->warning_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Info(fmt, ...) log_h->info_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Debug(fmt, ...) log_h->debug_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) + +namespace srsenb { + + +/******************************************************* + * + * Initialization and sched configuration functions + * + *******************************************************/ +sched::sched() +{ + log_h = NULL; + pthread_mutex_init(&mutex, NULL); + reset(); +} + +void sched::init(rrc_interface_mac *rrc_, srslte::log* log) +{ + sched_cfg.pdsch_max_mcs = 28; + sched_cfg.pdsch_mcs = -1; + sched_cfg.pusch_max_mcs = 28; + sched_cfg.pusch_mcs = -1; + sched_cfg.nof_ctrl_symbols = 3; + log_h = log; + rrc = rrc_; + reset(); +} + +int sched::reset() +{ + bzero(pending_rar, sizeof(sched_rar_t)*SCHED_MAX_PENDING_RAR); + bzero(pending_sibs, sizeof(sched_sib_t)*MAX_SIBS); + ue_db.clear(); + configured = false; + return 0; +} + +void sched::set_sched_cfg(sched_interface::sched_args_t* sched_cfg_) +{ + if (sched_cfg_) { + memcpy(&sched_cfg, sched_cfg_, sizeof(sched_args_t)); + } +} + +void sched::set_metric(sched::metric_dl* dl_metric_, sched::metric_ul* ul_metric_) +{ + dl_metric = dl_metric_; + ul_metric = ul_metric_; +} + +int sched::cell_cfg(sched_interface::cell_cfg_t* cell_cfg) +{ + // Basic cell config checks + if (cell_cfg->si_window_ms == 0) { + Error("SCHED: Invalid si-window length 0 ms\n"); + return -1; + } + + pthread_mutex_lock(&mutex); + + memcpy(&cfg, cell_cfg, sizeof(sched_interface::cell_cfg_t)); + + // Get DCI locations + srslte_regs_init(®s, cfg.cell); + + P = srslte_ra_type0_P(cfg.cell.nof_prb); + si_n_rbg = 4/P; + rar_n_rb = 3; + nof_rbg = (uint32_t) ceil((float) cfg.cell.nof_prb/P); + + // Compute Common locations for DCI for each CFI + for (uint32_t cfi=0;cfi<3;cfi++) { + generate_cce_location(®s, &common_locations[cfi], cfi+1); + } + + // Compute UE locations for RA-RNTI + for (int cfi=0;cfi<3;cfi++) { + for (int sf_idx=0;sf_idx<10;sf_idx++) { + uint16_t ra_rnti = 1+sf_idx; + generate_cce_location(®s, &rar_locations[cfi][sf_idx], cfi+1, sf_idx); + } + } + configured = true; + + pthread_mutex_unlock(&mutex); + + return 0; +} + + +/******************************************************* + * + * FAPI-like main sched interface. Wrappers to UE object + * + *******************************************************/ + +int sched::ue_cfg(uint16_t rnti, sched_interface::ue_cfg_t *ue_cfg) +{ + pthread_mutex_lock(&mutex); + + // Add or config user + ue_db[rnti].set_cfg(rnti, ue_cfg, &cfg, ®s, log_h); + ue_db[rnti].set_max_mcs(sched_cfg.pusch_max_mcs, sched_cfg.pdsch_max_mcs); + ue_db[rnti].set_fixed_mcs(sched_cfg.pusch_mcs, sched_cfg.pdsch_mcs); + + pthread_mutex_unlock(&mutex); + return 0; +} + +int sched::ue_rem(uint16_t rnti) +{ + pthread_mutex_lock(&mutex); + int ret = 0; + if (ue_db.count(rnti)) { + ue_db.erase(rnti); + } else { + Error("User rnti=0x%x not found\n", rnti); + ret = -1; + } + pthread_mutex_unlock(&mutex); + return ret; +} + +bool sched::ue_exists(uint16_t rnti) +{ + return (ue_db.count(rnti) == 1); +} + +void sched::phy_config_enabled(uint16_t rnti, bool enabled) +{ + pthread_mutex_lock(&mutex); + if (ue_db.count(rnti)) { + ue_db[rnti].phy_config_enabled(current_tti, enabled); + } else { + Error("User rnti=0x%x not found\n", rnti); + } + pthread_mutex_unlock(&mutex); +} + +int sched::bearer_ue_cfg(uint16_t rnti, uint32_t lc_id, sched_interface::ue_bearer_cfg_t *cfg) +{ + pthread_mutex_lock(&mutex); + int ret = 0; + if (ue_db.count(rnti)) { + ue_db[rnti].set_bearer_cfg(lc_id, cfg); + } else { + Error("User rnti=0x%x not found\n", rnti); + ret = -1; + } + pthread_mutex_unlock(&mutex); + return ret; +} + +int sched::bearer_ue_rem(uint16_t rnti, uint32_t lc_id) +{ + pthread_mutex_lock(&mutex); + int ret = 0; + if (ue_db.count(rnti)) { + ue_db[rnti].rem_bearer(lc_id); + } else { + Error("User rnti=0x%x not found\n", rnti); + ret = -1; + } + pthread_mutex_unlock(&mutex); + return ret; +} + +uint32_t sched::get_dl_buffer(uint16_t rnti) +{ + pthread_mutex_lock(&mutex); + uint32_t ret = 0; + if (ue_db.count(rnti)) { + ret = ue_db[rnti].get_pending_dl_new_data(current_tti); + } else { + Error("User rnti=0x%x not found\n", rnti); + } + pthread_mutex_unlock(&mutex); + return ret; +} + +uint32_t sched::get_ul_buffer(uint16_t rnti) +{ + pthread_mutex_lock(&mutex); + uint32_t ret = 0; + if (ue_db.count(rnti)) { + ret = ue_db[rnti].get_pending_ul_new_data(current_tti); + } else { + Error("User rnti=0x%x not found\n", rnti); + } + pthread_mutex_unlock(&mutex); + return ret; +} + +int sched::dl_rlc_buffer_state(uint16_t rnti, uint32_t lc_id, uint32_t tx_queue, uint32_t retx_queue) +{ + pthread_mutex_lock(&mutex); + int ret = 0; + if (ue_db.count(rnti)) { + ue_db[rnti].dl_buffer_state(lc_id, tx_queue, retx_queue); + } else { + Error("User rnti=0x%x not found\n", rnti); + ret = -1; + } + pthread_mutex_unlock(&mutex); + return ret; +} + +int sched::dl_mac_buffer_state(uint16_t rnti, uint32_t ce_code) +{ + pthread_mutex_lock(&mutex); + int ret = 0; + if (ue_db.count(rnti)) { + ue_db[rnti].mac_buffer_state(ce_code); + } else { + Error("User rnti=0x%x not found\n", rnti); + ret = -1; + } + pthread_mutex_unlock(&mutex); + return ret; +} + +int sched::dl_ack_info(uint32_t tti, uint16_t rnti, bool ack) +{ + pthread_mutex_lock(&mutex); + int ret = 0; + if (ue_db.count(rnti)) { + ret = ue_db[rnti].set_ack_info(tti, ack); + } else { + Error("User rnti=0x%x not found\n", rnti); + ret = -1; + } + pthread_mutex_unlock(&mutex); + return ret; +} + +int sched::ul_crc_info(uint32_t tti, uint16_t rnti, bool crc) +{ + pthread_mutex_lock(&mutex); + int ret = 0; + if (ue_db.count(rnti)) { + ue_db[rnti].set_ul_crc(tti, crc); + } else { + Error("User rnti=0x%x not found\n", rnti); + ret = -1; + } + pthread_mutex_unlock(&mutex); + return ret; +} + +int sched::dl_cqi_info(uint32_t tti, uint16_t rnti, uint32_t cqi_value) +{ + pthread_mutex_lock(&mutex); + int ret = 0; + if (ue_db.count(rnti)) { + ue_db[rnti].set_dl_cqi(tti, cqi_value); + } else { + Error("User rnti=0x%x not found\n", rnti); + ret = -1; + } + pthread_mutex_unlock(&mutex); + return ret; +} + +int sched::dl_rach_info(uint32_t tti, uint32_t ra_id, uint16_t rnti, uint32_t estimated_size) +{ + for (int i=0;i 0) { + x = (i-1)*cfg.si_window_ms; + sf = x%10; + } + if ((sfn%(cfg.sibs[i].period_rf)) == x/10 && sf_idx == sf) { + pending_sibs[i].is_in_window = true; + pending_sibs[i].window_start = current_tti; + pending_sibs[i].n_tx = 0; + } + } else { + if (i > 0) { + if (srslte_tti_interval(current_tti, pending_sibs[i].window_start) > cfg.si_window_ms) { + pending_sibs[i].is_in_window = false; + pending_sibs[i].window_start = 0; + } + } else { + // SIB1 is always in window + if (pending_sibs[0].n_tx == 4) { + pending_sibs[0].n_tx = 0; + } + } + } + } + } + + for (int i=0;i si_n_rbg) + { + uint32_t nof_tx = 4; + if (i > 0) { + if (cfg.si_window_ms <= 10) { + nof_tx = 1; + } else if (cfg.si_window_ms <= 20) { + nof_tx = 2; + } else if (cfg.si_window_ms <= 30) { + nof_tx = 3; + } else { + nof_tx = 4; + } + } + uint32_t n_sf = (current_tti-pending_sibs[i].window_start); + if ((i == 0 && (sfn%2) == 0 && sf_idx == 5) || + (i > 0 && n_sf >= (cfg.si_window_ms/nof_tx)*pending_sibs[i].n_tx && sf_idx==1)) + { + uint32_t rv = get_rvidx(pending_sibs[i].n_tx); + + // Try to allocate DCI first + if (generate_dci(&bc[nof_bc_elems].dci_location, &common_locations[current_cfi-1], bc_aggr_level)) { + if (generate_format1a(start_rbg*P, si_n_rbg*P, cfg.sibs[i].len, rv, &bc[nof_bc_elems].dci) >= 0) { + bc[nof_bc_elems].index = i; + bc[nof_bc_elems].type = sched_interface::dl_sched_bc_t::BCCH; + bc[nof_bc_elems].tbs = cfg.sibs[i].len; + + Debug("SCHED: SIB%d, start_rb=%d, n_rb=%d, rv=%d, len=%d, period=%d\n", + i+1, start_rbg*P, si_n_rbg*P, rv, cfg.sibs[i].len, cfg.sibs[i].period_rf); + + pending_sibs[i].n_tx++; + + nof_bc_elems++; + avail_rbg -= si_n_rbg; + start_rbg += si_n_rbg; + } else { + Error("Could not allocate DCI Format1A for SIB%d, len=%d\n", i+1, cfg.sibs[i].len); + } + } else { + Warning("SCHED: Could not schedule DCI for SIB=%d, L=%d\n", i+1, bc_aggr_level); + } + } + } + } + + // Schedule Paging + if (rrc) { + uint32_t paging_payload = 0; + if (rrc->is_paging_opportunity(current_tti, &paging_payload)) { + if (avail_rbg > si_n_rbg && paging_payload) + { + if (generate_dci(&bc[nof_bc_elems].dci_location, &common_locations[current_cfi-1], bc_aggr_level)) { + int tbs = generate_format1a(start_rbg*P, si_n_rbg*P, paging_payload, 0, &bc[nof_bc_elems].dci); + if (tbs > 0) { + + bc[nof_bc_elems].type = sched_interface::dl_sched_bc_t::PCCH; + bc[nof_bc_elems].tbs = tbs; + nof_bc_elems++; + + Info("SCHED: PCH start_rb=%d, tbs=%d\n", start_rbg, tbs); + + avail_rbg -= si_n_rbg; + start_rbg += si_n_rbg; + + } + } + } + } + } + + return nof_bc_elems; +} + + +// Schedules RAR +int sched::dl_sched_rar(dl_sched_rar_t rar[MAX_RAR_LIST]) +{ + + int nof_rar_elems = 0; + for (uint32_t i=0;i 0 && avail_rbg >= rar_n_rb) + { + /* Check if we are still within the RAR window, otherwise discard it */ + if (current_tti <= (pending_rar[i].rar_tti + cfg.prach_rar_window + 3)%10240 && current_tti >= pending_rar[i].rar_tti + 3) + { + // Try to schedule DCI for this RAR + if (generate_dci(&rar[nof_rar_elems].dci_location, &rar_locations[current_cfi-1][sf_idx], rar_aggr_level)) { + + /* Find all pending RARs with same transmission TTI */ + uint32_t tti = pending_rar[i].rar_tti; + uint32_t rar_sfidx = (tti+1)%10; + uint32_t buf_rar = 0; + uint32_t nof_grants = 0; + for (int j=0;jinfo("SCHED: RAR, ra_id=%d, rnti=0x%x, rarnti_idx=%d, start_rb=%d, n_rb=%d, rar_grant_rba=%d, rar_grant_mcs=%d\n", + pending_rar[j].ra_id, pending_rar[j].rnti, rar_sfidx, start_rbg*P, rar_n_rb, + rar[nof_rar_elems].grants[nof_grants].grant.rba, + rar[nof_rar_elems].grants[nof_grants].grant.trunc_mcs); + } else { + log_h->warning("Only 1 RA is responded at a time. Found %d for TTI=%d\n", nof_grants+1, tti); + } + nof_grants++; + } + } + + rar[nof_rar_elems].nof_grants = nof_grants; + rar[nof_rar_elems].rarnti = rar_sfidx; + + if (generate_format1a(start_rbg*P, rar_n_rb, buf_rar, 0, &rar[nof_rar_elems].dci) >= 0) { + rar[nof_rar_elems].tbs = buf_rar; + nof_rar_elems++; + avail_rbg -= rar_n_rb; + start_rbg += rar_n_rb; + } else { + Error("SCHED: Allocating Format1A grant\n"); + } + + } else { + log_h->console("SCHED: Could not schedule DCI for RAR tti=%d, L=%d\n", pending_rar[i].rar_tti, rar_aggr_level); + } + } else { + log_h->console("SCHED: Could not transmit RAR within the window (RA TTI=%d, Window=%d, Now=%d)\n", + pending_rar[i].rar_tti, cfg.prach_rar_window, current_tti); + pending_rar[i].buf_rar = 0; + pending_rar[i].rar_tti = 0; + } + } + } + return nof_rar_elems; +} + +// Schedules data to users +int sched::dl_sched_data(dl_sched_data_t data[MAX_DATA_LIST]) +{ + uint32_t nof_ctrl_symbols = (cfg.cell.nof_prb<10)?(current_cfi+1):current_cfi; + dl_metric->new_tti(ue_db, start_rbg, avail_rbg, nof_ctrl_symbols, current_tti); + + int nof_data_elems = 0; + for(std::map::iterator iter=ue_db.begin(); iter!=ue_db.end(); ++iter) { + sched_ue *user = (sched_ue*) &iter->second; + uint16_t rnti = (uint16_t) iter->first; + + dl_harq_proc *h = dl_metric->get_user_allocation(user); + + if (h) { + // Try to schedule DCI first + if (generate_dci(&data[nof_data_elems].dci_location, + user->get_locations(current_cfi, sf_idx), + user->get_aggr_level(srslte_dci_format_sizeof(SRSLTE_DCI_FORMAT1, cfg.cell.nof_prb, cfg.cell.nof_ports)), user)) + { + bool is_newtx = h->is_empty(); + int tbs = user->generate_format1(h, &data[nof_data_elems], current_tti, current_cfi); + if (tbs >= 0) { + log_h->info("SCHED: DL %s rnti=0x%x, pid=%d, mask=0x%x, dci=%d,%d, n_rtx=%d, tbs=%d, buffer=%d\n", + !is_newtx?"retx":"tx", rnti, h->get_id(), h->get_rbgmask(), + data[nof_data_elems].dci_location.L, data[nof_data_elems].dci_location.ncce, h->nof_retx(), + tbs, user->get_pending_dl_new_data(current_tti)); + nof_data_elems++; + } else { + log_h->warning("SCHED: Error DL %s rnti=0x%x, pid=%d, mask=0x%x, dci=%d,%d, tbs=%d, buffer=%d\n", + !is_newtx?"retx":"tx", rnti, h->get_id(), h->get_rbgmask(), + data[nof_data_elems].dci_location.L, data[nof_data_elems].dci_location.ncce, + tbs, user->get_pending_dl_new_data(current_tti)); + } + } else { + Warning("SCHED: Could not schedule DL DCI for rnti=0x%x, pid=%d\n", rnti, h->get_id()); + } + } + } + + return nof_data_elems; +} + +// Downlink Scheduler +int sched::dl_sched(uint32_t tti, sched_interface::dl_sched_res_t* sched_result) +{ + if (!configured) { + return 0; + } + pthread_mutex_lock(&mutex); + + /* If ul_sched() not yet called this tti, reset CCE state */ + if (current_tti != tti) { + bzero(used_cce, MAX_CCE*sizeof(bool)); + } + + /* Initialize variables */ + current_tti = tti; + sfn = tti/10; + sf_idx = tti%10; + avail_rbg = nof_rbg; + start_rbg = 0; + current_cfi = sched_cfg.nof_ctrl_symbols; + bc_aggr_level = 2; + rar_aggr_level = 2; + bzero(sched_result, sizeof(sched_interface::dl_sched_res_t)); + + /* Schedule Broadcast data */ + sched_result->nof_bc_elems += dl_sched_bc(sched_result->bc); + + /* Schedule RAR */ + sched_result->nof_rar_elems += dl_sched_rar(sched_result->rar); + + /* Schedule pending RLC data */ + sched_result->nof_data_elems += dl_sched_data(sched_result->data); + + /* Set CFI */ + sched_result->cfi = current_cfi; + + pthread_mutex_unlock(&mutex); + return 0; +} + +// Uplink sched +int sched::ul_sched(uint32_t tti, srsenb::sched_interface::ul_sched_res_t* sched_result) +{ + if (!configured) { + return 0; + } + + pthread_mutex_lock(&mutex); + + /* If dl_sched() not yet called this tti (this tti is +4ms advanced), reset CCE state */ + if ((current_tti+4)%10240 != tti) { + bzero(used_cce, MAX_CCE*sizeof(bool)); + } + + /* Initialize variables */ + current_tti = tti; + sfn = tti/10; + if (tti > 4) { + sf_idx = (tti-4)%10; + } else { + sf_idx = (tti+10240-4)%10; + } + int nof_dci_elems = 0; + int nof_phich_elems = 0; + + // current_cfi is set in dl_sched() + bzero(sched_result, sizeof(sched_interface::ul_sched_res_t)); + + // Get HARQ process for this TTI + for(std::map::iterator iter=ue_db.begin(); iter!=ue_db.end(); ++iter) { + sched_ue *user = (sched_ue*) &iter->second; + uint16_t rnti = (uint16_t) iter->first; + + ul_harq_proc *h = user->get_ul_harq(current_tti); + + /* Indicate PHICH acknowledgment if needed */ + if (h->has_pending_ack()) { + sched_result->phich[nof_phich_elems].phich = h->get_ack()?ul_sched_phich_t::ACK:ul_sched_phich_t::NACK; + sched_result->phich[nof_phich_elems].rnti = rnti; + nof_phich_elems++; + } + } + + ul_metric->new_tti(ue_db, cfg.cell.nof_prb, current_tti); + + // Update available allocation if there's a pending RAR + if (pending_msg3[tti%10].enabled) { + ul_harq_proc::ul_alloc_t msg3 = {pending_msg3[tti%10].n_prb, pending_msg3[tti%10].L}; + ul_metric->update_allocation(msg3); + } + + // Allocate PUCCH resources + for(std::map::iterator iter=ue_db.begin(); iter!=ue_db.end(); ++iter) { + sched_ue *user = (sched_ue*) &iter->second; + uint16_t rnti = (uint16_t) iter->first; + uint32_t prb_idx[2] = {0, 0}; + uint32_t L = 0; + if (user->get_pucch_sched(current_tti, prb_idx, &L)) { + for (int i=0;i<2;i++) { + ul_harq_proc::ul_alloc_t pucch = {prb_idx[i], L}; + ul_metric->update_allocation(pucch); + } + } + } + + // Now allocate PUSCH + for(std::map::iterator iter=ue_db.begin(); iter!=ue_db.end(); ++iter) { + sched_ue *user = (sched_ue*) &iter->second; + uint16_t rnti = (uint16_t) iter->first; + + ul_harq_proc *h = NULL; + + // Check if there are pending Msg3 transmissions + bool is_rar = false; + if (pending_msg3[tti%10].enabled && pending_msg3[tti%10].rnti == rnti) { + h = user->get_ul_harq(tti); + if (h) { + ul_harq_proc::ul_alloc_t alloc; + alloc.L = pending_msg3[tti%10].L; + alloc.RB_start = pending_msg3[tti%10].n_prb; + h->set_alloc(alloc); + h->set_rar_mcs(pending_msg3[tti%10].mcs); + is_rar = true; + pending_msg3[tti%10].enabled = false; + } else { + Warning("No HARQ pid available for transmission of Msg3\n"); + } + } else { + h = ul_metric->get_user_allocation(user); + } + if (h) + { + ul_harq_proc::ul_alloc_t alloc = h->get_alloc(); + bool is_newtx = h->is_empty(); + bool needs_pdcch = !h->is_adaptive_retx() && !is_rar; + + // Set number of retx + if (is_newtx) { + if (is_rar) { + h->set_max_retx(cfg.maxharq_msg3tx); + } else { + h->set_max_retx(user->get_max_retx()); + } + } + + // Generate PDCCH except for RAR and non-adaptive retx + if (needs_pdcch) { + uint32_t aggr_level = user->get_aggr_level(srslte_dci_format_sizeof(SRSLTE_DCI_FORMAT0, cfg.cell.nof_prb, cfg.cell.nof_ports)); + if (!generate_dci(&sched_result->pusch[nof_dci_elems].dci_location, + user->get_locations(current_cfi, sf_idx), + aggr_level)) + { + log_h->warning("SCHED: Could not schedule UL DCI rnti=0x%x, pid=%d, L=%d\n", + rnti, h->get_id(), aggr_level); + sched_result->pusch[nof_dci_elems].needs_pdcch = false; + } else { + sched_result->pusch[nof_dci_elems].needs_pdcch = true; + } + } else { + sched_result->pusch[nof_dci_elems].needs_pdcch = false; + } + + // Generate grant unless DCI could not be generated and was required + if (sched_result->pusch[nof_dci_elems].needs_pdcch == needs_pdcch) { + uint32_t pending_data_before = user->get_pending_ul_new_data(current_tti); + if (user->generate_format0(h, &sched_result->pusch[nof_dci_elems], current_tti, user->needs_cqi(tti, true)) > 0) + { + + if (is_newtx) { + // Un-trigger SR + user->unset_sr(); + } + + log_h->info("SCHED: %s %s rnti=0x%x, pid=%d, dci=%d,%d, grant=%d,%d, n_rtx=%d, tbs=%d, bsr=%d (%d)\n", + is_rar?"RAR":"UL", + is_newtx?"tx":"retx", + rnti, h->get_id(), + sched_result->pusch[nof_dci_elems].dci_location.L, sched_result->pusch[nof_dci_elems].dci_location.ncce, + alloc.RB_start, alloc.L, h->nof_retx(), sched_result->pusch[nof_dci_elems].tbs, + user->get_pending_ul_new_data(current_tti),pending_data_before); + + nof_dci_elems++; + } else { + log_h->warning("SCHED: Error %s %s rnti=0x%x, pid=%d, dci=%d,%d, grant=%d,%d, tbs=%d, bsr=%d\n", + is_rar?"RAR":"UL", + is_newtx?"tx":"retx", + rnti, h->get_id(), + sched_result->pusch[nof_dci_elems].dci_location.L, sched_result->pusch[nof_dci_elems].dci_location.ncce, + alloc.RB_start, alloc.L, sched_result->pusch[nof_dci_elems].tbs, + user->get_pending_ul_new_data(current_tti)); + } + } + } + } + + sched_result->nof_dci_elems = nof_dci_elems; + sched_result->nof_phich_elems = nof_phich_elems; + + pthread_mutex_unlock(&mutex); + + return SRSLTE_SUCCESS; +} + + +/******************************************************* + * + * Helper functions + * + *******************************************************/ + +void sched::generate_cce_location(srslte_regs_t *regs_, sched_ue::sched_dci_cce_t* location, + uint32_t cfi, uint32_t sf_idx, uint16_t rnti) +{ + srslte_dci_location_t loc[64]; + uint32_t nloc = 0; + if (rnti == 0) { + nloc = srslte_pdcch_common_locations_ncce(srslte_regs_pdcch_ncce(regs_, cfi), + loc, 64); + } else { + nloc = srslte_pdcch_ue_locations_ncce(srslte_regs_pdcch_ncce(regs_, cfi), + loc, 64, sf_idx, rnti); + } + + for (uint32_t l=0;l<=3;l++) { + int n=0; + for (uint32_t i=0;icce_start[l][n] = loc[i].ncce; + n++; + } + } + location->nof_loc[l] = n; + } + +} + + +#define NCCE(L) (1<nof_loc[aggr_level] && !allocated) { + uint32_t ncce = locations->cce_start[aggr_level][ncand]; + bool used = false; + if (user) { + used = user->pucch_sr_collision(current_tti, ncce); + } + for (int j=0;jL = aggr_level; + sched_location->ncce = locations->cce_start[aggr_level][ncand]; + } + + return allocated; +} + +int sched::generate_format1a(uint32_t rb_start, uint32_t l_crb, uint32_t tbs_bytes, uint32_t rv, srslte_ra_dl_dci_t *dci) +{ + /* Calculate I_tbs for this TBS */ + int tbs = tbs_bytes*8; + int i; + int mcs = -1; + for (i=0;i<27;i++) { + if (srslte_ra_tbs_from_idx(i, 2) >= tbs) { + dci->type2_alloc.n_prb1a = srslte_ra_type2_t::SRSLTE_RA_TYPE2_NPRB1A_2; + mcs = i; + tbs = srslte_ra_tbs_from_idx(i, 2); + break; + } else if (srslte_ra_tbs_from_idx(i, 3) >= tbs) { + dci->type2_alloc.n_prb1a = srslte_ra_type2_t::SRSLTE_RA_TYPE2_NPRB1A_3; + mcs = i; + tbs = srslte_ra_tbs_from_idx(i, 3); + break; + } + } + if (i == 28) { + Error("Can't allocate Format 1A for TBS=%d\n", tbs); + return -1; + } + + dci->alloc_type = SRSLTE_RA_ALLOC_TYPE2; + dci->type2_alloc.mode = srslte_ra_type2_t::SRSLTE_RA_TYPE2_LOC; + dci->type2_alloc.L_crb = l_crb; + dci->type2_alloc.RB_start = rb_start; + dci->harq_process = 0; + dci->mcs_idx = mcs; + dci->rv_idx = rv; + dci->tb_en[0] = true; + dci->tb_en[1] = false; + + return tbs; +} + + + + + +} + + diff --git a/srsenb/src/mac/scheduler_harq.cc b/srsenb/src/mac/scheduler_harq.cc new file mode 100644 index 000000000..4651b5533 --- /dev/null +++ b/srsenb/src/mac/scheduler_harq.cc @@ -0,0 +1,263 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2017 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of srsLTE. + * + * srsUE 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. + * + * srsUE 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 +#include + +#include "srslte/srslte.h" +#include "srslte/common/pdu.h" +#include "mac/scheduler.h" + +#define Error(fmt, ...) log_h->error_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Warning(fmt, ...) log_h->warning_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Info(fmt, ...) log_h->info_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Debug(fmt, ...) log_h->debug_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) + +namespace srsenb { + +/****************************************************** + * + * These classes manage the HARQ Processes. + * There is a common class and two child classes for UL and DL. + * + ******************************************************/ + +void harq_proc::config(uint32_t id_, uint32_t max_retx_, srslte::log* log_h_) +{ + log_h = log_h_; + id = id_; + max_retx = max_retx_; + ndi = false; +} + +void harq_proc::set_max_retx(uint32_t max_retx_) { + log_h->debug("Set max_retx=%d pid=%d\n", max_retx_, id); + max_retx = max_retx_; +} + +uint32_t harq_proc::get_id() +{ + return id; +} + +void harq_proc::reset() +{ + active = false; + ack = true; + ack_received = false; + n_rtx = 0; + tti = 0; + last_mcs = -1; + last_tbs = -1; + tx_cnt = 0; +} + +bool harq_proc::is_empty() +{ + return !active || (active && ack && ack_received); +} + +bool harq_proc::has_pending_retx_common() +{ + return !ack && n_rtx < max_retx; +} + +uint32_t harq_proc::get_tti() +{ + return tti; +} + +bool harq_proc::get_ack() +{ + return ack; +} + +void harq_proc::set_ack(bool ack_) +{ + ack = ack_; + ack_received = true; + log_h->debug("ACK=%d received pid=%d, n_rtx=%d, max_retx=%d\n", ack_, id, n_rtx, max_retx); + if (n_rtx >= max_retx) { + Warning("SCHED: discarting TB pid=%d, tti=%d, maximum number of retx exceeded (%d)\n", id, tti, max_retx); + active = false; + } +} + +void harq_proc::new_tx_common(uint32_t tti_, int mcs, int tbs) +{ + reset(); + ndi = !ndi; + tti = tti_; + tx_cnt++; + last_mcs = mcs; + last_tbs = tbs; + + if (max_retx) { + active = true; + } else { + active = false; // Can reuse this process if no retx are allowed + } +} + +void harq_proc::new_retx(uint32_t tti_, int *mcs, int *tbs) +{ + ack_received = false; + tti = tti_; + n_rtx++; + if (mcs) { + *mcs = last_mcs; + } + if (tbs) { + *tbs = last_tbs; + } +} + +uint32_t harq_proc::nof_tx() +{ + return tx_cnt; +} + +uint32_t harq_proc::nof_retx() +{ + return n_rtx; +} + +bool harq_proc::get_ndi() +{ + return ndi; +} + +/****************************************************** + * UE::DL HARQ class * + ******************************************************/ + +void dl_harq_proc::new_tx(uint32_t tti, int mcs, int tbs, uint32_t n_cce_) +{ + n_cce = n_cce_; + new_tx_common(tti, mcs, tbs); +} + +uint32_t dl_harq_proc::get_n_cce() +{ + return n_cce; +} + +uint32_t dl_harq_proc::get_rbgmask() +{ + return rbgmask; +} + +void dl_harq_proc::set_rbgmask(uint32_t new_mask) +{ + rbgmask = new_mask; +} + +bool dl_harq_proc::has_pending_retx(uint32_t current_tti) +{ + return srslte_tti_interval(current_tti, tti) >= 8 && has_pending_retx_common(); +} + +int dl_harq_proc::get_tbs() +{ + return last_tbs; +} + + + +/****************************************************** + * UE::UL HARQ class * + ******************************************************/ + +ul_harq_proc::ul_alloc_t ul_harq_proc::get_alloc() +{ + return allocation; +} + +void ul_harq_proc::set_alloc(ul_harq_proc::ul_alloc_t alloc) +{ + is_adaptive = false; + memcpy(&allocation, &alloc, sizeof(ul_alloc_t)); +} + +void ul_harq_proc::same_alloc() +{ + is_adaptive = true; +} + +bool ul_harq_proc::is_adaptive_retx() +{ + return is_adaptive; +} + +void ul_harq_proc::new_tx(uint32_t tti_, int mcs, int tbs) +{ + need_ack = true; + new_tx_common(tti_, mcs, tbs); + pending_data = tbs; +} + + +bool ul_harq_proc::has_pending_ack() +{ + bool ret = need_ack; + + // Reset if already received a positive ACK + if (active && ack) { + active = false; + } + if (!active) { + pending_data = 0; + need_ack = false; + } + return ret; +} + +uint32_t ul_harq_proc::get_pending_data() +{ + return pending_data; +} + +void ul_harq_proc::set_rar_mcs(uint32_t mcs) +{ + rar_mcs = mcs; + has_rar_mcs = true; +} + +bool ul_harq_proc::get_rar_mcs(int *mcs) +{ + if (has_rar_mcs) { + if (mcs) { + *mcs = (int) rar_mcs; + } + has_rar_mcs = false; + return true; + } + return false; +} + + + +} diff --git a/srsenb/src/mac/scheduler_metric.cc b/srsenb/src/mac/scheduler_metric.cc new file mode 100644 index 000000000..2a9a4432b --- /dev/null +++ b/srsenb/src/mac/scheduler_metric.cc @@ -0,0 +1,335 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2017 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of srsLTE. + * + * srsUE 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. + * + * srsUE 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 + +#include "srslte/srslte.h" +#include "mac/scheduler_metric.h" + +#define Error(fmt, ...) log_h->error_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Warning(fmt, ...) log_h->warning_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Info(fmt, ...) log_h->info_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Debug(fmt, ...) log_h->debug_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) + +namespace srsenb { + + + +/***************************************************************** + * + * Downlink Metric + * + *****************************************************************/ + +uint32_t dl_metric_rr::calc_rbg_mask(bool mask[MAX_RBG]) +{ + // Build RBG bitmask + uint32_t rbg_bitmask = 0; + for (uint32_t n=0;n 0) { + if ((mask & 1) == 1) { + count++; + } + mask >>= 1; + } + return count; +} + +uint32_t dl_metric_rr::get_required_rbg(sched_ue *user, uint32_t tti) +{ + dl_harq_proc *h = user->get_pending_dl_harq(tti); + if (h) { + return count_rbg(h->get_rbgmask()); + } + uint32_t pending_data = user->get_pending_dl_new_data(current_tti); + return user->get_required_prb_dl(pending_data, nof_ctrl_symbols); +} + +void dl_metric_rr::new_tti(std::map &ue_db, uint32_t start_rb, uint32_t nof_rb, uint32_t nof_ctrl_symbols_, uint32_t tti) +{ + + total_rb = start_rb+nof_rb; + for (uint32_t i=0;i::iterator iter=ue_db.begin(); iter!=ue_db.end(); ++iter) { + sched_ue *user = (sched_ue*) &iter->second; + if (user->get_pending_dl_new_data(current_tti) || user->get_pending_dl_harq(current_tti)) { + user->ue_idx = nof_users_with_data; + nof_users_with_data++; + } + } +} + +bool dl_metric_rr::new_allocation(uint32_t nof_rbg, uint32_t *rbgmask) { + bool mask_bit[MAX_RBG]; + bzero(mask_bit, sizeof(bool)*MAX_RBG); + + for (uint32_t i=0;i 0;i++) { + if (used_rb[i]) { + mask_bit[i] = false; + } else { + mask_bit[i] = true; + nof_rbg--; + } + } + if (rbgmask) { + *rbgmask = calc_rbg_mask(mask_bit); + } + return (nof_rbg == 0); +} + +void dl_metric_rr::update_allocation(uint32_t new_mask) { + used_rb_mask |= new_mask; + for (uint32_t n=0;nget_pending_dl_new_data(current_tti); + dl_harq_proc *h = user->get_pending_dl_harq(current_tti); + + // Time-domain RR scheduling + if (pending_data || h) { + if (nof_users_with_data) { + if (nof_users_with_data == 2) { + } + if ((current_tti%nof_users_with_data) != user->ue_idx) { + return NULL; + } + } + } + + // Schedule retx if we have space + if (h) { + uint32_t retx_mask = h->get_rbgmask(); + // If can schedule the same mask, do it + if (!allocation_is_valid(retx_mask)) { + update_allocation(retx_mask); + return h; + } + // If not, try to find another mask in the current tti + uint32_t nof_rbg = count_rbg(retx_mask); + if (nof_rbg < available_rb) { + if (new_allocation(nof_rbg, &retx_mask)) { + update_allocation(retx_mask); + h->set_rbgmask(retx_mask); + return h; + } + } + } + // If could not schedule the reTx, or there wasn't any pending retx, find an empty PID + h = user->get_empty_dl_harq(); + if (h) { + // Allocate resources based on pending data + if (pending_data) { + uint32_t pending_rb = user->get_required_prb_dl(pending_data, nof_ctrl_symbols); + uint32_t newtx_mask = 0; + new_allocation(pending_rb, &newtx_mask); + if (newtx_mask) { + update_allocation(newtx_mask); + h->set_rbgmask(newtx_mask); + return h; + } + } + } + return NULL; +} + + + + + + + + + +/***************************************************************** + * + * Uplink Metric + * + *****************************************************************/ + +void ul_metric_rr::new_tti(std::map &ue_db, uint32_t nof_rb_, uint32_t tti) +{ + current_tti = tti; + nof_rb = nof_rb_; + available_rb = nof_rb_; + bzero(used_rb, nof_rb*sizeof(bool)); + + nof_users_with_data = 0; + for(std::map::iterator iter=ue_db.begin(); iter!=ue_db.end(); ++iter) { + sched_ue *user = (sched_ue*) &iter->second; + if (user->get_pending_ul_new_data(current_tti) || !user->get_ul_harq(current_tti)->is_empty()) { + user->ue_idx = nof_users_with_data; + nof_users_with_data++; + } + } + +} + +bool ul_metric_rr::allocation_is_valid(ul_harq_proc::ul_alloc_t alloc) +{ + if (alloc.RB_start+alloc.L > nof_rb) { + return false; + } + for (uint32_t n=alloc.RB_start;nL < L;n++) { + if (!used_rb[n] && alloc->L == 0) { + alloc->RB_start = n; + } + if (!used_rb[n]) { + alloc->L++; + } else if (alloc->L > 0) { + // avoid edges + if (n < 3) { + alloc->RB_start = 0; + alloc->L = 0; + } else { + break; + } + } + } + if (!alloc->L) { + return 0; + } + + // Make sure L is allowed by SC-FDMA modulation + while (!srslte_dft_precoding_valid_prb(alloc->L)) { + alloc->L--; + } + return alloc->L == L; +} + +void ul_metric_rr::update_allocation(ul_harq_proc::ul_alloc_t alloc) +{ + if (alloc.L > available_rb) { + return; + } + if (alloc.RB_start + alloc.L > nof_rb) { + return; + } + for (uint32_t n=alloc.RB_start;nget_pending_ul_new_data(current_tti); + ul_harq_proc *h = user->get_ul_harq(current_tti); + + if (pending_data || !h->is_empty()) { + if (nof_users_with_data) { + if ((current_tti%nof_users_with_data) != user->ue_idx) { + return NULL; + } + } + } + + // Schedule retx if we have space + + if (!h->is_empty()) { + + ul_harq_proc::ul_alloc_t alloc = h->get_alloc(); + + // If can schedule the same mask, do it + if (allocation_is_valid(alloc)) { + update_allocation(alloc); + h->same_alloc(); + return h; + } + + // If not, try to find another mask in the current tti + if (new_allocation(alloc.L, &alloc)) { + update_allocation(alloc); + h->set_alloc(alloc); + return h; + } + } + // If could not schedule the reTx, or there wasn't any pending retx, find an empty PID + if (h->is_empty()) { + // Allocate resources based on pending data + if (pending_data) { + uint32_t pending_rb = user->get_required_prb_ul(pending_data); + ul_harq_proc::ul_alloc_t alloc; + new_allocation(pending_rb, &alloc); + if (alloc.L) { + update_allocation(alloc); + h->set_alloc(alloc); + return h; + } + } + } + return NULL; +} + + + +} diff --git a/srsenb/src/mac/scheduler_ue.cc b/srsenb/src/mac/scheduler_ue.cc new file mode 100644 index 000000000..178fe6446 --- /dev/null +++ b/srsenb/src/mac/scheduler_ue.cc @@ -0,0 +1,787 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2017 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of srsLTE. + * + * srsUE 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. + * + * srsUE 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 +#include + +#include "srslte/srslte.h" +#include "srslte/common/pdu.h" +#include "mac/scheduler_ue.h" +#include "mac/scheduler.h" + +#define Error(fmt, ...) log_h->error_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Warning(fmt, ...) log_h->warning_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Info(fmt, ...) log_h->info_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Debug(fmt, ...) log_h->debug_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) + +/****************************************************** + * UE class * + ******************************************************/ + +namespace srsenb { + + +/******************************************************* + * + * Initialization and configuration functions + * + *******************************************************/ + +sched_ue::sched_ue() +{ + reset(); +} + +void sched_ue::set_cfg(uint16_t rnti_, sched_interface::ue_cfg_t *cfg_, sched_interface::cell_cfg_t *cell_cfg, + srslte_regs_t *regs, srslte::log *log_h_) +{ + reset(); + + rnti = rnti_; + log_h = log_h_; + memcpy(&cell, &cell_cfg->cell, sizeof(srslte_cell_t)); + + max_mcs_dl = 28; + max_mcs_ul = 28; + + if (cfg_) { + memcpy(&cfg, cfg_, sizeof(sched_interface::ue_cfg_t)); + } + + Info("SCHED: Added user rnti=0x%x\n", rnti); + for (int i=0;i 4) { + len -= 4; + } + if (lcid < sched_interface::MAX_LC) { + if (bearer_is_ul(&lch[lcid])) { + if (lch[lcid].bsr > (int) len) { + lch[lcid].bsr -= len; + } else { + lch[lcid].bsr = 0; + } + } + } +} + +void sched_ue::set_ul_crc(uint32_t tti, bool crc_res) +{ + get_ul_harq(tti)->set_ack(crc_res); +} + +void sched_ue::set_dl_cqi(uint32_t tti, uint32_t cqi) +{ + dl_cqi = cqi; + dl_cqi_tti = tti; +} + +void sched_ue::set_ul_cqi(uint32_t tti, uint32_t cqi, uint32_t ul_ch_code) +{ + ul_cqi = cqi; + ul_cqi_tti = tti; +} + +void sched_ue::tpc_inc() { + if (power_headroom > 0) { + next_tpc_pusch = 3; + next_tpc_pucch = 3; + } + log_h->info("SCHED: Set TCP=%d for rnti=0x%x\n", next_tpc_pucch, rnti); +} + +void sched_ue::tpc_dec() { + next_tpc_pusch = 0; + next_tpc_pucch = 0; + log_h->info("SCHED: Set TCP=%d for rnti=0x%x\n", next_tpc_pucch, rnti); +} + +/******************************************************* + * + * Functions used to generate DCI grants + * + *******************************************************/ + + +// Generates a Format1 grant +int sched_ue::generate_format1(dl_harq_proc *h, + sched_interface::dl_sched_data_t *data, + uint32_t tti, + uint32_t cfi) +{ + srslte_ra_dl_dci_t *dci = &data->dci; + bzero(dci, sizeof(srslte_ra_dl_dci_t)); + + uint32_t sf_idx = tti%10; + + int mcs = 0; + int tbs = 0; + + dci->alloc_type = SRSLTE_RA_ALLOC_TYPE0; + dci->type0_alloc.rbg_bitmask = h->get_rbgmask(); + + + // If this is the first transmission for this UE, make room for MAC Contention Resolution ID + bool need_conres_ce = false; + if (is_first_dl_tx()) { + need_conres_ce = true; + } + if (h->is_empty()) { + + uint32_t req_bytes = get_pending_dl_new_data(tti); + + uint32_t nof_prb = format1_count_prb(h->get_rbgmask(), cell.nof_prb); + srslte_ra_dl_grant_t grant; + srslte_ra_dl_dci_to_grant_prb_allocation(dci, &grant, cell.nof_prb); + uint32_t nof_ctrl_symbols = cfi+(cell.nof_prb<10?1:0); + uint32_t nof_re = srslte_ra_dl_grant_nof_re(&grant, cell, sf_idx, nof_ctrl_symbols); + if (fixed_mcs_dl < 0) { + tbs = alloc_tbs(dl_cqi, nof_prb, nof_re, req_bytes, max_mcs_dl, &mcs); + } else { + tbs = srslte_ra_tbs_from_idx(srslte_ra_tbs_idx_from_mcs(fixed_mcs_dl), nof_prb); + mcs = fixed_mcs_dl; + } + + h->new_tx(tti, mcs, tbs, data->dci_location.ncce); + + Debug("SCHED: Alloc format1 new mcs=%d, tbs=%d, nof_prb=%d, req_bytes=%d\n", mcs, tbs, nof_prb, req_bytes); + } else { + h->new_retx(tti, &mcs, &tbs); + Debug("SCHED: Alloc format1 previous mcs=%d, tbs=%d\n", mcs, tbs); + } + + // Allocate MAC ConRes CE + if (need_conres_ce) { + data->pdu[0].lcid = srslte::sch_subh::CON_RES_ID; + data->nof_pdu_elems++; + Info("SCHED: Added MAC Contention Resolution CE for rnti=0x%x\n", rnti); + } + + int rem_tbs = tbs; + int x = 0; + do { + x = alloc_pdu(rem_tbs, &data->pdu[data->nof_pdu_elems]); + rem_tbs -= x; + if (x) { + data->nof_pdu_elems++; + } + } while(rem_tbs > 0 && x > 0); + + data->rnti = rnti; + + if (tbs > 0) { + dci->harq_process = h->get_id(); + dci->mcs_idx = mcs; + dci->rv_idx = sched::get_rvidx(h->nof_retx()); + dci->ndi = h->get_ndi(); + dci->tpc_pucch = next_tpc_pucch; + next_tpc_pucch = 1; + data->tbs = tbs; + dci->tb_en[0] = true; + dci->tb_en[1] = false; + } + return tbs; +} + + +int sched_ue::generate_format0(ul_harq_proc *h, + sched_interface::ul_sched_data_t *data, + uint32_t tti, + bool cqi_request) +{ + srslte_ra_ul_dci_t *dci = &data->dci; + bzero(dci, sizeof(srslte_ra_ul_dci_t)); + + int mcs = 0; + int tbs = 0; + + ul_harq_proc::ul_alloc_t allocation = h->get_alloc(); + + if (h->get_rar_mcs(&mcs)) { + tbs = srslte_ra_tbs_from_idx(srslte_ra_tbs_idx_from_mcs(mcs), allocation.L)/8; + h->new_tx(tti, mcs, tbs); + } else if (h->is_empty()) { + + uint32_t req_bytes = get_pending_ul_new_data(tti); + + uint32_t N_srs = 0; + uint32_t nof_re = (2*(SRSLTE_CP_NSYMB(cell.cp)-1) - N_srs)*allocation.L*SRSLTE_NRE; + if (fixed_mcs_ul < 0) { + tbs = alloc_tbs(ul_cqi, allocation.L, nof_re, req_bytes, max_mcs_ul, &mcs); + } else { + tbs = srslte_ra_tbs_from_idx(srslte_ra_tbs_idx_from_mcs(fixed_mcs_ul), allocation.L); + mcs = fixed_mcs_ul; + } + + h->new_tx(tti, mcs, tbs); + + } else { + h->new_retx(tti, &mcs, NULL); + tbs = srslte_ra_tbs_from_idx(srslte_ra_tbs_idx_from_mcs(mcs), allocation.L)/8; + } + + data->rnti = rnti; + data->tbs = tbs; + + if (tbs > 0) { + dci->type2_alloc.L_crb = allocation.L; + dci->type2_alloc.RB_start = allocation.RB_start; + dci->mcs_idx = mcs; + dci->rv_idx = sched::get_rvidx(h->nof_retx()); + dci->ndi = h->get_ndi(); + dci->cqi_request = cqi_request; + dci->freq_hop_fl = srslte_ra_ul_dci_t::SRSLTE_RA_PUSCH_HOP_DISABLED; + dci->tpc_pusch = next_tpc_pusch; + next_tpc_pusch = 1; + } + + return tbs; +} + +/******************************************************* + * + * Functions used by scheduler or scheduler metric objects + * + *******************************************************/ + +bool sched_ue::bearer_is_ul(ue_bearer_t *lch) { + return lch->cfg.direction == sched_interface::ue_bearer_cfg_t::UL || lch->cfg.direction == sched_interface::ue_bearer_cfg_t::BOTH; +} + +bool sched_ue::bearer_is_dl(ue_bearer_t *lch) { + return lch->cfg.direction == sched_interface::ue_bearer_cfg_t::DL || lch->cfg.direction == sched_interface::ue_bearer_cfg_t::BOTH; +} + +uint32_t sched_ue::get_max_retx() { + return cfg.maxharq_tx; +} + +bool sched_ue::is_first_dl_tx() +{ + for (int i=0;i 0) { + return false; + } + } + return true; +} + +bool sched_ue::needs_cqi(uint32_t tti, bool will_be_sent) +{ + bool ret = false; + if (phy_config_dedicated_enabled && + cfg.aperiodic_cqi_period && + get_pending_dl_new_data(tti) > 0) + { + uint32_t interval = srslte_tti_interval(tti, dl_cqi_tti); + bool needscqi = interval >= cfg.aperiodic_cqi_period; + if (needscqi) { + uint32_t interval_sent = srslte_tti_interval(tti, cqi_request_tti); + if (interval_sent >= 16) { + if (will_be_sent) { + cqi_request_tti = tti; + } + Debug("SCHED: Needs_cqi, last_sent=%d, will_be_sent=%d\n", cqi_request_tti, will_be_sent); + ret = true; + } + } + } + return ret; +} + +uint32_t sched_ue::get_pending_dl_new_data(uint32_t tti) +{ + uint32_t pending_data = 0; + for (int i=0;i pending_ul_data) { + pending_data -= pending_ul_data; + } else { + pending_data = 0; + } + return pending_data; +} + +uint32_t sched_ue::get_pending_ul_old_data() +{ + uint32_t pending_data = 0; + for (int i=0;i 0) { + nbytes = tbs; + } else if (tbs < 0) { + return 0; + } + } + return n; +} + +uint32_t sched_ue::get_required_prb_ul(uint32_t req_bytes) +{ + int mcs = 0; + int tbs = 0; + uint32_t nbytes = 0; + uint32_t N_srs = 0; + + uint32_t n = 0; + if (req_bytes == 0) { + return 0; + } + + for (n=1;n 0) { + nbytes = tbs; + } + } + + while (!srslte_dft_precoding_valid_prb(n)) { + n++; + } + + return n; +} + +bool sched_ue::is_sr_triggered() +{ + return sr; +} + +/* Gets HARQ process with oldest pending retx */ +dl_harq_proc* sched_ue::get_pending_dl_harq(uint32_t tti) +{ + int oldest_idx=-1; + uint32_t oldest_tti = 0; + for (int i=0;i oldest_tti) { + oldest_idx = i; + oldest_tti = x; + } + } + } + if (oldest_idx >= 0) { + return &dl_harq[oldest_idx]; + } else { + return NULL; + } +} + +dl_harq_proc* sched_ue::get_empty_dl_harq() +{ + for (int i=0;i max_coderate); + Debug("SCHED: CQI=%d, l=%d, nof_bits=%d, coderate=%.2f, max_coderate=%.2f\n", dl_cqi, l, nof_bits, coderate, max_coderate); + return l; +} + +sched_ue::sched_dci_cce_t* sched_ue::get_locations(uint32_t cfi, uint32_t sf_idx) +{ + if (cfi > 0 && cfi <= 3) { + return &dci_locations[cfi-1][sf_idx]; + } else { + Error("SCHED: Invalid CFI=%d\n", cfi); + return &dci_locations[0][sf_idx]; + } +} + +/* Allocates first available RLC PDU */ +int sched_ue::alloc_pdu(int tbs_bytes, sched_interface::dl_sched_pdu_t* pdu) +{ + // TODO: Implement lcid priority (now lowest index is lowest priority) + int x = 0; + int i = 0; + for (i=0;ilcid = i-1; + pdu->nbytes = x; + Debug("SCHED: Allocated lcid=%d, nbytes=%d, tbs_bytes=%d\n", pdu->lcid, pdu->nbytes, tbs_bytes); + } + return x; +} + +uint32_t sched_ue::format1_count_prb(uint32_t bitmask, uint32_t cell_nof_prb) { + uint32_t P = srslte_ra_type0_P(cell_nof_prb); + uint32_t nb = (int) ceilf((float) cell_nof_prb / P); + + uint32_t nof_prb = 0; + for (uint32_t i = 0; i < nb; i++) { + if (bitmask & (1 << (nb - i - 1))) { + for (uint32_t j = 0; j < P; j++) { + if (i*P+j < cell_nof_prb) { + nof_prb++; + } + } + } + } + return nof_prb; +} + +int sched_ue::cqi_to_tbs(uint32_t cqi, uint32_t nof_prb, uint32_t nof_re, uint32_t max_mcs, uint32_t *mcs) { + float max_coderate = srslte_cqi_to_coderate(cqi); + int sel_mcs = max_mcs+1; + float coderate = 99; + int tbs = 0; + + do { + sel_mcs--; + uint32_t tbs_idx = srslte_ra_tbs_idx_from_mcs(sel_mcs); + tbs = srslte_ra_tbs_from_idx(tbs_idx, nof_prb); + coderate = srslte_pdsch_coderate(tbs, nof_re); + } while(sel_mcs > 0 && coderate >= max_coderate); + if (mcs) { + *mcs = (uint32_t) sel_mcs; + } + return tbs; +} + +/* In this scheduler we tend to use all the available bandwidth and select the MCS + * that approximates the minimum between the capacity and the requested rate + */ +int sched_ue::alloc_tbs(uint32_t cqi, + uint32_t nof_prb, + uint32_t nof_re, + uint32_t req_bytes, + uint32_t max_mcs, + int *mcs) +{ + uint32_t sel_mcs = 0; + int tbs = cqi_to_tbs(cqi, nof_prb, nof_re, max_mcs, &sel_mcs)/8; + + /* If less bytes are requested, lower the MCS */ + if (tbs > (int) req_bytes && req_bytes > 0) { + uint32_t req_tbs_idx = srslte_ra_tbs_to_table_idx(req_bytes*8, nof_prb); + uint32_t req_mcs = srslte_ra_mcs_from_tbs_idx(req_tbs_idx); + if (req_mcs < sel_mcs) { + sel_mcs = req_mcs; + tbs = srslte_ra_tbs_from_idx(req_tbs_idx, nof_prb)/8; + } + } + // Avoid the unusual case n_prb=1, mcs=6 tbs=328 (used in voip) + if (nof_prb == 1 && sel_mcs == 6) { + sel_mcs--; + } + + if (mcs && tbs >= 0) { + *mcs = (int) sel_mcs; + } + + return tbs; +} + + +} diff --git a/srsenb/src/mac/ue.cc b/srsenb/src/mac/ue.cc new file mode 100644 index 000000000..cae9b6899 --- /dev/null +++ b/srsenb/src/mac/ue.cc @@ -0,0 +1,392 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2017 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of srsLTE. + * + * srsUE 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. + * + * srsUE 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 +#include + +#include "srslte/interfaces/enb_interfaces.h" +#include "mac/ue.h" + +#define Error(fmt, ...) log_h->error_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Warning(fmt, ...) log_h->warning_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Info(fmt, ...) log_h->info_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Debug(fmt, ...) log_h->debug_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) + + +namespace srsenb { + +void ue::config(uint16_t rnti_, uint32_t nof_prb, sched_interface *sched_, rrc_interface_mac *rrc_, rlc_interface_mac *rlc_, srslte::log *log_h_) +{ + rnti = rnti_; + rlc = rlc_; + rrc = rrc_; + log_h = log_h_; + sched = sched_; + pdus.init(this, log_h); + + for (int i=0;i 0) { + if (!pending_buffers[tti%NOF_HARQ_PROCESSES]) { + ret = pdus.request(len); + pending_buffers[tti%NOF_HARQ_PROCESSES] = ret; + } else { + log_h->console("Error requesting buffer for pid %d, not pushed yet\n", tti%NOF_HARQ_PROCESSES); + log_h->error("Requesting buffer for pid %d, not pushed yet\n", tti%NOF_HARQ_PROCESSES); + } + } else { + log_h->warning("Requesting buffer for zero bytes\n"); + } + pthread_mutex_unlock(&mutex); + return ret; +} + +bool ue::process_pdus() +{ + return pdus.process_pdus(); +} + +void ue::set_tti(uint32_t tti) { + last_tti = tti; +} + +#include + +void ue::process_pdu(uint8_t* pdu, uint32_t nof_bytes, uint32_t tstamp) +{ + // Unpack ULSCH MAC PDU + mac_msg_ul.init_rx(nof_bytes, true); + mac_msg_ul.parse_packet(pdu); + + if (pcap) { + pcap->write_ul_crnti(pdu, nof_bytes, rnti, true, last_tti); + } + + while(mac_msg_ul.next()) { + assert(mac_msg_ul.get()); + if (mac_msg_ul.get()->is_sdu()) + { + // Route logical channel + log_h->debug_hex(mac_msg_ul.get()->get_sdu_ptr(), mac_msg_ul.get()->get_payload_size(), + "PDU: rnti=0x%x, lcid=%d, %d bytes\n", + rnti, mac_msg_ul.get()->get_sdu_lcid(), mac_msg_ul.get()->get_payload_size()); + + + /* In some cases, an uplink transmission with only CQI has all zeros and gets routed to RRC + * Compute the checksum if lcid=0 and avoid routing in that case + */ + bool route_pdu = true; + if (mac_msg_ul.get()->get_sdu_lcid() == 0) { + uint8_t *x = mac_msg_ul.get()->get_sdu_ptr(); + uint32_t sum = 0; + for (uint32_t i=0;iget_payload_size();i++) { + sum += x[i]; + } + if (sum == 0) { + route_pdu = false; + Warning("Received all zero PDU\n"); + } + } + + if (route_pdu) { + rlc->write_pdu(rnti, + mac_msg_ul.get()->get_sdu_lcid(), + mac_msg_ul.get()->get_sdu_ptr(), + mac_msg_ul.get()->get_payload_size()); + } + + // Indicate scheduler to update BSR counters + sched->ul_recv_len(rnti, mac_msg_ul.get()->get_sdu_lcid(), mac_msg_ul.get()->get_payload_size()); + + // Save contention resolution if lcid == 0 + if (mac_msg_ul.get()->get_sdu_lcid() == 0 && route_pdu) { + uint32_t nbytes = srslte::sch_subh::MAC_CE_CONTRES_LEN; + if (mac_msg_ul.get()->get_payload_size() >= nbytes) { + uint8_t *ue_cri_ptr = (uint8_t*) &conres_id; + uint8_t *pkt_ptr = mac_msg_ul.get()->get_sdu_ptr(); // Warning here: we want to include the + for (uint32_t i=0;iget_payload_size()); + } + } + } else { + // Process MAC Control Element + if (!process_ce(mac_msg_ul.get())) { + Warning("Received Subheader with invalid or unkonwn LCID\n"); + } + } + } + + Debug("MAC PDU processed\n"); + +} + +void ue::deallocate_pdu(uint32_t tti) +{ + if (pending_buffers[tti%NOF_HARQ_PROCESSES]) { + pdus.deallocate(pending_buffers[tti%NOF_HARQ_PROCESSES]); + pending_buffers[tti%NOF_HARQ_PROCESSES] = NULL; + } else { + log_h->console("Error deallocating buffer for pid=%d. Not requested\n", tti%NOF_HARQ_PROCESSES); + } +} + +void ue::push_pdu(uint32_t tti, uint32_t len) +{ + if (pending_buffers[tti%NOF_HARQ_PROCESSES]) { + pdus.push(pending_buffers[tti%NOF_HARQ_PROCESSES], len); + pending_buffers[tti%NOF_HARQ_PROCESSES] = NULL; + } else { + log_h->console("Error pushing buffer for pid=%d. Not requested\n", tti%NOF_HARQ_PROCESSES); + } +} + +bool ue::process_ce(srslte::sch_subh *subh) { + uint32_t buff_size[4] = {0, 0, 0, 0}; + uint32_t idx = 0; + float phr = 0; + uint16_t old_rnti = 0; + switch(subh->ce_type()) { + case srslte::sch_subh::PHR_REPORT: + phr = subh->get_phr(); + Info("CE: Received PHR from rnti=0x%x, value=%.0f\n", rnti, phr); + sched->ul_phr(rnti, (int) phr); + metrics_phr(phr); + break; + case srslte::sch_subh::CRNTI: + old_rnti = subh->get_c_rnti(); + Info("CE: Received C-RNTI from temp_rnti=0x%x, rnti=0x%x\n", rnti, old_rnti); + if (sched->ue_exists(old_rnti)) { + rrc->upd_user(rnti, old_rnti); + rnti = old_rnti; + } else { + Error("Updating user C-RNTI: rnti=0x%x already released\n", old_rnti); + } + break; + case srslte::sch_subh::TRUNC_BSR: + case srslte::sch_subh::SHORT_BSR: + case srslte::sch_subh::LONG_BSR: + idx = subh->get_bsr(buff_size); + if (idx > 0) { + // Indicate BSR to scheduler + sched->ul_bsr(rnti, idx, buff_size[idx]); + Info("CE: Received BSR rnti=0x%x, lcid=%d, value=%d\n", rnti, idx, buff_size[idx]); + } else if (idx == 0) { + // TODO: map lcid group to lcid + for (int i=0;i<4;i++) { + sched->ul_bsr(rnti, i, buff_size[i]); + } + Info("CE: Received Long BSR rnti=0x%x, value=%d,%d,%d,%d\n", rnti, + buff_size[0], buff_size[1], buff_size[2], buff_size[3]); + } else { + printf("Error!\n"); + } + break; + case srslte::sch_subh::PADDING: + Debug("CE: Received padding for rnti=0x%x\n", rnti); + break; + default: + Error("CE: Invalid lcid=0x%x\n", subh->ce_type()); + break; + } + return true; +} + + +int ue::read_pdu(uint32_t lcid, uint8_t *payload, uint32_t requested_bytes) +{ + return rlc->read_pdu(rnti, lcid, payload, requested_bytes); +} + +void ue::allocate_sdu(srslte::sch_pdu *pdu, uint32_t lcid, uint32_t total_sdu_len) +{ + int sdu_space = pdu->get_sdu_space(); + if (sdu_space > 0) { + int sdu_len = SRSLTE_MIN(total_sdu_len, (uint32_t) sdu_space); + int n=1; + while(sdu_len > 0 && n > 0) { + if (pdu->new_subh()) { // there is space for a new subheader + log_h->debug("SDU: set_sdu(), lcid=%d, sdu_len=%d, sdu_space=%d\n", lcid, sdu_len, sdu_space); + n = pdu->get()->set_sdu(lcid, sdu_len, this); + if (n > 0) { // new SDU could be added + sdu_len -= n; + log_h->debug("SDU: rnti=0x%x, lcid=%d, nbytes=%d, rem_len=%d\n", + rnti, lcid, n, sdu_len); + } else { + Debug("Could not add SDU lcid=%d nbytes=%d, space=%d\n", lcid, sdu_len, sdu_space); + pdu->del_subh(); + } + } else { + n=0; + } + } + } +} + +void ue::allocate_ce(srslte::sch_pdu *pdu, uint32_t lcid) +{ + switch((srslte::sch_subh::cetype) lcid) { + case srslte::sch_subh::CON_RES_ID: + if (pdu->new_subh()) { + if (pdu->get()->set_con_res_id(conres_id)) { + Info("CE: Added Contention Resolution ID=0x%lx\n", conres_id); + } else { + Error("CE: Setting Contention Resolution ID CE\n"); + } + } else { + Error("CE: Setting Contention Resolution ID CE. No space for a subheader\n"); + } + break; + default: + Error("CE: Allocating CE=0x%x. Not supported\n", lcid); + break; + } +} + +uint8_t* ue::generate_pdu(sched_interface::dl_sched_pdu_t pdu[sched_interface::MAX_RLC_PDU_LIST], + uint32_t nof_pdu_elems, uint32_t grant_size) +{ + uint8_t *ret = NULL; + pthread_mutex_lock(&mutex); + if (rlc) + { + mac_msg_dl.init_tx(tx_payload_buffer, grant_size, false); + for (uint32_t i=0;iget_ul_buffer(rnti); + metrics.dl_buffer = sched->get_dl_buffer(rnti); + + memcpy(metrics_, &metrics, sizeof(mac_metrics_t)); + + phr_counter = 0; + bzero(&metrics, sizeof(mac_metrics_t)); +} + +void ue::metrics_phr(float phr) { + metrics.phr = SRSLTE_VEC_CMA(phr, metrics.phr, phr_counter); + phr_counter++; +} + +void ue::metrics_rx(bool crc, uint32_t tbs) +{ + if (crc) { + metrics.rx_brate += tbs*8; + } else { + metrics.rx_errors++; + } + metrics.rx_pkts++; +} + +void ue::metrics_tx(bool crc, uint32_t tbs) +{ + if (crc) { + metrics.tx_brate += tbs*8; + } else { + metrics.tx_errors++; + } + metrics.tx_pkts++; +} + + +} + diff --git a/srsenb/src/main.cc b/srsenb/src/main.cc new file mode 100644 index 000000000..a145e10d3 --- /dev/null +++ b/srsenb/src/main.cc @@ -0,0 +1,378 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2017 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of srsLTE. + * + * srsUE 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. + * + * srsUE 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 +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "enb.h" +#include "metrics_stdout.h" + +using namespace std; +using namespace srsenb; +namespace bpo = boost::program_options; + +/********************************************************************** + * Program arguments processing + ***********************************************************************/ +string config_file; + +void parse_args(all_args_t *args, int argc, char* argv[]) { + + string enb_id; + string cell_id; + string tac; + string mcc; + string mnc; + + // Command line only options + bpo::options_description general("General options"); + general.add_options() + ("help,h", "Produce help message") + ("version,v", "Print version information and exit") + ; + + // Command line or config file options + bpo::options_description common("Configuration options"); + common.add_options() + + ("enb.enb_id", bpo::value(&enb_id)->default_value("0x0"), "eNodeB ID") + ("enb.name", bpo::value(&args->enb.s1ap.enb_name)->default_value("srsenb01"), "eNodeB Name") + ("enb.cell_id", bpo::value(&cell_id)->default_value("0x0"), "Cell ID") + ("enb.tac", bpo::value(&tac)->default_value("0x0"), "Tracking Area Code") + ("enb.mcc", bpo::value(&mcc)->default_value("001"), "Mobile Country Code") + ("enb.mnc", bpo::value(&mnc)->default_value("01"), "Mobile Network Code") + ("enb.mme_addr", bpo::value(&args->enb.s1ap.mme_addr)->default_value("127.0.0.1"),"IP address of MME for S1 connnection") + ("enb.gtp_bind_addr", bpo::value(&args->enb.s1ap.gtp_bind_addr)->default_value("192.168.3.1"), "Local IP address to bind for GTP connection") + ("enb.phy_cell_id", bpo::value(&args->enb.pci)->default_value(0), "Physical Cell Identity (PCI)") + ("enb.n_prb", bpo::value(&args->enb.n_prb)->default_value(25), "Number of PRB") + + ("enb_files.sib_config", bpo::value(&args->enb_files.sib_config)->default_value("sib.conf"), "SIB configuration files") + ("enb_files.rr_config", bpo::value(&args->enb_files.rr_config)->default_value("rr.conf"), "RR configuration files") + ("enb_files.drb_config", bpo::value(&args->enb_files.drb_config)->default_value("drb.conf"), "DRB configuration files") + + ("rf.dl_earfcn", bpo::value(&args->rf.dl_earfcn)->default_value(3400), "Downlink EARFCN") + ("rf.ul_earfcn", bpo::value(&args->rf.ul_earfcn)->default_value(0), "Uplink EARFCN (Default based on Downlink EARFCN)") + ("rf.rx_gain", bpo::value(&args->rf.rx_gain)->default_value(50), "Front-end receiver gain") + ("rf.tx_gain", bpo::value(&args->rf.tx_gain)->default_value(70), "Front-end transmitter gain") + ("rf.dl_freq", bpo::value(&args->rf.dl_freq)->default_value(-1), "Downlink Frequency (if positive overrides EARFCN)") + ("rf.ul_freq", bpo::value(&args->rf.ul_freq)->default_value(-1), "Uplink Frequency (if positive overrides EARFCN)") + + ("rf.device_name", bpo::value(&args->rf.device_name)->default_value("auto"), "Front-end device name") + ("rf.device_args", bpo::value(&args->rf.device_args)->default_value("auto"), "Front-end device arguments") + ("rf.time_adv_nsamples", bpo::value(&args->rf.time_adv_nsamples)->default_value("auto"), "Transmission time advance") + ("rf.burst_preamble_us", bpo::value(&args->rf.burst_preamble)->default_value("auto"), "Transmission time advance") + + ("pcap.enable", bpo::value(&args->pcap.enable)->default_value(false), "Enable MAC packet captures for wireshark") + ("pcap.filename", bpo::value(&args->pcap.filename)->default_value("ue.pcap"), "MAC layer capture filename") + + ("gui.enable", bpo::value(&args->gui.enable)->default_value(false), "Enable GUI plots") + + ("log.phy_level", bpo::value(&args->log.phy_level), "PHY log level") + ("log.phy_hex_limit", bpo::value(&args->log.phy_hex_limit), "PHY log hex dump limit") + ("log.mac_level", bpo::value(&args->log.mac_level), "MAC log level") + ("log.mac_hex_limit", bpo::value(&args->log.mac_hex_limit), "MAC log hex dump limit") + ("log.rlc_level", bpo::value(&args->log.rlc_level), "RLC log level") + ("log.rlc_hex_limit", bpo::value(&args->log.rlc_hex_limit), "RLC log hex dump limit") + ("log.pdcp_level", bpo::value(&args->log.pdcp_level), "PDCP log level") + ("log.pdcp_hex_limit",bpo::value(&args->log.pdcp_hex_limit), "PDCP log hex dump limit") + ("log.rrc_level", bpo::value(&args->log.rrc_level), "RRC log level") + ("log.rrc_hex_limit", bpo::value(&args->log.rrc_hex_limit), "RRC log hex dump limit") + ("log.gtpu_level", bpo::value(&args->log.gtpu_level), "GTPU log level") + ("log.gtpu_hex_limit",bpo::value(&args->log.gtpu_hex_limit), "GTPU log hex dump limit") + ("log.s1ap_level", bpo::value(&args->log.s1ap_level), "S1AP log level") + ("log.s1ap_hex_limit",bpo::value(&args->log.s1ap_hex_limit), "S1AP log hex dump limit") + + ("log.all_level", bpo::value(&args->log.all_level)->default_value("info"), "ALL log level") + ("log.all_hex_limit", bpo::value(&args->log.all_hex_limit)->default_value(32), "ALL log hex dump limit") + + ("log.filename", bpo::value(&args->log.filename)->default_value("/tmp/ue.log"),"Log filename") + + /* MCS section */ + ("scheduler.pdsch_mcs", + bpo::value(&args->expert.mac.sched.pdsch_mcs)->default_value(-1), + "Optional fixed PDSCH MCS (ignores reported CQIs if specified)") + ("scheduler.pdsch_max_mcs", + bpo::value(&args->expert.mac.sched.pdsch_max_mcs)->default_value(-1), + "Optional PDSCH MCS limit") + ("scheduler.pusch_mcs", + bpo::value(&args->expert.mac.sched.pusch_mcs)->default_value(-1), + "Optional fixed PUSCH MCS (ignores reported CQIs if specified)") + ("scheduler.pusch_max_mcs", + bpo::value(&args->expert.mac.sched.pusch_max_mcs)->default_value(16), + "Optional PUSCH MCS limit") + ("scheduler.nof_ctrl_symbols", + bpo::value(&args->expert.mac.sched.nof_ctrl_symbols)->default_value(3), + "Number of control symbols") + + + /* Expert section */ + + ("expert.metrics_period_secs", + bpo::value(&args->expert.metrics_period_secs)->default_value(1.0), + "Periodicity for metrics in seconds") + + ("expert.pregenerate_signals", + bpo::value(&args->expert.phy.pregenerate_signals)->default_value(false), + "Pregenerate uplink signals after attach. Improves CPU performance.") + + ("expert.pusch_max_its", + bpo::value(&args->expert.phy.pusch_max_its)->default_value(4), + "Maximum number of turbo decoder iterations") + + ("expert.tx_amplitude", + bpo::value(&args->expert.phy.tx_amplitude)->default_value(0.8), + "Transmit amplitude factor") + + ("expert.nof_phy_threads", + bpo::value(&args->expert.phy.nof_phy_threads)->default_value(2), + "Number of PHY threads") + + ("expert.link_failure_nof_err", + bpo::value(&args->expert.mac.link_failure_nof_err)->default_value(50), + "Number of PUSCH failures after which a radio-link failure is triggered") + + ("expert.max_prach_offset_us", + bpo::value(&args->expert.phy.max_prach_offset_us)->default_value(30), + "Maximum allowed RACH offset (in us)") + + ("expert.equalizer_mode", + bpo::value(&args->expert.phy.equalizer_mode)->default_value("mmse"), + "Equalizer mode") + + ("expert.estimator_fil_w", + bpo::value(&args->expert.phy.estimator_fil_w)->default_value(0.1), + "Chooses the coefficients for the 3-tap channel estimator centered filter.") + + ("expert.rrc_inactivity_timer", + bpo::value(&args->expert.rrc_inactivity_timer)->default_value(5000), + "Inactivity timer in ms") + + + ("rf_calibration.tx_corr_dc_gain", bpo::value(&args->rf_cal.tx_corr_dc_gain)->default_value(0.0), "TX DC offset gain correction") + ("rf_calibration.tx_corr_dc_phase", bpo::value(&args->rf_cal.tx_corr_dc_phase)->default_value(0.0), "TX DC offset phase correction") + ("rf_calibration.tx_corr_iq_i", bpo::value(&args->rf_cal.tx_corr_iq_i)->default_value(0.0), "TX IQ imbalance inphase correction") + ("rf_calibration.tx_corr_iq_q", bpo::value(&args->rf_cal.tx_corr_iq_q)->default_value(0.0), "TX IQ imbalance quadrature correction") + + ; + + // Positional options - config file location + bpo::options_description position("Positional options"); + position.add_options() + ("config_file", bpo::value< string >(&config_file), "eNodeB configuration file") + ; + bpo::positional_options_description p; + p.add("config_file", -1); + + // these options are allowed on the command line + bpo::options_description cmdline_options; + cmdline_options.add(common).add(position).add(general); + + // parse the command line and store result in vm + bpo::variables_map vm; + bpo::store(bpo::command_line_parser(argc, argv).options(cmdline_options).positional(p).run(), vm); + bpo::notify(vm); + + // help option was given - print usage and exit + if (vm.count("help")) { + cout << "Usage: " << argv[0] << " [OPTIONS] config_file" << endl << endl; + cout << common << endl << general << endl; + exit(0); + } + + // print version number and exit + // print version number and exit + if (vm.count("version")) { + cout << "Version " << + srslte_get_version_major() << "." << + srslte_get_version_minor() << "." << + srslte_get_version_patch() << endl; + exit(0); + } + + // no config file given - print usage and exit + if (!vm.count("config_file")) { + cout << "Error: Configuration file not provided" << endl; + cout << "Usage: " << argv[0] << " [OPTIONS] config_file" << endl << endl; + exit(0); + } else { + cout << "Reading configuration file " << config_file << "..." << endl; + ifstream conf(config_file.c_str(), ios::in); + if(conf.fail()) { + cout << "Failed to read configuration file " << config_file << " - exiting" << endl; + exit(1); + } + bpo::store(bpo::parse_config_file(conf, common), vm); + bpo::notify(vm); + } + + // Convert hex strings + { + std::stringstream sstr; + sstr << std::hex << vm["enb.enb_id"].as(); + sstr >> args->enb.s1ap.enb_id; + } + { + std::stringstream sstr; + sstr << std::hex << vm["enb.cell_id"].as(); + uint16_t tmp; // Need intermediate uint16_t as uint8_t is treated as char + sstr >> tmp; + args->enb.s1ap.cell_id = tmp; + } + { + std::stringstream sstr; + sstr << std::hex << vm["enb.tac"].as(); + sstr >> args->enb.s1ap.tac; + } + + // Convert MCC/MNC strings + if(!srslte::string_to_mcc(mcc, &args->enb.s1ap.mcc)) { + cout << "Error parsing enb.mcc:" << mcc << " - must be a 3-digit string." << endl; + } + if(!srslte::string_to_mnc(mnc, &args->enb.s1ap.mnc)) { + cout << "Error parsing enb.mnc:" << mnc << " - must be a 2 or 3-digit string." << endl; + } + + + // Apply all_level to any unset layers + if (vm.count("log.all_level")) { + if(!vm.count("log.phy_level")) { + args->log.phy_level = args->log.all_level; + } + if(!vm.count("log.mac_level")) { + args->log.mac_level = args->log.all_level; + } + if(!vm.count("log.rlc_level")) { + args->log.rlc_level = args->log.all_level; + } + if(!vm.count("log.pdcp_level")) { + args->log.pdcp_level = args->log.all_level; + } + if(!vm.count("log.rrc_level")) { + args->log.rrc_level = args->log.all_level; + } + if(!vm.count("log.gtpu_level")) { + args->log.gtpu_level = args->log.all_level; + } + if(!vm.count("log.s1ap_level")) { + args->log.s1ap_level = args->log.all_level; + } + } + + // Apply all_hex_limit to any unset layers + if (vm.count("log.all_hex_limit")) { + if(!vm.count("log.phy_hex_limit")) { + args->log.phy_hex_limit = args->log.all_hex_limit; + } + if(!vm.count("log.mac_hex_limit")) { + args->log.mac_hex_limit = args->log.all_hex_limit; + } + if(!vm.count("log.rlc_hex_limit")) { + args->log.rlc_hex_limit = args->log.all_hex_limit; + } + if(!vm.count("log.pdcp_hex_limit")) { + args->log.pdcp_hex_limit = args->log.all_hex_limit; + } + if(!vm.count("log.rrc_hex_limit")) { + args->log.rrc_hex_limit = args->log.all_hex_limit; + } + if(!vm.count("log.gtpu_hex_limit")) { + args->log.gtpu_hex_limit = args->log.all_hex_limit; + } + if(!vm.count("log.s1ap_hex_limit")) { + args->log.s1ap_hex_limit = args->log.all_hex_limit; + } + } +} + +static bool running = true; +static bool do_metrics = false; + +void sig_int_handler(int signo) +{ + running = false; +} + +void *input_loop(void *m) +{ + metrics_stdout *metrics = (metrics_stdout*) m; + char key; + while(running) { + cin >> key; + if('t' == key) { + do_metrics = !do_metrics; + if(do_metrics) { + cout << "Enter t to stop trace." << endl; + } else { + cout << "Enter t to restart trace." << endl; + } + metrics->toggle_print(do_metrics); + } + } + return NULL; +} + +int main(int argc, char *argv[]) +{ + signal(SIGINT, sig_int_handler); + all_args_t args; + metrics_stdout metrics; + enb *enb = enb::get_instance(); + + cout << "--- Software Radio Systems LTE eNodeB ---" << endl << endl; + + parse_args(&args, argc, argv); + if(!enb->init(&args)) { + exit(1); + } + metrics.init(enb, args.expert.metrics_period_secs); + + pthread_t input; + pthread_create(&input, NULL, &input_loop, &metrics); + + bool plot_started = false; + bool signals_pregenerated = false; + while(running) { + if (!plot_started && args.gui.enable) { + enb->start_plot(); + plot_started = true; + } + sleep(1); + } + pthread_cancel(input); + metrics.stop(); + enb->stop(); + cout << "--- exiting ---" << endl; + exit(0); +} diff --git a/srsenb/src/metrics_stdout.cc b/srsenb/src/metrics_stdout.cc new file mode 100644 index 000000000..dc6b6d575 --- /dev/null +++ b/srsenb/src/metrics_stdout.cc @@ -0,0 +1,200 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2017 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of srsLTE. + * + * srsUE 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. + * + * srsUE 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 "metrics_stdout.h" + +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace std; + +namespace srsenb{ + +char const * const prefixes[2][9] = +{ + { "", "m", "u", "n", "p", "f", "a", "z", "y", }, + { "", "k", "M", "G", "T", "P", "E", "Z", "Y", }, +}; + +metrics_stdout::metrics_stdout() + :started(false) + ,do_print(false) + ,n_reports(10) +{ +} + +bool metrics_stdout::init(enb_metrics_interface *u, float report_period_secs) +{ + enb_ = u; + metrics_report_period = report_period_secs; + + started = true; + pthread_create(&metrics_thread, NULL, &metrics_thread_start, this); + return true; +} + +void metrics_stdout::stop() +{ + if(started) + { + started = false; + pthread_join(metrics_thread, NULL); + } +} + +void metrics_stdout::toggle_print(bool b) +{ + do_print = b; +} + +void* metrics_stdout::metrics_thread_start(void *m_) +{ + metrics_stdout *m = (metrics_stdout*)m_; + m->metrics_thread_run(); + return NULL; +} + +void metrics_stdout::metrics_thread_run() +{ + while(started) + { + usleep(metrics_report_period*1e6); + if(enb_->get_metrics(metrics)) { + if (metrics.rrc.n_ues > 0) { + print_metrics(); + } + } else { + print_disconnect(); + } + } +} + +void metrics_stdout::print_metrics() +{ + if(!do_print) + return; + + if(++n_reports > 10) + { + n_reports = 0; + cout << endl; + cout << "------DL-------------------UL----------------" << endl; + cout << "rnti mcs brate bler snr phr turbo mcs brate bler" << endl; + } + if (metrics.rrc.n_ues > 0) { + + for (int i=0;i metrics.mac[i].tx_pkts) { + printf("tx caution errors %d > %d\n", metrics.mac[i].tx_errors, metrics.mac[i].tx_pkts); + } + if (metrics.mac[i].rx_errors > metrics.mac[i].rx_pkts) { + printf("rx caution errors %d > %d\n", metrics.mac[i].rx_errors, metrics.mac[i].rx_pkts); + } + + cout << std::hex << metrics.mac[i].rnti << " "; + cout << float_to_string(metrics.phy[i].dl.mcs, 2); + if (metrics.mac[i].tx_brate > 0 && metrics_report_period) { + cout << float_to_eng_string((float) metrics.mac[i].tx_brate/metrics_report_period, 2); + } else { + cout << float_to_string(0, 2); + } + if (metrics.mac[i].tx_pkts > 0 && metrics.mac[i].tx_errors) { + cout << float_to_string((float) 100*metrics.mac[i].tx_errors/metrics.mac[i].tx_pkts, 2) << "%"; + } else { + cout << float_to_string(0, 2) << "%"; + } + cout << float_to_string(metrics.phy[i].ul.sinr, 2); + cout << float_to_string(metrics.mac[i].phr, 2); + cout << float_to_string(metrics.phy[i].ul.turbo_iters, 2); + cout << float_to_string(metrics.phy[i].ul.mcs, 2); + if (metrics.mac[i].rx_brate > 0 && metrics_report_period) { + cout << float_to_eng_string((float) metrics.mac[i].rx_brate/metrics_report_period, 2); + } else { + cout << float_to_string(0, 2); + } + if (metrics.mac[i].rx_pkts > 0 && metrics.mac[i].rx_errors > 0) { + cout << float_to_string((float) 100*metrics.mac[i].rx_errors/metrics.mac[i].rx_pkts, 2) << "%"; + } else { + cout << float_to_string(0, 2) << "%"; + } + cout << endl; + } + } else { + cout << "--- No users ---" << endl; + } + if(metrics.rf.rf_error) { + printf("RF status: O=%d, U=%d, L=%d\n", metrics.rf.rf_o, metrics.rf.rf_u, metrics.rf.rf_l); + } + +} + +void metrics_stdout::print_disconnect() +{ + if(do_print) { + cout << "--- disconnected ---" << endl; + } +} + +std::string metrics_stdout::float_to_string(float f, int digits) +{ + std::ostringstream os; + const int precision = (f == 0.0) ? digits-1 : digits - log10(fabs(f))-2*DBL_EPSILON; + os << std::setw(6) << std::fixed << std::setprecision(precision) << f; + return os.str(); +} + +std::string metrics_stdout::float_to_eng_string(float f, int digits) +{ + const int degree = (f == 0.0) ? 0 : lrint( floor( log10( fabs( f ) ) / 3) ); + + std::string factor; + + if ( abs( degree ) < 9 ) + { + if(degree < 0) + factor = prefixes[0][ abs( degree ) ]; + else + factor = prefixes[1][ abs( degree ) ]; + } else { + return "failed"; + } + + const double scaled = f * pow( 1000.0, -degree ); + if (degree != 0) { + return float_to_string(scaled, digits) + factor; + } else { + return " " + float_to_string(scaled, digits) + factor; + } +} + +} // namespace srsue diff --git a/srsenb/src/parser.cc b/srsenb/src/parser.cc new file mode 100644 index 000000000..82e088ab2 --- /dev/null +++ b/srsenb/src/parser.cc @@ -0,0 +1,146 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2017 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of srsLTE. + * + * srsUE 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. + * + * srsUE 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 "parser.h" +#include + +namespace srsenb { + +using namespace libconfig; + +int parser::parse_section(std::string filename, parser::section *s) +{ + parser p(filename); + p.add_section(s); + return p.parse(); +} + +parser::parser(std::string filename_) +{ + filename = filename_; +} + +void parser::add_section(parser::section* s) +{ + sections.push_back(s); +} + +int parser::parse() +{ + // open file + Config cfg; + + try + { + cfg.readFile(filename.c_str()); + } + catch(const FileIOException &fioex) + { + std::cerr << "I/O error while reading file: " << filename << std::endl; + return(-1); + } + catch(const ParseException &pex) + { + std::cerr << "Parse error at " << pex.getFile() << ":" << pex.getLine() + << " - " << pex.getError() << std::endl; + return(-1); + } + + for (std::list::iterator ci = sections.begin(); ci != sections.end(); ++ci) { + section *s = *ci; + if (s->parse(cfg.getRoot())) { + return -1; + } + } + return 0; +} + +parser::section::section(std::string name_) +{ + name = name_; + enabled_value = NULL; +} + +// Fields are allocated dynamically, free all fields added to the section +parser::section::~section() +{ + for (std::list::iterator ci = fields.begin(); ci != fields.end(); ++ci) { + delete *ci; + } +} + +void parser::section::add_field(field_itf* f) +{ + fields.push_back(f); +} + +void parser::section::add_subsection(parser::section* s) +{ + sub_sections.push_back(s); +} + +void parser::section::set_optional(bool* enabled_value_) +{ + enabled_value = enabled_value_; +} + +int parser::section::parse(Setting &root) +{ + try { + for (std::list::iterator ci = fields.begin(); ci != fields.end(); ++ci) { + field_itf *f = *ci; + if (f->parse(root[name.c_str()])) { + fprintf(stderr, "Error parsing field %s in section %s\n", f->get_name(), name.c_str()); + return -1; + } + } + for (std::list::iterator ci = sub_sections.begin(); ci != sub_sections.end(); ++ci) { + section *s = *ci; + if (s->parse(root[name.c_str()])) { + fprintf(stderr, "Error parsing section %s\n", name.c_str()); + return -1; + } + } + if (enabled_value) { + *enabled_value = true; + } + } catch(const SettingNotFoundException ex) { + if (enabled_value) { + *enabled_value = false; + return 0; + } else { + std::cerr << "Error section " << name.c_str() << " not found." << std::endl; + return -1; + } + } + return 0; +} + + + + + +} diff --git a/srsenb/src/phy/CMakeLists.txt b/srsenb/src/phy/CMakeLists.txt new file mode 100644 index 000000000..beae7143a --- /dev/null +++ b/srsenb/src/phy/CMakeLists.txt @@ -0,0 +1,8 @@ +file(GLOB SOURCES "*.cc") +add_library(srsenb_phy SHARED ${SOURCES}) +target_link_libraries(srsenb_phy) + +if(ENABLE_GUI AND SRSGUI_FOUND) + target_link_libraries(srsenb_phy ${SRSGUI_LIBRARIES}) +endif(ENABLE_GUI AND SRSGUI_FOUND) + diff --git a/srsenb/src/phy/phch_common.cc b/srsenb/src/phy/phch_common.cc new file mode 100644 index 000000000..bfb0d1b0d --- /dev/null +++ b/srsenb/src/phy/phch_common.cc @@ -0,0 +1,140 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2017 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of srsLTE. + * + * srsUE 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. + * + * srsUE 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/threads.h" +#include "srslte/common/log.h" + +#include "phy/txrx.h" + +#include +#include + +#define Error(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->error_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Warning(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->warning_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Info(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->info_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Debug(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->debug_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) + +using namespace std; + + +namespace srsenb { + +void phch_common::set_nof_mutex(uint32_t nof_mutex_) { + nof_mutex = nof_mutex_; + assert(nof_mutex <= max_mutex); +} + +void phch_common::reset() { + bzero(ul_grants, sizeof(mac_interface_phy::ul_sched_t)*10); + bzero(dl_grants, sizeof(mac_interface_phy::dl_sched_t)*10); +} + +bool phch_common::init(srslte_cell_t *cell_, srslte::radio* radio_h_, mac_interface_phy *mac_) +{ + radio = radio_h_; + mac = mac_; + memcpy(&cell, cell_, sizeof(srslte_cell_t)); + + is_first_of_burst = true; + is_first_tx = true; + for (uint32_t i=0;iset_tti(tx_mutex_cnt); + radio->tx(buffer, nof_samples, tx_time); + + // Trigger next transmission + pthread_mutex_unlock(&tx_mutex[(tx_mutex_cnt+1)%nof_mutex]); + + // Trigger MAC clock + mac->tti_clock(); +} + +void phch_common::ack_clear(uint32_t sf_idx) +{ + for(std::map::iterator iter=pending_ack.begin(); iter!=pending_ack.end(); ++iter) { + pending_ack_t *p = (pending_ack_t*) &iter->second; + p->is_pending[sf_idx] = false; + } +} + +void phch_common::ack_add_rnti(uint16_t rnti) +{ + for (int sf_idx=0;sf_idx<10;sf_idx++) { + pending_ack[rnti].is_pending[sf_idx] = false; + } +} + +void phch_common::ack_rem_rnti(uint16_t rnti) +{ + pending_ack.erase(rnti); +} + +void phch_common::ack_set_pending(uint32_t sf_idx, uint16_t rnti, uint32_t last_n_pdcch) +{ + if (pending_ack.count(rnti)) { + pending_ack[rnti].is_pending[sf_idx] = true; + pending_ack[rnti].n_pdcch[sf_idx] = last_n_pdcch; + } +} + +bool phch_common::ack_is_pending(uint32_t sf_idx, uint16_t rnti, uint32_t *last_n_pdcch) +{ + if (pending_ack.count(rnti)) { + bool ret = pending_ack[rnti].is_pending[sf_idx]; + pending_ack[rnti].is_pending[sf_idx] = false; + + if (ret && last_n_pdcch) { + *last_n_pdcch = pending_ack[rnti].n_pdcch[sf_idx]; + } + return ret; + } else { + return false; + } +} + +} diff --git a/srsenb/src/phy/phch_worker.cc b/srsenb/src/phy/phch_worker.cc new file mode 100644 index 000000000..eca637635 --- /dev/null +++ b/srsenb/src/phy/phch_worker.cc @@ -0,0 +1,821 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2017 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of srsLTE. + * + * srsUE 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. + * + * srsUE 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 + +#include "srslte/common/threads.h" +#include "srslte/common/log.h" + +#include "phy/phch_worker.h" + +#define Error(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->error_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Warning(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->warning_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Info(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->info_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Debug(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->debug_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) + +using namespace std; + +// Enable this to log SI +//#define LOG_THIS(a) 1 + +// Enable this one to skip SI-RNTI +#define LOG_THIS(rnti) (rnti != 0xFFFF) + + +/* Define GUI-related things */ +#ifdef ENABLE_GUI +#include "srsgui/srsgui.h" +#include +void init_plots(srsenb::phch_worker *worker); +pthread_t plot_thread; +sem_t plot_sem; +static int plot_worker_id = -1; +#else +#warning Compiling without srsGUI support +#endif +/*********************************************/ + + + +//#define DEBUG_WRITE_FILE + +namespace srsenb { + + +phch_worker::phch_worker() +{ + phy = NULL; + reset(); +} + +#ifdef DEBUG_WRITE_FILE +FILE *f; +#endif + +void phch_worker::init(phch_common* phy_, srslte::log *log_h_) +{ + phy = phy_; + log_h = log_h_; + + pthread_mutex_init(&mutex, NULL); + + // Init cell here + signal_buffer_rx = (cf_t*) srslte_vec_malloc(2*SRSLTE_SF_LEN_PRB(phy->cell.nof_prb)*sizeof(cf_t)); + if (!signal_buffer_rx) { + fprintf(stderr, "Error allocating memory\n"); + return; + } + signal_buffer_tx = (cf_t*) srslte_vec_malloc(2*SRSLTE_SF_LEN_PRB(phy->cell.nof_prb)*sizeof(cf_t)); + if (!signal_buffer_tx) { + fprintf(stderr, "Error allocating memory\n"); + return; + } + if (srslte_enb_dl_init(&enb_dl, phy->cell)) { + fprintf(stderr, "Error initiating ENB DL\n"); + return; + } + + if (srslte_enb_ul_init(&enb_ul, + phy->cell, + NULL, + &phy->pusch_cfg, + &phy->hopping_cfg, + &phy->pucch_cfg)) + { + fprintf(stderr, "Error initiating ENB DL\n"); + return; + } + + srslte_pucch_set_threshold(&enb_ul.pucch, 0.8, 0.5); + srslte_sch_set_max_noi(&enb_ul.pusch.ul_sch, phy->params.pusch_max_its); + srslte_enb_dl_set_amp(&enb_dl, phy->params.tx_amplitude); + + Info("Worker %d configured cell %d PRB\n", get_id(), phy->cell.nof_prb); + + initiated = true; + +#ifdef DEBUG_WRITE_FILE + f = fopen("test.dat", "w"); +#endif +} + +void phch_worker::reset() +{ + initiated = false; + ue_db.clear(); +} + +cf_t* phch_worker::get_buffer_rx() +{ + return signal_buffer_rx; +} + +void phch_worker::set_time(uint32_t tti_, uint32_t tx_mutex_cnt_, srslte_timestamp_t tx_time_) +{ + tti_rx = tti_; + tti_tx = (tti_ + 4)%10240; + tti_sched_ul = (tti_ + 8)%10240; + sf_rx = tti_rx%10; + sf_tx = tti_tx%10; + sf_sched_ul = tti_sched_ul%10; + tx_mutex_cnt = tx_mutex_cnt_; + memcpy(&tx_time, &tx_time_, sizeof(srslte_timestamp_t)); +} + +int phch_worker::add_rnti(uint16_t rnti) +{ + + if (srslte_enb_dl_add_rnti(&enb_dl, rnti)) { + return -1; + } + if (srslte_enb_ul_add_rnti(&enb_ul, rnti)) { + return -1; + } + + // Create user + ue_db[rnti].rnti = rnti; + + return SRSLTE_SUCCESS; + +} + +uint32_t phch_worker::get_nof_rnti() { + return ue_db.size(); +} + +void phch_worker::set_config_dedicated(uint16_t rnti, + srslte_uci_cfg_t *uci_cfg, + srslte_pucch_sched_t *pucch_sched, + srslte_refsignal_srs_cfg_t *srs_cfg, + uint32_t I_sr, bool pucch_cqi, uint32_t pmi_idx, bool pucch_cqi_ack) +{ + pthread_mutex_lock(&mutex); + if (ue_db.count(rnti)) { + pucch_sched->N_pucch_1 = phy->pucch_cfg.n1_pucch_an; + srslte_enb_ul_cfg_ue(&enb_ul, rnti, uci_cfg, pucch_sched, srs_cfg); + + ue_db[rnti].I_sr = I_sr; + ue_db[rnti].I_sr_en = true; + + if (pucch_cqi) { + ue_db[rnti].pmi_idx = pmi_idx; + ue_db[rnti].cqi_en = true; + ue_db[rnti].pucch_cqi_ack = pucch_cqi_ack; + } else { + ue_db[rnti].pmi_idx = 0; + ue_db[rnti].cqi_en = false; + } + + } else { + Error("Setting config dedicated: rnti=0x%x does not exist\n"); + } + pthread_mutex_unlock(&mutex); +} + +void phch_worker::rem_rnti(uint16_t rnti) +{ + pthread_mutex_lock(&mutex); + if (ue_db.count(rnti)) { + ue_db.erase(rnti); + + srslte_enb_dl_rem_rnti(&enb_dl, rnti); + srslte_enb_ul_rem_rnti(&enb_ul, rnti); + + // remove any pending grant for each subframe + for (uint32_t i=0;i<10;i++) { + for (uint32_t j=0;jul_grants[i].nof_grants;j++) { + if (phy->ul_grants[i].sched_grants[j].rnti == rnti) { + phy->ul_grants[i].sched_grants[j].rnti = 0; + } + } + for (uint32_t j=0;jdl_grants[i].nof_grants;j++) { + if (phy->dl_grants[i].sched_grants[j].rnti == rnti) { + phy->dl_grants[i].sched_grants[j].rnti = 0; + } + } + } + } else { + Error("Removing user: rnti=0x%x does not exist\n", rnti); + } + pthread_mutex_unlock(&mutex); +} + +void phch_worker::work_imp() +{ + uint32_t sf_ack; + + pthread_mutex_lock(&mutex); + + mac_interface_phy::ul_sched_t *ul_grants = phy->ul_grants; + mac_interface_phy::dl_sched_t *dl_grants = phy->dl_grants; + mac_interface_phy *mac = phy->mac; + + log_h->step(tti_rx); + + Debug("Worker %d running\n", get_id()); + + for(std::map::iterator iter=ue_db.begin(); iter!=ue_db.end(); ++iter) { + uint16_t rnti = (uint16_t) iter->first; + ue_db[rnti].has_grant_tti = -1; + } + + // Process UL signal + srslte_enb_ul_fft(&enb_ul, signal_buffer_rx); + + // Decode pending UL grants for the tti they were scheduled + decode_pusch(ul_grants[sf_rx].sched_grants, ul_grants[sf_rx].nof_grants, sf_rx); + + // Decode remaining PUCCH ACKs not associated with PUSCH transmission and SR signals + decode_pucch(tti_rx); + + // Get DL scheduling for the TX TTI from MAC + if (mac->get_dl_sched(tti_tx, &dl_grants[sf_tx]) < 0) { + Error("Getting DL scheduling from MAC\n"); + goto unlock; + } + + if (dl_grants[sf_tx].cfi < 1 || dl_grants[sf_tx].cfi > 3) { + Error("Invalid CFI=%d\n", dl_grants[sf_tx].cfi); + goto unlock; + } + + // Get UL scheduling for the TX TTI from MAC + if (mac->get_ul_sched(tti_sched_ul, &ul_grants[sf_sched_ul]) < 0) { + Error("Getting UL scheduling from MAC\n"); + goto unlock; + } + + // Put base signals (references, PBCH, PCFICH and PSS/SSS) into the resource grid + srslte_enb_dl_clear_sf(&enb_dl); + srslte_enb_dl_set_cfi(&enb_dl, dl_grants[sf_tx].cfi); + srslte_enb_dl_put_base(&enb_dl, tti_tx); + + // Put UL/DL grants to resource grid. PDSCH data will be encoded as well. + encode_pdcch_dl(dl_grants[sf_tx].sched_grants, dl_grants[sf_tx].nof_grants, sf_tx); + encode_pdcch_ul(ul_grants[sf_sched_ul].sched_grants, ul_grants[sf_sched_ul].nof_grants, sf_tx); + encode_pdsch(dl_grants[sf_tx].sched_grants, dl_grants[sf_tx].nof_grants, sf_tx); + + // Put pending PHICH HARQ ACK/NACK indications into subframe + encode_phich(ul_grants[sf_sched_ul].phich, ul_grants[sf_sched_ul].nof_phich, sf_tx); + + // Prepare for receive ACK for DL grants in sf_tx+4 + sf_ack = (sf_tx+4)%10; + phy->ack_clear(sf_ack); + for (uint32_t i=0;i= SRSLTE_CRNTI_START && dl_grants[sf_tx].sched_grants[i].rnti <= SRSLTE_CRNTI_END) { + phy->ack_set_pending(sf_ack, dl_grants[sf_tx].sched_grants[i].rnti, dl_grants[sf_tx].sched_grants[i].location.ncce); + } + } + + // Generate signal and transmit + srslte_enb_dl_gen_signal(&enb_dl, signal_buffer_tx); + Debug("Sending to radio\n"); + phy->worker_end(tx_mutex_cnt, signal_buffer_tx, SRSLTE_SF_LEN_PRB(phy->cell.nof_prb), tx_time); + +#ifdef DEBUG_WRITE_FILE + fwrite(signal_buffer_tx, SRSLTE_SF_LEN_PRB(phy->cell.nof_prb)*sizeof(cf_t), 1, f); +#endif + +#ifdef DEBUG_WRITE_FILE + if (tti_tx == 10) { + fclose(f); + exit(-1); + } +#endif + + /* Tell the plotting thread to draw the plots */ +#ifdef ENABLE_GUI + if ((int) get_id() == plot_worker_id) { + sem_post(&plot_sem); + } +#endif + +unlock: + pthread_mutex_unlock(&mutex); + +} + + +int phch_worker::decode_pusch(srslte_enb_ul_pusch_t *grants, uint32_t nof_pusch, uint32_t tti) +{ + srslte_uci_data_t uci_data; + bzero(&uci_data, sizeof(srslte_uci_data_t)); + + uint32_t wideband_cqi_value = 0; + + uint32_t n_rb_ho = 0; + for (uint32_t i=0;iack_is_pending(sf_rx, rnti)) { + uci_data.uci_ack_len = 1; + } + // Configure PUSCH CQI channel + srslte_cqi_value_t cqi_value; + bool cqi_enabled = false; + if (ue_db[rnti].cqi_en && srslte_cqi_send(ue_db[rnti].pmi_idx, tti_rx)) { + cqi_value.type = SRSLTE_CQI_TYPE_WIDEBAND; + cqi_enabled = true; + } else if (grants[i].grant.cqi_request) { + cqi_value.type = SRSLTE_CQI_TYPE_SUBBAND_HL; + cqi_value.subband_hl.N = (phy->cell.nof_prb > 7) ? srslte_cqi_hl_get_no_subbands(phy->cell.nof_prb) : 0; + cqi_enabled = true; + } + if (cqi_enabled) { + uci_data.uci_cqi_len = srslte_cqi_size(&cqi_value); + Info("cqi enabled len=%d\n", uci_data.uci_cqi_len); + } + + // mark this tti as having an ul grant to avoid pucch + ue_db[rnti].has_grant_tti = tti_rx; + + srslte_ra_ul_grant_t phy_grant; + int res = -1; + if (!srslte_ra_ul_dci_to_grant(&grants[i].grant, enb_ul.cell.nof_prb, n_rb_ho, &phy_grant, tti%8)) { + res = srslte_enb_ul_get_pusch(&enb_ul, &phy_grant, grants[i].softbuffer, + rnti, grants[i].rv_idx, + grants[i].current_tx_nb, + grants[i].data, + &uci_data, + tti); + } else { + Error("Computing PUSCH grant\n"); + return SRSLTE_ERROR; + } + + #ifdef LOG_EXECTIME + gettimeofday(&t[2], NULL); + get_time_interval(t); + snprintf(timestr, 64, ", dec_time=%4d us", (int) t[0].tv_usec); + #endif + + bool crc_res = (res == 0); + + // Save PHICH scheduling for this user. Each user can have just 1 PUSCH grant per TTI + ue_db[rnti].phich_info.n_prb_lowest = enb_ul.pusch_cfg.grant.n_prb_tilde[0]; + ue_db[rnti].phich_info.n_dmrs = phy_grant.ncs_dmrs; + + + + char cqi_str[64]; + if (cqi_enabled) { + srslte_cqi_value_unpack(uci_data.uci_cqi, &cqi_value); + if (ue_db[rnti].cqi_en) { + wideband_cqi_value = cqi_value.wideband.wideband_cqi; + } else if (grants[i].grant.cqi_request) { + wideband_cqi_value = cqi_value.subband_hl.wideband_cqi; + } + snprintf(cqi_str, 64, ", cqi=%d", wideband_cqi_value); + } + + float snr_db = 10*log10(srslte_chest_ul_get_snr(&enb_ul.chest)); + + /* + if (!crc_res && enb_ul.pusch_cfg.grant.L_prb == 1 && enb_ul.pusch_cfg.grant.n_prb[0] == 0 && snr_db > 5) { + srslte_vec_save_file("sf_symbols", enb_ul.sf_symbols, sizeof(cf_t)*SRSLTE_SF_LEN_RE(25, SRSLTE_CP_NORM)); + srslte_vec_save_file("ce", enb_ul.ce, sizeof(cf_t)*SRSLTE_SF_LEN_RE(25, SRSLTE_CP_NORM)); + srslte_vec_save_file("d", enb_ul.pusch.d, sizeof(cf_t)*enb_ul.pusch_cfg.nbits.nof_re); + srslte_vec_save_file("ce2", enb_ul.pusch.ce, sizeof(cf_t)*enb_ul.pusch_cfg.nbits.nof_re); + srslte_vec_save_file("z", enb_ul.pusch.z, sizeof(cf_t)*enb_ul.pusch_cfg.nbits.nof_re); + printf("saved sf_idx=%d, mcs=%d, tbs=%d, rnti=%d, rv=%d, snr=%.1f\n", tti%10, + grants[i].grant.mcs_idx, enb_ul.pusch_cfg.cb_segm.tbs, rnti, grants[i].rv_idx, snr_db); + exit(-1); + } + */ + log_h->info_hex(grants[i].data, phy_grant.mcs.tbs/8, + "PUSCH: rnti=0x%x, prb=(%d,%d), tbs=%d, mcs=%d, rv=%d, snr=%.1f dB, n_iter=%d, crc=%s%s%s%s\n", + rnti, phy_grant.n_prb[0], phy_grant.n_prb[0]+phy_grant.L_prb, + phy_grant.mcs.tbs/8, phy_grant.mcs.idx, grants[i].grant.rv_idx, + snr_db, + srslte_pusch_last_noi(&enb_ul.pusch), + crc_res?"OK":"KO", + uci_data.uci_ack_len>0?(uci_data.uci_ack?", ack=1":", ack=0"):"", + uci_data.uci_cqi_len>0?cqi_str:"", + timestr); + + // Notify MAC of RL status + if (grants[i].grant.rv_idx == 0) { + if (res && snr_db < PUSCH_RL_SNR_DB_TH) { + Debug("PUSCH: Radio-Link failure snr=%.1f dB\n", snr_db); + phy->mac->rl_failure(rnti); + } else { + phy->mac->rl_ok(rnti); + } + } + + // Notify MAC new received data and HARQ Indication value + phy->mac->crc_info(tti_rx, rnti, phy_grant.mcs.tbs/8, crc_res); + if (uci_data.uci_ack_len) { + phy->mac->ack_info(tti_rx, rnti, uci_data.uci_ack && (crc_res || snr_db > PUSCH_RL_SNR_DB_TH)); + } + + // Notify MAC of UL SNR and DL CQI + if (snr_db >= PUSCH_RL_SNR_DB_TH) { + phy->mac->snr_info(tti_rx, rnti, snr_db); + } + if (uci_data.uci_cqi_len>0 && crc_res) { + phy->mac->cqi_info(tti_rx, rnti, wideband_cqi_value); + } + + // Save metrics stats + ue_db[rnti].metrics_ul(phy_grant.mcs.idx, 0, snr_db, srslte_pusch_last_noi(&enb_ul.pusch)); + } + } + return SRSLTE_SUCCESS; +} + + +int phch_worker::decode_pucch(uint32_t tti_rx) +{ + uint32_t sf_rx = tti_rx%10; + srslte_uci_data_t uci_data; + + for(std::map::iterator iter=ue_db.begin(); iter!=ue_db.end(); ++iter) { + uint16_t rnti = (uint16_t) iter->first; + + if (rnti >= SRSLTE_CRNTI_START && rnti <= SRSLTE_CRNTI_END && ue_db[rnti].has_grant_tti != (int) tti_rx) { + // Check if user needs to receive PUCCH + bool needs_pucch = false, needs_ack=false, needs_sr=false, needs_cqi=false; + uint32_t last_n_pdcch = 0; + bzero(&uci_data, sizeof(srslte_uci_data_t)); + + if (ue_db[rnti].I_sr_en) { + if (srslte_ue_ul_sr_send_tti(ue_db[rnti].I_sr, tti_rx)) { + needs_pucch = true; + needs_sr = true; + uci_data.scheduling_request = true; + } + } + if (phy->ack_is_pending(sf_rx, rnti, &last_n_pdcch)) { + needs_pucch = true; + needs_ack = true; + uci_data.uci_ack_len = 1; + } + srslte_cqi_value_t cqi_value; + if (ue_db[rnti].cqi_en && (ue_db[rnti].pucch_cqi_ack || !needs_ack)) { + if (srslte_cqi_send(ue_db[rnti].pmi_idx, tti_rx)) { + needs_pucch = true; + needs_cqi = true; + cqi_value.type = SRSLTE_CQI_TYPE_WIDEBAND; + uci_data.uci_cqi_len = srslte_cqi_size(&cqi_value); + } + } + + if (needs_pucch) { + if (srslte_enb_ul_get_pucch(&enb_ul, rnti, last_n_pdcch, sf_rx, &uci_data)) { + fprintf(stderr, "Error getting PUCCH\n"); + return SRSLTE_ERROR; + } + if (uci_data.uci_ack_len > 0) { + phy->mac->ack_info(tti_rx, rnti, uci_data.uci_ack && (srslte_pucch_get_last_corr(&enb_ul.pucch) >= PUCCH_RL_CORR_TH)); + } + if (uci_data.scheduling_request) { + phy->mac->sr_detected(tti_rx, rnti); + } + + char cqi_str[64]; + if (uci_data.uci_cqi_len) { + srslte_cqi_value_unpack(uci_data.uci_cqi, &cqi_value); + phy->mac->cqi_info(tti_rx, rnti, cqi_value.wideband.wideband_cqi); + sprintf(cqi_str, ", cqi=%d", cqi_value.wideband.wideband_cqi); + } + log_h->info("PUCCH: rnti=0x%x, corr=%.2f, n_pucch=%d, n_prb=%d%s%s%s\n", + rnti, + srslte_pucch_get_last_corr(&enb_ul.pucch), + enb_ul.pucch.last_n_pucch, enb_ul.pucch.last_n_prb, + needs_ack?(uci_data.uci_ack?", ack=1":", ack=0"):"", + needs_sr?(uci_data.scheduling_request?", sr=yes":", sr=no"):"", + needs_cqi?cqi_str:""); + + + // Notify MAC of RL status + if (!needs_sr) { + if (srslte_pucch_get_last_corr(&enb_ul.pucch) < PUCCH_RL_CORR_TH) { + Debug("PUCCH: Radio-Link failure corr=%.1f\n", srslte_pucch_get_last_corr(&enb_ul.pucch)); + phy->mac->rl_failure(rnti); + } else { + phy->mac->rl_ok(rnti); + } + } + } + } + } + return 0; +} + + +int phch_worker::encode_phich(srslte_enb_dl_phich_t *acks, uint32_t nof_acks, uint32_t sf_idx) +{ + for (uint32_t i=0;iinfo_hex(ptr, len, + "PDSCH: rnti=0x%x, l_crb=%2d, %s, harq=%d, tbs=%d, mcs=%d, rv=%d, tti_tx=%d\n", + rnti, phy_grant.nof_prb, grant_str, grants[i].grant.harq_process, + phy_grant.mcs.tbs/8, phy_grant.mcs.idx, grants[i].grant.rv_idx, tti_tx); + } + if (srslte_enb_dl_put_pdsch(&enb_dl, &phy_grant, grants[i].softbuffer, rnti, grants[i].grant.rv_idx, sf_idx, + grants[i].data)) + { + fprintf(stderr, "Error putting PDSCH %d\n",i); + return SRSLTE_ERROR; + } + + // Save metrics stats + ue_db[rnti].metrics_dl(phy_grant.mcs.idx); + } + } + return SRSLTE_SUCCESS; +} + + + +/************ METRICS interface ********************/ +uint32_t phch_worker::get_metrics(phy_metrics_t metrics[ENB_METRICS_MAX_USERS]) +{ + uint32_t cnt=0; + for(std::map::iterator iter=ue_db.begin(); iter!=ue_db.end(); ++iter) { + ue *u = (ue*) &iter->second; + uint16_t rnti = iter->first; + if (rnti >= SRSLTE_CRNTI_START && rnti <= SRSLTE_CRNTI_END) { + u->metrics_read(&metrics[cnt]); + cnt++; + } + } + return cnt; +} + +void phch_worker::ue::metrics_read(phy_metrics_t* metrics_) +{ + memcpy(metrics_, &metrics, sizeof(phy_metrics_t)); + bzero(&metrics, sizeof(phy_metrics_t)); +} + +void phch_worker::ue::metrics_dl(uint32_t mcs) +{ + metrics.dl.mcs = SRSLTE_VEC_CMA(mcs, metrics.dl.mcs, metrics.dl.n_samples); + metrics.dl.n_samples++; +} + +void phch_worker::ue::metrics_ul(uint32_t mcs, float rssi, float sinr, uint32_t turbo_iters) +{ + metrics.ul.mcs = SRSLTE_VEC_CMA((float) mcs, metrics.ul.mcs, metrics.ul.n_samples); + metrics.ul.sinr = SRSLTE_VEC_CMA((float) sinr, metrics.ul.sinr, metrics.ul.n_samples); + metrics.ul.rssi = SRSLTE_VEC_CMA((float) sinr, metrics.ul.rssi, metrics.ul.n_samples); + metrics.ul.turbo_iters = SRSLTE_VEC_CMA((float) turbo_iters, metrics.ul.turbo_iters, metrics.ul.n_samples); + metrics.ul.n_samples++; +} + + + + + + + + + + + + + + + +void phch_worker::start_plot() { +#ifdef ENABLE_GUI + if (plot_worker_id == -1) { + plot_worker_id = get_id(); + log_h->console("Starting plot for worker_id=%d\n", plot_worker_id); + init_plots(this); + } else { + log_h->console("Trying to start a plot but already started by worker_id=%d\n", plot_worker_id); + } +#else + log_h->console("Trying to start a plot but plots are disabled (ENABLE_GUI constant in phch_worker.cc)\n"); +#endif +} + + +int phch_worker::read_ce_abs(float *ce_abs) { + uint32_t i=0; + int sz = srslte_symbol_sz(phy->cell.nof_prb); + bzero(ce_abs, sizeof(float)*sz); + int g = (sz - 12*phy->cell.nof_prb)/2; + for (i = 0; i < 12*phy->cell.nof_prb; i++) { + ce_abs[g+i] = 20 * log10(cabs(enb_ul.ce[i])); + if (isinf(ce_abs[g+i])) { + ce_abs[g+i] = -80; + } + } + return sz; +} + +int phch_worker::read_pusch_d(cf_t* pdsch_d) +{ + int nof_re = 400;//enb_ul.pusch_cfg.nbits.nof_re + memcpy(pdsch_d, enb_ul.pusch.d, nof_re*sizeof(cf_t)); + return nof_re; +} + + +} + + +/*********************************************************** + * + * PLOT TO VISUALIZE THE CHANNEL RESPONSEE + * + ***********************************************************/ + + +#ifdef ENABLE_GUI +plot_real_t pce; +plot_scatter_t pconst; +#define SCATTER_PUSCH_BUFFER_LEN (20*6*SRSLTE_SF_LEN_RE(SRSLTE_MAX_PRB, SRSLTE_CP_NORM)) +#define SCATTER_PUSCH_PLOT_LEN 4000 +float tmp_plot[SCATTER_PUSCH_BUFFER_LEN]; +cf_t tmp_plot2[SRSLTE_SF_LEN_RE(SRSLTE_MAX_PRB, SRSLTE_CP_NORM)]; + +void *plot_thread_run(void *arg) { + srsenb::phch_worker *worker = (srsenb::phch_worker*) arg; + + sdrgui_init_title("srsENB"); + plot_real_init(&pce); + plot_real_setTitle(&pce, (char*) "Channel Response - Magnitude"); + plot_real_setLabels(&pce, (char*) "Index", (char*) "dB"); + plot_real_setYAxisScale(&pce, -40, 40); + + plot_scatter_init(&pconst); + plot_scatter_setTitle(&pconst, (char*) "PUSCH - Equalized Symbols"); + plot_scatter_setXAxisScale(&pconst, -4, 4); + plot_scatter_setYAxisScale(&pconst, -4, 4); + + plot_real_addToWindowGrid(&pce, (char*)"srsenb", 0, 0); + plot_scatter_addToWindowGrid(&pconst, (char*)"srsenb", 0, 1); + + int n; + int readed_pusch_re=0; + while(1) { + sem_wait(&plot_sem); + + n = worker->read_pusch_d(tmp_plot2); + plot_scatter_setNewData(&pconst, tmp_plot2, n); + n = worker->read_ce_abs(tmp_plot); + plot_real_setNewData(&pce, tmp_plot, n); + + } + return NULL; +} + + +void init_plots(srsenb::phch_worker *worker) { + + if (sem_init(&plot_sem, 0, 0)) { + perror("sem_init"); + exit(-1); + } + + pthread_attr_t attr; + struct sched_param param; + param.sched_priority = 0; + pthread_attr_init(&attr); + pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED); + pthread_attr_setschedpolicy(&attr, SCHED_OTHER); + pthread_attr_setschedparam(&attr, ¶m); + if (pthread_create(&plot_thread, &attr, plot_thread_run, worker)) { + perror("pthread_create"); + exit(-1); + } +} +#endif + + + + diff --git a/srsenb/src/phy/phy.cc b/srsenb/src/phy/phy.cc new file mode 100644 index 000000000..bc4f3173e --- /dev/null +++ b/srsenb/src/phy/phy.cc @@ -0,0 +1,238 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2017 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of srsLTE. + * + * srsUE 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. + * + * srsUE 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 +#include +#include +#include +#include +#include +#include + +#include "srslte/common/threads.h" +#include "srslte/common/log.h" +#include "phy/phy.h" + +#define Error(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->error_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Warning(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->warning_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Info(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->info_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Debug(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->debug_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) + +using namespace std; + + +namespace srsenb { + +phy::phy() : workers_pool(MAX_WORKERS), + workers(MAX_WORKERS), + workers_common(txrx::MUTEX_X_WORKER*MAX_WORKERS) +{ +} + +void phy::parse_config(phy_cfg_t* cfg) +{ + + // PRACH configuration + prach_cfg.config_idx = cfg->prach_cnfg.prach_cnfg_info.prach_config_index; + prach_cfg.hs_flag = cfg->prach_cnfg.prach_cnfg_info.high_speed_flag; + prach_cfg.root_seq_idx = cfg->prach_cnfg.root_sequence_index; + prach_cfg.zero_corr_zone = cfg->prach_cnfg.prach_cnfg_info.zero_correlation_zone_config; + prach_cfg.freq_offset = cfg->prach_cnfg.prach_cnfg_info.prach_freq_offset; + + // PUSCH DMRS configuration + workers_common.pusch_cfg.cyclic_shift = cfg->pusch_cnfg.ul_rs.cyclic_shift; + workers_common.pusch_cfg.delta_ss = cfg->pusch_cnfg.ul_rs.group_assignment_pusch; + workers_common.pusch_cfg.group_hopping_en = cfg->pusch_cnfg.ul_rs.group_hopping_enabled; + workers_common.pusch_cfg.sequence_hopping_en = cfg->pusch_cnfg.ul_rs.sequence_hopping_enabled; + + // PUSCH hopping configuration + workers_common.hopping_cfg.hop_mode = cfg->pusch_cnfg.hopping_mode == LIBLTE_RRC_HOPPING_MODE_INTRA_AND_INTER_SUBFRAME ? + srslte_pusch_hopping_cfg_t::SRSLTE_PUSCH_HOP_MODE_INTRA_SF : + srslte_pusch_hopping_cfg_t::SRSLTE_PUSCH_HOP_MODE_INTER_SF; ; + workers_common.hopping_cfg.n_sb = cfg->pusch_cnfg.n_sb; + workers_common.hopping_cfg.hopping_offset = cfg->pusch_cnfg.pusch_hopping_offset; + + // PUCCH configuration + workers_common.pucch_cfg.delta_pucch_shift = liblte_rrc_delta_pucch_shift_num[cfg->pucch_cnfg.delta_pucch_shift%LIBLTE_RRC_DELTA_PUCCH_SHIFT_N_ITEMS]; + workers_common.pucch_cfg.N_cs = cfg->pucch_cnfg.n_cs_an; + workers_common.pucch_cfg.n_rb_2 = cfg->pucch_cnfg.n_rb_cqi; + workers_common.pucch_cfg.srs_configured = false; + workers_common.pucch_cfg.n1_pucch_an = cfg->pucch_cnfg.n1_pucch_an;; +} + +bool phy::init(phy_args_t *args, + phy_cfg_t *cfg, + srslte::radio* radio_handler_, + mac_interface_phy *mac, + srslte::log* log_h) +{ + std::vector log_vec; + for (int i=0;inof_phy_threads;i++) { + log_vec[i] = (void*) log_h; + } + init(args, cfg, radio_handler_, mac, log_vec); + return true; +} + +bool phy::init(phy_args_t *args, + phy_cfg_t *cfg, + srslte::radio* radio_handler_, + mac_interface_phy *mac, + std::vector log_vec) +{ + + mlockall(MCL_CURRENT | MCL_FUTURE); + + radio_handler = radio_handler_; + nof_workers = args->nof_phy_threads; + + workers_common.params = *args; + + workers_common.init(&cfg->cell, radio_handler, mac); + + parse_config(cfg); + + // Add workers to workers pool and start threads + for (uint32_t i=0;icell, &prach_cfg, mac, (srslte::log*) log_vec[0], PRACH_WORKER_THREAD_PRIO); + prach.set_max_prach_offset_us(args->max_prach_offset_us); + + // Warning this must be initialized after all workers have been added to the pool + tx_rx.init(radio_handler, &workers_pool, &workers_common, &prach, (srslte::log*) log_vec[0], SF_RECV_THREAD_PRIO); + + return true; +} + +void phy::stop() +{ + tx_rx.stop(); + workers_common.stop(); + workers_pool.stop(); + prach.stop(); +} + +uint32_t phy::tti_to_SFN(uint32_t tti) { + return tti/10; +} + +uint32_t phy::tti_to_subf(uint32_t tti) { + return tti%10; +} + +/***** MAC->PHY interface **********/ +int phy::add_rnti(uint16_t rnti) +{ + if (rnti >= SRSLTE_CRNTI_START && rnti <= SRSLTE_CRNTI_END) { + workers_common.ack_add_rnti(rnti); + } + for (uint32_t i=0;i= SRSLTE_CRNTI_START && rnti <= SRSLTE_CRNTI_END) { + workers_common.ack_rem_rnti(rnti); + } + for (uint32_t i=0;iPHY interface **********/ + +void phy::set_config_dedicated(uint16_t rnti, LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT* dedicated) +{ + // Parse RRC config + srslte_uci_cfg_t uci_cfg; + srslte_pucch_sched_t pucch_sched; + + /* PUSCH UCI configuration */ + bzero(&uci_cfg, sizeof(srslte_uci_cfg_t)); + uci_cfg.I_offset_ack = dedicated->pusch_cnfg_ded.beta_offset_ack_idx; + uci_cfg.I_offset_cqi = dedicated->pusch_cnfg_ded.beta_offset_cqi_idx; + uci_cfg.I_offset_ri = dedicated->pusch_cnfg_ded.beta_offset_ri_idx; + + /* PUCCH Scheduling configuration */ + bzero(&pucch_sched, sizeof(srslte_pucch_sched_t)); + pucch_sched.n_pucch_2 = dedicated->cqi_report_cnfg.report_periodic.pucch_resource_idx; + pucch_sched.n_pucch_sr = dedicated->sched_request_cnfg.sr_pucch_resource_idx; + + for (uint32_t i=0;isched_request_cnfg.sr_cnfg_idx, + dedicated->cqi_report_cnfg.report_periodic_setup_present, + dedicated->cqi_report_cnfg.report_periodic.pmi_cnfg_idx, + dedicated->cqi_report_cnfg.report_periodic.simult_ack_nack_and_cqi); + } +} + +// Start GUI +void phy::start_plot() { + ((phch_worker) workers[0]).start_plot(); +} + +} diff --git a/srsenb/src/phy/prach_worker.cc b/srsenb/src/phy/prach_worker.cc new file mode 100644 index 000000000..218f7cc21 --- /dev/null +++ b/srsenb/src/phy/prach_worker.cc @@ -0,0 +1,159 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2017 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of srsLTE. + * + * srsUE 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. + * + * srsUE 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 "phy/prach_worker.h" + +namespace srsenb { + +int prach_worker::init(srslte_cell_t *cell_, srslte_prach_cfg_t *prach_cfg_, mac_interface_phy* mac_, srslte::log* log_h_, int priority) +{ + log_h = log_h_; + mac = mac_; + memcpy(&prach_cfg, prach_cfg_, sizeof(srslte_prach_cfg_t)); + memcpy(&cell, cell_, sizeof(srslte_cell_t)); + + max_prach_offset_us = 50; + + pthread_mutex_init(&mutex, NULL); + pthread_cond_init(&cvar, NULL); + + if (srslte_prach_init_cfg(&prach, &prach_cfg, cell.nof_prb)) { + fprintf(stderr, "Error initiating PRACH\n"); + return -1; + } + + srslte_prach_set_detect_factor(&prach, 60); + + nof_sf = (uint32_t) ceilf(prach.T_tot*1000); + + signal_buffer_rx = (cf_t*) srslte_vec_malloc(sizeof(cf_t)*nof_sf*SRSLTE_SF_LEN_PRB(cell.nof_prb)); + if (!signal_buffer_rx) { + perror("malloc"); + return -1; + } + + start(priority); + initiated = true; + + pending_tti = 0; + processed_tti = 0; + return 0; +} + +void prach_worker::stop() +{ + pthread_mutex_lock(&mutex); + processed_tti = 99999; + running = false; + pthread_cond_signal(&cvar); + pthread_mutex_unlock(&mutex); + + wait_thread_finish(); +} + +void prach_worker::set_max_prach_offset_us(float delay_us) +{ + max_prach_offset_us = delay_us; +} + +int prach_worker::new_tti(uint32_t tti_rx, cf_t* buffer_rx) +{ + // Save buffer only if it's a PRACH TTI + if (srslte_prach_tti_opportunity(&prach, tti_rx, -1) || sf_cnt) { + memcpy(&signal_buffer_rx[sf_cnt*SRSLTE_SF_LEN_PRB(cell.nof_prb)], buffer_rx, sizeof(cf_t)*SRSLTE_SF_LEN_PRB(cell.nof_prb)); + sf_cnt++; + if (sf_cnt == nof_sf) { + sf_cnt = 0; + if ((int) pending_tti != processed_tti) { + log_h->warning("PRACH thread did not finish processing TTI=%d\n", pending_tti); + } + pthread_mutex_lock(&mutex); + if (tti_rx+1 > nof_sf) { + pending_tti = tti_rx+1-nof_sf; + } else { + pending_tti = 10240+(tti_rx+1-nof_sf); + } + pthread_cond_signal(&cvar); + pthread_mutex_unlock(&mutex); + } + } + return 0; +} + + +int prach_worker::run_tti(uint32_t tti_rx) +{ + if (srslte_prach_tti_opportunity(&prach, tti_rx, -1)) + { + // Detect possible PRACHs + if (srslte_prach_detect_offset(&prach, + prach_cfg.freq_offset, + &signal_buffer_rx[prach.N_cp], + nof_sf*SRSLTE_SF_LEN_PRB(cell.nof_prb)-prach.N_cp, + prach_indices, + prach_offsets, + prach_p2avg, + &prach_nof_det)) + { + log_h->error("Error detecting PRACH\n"); + return SRSLTE_ERROR; + } + + if (prach_nof_det) { + for (uint32_t i=0;iinfo("PRACH: %d/%d, preamble=%d, offset=%.1f us, peak2avg=%.1f, max_offset=%.1f us\n", + i, prach_nof_det, prach_indices[i], prach_offsets[i]*1e6, prach_p2avg[i], max_prach_offset_us); + + if (prach_offsets[i]*1e6 < max_prach_offset_us) { + mac->rach_detected(tti_rx, prach_indices[i], (uint32_t) (prach_offsets[i]*1e6)); + } + } + } + } + return 0; +} + +void prach_worker::run_thread() +{ + running = true; + while(running) { + pthread_mutex_lock(&mutex); + while(processed_tti == (int) pending_tti) { + pthread_cond_wait(&cvar, &mutex); + } + pthread_mutex_unlock(&mutex); + log_h->debug("Processing pending_tti=%d\n", pending_tti); + if (running) { + if (run_tti(pending_tti)) { + running = false; + } + processed_tti = pending_tti; + } + } +} + + +} diff --git a/srsenb/src/phy/txrx.cc b/srsenb/src/phy/txrx.cc new file mode 100644 index 000000000..9427e3459 --- /dev/null +++ b/srsenb/src/phy/txrx.cc @@ -0,0 +1,143 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2017 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of srsLTE. + * + * srsUE 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. + * + * srsUE 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 + +#include "srslte/common/threads.h" +#include "srslte/common/log.h" + +#include "phy/txrx.h" +#include "phy/phch_worker.h" + +#define Error(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->error_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Warning(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->warning_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Info(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->info_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Debug(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->debug_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) + +using namespace std; + + +namespace srsenb { + +txrx::txrx() +{ + running = false; + radio_h = NULL; + log_h = NULL; + workers_pool = NULL; + worker_com = NULL; +} + +bool txrx::init(srslte::radio* radio_h_, srslte::thread_pool* workers_pool_, phch_common* worker_com_, prach_worker *prach_, srslte::log* log_h_, uint32_t prio_) +{ + radio_h = radio_h_; + log_h = log_h_; + workers_pool = workers_pool_; + worker_com = worker_com_; + prach = prach_; + tx_mutex_cnt = 0; + running = true; + + nof_tx_mutex = MUTEX_X_WORKER*workers_pool->get_nof_workers(); + worker_com->set_nof_mutex(nof_tx_mutex); + + start(prio_); + return true; +} + +void txrx::stop() +{ + running = false; + wait_thread_finish(); +} + +void txrx::run_thread() +{ + phch_worker *worker = NULL; + cf_t *buffer = NULL; + srslte_timestamp_t rx_time, tx_time; + uint32_t sf_len = SRSLTE_SF_LEN_PRB(worker_com->cell.nof_prb); + + float samp_rate = srslte_sampling_freq_hz(worker_com->cell.nof_prb); + if (30720%((int) samp_rate/1000) == 0) { + radio_h->set_master_clock_rate(30.72e6); + } else { + radio_h->set_master_clock_rate(23.04e6); + } + + log_h->console("Setting Sampling frequency %.2f MHz\n", (float) samp_rate/1000000); + + // Configure radio + radio_h->set_rx_srate(samp_rate); + radio_h->set_tx_srate(samp_rate); + + log_h->info("Starting RX/TX thread nof_prb=%d, sf_len=%d\n",worker_com->cell.nof_prb, sf_len); + + // Start streaming RX samples + radio_h->start_rx(); + + // Set TTI so that first TX is at tti=0 + tti = 10235; + + printf("\n==== eNodeB started ===\n"); + printf("Type to view trace\n"); + // Main loop + while (running) { + tti = (tti+1)%10240; + worker = (phch_worker*) workers_pool->wait_worker(tti); + if (worker) { + buffer = worker->get_buffer_rx(); + + radio_h->rx_now(buffer, sf_len, &rx_time); + + /* Compute TX time: Any transmission happens in TTI+4 thus advance 4 ms the reception time */ + srslte_timestamp_copy(&tx_time, &rx_time); + srslte_timestamp_add(&tx_time, 0, 4e-3); + + Debug("Settting TTI=%d, tx_mutex=%d, tx_time=%d:%f to worker %d\n", + tti, tx_mutex_cnt, + tx_time.full_secs, tx_time.frac_secs, + worker->get_id()); + + worker->set_time(tti, tx_mutex_cnt, tx_time); + tx_mutex_cnt = (tx_mutex_cnt+1)%nof_tx_mutex; + + // Trigger phy worker execution + workers_pool->start_worker(worker); + + // Trigger prach worker execution + prach->new_tti(tti, buffer); + + } else { + // wait_worker() only returns NULL if it's being closed. Quit now to avoid unnecessary loops here + running = false; + } + } +} + + + +} diff --git a/srsenb/src/upper/CMakeLists.txt b/srsenb/src/upper/CMakeLists.txt new file mode 100644 index 000000000..aed9b0283 --- /dev/null +++ b/srsenb/src/upper/CMakeLists.txt @@ -0,0 +1,3 @@ +file(GLOB SOURCES "*.cc") +add_library(srsenb_upper SHARED ${SOURCES}) +target_link_libraries(srsenb_upper) diff --git a/srsenb/src/upper/gtpu.cc b/srsenb/src/upper/gtpu.cc new file mode 100644 index 000000000..83f7a1b75 --- /dev/null +++ b/srsenb/src/upper/gtpu.cc @@ -0,0 +1,266 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2017 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of srsLTE. + * + * srsUE 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. + * + * srsUE 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 "upper/gtpu.h" +#include + +using namespace srslte; + +namespace srsenb { + +bool gtpu::init(std::string gtp_bind_addr_, std::string mme_addr_, srsenb::pdcp_interface_gtpu* pdcp_, srslte::log* gtpu_log_) +{ + pdcp = pdcp_; + gtpu_log = gtpu_log_; + gtp_bind_addr = gtp_bind_addr_; + mme_addr = mme_addr_; + + pthread_mutex_init(&mutex, NULL); + + pool = byte_buffer_pool::get_instance(); + + if(0 != srslte_netsource_init(&src, gtp_bind_addr.c_str(), GTPU_PORT, SRSLTE_NETSOURCE_UDP)) { + gtpu_log->error("Failed to create source socket on %s:%d", gtp_bind_addr.c_str(), GTPU_PORT); + return false; + } + if(0 != srslte_netsink_init(&snk, mme_addr.c_str(), GTPU_PORT, SRSLTE_NETSINK_UDP)) { + gtpu_log->error("Failed to create sink socket on %s:%d", mme_addr.c_str(), GTPU_PORT); + return false; + } + + srslte_netsink_set_nonblocking(&snk); + + // Setup a thread to receive packets from the src socket + start(THREAD_PRIO); + return true; + +} + +void gtpu::stop() +{ + if(run_enable) { + run_enable = false; + // Wait thread to exit gracefully otherwise might leave a mutex locked + int cnt=0; + while(running && cnt<100) { + usleep(10000); + cnt++; + } + if (running) { + thread_cancel(); + } + wait_thread_finish(); + } + + srslte_netsink_free(&snk); + srslte_netsource_free(&src); +} + +// gtpu_interface_pdcp +void gtpu::write_pdu(uint16_t rnti, uint32_t lcid, srslte::byte_buffer_t* pdu) +{ + gtpu_log->info_hex(pdu->msg, pdu->N_bytes, "TX PDU, RNTI: 0x%x, LCID: %d", rnti, lcid); + gtpu_header_t header; + header.flags = 0x30; + header.message_type = 0xFF; + header.length = pdu->N_bytes; + header.teid = rnti_bearers[rnti].teids_out[lcid]; + + gtpu_write_header(&header, pdu); + srslte_netsink_write(&snk, pdu->msg, pdu->N_bytes); + pool->deallocate(pdu); +} + +// gtpu_interface_rrc +void gtpu::add_bearer(uint16_t rnti, uint32_t lcid, uint32_t teid_out, uint32_t *teid_in) +{ + // Allocate a TEID for the incoming tunnel + rntilcid_to_teidin(rnti, lcid, teid_in); + gtpu_log->info("Adding bearer for rnti: 0x%x, lcid: %d, teid_out: 0x%x, teid_in: 0x%x\n", rnti, lcid, teid_out, *teid_in); + + // Initialize maps if it's a new RNTI + if(rnti_bearers.count(rnti) == 0) { + for(int i=0;iinfo("Removing bearer for rnti: 0x%x, lcid: %d\n", rnti, lcid); + + rnti_bearers[rnti].teids_in[lcid] = 0; + rnti_bearers[rnti].teids_out[lcid] = 0; + + // Remove RNTI if all bearers are removed + bool rem = true; + for(int i=0;ireset(); + gtpu_log->debug("Waiting for read...\n"); + pdu->N_bytes = srslte_netsource_read(&src, pdu->msg, SRSENB_MAX_BUFFER_SIZE_BYTES - SRSENB_BUFFER_HEADER_OFFSET); + + + gtpu_header_t header; + gtpu_read_header(pdu, &header); + + uint16_t rnti = 0; + uint16_t lcid = 0; + teidin_to_rntilcid(header.teid, &rnti, &lcid); + + pthread_mutex_lock(&mutex); + bool user_exists = (rnti_bearers.count(rnti) > 0); + pthread_mutex_unlock(&mutex); + + if(!user_exists) { + gtpu_log->error("Unrecognized RNTI for DL PDU: 0x%x - dropping packet\n", rnti); + continue; + } + + if(lcid < SRSENB_N_SRB || lcid >= SRSENB_N_RADIO_BEARERS) { + gtpu_log->error("Invalid LCID for DL PDU: %d - dropping packet\n", lcid); + continue; + } + + gtpu_log->info_hex(pdu->msg, pdu->N_bytes, "RX GTPU PDU rnti=0x%x, lcid=%d", rnti, lcid); + + pdcp->write_sdu(rnti, lcid, pdu); + do { + pdu = pool_allocate; + if (!pdu) { + gtpu_log->console("GTPU Buffer pool empty. Trying again...\n"); + usleep(10000); + } + } while(!pdu); + } + running=false; +} + +/**************************************************************************** + * Header pack/unpack helper functions + * Ref: 3GPP TS 29.281 v10.1.0 Section 5 + ***************************************************************************/ + +bool gtpu::gtpu_write_header(gtpu_header_t *header, srslte::byte_buffer_t *pdu) +{ + if(header->flags != 0x30) { + gtpu_log->error("gtpu_write_header - Unhandled header flags: 0x%x\n", header->flags); + return false; + } + if(header->message_type != 0xFF) { + gtpu_log->error("gtpu_write_header - Unhandled message type: 0x%x\n", header->message_type); + return false; + } + if(pdu->get_headroom() < GTPU_HEADER_LEN) { + gtpu_log->error("gtpu_write_header - No room in PDU for header\n"); + return false; + } + + pdu->msg -= GTPU_HEADER_LEN; + pdu->N_bytes += GTPU_HEADER_LEN; + + uint8_t *ptr = pdu->msg; + + *ptr = header->flags; + ptr++; + *ptr = header->message_type; + ptr++; + uint16_to_uint8(header->length, ptr); + ptr += 2; + uint32_to_uint8(header->teid, ptr); + + return true; +} + +bool gtpu::gtpu_read_header(srslte::byte_buffer_t *pdu, gtpu_header_t *header) +{ + uint8_t *ptr = pdu->msg; + + pdu->msg += GTPU_HEADER_LEN; + pdu->N_bytes -= GTPU_HEADER_LEN; + + header->flags = *ptr; + ptr++; + header->message_type = *ptr; + ptr++; + uint8_to_uint16(ptr, &header->length); + ptr += 2; + uint8_to_uint32(ptr, &header->teid); + + if(header->flags != 0x30) { + gtpu_log->error("gtpu_read_header - Unhandled header flags: 0x%x\n", header->flags); + return false; + } + if(header->message_type != 0xFF) { + gtpu_log->error("gtpu_read_header - Unhandled message type: 0x%x\n", header->message_type); + return false; + } + + return true; +} + +/**************************************************************************** + * TEID to RNIT/LCID helper functions + ***************************************************************************/ +void gtpu::teidin_to_rntilcid(uint32_t teidin, uint16_t *rnti, uint16_t *lcid) +{ + *lcid = teidin & 0xFFFF; + *rnti = (teidin >> 16) & 0xFFFF; +} + +void gtpu::rntilcid_to_teidin(uint16_t rnti, uint16_t lcid, uint32_t *teidin) +{ + *teidin = (rnti << 16) | lcid; +} + +} // namespace srsenb diff --git a/srsenb/src/upper/pdcp.cc b/srsenb/src/upper/pdcp.cc new file mode 100644 index 000000000..772184fbd --- /dev/null +++ b/srsenb/src/upper/pdcp.cc @@ -0,0 +1,148 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2017 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of srsLTE. + * + * srsUE 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. + * + * srsUE 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 "upper/pdcp.h" + +namespace srsenb { + +void pdcp::init(rlc_interface_pdcp* rlc_, rrc_interface_pdcp* rrc_, gtpu_interface_pdcp* gtpu_, srslte::log* pdcp_log_) +{ + rlc = rlc_; + rrc = rrc_; + gtpu = gtpu_; + log_h = pdcp_log_; + + pool = srslte::byte_buffer_pool::get_instance(); +} + +void pdcp::stop() +{ + for(std::map::iterator iter=users.begin(); iter!=users.end(); ++iter) { + rem_user((uint32_t) iter->first); + } + users.clear(); +} + +void pdcp::add_user(uint16_t rnti) +{ + if (users.count(rnti) == 0) { + srslte::pdcp *obj = new srslte::pdcp; + obj->init(&users[rnti].rlc_itf, &users[rnti].rrc_itf, &users[rnti].gtpu_itf, log_h, SECURITY_DIRECTION_DOWNLINK); + users[rnti].rlc_itf.rnti = rnti; + users[rnti].gtpu_itf.rnti = rnti; + users[rnti].rrc_itf.rnti = rnti; + + users[rnti].rrc_itf.rrc = rrc; + users[rnti].rlc_itf.rlc = rlc; + users[rnti].gtpu_itf.gtpu = gtpu; + users[rnti].pdcp = obj; + } +} + +void pdcp::rem_user(uint16_t rnti) +{ + if (users.count(rnti)) { + users[rnti].pdcp->stop(); + delete users[rnti].pdcp; + users[rnti].pdcp = NULL; + users.erase(rnti); + } +} + +void pdcp::add_bearer(uint16_t rnti, uint32_t lcid, LIBLTE_RRC_PDCP_CONFIG_STRUCT* cnfg) +{ + if (users.count(rnti)) { + users[rnti].pdcp->add_bearer(lcid, cnfg); + } +} + + +void pdcp::reset(uint16_t rnti) +{ + if (users.count(rnti)) { + users[rnti].pdcp->reset(); + } +} + +void pdcp::config_security(uint16_t rnti, uint32_t lcid, uint8_t* k_rrc_enc_, uint8_t* k_rrc_int_, + srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo_, + srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo_) +{ + if (users.count(rnti)) { + users[rnti].pdcp->config_security(lcid, k_rrc_enc_, k_rrc_int_, cipher_algo_, integ_algo_); + } +} + +void pdcp::write_pdu(uint16_t rnti, uint32_t lcid, srslte::byte_buffer_t* sdu) +{ + if (users.count(rnti)) { + users[rnti].pdcp->write_pdu(lcid, sdu); + } else { + pool->deallocate(sdu); + } +} + +void pdcp::write_sdu(uint16_t rnti, uint32_t lcid, srslte::byte_buffer_t* sdu) +{ + if (users.count(rnti)) { + users[rnti].pdcp->write_sdu(lcid, sdu); + } else { + pool->deallocate(sdu); + } +} + +void pdcp::user_interface_gtpu::write_pdu(uint32_t lcid, srslte::byte_buffer_t *pdu) +{ + gtpu->write_pdu(rnti, lcid, pdu); +} + +void pdcp::user_interface_rlc::write_sdu(uint32_t lcid, srslte::byte_buffer_t* sdu) +{ + rlc->write_sdu(rnti, lcid, sdu); +} + +void pdcp::user_interface_rrc::write_pdu(uint32_t lcid, srslte::byte_buffer_t* pdu) +{ + rrc->write_pdu(rnti, lcid, pdu); +} + +void pdcp::user_interface_rrc::write_pdu_bcch_bch(srslte::byte_buffer_t* pdu) +{ + fprintf(stderr, "Error: Received BCCH from ue=%d\n", rnti); +} + +void pdcp::user_interface_rrc::write_pdu_bcch_dlsch(srslte::byte_buffer_t* pdu) +{ + fprintf(stderr, "Error: Received BCCH from ue=%d\n", rnti); +} + +void pdcp::user_interface_rrc::write_pdu_pcch(srslte::byte_buffer_t* pdu) +{ + fprintf(stderr, "Error: Received PCCH from ue=%d\n", rnti); +} + + +} diff --git a/srsenb/src/upper/rlc.cc b/srsenb/src/upper/rlc.cc new file mode 100644 index 000000000..1af7a76de --- /dev/null +++ b/srsenb/src/upper/rlc.cc @@ -0,0 +1,187 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2017 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of srsLTE. + * + * srsUE 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. + * + * srsUE 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 "upper/rlc.h" + +namespace srsenb { + +void rlc::init(pdcp_interface_rlc* pdcp_, rrc_interface_rlc* rrc_, mac_interface_rlc *mac_, + srslte::mac_interface_timers *mac_timers_, srslte::log* log_h_) +{ + pdcp = pdcp_; + rrc = rrc_, + log_h = log_h_; + mac = mac_; + mac_timers = mac_timers_; + + pool = srslte::byte_buffer_pool::get_instance(); + +} + +void rlc::stop() +{ + for(std::map::iterator iter=users.begin(); iter!=users.end(); ++iter) { + rem_user((uint32_t) iter->first); + } + users.clear(); +} + +void rlc::add_user(uint16_t rnti) +{ + if (users.count(rnti) == 0) { + srslte::rlc *obj = new srslte::rlc; + obj->init(&users[rnti], &users[rnti], &users[rnti], log_h, mac_timers); + users[rnti].rnti = rnti; + users[rnti].pdcp = pdcp; + users[rnti].rrc = rrc; + users[rnti].rlc = obj; + users[rnti].parent = this; + } +} + +void rlc::rem_user(uint16_t rnti) +{ + if (users.count(rnti)) { + users[rnti].rlc->stop(); + delete users[rnti].rlc; + users[rnti].rlc = NULL; + users.erase(rnti); + } +} + +void rlc::reset(uint16_t rnti) +{ + if (users.count(rnti)) { + users[rnti].rlc->reset(); + } +} + +void rlc::clear_buffer(uint16_t rnti) +{ + if (users.count(rnti)) { + log_h->info("Clearing buffer rnti=0x%x\n", rnti); + users[rnti].rlc->reset(); + for (int i=0;irlc_buffer_state(rnti, i, 0, 0); + } + } +} + +void rlc::add_bearer(uint16_t rnti, uint32_t lcid) +{ + if (users.count(rnti)) { + users[rnti].rlc->add_bearer(lcid); + } +} + +void rlc::add_bearer(uint16_t rnti, uint32_t lcid, LIBLTE_RRC_RLC_CONFIG_STRUCT* cnfg) +{ + if (users.count(rnti)) { + users[rnti].rlc->add_bearer(lcid, cnfg); + } +} + +void rlc::read_pdu_pcch(uint8_t* payload, uint32_t buffer_size) +{ + rrc->read_pdu_pcch(payload, buffer_size); +} + +int rlc::read_pdu(uint16_t rnti, uint32_t lcid, uint8_t* payload, uint32_t nof_bytes) +{ + int ret = users[rnti].rlc->read_pdu(lcid, payload, nof_bytes); + + // In the eNodeB, there is no polling for buffer state from the scheduler, thus + // communicate buffer state every time a PDU is read + uint32_t tx_queue = users[rnti].rlc->get_total_buffer_state(lcid); + uint32_t retx_queue = 0; + log_h->debug("Buffer state PDCP: rnti=0x%x, lcid=%d, tx_queue=%d\n", rnti, lcid, tx_queue); + mac->rlc_buffer_state(rnti, lcid, tx_queue, retx_queue); + + return ret; +} + +void rlc::write_pdu(uint16_t rnti, uint32_t lcid, uint8_t* payload, uint32_t nof_bytes) +{ + if (users.count(rnti)) { + users[rnti].rlc->write_pdu(lcid, payload, nof_bytes); + + // In the eNodeB, there is no polling for buffer state from the scheduler, thus + // communicate buffer state every time a new PDU is written + uint32_t tx_queue = users[rnti].rlc->get_total_buffer_state(lcid); + uint32_t retx_queue = 0; + log_h->debug("Buffer state PDCP: rnti=0x%x, lcid=%d, tx_queue=%d\n", rnti, lcid, tx_queue); + mac->rlc_buffer_state(rnti, lcid, tx_queue, retx_queue); + } +} + +void rlc::read_pdu_bcch_dlsch(uint32_t sib_index, uint8_t *payload) +{ + // RLC is transparent for BCCH + rrc->read_pdu_bcch_dlsch(sib_index, payload); +} + +void rlc::write_sdu(uint16_t rnti, uint32_t lcid, srslte::byte_buffer_t* sdu) +{ + if (users.count(rnti)) { + users[rnti].rlc->write_sdu(lcid, sdu); + + // In the eNodeB, there is no polling for buffer state from the scheduler, thus + // communicate buffer state every time a new SDU is written + uint32_t tx_queue = users[rnti].rlc->get_total_buffer_state(lcid); + uint32_t retx_queue = 0; + log_h->info("Buffer state: rnti=0x%x, lcid=%d, tx_queue=%d\n", rnti, lcid, tx_queue); + mac->rlc_buffer_state(rnti, lcid, tx_queue, retx_queue); + } else { + pool->deallocate(sdu); + } +} + +void rlc::user_interface::max_retx_attempted() +{ + rrc->max_retx_attempted(rnti); +} + +void rlc::user_interface::write_pdu(uint32_t lcid, srslte::byte_buffer_t* sdu) +{ + pdcp->write_pdu(rnti, lcid, sdu); +} + +void rlc::user_interface::write_pdu_bcch_bch(srslte::byte_buffer_t* sdu) +{ + fprintf(stderr, "Error: Received BCCH from ue=%d\n", rnti); +} + +void rlc::user_interface::write_pdu_bcch_dlsch(srslte::byte_buffer_t* sdu) +{ + fprintf(stderr, "Error: Received BCCH from ue=%d\n", rnti); +} + +void rlc::user_interface::write_pdu_pcch(srslte::byte_buffer_t* sdu) +{ + fprintf(stderr, "Error: Received PCCH from ue=%d\n", rnti); +} + +} diff --git a/srsenb/src/upper/rrc.cc b/srsenb/src/upper/rrc.cc new file mode 100644 index 000000000..aa6ca4127 --- /dev/null +++ b/srsenb/src/upper/rrc.cc @@ -0,0 +1,1637 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2017 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of srsLTE. + * + * srsUE 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. + * + * srsUE 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/asn1/liblte_mme.h" +#include "upper/rrc.h" + +using srslte::rb_id_text; +using srslte::byte_buffer_t; +using srslte::bit_buffer_t; +using srslte::rb_id_t; + +namespace srsenb { + +void rrc::init(rrc_cfg_t *cfg_, + phy_interface_rrc* phy_, + mac_interface_rrc* mac_, + rlc_interface_rrc* rlc_, + pdcp_interface_rrc* pdcp_, + s1ap_interface_rrc *s1ap_, + gtpu_interface_rrc* gtpu_, + srslte::log* log_rrc) +{ + phy = phy_; + mac = mac_; + rlc = rlc_; + pdcp = pdcp_; + gtpu = gtpu_; + s1ap = s1ap_; + rrc_log = log_rrc; + cnotifier = NULL; + + running = false; + pool = srslte::byte_buffer_pool::get_instance(); + + memcpy(&cfg, cfg_, sizeof(rrc_cfg_t)); + nof_si_messages = generate_sibs(); + config_mac(); + + pthread_mutex_init(&user_mutex, NULL); + pthread_mutex_init(&paging_mutex, NULL); + + bzero(&sr_sched, sizeof(sr_sched_t)); + + start(RRC_THREAD_PRIO); +} + +rrc::activity_monitor::activity_monitor(rrc* parent_) +{ + running = true; + parent = parent_; + start(RRC_THREAD_PRIO); +} + +void rrc::activity_monitor::stop() +{ + if (running) { + running = false; + thread_cancel(); + wait_thread_finish(); + } +} + +void rrc::set_connect_notifer(connect_notifier *cnotifier) +{ + this->cnotifier = cnotifier; +} + +void rrc::stop() +{ + if(running) { + running = false; + thread_cancel(); + wait_thread_finish(); + } + act_monitor.stop(); + users.clear(); + pthread_mutex_destroy(&user_mutex); + pthread_mutex_destroy(&paging_mutex); +} + +void rrc::get_metrics(rrc_metrics_t &m) +{ + pthread_mutex_lock(&user_mutex); + m.n_ues = 0; + for(std::map::iterator iter=users.begin(); m.n_ues < ENB_METRICS_MAX_USERS &&iter!=users.end(); ++iter) { + ue *u = (ue*) &iter->second; + m.ues[m.n_ues++].state = u->get_state(); + } + pthread_mutex_unlock(&user_mutex); +} + +uint32_t rrc::generate_sibs() +{ + uint32_t nof_messages = 1+cfg.sibs[0].sib.sib1.N_sched_info; + LIBLTE_RRC_SCHEDULING_INFO_STRUCT *sched_info = cfg.sibs[0].sib.sib1.sched_info; + + // Allocate DSLCH msg structs + LIBLTE_RRC_BCCH_DLSCH_MSG_STRUCT *msg = (LIBLTE_RRC_BCCH_DLSCH_MSG_STRUCT*)calloc(nof_messages, sizeof(LIBLTE_RRC_BCCH_DLSCH_MSG_STRUCT)); + + // Copy SIB1 + msg[0].N_sibs = 1; + memcpy(&msg[0].sibs[0], &cfg.sibs[0], sizeof(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_STRUCT)); + + // Copy rest of SIBs + for (uint32_t i=1;icell_cfg(&sched_cfg); +} + + +void rrc::read_pdu_bcch_dlsch(uint32_t sib_index, uint8_t* payload) +{ + if (sib_index < LIBLTE_RRC_MAX_SIB) { + memcpy(payload, sib_buffer[sib_index].msg, sib_buffer[sib_index].N_bytes); + } +} + +void rrc::rl_failure(uint16_t rnti) +{ + rrc_log->info("Radio-Link failure detected rnti=0x%x\n", rnti); + if (s1ap->user_exists(rnti)) { + if (!s1ap->user_link_lost(rnti)) { + rrc_log->info("Removing rnti=0x%x\n", rnti); + rem_user_thread(rnti); + } + } else { + rrc_log->warning("User rnti=0x%x context not existing in S1AP. Removing user\n", rnti); + rem_user_thread(rnti); + } +} + +void rrc::add_user(uint16_t rnti) +{ + pthread_mutex_lock(&user_mutex); + if (users.count(rnti) == 0) { + users[rnti].parent = this; + users[rnti].rnti = rnti; + rlc->add_user(rnti); + pdcp->add_user(rnti); + rrc_log->info("Added new user rnti=0x%x\n", rnti); + } else { + rrc_log->error("Adding user rnti=0x%x (already exists)\n"); + } + pthread_mutex_unlock(&user_mutex); +} + +void rrc::rem_user(uint16_t rnti) +{ + pthread_mutex_lock(&user_mutex); + if (users.count(rnti) == 1) { + rrc_log->console("Disconnecting rnti=0x%x.\n", rnti); + rrc_log->info("Disconnecting rnti=0x%x.\n", rnti); + /* **Caution** order of removal here is imporant: from bottom to top */ + mac->ue_rem(rnti); // MAC handles PHY + rlc->rem_user(rnti); + pdcp->rem_user(rnti); + gtpu->rem_user(rnti); + users[rnti].sr_free(); + users[rnti].cqi_free(); + users.erase(rnti); + rrc_log->info("Removed user rnti=0x%x\n", rnti); + } else { + rrc_log->error("Removing user rnti=0x%x (does not exist)\n", rnti); + } + pthread_mutex_unlock(&user_mutex); +} + +// Function called by MAC after the reception of a C-RNTI CE indicating that the UE still has a +// valid RNTI +void rrc::upd_user(uint16_t new_rnti, uint16_t old_rnti) +{ + // Remove new_rnti + rem_user_thread(new_rnti); + + // Send Reconfiguration to old_rnti if is RRC_CONNECT or RRC Release if already released here + if (users.count(old_rnti) == 1) { + if (users[old_rnti].is_connected()) { + users[old_rnti].send_connection_reconf_upd(pool_allocate); + } else { + users[old_rnti].send_connection_release(); + } + } +} + +void rrc::set_activity_user(uint16_t rnti) +{ + if (users.count(rnti) == 1) { + users[rnti].set_activity(); + } +} + +void rrc::rem_user_thread(uint16_t rnti) +{ + if (users.count(rnti) == 1) { + rrc_pdu p = {rnti, LCID_REM_USER, NULL}; + rx_pdu_queue.push(p); + } +} + +uint32_t rrc::get_nof_users() { + return users.size(); +} + +void rrc::max_retx_attempted(uint16_t rnti) +{ + +} + +/******************************************************************************* + PDCP interface +*******************************************************************************/ +void rrc::write_pdu(uint16_t rnti, uint32_t lcid, byte_buffer_t* pdu) +{ + rrc_pdu p = {rnti, lcid, pdu}; + rx_pdu_queue.push(p); +} + +/******************************************************************************* + S1AP interface +*******************************************************************************/ +void rrc::write_dl_info(uint16_t rnti, byte_buffer_t* sdu) +{ + LIBLTE_RRC_DL_DCCH_MSG_STRUCT dl_dcch_msg; + bzero(&dl_dcch_msg, sizeof(LIBLTE_RRC_DL_DCCH_MSG_STRUCT)); + + if (users.count(rnti) == 1) { + dl_dcch_msg.msg_type = LIBLTE_RRC_DL_DCCH_MSG_TYPE_DL_INFO_TRANSFER; + memcpy(dl_dcch_msg.msg.dl_info_transfer.dedicated_info.msg, sdu->msg, sdu->N_bytes); + dl_dcch_msg.msg.dl_info_transfer.dedicated_info.N_bytes = sdu->N_bytes; + + sdu->reset(); + + users[rnti].send_dl_dcch(&dl_dcch_msg, sdu); + + } else { + rrc_log->error("Rx SDU for unknown rnti=0x%x\n", rnti); + } +} + +void rrc::release_complete(uint16_t rnti) +{ + rrc_log->info("Received Release Complete rnti=0x%x\n", rnti); + if (users.count(rnti) == 1) { + if (!users[rnti].is_idle()) { + rlc->clear_buffer(rnti); + users[rnti].send_connection_release(); + // There is no RRCReleaseComplete message from UE thus sleep to enable all retx in PHY +50% + usleep(1.5*8*1e3*cfg.mac_cnfg.ulsch_cnfg.max_harq_tx); + } + rem_user(rnti); + } else { + + rrc_log->error("Received ReleaseComplete for unknown rnti=0x%x\n", rnti); + } +} + +bool rrc::setup_ue_ctxt(uint16_t rnti, LIBLTE_S1AP_MESSAGE_INITIALCONTEXTSETUPREQUEST_STRUCT *msg) +{ + rrc_log->info("Adding initial context for 0x%x\n", rnti); + + if(users.count(rnti) == 0) { + rrc_log->warning("Unrecognised rnti: 0x%x\n", rnti); + return false; + } + + if(msg->CSFallbackIndicator_present) { + rrc_log->warning("Not handling CSFallbackIndicator\n"); + } + if(msg->AdditionalCSFallbackIndicator_present) { + rrc_log->warning("Not handling AdditionalCSFallbackIndicator\n"); + } + if(msg->CSGMembershipStatus_present) { + rrc_log->warning("Not handling CSGMembershipStatus\n"); + } + if(msg->GUMMEI_ID_present) { + rrc_log->warning("Not handling GUMMEI_ID\n"); + } + if(msg->HandoverRestrictionList_present) { + rrc_log->warning("Not handling HandoverRestrictionList\n"); + } + if(msg->ManagementBasedMDTAllowed_present) { + rrc_log->warning("Not handling ManagementBasedMDTAllowed\n"); + } + if(msg->ManagementBasedMDTPLMNList_present) { + rrc_log->warning("Not handling ManagementBasedMDTPLMNList\n"); + } + if(msg->MME_UE_S1AP_ID_2_present) { + rrc_log->warning("Not handling MME_UE_S1AP_ID_2\n"); + } + if(msg->RegisteredLAI_present) { + rrc_log->warning("Not handling RegisteredLAI\n"); + } + if(msg->SRVCCOperationPossible_present) { + rrc_log->warning("Not handling SRVCCOperationPossible\n"); + } + if(msg->SubscriberProfileIDforRFP_present) { + rrc_log->warning("Not handling SubscriberProfileIDforRFP\n"); + } + if(msg->TraceActivation_present) { + rrc_log->warning("Not handling TraceActivation\n"); + } + if(msg->UERadioCapability_present) { + rrc_log->warning("Not handling UERadioCapability\n"); + } + + // UEAggregateMaximumBitrate + users[rnti].set_bitrates(&msg->uEaggregateMaximumBitrate); + + // UESecurityCapabilities + users[rnti].set_security_capabilities(&msg->UESecurityCapabilities); + + // SecurityKey + uint8_t key[32]; + liblte_pack(msg->SecurityKey.buffer, LIBLTE_S1AP_SECURITYKEY_BIT_STRING_LEN, key); + users[rnti].set_security_key(key, LIBLTE_S1AP_SECURITYKEY_BIT_STRING_LEN/8); + + // Send RRC security mode command + users[rnti].send_security_mode_command(); + + // Setup E-RABs + users[rnti].setup_erabs(&msg->E_RABToBeSetupListCtxtSUReq); + + return true; +} + +bool rrc::setup_ue_erabs(uint16_t rnti, LIBLTE_S1AP_MESSAGE_E_RABSETUPREQUEST_STRUCT *msg) +{ + rrc_log->info("Setting up erab(s) for 0x%x\n", rnti); + + if(users.count(rnti) == 0) { + rrc_log->warning("Unrecognised rnti: 0x%x\n", rnti); + return false; + } + + if(msg->uEaggregateMaximumBitrate_present) { + // UEAggregateMaximumBitrate + users[rnti].set_bitrates(&msg->uEaggregateMaximumBitrate); + } + + // Setup E-RABs + users[rnti].setup_erabs(&msg->E_RABToBeSetupListBearerSUReq); + + return true; +} + +bool rrc::release_erabs(uint32_t rnti) +{ + rrc_log->info("Releasing E-RABs for 0x%x\n", rnti); + + if(users.count(rnti) == 0) { + rrc_log->warning("Unrecognised rnti: 0x%x\n", rnti); + return false; + } + + return users[rnti].release_erabs(); +} + +void rrc::add_paging_id(uint32_t ueid, LIBLTE_S1AP_UEPAGINGID_STRUCT UEPagingID) +{ + pthread_mutex_lock(&paging_mutex); + if (pending_paging.count(ueid) == 0) { + pending_paging[ueid] = UEPagingID; + } else { + rrc_log->warning("Received Paging for UEID=%d but not yet transmitted\n", ueid); + } + pthread_mutex_unlock(&paging_mutex); +} + +// Described in Section 7 of 36.304 +bool rrc::is_paging_opportunity(uint32_t tti, uint32_t *payload_len) +{ + int sf_pattern[4][3] = {{9, 4, 0}, {-1, 9, 4}, {-1, -1, 5}, {-1, -1, 9}}; + + if (pending_paging.empty()) { + return false; + } + + pthread_mutex_lock(&paging_mutex); + + LIBLTE_RRC_PCCH_MSG_STRUCT pcch_msg; + bzero(&pcch_msg, sizeof(LIBLTE_RRC_PCCH_MSG_STRUCT)); + + // Default paging cycle, should get DRX from user + uint32_t T = liblte_rrc_default_paging_cycle_num[cfg.sibs[1].sib.sib2.rr_config_common_sib.pcch_cnfg.default_paging_cycle]; + uint32_t Nb = T*liblte_rrc_nb_num[cfg.sibs[1].sib.sib2.rr_config_common_sib.pcch_cnfg.nB]; + + uint32_t N = T1?Nb/T:1; + uint32_t sfn = tti/10; + + std::vector ue_to_remove; + + int n=0; + for(std::map::iterator iter=pending_paging.begin(); n < LIBLTE_RRC_MAX_PAGE_REC && iter!=pending_paging.end(); ++iter) { + LIBLTE_S1AP_UEPAGINGID_STRUCT u = (LIBLTE_S1AP_UEPAGINGID_STRUCT) iter->second; + uint32_t ueid = ((uint32_t) iter->first)%1024; + uint32_t i_s = (ueid/N) % Ns; + + if ((sfn % T) == (T/N) * (ueid % N)) { + + int sf_idx = sf_pattern[i_s%4][(Ns-1)%3]; + if (sf_idx < 0) { + rrc_log->error("SF pattern is N/A for Ns=%d, i_s=%d, imsi_decimal=%d\n", Ns, i_s, ueid); + } else if ((uint32_t) sf_idx == (tti%10)) { + + if (u.choice_type == LIBLTE_S1AP_UEPAGINGID_CHOICE_IMSI) { + pcch_msg.paging_record_list[n].ue_identity.ue_identity_type = LIBLTE_RRC_PAGING_UE_IDENTITY_TYPE_IMSI; + memcpy(pcch_msg.paging_record_list[n].ue_identity.imsi, u.choice.iMSI.buffer, u.choice.iMSI.n_octets); + pcch_msg.paging_record_list[n].ue_identity.imsi_size = u.choice.iMSI.n_octets; + printf("Warning IMSI paging not tested\n"); + } else { + pcch_msg.paging_record_list[n].ue_identity.ue_identity_type = LIBLTE_RRC_PAGING_UE_IDENTITY_TYPE_S_TMSI; + pcch_msg.paging_record_list[n].ue_identity.s_tmsi.mmec = u.choice.s_TMSI.mMEC.buffer[0]; + uint32_t m_tmsi = 0; + for (int i=0;iinfo("Assembled paging for ue_id=%d, tti=%d\n", ueid, tti); + } + } + } + + for (uint32_t i=0;i 0) { + pcch_msg.paging_record_list_size = n; + liblte_rrc_pack_pcch_msg(&pcch_msg, (LIBLTE_BIT_MSG_STRUCT*)&bit_buf_paging); + uint32_t N_bytes = (bit_buf_paging.N_bits-1)/8+1; + + if (payload_len) { + *payload_len = N_bytes; + } + rrc_log->info("Assembling PCCH payload with %d UE identities, payload_len=%d bytes, nbits=%d\n", + pcch_msg.paging_record_list_size, N_bytes, bit_buf_paging.N_bits); + return true; + } + + return false; +} + + +void rrc::read_pdu_pcch(uint8_t *payload, uint32_t buffer_size) +{ + uint32_t N_bytes = (bit_buf_paging.N_bits-1)/8+1; + if (N_bytes <= buffer_size) { + srslte_bit_pack_vector(bit_buf_paging.msg, payload, bit_buf_paging.N_bits); + } +} + +/******************************************************************************* + Parsers +*******************************************************************************/ + +void rrc::parse_ul_ccch(uint16_t rnti, byte_buffer_t *pdu) +{ + uint16_t old_rnti = 0; + + LIBLTE_RRC_UL_CCCH_MSG_STRUCT ul_ccch_msg; + bzero(&ul_ccch_msg, sizeof(LIBLTE_RRC_UL_CCCH_MSG_STRUCT)); + + srslte_bit_unpack_vector(pdu->msg, bit_buf.msg, pdu->N_bytes*8); + bit_buf.N_bits = pdu->N_bytes*8; + liblte_rrc_unpack_ul_ccch_msg((LIBLTE_BIT_MSG_STRUCT*)&bit_buf, &ul_ccch_msg); + + rrc_log->info_hex(pdu->msg, pdu->N_bytes, + "SRB0 - Rx: %s", + liblte_rrc_ul_ccch_msg_type_text[ul_ccch_msg.msg_type]); + + switch(ul_ccch_msg.msg_type) { + case LIBLTE_RRC_UL_CCCH_MSG_TYPE_RRC_CON_REQ: + if (users.count(rnti)) { + users[rnti].handle_rrc_con_req(&ul_ccch_msg.msg.rrc_con_req); + } else { + rrc_log->error("Received ConnectionSetup for rnti=0x%x without context\n", rnti); + } + break; + case LIBLTE_RRC_UL_CCCH_MSG_TYPE_RRC_CON_REEST_REQ: + rrc_log->debug("rnti=0x%x, phyid=0x%x, smac=0x%x, cause=%s\n", + ul_ccch_msg.msg.rrc_con_reest_req.ue_id.c_rnti, ul_ccch_msg.msg.rrc_con_reest_req.ue_id.phys_cell_id, + ul_ccch_msg.msg.rrc_con_reest_req.ue_id.short_mac_i, liblte_rrc_con_reest_req_cause_text[ul_ccch_msg.msg.rrc_con_reest_req.cause] + ); + if (users[rnti].is_idle()) { + old_rnti = ul_ccch_msg.msg.rrc_con_reest_req.ue_id.c_rnti; + if (users.count(old_rnti)) { + rrc_log->error("Not supported: ConnectionReestablishment. Sending Connection Reject\n", old_rnti); + users[rnti].send_connection_reest_rej(); + rem_user_thread(old_rnti); + } else { + rrc_log->error("Received ConnectionReestablishment for rnti=0x%x without context\n", old_rnti); + users[rnti].send_connection_reest_rej(); + } + // remove temporal rnti + rem_user_thread(rnti); + } else { + rrc_log->error("Received ReestablishmentRequest from an rnti=0x%x not in IDLE\n", rnti); + } + break; + default: + rrc_log->error("UL CCCH message not recognised\n"); + break; + } + + pool->deallocate(pdu); +} + +void rrc::parse_ul_dcch(uint16_t rnti, uint32_t lcid, byte_buffer_t *pdu) +{ + if (users.count(rnti)) { + users[rnti].parse_ul_dcch(lcid, pdu); + } else { + rrc_log->error("Processing %s: Unkown rnti=0x%x\n", rb_id_text[lcid], rnti); + } +} + +/******************************************************************************* + RRC thread +*******************************************************************************/ + +void rrc::run_thread() +{ + rrc_pdu p; + running = true; + + while(running) { + p = rx_pdu_queue.wait_pop(); + if (p.pdu) { + rrc_log->info_hex(p.pdu->msg, p.pdu->N_bytes, "Rx %s PDU", rb_id_text[p.lcid]); + } + switch(p.lcid) + { + case srslte::RB_ID_SRB0: + parse_ul_ccch(p.rnti, p.pdu); + break; + case srslte::RB_ID_SRB1: + case srslte::RB_ID_SRB2: + parse_ul_dcch(p.rnti, p.lcid, p.pdu); + break; + case LCID_REM_USER: + usleep(10000); + rem_user(p.rnti); + break; + default: + rrc_log->error("Rx PDU with invalid bearer id: %s", p.lcid); + break; + } + } +} +void rrc::activity_monitor::run_thread() +{ + while(running) + { + usleep(10000); + pthread_mutex_lock(&parent->user_mutex); + uint16_t rem_rnti = 0; + for(std::map::iterator iter=parent->users.begin(); rem_rnti == 0 && iter!=parent->users.end(); ++iter) { + ue *u = (ue*) &iter->second; + uint16_t rnti = (uint16_t) iter->first; + + if (parent->cnotifier && u->is_connected() && !u->connect_notified) { + parent->cnotifier->user_connected(rnti); + u->connect_notified = true; + } + + if (u->is_timeout()) { + parent->rrc_log->info("User rnti=0x%x timed out. Exists in s1ap=%s\n", rnti, parent->s1ap->user_exists(rnti)?"yes":"no"); + rem_rnti = rnti; + } + } + pthread_mutex_unlock(&parent->user_mutex); + if (rem_rnti) { + if (parent->s1ap->user_exists(rem_rnti)) { + parent->s1ap->user_inactivity(rem_rnti); + } else { + parent->rem_user(rem_rnti); + } + } + } +} + +/******************************************************************************* + RRC::UE Helpers +*******************************************************************************/ + +void rrc::configure_security(uint16_t rnti, + uint32_t lcid, + uint8_t *k_rrc_enc, + uint8_t *k_rrc_int, + uint8_t *k_up_enc, + uint8_t *k_up_int, + srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo, + srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo) +{ + // TODO: add k_up_enc, k_up_int support to PDCP + pdcp->config_security(rnti, lcid, k_rrc_enc, k_rrc_int, cipher_algo, integ_algo); +} + + + + +/******************************************************************************* + UE class +*******************************************************************************/ +rrc::ue::ue() +{ + parent = NULL; + set_activity(); + sr_allocated = false; + has_tmsi = false; + connect_notified = false; + transaction_id = 0; + state = RRC_STATE_IDLE; +} + +rrc_state_t rrc::ue::get_state() +{ + return state; +} + +void rrc::ue::set_activity() +{ + gettimeofday(&t_last_activity, NULL); + if (parent) { + if (parent->rrc_log) { + parent->rrc_log->debug("Activity registered rnti=0x%x\n", rnti); + } + } +} + +bool rrc::ue::is_connected() { + return state == RRC_STATE_REGISTERED; +} + +bool rrc::ue::is_idle() { + return state == RRC_STATE_IDLE; +} + +bool rrc::ue::is_timeout() +{ + + if (!parent) { + return false; + } + + struct timeval t[3]; + uint32_t deadline_s = 0; + uint32_t deadline_us = 0; + const char *deadline_str = NULL; + memcpy(&t[1], &t_last_activity, sizeof(struct timeval)); + gettimeofday(&t[2], NULL); + get_time_interval(t); + + switch(state) { + case RRC_STATE_IDLE: + deadline_s = 0; + deadline_us = (parent->sib2.rr_config_common_sib.rach_cnfg.max_harq_msg3_tx + 1)* 8 * 1000; + deadline_str = "RRCConnectionSetup"; + break; + case RRC_STATE_WAIT_FOR_CON_SETUP_COMPLETE: + deadline_s = 1; + deadline_us = 0; + deadline_str = "RRCConnectionSetupComplete"; + break; + case RRC_STATE_RELEASE_REQUEST: + deadline_s = 4; + deadline_us = 0; + deadline_str = "RRCReleaseRequest"; + break; + default: + deadline_s = parent->cfg.inactivity_timeout_ms/1000; + deadline_us = (parent->cfg.inactivity_timeout_ms%1000)*1000; + deadline_str = "Activity"; + break; + } + + if (deadline_str) { + uint64_t deadline = deadline_s*1e6 + deadline_us; + uint64_t elapsed = t[0].tv_sec*1e6 + t[0].tv_usec; + if (elapsed > deadline) { + parent->rrc_log->warning("User rnti=0x%x expired %s deadline: %d:%d>%d:%d us\n", + rnti, deadline_str, + t[0].tv_sec, t[0].tv_usec, + deadline_s, deadline_us); + memcpy(&t_last_activity, &t[2], sizeof(struct timeval)); + state = RRC_STATE_RELEASE_REQUEST; + return true; + } + } + return false; +} + +void rrc::ue::parse_ul_dcch(uint32_t lcid, byte_buffer_t *pdu) +{ + + set_activity(); + + LIBLTE_RRC_UL_DCCH_MSG_STRUCT ul_dcch_msg; + bzero(&ul_dcch_msg, sizeof(LIBLTE_RRC_UL_DCCH_MSG_STRUCT)); + + srslte_bit_unpack_vector(pdu->msg, parent->bit_buf.msg, pdu->N_bytes*8); + parent->bit_buf.N_bits = pdu->N_bytes*8; + liblte_rrc_unpack_ul_dcch_msg((LIBLTE_BIT_MSG_STRUCT*)&parent->bit_buf, &ul_dcch_msg); + + parent->rrc_log->info_hex(pdu->msg, pdu->N_bytes, + "%s - Rx %s\n", + rb_id_text[lcid], liblte_rrc_ul_dcch_msg_type_text[ul_dcch_msg.msg_type]); + transaction_id = 0; + pdu->reset(); + + switch(ul_dcch_msg.msg_type) { + case LIBLTE_RRC_UL_DCCH_MSG_TYPE_RRC_CON_SETUP_COMPLETE: + handle_rrc_con_setup_complete(&ul_dcch_msg.msg.rrc_con_setup_complete, pdu); + break; + case LIBLTE_RRC_UL_DCCH_MSG_TYPE_UL_INFO_TRANSFER: + memcpy(pdu->msg, ul_dcch_msg.msg.ul_info_transfer.dedicated_info.msg, ul_dcch_msg.msg.ul_info_transfer.dedicated_info.N_bytes); + pdu->N_bytes = ul_dcch_msg.msg.ul_info_transfer.dedicated_info.N_bytes; + parent->s1ap->write_pdu(rnti, pdu); + break; + case LIBLTE_RRC_UL_DCCH_MSG_TYPE_RRC_CON_RECONFIG_COMPLETE: + parent->rrc_log->console("User 0x%x connected\n", rnti); + state = RRC_STATE_REGISTERED; + break; + case LIBLTE_RRC_UL_DCCH_MSG_TYPE_SECURITY_MODE_COMPLETE: + handle_security_mode_complete(&ul_dcch_msg.msg.security_mode_complete); + // Skipping send_ue_cap_enquiry() procedure for now + // state = RRC_STATE_WAIT_FOR_UE_CAP_INFO; + notify_s1ap_ue_ctxt_setup_complete(); + send_connection_reconf(pdu); + state = RRC_STATE_WAIT_FOR_CON_RECONF_COMPLETE; + break; + case LIBLTE_RRC_UL_DCCH_MSG_TYPE_SECURITY_MODE_FAILURE: + handle_security_mode_failure(&ul_dcch_msg.msg.security_mode_failure); + break; + case LIBLTE_RRC_UL_DCCH_MSG_TYPE_UE_CAPABILITY_INFO: + handle_ue_cap_info(&ul_dcch_msg.msg.ue_capability_info); + send_connection_reconf(pdu); + state = RRC_STATE_WAIT_FOR_CON_RECONF_COMPLETE; + break; + default: + parent->rrc_log->error("Msg: %s not supported\n", liblte_rrc_ul_dcch_msg_type_text[ul_dcch_msg.msg_type]); + break; + } +} + +void rrc::ue::handle_rrc_con_req(LIBLTE_RRC_CONNECTION_REQUEST_STRUCT *msg) +{ + set_activity(); + + if(msg->ue_id_type == LIBLTE_RRC_CON_REQ_UE_ID_TYPE_S_TMSI) { + mmec = msg->ue_id.s_tmsi.mmec; + m_tmsi = msg->ue_id.s_tmsi.m_tmsi; + has_tmsi = true; + } + send_connection_setup(); + state = RRC_STATE_WAIT_FOR_CON_SETUP_COMPLETE; +} + +void rrc::ue::handle_rrc_con_reest_req(LIBLTE_RRC_CONNECTION_REESTABLISHMENT_REQUEST_STRUCT *msg) +{ + //TODO: Check Short-MAC-I value + parent->rrc_log->error("Not Supported: ConnectionReestablishment. \n"); + +} + +void rrc::ue::handle_rrc_con_setup_complete(LIBLTE_RRC_CONNECTION_SETUP_COMPLETE_STRUCT *msg, srslte::byte_buffer_t *pdu) +{ + parent->rrc_log->info("RRCConnectionSetupComplete transaction ID: %d\n", msg->rrc_transaction_id); + + // TODO: msg->selected_plmn_id - used to select PLMN from SIB1 list + // TODO: if(msg->registered_mme_present) - the indicated MME should be used from a pool + + memcpy(pdu->msg, msg->dedicated_info_nas.msg, msg->dedicated_info_nas.N_bytes); + pdu->N_bytes = msg->dedicated_info_nas.N_bytes; + + if(has_tmsi) { + parent->s1ap->initial_ue(rnti, pdu, m_tmsi, mmec); + } else { + parent->s1ap->initial_ue(rnti, pdu); + } + state = RRC_STATE_WAIT_FOR_CON_RECONF_COMPLETE; +} + +void rrc::ue::handle_security_mode_complete(LIBLTE_RRC_SECURITY_MODE_COMPLETE_STRUCT *msg) +{ + parent->rrc_log->info("SecurityModeComplete transaction ID: %d\n", msg->rrc_transaction_id); +} + +void rrc::ue::handle_security_mode_failure(LIBLTE_RRC_SECURITY_MODE_FAILURE_STRUCT *msg) +{ + parent->rrc_log->info("SecurityModeFailure transaction ID: %d\n", msg->rrc_transaction_id); +} + +void rrc::ue::handle_ue_cap_info(LIBLTE_RRC_UE_CAPABILITY_INFORMATION_STRUCT *msg) +{ + parent->rrc_log->info("UECapabilityInformation transaction ID: %d\n", msg->rrc_transaction_id); + for(uint32_t i=0; iN_ue_caps; i++) { + if(msg->ue_capability_rat[i].rat_type != LIBLTE_RRC_RAT_TYPE_EUTRA) { + parent->rrc_log->warning("Not handling UE capability information for RAT type %s\n", + liblte_rrc_rat_type_text[msg->ue_capability_rat[i].rat_type]); + } else { + memcpy(&eutra_capabilities, &msg->ue_capability_rat[0], sizeof(LIBLTE_RRC_UE_EUTRA_CAPABILITY_STRUCT)); + parent->rrc_log->info("UE rnti: 0x%x category: %d\n", rnti, msg->ue_capability_rat[0].eutra_capability.ue_category); + } + } + + // TODO: Add liblte_rrc support for unpacking UE cap info and repacking into + // inter-node UERadioAccessCapabilityInformation (36.331 v10.0.0 Section 10.2.2). + // This is then passed to S1AP for transfer to EPC. + // parent->s1ap->ue_capabilities(rnti, &eutra_capabilities); +} + +void rrc::ue::set_bitrates(LIBLTE_S1AP_UEAGGREGATEMAXIMUMBITRATE_STRUCT *rates) +{ + memcpy(&bitrates, rates, sizeof(LIBLTE_S1AP_UEAGGREGATEMAXIMUMBITRATE_STRUCT)); +} + +void rrc::ue::set_security_capabilities(LIBLTE_S1AP_UESECURITYCAPABILITIES_STRUCT *caps) +{ + memcpy(&security_capabilities, caps, sizeof(LIBLTE_S1AP_UESECURITYCAPABILITIES_STRUCT)); +} + +void rrc::ue::set_security_key(uint8_t* key, uint32_t length) +{ + memcpy(k_enb, key, length); + + // Select algos (TODO: use security capabilities and config preferences) + cipher_algo = srslte::CIPHERING_ALGORITHM_ID_EEA0; + integ_algo = srslte::INTEGRITY_ALGORITHM_ID_128_EIA1; + + // Generate K_rrc_enc and K_rrc_int + security_generate_k_rrc( k_enb, + cipher_algo, + integ_algo, + k_rrc_enc, + k_rrc_int); + + // Generate K_up_enc and K_up_int + security_generate_k_up( k_enb, + cipher_algo, + integ_algo, + k_up_enc, + k_up_int); + + parent->configure_security(rnti, srslte::RB_ID_SRB1, + k_rrc_enc, k_rrc_int, + k_up_enc, k_up_int, + cipher_algo, integ_algo); +} + +bool rrc::ue::setup_erabs(LIBLTE_S1AP_E_RABTOBESETUPLISTCTXTSUREQ_STRUCT *e) +{ + for(uint32_t i=0; ilen; i++) { + LIBLTE_S1AP_E_RABTOBESETUPITEMCTXTSUREQ_STRUCT *erab = &e->buffer[i]; + if(erab->ext) { + parent->rrc_log->warning("Not handling LIBLTE_S1AP_E_RABTOBESETUPITEMCTXTSUREQ_STRUCT extensions\n"); + } + if(erab->iE_Extensions_present) { + parent->rrc_log->warning("Not handling LIBLTE_S1AP_E_RABTOBESETUPITEMCTXTSUREQ_STRUCT extensions\n"); + } + + uint8_t id = erab->e_RAB_ID.E_RAB_ID; + erabs[id].id = id; + memcpy(&erabs[id].qos_params, &erab->e_RABlevelQoSParameters, sizeof(LIBLTE_S1AP_E_RABLEVELQOSPARAMETERS_STRUCT)); + memcpy(&erabs[id].address, &erab->transportLayerAddress, sizeof(LIBLTE_S1AP_TRANSPORTLAYERADDRESS_STRUCT)); + uint8_to_uint32(erab->gTP_TEID.buffer, &erabs[id].teid_out); + + uint8_t lcid = id - 2; // Map e.g. E-RAB 5 to LCID 3 (==DRB1) + parent->gtpu->add_bearer(rnti, lcid, erabs[id].teid_out, &(erabs[id].teid_in)); + + if(erab->nAS_PDU_present) { + memcpy(parent->erab_info.msg, erab->nAS_PDU.buffer, erab->nAS_PDU.n_octets); + parent->erab_info.N_bytes = erab->nAS_PDU.n_octets; + } + } + return true; +} + +bool rrc::ue::setup_erabs(LIBLTE_S1AP_E_RABTOBESETUPLISTBEARERSUREQ_STRUCT *e) +{ + for(uint32_t i=0; ilen; i++) { + LIBLTE_S1AP_E_RABTOBESETUPITEMBEARERSUREQ_STRUCT *erab = &e->buffer[i]; + if(erab->ext) { + parent->rrc_log->warning("Not handling LIBLTE_S1AP_E_RABTOBESETUPITEMCTXTSUREQ_STRUCT extensions\n"); + } + if(erab->iE_Extensions_present) { + parent->rrc_log->warning("Not handling LIBLTE_S1AP_E_RABTOBESETUPITEMCTXTSUREQ_STRUCT extensions\n"); + } + + uint8_t id = erab->e_RAB_ID.E_RAB_ID; + erabs[id].id = id; + memcpy(&erabs[id].qos_params, &erab->e_RABlevelQoSParameters, sizeof(LIBLTE_S1AP_E_RABLEVELQOSPARAMETERS_STRUCT)); + memcpy(&erabs[id].address, &erab->transportLayerAddress, sizeof(LIBLTE_S1AP_TRANSPORTLAYERADDRESS_STRUCT)); + uint8_to_uint32(erab->gTP_TEID.buffer, &erabs[id].teid_out); + + uint8_t lcid = id - 2; // Map e.g. E-RAB 5 to LCID 3 (==DRB1) + parent->gtpu->add_bearer(rnti, lcid, erabs[id].teid_out, &(erabs[id].teid_in)); + + memcpy(parent->erab_info.msg, erab->nAS_PDU.buffer, erab->nAS_PDU.n_octets); + parent->erab_info.N_bytes = erab->nAS_PDU.n_octets; + } + // Work in progress + notify_s1ap_ue_erab_setup_response(e); + send_connection_reconf_new_bearer(e); + return true; +} + +bool rrc::ue::release_erabs() +{ + typedef std::map::iterator it_t; + for(it_t it=erabs.begin(); it!=erabs.end(); ++it) { + // TODO: notify GTPU layer + } + erabs.clear(); + return true; +} + +void rrc::ue::notify_s1ap_ue_ctxt_setup_complete() +{ + LIBLTE_S1AP_MESSAGE_INITIALCONTEXTSETUPRESPONSE_STRUCT res; + res.E_RABSetupListCtxtSURes.len = 0; + res.E_RABFailedToSetupListCtxtSURes.len = 0; + + typedef std::map::iterator it_t; + for(it_t it=erabs.begin(); it!=erabs.end(); ++it) { + uint32_t j = res.E_RABSetupListCtxtSURes.len++; + res.E_RABSetupListCtxtSURes.buffer[j].ext = false; + res.E_RABSetupListCtxtSURes.buffer[j].iE_Extensions_present = false; + res.E_RABSetupListCtxtSURes.buffer[j].e_RAB_ID.ext = false; + res.E_RABSetupListCtxtSURes.buffer[j].e_RAB_ID.E_RAB_ID = it->second.id; + uint32_to_uint8(it->second.teid_in, res.E_RABSetupListCtxtSURes.buffer[j].gTP_TEID.buffer); + } + + parent->s1ap->ue_ctxt_setup_complete(rnti, &res); +} + +void rrc::ue::notify_s1ap_ue_erab_setup_response(LIBLTE_S1AP_E_RABTOBESETUPLISTBEARERSUREQ_STRUCT *e) +{ + LIBLTE_S1AP_MESSAGE_E_RABSETUPRESPONSE_STRUCT res; + res.E_RABSetupListBearerSURes.len = 0; + res.E_RABFailedToSetupListBearerSURes.len = 0; + + for(uint32_t i=0; ilen; i++) { + res.E_RABSetupListBearerSURes_present = true; + LIBLTE_S1AP_E_RABTOBESETUPITEMBEARERSUREQ_STRUCT *erab = &e->buffer[i]; + uint8_t id = erab->e_RAB_ID.E_RAB_ID; + uint32_t j = res.E_RABSetupListBearerSURes.len++; + res.E_RABSetupListBearerSURes.buffer[j].ext = false; + res.E_RABSetupListBearerSURes.buffer[j].iE_Extensions_present = false; + res.E_RABSetupListBearerSURes.buffer[j].e_RAB_ID.ext = false; + res.E_RABSetupListBearerSURes.buffer[j].e_RAB_ID.E_RAB_ID = id; + uint32_to_uint8(erabs[id].teid_in, res.E_RABSetupListBearerSURes.buffer[j].gTP_TEID.buffer); + } + + parent->s1ap->ue_erab_setup_complete(rnti, &res); +} + +void rrc::ue::send_connection_reest_rej() +{ + LIBLTE_RRC_DL_CCCH_MSG_STRUCT dl_ccch_msg; + bzero(&dl_ccch_msg, sizeof(LIBLTE_RRC_DL_CCCH_MSG_STRUCT)); + + dl_ccch_msg.msg_type = LIBLTE_RRC_DL_CCCH_MSG_TYPE_RRC_CON_REEST_REJ; + + send_dl_ccch(&dl_ccch_msg); + +} + +void rrc::ue::send_connection_setup(bool is_setup) +{ + LIBLTE_RRC_DL_CCCH_MSG_STRUCT dl_ccch_msg; + bzero(&dl_ccch_msg, sizeof(LIBLTE_RRC_DL_CCCH_MSG_STRUCT)); + + LIBLTE_RRC_RR_CONFIG_DEDICATED_STRUCT* rr_cfg = NULL; + if (is_setup) { + dl_ccch_msg.msg_type = LIBLTE_RRC_DL_CCCH_MSG_TYPE_RRC_CON_SETUP; + dl_ccch_msg.msg.rrc_con_setup.rrc_transaction_id = (transaction_id++)%4; + rr_cfg = &dl_ccch_msg.msg.rrc_con_setup.rr_cnfg; + } else { + dl_ccch_msg.msg_type = LIBLTE_RRC_DL_CCCH_MSG_TYPE_RRC_CON_REEST; + dl_ccch_msg.msg.rrc_con_reest.rrc_transaction_id = (transaction_id++)%4; + rr_cfg = &dl_ccch_msg.msg.rrc_con_reest.rr_cnfg; + } + + + // Add SRB1 to cfg + rr_cfg->srb_to_add_mod_list_size = 1; + rr_cfg->srb_to_add_mod_list[0].srb_id = 1; + rr_cfg->srb_to_add_mod_list[0].lc_cnfg_present = true; + rr_cfg->srb_to_add_mod_list[0].lc_default_cnfg_present = true; + rr_cfg->srb_to_add_mod_list[0].rlc_cnfg_present = true; + rr_cfg->srb_to_add_mod_list[0].rlc_default_cnfg_present = true; + + // mac-MainConfig + rr_cfg->mac_main_cnfg_present = true; + LIBLTE_RRC_MAC_MAIN_CONFIG_STRUCT *mac_cfg = &rr_cfg->mac_main_cnfg.explicit_value; + mac_cfg->ulsch_cnfg_present = true; + memcpy(&mac_cfg->ulsch_cnfg, &parent->cfg.mac_cnfg.ulsch_cnfg, sizeof(LIBLTE_RRC_ULSCH_CONFIG_STRUCT)); + mac_cfg->drx_cnfg_present = false; + mac_cfg->phr_cnfg_present = true; + memcpy(&mac_cfg->phr_cnfg, &parent->cfg.mac_cnfg.phr_cnfg, sizeof(LIBLTE_RRC_PHR_CONFIG_STRUCT)); + mac_cfg->time_alignment_timer = parent->cfg.mac_cnfg.time_alignment_timer; + + // physicalConfigDedicated + rr_cfg->phy_cnfg_ded_present = true; + LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT *phy_cfg = &rr_cfg->phy_cnfg_ded; + bzero(phy_cfg, sizeof(LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT)); + phy_cfg->pusch_cnfg_ded_present = true; + memcpy(&phy_cfg->pusch_cnfg_ded, &parent->cfg.pusch_cfg, sizeof(LIBLTE_RRC_PUSCH_CONFIG_DEDICATED_STRUCT)); + phy_cfg->sched_request_cnfg_present = true; + phy_cfg->sched_request_cnfg.setup_present = true; + phy_cfg->sched_request_cnfg.dsr_trans_max = parent->cfg.sr_cfg.dsr_max; + + if (is_setup) { + if (sr_allocate(parent->cfg.sr_cfg.period, &phy_cfg->sched_request_cnfg.sr_cnfg_idx, &phy_cfg->sched_request_cnfg.sr_pucch_resource_idx)) { + parent->rrc_log->error("Allocating SR resources for rnti=%d\n", rnti); + return; + } + } else { + phy_cfg->sched_request_cnfg.sr_cnfg_idx = sr_I; + phy_cfg->sched_request_cnfg.sr_pucch_resource_idx = sr_N_pucch; + } + // Power control + phy_cfg->ul_pwr_ctrl_ded_present = true; + phy_cfg->ul_pwr_ctrl_ded.p0_ue_pusch = 0; + phy_cfg->ul_pwr_ctrl_ded.delta_mcs_en = LIBLTE_RRC_DELTA_MCS_ENABLED_EN0; + phy_cfg->ul_pwr_ctrl_ded.accumulation_en = true; + phy_cfg->ul_pwr_ctrl_ded.p0_ue_pucch = 0, + phy_cfg->ul_pwr_ctrl_ded.p_srs_offset = 3; + + phy_cfg->pdsch_cnfg_ded_present = true; + phy_cfg->pdsch_cnfg_ded = LIBLTE_RRC_PDSCH_CONFIG_P_A_DB_0; + + phy_cfg->cqi_report_cnfg_present = true; + if(parent->cfg.cqi_cfg.mode == RRC_CFG_CQI_MODE_APERIODIC) { + phy_cfg->cqi_report_cnfg.report_mode_aperiodic_present = true; + phy_cfg->cqi_report_cnfg.report_mode_aperiodic = LIBLTE_RRC_CQI_REPORT_MODE_APERIODIC_RM30; + } else { + phy_cfg->cqi_report_cnfg.report_periodic_present = true; + phy_cfg->cqi_report_cnfg.report_periodic_setup_present = true; + phy_cfg->cqi_report_cnfg.report_periodic.format_ind_periodic = LIBLTE_RRC_CQI_FORMAT_INDICATOR_PERIODIC_WIDEBAND_CQI; + phy_cfg->cqi_report_cnfg.report_periodic.simult_ack_nack_and_cqi = parent->cfg.cqi_cfg.simultaneousAckCQI; + phy_cfg->cqi_report_cnfg.report_periodic.ri_cnfg_idx_present = false; + if (is_setup) { + if (cqi_allocate(parent->cfg.cqi_cfg.period, + &phy_cfg->cqi_report_cnfg.report_periodic.pmi_cnfg_idx, + &phy_cfg->cqi_report_cnfg.report_periodic.pucch_resource_idx)) + { + parent->rrc_log->error("Allocating CQI resources for rnti=%d\n", rnti); + return; + } + } else { + phy_cfg->cqi_report_cnfg.report_periodic.pucch_resource_idx = cqi_pucch; + phy_cfg->cqi_report_cnfg.report_periodic.pmi_cnfg_idx = cqi_idx; + } + } + phy_cfg->cqi_report_cnfg.nom_pdsch_rs_epre_offset = 0; + + + // Add SRB1 to Scheduler + srsenb::sched_interface::ue_cfg_t sched_cfg; + bzero(&sched_cfg, sizeof(srsenb::sched_interface::ue_cfg_t)); + sched_cfg.maxharq_tx = liblte_rrc_max_harq_tx_num[parent->cfg.mac_cnfg.ulsch_cnfg.max_harq_tx]; + sched_cfg.continuous_pusch = false; + sched_cfg.aperiodic_cqi_period = parent->cfg.cqi_cfg.mode == RRC_CFG_CQI_MODE_APERIODIC?parent->cfg.cqi_cfg.period:0; + sched_cfg.ue_bearers[0].direction = srsenb::sched_interface::ue_bearer_cfg_t::BOTH; + sched_cfg.ue_bearers[1].direction = srsenb::sched_interface::ue_bearer_cfg_t::BOTH; + sched_cfg.sr_I = sr_I; + sched_cfg.sr_N_pucch = sr_N_pucch; + sched_cfg.sr_enabled = true; + sched_cfg.cqi_pucch = cqi_pucch; + sched_cfg.cqi_idx = cqi_idx; + sched_cfg.cqi_enabled = parent->cfg.cqi_cfg.mode == RRC_CFG_CQI_MODE_PERIODIC; + sched_cfg.pucch_cfg.delta_pucch_shift = liblte_rrc_delta_pucch_shift_num[parent->sib2.rr_config_common_sib.pucch_cnfg.delta_pucch_shift%LIBLTE_RRC_DELTA_PUCCH_SHIFT_N_ITEMS]; + sched_cfg.pucch_cfg.N_cs = parent->sib2.rr_config_common_sib.pucch_cnfg.n_cs_an; + sched_cfg.pucch_cfg.n_rb_2 = parent->sib2.rr_config_common_sib.pucch_cnfg.n_rb_cqi; + + // Configure MAC + parent->mac->ue_cfg(rnti, &sched_cfg); + + // Configure SRB1 in RLC and PDCP + parent->rlc->add_bearer(rnti, 1); + parent->pdcp->add_bearer(rnti, 1); + + // Configure PHY layer + parent->phy->set_config_dedicated(rnti, phy_cfg); + parent->mac->phy_config_enabled(rnti, true); + + rr_cfg->drb_to_add_mod_list_size = 0; + rr_cfg->drb_to_release_list_size = 0; + rr_cfg->rlf_timers_and_constants_present = false; + rr_cfg->sps_cnfg_present = false; + + send_dl_ccch(&dl_ccch_msg); + +} + + +void rrc::ue::send_connection_reest() +{ + send_connection_setup(false); +} + + +void rrc::ue::send_connection_release() +{ + LIBLTE_RRC_DL_DCCH_MSG_STRUCT dl_dcch_msg; + dl_dcch_msg.msg_type = LIBLTE_RRC_DL_DCCH_MSG_TYPE_RRC_CON_RELEASE; + dl_dcch_msg.msg.rrc_con_release.rrc_transaction_id = (transaction_id++)%4; + dl_dcch_msg.msg.rrc_con_release.release_cause = LIBLTE_RRC_RELEASE_CAUSE_OTHER; + + send_dl_dcch(&dl_dcch_msg); +} + +int rrc::ue::get_drbid_config(LIBLTE_RRC_DRB_TO_ADD_MOD_STRUCT *drb, int drb_id) +{ + uint32_t lc_id = drb_id + 2; + uint32_t erab_id = lc_id + 2; + uint32_t qci = erabs[erab_id].qos_params.qCI.QCI; + + if (qci >= MAX_NOF_QCI) { + parent->rrc_log->error("Invalid QCI=%d for ERAB_id=%d, DRB_id=%d\n", qci, erab_id, drb_id); + return -1; + } + + if (!parent->cfg.qci_cfg[qci].configured) { + parent->rrc_log->error("QCI=%d not configured\n", qci); + return -1; + } + + // Add DRB1 to the message + drb->drb_id = drb_id; + drb->lc_id = lc_id; + drb->lc_id_present = true; + drb->eps_bearer_id = erab_id; + drb->eps_bearer_id_present = true; + + drb->lc_cnfg_present = true; + drb->lc_cnfg.ul_specific_params_present = true; + drb->lc_cnfg.log_chan_sr_mask_present = false; + drb->lc_cnfg.ul_specific_params.log_chan_group_present = true; + memcpy(&drb->lc_cnfg.ul_specific_params, &parent->cfg.qci_cfg[qci].lc_cfg, sizeof(LIBLTE_RRC_UL_SPECIFIC_PARAMETERS_STRUCT)); + + drb->pdcp_cnfg_present = true; + memcpy(&drb->pdcp_cnfg, &parent->cfg.qci_cfg[qci].pdcp_cfg, sizeof(LIBLTE_RRC_PDCP_CONFIG_STRUCT)); + + drb->rlc_cnfg_present = true; + memcpy(&drb->rlc_cnfg, &parent->cfg.qci_cfg[qci].rlc_cfg, sizeof(LIBLTE_RRC_RLC_CONFIG_STRUCT)); + + return 0; +} + +void rrc::ue::send_connection_reconf_upd(srslte::byte_buffer_t *pdu) +{ + + LIBLTE_RRC_DL_DCCH_MSG_STRUCT dl_dcch_msg; + bzero(&dl_dcch_msg, sizeof(LIBLTE_RRC_DL_DCCH_MSG_STRUCT)); + + dl_dcch_msg.msg_type = LIBLTE_RRC_DL_DCCH_MSG_TYPE_RRC_CON_RECONFIG; + dl_dcch_msg.msg.rrc_con_reconfig.rrc_transaction_id = (transaction_id++)%4; + + LIBLTE_RRC_RR_CONFIG_DEDICATED_STRUCT* rr_cfg = &dl_dcch_msg.msg.rrc_con_reconfig.rr_cnfg_ded; + + dl_dcch_msg.msg.rrc_con_reconfig.rr_cnfg_ded_present = true; + + rr_cfg->phy_cnfg_ded_present = true; + LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT *phy_cfg = &rr_cfg->phy_cnfg_ded; + bzero(phy_cfg, sizeof(LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT)); + phy_cfg->sched_request_cnfg_present = true; + phy_cfg->sched_request_cnfg.setup_present = true; + phy_cfg->sched_request_cnfg.dsr_trans_max = parent->cfg.sr_cfg.dsr_max; + + phy_cfg->cqi_report_cnfg_present = true; + if (cqi_allocated) { + phy_cfg->cqi_report_cnfg.report_periodic_present = true; + phy_cfg->cqi_report_cnfg.report_periodic_setup_present = true; + phy_cfg->cqi_report_cnfg.report_periodic.format_ind_periodic = LIBLTE_RRC_CQI_FORMAT_INDICATOR_PERIODIC_WIDEBAND_CQI; + phy_cfg->cqi_report_cnfg.report_periodic.simult_ack_nack_and_cqi = false; + phy_cfg->cqi_report_cnfg.report_periodic.ri_cnfg_idx_present = false; + phy_cfg->cqi_report_cnfg.report_periodic.pucch_resource_idx = cqi_pucch; + phy_cfg->cqi_report_cnfg.report_periodic.pmi_cnfg_idx = cqi_idx; + } else { + phy_cfg->cqi_report_cnfg.report_mode_aperiodic_present = true; + phy_cfg->cqi_report_cnfg.report_mode_aperiodic = LIBLTE_RRC_CQI_REPORT_MODE_APERIODIC_RM30; + phy_cfg->cqi_report_cnfg.nom_pdsch_rs_epre_offset = 0; + } + + sr_get(&phy_cfg->sched_request_cnfg.sr_cnfg_idx, &phy_cfg->sched_request_cnfg.sr_pucch_resource_idx); + + pdu->reset(); + + send_dl_dcch(&dl_dcch_msg, pdu); + + state = RRC_STATE_WAIT_FOR_CON_RECONF_COMPLETE; + +} + +void rrc::ue::send_connection_reconf(srslte::byte_buffer_t *pdu) +{ + + LIBLTE_RRC_DL_DCCH_MSG_STRUCT dl_dcch_msg; + dl_dcch_msg.msg_type = LIBLTE_RRC_DL_DCCH_MSG_TYPE_RRC_CON_RECONFIG; + dl_dcch_msg.msg.rrc_con_reconfig.rrc_transaction_id = (transaction_id++)%4; + + LIBLTE_RRC_CONNECTION_RECONFIGURATION_STRUCT* conn_reconf = &dl_dcch_msg.msg.rrc_con_reconfig; + conn_reconf->rr_cnfg_ded_present = true; + conn_reconf->rr_cnfg_ded.mac_main_cnfg_present = false; + conn_reconf->rr_cnfg_ded.phy_cnfg_ded_present = false; + conn_reconf->rr_cnfg_ded.rlf_timers_and_constants_present = false; + conn_reconf->rr_cnfg_ded.sps_cnfg_present = false; + conn_reconf->rr_cnfg_ded.drb_to_release_list_size = 0; + conn_reconf->meas_cnfg_present = false; + conn_reconf->mob_ctrl_info_present = false; + conn_reconf->sec_cnfg_ho_present = false; + + // Add SRB2 to the message + conn_reconf->rr_cnfg_ded.srb_to_add_mod_list_size = 1; + conn_reconf->rr_cnfg_ded.srb_to_add_mod_list[0].srb_id = 2; + conn_reconf->rr_cnfg_ded.srb_to_add_mod_list[0].lc_cnfg_present = true; + conn_reconf->rr_cnfg_ded.srb_to_add_mod_list[0].lc_default_cnfg_present = true; + conn_reconf->rr_cnfg_ded.srb_to_add_mod_list[0].rlc_cnfg_present = true; + conn_reconf->rr_cnfg_ded.srb_to_add_mod_list[0].rlc_default_cnfg_present = true; + + // Get DRB1 configuration + if (get_drbid_config(&conn_reconf->rr_cnfg_ded.drb_to_add_mod_list[0], 1)) { + parent->rrc_log->error("Getting DRB1 configuration\n"); + } else { + conn_reconf->rr_cnfg_ded.drb_to_add_mod_list_size = 1; + } + + // Add SRB2 and DRB1 to the scheduler + srsenb::sched_interface::ue_bearer_cfg_t bearer_cfg; + bearer_cfg.direction = srsenb::sched_interface::ue_bearer_cfg_t::BOTH; + parent->mac->bearer_ue_cfg(rnti, 2, &bearer_cfg); + parent->mac->bearer_ue_cfg(rnti, 3, &bearer_cfg); + + // Configure SRB2 in RLC and PDCP + parent->rlc->add_bearer(rnti, 2); + parent->pdcp->add_bearer(rnti, 2); + + // Configure DRB1 in RLC + parent->rlc->add_bearer(rnti, 3, &conn_reconf->rr_cnfg_ded.drb_to_add_mod_list[0].rlc_cnfg); + // Configure DRB1 in PDCP + parent->pdcp->add_bearer(rnti, 3, &conn_reconf->rr_cnfg_ded.drb_to_add_mod_list[0].pdcp_cnfg); + // DRB1 has already been configured in GTPU through bearer setup + + // Add NAS Attach accept + conn_reconf->N_ded_info_nas = 1; + conn_reconf->ded_info_nas_list[0].N_bytes = parent->erab_info.N_bytes; + memcpy(conn_reconf->ded_info_nas_list[0].msg, parent->erab_info.msg, parent->erab_info.N_bytes); + + // Reuse same PDU + pdu->reset(); + + send_dl_dcch(&dl_dcch_msg, pdu); + + state = RRC_STATE_WAIT_FOR_CON_RECONF_COMPLETE; +} + +void rrc::ue::send_connection_reconf_new_bearer(LIBLTE_S1AP_E_RABTOBESETUPLISTBEARERSUREQ_STRUCT *e) +{ + srslte::byte_buffer_t *pdu = parent->pool->allocate(__FUNCTION__); + + LIBLTE_RRC_DL_DCCH_MSG_STRUCT dl_dcch_msg; + dl_dcch_msg.msg_type = LIBLTE_RRC_DL_DCCH_MSG_TYPE_RRC_CON_RECONFIG; + dl_dcch_msg.msg.rrc_con_reconfig.rrc_transaction_id = (transaction_id++)%4; + + LIBLTE_RRC_CONNECTION_RECONFIGURATION_STRUCT* conn_reconf = &dl_dcch_msg.msg.rrc_con_reconfig; + conn_reconf->rr_cnfg_ded_present = true; + conn_reconf->rr_cnfg_ded.mac_main_cnfg_present = false; + conn_reconf->rr_cnfg_ded.phy_cnfg_ded_present = false; + conn_reconf->rr_cnfg_ded.rlf_timers_and_constants_present = false; + conn_reconf->rr_cnfg_ded.sps_cnfg_present = false; + conn_reconf->rr_cnfg_ded.drb_to_release_list_size = 0; + conn_reconf->rr_cnfg_ded.srb_to_add_mod_list_size = 0; + conn_reconf->rr_cnfg_ded.drb_to_add_mod_list_size = 0; + conn_reconf->meas_cnfg_present = false; + conn_reconf->mob_ctrl_info_present = false; + conn_reconf->sec_cnfg_ho_present = false; + + for(uint32_t i=0; ilen; i++) { + LIBLTE_S1AP_E_RABTOBESETUPITEMBEARERSUREQ_STRUCT *erab = &e->buffer[i]; + uint8_t id = erab->e_RAB_ID.E_RAB_ID; + uint8_t lcid = id - 2; // Map e.g. E-RAB 5 to LCID 3 (==DRB1) + + // Get DRB configuration + if (get_drbid_config(&conn_reconf->rr_cnfg_ded.drb_to_add_mod_list[i], lcid)) { + parent->rrc_log->error("Getting DRB configuration\n"); + } else { + conn_reconf->rr_cnfg_ded.drb_to_add_mod_list_size++; + } + + // Add DRB to the scheduler + srsenb::sched_interface::ue_bearer_cfg_t bearer_cfg; + bearer_cfg.direction = srsenb::sched_interface::ue_bearer_cfg_t::BOTH; + parent->mac->bearer_ue_cfg(rnti, lcid, &bearer_cfg); + + // Configure DRB in RLC + parent->rlc->add_bearer(rnti, lcid, &conn_reconf->rr_cnfg_ded.drb_to_add_mod_list[i].rlc_cnfg); + // Configure DRB in PDCP + parent->pdcp->add_bearer(rnti, lcid, &conn_reconf->rr_cnfg_ded.drb_to_add_mod_list[i].pdcp_cnfg); + // DRB has already been configured in GTPU through bearer setup + + // Add NAS message + conn_reconf->ded_info_nas_list[conn_reconf->N_ded_info_nas].N_bytes = parent->erab_info.N_bytes; + memcpy(conn_reconf->ded_info_nas_list[conn_reconf->N_ded_info_nas].msg, parent->erab_info.msg, parent->erab_info.N_bytes); + conn_reconf->N_ded_info_nas++; + } + + send_dl_dcch(&dl_dcch_msg, pdu); +} + +void rrc::ue::send_security_mode_command() +{ + LIBLTE_RRC_DL_DCCH_MSG_STRUCT dl_dcch_msg; + dl_dcch_msg.msg_type = LIBLTE_RRC_DL_DCCH_MSG_TYPE_SECURITY_MODE_COMMAND; + + LIBLTE_RRC_SECURITY_MODE_COMMAND_STRUCT* comm = &dl_dcch_msg.msg.security_mode_cmd; + comm->rrc_transaction_id = (transaction_id++)%4; + + // TODO: select these based on UE capabilities and preference order + comm->sec_algs.cipher_alg = (LIBLTE_RRC_CIPHERING_ALGORITHM_ENUM)cipher_algo; + comm->sec_algs.int_alg = (LIBLTE_RRC_INTEGRITY_PROT_ALGORITHM_ENUM)integ_algo; + + send_dl_dcch(&dl_dcch_msg); +} + +void rrc::ue::send_ue_cap_enquiry() +{ + LIBLTE_RRC_DL_DCCH_MSG_STRUCT dl_dcch_msg; + dl_dcch_msg.msg_type = LIBLTE_RRC_DL_DCCH_MSG_TYPE_UE_CAPABILITY_ENQUIRY; + + LIBLTE_RRC_UE_CAPABILITY_ENQUIRY_STRUCT* enq = &dl_dcch_msg.msg.ue_cap_enquiry; + enq->rrc_transaction_id = (transaction_id++)%4; + + enq->N_ue_cap_reqs = 1; + enq->ue_capability_request[0] = LIBLTE_RRC_RAT_TYPE_EUTRA; + + send_dl_dcch(&dl_dcch_msg); +} + +/********************** HELPERS ***************************/ + +void rrc::ue::send_dl_ccch(LIBLTE_RRC_DL_CCCH_MSG_STRUCT *dl_ccch_msg) +{ + // Allocate a new PDU buffer, pack the message and send to PDCP + byte_buffer_t *pdu = parent->pool->allocate(__FUNCTION__); + if (pdu) { + liblte_rrc_pack_dl_ccch_msg(dl_ccch_msg, (LIBLTE_BIT_MSG_STRUCT*) &parent->bit_buf); + srslte_bit_pack_vector(parent->bit_buf.msg, pdu->msg, parent->bit_buf.N_bits); + pdu->N_bytes = 1+(parent->bit_buf.N_bits-1)/8; + parent->rrc_log->info_hex(pdu->msg, pdu->N_bytes, + "SRB0 - rnti=0x%x, Sending: %s\n", + rnti, + liblte_rrc_dl_ccch_msg_type_text[dl_ccch_msg->msg_type]); + + parent->pdcp->write_sdu(rnti, srslte::RB_ID_SRB0, pdu); + + } else { + parent->rrc_log->error("Allocating pdu\n"); + } +} + +void rrc::ue::send_dl_dcch(LIBLTE_RRC_DL_DCCH_MSG_STRUCT *dl_dcch_msg, byte_buffer_t *pdu) +{ + if (!pdu) { + pdu = parent->pool->allocate(__FUNCTION__); + } + if (pdu) { + liblte_rrc_pack_dl_dcch_msg(dl_dcch_msg, (LIBLTE_BIT_MSG_STRUCT*) &parent->bit_buf); + srslte_bit_pack_vector(parent->bit_buf.msg, pdu->msg, parent->bit_buf.N_bits); + pdu->N_bytes = 1+(parent->bit_buf.N_bits-1)/8; + parent->rrc_log->info_hex(pdu->msg, pdu->N_bytes, + "SRB1 - rnti=0x%x, Sending: %s\n", + rnti, + liblte_rrc_dl_dcch_msg_type_text[dl_dcch_msg->msg_type]); + + parent->pdcp->write_sdu(rnti, srslte::RB_ID_SRB1, pdu); + + } else { + parent->rrc_log->error("Allocating pdu\n"); + } +} + +int rrc::ue::sr_free() +{ + if (sr_allocated) { + if (parent->sr_sched.nof_users[sr_sched_prb_idx][sr_sched_sf_idx] > 0) { + parent->sr_sched.nof_users[sr_sched_prb_idx][sr_sched_sf_idx]--; + } else { + parent->rrc_log->warning("Removing SR resources: no users in time-frequency slot (%d, %d)\n", sr_sched_prb_idx, sr_sched_sf_idx); + } + parent->rrc_log->info("Deallocated SR resources for time-frequency slot (%d, %d)\n", sr_sched_prb_idx, sr_sched_sf_idx); + } + return 0; +} + +void rrc::ue::sr_get(uint32_t *I_sr, uint32_t *N_pucch_sr) +{ + *I_sr = sr_I; + *N_pucch_sr = sr_N_pucch; +} + +int rrc::ue::sr_allocate(uint32_t period, uint32_t *I_sr, uint32_t *N_pucch_sr) +{ + uint32_t c = SRSLTE_CP_ISNORM(parent->cfg.cell.cp)?3:2; + uint32_t delta_pucch_shift = liblte_rrc_delta_pucch_shift_num[parent->sib2.rr_config_common_sib.pucch_cnfg.delta_pucch_shift]; + + uint32_t max_users = 12*c/delta_pucch_shift; + + // Find freq-time resources with least number of users + int i_min=0, j_min=0; + uint32_t min_users = 1e6; + for (uint32_t i=0;icfg.sr_cfg.nof_prb;i++) { + for (uint32_t j=0;jcfg.sr_cfg.nof_subframes;j++) { + if (parent->sr_sched.nof_users[i][j] < min_users) { + i_min = i; + j_min = j; + min_users = parent->sr_sched.nof_users[i][j]; + } + } + } + + if (parent->sr_sched.nof_users[i_min][j_min] > max_users) { + parent->rrc_log->error("Not enough PUCCH resources to allocate Scheduling Request\n"); + return -1; + } + + // Compute I_sr + if (period != 5 && period != 10 && period != 20 && period != 40 && period != 80) { + parent->rrc_log->error("Invalid SchedulingRequest period %d ms\n", period); + return -1; + } + if (parent->cfg.sr_cfg.sf_mapping[j_min] < period) { + if (period > 5) { + *I_sr = period - 5 + parent->cfg.sr_cfg.sf_mapping[j_min]; + } else { + *I_sr = period + parent->cfg.sr_cfg.sf_mapping[j_min]; + } + } else { + parent->rrc_log->error("Allocating SR: invalid sf_idx=%d for period=%d\n", parent->cfg.sr_cfg.sf_mapping[j_min], period); + return -1; + } + + // Compute N_pucch_sr + *N_pucch_sr = i_min*max_users + parent->sr_sched.nof_users[i_min][j_min]; + if (parent->sib2.rr_config_common_sib.pucch_cnfg.n_cs_an) { + *N_pucch_sr += parent->sib2.rr_config_common_sib.pucch_cnfg.n_cs_an; + } + + // Allocate user + parent->sr_sched.nof_users[i_min][j_min]++; + sr_sched_prb_idx = i_min; + sr_sched_sf_idx = j_min; + sr_allocated = true; + sr_I = *I_sr; + sr_N_pucch = *N_pucch_sr; + + parent->rrc_log->info("Allocated SR resources for time-frequency slot (%d, %d), N_pucch_sr=%d, I_sr=%d\n", + sr_sched_prb_idx, sr_sched_sf_idx, *N_pucch_sr, *I_sr); + + return 0; +} + + +int rrc::ue::cqi_free() +{ + if (cqi_allocated) { + if (parent->cqi_sched.nof_users[cqi_sched_prb_idx][cqi_sched_sf_idx] > 0) { + parent->cqi_sched.nof_users[cqi_sched_prb_idx][cqi_sched_sf_idx]--; + } else { + parent->rrc_log->warning("Removing CQI resources: no users in time-frequency slot (%d, %d)\n", cqi_sched_prb_idx, cqi_sched_sf_idx); + } + parent->rrc_log->info("Deallocated CQI resources for time-frequency slot (%d, %d)\n", cqi_sched_prb_idx, cqi_sched_sf_idx); + } + return 0; +} + +void rrc::ue::cqi_get(uint32_t *pmi_idx, uint32_t *n_pucch) +{ + *pmi_idx = cqi_idx; + *n_pucch = cqi_pucch; +} + +int rrc::ue::cqi_allocate(uint32_t period, uint32_t *pmi_idx, uint32_t *n_pucch) +{ + uint32_t c = SRSLTE_CP_ISNORM(parent->cfg.cell.cp)?3:2; + uint32_t delta_pucch_shift = liblte_rrc_delta_pucch_shift_num[parent->sib2.rr_config_common_sib.pucch_cnfg.delta_pucch_shift]; + + uint32_t max_users = 12*c/delta_pucch_shift; + + // Find freq-time resources with least number of users + int i_min=0, j_min=0; + uint32_t min_users = 1e6; + for (uint32_t i=0;icfg.cqi_cfg.nof_prb;i++) { + for (uint32_t j=0;jcfg.cqi_cfg.nof_subframes;j++) { + if (parent->cqi_sched.nof_users[i][j] < min_users) { + i_min = i; + j_min = j; + min_users = parent->cqi_sched.nof_users[i][j]; + } + } + } + + if (parent->cqi_sched.nof_users[i_min][j_min] > max_users) { + parent->rrc_log->error("Not enough PUCCH resources to allocate Scheduling Request\n"); + return -1; + } + + // Compute I_sr + if (period != 2 && period != 5 && period != 10 && period != 20 && period != 40 && period != 80 && + period != 160 && period != 32 && period != 64 && period != 128) { + parent->rrc_log->error("Invalid CQI Report period %d ms\n", period); + return -1; + } + if (parent->cfg.cqi_cfg.sf_mapping[j_min] < period) { + if (period != 32 && period != 64 && period != 128) { + if (period > 2) { + *pmi_idx = period - 3 + parent->cfg.cqi_cfg.sf_mapping[j_min]; + } else { + *pmi_idx = parent->cfg.cqi_cfg.sf_mapping[j_min]; + } + } else { + if (period == 32) { + *pmi_idx = 318 + parent->cfg.cqi_cfg.sf_mapping[j_min]; + } else if (period == 64) { + *pmi_idx = 350 + parent->cfg.cqi_cfg.sf_mapping[j_min]; + } else if (period == 64) { + *pmi_idx = 414 + parent->cfg.cqi_cfg.sf_mapping[j_min]; + } + } + } else { + parent->rrc_log->error("Allocating SR: invalid sf_idx=%d for period=%d\n", parent->cfg.cqi_cfg.sf_mapping[j_min], period); + return -1; + } + + // Compute n_pucch_2 + *n_pucch = i_min*max_users + parent->cqi_sched.nof_users[i_min][j_min]; + if (parent->sib2.rr_config_common_sib.pucch_cnfg.n_cs_an) { + *n_pucch += parent->sib2.rr_config_common_sib.pucch_cnfg.n_cs_an; + } + + // Allocate user + parent->cqi_sched.nof_users[i_min][j_min]++; + cqi_sched_prb_idx = i_min; + cqi_sched_sf_idx = j_min; + cqi_allocated = true; + cqi_idx = *pmi_idx; + cqi_pucch = *n_pucch; + + parent->rrc_log->info("Allocated CQI resources for time-frequency slot (%d, %d), n_pucch_2=%d, pmi_cfg_idx=%d\n", + cqi_sched_prb_idx, cqi_sched_sf_idx, *n_pucch, *pmi_idx); + + return 0; +} + + + + +} diff --git a/srsenb/src/upper/s1ap.cc b/srsenb/src/upper/s1ap.cc new file mode 100644 index 000000000..032a6018f --- /dev/null +++ b/srsenb/src/upper/s1ap.cc @@ -0,0 +1,1055 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2017 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of srsLTE. + * + * srsUE 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. + * + * srsUE 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 "upper/s1ap.h" +#include "upper/common_enb.h" + +#include +#include +#include //for close(), sleep() +#include +#include +#include +#include +#include //for inet_ntop() + +namespace srsenb{ + +bool s1ap::init(s1ap_args_t args_, rrc_interface_s1ap *rrc_, srslte::log *s1ap_log_) +{ + rrc = rrc_; + args = args_; + s1ap_log = s1ap_log_; + + pool = srslte::byte_buffer_pool::get_instance(); + mme_connected = false; + running = false; + next_eNB_UE_S1AP_ID = 1; + next_ue_stream_id = 1; + + build_tai_cgi(); + + start(S1AP_THREAD_PRIO); + + return true; +} + +void s1ap::stop() +{ + if(running) { + running = false; + thread_cancel(); + wait_thread_finish(); + } + + if(close(socket_fd) == -1) { + s1ap_log->error("Failed to close SCTP socket\n"); + } + return; +} + +void s1ap::get_metrics(s1ap_metrics_t &m) +{ + if(!running) { + m.status = S1AP_ERROR; + return; + } + if(mme_connected) { + m.status = S1AP_READY; + }else{ + m.status = S1AP_ATTACHING; + } + return; +} + +void s1ap::run_thread() +{ + srslte::byte_buffer_t *pdu = pool_allocate; + + uint32_t sz = SRSLTE_MAX_BUFFER_SIZE_BYTES - SRSLTE_BUFFER_HEADER_OFFSET; + running = true; + + // Connect to MME + while(running && !connect_mme()) { + s1ap_log->error("Failed to connect to MME - retrying in 10 seconds\n"); + s1ap_log->console("Failed to connect to MME - retrying in 10 seconds\n"); + sleep(10); + } + if(!setup_s1()) { + s1ap_log->error("S1 setup failed\n"); + s1ap_log->console("S1 setup failed\n"); + running = false; + return; + } + + // S1AP rx loop + while(running) { + pdu->reset(); + pdu->N_bytes = recv(socket_fd, pdu->msg, sz, 0); + + if(pdu->N_bytes <= 0) { + mme_connected = false; + do { + s1ap_log->error("Disconnected - attempting reconnection in 10 seconds\n"); + s1ap_log->console("Disconnected - attempting reconnection in 10 seconds\n"); + sleep(10); + } while(running && !connect_mme()); + + if(!setup_s1()) { + s1ap_log->error("S1 setup failed\n"); + s1ap_log->console("S1 setup failed\n"); + running = false; + return; + } + } + + s1ap_log->info_hex(pdu->msg, pdu->N_bytes, "Received S1AP PDU"); + handle_s1ap_rx_pdu(pdu); + } +} + +// Generate common S1AP protocol IEs from config args +void s1ap::build_tai_cgi() +{ + uint32_t plmn; + uint32_t tmp32; + uint16_t tmp16; + + // TAI + tai.ext = false; + tai.iE_Extensions_present = false; + s1ap_mccmnc_to_plmn(args.mcc, args.mnc, &plmn); + tmp32 = htonl(plmn); + tai.pLMNidentity.buffer[0] = ((uint8_t*)&tmp32)[1]; + tai.pLMNidentity.buffer[1] = ((uint8_t*)&tmp32)[2]; + tai.pLMNidentity.buffer[2] = ((uint8_t*)&tmp32)[3]; + tmp16 = htons(args.tac); + memcpy(tai.tAC.buffer, (uint8_t*)&tmp16, 2); + + // EUTRAN_CGI + eutran_cgi.ext = false; + eutran_cgi.iE_Extensions_present = false; + s1ap_mccmnc_to_plmn(args.mcc, args.mnc, &plmn); + tmp32 = htonl(plmn); + eutran_cgi.pLMNidentity.buffer[0] = ((uint8_t*)&tmp32)[1]; + eutran_cgi.pLMNidentity.buffer[1] = ((uint8_t*)&tmp32)[2]; + eutran_cgi.pLMNidentity.buffer[2] = ((uint8_t*)&tmp32)[3]; + + tmp32 = htonl(args.enb_id); + uint8_t enb_id_bits[4*8]; + liblte_unpack((uint8_t*)&tmp32, 4, enb_id_bits); + uint8_t cell_id_bits[1*8]; + liblte_unpack(&args.cell_id, 1, cell_id_bits); + memcpy(eutran_cgi.cell_ID.buffer, &enb_id_bits[32-LIBLTE_S1AP_MACROENB_ID_BIT_STRING_LEN], LIBLTE_S1AP_MACROENB_ID_BIT_STRING_LEN); + memcpy(&eutran_cgi.cell_ID.buffer[LIBLTE_S1AP_MACROENB_ID_BIT_STRING_LEN], cell_id_bits, 8); +} + +/******************************************************************************* +/* RRC interface +********************************************************************************/ +void s1ap::initial_ue(uint16_t rnti, srslte::byte_buffer_t *pdu) +{ + ue_ctxt_map[rnti].eNB_UE_S1AP_ID = next_eNB_UE_S1AP_ID++; + ue_ctxt_map[rnti].stream_id = next_ue_stream_id++; + ue_ctxt_map[rnti].release_requested = false; + enbid_to_rnti_map[ue_ctxt_map[rnti].eNB_UE_S1AP_ID] = rnti; + send_initialuemessage(rnti, pdu, false); +} + +void s1ap::initial_ue(uint16_t rnti, srslte::byte_buffer_t *pdu, uint32_t m_tmsi, uint8_t mmec) +{ + ue_ctxt_map[rnti].eNB_UE_S1AP_ID = next_eNB_UE_S1AP_ID++; + ue_ctxt_map[rnti].stream_id = next_ue_stream_id++; + ue_ctxt_map[rnti].release_requested = false; + enbid_to_rnti_map[ue_ctxt_map[rnti].eNB_UE_S1AP_ID] = rnti; + send_initialuemessage(rnti, pdu, true, m_tmsi, mmec); +} + +void s1ap::write_pdu(uint16_t rnti, srslte::byte_buffer_t *pdu) +{ + s1ap_log->info_hex(pdu->msg, pdu->N_bytes, "Received RRC SDU"); + + if(ue_ctxt_map.end() == ue_ctxt_map.find(rnti)) { + s1ap_log->warning("User RNTI:0x%x context not found\n", rnti); + return; + } + + send_ulnastransport(rnti, pdu); +} + +void s1ap::user_inactivity(uint16_t rnti) +{ + s1ap_log->info("User inactivity - RNTI:0x%x\n", rnti); + + if(ue_ctxt_map.end() == ue_ctxt_map.find(rnti)) { + s1ap_log->warning("User RNTI:0x%x context not found\n", rnti); + return; + } + + if(ue_ctxt_map[rnti].release_requested) { + s1ap_log->warning("UE context for RNTI:0x%x is in zombie state. Releasing...\n", rnti); + ue_ctxt_map.erase(rnti); + rrc->release_complete(rnti); + return; + } + + LIBLTE_S1AP_CAUSE_STRUCT cause; + cause.ext = false; + cause.choice_type = LIBLTE_S1AP_CAUSE_CHOICE_RADIONETWORK; + cause.choice.radioNetwork.ext = false; + cause.choice.radioNetwork.e = LIBLTE_S1AP_CAUSERADIONETWORK_USER_INACTIVITY; + + ue_ctxt_map[rnti].release_requested = true; + send_uectxtreleaserequest(rnti, &cause); +} + + +void s1ap::release_eutran(uint16_t rnti) +{ + s1ap_log->info("Release by EUTRAN - RNTI:0x%x\n", rnti); + + if(ue_ctxt_map.end() == ue_ctxt_map.find(rnti)) { + s1ap_log->warning("User RNTI:0x%x context not found\n", rnti); + return; + } + + if(ue_ctxt_map[rnti].release_requested) { + return; + } + + LIBLTE_S1AP_CAUSE_STRUCT cause; + cause.ext = false; + cause.choice_type = LIBLTE_S1AP_CAUSE_CHOICE_RADIONETWORK; + cause.choice.radioNetwork.ext = false; + cause.choice.radioNetwork.e = LIBLTE_S1AP_CAUSERADIONETWORK_RELEASE_DUE_TO_EUTRAN_GENERATED_REASON; + + ue_ctxt_map[rnti].release_requested = true; + send_uectxtreleaserequest(rnti, &cause); +} + +bool s1ap::user_exists(uint16_t rnti) +{ + return ue_ctxt_map.end() != ue_ctxt_map.find(rnti); +} + +bool s1ap::user_link_lost(uint16_t rnti) +{ + s1ap_log->info("User link lost - RNTI:0x%x\n", rnti); + + if(ue_ctxt_map.end() == ue_ctxt_map.find(rnti)) { + s1ap_log->warning("User RNTI:0x%x context not found\n", rnti); + return false; + } + + if(ue_ctxt_map[rnti].release_requested) { + return false; + } + + LIBLTE_S1AP_CAUSE_STRUCT cause; + cause.ext = false; + cause.choice_type = LIBLTE_S1AP_CAUSE_CHOICE_RADIONETWORK; + cause.choice.radioNetwork.ext = false; + cause.choice.radioNetwork.e = LIBLTE_S1AP_CAUSERADIONETWORK_RADIO_CONNECTION_WITH_UE_LOST; + + ue_ctxt_map[rnti].release_requested = true; + return send_uectxtreleaserequest(rnti, &cause); +} + +void s1ap::ue_ctxt_setup_complete(uint16_t rnti, LIBLTE_S1AP_MESSAGE_INITIALCONTEXTSETUPRESPONSE_STRUCT *res) +{ + if(res->E_RABSetupListCtxtSURes.len > 0) { + send_initial_ctxt_setup_response(rnti, res); + } else { + send_initial_ctxt_setup_failure(rnti); + } +} + +void s1ap::ue_erab_setup_complete(uint16_t rnti, LIBLTE_S1AP_MESSAGE_E_RABSETUPRESPONSE_STRUCT *res) +{ + send_erab_setup_response(rnti, res); +} + +//void ue_capabilities(uint16_t rnti, LIBLTE_RRC_UE_EUTRA_CAPABILITY_STRUCT *caps) +//{ + +//} + +/******************************************************************************* +/* S1AP connection helpers +********************************************************************************/ + +bool s1ap::connect_mme() +{ + socket_fd = 0; + + s1ap_log->info("Connecting to MME %s:%d\n", args.mme_addr.c_str(), MME_PORT); + + if((socket_fd = socket(ADDR_FAMILY, SOCK_TYPE, PROTO)) == -1) { + s1ap_log->error("Failed to create S1AP socket\n"); + return false; + } + + // Bind to the local address + struct sockaddr_in local_addr; + memset(&local_addr, 0, sizeof(struct sockaddr_in)); + local_addr.sin_family = ADDR_FAMILY; + local_addr.sin_port = 0; // Any local port will do + if(inet_pton(AF_INET, args.gtp_bind_addr.c_str(), &(local_addr.sin_addr)) != 1) { + s1ap_log->error("Error converting IP address (%s) to sockaddr_in structure\n", args.gtp_bind_addr.c_str()); + return false; + } + bind(socket_fd, (struct sockaddr *)&local_addr, sizeof(local_addr)); + + // Connect to the MME address + memset(&mme_addr, 0, sizeof(struct sockaddr_in)); + mme_addr.sin_family = ADDR_FAMILY; + mme_addr.sin_port = htons(MME_PORT); + if(inet_pton(AF_INET, args.mme_addr.c_str(), &(mme_addr.sin_addr)) != 1) { + s1ap_log->error("Error converting IP address (%s) to sockaddr_in structure\n", args.mme_addr.c_str()); + return false; + } + + if(connect(socket_fd, (struct sockaddr*)&mme_addr, sizeof(mme_addr)) == -1) { + s1ap_log->error("Failed to establish socket connection to MME\n"); + return false; + } + + s1ap_log->info("SCTP socket established with MME\n"); + return true; +} + +bool s1ap::setup_s1() +{ + uint32_t tmp32; + uint16_t tmp16; + srslte::byte_buffer_t msg; + LIBLTE_S1AP_S1AP_PDU_STRUCT pdu; + + pdu.choice_type = LIBLTE_S1AP_S1AP_PDU_CHOICE_INITIATINGMESSAGE; + + LIBLTE_S1AP_INITIATINGMESSAGE_STRUCT *init = &pdu.choice.initiatingMessage; + + init->procedureCode = LIBLTE_S1AP_PROC_ID_S1SETUP; + init->choice_type = LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_S1SETUPREQUEST; + + LIBLTE_S1AP_MESSAGE_S1SETUPREQUEST_STRUCT *s1setup = &init->choice.S1SetupRequest; + s1setup->ext = false; + s1setup->CSG_IdList_present = false; + + s1setup->Global_ENB_ID.ext = false; + s1setup->Global_ENB_ID.iE_Extensions_present = false; + uint32_t plmn; + s1ap_mccmnc_to_plmn(args.mcc, args.mnc, &plmn); + tmp32 = htonl(plmn); + s1setup->Global_ENB_ID.pLMNidentity.buffer[0] = ((uint8_t*)&tmp32)[1]; + s1setup->Global_ENB_ID.pLMNidentity.buffer[1] = ((uint8_t*)&tmp32)[2]; + s1setup->Global_ENB_ID.pLMNidentity.buffer[2] = ((uint8_t*)&tmp32)[3]; + + s1setup->Global_ENB_ID.ext = false; + s1setup->Global_ENB_ID.eNB_ID.ext = false; + s1setup->Global_ENB_ID.eNB_ID.choice_type = LIBLTE_S1AP_ENB_ID_CHOICE_MACROENB_ID; + tmp32 = htonl(args.enb_id); + uint8_t enb_id_bits[4*8]; + liblte_unpack((uint8_t*)&tmp32, 4, enb_id_bits); + memcpy(s1setup->Global_ENB_ID.eNB_ID.choice.macroENB_ID.buffer, &enb_id_bits[32-LIBLTE_S1AP_MACROENB_ID_BIT_STRING_LEN], LIBLTE_S1AP_MACROENB_ID_BIT_STRING_LEN); + + s1setup->eNBname_present = true; + s1setup->eNBname.ext = false; + if(args.enb_name.length() >= 150) { + args.enb_name.resize(150-1); + } + memcpy(s1setup->eNBname.buffer, args.enb_name.c_str(), args.enb_name.length()); + s1setup->eNBname.n_octets = args.enb_name.length(); + + s1setup->SupportedTAs.len = 1; + s1setup->SupportedTAs.buffer[0].ext = false; + s1setup->SupportedTAs.buffer[0].iE_Extensions_present = false; + tmp16 = htons(args.tac); + memcpy(s1setup->SupportedTAs.buffer[0].tAC.buffer, (uint8_t*)&tmp16, 2); + s1setup->SupportedTAs.buffer[0].broadcastPLMNs.len = 1; + tmp32 = htonl(plmn); + s1setup->SupportedTAs.buffer[0].broadcastPLMNs.buffer[0].buffer[0] = ((uint8_t*)&tmp32)[1]; + s1setup->SupportedTAs.buffer[0].broadcastPLMNs.buffer[0].buffer[1] = ((uint8_t*)&tmp32)[2]; + s1setup->SupportedTAs.buffer[0].broadcastPLMNs.buffer[0].buffer[2] = ((uint8_t*)&tmp32)[3]; + + s1setup->DefaultPagingDRX.ext = false; + s1setup->DefaultPagingDRX.e = LIBLTE_S1AP_PAGINGDRX_V128; // Todo: add to args, config file + + liblte_s1ap_pack_s1ap_pdu(&pdu, (LIBLTE_BYTE_MSG_STRUCT*)&msg); + s1ap_log->info_hex(msg.msg, msg.N_bytes, "Sending s1SetupRequest"); + + ssize_t n_sent = sctp_sendmsg(socket_fd, msg.msg, msg.N_bytes, + (struct sockaddr*)&mme_addr, sizeof(struct sockaddr_in), + htonl(PPID), 0, NONUE_STREAM_ID, 0, 0); + if(n_sent == -1) { + s1ap_log->error("Failed to send s1SetupRequest\n"); + return false; + } + + return true; +} + +/******************************************************************************* +/* S1AP message handlers +********************************************************************************/ + +bool s1ap::handle_s1ap_rx_pdu(srslte::byte_buffer_t *pdu) +{ + LIBLTE_S1AP_S1AP_PDU_STRUCT rx_pdu; + + if(liblte_s1ap_unpack_s1ap_pdu((LIBLTE_BYTE_MSG_STRUCT*)pdu, &rx_pdu) != LIBLTE_SUCCESS) { + s1ap_log->error("Failed to unpack received PDU\n"); + return false; + } + + switch(rx_pdu.choice_type) { + case LIBLTE_S1AP_S1AP_PDU_CHOICE_INITIATINGMESSAGE: + return handle_initiatingmessage(&rx_pdu.choice.initiatingMessage); + break; + case LIBLTE_S1AP_S1AP_PDU_CHOICE_SUCCESSFULOUTCOME: + return handle_successfuloutcome(&rx_pdu.choice.successfulOutcome); + break; + case LIBLTE_S1AP_S1AP_PDU_CHOICE_UNSUCCESSFULOUTCOME: + return handle_unsuccessfuloutcome(&rx_pdu.choice.unsuccessfulOutcome); + break; + default: + s1ap_log->error("Unhandled PDU type %d\n", rx_pdu.choice_type); + return false; + } + + return true; +} + +bool s1ap::handle_initiatingmessage(LIBLTE_S1AP_INITIATINGMESSAGE_STRUCT *msg) +{ + switch(msg->choice_type) { + case LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_DOWNLINKNASTRANSPORT: + return handle_dlnastransport(&msg->choice.DownlinkNASTransport); + case LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_INITIALCONTEXTSETUPREQUEST: + return handle_initialctxtsetuprequest(&msg->choice.InitialContextSetupRequest); + case LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_UECONTEXTRELEASECOMMAND: + return handle_uectxtreleasecommand(&msg->choice.UEContextReleaseCommand); + case LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_PAGING: + return handle_paging(&msg->choice.Paging); + case LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_E_RABSETUPREQUEST: + return handle_erabsetuprequest(&msg->choice.E_RABSetupRequest); + default: + s1ap_log->error("Unhandled intiating message: %s\n", liblte_s1ap_initiatingmessage_choice_text[msg->choice_type]); + } + return true; +} + +bool s1ap::handle_successfuloutcome(LIBLTE_S1AP_SUCCESSFULOUTCOME_STRUCT *msg) +{ + switch(msg->choice_type) { + case LIBLTE_S1AP_SUCCESSFULOUTCOME_CHOICE_S1SETUPRESPONSE: + return handle_s1setupresponse(&msg->choice.S1SetupResponse); + default: + s1ap_log->error("Unhandled successful outcome message: %s\n", liblte_s1ap_successfuloutcome_choice_text[msg->choice_type]); + } + return true; +} + +bool s1ap::handle_unsuccessfuloutcome(LIBLTE_S1AP_UNSUCCESSFULOUTCOME_STRUCT *msg) +{ + switch(msg->choice_type) { + case LIBLTE_S1AP_UNSUCCESSFULOUTCOME_CHOICE_S1SETUPFAILURE: + return handle_s1setupfailure(&msg->choice.S1SetupFailure); + default: + s1ap_log->error("Unhandled unsuccessful outcome message: %s\n", liblte_s1ap_unsuccessfuloutcome_choice_text[msg->choice_type]); + } + return true; +} + +bool s1ap::handle_s1setupresponse(LIBLTE_S1AP_MESSAGE_S1SETUPRESPONSE_STRUCT *msg) +{ + s1ap_log->info("Received S1SetupResponse\n"); + s1setupresponse = *msg; + mme_connected = true; + return true; +} + +bool s1ap::handle_dlnastransport(LIBLTE_S1AP_MESSAGE_DOWNLINKNASTRANSPORT_STRUCT *msg) +{ + s1ap_log->info("Received DownlinkNASTransport\n"); + if(msg->ext) { + s1ap_log->warning("Not handling S1AP message extension\n"); + } + if(enbid_to_rnti_map.end() == enbid_to_rnti_map.find(msg->eNB_UE_S1AP_ID.ENB_UE_S1AP_ID)) { + s1ap_log->warning("eNB_UE_S1AP_ID not found - discarding message\n"); + return false; + } + uint16_t rnti = enbid_to_rnti_map[msg->eNB_UE_S1AP_ID.ENB_UE_S1AP_ID]; + ue_ctxt_map[rnti].MME_UE_S1AP_ID = msg->MME_UE_S1AP_ID.MME_UE_S1AP_ID; + + if(msg->HandoverRestrictionList_present) { + s1ap_log->warning("Not handling HandoverRestrictionList\n"); + } + if(msg->SubscriberProfileIDforRFP_present) { + s1ap_log->warning("Not handling SubscriberProfileIDforRFP\n"); + } + + srslte::byte_buffer_t *pdu = pool_allocate; + memcpy(pdu->msg, msg->NAS_PDU.buffer, msg->NAS_PDU.n_octets); + pdu->N_bytes = msg->NAS_PDU.n_octets; + rrc->write_dl_info(rnti, pdu); + return true; +} + +bool s1ap::handle_initialctxtsetuprequest(LIBLTE_S1AP_MESSAGE_INITIALCONTEXTSETUPREQUEST_STRUCT *msg) +{ + s1ap_log->info("Received InitialContextSetupRequest\n"); + if(msg->ext) { + s1ap_log->warning("Not handling S1AP message extension\n"); + } + if(enbid_to_rnti_map.end() == enbid_to_rnti_map.find(msg->eNB_UE_S1AP_ID.ENB_UE_S1AP_ID)) { + s1ap_log->warning("eNB_UE_S1AP_ID not found - discarding message\n"); + return false; + } + uint16_t rnti = enbid_to_rnti_map[msg->eNB_UE_S1AP_ID.ENB_UE_S1AP_ID]; + if(msg->MME_UE_S1AP_ID.MME_UE_S1AP_ID != ue_ctxt_map[rnti].MME_UE_S1AP_ID) { + s1ap_log->warning("MME_UE_S1AP_ID has changed - old:%d, new:%d\n", + ue_ctxt_map[rnti].MME_UE_S1AP_ID, + msg->MME_UE_S1AP_ID.MME_UE_S1AP_ID); + ue_ctxt_map[rnti].MME_UE_S1AP_ID = msg->MME_UE_S1AP_ID.MME_UE_S1AP_ID; + } + + // Setup UE ctxt in RRC + if(!rrc->setup_ue_ctxt(rnti, msg)) { + return false; + } + + return true; +} + +bool s1ap::handle_paging(LIBLTE_S1AP_MESSAGE_PAGING_STRUCT *msg) +{ + if(msg->ext) { + s1ap_log->warning("Not handling S1AP message extension\n"); + } + uint8_t *ptr = msg->UEIdentityIndexValue.buffer; + uint32_t ueid = srslte_bit_pack(&ptr, 10); + + rrc->add_paging_id(ueid, msg->UEPagingID); + return true; +} + +bool s1ap::handle_erabsetuprequest(LIBLTE_S1AP_MESSAGE_E_RABSETUPREQUEST_STRUCT *msg) +{ + s1ap_log->info("Received ERABSetupRequest\n"); + if(msg->ext) { + s1ap_log->warning("Not handling S1AP message extension\n"); + } + + if(enbid_to_rnti_map.end() == enbid_to_rnti_map.find(msg->eNB_UE_S1AP_ID.ENB_UE_S1AP_ID)) { + s1ap_log->warning("eNB_UE_S1AP_ID not found - discarding message\n"); + return false; + } + uint16_t rnti = enbid_to_rnti_map[msg->eNB_UE_S1AP_ID.ENB_UE_S1AP_ID]; + if(msg->MME_UE_S1AP_ID.MME_UE_S1AP_ID != ue_ctxt_map[rnti].MME_UE_S1AP_ID) { + s1ap_log->warning("MME_UE_S1AP_ID has changed - old:%d, new:%d\n", + ue_ctxt_map[rnti].MME_UE_S1AP_ID, + msg->MME_UE_S1AP_ID.MME_UE_S1AP_ID); + ue_ctxt_map[rnti].MME_UE_S1AP_ID = msg->MME_UE_S1AP_ID.MME_UE_S1AP_ID; + } + + // Setup UE ctxt in RRC + if(!rrc->setup_ue_erabs(rnti, msg)) { + return false; + } + + return true; +} + +bool s1ap::handle_uectxtreleasecommand(LIBLTE_S1AP_MESSAGE_UECONTEXTRELEASECOMMAND_STRUCT *msg) +{ + s1ap_log->info("Received UEContextReleaseCommand\n"); + if(msg->ext) { + s1ap_log->warning("Not handling S1AP message extension\n"); + } + if(msg->UE_S1AP_IDs.ext) { + s1ap_log->warning("Not handling S1AP message extension\n"); + } + + uint16_t rnti; + if(msg->UE_S1AP_IDs.choice_type == LIBLTE_S1AP_UE_S1AP_IDS_CHOICE_UE_S1AP_ID_PAIR) { + + if(msg->UE_S1AP_IDs.choice.uE_S1AP_ID_pair.ext) { + s1ap_log->warning("Not handling S1AP message extension\n"); + } + if(msg->UE_S1AP_IDs.choice.uE_S1AP_ID_pair.iE_Extensions_present) { + s1ap_log->warning("Not handling S1AP message iE_Extensions\n"); + } + uint32_t enb_ue_id = msg->UE_S1AP_IDs.choice.uE_S1AP_ID_pair.eNB_UE_S1AP_ID.ENB_UE_S1AP_ID; + if(enbid_to_rnti_map.end() == enbid_to_rnti_map.find(enb_ue_id)) { + s1ap_log->warning("eNB_UE_S1AP_ID:%d not found - discarding message\n", enb_ue_id); + return false; + } + rnti = enbid_to_rnti_map[enb_ue_id]; + enbid_to_rnti_map.erase(enb_ue_id); + + } else { // LIBLTE_S1AP_UE_S1AP_IDS_CHOICE_MME_UE_S1AP_ID + + uint32_t mme_ue_id = msg->UE_S1AP_IDs.choice.mME_UE_S1AP_ID.MME_UE_S1AP_ID; + uint32_t enb_ue_id; + if(!find_mme_ue_id(mme_ue_id, &rnti, &enb_ue_id)) { + s1ap_log->warning("UE for MME_UE_S1AP_ID:%d not found - discarding message\n", mme_ue_id); + return false; + } + enbid_to_rnti_map.erase(enb_ue_id); + } + + if(ue_ctxt_map.end() == ue_ctxt_map.find(rnti)) { + s1ap_log->warning("UE context for RNTI:0x%x not found - discarding message\n", rnti); + return false; + } + + rrc->release_erabs(rnti); + send_uectxtreleasecomplete(rnti, ue_ctxt_map[rnti].MME_UE_S1AP_ID, ue_ctxt_map[rnti].eNB_UE_S1AP_ID); + ue_ctxt_map.erase(rnti); + s1ap_log->info("UE context for RNTI:0x%x released\n", rnti); + rrc->release_complete(rnti); + return true; +} + +bool s1ap::handle_s1setupfailure(LIBLTE_S1AP_MESSAGE_S1SETUPFAILURE_STRUCT *msg) { + std::string cause = get_cause(&msg->Cause); + s1ap_log->error("S1 Setup Failure. Cause: %s\n", cause.c_str()); + s1ap_log->console("S1 Setup Failure. Cause: %s\n", cause.c_str()); + return true; +} + +/******************************************************************************* +/* S1AP message senders +********************************************************************************/ + +bool s1ap::send_initialuemessage(uint16_t rnti, srslte::byte_buffer_t *pdu, bool has_tmsi, uint32_t m_tmsi, uint8_t mmec) +{ + if(!mme_connected) { + return false; + } + srslte::byte_buffer_t msg; + + LIBLTE_S1AP_S1AP_PDU_STRUCT tx_pdu; + tx_pdu.ext = false; + tx_pdu.choice_type = LIBLTE_S1AP_S1AP_PDU_CHOICE_INITIATINGMESSAGE; + + LIBLTE_S1AP_INITIATINGMESSAGE_STRUCT *init = &tx_pdu.choice.initiatingMessage; + init->procedureCode = LIBLTE_S1AP_PROC_ID_INITIALUEMESSAGE; + init->choice_type = LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_INITIALUEMESSAGE; + + LIBLTE_S1AP_MESSAGE_INITIALUEMESSAGE_STRUCT *initue = &init->choice.InitialUEMessage; + initue->ext = false; + initue->CellAccessMode_present = false; + initue->CSG_Id_present = false; + initue->GUMMEIType_present = false; + initue->GUMMEI_ID_present = false; + initue->GW_TransportLayerAddress_present = false; + initue->LHN_ID_present = false; + initue->RelayNode_Indicator_present = false; + initue->SIPTO_L_GW_TransportLayerAddress_present = false; + initue->S_TMSI_present = false; + initue->Tunnel_Information_for_BBF_present = false; + + // S_TMSI + if(has_tmsi) { + initue->S_TMSI_present = true; + initue->S_TMSI.ext = false; + initue->S_TMSI.iE_Extensions_present = false; + + uint32_to_uint8(m_tmsi, initue->S_TMSI.m_TMSI.buffer); + initue->S_TMSI.mMEC.buffer[0] = mmec; + } + + // ENB_UE_S1AP_ID + initue->eNB_UE_S1AP_ID.ENB_UE_S1AP_ID = ue_ctxt_map[rnti].eNB_UE_S1AP_ID; + + // NAS_PDU + memcpy(initue->NAS_PDU.buffer, pdu->msg, pdu->N_bytes); + initue->NAS_PDU.n_octets = pdu->N_bytes; + + // TAI + memcpy(&initue->TAI, &tai, sizeof(LIBLTE_S1AP_TAI_STRUCT)); + + // EUTRAN_CGI + memcpy(&initue->EUTRAN_CGI, &eutran_cgi, sizeof(LIBLTE_S1AP_EUTRAN_CGI_STRUCT)); + + // RRC Establishment Cause + initue->RRC_Establishment_Cause.ext = false; + initue->RRC_Establishment_Cause.e = LIBLTE_S1AP_RRC_ESTABLISHMENT_CAUSE_MO_SIGNALLING; + + liblte_s1ap_pack_s1ap_pdu(&tx_pdu, (LIBLTE_BYTE_MSG_STRUCT*)&msg); + s1ap_log->info_hex(msg.msg, msg.N_bytes, "Sending InitialUEMessage for RNTI:0x%x", rnti); + + ssize_t n_sent = sctp_sendmsg(socket_fd, msg.msg, msg.N_bytes, + (struct sockaddr*)&mme_addr, sizeof(struct sockaddr_in), + htonl(PPID), 0, ue_ctxt_map[rnti].stream_id, 0, 0); + if(n_sent == -1) { + s1ap_log->error("Failed to send InitialUEMessage for RNTI:0x%x\n", rnti); + return false; + } + + return true; +} + +bool s1ap::send_ulnastransport(uint16_t rnti, srslte::byte_buffer_t *pdu) +{ + if(!mme_connected) { + return false; + } + srslte::byte_buffer_t msg; + + LIBLTE_S1AP_S1AP_PDU_STRUCT tx_pdu; + tx_pdu.ext = false; + tx_pdu.choice_type = LIBLTE_S1AP_S1AP_PDU_CHOICE_INITIATINGMESSAGE; + + LIBLTE_S1AP_INITIATINGMESSAGE_STRUCT *init = &tx_pdu.choice.initiatingMessage; + init->procedureCode = LIBLTE_S1AP_PROC_ID_UPLINKNASTRANSPORT; + init->choice_type = LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_UPLINKNASTRANSPORT; + + LIBLTE_S1AP_MESSAGE_UPLINKNASTRANSPORT_STRUCT *ultx = &init->choice.UplinkNASTransport; + ultx->ext = false; + ultx->GW_TransportLayerAddress_present = false; + ultx->LHN_ID_present = false; + ultx->SIPTO_L_GW_TransportLayerAddress_present = false; + + // MME_UE_S1AP_ID + ultx->MME_UE_S1AP_ID.MME_UE_S1AP_ID = ue_ctxt_map[rnti].MME_UE_S1AP_ID; + // ENB_UE_S1AP_ID + ultx->eNB_UE_S1AP_ID.ENB_UE_S1AP_ID = ue_ctxt_map[rnti].eNB_UE_S1AP_ID; + + // NAS_PDU + memcpy(ultx->NAS_PDU.buffer, pdu->msg, pdu->N_bytes); + ultx->NAS_PDU.n_octets = pdu->N_bytes; + + // EUTRAN_CGI + memcpy(&ultx->EUTRAN_CGI, &eutran_cgi, sizeof(LIBLTE_S1AP_EUTRAN_CGI_STRUCT)); + + // TAI + memcpy(&ultx->TAI, &tai, sizeof(LIBLTE_S1AP_TAI_STRUCT)); + + liblte_s1ap_pack_s1ap_pdu(&tx_pdu, (LIBLTE_BYTE_MSG_STRUCT*)&msg); + s1ap_log->info_hex(msg.msg, msg.N_bytes, "Sending UplinkNASTransport for RNTI:0x%x", rnti); + + ssize_t n_sent = sctp_sendmsg(socket_fd, msg.msg, msg.N_bytes, + (struct sockaddr*)&mme_addr, sizeof(struct sockaddr_in), + htonl(PPID), 0, ue_ctxt_map[rnti].stream_id, 0, 0); + if(n_sent == -1) { + s1ap_log->error("Failed to send UplinkNASTransport for RNTI:0x%x\n", rnti); + return false; + } + + return true; +} + +bool s1ap::send_uectxtreleaserequest(uint16_t rnti, LIBLTE_S1AP_CAUSE_STRUCT *cause) +{ + if(!mme_connected) { + return false; + } + srslte::byte_buffer_t msg; + + LIBLTE_S1AP_S1AP_PDU_STRUCT tx_pdu; + tx_pdu.ext = false; + tx_pdu.choice_type = LIBLTE_S1AP_S1AP_PDU_CHOICE_INITIATINGMESSAGE; + + LIBLTE_S1AP_INITIATINGMESSAGE_STRUCT *init = &tx_pdu.choice.initiatingMessage; + init->procedureCode = LIBLTE_S1AP_PROC_ID_UECONTEXTRELEASEREQUEST; + init->choice_type = LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_UECONTEXTRELEASEREQUEST; + + LIBLTE_S1AP_MESSAGE_UECONTEXTRELEASEREQUEST_STRUCT *req = &init->choice.UEContextReleaseRequest; + req->ext = false; + req->GWContextReleaseIndication_present = false; + + // MME_UE_S1AP_ID + req->MME_UE_S1AP_ID.MME_UE_S1AP_ID = ue_ctxt_map[rnti].MME_UE_S1AP_ID; + // ENB_UE_S1AP_ID + req->eNB_UE_S1AP_ID.ENB_UE_S1AP_ID = ue_ctxt_map[rnti].eNB_UE_S1AP_ID; + + // Cause + memcpy(&req->Cause, cause, sizeof(LIBLTE_S1AP_CAUSE_STRUCT)); + + liblte_s1ap_pack_s1ap_pdu(&tx_pdu, (LIBLTE_BYTE_MSG_STRUCT*)&msg); + s1ap_log->info_hex(msg.msg, msg.N_bytes, "Sending UEContextReleaseRequest for RNTI:0x%x", rnti); + + ssize_t n_sent = sctp_sendmsg(socket_fd, msg.msg, msg.N_bytes, + (struct sockaddr*)&mme_addr, sizeof(struct sockaddr_in), + htonl(PPID), 0, ue_ctxt_map[rnti].stream_id, 0, 0); + if(n_sent == -1) { + s1ap_log->error("Failed to send UEContextReleaseRequest for RNTI:0x%x\n", rnti); + return false; + } + + return true; +} + +bool s1ap::send_uectxtreleasecomplete(uint16_t rnti, uint32_t mme_ue_id, uint32_t enb_ue_id) +{ + if(!mme_connected) { + return false; + } + srslte::byte_buffer_t msg; + + LIBLTE_S1AP_S1AP_PDU_STRUCT tx_pdu; + tx_pdu.ext = false; + tx_pdu.choice_type = LIBLTE_S1AP_S1AP_PDU_CHOICE_SUCCESSFULOUTCOME; + + LIBLTE_S1AP_SUCCESSFULOUTCOME_STRUCT *succ = &tx_pdu.choice.successfulOutcome; + succ->procedureCode = LIBLTE_S1AP_PROC_ID_UECONTEXTRELEASE; + succ->choice_type = LIBLTE_S1AP_SUCCESSFULOUTCOME_CHOICE_UECONTEXTRELEASECOMPLETE; + + LIBLTE_S1AP_MESSAGE_UECONTEXTRELEASECOMPLETE_STRUCT *comp = &succ->choice.UEContextReleaseComplete; + comp->ext = false; + comp->CriticalityDiagnostics_present = false; + comp->UserLocationInformation_present = false; + + comp->eNB_UE_S1AP_ID.ENB_UE_S1AP_ID = enb_ue_id; + comp->MME_UE_S1AP_ID.MME_UE_S1AP_ID = mme_ue_id; + + liblte_s1ap_pack_s1ap_pdu(&tx_pdu, (LIBLTE_BYTE_MSG_STRUCT*)&msg); + s1ap_log->info_hex(msg.msg, msg.N_bytes, "Sending UEContextReleaseComplete for RNTI:0x%x", rnti); + + ssize_t n_sent = sctp_sendmsg(socket_fd, msg.msg, msg.N_bytes, + (struct sockaddr*)&mme_addr, sizeof(struct sockaddr_in), + htonl(PPID), 0, ue_ctxt_map[rnti].stream_id, 0, 0); + if(n_sent == -1) { + s1ap_log->error("Failed to send UEContextReleaseComplete for RNTI:0x%x\n", rnti); + return false; + } + + return true; +} + +bool s1ap::send_initial_ctxt_setup_response(uint16_t rnti, LIBLTE_S1AP_MESSAGE_INITIALCONTEXTSETUPRESPONSE_STRUCT *res_) +{ + if(!mme_connected) { + return false; + } + srslte::byte_buffer_t *buf = pool_allocate; + LIBLTE_S1AP_S1AP_PDU_STRUCT tx_pdu; + + tx_pdu.ext = false; + tx_pdu.choice_type = LIBLTE_S1AP_S1AP_PDU_CHOICE_SUCCESSFULOUTCOME; + + LIBLTE_S1AP_SUCCESSFULOUTCOME_STRUCT *succ = &tx_pdu.choice.successfulOutcome; + succ->procedureCode = LIBLTE_S1AP_PROC_ID_INITIALCONTEXTSETUP; + succ->choice_type = LIBLTE_S1AP_SUCCESSFULOUTCOME_CHOICE_INITIALCONTEXTSETUPRESPONSE; + + // Copy in the provided response message + LIBLTE_S1AP_MESSAGE_INITIALCONTEXTSETUPRESPONSE_STRUCT *res = &succ->choice.InitialContextSetupResponse; + memcpy(res, res_, sizeof(LIBLTE_S1AP_MESSAGE_INITIALCONTEXTSETUPRESPONSE_STRUCT)); + + // Fill in the GTP bind address for all bearers + for(uint32_t i=0;iE_RABSetupListCtxtSURes.len; i++) { + uint8_t addr[4]; + inet_pton(AF_INET, args.gtp_bind_addr.c_str(), addr); + liblte_unpack(addr, 4, res->E_RABSetupListCtxtSURes.buffer[i].transportLayerAddress.buffer); + res->E_RABSetupListCtxtSURes.buffer[i].transportLayerAddress.n_bits = 32; + res->E_RABSetupListCtxtSURes.buffer[i].transportLayerAddress.ext = false; + } + + // Fill in the MME and eNB IDs + res->MME_UE_S1AP_ID.MME_UE_S1AP_ID = ue_ctxt_map[rnti].MME_UE_S1AP_ID; + res->eNB_UE_S1AP_ID.ENB_UE_S1AP_ID = ue_ctxt_map[rnti].eNB_UE_S1AP_ID; + + liblte_s1ap_pack_s1ap_pdu(&tx_pdu, (LIBLTE_BYTE_MSG_STRUCT*)buf); + s1ap_log->info_hex(buf->msg, buf->N_bytes, "Sending InitialContextSetupResponse for RNTI:0x%x", rnti); + + ssize_t n_sent = sctp_sendmsg(socket_fd, buf->msg, buf->N_bytes, + (struct sockaddr*)&mme_addr, sizeof(struct sockaddr_in), + htonl(PPID), 0, ue_ctxt_map[rnti].stream_id, 0, 0); + if(n_sent == -1) { + s1ap_log->error("Failed to send InitialContextSetupResponse for RNTI:0x%x\n", rnti); + return false; + } + + return true; +} + +bool s1ap::send_erab_setup_response(uint16_t rnti, LIBLTE_S1AP_MESSAGE_E_RABSETUPRESPONSE_STRUCT *res_) +{ + if(!mme_connected) { + return false; + } + srslte::byte_buffer_t *buf = pool_allocate; + LIBLTE_S1AP_S1AP_PDU_STRUCT tx_pdu; + + tx_pdu.ext = false; + tx_pdu.choice_type = LIBLTE_S1AP_S1AP_PDU_CHOICE_SUCCESSFULOUTCOME; + + LIBLTE_S1AP_SUCCESSFULOUTCOME_STRUCT *succ = &tx_pdu.choice.successfulOutcome; + succ->procedureCode = LIBLTE_S1AP_PROC_ID_E_RABSETUP; + succ->choice_type = LIBLTE_S1AP_SUCCESSFULOUTCOME_CHOICE_E_RABSETUPRESPONSE; + + // Copy in the provided response message + LIBLTE_S1AP_MESSAGE_E_RABSETUPRESPONSE_STRUCT *res = &succ->choice.E_RABSetupResponse; + memcpy(res, res_, sizeof(LIBLTE_S1AP_MESSAGE_E_RABSETUPRESPONSE_STRUCT)); + + // Fill in the GTP bind address for all bearers + for(uint32_t i=0;iE_RABSetupListBearerSURes.len; i++) { + uint8_t addr[4]; + inet_pton(AF_INET, args.gtp_bind_addr.c_str(), addr); + liblte_unpack(addr, 4, res->E_RABSetupListBearerSURes.buffer[i].transportLayerAddress.buffer); + res->E_RABSetupListBearerSURes.buffer[i].transportLayerAddress.n_bits = 32; + res->E_RABSetupListBearerSURes.buffer[i].transportLayerAddress.ext = false; + } + + // Fill in the MME and eNB IDs + res->MME_UE_S1AP_ID.MME_UE_S1AP_ID = ue_ctxt_map[rnti].MME_UE_S1AP_ID; + res->eNB_UE_S1AP_ID.ENB_UE_S1AP_ID = ue_ctxt_map[rnti].eNB_UE_S1AP_ID; + + liblte_s1ap_pack_s1ap_pdu(&tx_pdu, (LIBLTE_BYTE_MSG_STRUCT*)buf); + s1ap_log->info_hex(buf->msg, buf->N_bytes, "Sending E_RABSetupResponse for RNTI:0x%x", rnti); + + ssize_t n_sent = sctp_sendmsg(socket_fd, buf->msg, buf->N_bytes, + (struct sockaddr*)&mme_addr, sizeof(struct sockaddr_in), + htonl(PPID), 0, ue_ctxt_map[rnti].stream_id, 0, 0); + if(n_sent == -1) { + s1ap_log->error("Failed to send E_RABSetupResponse for RNTI:0x%x\n", rnti); + return false; + } + + return true; +} + +bool s1ap::send_initial_ctxt_setup_failure(uint16_t rnti) +{ + if(!mme_connected) { + return false; + } + srslte::byte_buffer_t *buf = pool_allocate; + LIBLTE_S1AP_S1AP_PDU_STRUCT tx_pdu; + tx_pdu.ext = false; + tx_pdu.choice_type = LIBLTE_S1AP_S1AP_PDU_CHOICE_UNSUCCESSFULOUTCOME; + + LIBLTE_S1AP_UNSUCCESSFULOUTCOME_STRUCT *unsucc = &tx_pdu.choice.unsuccessfulOutcome; + unsucc->procedureCode = LIBLTE_S1AP_PROC_ID_INITIALCONTEXTSETUP; + unsucc->choice_type = LIBLTE_S1AP_UNSUCCESSFULOUTCOME_CHOICE_INITIALCONTEXTSETUPFAILURE; + + LIBLTE_S1AP_MESSAGE_INITIALCONTEXTSETUPFAILURE_STRUCT *fail = &unsucc->choice.InitialContextSetupFailure; + fail->ext = false; + fail->CriticalityDiagnostics_present = false; + + fail->MME_UE_S1AP_ID.MME_UE_S1AP_ID = ue_ctxt_map[rnti].MME_UE_S1AP_ID; + fail->eNB_UE_S1AP_ID.ENB_UE_S1AP_ID = ue_ctxt_map[rnti].eNB_UE_S1AP_ID; + + fail->Cause.ext = false; + fail->Cause.choice_type = LIBLTE_S1AP_CAUSE_CHOICE_RADIONETWORK; + fail->Cause.choice.radioNetwork.ext = false; + fail->Cause.choice.radioNetwork.e = LIBLTE_S1AP_CAUSERADIONETWORK_UNSPECIFIED; + + liblte_s1ap_pack_s1ap_pdu(&tx_pdu, (LIBLTE_BYTE_MSG_STRUCT*)&buf); + s1ap_log->info_hex(buf->msg, buf->N_bytes, "Sending InitialContextSetupFailure for RNTI:0x%x", rnti); + + ssize_t n_sent = sctp_sendmsg(socket_fd, buf->msg, buf->N_bytes, + (struct sockaddr*)&mme_addr, sizeof(struct sockaddr_in), + htonl(PPID), 0, ue_ctxt_map[rnti].stream_id, 0, 0); + if(n_sent == -1) { + s1ap_log->error("Failed to send UplinkNASTransport for RNTI:0x%x\n", rnti); + return false; + } + + return true; +} + + +//bool s1ap::send_ue_capabilities(uint16_t rnti, LIBLTE_RRC_UE_EUTRA_CAPABILITY_STRUCT *caps) +//{ +// srslte::byte_buffer_t msg; + +// LIBLTE_S1AP_S1AP_PDU_STRUCT tx_pdu; +// tx_pdu.ext = false; +// tx_pdu.choice_type = LIBLTE_S1AP_S1AP_PDU_CHOICE_INITIATINGMESSAGE; + +// LIBLTE_S1AP_INITIATINGMESSAGE_STRUCT *init = &tx_pdu.choice.initiatingMessage; +// init->procedureCode = LIBLTE_S1AP_PROC_ID_UPLINKNASTRANSPORT; +// init->choice_type = LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_UECAPABILITYINFOINDICATION; + +// LIBLTE_S1AP_MESSAGE_UECAPABILITYINFOINDICATION_STRUCT *caps = &init->choice.UECapabilityInfoIndication; +// caps->ext = false; +// caps->MME_UE_S1AP_ID.MME_UE_S1AP_ID = ue_ctxt_map[rnti].MME_UE_S1AP_ID; +// caps->eNB_UE_S1AP_ID.ENB_UE_S1AP_ID = ue_ctxt_map[rnti].eNB_UE_S1AP_ID; +// // TODO: caps->UERadioCapability. + +// liblte_s1ap_pack_s1ap_pdu(&tx_pdu, (LIBLTE_BYTE_MSG_STRUCT*)&msg); +// s1ap_log->info_hex(msg.msg, msg.N_bytes, "Sending UERadioCapabilityInfo for RNTI:0x%x", rnti); + +// ssize_t n_sent = sctp_sendmsg(socket_fd, msg.msg, msg.N_bytes, +// (struct sockaddr*)&mme_addr, sizeof(struct sockaddr_in), +// htonl(PPID), 0, ue_ctxt_map[rnti].stream_id, 0, 0); +// if(n_sent == -1) { +// s1ap_log->error("Failed to send UplinkNASTransport for RNTI:0x%x\n", rnti); +// return false; +// } + +// return true; +//} + +/******************************************************************************* +/* General helpers +********************************************************************************/ + +bool s1ap::find_mme_ue_id(uint32_t mme_ue_id, uint16_t *rnti, uint32_t *enb_ue_id) +{ + typedef std::map::iterator it_t; + for(it_t it=ue_ctxt_map.begin(); it!=ue_ctxt_map.end(); ++it) { + if(it->second.MME_UE_S1AP_ID == mme_ue_id) { + *rnti = it->second.rnti; + *enb_ue_id = it->second.eNB_UE_S1AP_ID; + return true; + } + } + return false; +} + +std::string s1ap::get_cause(LIBLTE_S1AP_CAUSE_STRUCT *c) +{ + std::string cause = liblte_s1ap_cause_choice_text[c->choice_type]; + cause += " - "; + switch(c->choice_type) { + case LIBLTE_S1AP_CAUSE_CHOICE_RADIONETWORK: + cause += liblte_s1ap_causeradionetwork_text[c->choice.radioNetwork.e]; + break; + case LIBLTE_S1AP_CAUSE_CHOICE_TRANSPORT: + cause += liblte_s1ap_causetransport_text[c->choice.transport.e]; + break; + case LIBLTE_S1AP_CAUSE_CHOICE_NAS: + cause += liblte_s1ap_causenas_text[c->choice.nas.e]; + break; + case LIBLTE_S1AP_CAUSE_CHOICE_PROTOCOL: + cause += liblte_s1ap_causeprotocol_text[c->choice.protocol.e]; + break; + case LIBLTE_S1AP_CAUSE_CHOICE_MISC: + cause += liblte_s1ap_causemisc_text[c->choice.misc.e]; + break; + default: + cause += "unkown"; + break; + } + return cause; +} + +} // namespace srsenb diff --git a/srsenb/test/CMakeLists.txt b/srsenb/test/CMakeLists.txt new file mode 100644 index 000000000..6a86702b2 --- /dev/null +++ b/srsenb/test/CMakeLists.txt @@ -0,0 +1,3 @@ + +add_subdirectory(mac) +add_subdirectory(upper) \ No newline at end of file diff --git a/srsenb/test/mac/CMakeLists.txt b/srsenb/test/mac/CMakeLists.txt new file mode 100644 index 000000000..9048b4e59 --- /dev/null +++ b/srsenb/test/mac/CMakeLists.txt @@ -0,0 +1,9 @@ + +# Scheduler test +add_executable(scheduler_test scheduler_test.cc) +target_link_libraries(scheduler_test srsenb_mac + srsenb_phy + srslte_common + srslte_phy + ${CMAKE_THREAD_LIBS_INIT} + ${Boost_LIBRARIES}) diff --git a/srsenb/test/mac/scheduler_test.cc b/srsenb/test/mac/scheduler_test.cc new file mode 100644 index 000000000..53bb28e18 --- /dev/null +++ b/srsenb/test/mac/scheduler_test.cc @@ -0,0 +1,136 @@ + +#include + +#include "mac/mac.h" +#include "phy/phy.h" + +#include "srslte/interfaces/enb_interfaces.h" +#include "srslte/interfaces/sched_interface.h" +#include "srslte/common/log_stdout.h" +#include "srslte/radio/radio.h" +#include "srslte/phy/utils/debug.h" + + + + +uint8_t sib1_payload[18] = {0x60,0x40,0x04,0x03,0x00,0x01,0x1a,0x2d,0x00,0x18,0x02,0x81,0x80,0x42,0x0c,0x80,0x00,0x00}; +uint8_t sib2_payload[41] = {0x00,0x80,0x1c,0x31,0x18,0x6f,0xe1,0x20,0x00,0x35,0x84,0x8c, + 0xe2,0xd0,0x00,0x02,0x00,0x78,0xee,0x31,0x6a,0xa5,0x37,0x30, + 0xa0,0x70,0xc9,0x49,0xfa,0x8d,0xd2,0x78,0x1a,0x02,0x77,0x4a, + 0x92,0x40,0x00,0x00,0x00}; + +// Define dummy RLC always transmitts +class rlc : public srsenb::rlc_interface_mac +{ +public: + uint32_t get_buffer_state(uint16_t rnti, uint32_t lcid) + { + return 1; + } + + int read_pdu(uint16_t rnti, uint32_t lcid, uint8_t *payload, uint32_t nof_bytes) + { + for (uint32_t i=0;i 50) { + running = false; + } + my_sched.dl_sched(tti, &sched_result_dl); + my_sched.ul_sched(tti, &sched_result_ul); + tti = (tti+1)%10240; + if (tti >= 4) { + my_sched.ul_crc_info(tti, rnti, tti%2); + } + } + + +} diff --git a/srsenb/test/upper/CMakeLists.txt b/srsenb/test/upper/CMakeLists.txt new file mode 100644 index 000000000..243da5cdf --- /dev/null +++ b/srsenb/test/upper/CMakeLists.txt @@ -0,0 +1,17 @@ +# IP tx/rx program test +add_executable(ip_test_enb ip_test.cc) +target_link_libraries(ip_test_enb srsenb_upper + srsenb_mac + srsenb_phy + srslte_common + srslte_phy + srslte_upper + srslte_radio + ${CMAKE_THREAD_LIBS_INIT} + ${Boost_LIBRARIES} + ${SEC_LIBRARIES}) + +# Simple PLMN -> MCC/MNC test +add_executable(plmn_test plmn_test.cc) +target_link_libraries(plmn_test srsenb_upper srslte_asn1 ) + diff --git a/srsenb/test/upper/ip_test.cc b/srsenb/test/upper/ip_test.cc new file mode 100644 index 000000000..f2ec84f64 --- /dev/null +++ b/srsenb/test/upper/ip_test.cc @@ -0,0 +1,646 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mac/mac.h" +#include "phy/phy.h" +#include "srslte/common/threads.h" +#include "srslte/interfaces/enb_interfaces.h" +#include "srslte/common/common.h" +#include "srslte/common/buffer_pool.h" +#include "srslte/common/logger.h" +#include "srslte/common/log_filter.h" +#include "srslte/upper/rlc.h" +#include "srslte/radio/radio.h" +#include "srslte/phy/utils/debug.h" + +#define START_TUNTAP +#define USE_RADIO + +/********************************************************************** + * Program arguments processing + ***********************************************************************/ + +#define LCID 3 + +typedef struct { + float rx_freq; + float tx_freq; + float rx_gain; + float tx_gain; + bool enable_gui; + int time_adv; + std::string ip_address; +}prog_args_t; + +uint32_t srsapps_verbose = 1; + +prog_args_t prog_args; + +void args_default(prog_args_t *args) { + args->rx_freq = 2.505e9; + args->tx_freq = 2.625e9; + args->rx_gain = 50.0; + args->tx_gain = 70.0; + args->enable_gui = false; + args->time_adv = -1; // calibrated for b210 + args->ip_address = "192.168.3.1"; +} + +void usage(prog_args_t *args, char *prog) { + printf("Usage: %s [gGIrfFdv] \n", prog); + printf("\t-f RX frequency [Default %.1f MHz]\n", args->rx_freq/1e6); + printf("\t-F TX frequency [Default %.1f MHz]\n", args->tx_freq/1e6); + printf("\t-g RX gain [Default %.1f]\n", args->rx_gain); + printf("\t-G TX gain [Default %.1f]\n", args->tx_gain); + printf("\t-I IP address [Default %s]\n", args->ip_address.c_str()); + printf("\t-t time advance (in samples) [Default %d]\n", args->time_adv); + printf("\t-d Enable gui [Default disabled]\n"); + printf("\t-v [increase verbosity, default none]\n"); +} + +void parse_args(prog_args_t *args, int argc, char **argv) { + int opt; + args_default(args); + while ((opt = getopt(argc, argv, "gGfFItdv")) != -1) { + switch (opt) { + case 'd': + args->enable_gui = true; + break; + case 'g': + args->rx_gain = atof(argv[optind]); + break; + case 'G': + args->tx_gain = atof(argv[optind]); + break; + case 'f': + args->rx_freq = atof(argv[optind]); + break; + case 'F': + args->tx_freq = atof(argv[optind]); + break; + case 'I': + args->ip_address = argv[optind]; + break; + case 't': + args->time_adv = atoi(argv[optind]); + break; + case 'v': + srsapps_verbose++; + break; + default: + usage(args, argv[0]); + exit(-1); + } + } + if (args->rx_freq < 0 || args->tx_freq < 0) { + usage(args, argv[0]); + exit(-1); + } +} + +LIBLTE_BYTE_MSG_STRUCT sib_buffer[2]; + +int setup_if_addr(char *ip_addr); + +class tester : public srsue::pdcp_interface_rlc, + public srsue::rrc_interface_rlc, + public srsue::ue_interface, + public srsenb::rlc_interface_mac, + public srsenb::rrc_interface_mac, + public thread +{ +public: + + tester() { + rnti = 0; + } + + void init(srslte::rlc *rlc_, srsenb::mac *mac_, srsenb::phy *phy_, srslte::log *log_h_, std::string ip_address) { + log_h = log_h_; + rlc = rlc_; + mac = mac_; + phy = phy_; + + tun_fd = 0; + +#ifdef START_TUNTAP + if (init_tuntap((char*) ip_address.c_str())) { + log_h->error("Initiating IP address\n"); + } +#endif + + pool = srslte::byte_buffer_pool::get_instance(); + + // Start reader thread + running=true; + start(); + } + + void write_pdu_bcch_bch(srslte::byte_buffer_t *sdu) {} + void write_pdu_bcch_dlsch(srslte::byte_buffer_t *sdu) {} + void write_pdu_pcch(srslte::byte_buffer_t *sdu) {} + void max_retx_attempted(){} + void add_user(uint16_t rnti) {} + void release_user(uint16_t rnti) {} + void upd_user(uint16_t rnti, uint16_t old_rnti) {} + void set_activity_user(uint16_t rnti) {} + bool is_paging_opportunity(uint32_t tti, uint32_t *payload_len) {return false;} + void read_pdu_pcch(uint8_t* payload, uint32_t buffer_size) {} + + void write_pdu(uint32_t lcid, srslte::byte_buffer_t *sdu) + { + int n = write(tun_fd, sdu->msg, sdu->N_bytes); + if (n != (int) sdu->N_bytes) { + log_h->error("TUN/TAP write failure n=%d, nof_bytes=%d\n", n, sdu->N_bytes); + return; + } + log_h->debug_hex(sdu->msg, sdu->N_bytes, + "Wrote %d bytes to TUN/TAP\n", + sdu->N_bytes); + pool->deallocate(sdu); + } + + int read_pdu(uint16_t rnti, uint32_t lcid, uint8_t *payload, uint32_t nof_bytes) + { + return rlc->read_pdu(lcid, payload, nof_bytes); + } + + void read_pdu_bcch_dlsch(uint32_t sib_index, uint8_t payload[srsenb::sched_interface::MAX_SIB_PAYLOAD_LEN]) + { + if (sib_index < 2) { + memcpy(payload, sib_buffer[sib_index].msg, sib_buffer[sib_index].N_bytes); + } + } + + void write_pdu(uint16_t rnti, uint32_t lcid, uint8_t *payload, uint32_t nof_bytes) + { + srslte::byte_buffer_t *sdu = NULL; + log_h->info("Received PDU rnti=0x%x, lcid=%d, nof_bytes=%d\n", rnti, lcid, nof_bytes); + switch(lcid) { + case LCID: + rlc->write_pdu(lcid, payload, nof_bytes); + break; + case 0: + log_h->info("Received ConnectionRequest from rnti=0x%x\n", rnti); + + // Configure User in MAC + srsenb::sched_interface::ue_cfg_t uecfg; + bzero(&uecfg, sizeof(srsenb::sched_interface::ue_cfg_t)); + uecfg.maxharq_tx = 5; + uecfg.continuous_pusch = false; + uecfg.ue_bearers[0].direction = srsenb::sched_interface::ue_bearer_cfg_t::BOTH; + uecfg.ue_bearers[LCID].direction = srsenb::sched_interface::ue_bearer_cfg_t::BOTH; + mac->ue_cfg(rnti, &uecfg); + + // configure DRB1 as UM + LIBLTE_RRC_RLC_CONFIG_STRUCT cfg; + bzero(&cfg, sizeof(LIBLTE_RRC_RLC_CONFIG_STRUCT)); + cfg.rlc_mode = LIBLTE_RRC_RLC_MODE_UM_BI; + cfg.dl_um_bi_rlc.t_reordering = LIBLTE_RRC_T_REORDERING_MS100; + cfg.dl_um_bi_rlc.sn_field_len = LIBLTE_RRC_SN_FIELD_LENGTH_SIZE10; + cfg.ul_um_bi_rlc.sn_field_len = LIBLTE_RRC_SN_FIELD_LENGTH_SIZE10; + rlc->add_bearer(LCID, &cfg); + + // Send dummy ConnectionSetup. MAC will send contention resolution ID automatically. + log_h->info("Sending ConnectionSetup\n"); + sdu = pool_allocate; + sdu->msg[0] = 0xab; + sdu->N_bytes = 1; + rlc->write_sdu(0, sdu); + + // Indicate RLC status to mac + mac->rlc_buffer_state(rnti, 0, 1, 0); + + LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT dedicated; + bzero(&dedicated, sizeof(LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT)); + dedicated.pusch_cnfg_ded.beta_offset_ack_idx = 5; + dedicated.pusch_cnfg_ded.beta_offset_ri_idx = 12; + dedicated.pusch_cnfg_ded.beta_offset_cqi_idx = 15; + dedicated.pusch_cnfg_ded_present = true; + dedicated.sched_request_cnfg.dsr_trans_max = LIBLTE_RRC_DSR_TRANS_MAX_N4; + dedicated.sched_request_cnfg.sr_pucch_resource_idx = 0; + dedicated.sched_request_cnfg.sr_cnfg_idx = 35; + dedicated.sched_request_cnfg_present = true; + phy->set_config_dedicated(rnti, &dedicated); + + usleep(500); + break; + default: + log_h->error("Received message for lcid=%d\n", lcid); + break; + } + } + + void rl_failure(uint16_t rnti) + { + log_h->console("Disconnecting rnti=0x%x.\n", rnti); + mac->ue_rem(rnti); + rlc->reset(); + } + +private: + int tun_fd; + bool running; + srslte::log *log_h; + srslte::byte_buffer_pool *pool; + srslte::rlc *rlc; + srsenb::mac *mac; + srsenb::phy *phy; + uint16_t rnti; + bool read_enable; + + int init_tuntap(char *ip_address) { + read_enable = true; + tun_fd = setup_if_addr(ip_address); + if (tun_fd<0) { + fprintf(stderr, "Error setting up IP %s\n", ip_address); + return -1; + } + printf("Created tun/tap interface at IP %s\n", ip_address); + return 0; + } + + void run_thread() { + struct iphdr *ip_pkt; + uint32_t idx = 0; + int32_t N_bytes = 0; + srslte::byte_buffer_t *pdu = pool_allocate; + + log_h->info("TUN/TAP reader thread running\n"); + + int first=1; + while(running) { + if (tun_fd > 0) { + pdu->msg[0] = 0x0; + N_bytes = read(tun_fd, &pdu->msg[idx], SRSLTE_MAX_BUFFER_SIZE_BYTES-SRSLTE_BUFFER_HEADER_OFFSET - idx); + } + if(N_bytes > 0) + { + if (read_enable && pdu->msg[0] != 0x60) { + + pdu->N_bytes = idx + N_bytes; + ip_pkt = (struct iphdr*)pdu->msg; + + log_h->debug_hex(pdu->msg, pdu->N_bytes, + "Read %d bytes from TUN/TAP\n", + N_bytes); + + // Check if entire packet was received + if(ntohs(ip_pkt->tot_len) == pdu->N_bytes) + { + // Send PDU directly to RLC + pdu->set_timestamp(); + rlc->write_sdu(LCID, pdu); + + // Indicate RLC status to mac + mac->rlc_buffer_state(rnti, LCID, rlc->get_buffer_state(LCID), 0); + + pdu = pool_allocate; + idx = 0; + } else{ + idx += N_bytes; + } + } + }else{ + log_h->error("Failed to read from TUN interface - gw receive thread exiting.\n"); + break; + } + } + } +}; + + +// Create classes +srslte::logger logger; +srslte::log_filter log_phy; +srslte::log_filter log_mac; +srslte::log_filter log_rlc; +srslte::log_filter log_tester; +srsenb::phy my_phy; +srsenb::mac my_mac; +srslte::rlc my_rlc; +srslte::radio my_radio; + +// Local classes for testing +tester my_tester; + + +void generate_cell_configuration(srsenb::sched_interface::cell_cfg_t *mac_cfg, srsenb::phy_cfg_t *phy_cfg) +{ + // Main cell configuration + srslte_cell_t cell; + cell.id = 0; + cell.cp = SRSLTE_CP_NORM; + cell.nof_ports = 1; + cell.nof_prb = 25; + cell.phich_length = SRSLTE_PHICH_NORM; + cell.phich_resources = SRSLTE_PHICH_R_1; + + // Generate SIB1 + LIBLTE_RRC_BCCH_DLSCH_MSG_STRUCT msg[2]; + bzero(&msg[0], sizeof(LIBLTE_RRC_BCCH_DLSCH_MSG_STRUCT)); + bzero(&msg[1], sizeof(LIBLTE_RRC_BCCH_DLSCH_MSG_STRUCT)); + + msg[0].N_sibs = 1; + msg[0].sibs[0].sib_type = LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1; + LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1_STRUCT *sib1 = &msg[0].sibs[0].sib.sib1; + + sib1->cell_id = 0x1234; + sib1->tracking_area_code = 0x1234; + sib1->freq_band_indicator = 2; + sib1->N_plmn_ids = 1; + sib1->plmn_id[0].id.mcc = 1; + sib1->plmn_id[0].id.mnc = 1; + sib1->plmn_id[0].resv_for_oper = LIBLTE_RRC_NOT_RESV_FOR_OPER; + sib1->cell_barred = LIBLTE_RRC_CELL_NOT_BARRED; + sib1->intra_freq_reselection = LIBLTE_RRC_INTRA_FREQ_RESELECTION_ALLOWED; + sib1->q_rx_lev_min = -140; + sib1->q_rx_lev_min_offset = 1; + sib1->p_max = 10; + sib1->p_max_present = true; + sib1->si_window_length = LIBLTE_RRC_SI_WINDOW_LENGTH_MS40; + sib1->N_sched_info = 1; + sib1->sched_info[0].si_periodicity = LIBLTE_RRC_SI_PERIODICITY_RF16; + sib1->sched_info[0].N_sib_mapping_info = 0; + sib1->system_info_value_tag = 8; + + // Generate SIB2 + msg[1].N_sibs = 2; + msg[1].sibs[0].sib_type = LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2; + msg[1].sibs[1].sib_type = LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_3; + LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT *sib2 = &msg[1].sibs[0].sib.sib2; + + // RACH configuration + sib2->rr_config_common_sib.rach_cnfg.num_ra_preambles = LIBLTE_RRC_NUMBER_OF_RA_PREAMBLES_N64; + sib2->rr_config_common_sib.rach_cnfg.preambles_group_a_cnfg.present = false; + sib2->rr_config_common_sib.rach_cnfg.preamble_init_rx_target_pwr = LIBLTE_RRC_PREAMBLE_INITIAL_RECEIVED_TARGET_POWER_DBM_N90; + sib2->rr_config_common_sib.rach_cnfg.pwr_ramping_step = LIBLTE_RRC_POWER_RAMPING_STEP_DB6; + sib2->rr_config_common_sib.rach_cnfg.preamble_trans_max = LIBLTE_RRC_PREAMBLE_TRANS_MAX_N10; + sib2->rr_config_common_sib.rach_cnfg.ra_resp_win_size = LIBLTE_RRC_RA_RESPONSE_WINDOW_SIZE_SF10; + sib2->rr_config_common_sib.rach_cnfg.mac_con_res_timer = LIBLTE_RRC_MAC_CONTENTION_RESOLUTION_TIMER_SF40; + sib2->rr_config_common_sib.rach_cnfg.max_harq_msg3_tx = 4; + + // BCCH + sib2->rr_config_common_sib.bcch_cnfg.modification_period_coeff = LIBLTE_RRC_MODIFICATION_PERIOD_COEFF_N16; + + // PCCH + sib2->rr_config_common_sib.pcch_cnfg.default_paging_cycle = LIBLTE_RRC_DEFAULT_PAGING_CYCLE_RF128; + sib2->rr_config_common_sib.pcch_cnfg.nB = LIBLTE_RRC_NB_ONE_THIRTY_SECOND_T; + + // PRACH Configuration + sib2->rr_config_common_sib.prach_cnfg.root_sequence_index = 41; + sib2->rr_config_common_sib.prach_cnfg.prach_cnfg_info.high_speed_flag = false; + sib2->rr_config_common_sib.prach_cnfg.prach_cnfg_info.prach_config_index = 4; + sib2->rr_config_common_sib.prach_cnfg.prach_cnfg_info.prach_freq_offset = 2; + sib2->rr_config_common_sib.prach_cnfg.prach_cnfg_info.zero_correlation_zone_config = 11; + + // PDSCH configuration + sib2->rr_config_common_sib.pdsch_cnfg.p_b = 0; + sib2->rr_config_common_sib.pdsch_cnfg.rs_power = -5; + + // PUSCH configuration + sib2->rr_config_common_sib.pusch_cnfg.n_sb = 1; + sib2->rr_config_common_sib.pusch_cnfg.hopping_mode = LIBLTE_RRC_HOPPING_MODE_INTER_SUBFRAME; + sib2->rr_config_common_sib.pusch_cnfg.pusch_hopping_offset = 4; + sib2->rr_config_common_sib.pusch_cnfg.enable_64_qam = false; + sib2->rr_config_common_sib.pusch_cnfg.ul_rs.cyclic_shift = 0; + sib2->rr_config_common_sib.pusch_cnfg.ul_rs.group_assignment_pusch = 0; + sib2->rr_config_common_sib.pusch_cnfg.ul_rs.group_hopping_enabled = false; + sib2->rr_config_common_sib.pusch_cnfg.ul_rs.sequence_hopping_enabled = false; + + // PUCCH configuration + sib2->rr_config_common_sib.pucch_cnfg.delta_pucch_shift = LIBLTE_RRC_DELTA_PUCCH_SHIFT_DS2; + sib2->rr_config_common_sib.pucch_cnfg.n_rb_cqi = 2; + sib2->rr_config_common_sib.pucch_cnfg.n_cs_an = 0; + sib2->rr_config_common_sib.pucch_cnfg.n1_pucch_an = 12; + + // SRS configuration + sib2->rr_config_common_sib.srs_ul_cnfg.present = false; + + // UL power control + sib2->rr_config_common_sib.ul_pwr_ctrl.p0_nominal_pusch = -80; + sib2->rr_config_common_sib.ul_pwr_ctrl.alpha = LIBLTE_RRC_UL_POWER_CONTROL_ALPHA_1; + sib2->rr_config_common_sib.ul_pwr_ctrl.p0_nominal_pucch = -80; + sib2->rr_config_common_sib.ul_pwr_ctrl.delta_flist_pucch.format_1 = LIBLTE_RRC_DELTA_F_PUCCH_FORMAT_1_0; + sib2->rr_config_common_sib.ul_pwr_ctrl.delta_flist_pucch.format_1b = LIBLTE_RRC_DELTA_F_PUCCH_FORMAT_1B_5; + sib2->rr_config_common_sib.ul_pwr_ctrl.delta_flist_pucch.format_2 = LIBLTE_RRC_DELTA_F_PUCCH_FORMAT_2_2; + sib2->rr_config_common_sib.ul_pwr_ctrl.delta_flist_pucch.format_2a = LIBLTE_RRC_DELTA_F_PUCCH_FORMAT_2A_2; + sib2->rr_config_common_sib.ul_pwr_ctrl.delta_flist_pucch.format_2b = LIBLTE_RRC_DELTA_F_PUCCH_FORMAT_2B_2; + sib2->rr_config_common_sib.ul_pwr_ctrl.delta_preamble_msg3 = 4; + + sib2->rr_config_common_sib.ul_cp_length = LIBLTE_RRC_UL_CP_LENGTH_1; + + sib2->ue_timers_and_constants.t300 = LIBLTE_RRC_T300_MS1000; + sib2->ue_timers_and_constants.t301 = LIBLTE_RRC_T301_MS1000; + sib2->ue_timers_and_constants.n310 = LIBLTE_RRC_N310_N10; + sib2->ue_timers_and_constants.t311 = LIBLTE_RRC_T311_MS1000; + sib2->ue_timers_and_constants.n311 = LIBLTE_RRC_N311_N1; + + sib2->time_alignment_timer = LIBLTE_RRC_TIME_ALIGNMENT_TIMER_INFINITY; + sib2->additional_spectrum_emission = 1; + sib2->arfcn_value_eutra.present = false; + sib2->ul_bw.present = false; + + LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_3_STRUCT *sib3 = &msg[1].sibs[1].sib.sib3; + + bzero(sib3, sizeof(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_3_STRUCT)); + sib3->q_hyst = LIBLTE_RRC_Q_HYST_DB_2; + sib3->s_non_intra_search = 6; + sib3->s_non_intra_search_present = true; + sib3->thresh_serving_low = 4; + sib3->cell_resel_prio = 6; + sib3->q_rx_lev_min = -122; + sib3->p_max = 23; + sib3->p_max_present = true; + sib3->s_intra_search = 10; + sib3->s_intra_search_present = true; + sib3->presence_ant_port_1 = true; + sib3->neigh_cell_cnfg = 1; + sib3->t_resel_eutra = 1; + + // Genreate payload + LIBLTE_BIT_MSG_STRUCT bitbuffer[2]; + for (int i=0;i<2;i++) { + liblte_rrc_pack_bcch_dlsch_msg(&msg[i], &bitbuffer[i]); + srslte_bit_pack_vector(bitbuffer[i].msg, sib_buffer[i].msg, bitbuffer[i].N_bits); + sib_buffer[i].N_bytes = (bitbuffer[i].N_bits-1)/8+1; + } + + // Fill MAC scheduler configuration + bzero(mac_cfg, sizeof(srsenb::sched_interface::cell_cfg_t)); + memcpy(&mac_cfg->cell, &cell, sizeof(srslte_cell_t)); + mac_cfg->sibs[0].len = sib_buffer[0].N_bytes; + mac_cfg->sibs[0].period_rf = 8; // Fixed to 8 rf + mac_cfg->sibs[1].len = sib_buffer[1].N_bytes; + mac_cfg->sibs[1].period_rf = liblte_rrc_si_periodicity_num[sib1->sched_info[0].si_periodicity]; + mac_cfg->si_window_ms = liblte_rrc_si_window_length_num[sib1->si_window_length]; + + + mac_cfg->prach_rar_window = liblte_rrc_ra_response_window_size_num[sib2->rr_config_common_sib.rach_cnfg.ra_resp_win_size]; + + // Copy PHY common configuration + bzero(phy_cfg, sizeof(srsenb::phy_cfg_t)); + memcpy(&phy_cfg->cell, &cell, sizeof(srslte_cell_t)); + memcpy(&phy_cfg->prach_cnfg, &sib2->rr_config_common_sib.prach_cnfg, sizeof(LIBLTE_RRC_PRACH_CONFIG_SIB_STRUCT)); + memcpy(&phy_cfg->pdsch_cnfg, &sib2->rr_config_common_sib.pdsch_cnfg, sizeof(LIBLTE_RRC_PDSCH_CONFIG_COMMON_STRUCT)); + memcpy(&phy_cfg->pusch_cnfg, &sib2->rr_config_common_sib.pusch_cnfg, sizeof(LIBLTE_RRC_PUSCH_CONFIG_COMMON_STRUCT)); + memcpy(&phy_cfg->pucch_cnfg, &sib2->rr_config_common_sib.pucch_cnfg, sizeof(LIBLTE_RRC_PUCCH_CONFIG_COMMON_STRUCT)); + memcpy(&phy_cfg->srs_ul_cnfg, &sib2->rr_config_common_sib.srs_ul_cnfg, sizeof(LIBLTE_RRC_SRS_UL_CONFIG_COMMON_STRUCT)); +} + +int main(int argc, char *argv[]) +{ + + parse_args(&prog_args, argc, argv); + + logger.init("/tmp/ip_test.log"); + log_phy.init("PHY ", &logger, true); + log_mac.init("MAC ", &logger, true); + log_rlc.init("RLC ", &logger); + log_tester.init("TEST", &logger); + logger.log("\n\n"); + + if (srsapps_verbose == 1) { + log_phy.set_level(srslte::LOG_LEVEL_INFO); + log_phy.set_hex_limit(100); + log_mac.set_level(srslte::LOG_LEVEL_DEBUG); + log_mac.set_hex_limit(100); + log_rlc.set_level(srslte::LOG_LEVEL_DEBUG); + log_rlc.set_hex_limit(1000); + log_tester.set_level(srslte::LOG_LEVEL_DEBUG); + log_tester.set_hex_limit(100); + printf("Log level info\n"); + } + if (srsapps_verbose == 2) { + log_phy.set_level(srslte::LOG_LEVEL_DEBUG); + log_phy.set_hex_limit(100); + log_mac.set_level(srslte::LOG_LEVEL_DEBUG); + log_mac.set_hex_limit(100); + log_rlc.set_level(srslte::LOG_LEVEL_DEBUG); + log_rlc.set_hex_limit(100); + log_tester.set_level(srslte::LOG_LEVEL_DEBUG); + log_tester.set_hex_limit(100); + srslte_verbose = SRSLTE_VERBOSE_DEBUG; + printf("Log level debug\n"); + } + + // Init Radio and PHY +#ifdef USE_RADIO + my_radio.init(); +#else + my_radio.init(NULL, (char*) "dummy"); +#endif + my_radio.set_tx_freq(prog_args.tx_freq); + my_radio.set_tx_gain(prog_args.tx_gain); + my_radio.set_rx_freq(prog_args.rx_freq); + my_radio.set_rx_gain(prog_args.rx_gain); + //my_radio.set_tx_adv_neg(true); + if (prog_args.time_adv >= 0) { + printf("Setting TA=%d samples\n", prog_args.time_adv); + my_radio.set_tx_adv(prog_args.time_adv); + } + + // Configuure cell + srsenb::phy_cfg_t phy_cfg; + srsenb::sched_interface::cell_cfg_t mac_cfg; + srsenb::mac_args_t mac_args; + srsenb::phy_args_t phy_args; + + mac_args.link_failure_nof_err = 10; + phy_args.equalizer_mode = "mmse"; + phy_args.estimator_fil_w = 0.2; + phy_args.max_prach_offset_us = 50; + phy_args.nof_phy_threads = 1; + phy_args.pusch_max_its = 5; + + generate_cell_configuration(&mac_cfg, &phy_cfg); + + my_phy.init(&phy_args, &phy_cfg, &my_radio, &my_mac, &log_phy); + my_mac.init(&mac_args, &mac_cfg.cell, &my_phy, &my_tester, &my_tester, &log_mac); + my_rlc.init(&my_tester, &my_tester, &my_tester, &log_rlc, &my_mac); + my_tester.init(&my_rlc, &my_mac, &my_phy, &log_tester, prog_args.ip_address); + + if (prog_args.enable_gui) { + sleep(1); + my_phy.start_plot(); + } + + bool running = true; + while(running) { + printf("Main running\n"); + sleep(1); + } + my_phy.stop(); + my_mac.stop(); +} + + + + +/******************* This is copied from srsue gw **********************/ +int setup_if_addr(char *ip_addr) +{ + + char *dev = (char*) "tun_srsenb"; + + // Construct the TUN device + int tun_fd = open("/dev/net/tun", O_RDWR); + if(0 > tun_fd) + { + perror("open"); + return(-1); + } + + struct ifreq ifr; + + memset(&ifr, 0, sizeof(ifr)); + ifr.ifr_flags = IFF_TUN | IFF_NO_PI; + strncpy(ifr.ifr_ifrn.ifrn_name, dev, IFNAMSIZ); + if(0 > ioctl(tun_fd, TUNSETIFF, &ifr)) + { + perror("ioctl1"); + return -1; + } + + // Bring up the interface + int sock = socket(AF_INET, SOCK_DGRAM, 0); + if(0 > ioctl(sock, SIOCGIFFLAGS, &ifr)) + { + perror("socket"); + return -1; + } + ifr.ifr_flags |= IFF_UP | IFF_RUNNING; + if(0 > ioctl(sock, SIOCSIFFLAGS, &ifr)) + { + perror("ioctl2"); + return -1; + } + + // Setup the IP address + sock = socket(AF_INET, SOCK_DGRAM, 0); + ifr.ifr_addr.sa_family = AF_INET; + ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr = inet_addr(ip_addr); + if(0 > ioctl(sock, SIOCSIFADDR, &ifr)) + { + perror("ioctl"); + return -1; + } + ifr.ifr_netmask.sa_family = AF_INET; + ((struct sockaddr_in *)&ifr.ifr_netmask)->sin_addr.s_addr = inet_addr("255.255.255.0"); + if(0 > ioctl(sock, SIOCSIFNETMASK, &ifr)) + { + perror("ioctl"); + return -1; + } + + return(tun_fd); +} diff --git a/srsenb/test/upper/plmn_test.cc b/srsenb/test/upper/plmn_test.cc new file mode 100644 index 000000000..ddf68d130 --- /dev/null +++ b/srsenb/test/upper/plmn_test.cc @@ -0,0 +1,77 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2016 Software Radio Systems Limited + * + * + */ + +#include +#include "upper/common_enb.h" +#include "srslte/asn1/liblte_rrc.h" + +void rrc_plmn_test() +{ + LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_in, plmn_out; + plmn_in.mcc = 0xF123; + plmn_in.mnc = 0xFF45; + + // 2-digit MNC test + uint8_t bit_buf[32]; + uint8_t *ie_ptr = bit_buf; + + liblte_rrc_pack_plmn_identity_ie(&plmn_in, &ie_ptr); + uint8_t byte_buf[4]; + liblte_pack(bit_buf, 22, byte_buf); + uint8_t ref[3] = {0x89, 0x19, 0x05}; + for(int i=0;i<3;i++) { + assert(ref[i] == byte_buf[i]); + } + ie_ptr = bit_buf; + liblte_rrc_unpack_plmn_identity_ie(&ie_ptr, &plmn_out); + assert(plmn_in.mcc == plmn_out.mcc); + assert(plmn_in.mnc == plmn_out.mnc); + + // 3-digit MNC test + plmn_in.mnc = 0xF456; + ie_ptr = bit_buf; + liblte_rrc_pack_plmn_identity_ie(&plmn_in, &ie_ptr); + liblte_pack(bit_buf, 26, byte_buf); + uint8_t ref2[4] = {0x89, 0x1D, 0x15, 0x02}; + for(int i=0;i<3;i++) { + assert(ref2[i] == byte_buf[i]); + } + ie_ptr = bit_buf; + liblte_rrc_unpack_plmn_identity_ie(&ie_ptr, &plmn_out); + assert(plmn_in.mcc == plmn_out.mcc); + assert(plmn_in.mnc == plmn_out.mnc); +} + +void s1ap_plmn_test() +{ + uint16_t mcc = 0xF123; + uint16_t mnc = 0xFF45; + uint32_t plmn; + + // 2-digit MNC test + srsenb::s1ap_mccmnc_to_plmn(mcc, mnc, &plmn); + assert(plmn == 0x21F354); + srsenb::s1ap_plmn_to_mccmnc(plmn, &mcc, &mnc); + assert(mcc == 0xF123); + assert(mnc == 0xFF45); + + // 3-digit MNC test + mnc = 0xF456; + srsenb::s1ap_mccmnc_to_plmn(mcc, mnc, &plmn); + assert(plmn == 0x216354); + srsenb::s1ap_plmn_to_mccmnc(plmn, &mcc, &mnc); + assert(mcc == 0xF123); + assert(mnc == 0xF456); +} + +int main(int argc, char **argv) +{ + rrc_plmn_test(); + s1ap_plmn_test(); +} diff --git a/srslte/include/srslte/srslte.h b/srslte/include/srslte/srslte.h deleted file mode 100644 index 719b5d945..000000000 --- a/srslte/include/srslte/srslte.h +++ /dev/null @@ -1,129 +0,0 @@ -/** - * - * \section COPYRIGHT - * - * Copyright 2013-2015 Software Radio Systems Limited - * - * \section LICENSE - * - * This file is part of the srsLTE library. - * - * 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 _LTE_ -#define _LTE_ - -#ifdef __cplusplus - extern "C" { -#endif - -#include -#include - -#include "srslte/config.h" -#include "srslte/version.h" - -#include "srslte/utils/bit.h" -#include "srslte/utils/convolution.h" -#include "srslte/utils/debug.h" -#include "srslte/utils/cexptab.h" -#include "srslte/utils/vector.h" - -#include "srslte/common/timestamp.h" -#include "srslte/common/sequence.h" -#include "srslte/common/phy_common.h" - -#include "srslte/ch_estimation/chest_ul.h" -#include "srslte/ch_estimation/chest_dl.h" -#include "srslte/ch_estimation/refsignal_dl.h" -#include "srslte/ch_estimation/refsignal_ul.h" - -#include "srslte/resampling/interp.h" -#include "srslte/resampling/decim.h" -#include "srslte/resampling/resample_arb.h" - -#include "srslte/channel/ch_awgn.h" - -#include "srslte/fec/viterbi.h" -#include "srslte/fec/convcoder.h" -#include "srslte/fec/crc.h" -#include "srslte/fec/tc_interl.h" -#include "srslte/fec/turbocoder.h" -#include "srslte/fec/turbodecoder.h" -#include "srslte/fec/cbsegm.h" -#include "srslte/fec/rm_conv.h" -#include "srslte/fec/rm_turbo.h" - -#include "srslte/dft/dft_precoding.h" -#include "srslte/dft/ofdm.h" -#include "srslte/dft/dft.h" - -#include "srslte/io/binsource.h" -#include "srslte/io/filesink.h" -#include "srslte/io/filesource.h" -#include "srslte/io/netsink.h" -#include "srslte/io/netsource.h" - -#include "srslte/modem/demod_hard.h" -#include "srslte/modem/demod_soft.h" -#include "srslte/modem/mod.h" -#include "srslte/modem/modem_table.h" - -#include "srslte/mimo/precoding.h" -#include "srslte/mimo/layermap.h" - -#include "srslte/phch/cqi.h" -#include "srslte/phch/dci.h" -#include "srslte/fec/softbuffer.h" -#include "srslte/phch/pbch.h" -#include "srslte/phch/pcfich.h" -#include "srslte/phch/pdcch.h" -#include "srslte/phch/pdsch.h" -#include "srslte/phch/phich.h" -#include "srslte/phch/pusch.h" -#include "srslte/phch/pucch.h" -#include "srslte/phch/prach.h" -#include "srslte/phch/ra.h" -#include "srslte/phch/regs.h" -#include "srslte/phch/sch.h" -#include "srslte/phch/uci.h" - -#include "srslte/ue/ue_sync.h" -#include "srslte/ue/ue_mib.h" -#include "srslte/ue/ue_cell_search.h" -#include "srslte/ue/ue_dl.h" -#include "srslte/ue/ue_ul.h" - -#include "srslte/enb/enb_dl.h" -#include "srslte/enb/enb_ul.h" - -#include "srslte/scrambling/scrambling.h" - -#include "srslte/sync/pss.h" -#include "srslte/sync/sfo.h" -#include "srslte/sync/sss.h" -#include "srslte/sync/sync.h" -#include "srslte/sync/cfo.h" -#include "srslte/sync/cp.h" - -#ifdef __cplusplus -} -#undef I // Fix complex.h #define I nastiness when using C++ -#endif - -#endif diff --git a/srslte/lib/rf/uhd_c_api.h b/srslte/lib/rf/uhd_c_api.h deleted file mode 100644 index 263441975..000000000 --- a/srslte/lib/rf/uhd_c_api.h +++ /dev/null @@ -1,11 +0,0 @@ - -#include -#include "srslte/config.h" -#include "srslte/rf/rf.h" - -/* Declare functions not currently provided by the C-API */ -SRSLTE_API void rf_uhd_register_msg_handler_c(void (*new_handler)(const char*)); -SRSLTE_API void uhd_tx_metadata_set_time_spec(uhd_tx_metadata_handle *md, time_t secs, double frac_secs); -SRSLTE_API void uhd_tx_metadata_set_start(uhd_tx_metadata_handle *md, bool is_start_of_burst); -SRSLTE_API void uhd_tx_metadata_set_end(uhd_tx_metadata_handle *md, bool is_end_of_burst); -SRSLTE_API void uhd_tx_metadata_add_time_spec(uhd_tx_metadata_handle *md, double frac_secs); diff --git a/srsue/CMakeLists.txt b/srsue/CMakeLists.txt new file mode 100644 index 000000000..85f391d6b --- /dev/null +++ b/srsue/CMakeLists.txt @@ -0,0 +1,46 @@ +# +# Copyright 2013-2017 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/. +# + +######################################################################## +# Boost is required +######################################################################## +if(NOT Boost_FOUND) + message(FATAL_ERROR "Boost required to compile srsUE and ") +endif() + +######################################################################## +# Setup the include and linker paths +######################################################################## +include_directories( + ${Boost_INCLUDE_DIRS} + ${SEC_INCLUDE_DIRS} + ${PROJECT_SOURCE_DIR}/srsue/hdr +) + +link_directories( + ${Boost_LIBRARY_DIRS} + ${SEC_LIBRARY_DIRS} +) + +######################################################################## +# Add subdirectories +######################################################################## +add_subdirectory(src) +add_subdirectory(test) diff --git a/srsue/hdr/mac/demux.h b/srsue/hdr/mac/demux.h new file mode 100644 index 000000000..773181220 --- /dev/null +++ b/srsue/hdr/mac/demux.h @@ -0,0 +1,90 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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 DEMUX_H +#define DEMUX_H + +#include "srslte/interfaces/ue_interfaces.h" +#include "srslte/common/pdu_queue.h" +#include "srslte/common/log.h" +#include "srslte/common/timers.h" +#include "srslte/common/pdu.h" + +/* Logical Channel Demultiplexing and MAC CE dissassemble */ + + +namespace srsue { + +class demux : public srslte::pdu_queue::process_callback +{ +public: + demux(); + void init(phy_interface_mac* phy_h_, rlc_interface_mac *rlc, srslte::log* log_h_, srslte::timers* timers_db_); + + bool process_pdus(); + uint8_t* request_buffer(uint32_t pid, uint32_t len); + void deallocate(uint8_t* payload_buffer_ptr); + + void push_pdu(uint32_t pid, uint8_t *buff, uint32_t nof_bytes, uint32_t tstamp); + void push_pdu_temp_crnti(uint8_t *buff, uint32_t nof_bytes); + + void set_uecrid_callback(bool (*callback)(void*, uint64_t), void *arg); + bool get_uecrid_successful(); + + void process_pdu(uint8_t *pdu, uint32_t nof_bytes, uint32_t tstamp); + +private: + const static int NOF_HARQ_PID = 8; + const static int MAX_PDU_LEN = 150*1024/8; // ~ 150 Mbps + const static int NOF_BUFFER_PDUS = 64; // Number of PDU buffers per HARQ pid + uint8_t bcch_buffer[1024]; // BCCH PID has a dedicated buffer + + bool (*uecrid_callback) (void*, uint64_t); + void *uecrid_callback_arg; + + srslte::sch_pdu mac_msg; + srslte::sch_pdu pending_mac_msg; + + void process_sch_pdu(srslte::sch_pdu *pdu); + bool process_ce(srslte::sch_subh *subheader); + + bool is_uecrid_successful; + + phy_interface_mac *phy_h; + srslte::log *log_h; + srslte::timers *timers_db; + rlc_interface_mac *rlc; + + // Buffer of PDUs + srslte::pdu_queue pdus; +}; + +} // namespace srsue + +#endif // DEMUX_H + + + diff --git a/srsue/hdr/mac/dl_harq.h b/srsue/hdr/mac/dl_harq.h new file mode 100644 index 000000000..e64e204c6 --- /dev/null +++ b/srsue/hdr/mac/dl_harq.h @@ -0,0 +1,120 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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 DL_HARQ_H +#define DL_HARQ_H + +#include "srslte/common/log.h" +#include "srslte/common/timers.h" +#include "mac/demux.h" +#include "mac/dl_sps.h" +#include "srslte/common/mac_pcap.h" + +#include "srslte/interfaces/ue_interfaces.h" + +/* Downlink HARQ entity as defined in 5.3.2 of 36.321 */ + + +namespace srsue { + +class dl_harq_entity +{ +public: + + const static uint32_t NOF_HARQ_PROC = 8; + const static uint32_t HARQ_BCCH_PID = NOF_HARQ_PROC; + + dl_harq_entity(); + bool init(srslte::log *log_h_, mac_interface_rrc::mac_cfg_t *mac_cfg, srslte::timers *timers_, demux *demux_unit); + + + /***************** PHY->MAC interface for DL processes **************************/ + void new_grant_dl(mac_interface_phy::mac_grant_t grant, mac_interface_phy::tb_action_dl_t *action); + void tb_decoded(bool ack, srslte_rnti_type_t rnti_type, uint32_t harq_pid); + + + void reset(); + void start_pcap(srslte::mac_pcap* pcap); + int get_current_tbs(uint32_t harq_pid); + + void set_si_window_start(int si_window_start); + + float get_average_retx(); + +private: + + + class dl_harq_process { + public: + dl_harq_process(); + bool init(uint32_t pid, dl_harq_entity *parent); + void reset(); + bool is_sps(); + void new_grant_dl(mac_interface_phy::mac_grant_t grant, mac_interface_phy::tb_action_dl_t *action); + void tb_decoded(bool ack); + int get_current_tbs(); + + private: + bool calc_is_new_transmission(mac_interface_phy::mac_grant_t grant); + + bool is_initiated; + dl_harq_entity *harq_entity; + srslte::log *log_h; + + bool is_new_transmission; + + uint32_t pid; + uint8_t *payload_buffer_ptr; + bool ack; + + uint32_t n_retx; + + mac_interface_phy::mac_grant_t cur_grant; + srslte_softbuffer_rx_t softbuffer; + + }; + static bool generate_ack_callback(void *arg); + + uint32_t get_harq_sps_pid(uint32_t tti); + + dl_sps dl_sps_assig; + + dl_harq_process proc[NOF_HARQ_PROC+1]; + srslte::timers *timers_db; + mac_interface_rrc::mac_cfg_t *mac_cfg; + demux *demux_unit; + srslte::log *log_h; + srslte::mac_pcap *pcap; + uint16_t last_temporal_crnti; + int si_window_start; + + float average_retx; + uint64_t nof_pkts; +}; + +} // namespace srsue + +#endif // DL_HARQ_H diff --git a/srsue/hdr/mac/dl_sps.h b/srsue/hdr/mac/dl_sps.h new file mode 100644 index 000000000..8ec83cb52 --- /dev/null +++ b/srsue/hdr/mac/dl_sps.h @@ -0,0 +1,53 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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 DL_SPS_H +#define DL_SPS_H + +#include "srslte/common/log.h" +#include "srslte/common/timers.h" + +/* Downlink Semi-Persistent schedulign (Section 5.10.1) */ + + +namespace srsue { + +class dl_sps +{ +public: + + void clear() {} + void reset() {} + bool get_pending_grant(uint32_t tti, mac_interface_phy::mac_grant_t *grant) { + return false; + } +private: + +}; + +} // namespace srsue + +#endif // DL_SPS_H diff --git a/srsue/hdr/mac/mac.h b/srsue/hdr/mac/mac.h new file mode 100644 index 000000000..f6f22f334 --- /dev/null +++ b/srsue/hdr/mac/mac.h @@ -0,0 +1,207 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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 MAC_H +#define MAC_H + +#include "srslte/common/log.h" +#include "mac/dl_harq.h" +#include "mac/ul_harq.h" +#include "srslte/common/timers.h" +#include "mac/mac_metrics.h" +#include "mac/proc_ra.h" +#include "mac/proc_sr.h" +#include "mac/proc_bsr.h" +#include "mac/proc_phr.h" +#include "mac/mux.h" +#include "mac/demux.h" +#include "srslte/common/mac_pcap.h" +#include "srslte/interfaces/ue_interfaces.h" +#include "srslte/common/tti_sync_cv.h" +#include "srslte/common/threads.h" + +namespace srsue { + +class mac + :public mac_interface_phy + ,public mac_interface_rrc + ,public srslte::mac_interface_timers + ,public thread + ,public srslte::timer_callback +{ +public: + mac(); + bool init(phy_interface_mac *phy, rlc_interface_mac *rlc, rrc_interface_mac* rrc, srslte::log *log_h); + void stop(); + + void get_metrics(mac_metrics_t &m); + + /******** Interface from PHY (PHY -> MAC) ****************/ + /* see mac_interface.h for comments */ + void new_grant_ul(mac_grant_t grant, tb_action_ul_t *action); + void new_grant_ul_ack(mac_grant_t grant, bool ack, tb_action_ul_t *action); + void harq_recv(uint32_t tti, bool ack, tb_action_ul_t *action); + void new_grant_dl(mac_grant_t grant, tb_action_dl_t *action); + void tb_decoded(bool ack, srslte_rnti_type_t rnti_type, uint32_t harq_pid); + void bch_decoded_ok(uint8_t *payload, uint32_t len); + void pch_decoded_ok(uint32_t len); + void tti_clock(uint32_t tti); + + + /******** Interface from RLC (RLC -> MAC) ****************/ + void bcch_start_rx(); + void bcch_stop_rx(); + void bcch_start_rx(int si_window_start, int si_window_length); + void pcch_start_rx(); + void pcch_stop_rx(); + void setup_lcid(uint32_t lcid, uint32_t lcg, uint32_t priority, int PBR_x_tti, uint32_t BSD); + void reconfiguration(); + void reset(); + + /******** set/get MAC configuration ****************/ + void set_config(mac_cfg_t *mac_cfg); + void get_config(mac_cfg_t *mac_cfg); + void set_config_main(LIBLTE_RRC_MAC_MAIN_CONFIG_STRUCT *main_cfg); + void set_config_rach(LIBLTE_RRC_RACH_CONFIG_COMMON_STRUCT *rach_cfg, uint32_t prach_config_index); + void set_config_sr(LIBLTE_RRC_SCHEDULING_REQUEST_CONFIG_STRUCT *sr_cfg); + void set_contention_id(uint64_t uecri); + + void get_rntis(ue_rnti_t *rntis); + + void timer_expired(uint32_t timer_id); + void start_pcap(srslte::mac_pcap* pcap); + + srslte::timers::timer* get(uint32_t timer_id); + u_int32_t get_unique_id(); + + uint32_t get_current_tti(); + + enum { + HARQ_RTT, + TIME_ALIGNMENT, + CONTENTION_TIMER, + BSR_TIMER_PERIODIC, + BSR_TIMER_RETX, + PHR_TIMER_PERIODIC, + PHR_TIMER_PROHIBIT, + NOF_MAC_TIMERS + } mac_timers_t; + + static const int MAC_NOF_UPPER_TIMERS = 20; + +private: + void run_thread(); + + static const int MAC_MAIN_THREAD_PRIO = 5; + static const int MAC_PDU_THREAD_PRIO = 6; + + // Interaction with PHY + srslte::tti_sync_cv ttisync; + phy_interface_mac *phy_h; + rlc_interface_mac *rlc_h; + rrc_interface_mac *rrc_h; + srslte::log *log_h; + + // MAC configuration + mac_cfg_t config; + + // UE-specific RNTIs + ue_rnti_t uernti; + + uint32_t tti; + bool started; + bool is_synchronized; + uint16_t last_temporal_crnti; + uint16_t phy_rnti; + + /* Multiplexing/Demultiplexing Units */ + mux mux_unit; + demux demux_unit; + + /* DL/UL HARQ */ + dl_harq_entity dl_harq; + ul_harq_entity ul_harq; + + /* MAC Uplink-related Procedures */ + ra_proc ra_procedure; + sr_proc sr_procedure; + bsr_proc bsr_procedure; + phr_proc phr_procedure; + + /* Buffers for PCH reception (not included in DL HARQ) */ + const static uint32_t pch_payload_buffer_sz = 8*1024; + srslte_softbuffer_rx_t pch_softbuffer; + uint8_t pch_payload_buffer[pch_payload_buffer_sz]; + + /* Functions for MAC Timers */ + srslte::timers timers_db; + void setup_timers(); + void timeAlignmentTimerExpire(); + + // pointer to MAC PCAP object + srslte::mac_pcap* pcap; + bool signals_pregenerated; + bool is_first_ul_grant; + + + mac_metrics_t metrics; + + + /* Class to run upper-layer timers with normal priority */ + class upper_timers : public periodic_thread { + public: + upper_timers(); + void reset(); + srslte::timers::timer* get(uint32_t timer_id); + uint32_t get_unique_id(); + private: + void run_period(); + srslte::timers timers_db; + }; + upper_timers upper_timers_thread; + + + + /* Class to process MAC PDUs from DEMUX unit */ + class pdu_process : public thread { + public: + pdu_process(demux *demux_unit); + void notify(); + void stop(); + private: + void run_thread(); + bool running; + bool have_data; + pthread_mutex_t mutex; + pthread_cond_t cvar; + demux* demux_unit; + }; + pdu_process pdu_process_thread; +}; + +} // namespace srsue + +#endif // MAC_H diff --git a/srsue/hdr/mac/mac_metrics.h b/srsue/hdr/mac/mac_metrics.h new file mode 100644 index 000000000..91ce29cab --- /dev/null +++ b/srsue/hdr/mac/mac_metrics.h @@ -0,0 +1,46 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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 UE_MAC_METRICS_H +#define UE_MAC_METRICS_H + + +namespace srsue { + +struct mac_metrics_t +{ + int tx_pkts; + int tx_errors; + int tx_brate; + int rx_pkts; + int rx_errors; + int rx_brate; + int ul_buffer; +}; + +} // namespace srsue + +#endif // UE_MAC_METRICS_H diff --git a/srsue/hdr/mac/mux.h b/srsue/hdr/mac/mux.h new file mode 100644 index 000000000..db98ebe78 --- /dev/null +++ b/srsue/hdr/mac/mux.h @@ -0,0 +1,116 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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 MUX_H +#define MUX_H + +#include + +#include + +#include "srslte/common/log.h" +#include "srslte/interfaces/ue_interfaces.h" +#include "srslte/common/pdu.h" +#include "mac/proc_bsr.h" +#include "mac/proc_phr.h" + +/* Logical Channel Multiplexing and Prioritization + Msg3 Buffer */ + + +typedef struct { + uint32_t id; + int Bj; + int PBR; // -1 sets to infinity + uint32_t BSD; + uint32_t priority; + int sched_len; + int buffer_len; +} lchid_t; + +namespace srsue { + +class mux +{ +public: + mux(); + void reset(); + void init(rlc_interface_mac *rlc, srslte::log *log_h, bsr_proc *bsr_procedure, phr_proc *phr_procedure_); + + bool is_pending_any_sdu(); + bool is_pending_sdu(uint32_t lcid); + + uint8_t* pdu_get(uint8_t *payload, uint32_t pdu_sz, uint32_t tx_tti, uint32_t pid); + uint8_t* msg3_get(uint8_t* payload, uint32_t pdu_sz); + + void msg3_flush(); + bool msg3_is_transmitted(); + + void append_crnti_ce_next_tx(uint16_t crnti); + + void set_priority(uint32_t lcid, uint32_t priority, int PBR_x_tti, uint32_t BSD); + void clear_lch(uint32_t lch_id); + void pusch_retx(uint32_t tx_tti, uint32_t pid); + +private: + int find_lchid(uint32_t lch_id); + bool pdu_move_to_msg3(uint32_t pdu_sz); + bool allocate_sdu(uint32_t lcid, srslte::sch_pdu *pdu, int max_sdu_sz); + bool sched_sdu(lchid_t *ch, int *sdu_space, int max_sdu_sz); + + const static int MIN_RLC_SDU_LEN = 0; + const static int MAX_NOF_SUBHEADERS = 20; + const static int MAX_HARQ_PROC = 8; + + std::vector lch; + + // Keep track of the PIDs that transmitted BSR reports + bool pid_has_bsr[MAX_HARQ_PROC]; + + // Mutex for exclusive access + pthread_mutex_t mutex; + + srslte::log *log_h; + rlc_interface_mac *rlc; + bsr_proc *bsr_procedure; + phr_proc *phr_procedure; + uint16_t pending_crnti_ce; + + /* Msg3 Buffer */ + static const uint32_t MSG3_BUFF_SZ = 128; + uint8_t msg3_buff[MSG3_BUFF_SZ]; + + /* PDU Buffer */ + srslte::sch_pdu pdu_msg; + bool msg3_has_been_transmitted; + + + +}; + +} // namespace srsue + +#endif // MUX_H + diff --git a/srsue/hdr/mac/proc.h b/srsue/hdr/mac/proc.h new file mode 100644 index 000000000..3fa864cb0 --- /dev/null +++ b/srsue/hdr/mac/proc.h @@ -0,0 +1,59 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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 PROC_H +#define PROC_H + +#include + +/* Interface for a MAC procedure */ + + +namespace srsue { + +class proc +{ +public: + proc() { + running = false; + } + void run() { + running = true; + } + void stop() { + running = false; + } + bool is_running() { + return running; + } + virtual void step(uint32_t tti) = 0; +private: + bool running; +}; + +} // namespace srsue + +#endif // PROC_H diff --git a/srsue/hdr/mac/proc_bsr.h b/srsue/hdr/mac/proc_bsr.h new file mode 100644 index 000000000..bbfaa1c90 --- /dev/null +++ b/srsue/hdr/mac/proc_bsr.h @@ -0,0 +1,100 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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 PROCBSR_H +#define PROCBSR_H + +#include + +#include "srslte/common/log.h" +#include "srslte/interfaces/ue_interfaces.h" +#include "srslte/common/timers.h" + +/* Buffer status report procedure */ + +namespace srsue { + +class bsr_proc : public srslte::timer_callback +{ +public: + bsr_proc(); + void init(rlc_interface_mac *rlc, srslte::log *log_h, mac_interface_rrc::mac_cfg_t *mac_cfg, srslte::timers *timers_db); + void step(uint32_t tti); + void reset(); + void setup_lcg(uint32_t lcid, uint32_t new_lcg); + void set_priority(uint32_t lcid, uint32_t priority); + void timer_expired(uint32_t timer_id); + uint32_t get_buffer_state(); + + typedef enum { + LONG_BSR, + SHORT_BSR, + TRUNC_BSR + } bsr_format_t; + + typedef struct { + bsr_format_t format; + uint32_t buff_size[4]; + } bsr_t; + + bool need_to_send_bsr_on_ul_grant(uint32_t grant_size, bsr_t *bsr); + bool generate_padding_bsr(uint32_t nof_padding_bytes, bsr_t *bsr); + bool need_to_send_sr(uint32_t tti); + bool need_to_reset_sr(); + void set_tx_tti(uint32_t tti); + +private: + + const static int QUEUE_STATUS_PERIOD_MS = 500; + + bool reset_sr; + mac_interface_rrc::mac_cfg_t *mac_cfg; + srslte::timers *timers_db; + srslte::log *log_h; + rlc_interface_mac *rlc; + bool initiated; + const static int MAX_LCID = 6; + int lcg[MAX_LCID]; + uint32_t last_pending_data[MAX_LCID]; + int priorities[MAX_LCID]; + uint32_t find_max_priority_lcid(); + typedef enum {NONE, REGULAR, PADDING, PERIODIC} triggered_bsr_type_t; + triggered_bsr_type_t triggered_bsr_type; + + bool sr_is_sent; + uint32_t last_print; + uint32_t next_tx_tti; + void update_pending_data(); + bool check_highest_channel(); + bool check_single_channel(); + bool generate_bsr(bsr_t *bsr, uint32_t nof_padding_bytes); + char* bsr_type_tostring(triggered_bsr_type_t type); + char* bsr_format_tostring(bsr_format_t format); +}; + +} // namespace srsue + +#endif // PROCBSR_H diff --git a/srsue/hdr/mac/proc_phr.h b/srsue/hdr/mac/proc_phr.h new file mode 100644 index 000000000..942f30456 --- /dev/null +++ b/srsue/hdr/mac/proc_phr.h @@ -0,0 +1,71 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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 PROCPHR_H +#define PROCPHR_H + +#include +#include "srslte/common/timers.h" +#include "srslte/interfaces/ue_interfaces.h" +#include "srslte/common/log.h" + + +/* Power headroom report procedure */ + + +namespace srsue { + +class phr_proc : public srslte::timer_callback +{ +public: + phr_proc(); + void init(phy_interface_mac* phy_h, srslte::log* log_h_, mac_interface_rrc::mac_cfg_t *mac_cfg, srslte::timers *timers_db_); + + void step(uint32_t tti); + void reset(); + + bool generate_phr_on_ul_grant(float *phr); + void timer_expired(uint32_t timer_id); + +private: + + bool pathloss_changed(); + + srslte::log* log_h; + mac_interface_rrc::mac_cfg_t *mac_cfg; + phy_interface_mac* phy_h; + srslte::timers* timers_db; + bool initiated; + int timer_prohibit; + int timer_periodic; + int dl_pathloss_change; + int last_pathloss_db; + bool phr_is_triggered; +}; + +} // namespace srsue + +#endif // PROCPHR_H diff --git a/srsue/hdr/mac/proc_ra.h b/srsue/hdr/mac/proc_ra.h new file mode 100644 index 000000000..6863371c0 --- /dev/null +++ b/srsue/hdr/mac/proc_ra.h @@ -0,0 +1,201 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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 PROCRA_H +#define PROCRA_H + +#include + +#include "srslte/common/log.h" +#include "srslte/common/timers.h" +#include "mac/mux.h" +#include "mac/demux.h" +#include "srslte/common/pdu.h" +#include "srslte/common/mac_pcap.h" + +/* Random access procedure as specified in Section 5.1 of 36.321 */ + + +namespace srsue { + +class ra_proc : public srslte::timer_callback +{ + public: + ra_proc() : rar_pdu_msg(20) { + bzero(&softbuffer_rar, sizeof(srslte_softbuffer_rx_t)); + pcap = NULL; + backoff_interval_start = 0; + backoff_inteval = 0; + received_target_power_dbm = 0; + ra_rnti = 0; + current_ta = 0; + state = IDLE; + last_msg3_group = RA_GROUP_A; + msg3_transmitted = false; + first_rar_received = false; + phy_h = NULL; + log_h = NULL; + mac_cfg = NULL; + timers_db = NULL; + mux_unit = NULL; + demux_unit = NULL; + rrc = NULL; + transmitted_contention_id = 0; + transmitted_crnti = 0; + pdcch_to_crnti_received = PDCCH_CRNTI_NOT_RECEIVED; + started_by_pdcch = false; + rar_grant_nbytes = 0; + rar_grant_tti = 0; + msg3_flushed = false; + }; + void init(phy_interface_mac *phy_h, + rrc_interface_mac *rrc_, + srslte::log *log_h, + mac_interface_rrc::ue_rnti_t *rntis, + mac_interface_rrc::mac_cfg_t *mac_cfg, + srslte::timers *timers_db, + mux *mux_unit, + demux *demux_unit); + void reset(); + void start_pdcch_order(); + void start_mac_order(uint32_t msg_len_bits = 56); + void step(uint32_t tti); + bool is_successful(); + bool is_response_error(); + bool is_contention_resolution(); + void harq_retx(); + bool is_error(); + bool in_progress(); + void pdcch_to_crnti(bool contains_uplink_grant); + void timer_expired(uint32_t timer_id); + + void new_grant_dl(mac_interface_phy::mac_grant_t grant, mac_interface_phy::tb_action_dl_t* action); + void tb_decoded_ok(); + + void start_pcap(srslte::mac_pcap* pcap); +private: + static bool uecrid_callback(void *arg, uint64_t uecri); + + bool contention_resolution_id_received(uint64_t uecri); + void process_timeadv_cmd(uint32_t ta_cmd); + void step_initialization(); + void step_resource_selection(); + void step_preamble_transmission(); + void step_pdcch_setup(); + void step_response_reception(); + void step_response_error(); + void step_backoff_wait(); + void step_contention_resolution(); + void step_completition(); + + // Buffer to receive RAR PDU + static const uint32_t MAX_RAR_PDU_LEN = 2048; + uint8_t rar_pdu_buffer[MAX_RAR_PDU_LEN]; + srslte::rar_pdu rar_pdu_msg; + + // Random Access parameters provided by higher layers defined in 5.1.1 + uint32_t configIndex; + uint32_t nof_preambles; + uint32_t nof_groupA_preambles; + uint32_t nof_groupB_preambles; + uint32_t messagePowerOffsetGroupB; + uint32_t messageSizeGroupA; + uint32_t responseWindowSize; + uint32_t powerRampingStep; + uint32_t preambleTransMax; + uint32_t iniReceivedTargetPower; + int delta_preamble_db; + uint32_t contentionResolutionTimer; + uint32_t maskIndex; + int preambleIndex; + uint32_t new_ra_msg_len; + + // Internal variables + uint32_t preambleTransmissionCounter; + uint32_t backoff_param_ms; + uint32_t sel_maskIndex; + uint32_t sel_preamble; + uint32_t backoff_interval_start; + uint32_t backoff_inteval; + int received_target_power_dbm; + uint32_t ra_rnti; + uint32_t current_ta; + + srslte_softbuffer_rx_t softbuffer_rar; + + + enum { + IDLE = 0, + INITIALIZATION, // Section 5.1.1 + RESOURCE_SELECTION, // Section 5.1.2 + PREAMBLE_TRANSMISSION, // Section 5.1.3 + PDCCH_SETUP, + RESPONSE_RECEPTION, // Section 5.1.4 + RESPONSE_ERROR, + BACKOFF_WAIT, + CONTENTION_RESOLUTION, // Section 5.1.5 + COMPLETION, // Section 5.1.6 + COMPLETION_DONE, + RA_PROBLEM // Section 5.1.5 last part + } state; + + typedef enum {RA_GROUP_A, RA_GROUP_B} ra_group_t; + + ra_group_t last_msg3_group; + bool msg3_transmitted; + bool first_rar_received; + void read_params(); + + phy_interface_mac *phy_h; + srslte::log *log_h; + srslte::timers *timers_db; + mux *mux_unit; + demux *demux_unit; + srslte::mac_pcap *pcap; + rrc_interface_mac *rrc; + + mac_interface_rrc::ue_rnti_t *rntis; + mac_interface_rrc::mac_cfg_t *mac_cfg; + + uint64_t transmitted_contention_id; + uint16_t transmitted_crnti; + + enum { + PDCCH_CRNTI_NOT_RECEIVED = 0, + PDCCH_CRNTI_UL_GRANT, + PDCCH_CRNTI_DL_GRANT + } pdcch_to_crnti_received; + + bool started_by_pdcch; + uint32_t rar_grant_nbytes; + uint32_t rar_grant_tti; + bool msg3_flushed; + bool rar_received; +}; + +} // namespace srsue + +#endif // PROCRA_H diff --git a/srsue/hdr/mac/proc_sr.h b/srsue/hdr/mac/proc_sr.h new file mode 100644 index 000000000..9425481dd --- /dev/null +++ b/srsue/hdr/mac/proc_sr.h @@ -0,0 +1,67 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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 PROCSR_H +#define PROCSR_H + +#include +#include "srslte/interfaces/ue_interfaces.h" +#include "srslte/common/log.h" + +/* Scheduling Request procedure as defined in 5.4.4 of 36.321 */ + + +namespace srsue { + +class sr_proc +{ +public: + sr_proc(); + void init(phy_interface_mac *phy_h, rrc_interface_mac *rrc, srslte::log *log_h, mac_interface_rrc::mac_cfg_t *mac_cfg); + void step(uint32_t tti); + void reset(); + void start(); + bool need_random_access(); + +private: + bool need_tx(uint32_t tti); + + uint32_t sr_counter; + uint32_t dsr_transmax; + bool is_pending_sr; + mac_interface_rrc::mac_cfg_t *mac_cfg; + + rrc_interface_mac *rrc; + phy_interface_mac *phy_h; + srslte::log *log_h; + + bool initiated; + bool do_ra; +}; + +} // namespace srsue + +#endif // PROCSR_H diff --git a/srsue/hdr/mac/ul_harq.h b/srsue/hdr/mac/ul_harq.h new file mode 100644 index 000000000..cea469e33 --- /dev/null +++ b/srsue/hdr/mac/ul_harq.h @@ -0,0 +1,150 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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 ULHARQ_H +#define ULHARQ_H + +#include "srslte/interfaces/ue_interfaces.h" +#include "srslte/common/log.h" +#include "mac/mux.h" +#include "mac/ul_sps.h" +#include "srslte/common/mac_pcap.h" +#include "srslte/common/timers.h" + +/* Uplink HARQ entity as defined in 5.4.2 of 36.321 */ + + +namespace srsue { + +class ul_harq_entity +{ +public: + + const static uint32_t NOF_HARQ_PROC = 8; + static uint32_t pidof(uint32_t tti); + + ul_harq_entity() { + pcap = NULL; + timers_db = NULL; + mux_unit = NULL; + log_h = NULL; + mac_cfg = NULL; + rntis = NULL; + average_retx = 0; + nof_pkts = 0; + } + bool init(srslte::log *log_h, + mac_interface_rrc::ue_rnti_t *rntis, + mac_interface_rrc::mac_cfg_t *mac_cfg, + srslte::timers* timers_, + mux *mux_unit); + void reset(); + void reset_ndi(); + + void start_pcap(srslte::mac_pcap* pcap); + + + /***************** PHY->MAC interface for UL processes **************************/ + void new_grant_ul(mac_interface_phy::mac_grant_t grant, mac_interface_phy::tb_action_ul_t *action); + void new_grant_ul_ack(mac_interface_phy::mac_grant_t grant, bool ack, mac_interface_phy::tb_action_ul_t *action); + void harq_recv(uint32_t tti, bool ack, mac_interface_phy::tb_action_ul_t *action); + + int get_current_tbs(uint32_t tti); + + float get_average_retx(); + +private: + + class ul_harq_process { + public: + ul_harq_process(); + bool init(uint32_t pid, ul_harq_entity *parent); + void reset(); + void reset_ndi(); + + void run_tti(uint32_t tti, mac_interface_phy::mac_grant_t *grant, mac_interface_phy::tb_action_ul_t* action); + + uint32_t get_rv(); + bool has_grant(); + + void set_harq_feedback(bool ack); + bool get_ndi(); + bool is_sps(); + uint32_t last_tx_tti(); + uint32_t get_nof_retx(); + int get_current_tbs(); + + private: + mac_interface_phy::mac_grant_t cur_grant; + + uint32_t pid; + uint32_t current_tx_nb; + uint32_t current_irv; + bool harq_feedback; + bool ndi; + srslte::log *log_h; + ul_harq_entity *harq_entity; + bool is_grant_configured; + srslte_softbuffer_tx_t softbuffer; + bool is_msg3; + bool is_initiated; + uint32_t tti_last_tx; + + + const static int payload_buffer_len = 128*1024; + uint8_t *payload_buffer; + uint8_t *pdu_ptr; + + void generate_retx(uint32_t tti_tx, mac_interface_phy::tb_action_ul_t *action); + void generate_retx(uint32_t tti_tx, mac_interface_phy::mac_grant_t *grant, + mac_interface_phy::tb_action_ul_t *action); + void generate_new_tx(uint32_t tti_tx, bool is_msg3, mac_interface_phy::mac_grant_t *grant, + mac_interface_phy::tb_action_ul_t *action); + void generate_tx(uint32_t tti_tx, mac_interface_phy::tb_action_ul_t *action); + }; + + + void run_tti(uint32_t tti, mac_interface_phy::mac_grant_t *grant, mac_interface_phy::tb_action_ul_t* action); + void set_ack(uint32_t tti, bool ack); + + ul_sps ul_sps_assig; + + srslte::timers *timers_db; + mux *mux_unit; + ul_harq_process proc[NOF_HARQ_PROC]; + srslte::log *log_h; + srslte::mac_pcap *pcap; + + mac_interface_rrc::ue_rnti_t *rntis; + mac_interface_rrc::mac_cfg_t *mac_cfg; + + float average_retx; + uint64_t nof_pkts; +}; + +} // namespace srsue + +#endif // ULHARQ_H diff --git a/srsue/hdr/mac/ul_sps.h b/srsue/hdr/mac/ul_sps.h new file mode 100644 index 000000000..59af7f507 --- /dev/null +++ b/srsue/hdr/mac/ul_sps.h @@ -0,0 +1,53 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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 ULSPS_H +#define ULSPS_H + +#include "srslte/common/log.h" +#include "srslte/common/timers.h" + +/* Uplink Semi-Persistent schedulign (Section 5.10.2) */ + + +namespace srsue { + +typedef _Complex float cf_t; + +class ul_sps +{ +public: + + void clear() {} + void reset(uint32_t tti) {} + bool get_pending_grant(uint32_t tti, mac_interface_phy::mac_grant_t *grant) { return false; } +private: + +}; + +} // namespace srsue + +#endif // ULSPS_H diff --git a/srsue/hdr/metrics_stdout.h b/srsue/hdr/metrics_stdout.h new file mode 100644 index 000000000..cd3efc1a3 --- /dev/null +++ b/srsue/hdr/metrics_stdout.h @@ -0,0 +1,73 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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: metrics_stdout.h + * Description: Metrics class printing to stdout. + *****************************************************************************/ + +#ifndef METRICS_STDOUT_H +#define METRICS_STDOUT_H + +#include +#include +#include + +#include "ue_metrics_interface.h" + +namespace srsue { + +class metrics_stdout +{ +public: + metrics_stdout(); + + bool init(ue_metrics_interface *u, float report_period_secs=1.0); + void stop(); + void toggle_print(bool b); + static void* metrics_thread_start(void *m); + void metrics_thread_run(); + +private: + void print_metrics(); + void print_disconnect(); + std::string float_to_string(float f, int digits); + std::string float_to_eng_string(float f, int digits); + std::string int_to_eng_string(int f, int digits); + + ue_metrics_interface *ue_; + + bool started; + bool do_print; + pthread_t metrics_thread; + ue_metrics_t metrics; + float metrics_report_period; // seconds + uint8_t n_reports; +}; + +} // namespace srsue + +#endif // METRICS_STDOUT_H diff --git a/srsue/hdr/phy/phch_common.h b/srsue/hdr/phy/phch_common.h new file mode 100644 index 000000000..7f0075e33 --- /dev/null +++ b/srsue/hdr/phy/phch_common.h @@ -0,0 +1,161 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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 UEPHYWORKERCOMMON_H +#define UEPHYWORKERCOMMON_H + +#include +#include +#include +#include "srslte/srslte.h" +#include "srslte/interfaces/ue_interfaces.h" +#include "srslte/radio/radio.h" +#include "srslte/common/log.h" +#include "phy/phy_metrics.h" + +//#define CONTINUOUS_TX + + +namespace srsue { + +/* Subclass that manages variables common to all workers */ + class phch_common { + public: + + /* Common variables used by all phy workers */ + phy_interface_rrc::phy_cfg_t *config; + phy_args_t *args; + srslte::log *log_h; + mac_interface_phy *mac; + srslte_ue_ul_t ue_ul; + + /* Power control variables */ + float pathloss; + float cur_pathloss; + float p0_preamble; + float cur_radio_power; + float cur_pusch_power; + float avg_rsrp_db; + float avg_rsrq_db; + float rx_gain_offset; + float avg_snr_db; + float avg_noise; + float avg_rsrp; + + phch_common(uint32_t max_mutex = 3); + void init(phy_interface_rrc::phy_cfg_t *config, + phy_args_t *args, + srslte::log *_log, + srslte::radio *_radio, + mac_interface_phy *_mac); + + /* For RNTI searches, -1 means now or forever */ + void set_ul_rnti(srslte_rnti_type_t type, uint16_t rnti_value, int tti_start = -1, int tti_end = -1); + uint16_t get_ul_rnti(uint32_t tti); + srslte_rnti_type_t get_ul_rnti_type(); + + void set_dl_rnti(srslte_rnti_type_t type, uint16_t rnti_value, int tti_start = -1, int tti_end = -1); + uint16_t get_dl_rnti(uint32_t tti); + srslte_rnti_type_t get_dl_rnti_type(); + + void set_rar_grant(uint32_t tti, uint8_t grant_payload[SRSLTE_RAR_GRANT_LEN]); + bool get_pending_rar(uint32_t tti, srslte_dci_rar_grant_t *rar_grant = NULL); + + void reset_pending_ack(uint32_t tti); + void set_pending_ack(uint32_t tti, uint32_t I_lowest, uint32_t n_dmrs); + bool get_pending_ack(uint32_t tti); + bool get_pending_ack(uint32_t tti, uint32_t *I_lowest, uint32_t *n_dmrs); + + void worker_end(uint32_t tti, bool tx_enable, cf_t *buffer, uint32_t nof_samples, srslte_timestamp_t tx_time); + + void set_nof_mutex(uint32_t nof_mutex); + + bool sr_enabled; + int sr_last_tx_tti; + + srslte::radio* get_radio(); + + void set_cell(const srslte_cell_t &c); + uint32_t get_nof_prb(); + void set_dl_metrics(const dl_metrics_t &m); + void get_dl_metrics(dl_metrics_t &m); + void set_ul_metrics(const ul_metrics_t &m); + void get_ul_metrics(ul_metrics_t &m); + void set_sync_metrics(const sync_metrics_t &m); + void get_sync_metrics(sync_metrics_t &m); + + void reset_ul(); + + private: + + std::vector tx_mutex; + + bool is_first_of_burst; + srslte::radio *radio_h; + float cfo; + + + bool ul_rnti_active(uint32_t tti); + bool dl_rnti_active(uint32_t tti); + uint16_t ul_rnti, dl_rnti; + srslte_rnti_type_t ul_rnti_type, dl_rnti_type; + int ul_rnti_start, ul_rnti_end, dl_rnti_start, dl_rnti_end; + + float time_adv_sec; + + srslte_dci_rar_grant_t rar_grant; + bool rar_grant_pending; + uint32_t rar_grant_tti; + + typedef struct { + bool enabled; + uint32_t I_lowest; + uint32_t n_dmrs; + } pending_ack_t; + pending_ack_t pending_ack[10]; + + bool is_first_tx; + + uint32_t nof_workers; + uint32_t nof_mutex; + uint32_t max_mutex; + + srslte_cell_t cell; + + dl_metrics_t dl_metrics; + uint32_t dl_metrics_count; + bool dl_metrics_read; + ul_metrics_t ul_metrics; + uint32_t ul_metrics_count; + bool ul_metrics_read; + sync_metrics_t sync_metrics; + uint32_t sync_metrics_count; + bool sync_metrics_read; + }; + +} // namespace srsue + +#endif // UEPHYWORKERCOMMON_H diff --git a/srsue/hdr/phy/phch_recv.h b/srsue/hdr/phy/phch_recv.h new file mode 100644 index 000000000..838d49d30 --- /dev/null +++ b/srsue/hdr/phy/phch_recv.h @@ -0,0 +1,122 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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 UEPHYRECV_H +#define UEPHYRECV_H + +#include "srslte/srslte.h" +#include "srslte/common/log.h" +#include "srslte/common/threads.h" +#include "srslte/common/thread_pool.h" +#include "srslte/radio/radio_multi.h" +#include "phy/prach.h" +#include "phy/phch_worker.h" +#include "phy/phch_common.h" +#include "srslte/interfaces/ue_interfaces.h" + +namespace srsue { + +typedef _Complex float cf_t; + +class phch_recv : public thread +{ +public: + phch_recv(); + void init(srslte::radio_multi* radio_handler, mac_interface_phy *mac,rrc_interface_phy *rrc, + prach *prach_buffer, srslte::thread_pool *_workers_pool, + phch_common *_worker_com, srslte::log* _log_h, uint32_t nof_rx_antennas, uint32_t prio, int sync_cpu_affinity = -1); + void stop(); + void set_agc_enable(bool enable); + + void resync_sfn(); + + uint32_t get_current_tti(); + + void sync_start(); + void sync_stop(); + bool status_is_sync(); + + void set_time_adv_sec(float time_adv_sec); + void get_current_cell(srslte_cell_t *cell); + + const static int MUTEX_X_WORKER = 4; + +private: + + void set_ue_sync_opts(srslte_ue_sync_t *q); + void run_thread(); + int sync_sfn(); + + bool running; + + srslte::radio_multi *radio_h; + mac_interface_phy *mac; + rrc_interface_phy *rrc; + srslte::log *log_h; + srslte::thread_pool *workers_pool; + phch_common *worker_com; + prach *prach_buffer; + + srslte_ue_sync_t ue_sync; + srslte_ue_mib_t ue_mib; + + uint32_t nof_rx_antennas; + + cf_t *sf_buffer_sfn[SRSLTE_MAX_PORTS]; + + // Sync metrics + sync_metrics_t metrics; + + enum { + IDLE, CELL_SEARCH, SYNCING, SYNC_DONE + } phy_state; + + srslte_cell_t cell; + bool cell_is_set; + bool is_sfn_synched; + bool started; + float time_adv_sec; + bool radio_is_streaming; + uint32_t tti; + bool do_agc; + + float last_gain; + float cellsearch_cfo; + uint32_t nof_tx_mutex; + uint32_t tx_mutex_cnt; + + uint32_t sync_sfn_cnt; + const static uint32_t SYNC_SFN_TIMEOUT = 5000; + float ul_dl_factor; + + bool cell_search(int force_N_id_2 = -1); + bool init_cell(); + void free_cell(); +}; + +} // namespace srsue + +#endif // UEPHYRECV_H diff --git a/srsue/hdr/phy/phch_worker.h b/srsue/hdr/phy/phch_worker.h new file mode 100644 index 000000000..669422981 --- /dev/null +++ b/srsue/hdr/phy/phch_worker.h @@ -0,0 +1,154 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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 UEPHYWORKER_H +#define UEPHYWORKER_H + +#include +#include "srslte/srslte.h" +#include "srslte/common/thread_pool.h" +#include "srslte/common/trace.h" +#include "phy/phch_common.h" + +#define LOG_EXECTIME + +namespace srsue { + +class phch_worker : public srslte::thread_pool::worker +{ +public: + + phch_worker(); + void reset(); + void set_common(phch_common *phy); + bool init_cell(srslte_cell_t cell); + void free_cell(); + + /* Functions used by main PHY thread */ + cf_t* get_buffer(uint32_t antenna_idx); + void set_tti(uint32_t tti, uint32_t tx_tti); + void set_tx_time(srslte_timestamp_t tx_time); + void set_cfo(float cfo); + void set_sample_offset(float sample_offset); + + void set_ul_params(bool pregen_disabled = false); + void set_crnti(uint16_t rnti); + void enable_pregen_signals(bool enabled); + + void start_trace(); + void write_trace(std::string filename); + + int read_ce_abs(float *ce_abs); + int read_pdsch_d(cf_t *pdsch_d); + void start_plot(); + +private: + /* Inherited from thread_pool::worker. Function called every subframe to run the DL/UL processing */ + void work_imp(); + + + /* Internal methods */ + bool extract_fft_and_pdcch_llr(); + + /* ... for DL */ + bool decode_pdcch_ul(mac_interface_phy::mac_grant_t *grant); + bool decode_pdcch_dl(mac_interface_phy::mac_grant_t *grant); + bool decode_phich(bool *ack); + bool decode_pdsch(srslte_ra_dl_grant_t *grant, uint8_t *payload, srslte_softbuffer_rx_t* softbuffer, int rv, uint16_t rnti, uint32_t pid); + + /* ... for UL */ + void encode_pusch(srslte_ra_ul_grant_t *grant, uint8_t *payload, uint32_t current_tx_nb, srslte_softbuffer_tx_t *softbuffer, + uint32_t rv, uint16_t rnti, bool is_from_rar); + void encode_pucch(); + void encode_srs(); + void reset_uci(); + void set_uci_sr(); + void set_uci_periodic_cqi(); + void set_uci_aperiodic_cqi(); + void set_uci_ack(bool ack); + bool srs_is_ready_to_send(); + float set_power(float tx_power); + void setup_tx_gain(); + + void update_measurements(); + + void tr_log_start(); + void tr_log_end(); + struct timeval tr_time[3]; + srslte::trace tr_exec; + bool trace_enabled; + + + /* Common objects */ + phch_common *phy; + srslte_cell_t cell; + bool cell_initiated; + cf_t *signal_buffer[SRSLTE_MAX_PORTS]; + uint32_t tti; + uint32_t tx_tti; + bool pregen_enabled; + uint32_t last_dl_pdcch_ncce; + bool rnti_is_set; + + /* Objects for DL */ + srslte_ue_dl_t ue_dl; + uint32_t cfi; + uint16_t dl_rnti; + + /* Objects for UL */ + srslte_ue_ul_t ue_ul; + srslte_timestamp_t tx_time; + srslte_uci_data_t uci_data; + uint16_t ul_rnti; + + // UL configuration parameters + srslte_refsignal_srs_cfg_t srs_cfg; + srslte_pucch_cfg_t pucch_cfg; + srslte_refsignal_dmrs_pusch_cfg_t dmrs_cfg; + srslte_pusch_hopping_cfg_t pusch_hopping; + srslte_pucch_sched_t pucch_sched; + srslte_uci_cfg_t uci_cfg; + srslte_cqi_periodic_cfg_t period_cqi; + srslte_ue_ul_powerctrl_t power_ctrl; + uint32_t I_sr; + float cfo; + bool rar_cqi_request; + + // Metrics + dl_metrics_t dl_metrics; + ul_metrics_t ul_metrics; + +#ifdef LOG_EXECTIME + struct timeval logtime_start[3]; + bool chest_done; +#endif + +}; + +} // namespace srsue + +#endif // UEPHYWORKER_H + diff --git a/srsue/hdr/phy/phy.h b/srsue/hdr/phy/phy.h new file mode 100644 index 000000000..b478bbcdd --- /dev/null +++ b/srsue/hdr/phy/phy.h @@ -0,0 +1,165 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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 UEPHY_H +#define UEPHY_H + +#include "srslte/srslte.h" +#include "srslte/common/log.h" +#include "phy/phy_metrics.h" +#include "phy/phch_recv.h" +#include "phy/prach.h" +#include "phy/phch_worker.h" +#include "phy/phch_common.h" +#include "srslte/radio/radio.h" +#include "srslte/common/task_dispatcher.h" +#include "srslte/common/trace.h" +#include "srslte/interfaces/ue_interfaces.h" + +namespace srsue { + +typedef _Complex float cf_t; + +class phy + : public phy_interface_mac + , public phy_interface_rrc +{ +public: + phy(); + bool init(srslte::radio_multi *radio_handler, + mac_interface_phy *mac, + rrc_interface_phy *rrc, + srslte::log *log_h, + phy_args_t *args = NULL); + + void stop(); + + void set_agc_enable(bool enabled); + + void get_metrics(phy_metrics_t &m); + + + + static uint32_t tti_to_SFN(uint32_t tti); + static uint32_t tti_to_subf(uint32_t tti); + + void enable_pregen_signals(bool enable); + + void start_trace(); + void write_trace(std::string filename); + + /********** RRC INTERFACE ********************/ + void reset(); + bool status_is_sync(); + void configure_ul_params(bool pregen_disabled = false); + void resync_sfn(); + + /********** MAC INTERFACE ********************/ + /* Functions to synchronize with a cell */ + void sync_start(); + void sync_stop(); + + /* Sets a C-RNTI allowing the PHY to pregenerate signals if necessary */ + void set_crnti(uint16_t rnti); + + /* Instructs the PHY to configure using the parameters written by set_param() */ + void configure_prach_params(); + + /* Transmits PRACH in the next opportunity */ + void prach_send(uint32_t preamble_idx, int allowed_subframe = -1, float target_power_dbm = 0.0); + int prach_tx_tti(); + + /* Indicates the transmission of a SR signal in the next opportunity */ + void sr_send(); + int sr_last_tx_tti(); + + // Time advance commands + void set_timeadv_rar(uint32_t ta_cmd); + void set_timeadv(uint32_t ta_cmd); + + /* Sets RAR grant payload */ + void set_rar_grant(uint32_t tti, uint8_t grant_payload[SRSLTE_RAR_GRANT_LEN]); + + /* Instruct the PHY to decode PDCCH with the CRC scrambled with given RNTI */ + void pdcch_ul_search(srslte_rnti_type_t rnti_type, uint16_t rnti, int tti_start = -1, int tti_end = -1); + void pdcch_dl_search(srslte_rnti_type_t rnti_type, uint16_t rnti, int tti_start = -1, int tti_end = -1); + void pdcch_ul_search_reset(); + void pdcch_dl_search_reset(); + + /* Get/Set PHY parameters interface from RRC */ + void get_config(phy_cfg_t *phy_cfg); + void set_config(phy_cfg_t *phy_cfg); + void set_config_dedicated(LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT *dedicated); + void set_config_common(phy_cfg_common_t *common); + void set_config_tdd(LIBLTE_RRC_TDD_CONFIG_STRUCT *tdd); + void set_config_64qam_en(bool enable); + + + float get_phr(); + float get_pathloss_db(); + + uint32_t get_current_tti(); + void get_current_cell(srslte_cell_t *cell); + + void start_plot(); + +private: + + uint32_t nof_workers; + + const static int MAX_WORKERS = 4; + const static int DEFAULT_WORKERS = 2; + + const static int SF_RECV_THREAD_PRIO = 1; + const static int WORKERS_THREAD_PRIO = 0; + + srslte::radio_multi *radio_handler; + srslte::log *log_h; + + srslte::thread_pool workers_pool; + std::vector workers; + phch_common workers_common; + phch_recv sf_recv; + prach prach_buffer; + + srslte_cell_t cell; + + phy_cfg_t config; + phy_args_t *args; + phy_args_t default_args; + + /* Current time advance */ + uint32_t n_ta; + + bool init_(srslte::radio *radio_handler, mac_interface_phy *mac, srslte::log *log_h, bool do_agc, uint32_t nof_workers); + void set_default_args(phy_args_t *args); + bool check_args(phy_args_t *args); + +}; + +} // namespace srsue + +#endif // UEPHY_H diff --git a/srsue/hdr/phy/phy_metrics.h b/srsue/hdr/phy/phy_metrics.h new file mode 100644 index 000000000..eafff2183 --- /dev/null +++ b/srsue/hdr/phy/phy_metrics.h @@ -0,0 +1,68 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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 UE_PHY_METRICS_H +#define UE_PHY_METRICS_H + + +namespace srsue { + +struct sync_metrics_t +{ + float cfo; + float sfo; +}; + +struct dl_metrics_t +{ + float n; + float sinr; + float rsrp; + float rsrq; + float rssi; + float turbo_iters; + float mcs; + float pathloss; + float mabr_mbps; +}; + +struct ul_metrics_t +{ + float mcs; + float power; + float mabr_mbps; +}; + +struct phy_metrics_t +{ + sync_metrics_t sync; + dl_metrics_t dl; + ul_metrics_t ul; +}; + +} // namespace srsue + +#endif // UE_PHY_METRICS_H diff --git a/srsue/hdr/phy/prach.h b/srsue/hdr/phy/prach.h new file mode 100644 index 000000000..694353926 --- /dev/null +++ b/srsue/hdr/phy/prach.h @@ -0,0 +1,87 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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 UEPRACH_H +#define UEPRACH_H + +#include + +#include "srslte/srslte.h" +#include "srslte/radio/radio.h" +#include "srslte/common/log.h" +#include "srslte/interfaces/ue_interfaces.h" + +namespace srsue { + + class prach { + public: + prach() { + bzero(&prach_obj, sizeof(srslte_prach_t)); + bzero(&cell, sizeof(srslte_cell_t)); + bzero(&cfo_h, sizeof(srslte_cfo_t)); + + args = NULL; + config = NULL; + initiated = false; + signal_buffer = NULL; + transmitted_tti = 0; + target_power_dbm = 0; + } + void init(LIBLTE_RRC_PRACH_CONFIG_SIB_STRUCT *config, phy_args_t *args, srslte::log *log_h); + bool init_cell(srslte_cell_t cell); + void free_cell(); + bool prepare_to_send(uint32_t preamble_idx, int allowed_subframe = -1, float target_power_dbm = -1); + bool is_ready_to_send(uint32_t current_tti); + int tx_tti(); + + void send(srslte::radio* radio_handler, float cfo, float pathloss, srslte_timestamp_t rx_time); + float get_p0_preamble(); + + static const uint32_t tx_advance_sf = 4; // Number of subframes to advance transmission + + private: + + LIBLTE_RRC_PRACH_CONFIG_SIB_STRUCT *config; + phy_args_t *args; + + srslte::log *log_h; + int preamble_idx; + int allowed_subframe; + bool initiated; + uint32_t len; + cf_t *buffer[64]; + srslte_prach_t prach_obj; + int transmitted_tti; + srslte_cell_t cell; + cf_t *signal_buffer; + srslte_cfo_t cfo_h; + float target_power_dbm; + + }; + +} // namespace srsue + +#endif // UEPRACH_H diff --git a/srsue/hdr/ue.h b/srsue/hdr/ue.h new file mode 100644 index 000000000..f401697e9 --- /dev/null +++ b/srsue/hdr/ue.h @@ -0,0 +1,201 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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: ue.h + * Description: Top-level UE class. Creates and links all + * layers and helpers. + *****************************************************************************/ + +#ifndef UE_H +#define UE_H + +#include +#include +#include + +#include "srslte/radio/radio_multi.h" +#include "phy/phy.h" +#include "mac/mac.h" +#include "srslte/upper/rlc.h" +#include "srslte/upper/pdcp.h" +#include "upper/rrc.h" +#include "upper/nas.h" +#include "srslte/upper/gw.h" +#include "upper/usim.h" + +#include "srslte/common/buffer_pool.h" +#include "srslte/interfaces/ue_interfaces.h" +#include "srslte/common/logger.h" +#include "srslte/common/log_filter.h" + +#include "ue_metrics_interface.h" + +namespace srsue { + +/******************************************************************************* + UE Parameters +*******************************************************************************/ + +typedef struct { + float dl_freq; + float ul_freq; + float rx_gain; + float tx_gain; + uint32_t nof_rx_ant; + std::string device_name; + std::string device_args; + std::string time_adv_nsamples; + std::string burst_preamble; +}rf_args_t; + +typedef struct { + bool enable; + std::string filename; +}pcap_args_t; + +typedef struct { + bool enable; + std::string phy_filename; + std::string radio_filename; +}trace_args_t; + +typedef struct { + std::string phy_level; + std::string mac_level; + std::string rlc_level; + std::string pdcp_level; + std::string rrc_level; + std::string gw_level; + std::string nas_level; + std::string usim_level; + std::string all_level; + int phy_hex_limit; + int mac_hex_limit; + int rlc_hex_limit; + int pdcp_hex_limit; + int rrc_hex_limit; + int gw_hex_limit; + int nas_hex_limit; + int usim_hex_limit; + int all_hex_limit; + std::string filename; +}log_args_t; + +typedef struct { + bool enable; +}gui_args_t; + +typedef struct { + phy_args_t phy; + float metrics_period_secs; + bool pregenerate_signals; + int ue_cateogry; + +}expert_args_t; + +typedef struct { + rf_args_t rf; + rf_cal_t rf_cal; + pcap_args_t pcap; + trace_args_t trace; + log_args_t log; + gui_args_t gui; + usim_args_t usim; + expert_args_t expert; +}all_args_t; + +/******************************************************************************* + Main UE class +*******************************************************************************/ + +class ue + :public ue_interface + ,public ue_metrics_interface +{ +public: + static ue* get_instance(void); + static void cleanup(void); + + bool init(all_args_t *args_); + void stop(); + bool is_attached(); + void start_plot(); + + static void rf_msg(srslte_rf_error_t error); + void handle_rf_msg(srslte_rf_error_t error); + + // UE metrics interface + bool get_metrics(ue_metrics_t &m); + + void pregenerate_signals(bool enable); + + // Testing + void test_con_restablishment(); + + +private: + static ue *instance; + ue(); + virtual ~ue(); + + srslte::radio_multi radio; + srsue::phy phy; + srsue::mac mac; + srslte::mac_pcap mac_pcap; + srslte::rlc rlc; + srslte::pdcp pdcp; + srsue::rrc rrc; + srsue::nas nas; + srslte::gw gw; + srsue::usim usim; + + srslte::logger logger; + srslte::log_filter rf_log; + srslte::log_filter phy_log; + srslte::log_filter mac_log; + srslte::log_filter rlc_log; + srslte::log_filter pdcp_log; + srslte::log_filter rrc_log; + srslte::log_filter nas_log; + srslte::log_filter gw_log; + srslte::log_filter usim_log; + + srslte::byte_buffer_pool *pool; + + all_args_t *args; + bool started; + rf_metrics_t rf_metrics; + + srslte::LOG_LEVEL_ENUM level(std::string l); + + bool check_srslte_version(); +}; + +} // namespace srsue + +#endif // UE_H + diff --git a/srsue/hdr/ue_metrics_interface.h b/srsue/hdr/ue_metrics_interface.h new file mode 100644 index 000000000..70688863e --- /dev/null +++ b/srsue/hdr/ue_metrics_interface.h @@ -0,0 +1,63 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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 UE_METRICS_INTERFACE_H +#define UE_METRICS_INTERFACE_H + +#include + +#include "srslte/upper/gw_metrics.h" +#include "srslte/upper/rlc_metrics.h" +#include "mac/mac_metrics.h" +#include "phy/phy_metrics.h" + +namespace srsue { + +typedef struct { + uint32_t rf_o; + uint32_t rf_u; + uint32_t rf_l; + bool rf_error; +}rf_metrics_t; + +typedef struct { + rf_metrics_t rf; + phy_metrics_t phy; + mac_metrics_t mac; + srslte::rlc_metrics_t rlc; + srslte::gw_metrics_t gw; +}ue_metrics_t; + +// UE interface +class ue_metrics_interface +{ +public: + virtual bool get_metrics(ue_metrics_t &m) = 0; +}; + +} // namespace srsue + +#endif // UE_METRICS_INTERFACE_H diff --git a/srsue/hdr/upper/nas.h b/srsue/hdr/upper/nas.h new file mode 100644 index 000000000..5e3a8b098 --- /dev/null +++ b/srsue/hdr/upper/nas.h @@ -0,0 +1,146 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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 NAS_H +#define NAS_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/asn1/liblte_mme.h" + +using srslte::byte_buffer_t; + +namespace srsue { + +// EMM states (3GPP 24.302 v10.0.0) +typedef enum{ + EMM_STATE_NULL = 0, + EMM_STATE_DEREGISTERED, + EMM_STATE_REGISTERED_INITIATED, + EMM_STATE_REGISTERED, + EMM_STATE_SERVICE_REQUEST_INITIATED, + EMM_STATE_DEREGISTERED_INITIATED, + EMM_STATE_TAU_INITIATED, + EMM_STATE_N_ITEMS, +}emm_state_t; +static const char emm_state_text[EMM_STATE_N_ITEMS][100] = {"NULL", + "DEREGISTERED", + "REGISTERED INITIATED", + "REGISTERED", + "SERVICE REQUEST INITIATED", + "DEREGISTERED INITIATED", + "TRACKING AREA UPDATE INITIATED"}; + +class nas + :public nas_interface_rrc +{ +public: + nas(); + void init(usim_interface_nas *usim_, + rrc_interface_nas *rrc_, + gw_interface_nas *gw_, + srslte::log *nas_log_); + void stop(); + + emm_state_t get_state(); + + // RRC interface + void notify_connection_setup(); + void write_pdu(uint32_t lcid, byte_buffer_t *pdu); + uint32_t get_ul_count(); + bool is_attached(); + bool get_s_tmsi(LIBLTE_RRC_S_TMSI_STRUCT *s_tmsi); + +private: + srslte::byte_buffer_pool *pool; + srslte::log *nas_log; + rrc_interface_nas *rrc; + usim_interface_nas *usim; + gw_interface_nas *gw; + + emm_state_t state; + + // Save short MAC + + // Identifiers + LIBLTE_MME_EPS_MOBILE_ID_GUTI_STRUCT guti; + bool is_guti_set; + + uint32_t ip_addr; + uint8_t eps_bearer_id; + + uint8_t transaction_id; + + // NAS counters - incremented for each security-protected message recvd/sent + uint32_t count_ul; + uint32_t count_dl; + + // Security + uint8_t ksi; + uint8_t k_nas_enc[32]; + uint8_t k_nas_int[32]; + + srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo; + srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo; + + void integrity_generate(uint8_t *key_128, + uint32_t count, + uint8_t rb_id, + uint8_t direction, + uint8_t *msg, + uint32_t msg_len, + uint8_t *mac); + void integrity_check(); + void cipher_encrypt(); + void cipher_decrypt(); + + // Parsers + void parse_attach_accept(uint32_t lcid, byte_buffer_t *pdu); + void parse_attach_reject(uint32_t lcid, byte_buffer_t *pdu); + void parse_authentication_request(uint32_t lcid, byte_buffer_t *pdu); + void parse_authentication_reject(uint32_t lcid, byte_buffer_t *pdu); + void parse_identity_request(uint32_t lcid, byte_buffer_t *pdu); + void parse_security_mode_command(uint32_t lcid, byte_buffer_t *pdu); + void parse_service_reject(uint32_t lcid, byte_buffer_t *pdu); + void parse_esm_information_request(uint32_t lcid, byte_buffer_t *pdu); + void parse_emm_information(uint32_t lcid, byte_buffer_t *pdu); + + // Senders + void send_attach_request(); + void send_identity_response(); + void send_service_request(); + void send_esm_information_response(); + + void gen_pdn_connectivity_request(LIBLTE_BYTE_MSG_STRUCT *msg); +}; + +} // namespace srsue + + +#endif // NAS_H diff --git a/srsue/hdr/upper/rrc.h b/srsue/hdr/upper/rrc.h new file mode 100644 index 000000000..cc1a22fd1 --- /dev/null +++ b/srsue/hdr/upper/rrc.h @@ -0,0 +1,211 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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 RRC_H +#define RRC_H + +#include "pthread.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 + +using srslte::byte_buffer_t; + +namespace srsue { + +// RRC states (3GPP 36.331 v10.0.0) +typedef enum{ + RRC_STATE_IDLE = 0, + RRC_STATE_SIB1_SEARCH, + RRC_STATE_SIB2_SEARCH, + RRC_STATE_WAIT_FOR_CON_SETUP, + RRC_STATE_COMPLETING_SETUP, + RRC_STATE_RRC_CONNECTED, + RRC_STATE_N_ITEMS, +}rrc_state_t; +static const char rrc_state_text[RRC_STATE_N_ITEMS][100] = {"IDLE", + "SIB1_SEARCH", + "SIB2_SEARCH", + "WAIT FOR CON SETUP", + "COMPLETING SETUP", + "RRC CONNECTED"}; + + +class rrc + :public rrc_interface_nas + ,public rrc_interface_phy + ,public rrc_interface_mac + ,public rrc_interface_gw + ,public rrc_interface_pdcp + ,public rrc_interface_rlc + ,public srslte::timer_callback +{ +public: + rrc(); + void init(phy_interface_rrc *phy_, + mac_interface_rrc *mac_, + rlc_interface_rrc *rlc_, + pdcp_interface_rrc *pdcp_, + nas_interface_rrc *nas_, + usim_interface_rrc *usim_, + srslte::mac_interface_timers *mac_timers_, + srslte::log *rrc_log_); + void stop(); + + rrc_state_t get_state(); + void set_ue_category(int category); + + // Timeout callback interface + void timer_expired(uint32_t timeout_id); + + void test_con_restablishment(); + void liblte_rrc_log(char* str); + +private: + srslte::byte_buffer_pool *pool; + srslte::log *rrc_log; + phy_interface_rrc *phy; + mac_interface_rrc *mac; + rlc_interface_rrc *rlc; + pdcp_interface_rrc *pdcp; + nas_interface_rrc *nas; + usim_interface_rrc *usim; + + srslte::bit_buffer_t bit_buf; + + pthread_mutex_t mutex; + + rrc_state_t state; + uint8_t transaction_id; + bool drb_up; + + uint8_t k_rrc_enc[32]; + uint8_t k_rrc_int[32]; + uint8_t k_up_enc[32]; + uint8_t k_up_int[32]; // Not used: only for relay nodes (3GPP 33.401 Annex A.7) + + srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo; + srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo; + + LIBLTE_RRC_MIB_STRUCT mib; + LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1_STRUCT sib1; + LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT sib2; + + std::map srbs; + std::map drbs; + + LIBLTE_RRC_DL_CCCH_MSG_STRUCT dl_ccch_msg; + LIBLTE_RRC_DL_DCCH_MSG_STRUCT dl_dcch_msg; + + pthread_t sib_search_thread; + + // RRC constants and timers + srslte::mac_interface_timers *mac_timers; + uint32_t n310_cnt, N310; + uint32_t n311_cnt, N311; + uint32_t t301, t310, t311; + uint32_t safe_reset_timer; + int ue_category; + + + // NAS interface + void write_sdu(uint32_t lcid, byte_buffer_t *sdu); + uint16_t get_mcc(); + uint16_t get_mnc(); + void enable_capabilities(); + + // PHY interface + void in_sync(); + void out_of_sync(); + + // MAC interface + void release_pucch_srs(); + void ra_problem(); + + // GW interface + bool rrc_connected(); + void rrc_connect(); + bool have_drb(); + + // PDCP interface + void write_pdu(uint32_t lcid, byte_buffer_t *pdu); + void write_pdu_bcch_bch(byte_buffer_t *pdu); + void write_pdu_bcch_dlsch(byte_buffer_t *pdu); + void write_pdu_pcch(byte_buffer_t *pdu); + + // RLC interface + void max_retx_attempted(); + + // Senders + void send_con_request(); + void send_con_restablish_request(); + void send_con_restablish_complete(); + void send_con_setup_complete(byte_buffer_t *nas_msg); + void send_ul_info_transfer(uint32_t lcid, byte_buffer_t *sdu); + void send_security_mode_complete(uint32_t lcid, byte_buffer_t *pdu); + void send_rrc_con_reconfig_complete(uint32_t lcid, byte_buffer_t *pdu); + void send_rrc_ue_cap_info(uint32_t lcid, byte_buffer_t *pdu); + + // Parsers + void parse_dl_ccch(byte_buffer_t *pdu); + void parse_dl_dcch(uint32_t lcid, byte_buffer_t *pdu); + void parse_dl_info_transfer(uint32_t lcid, byte_buffer_t *pdu); + + // Helpers + void reset_ue(); + void rrc_connection_release(); + void radio_link_failure(); + static void* start_sib_thread(void *rrc_); + void sib_search(); + uint32_t sib_start_tti(uint32_t tti, uint32_t period, uint32_t x); + void apply_sib2_configs(); + void handle_con_setup(LIBLTE_RRC_CONNECTION_SETUP_STRUCT *setup); + void handle_con_reest(LIBLTE_RRC_CONNECTION_REESTABLISHMENT_STRUCT *setup); + void handle_rrc_con_reconfig(uint32_t lcid, LIBLTE_RRC_CONNECTION_RECONFIGURATION_STRUCT *reconfig, byte_buffer_t *pdu); + void add_srb(LIBLTE_RRC_SRB_TO_ADD_MOD_STRUCT *srb_cnfg); + void add_drb(LIBLTE_RRC_DRB_TO_ADD_MOD_STRUCT *drb_cnfg); + void release_drb(uint8_t lcid); + void apply_rr_config_dedicated(LIBLTE_RRC_RR_CONFIG_DEDICATED_STRUCT *cnfg); + void apply_phy_config_dedicated(LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT *phy_cnfg, bool apply_defaults); + void apply_mac_config_dedicated(LIBLTE_RRC_MAC_MAIN_CONFIG_STRUCT *mac_cfg, bool apply_defaults); + + // Helpers for setting default values + void set_phy_default_pucch_srs(); + void set_phy_default(); + void set_mac_default(); + void set_rrc_default(); + +}; + +} // namespace srsue + + +#endif // RRC_H diff --git a/srsue/hdr/upper/usim.h b/srsue/hdr/upper/usim.h new file mode 100644 index 000000000..bb4e394bd --- /dev/null +++ b/srsue/hdr/upper/usim.h @@ -0,0 +1,127 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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 USIM_H +#define USIM_H + +#include +#include "srslte/common/log.h" +#include "srslte/common/common.h" +#include "srslte/interfaces/ue_interfaces.h" +#include "srslte/common/security.h" + +namespace srsue { + +typedef enum{ + auth_algo_milenage = 0, + auth_algo_xor, +}auth_algo_t; + +typedef struct{ + std::string algo; + std::string op; + std::string amf; + std::string imsi; + std::string imei; + std::string k; +}usim_args_t; + +class usim + :public usim_interface_nas + ,public usim_interface_rrc +{ +public: + usim(); + void init(usim_args_t *args, srslte::log *usim_log_); + void stop(); + + // NAS interface + void get_imsi_vec(uint8_t* imsi_, uint32_t n); + void get_imei_vec(uint8_t* imei_, uint32_t n); + + void generate_authentication_response(uint8_t *rand, + uint8_t *autn_enb, + uint16_t mcc, + uint16_t mnc, + bool *net_valid, + uint8_t *res); + + void generate_nas_keys(uint8_t *k_nas_enc, + uint8_t *k_nas_int, + srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo, + srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo); + + // RRC interface + void generate_as_keys(uint32_t count_ul, + uint8_t *k_rrc_enc, + uint8_t *k_rrc_int, + uint8_t *k_up_enc, + uint8_t *k_up_int, + srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo, + srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo); + + +private: + void gen_auth_res_milenage( uint8_t *rand, + uint8_t *autn_enb, + uint16_t mcc, + uint16_t mnc, + bool *net_valid, + uint8_t *res); + void gen_auth_res_xor( uint8_t *rand, + uint8_t *autn_enb, + uint16_t mcc, + uint16_t mnc, + bool *net_valid, + uint8_t *res); + void str_to_hex(std::string str, uint8_t *hex); + + srslte::log *usim_log; + + // User data + auth_algo_t auth_algo; + uint8_t amf[2]; // 3GPP 33.102 v10.0.0 Annex H + uint8_t op[16]; + uint64_t imsi; + uint64_t imei; + uint8_t k[16]; + + // Security variables + uint8_t rand[16]; + uint8_t ck[16]; + uint8_t ik[16]; + uint8_t ak[6]; + uint8_t mac[8]; + uint8_t autn[16]; + uint8_t k_asme[32]; + uint8_t k_enb[32]; + +}; + +} // namespace srsue + + +#endif // USIM_H diff --git a/srsue/src/CMakeLists.txt b/srsue/src/CMakeLists.txt new file mode 100644 index 000000000..ef31e90fe --- /dev/null +++ b/srsue/src/CMakeLists.txt @@ -0,0 +1,52 @@ +# +# Copyright 2013-2017 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/. +# + +add_subdirectory(phy) +add_subdirectory(mac) +add_subdirectory(upper) + +if (RPATH) + set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE) +endif (RPATH) + +add_executable(srsue main.cc ue.cc metrics_stdout.cc) +target_link_libraries(srsue srsue_mac + srsue_phy + srsue_upper + srslte_common + srslte_phy + srslte_upper + srslte_radio + ${CMAKE_THREAD_LIBS_INIT} + ${Boost_LIBRARIES}) + +if (RPATH) + set_target_properties(srsue PROPERTIES INSTALL_RPATH ".") +endif (RPATH) + +######################################################################## +# Option to run command after build (useful for remote builds) +######################################################################## +if (NOT ${BUILDUE_CMD} STREQUAL "") + message(STATUS "Added custom post-build-UE command: ${BUILDUE_CMD}") + add_custom_command(TARGET ue POST_BUILD COMMAND ${BUILDUE_CMD}) +else(NOT ${BUILDUE_CMD} STREQUAL "") + message(STATUS "No post-build-UE command defined") +endif (NOT ${BUILDUE_CMD} STREQUAL "") diff --git a/srsue/src/mac/CMakeLists.txt b/srsue/src/mac/CMakeLists.txt new file mode 100644 index 000000000..1aae8ffd6 --- /dev/null +++ b/srsue/src/mac/CMakeLists.txt @@ -0,0 +1,23 @@ +# +# Copyright 2013-2017 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(GLOB SOURCES "*.cc") +add_library(srsue_mac ${SOURCES}) +target_link_libraries(srsue_mac) diff --git a/srsue/src/mac/demux.cc b/srsue/src/mac/demux.cc new file mode 100644 index 000000000..c7c73a14b --- /dev/null +++ b/srsue/src/mac/demux.cc @@ -0,0 +1,206 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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/. + * + */ + + +#define Error(fmt, ...) log_h->error_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Warning(fmt, ...) log_h->warning_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Info(fmt, ...) log_h->info_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Debug(fmt, ...) log_h->debug_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) + +#include "mac/mac.h" +#include "mac/demux.h" +#include "srslte/interfaces/ue_interfaces.h" + +namespace srsue { + +demux::demux() : mac_msg(20), pending_mac_msg(20) +{ +} + +void demux::init(phy_interface_mac* phy_h_, rlc_interface_mac *rlc_, srslte::log* log_h_, srslte::timers* timers_db_) +{ + phy_h = phy_h_; + log_h = log_h_; + rlc = rlc_; + timers_db = timers_db_; + pdus.init(this, log_h); +} + +void demux::set_uecrid_callback(bool (*callback)(void*,uint64_t), void *arg) { + uecrid_callback = callback; + uecrid_callback_arg = arg; +} + +bool demux::get_uecrid_successful() { + return is_uecrid_successful; +} + +void demux::deallocate(uint8_t* payload_buffer_ptr) +{ + if (payload_buffer_ptr != bcch_buffer) { + pdus.deallocate(payload_buffer_ptr); + } +} + +uint8_t* demux::request_buffer(uint32_t pid, uint32_t len) +{ + uint8_t *buff = NULL; + if (pid < NOF_HARQ_PID) { + return pdus.request(len); + } else if (pid == NOF_HARQ_PID) { + buff = bcch_buffer; + } else { + Error("Requested buffer for invalid PID=%d\n", pid); + } + return buff; +} + +/* Demultiplexing of MAC PDU associated with a Temporal C-RNTI. The PDU will + * remain in buffer until demultiplex_pending_pdu() is called. + * This features is provided to enable the Random Access Procedure to decide + * wether the PDU shall pass to upper layers or not, which depends on the + * Contention Resolution result. + * + * Warning: this function does some processing here assuming ACK deadline is not an + * issue here because Temp C-RNTI messages have small payloads + */ +void demux::push_pdu_temp_crnti(uint8_t *buff, uint32_t nof_bytes) +{ + if (nof_bytes > 0) { + // Unpack DLSCH MAC PDU + pending_mac_msg.init_rx(nof_bytes); + pending_mac_msg.parse_packet(buff); + + // Look for Contention Resolution UE ID + is_uecrid_successful = false; + while(pending_mac_msg.next() && !is_uecrid_successful) { + if (pending_mac_msg.get()->ce_type() == srslte::sch_subh::CON_RES_ID) { + Debug("Found Contention Resolution ID CE\n"); + is_uecrid_successful = uecrid_callback(uecrid_callback_arg, pending_mac_msg.get()->get_con_res_id()); + } + } + + pending_mac_msg.reset(); + + Debug("Saved MAC PDU with Temporal C-RNTI in buffer\n"); + + pdus.push(buff, nof_bytes); + } else { + Warning("Trying to push PDU with payload size zero\n"); + } +} + +/* Demultiplexing of logical channels and dissassemble of MAC CE + * This function enqueues the packet and returns quicly because ACK + * deadline is important here. + */ +void demux::push_pdu(uint32_t pid, uint8_t *buff, uint32_t nof_bytes, uint32_t tstamp) +{ + if (pid < NOF_HARQ_PID) { + return pdus.push(buff, nof_bytes, tstamp); + } else if (pid == NOF_HARQ_PID) { + /* Demultiplexing of MAC PDU associated with SI-RNTI. The PDU passes through + * the MAC in transparent mode. + * Warning: In this case function sends the message to RLC now, since SI blocks do not + * require ACK feedback to be transmitted quickly. + */ + Debug("Pushed BCCH MAC PDU in transparent mode\n"); + rlc->write_pdu_bcch_dlsch(buff, nof_bytes); + } else { + Error("Pushed buffer for invalid PID=%d\n", pid); + } +} + +bool demux::process_pdus() +{ + return pdus.process_pdus(); +} + +void demux::process_pdu(uint8_t *mac_pdu, uint32_t nof_bytes, uint32_t tstamp) +{ + // Unpack DLSCH MAC PDU + mac_msg.init_rx(nof_bytes); + mac_msg.parse_packet(mac_pdu); + + process_sch_pdu(&mac_msg); + //srslte_vec_fprint_byte(stdout, mac_pdu, nof_bytes); + Debug("MAC PDU processed\n"); +} + +void demux::process_sch_pdu(srslte::sch_pdu *pdu_msg) +{ + while(pdu_msg->next()) { + if (pdu_msg->get()->is_sdu()) { + bool route_pdu = true; + if (pdu_msg->get()->get_sdu_lcid() == 0) { + uint8_t *x = pdu_msg->get()->get_sdu_ptr(); + uint32_t sum = 0; + for (uint32_t i=0;iget()->get_payload_size();i++) { + sum += x[i]; + } + if (sum == 0) { + route_pdu = false; + Warning("Received all zero PDU\n"); + } + } + // Route logical channel + if (route_pdu) { + Info("Delivering PDU for lcid=%d, %d bytes\n", pdu_msg->get()->get_sdu_lcid(), pdu_msg->get()->get_payload_size()); + rlc->write_pdu(pdu_msg->get()->get_sdu_lcid(), pdu_msg->get()->get_sdu_ptr(), pdu_msg->get()->get_payload_size()); + } + } else { + // Process MAC Control Element + if (!process_ce(pdu_msg->get())) { + Warning("Received Subheader with invalid or unkonwn LCID\n"); + } + } + } +} + +bool demux::process_ce(srslte::sch_subh *subh) { + switch(subh->ce_type()) { + case srslte::sch_subh::CON_RES_ID: + // Do nothing + break; + case srslte::sch_subh::TA_CMD: + phy_h->set_timeadv(subh->get_ta_cmd()); + Info("Received TA=%d\n", subh->get_ta_cmd()); + + // Start or restart timeAlignmentTimer + timers_db->get(mac::TIME_ALIGNMENT)->reset(); + timers_db->get(mac::TIME_ALIGNMENT)->run(); + break; + case srslte::sch_subh::PADDING: + break; + default: + Error("MAC CE 0x%x not supported\n", subh->ce_type()); + break; + } + return true; +} + + +} diff --git a/srsue/src/mac/dl_harq.cc b/srsue/src/mac/dl_harq.cc new file mode 100644 index 000000000..685224786 --- /dev/null +++ b/srsue/src/mac/dl_harq.cc @@ -0,0 +1,337 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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/. + * + */ + +#define Error(fmt, ...) log_h->error_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Warning(fmt, ...) log_h->warning_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Info(fmt, ...) log_h->info_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Debug(fmt, ...) log_h->debug_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) + +#include "mac/mac.h" +#include "mac/dl_harq.h" + + +namespace srsue { + + + /*********************************************************** + * + * HARQ ENTITY + * + *********************************************************/ + +dl_harq_entity::dl_harq_entity() +{ + pcap = NULL; +} + +bool dl_harq_entity::init(srslte::log* log_h_, mac_interface_rrc::mac_cfg_t *mac_cfg_, srslte::timers* timers_, demux *demux_unit_) +{ + timers_db = timers_; + demux_unit = demux_unit_; + mac_cfg = mac_cfg_; + si_window_start = 0; + log_h = log_h_; + for (uint32_t i=0;iget(mac::TIME_ALIGNMENT)->is_running()) { + //phy_h->send_sps_ack(); + Warning("PHY Send SPS ACK not implemented\n"); + } + } else { + Error("SPS not implemented\n"); + //dl_sps_assig.reset(grant.tti, grant); + //grant.ndi = true; + //procs[harq_pid].save_grant(); + } + } + } +} + +void dl_harq_entity::tb_decoded(bool ack, srslte_rnti_type_t rnti_type, uint32_t harq_pid) +{ + if (rnti_type == SRSLTE_RNTI_SI) { + proc[NOF_HARQ_PROC].tb_decoded(ack); + } else { + proc[harq_pid%NOF_HARQ_PROC].tb_decoded(ack); + } +} + +int dl_harq_entity::get_current_tbs(uint32_t harq_pid) +{ + return proc[harq_pid%NOF_HARQ_PROC].get_current_tbs(); +} + + +bool dl_harq_entity::generate_ack_callback(void *arg) +{ + demux *demux_unit = (demux*) arg; + return demux_unit->get_uecrid_successful(); +} + +void dl_harq_entity::set_si_window_start(int si_window_start_) +{ + si_window_start = si_window_start_; +} + +float dl_harq_entity::get_average_retx() +{ + return average_retx; +} + + /*********************************************************** + * + * HARQ PROCESS + * + *********************************************************/ + +dl_harq_entity::dl_harq_process::dl_harq_process() { + is_initiated = false; + ack = false; + bzero(&cur_grant, sizeof(mac_interface_phy::mac_grant_t)); +} + +void dl_harq_entity::dl_harq_process::reset() { + ack = false; + payload_buffer_ptr = NULL; + bzero(&cur_grant, sizeof(mac_interface_phy::mac_grant_t)); + if (is_initiated) { + srslte_softbuffer_rx_reset(&softbuffer); + } +} + +bool dl_harq_entity::dl_harq_process::init(uint32_t pid_, dl_harq_entity *parent) { + if (srslte_softbuffer_rx_init(&softbuffer, 110)) { + Error("Error initiating soft buffer\n"); + return false; + } else { + pid = pid_; + is_initiated = true; + harq_entity = parent; + log_h = harq_entity->log_h; + return true; + } +} + +bool dl_harq_entity::dl_harq_process::is_sps() +{ + return false; +} + +bool dl_harq_entity::dl_harq_process::calc_is_new_transmission(mac_interface_phy::mac_grant_t grant) { + + bool is_new_tb = true; + if ((srslte_tti_interval(grant.tti, cur_grant.tti) <= 8 && (grant.n_bytes == cur_grant.n_bytes)) || + pid == HARQ_BCCH_PID) + { + is_new_tb = false; + } + + if ((grant.ndi != cur_grant.ndi && !is_new_tb) || // NDI toggled for same TB + is_new_tb || // is new TB + (pid == HARQ_BCCH_PID && grant.rv == 0)) // Broadcast PID and 1st TX (RV=0) + { + is_new_transmission = true; + Debug("Set HARQ for new transmission\n"); + } else { + is_new_transmission = false; + Debug("Set HARQ for retransmission\n"); + } + + return is_new_transmission; +} + +void dl_harq_entity::dl_harq_process::new_grant_dl(mac_interface_phy::mac_grant_t grant, mac_interface_phy::tb_action_dl_t* action) +{ + // Compute RV for BCCH when not specified in PDCCH format + if (pid == HARQ_BCCH_PID && grant.rv == -1) { + uint32_t k; + if ((grant.tti/10)%2 == 0 && grant.tti%10 == 5) { // This is SIB1, k is different + k = (grant.tti/20)%4; + grant.rv = ((uint32_t) ceilf((float)1.5*k))%4; + } else if (grant.rv == -1) { + k = (grant.tti-harq_entity->si_window_start)%4; + grant.rv = ((uint32_t) ceilf((float)1.5*k))%4; + } + } + calc_is_new_transmission(grant); + if (is_new_transmission) { + ack = false; + srslte_softbuffer_rx_reset_tbs(&softbuffer, cur_grant.n_bytes*8); + n_retx = 0; + } + + // Save grant + grant.last_ndi = cur_grant.ndi; + grant.last_tti = cur_grant.tti; + memcpy(&cur_grant, &grant, sizeof(mac_interface_phy::mac_grant_t)); + + // Fill action structure + bzero(action, sizeof(mac_interface_phy::tb_action_dl_t)); + action->default_ack = ack; + action->generate_ack = true; + action->decode_enabled = false; + + // If data has not yet been successfully decoded + if (ack == false) { + + // Instruct the PHY To combine the received data and attempt to decode it + payload_buffer_ptr = harq_entity->demux_unit->request_buffer(pid, cur_grant.n_bytes); + action->payload_ptr = payload_buffer_ptr; + if (!action->payload_ptr) { + action->decode_enabled = false; + Error("Can't get a buffer for TBS=%d\n", cur_grant.n_bytes); + return; + } + action->decode_enabled = true; + action->rv = cur_grant.rv; + action->rnti = cur_grant.rnti; + action->softbuffer = &softbuffer; + memcpy(&action->phy_grant, &cur_grant.phy_grant, sizeof(srslte_phy_grant_t)); + n_retx++; + + } else { + Warning("DL PID %d: Received duplicate TB. Discarting and retransmitting ACK\n", pid); + } + + if (pid == HARQ_BCCH_PID || harq_entity->timers_db->get(mac::TIME_ALIGNMENT)->is_expired()) { + // Do not generate ACK + Debug("Not generating ACK\n"); + action->generate_ack = false; + } else { + if (cur_grant.rnti_type == SRSLTE_RNTI_TEMP && ack == false) { + // Postpone ACK after contention resolution is resolved + action->generate_ack_callback = harq_entity->generate_ack_callback; + action->generate_ack_callback_arg = harq_entity->demux_unit; + Debug("ACK pending contention resolution\n"); + } else { + Debug("Generating ACK\n"); + } + } +} + +int dl_harq_entity::dl_harq_process::get_current_tbs() +{ + return cur_grant.n_bytes*8; +} + +void dl_harq_entity::dl_harq_process::tb_decoded(bool ack_) +{ + ack = ack_; + if (ack == true) { + if (pid == HARQ_BCCH_PID) { + if (harq_entity->pcap) { + harq_entity->pcap->write_dl_sirnti(payload_buffer_ptr, cur_grant.n_bytes, ack, cur_grant.tti); + } + Debug("Delivering PDU=%d bytes to Dissassemble and Demux unit (BCCH)\n", cur_grant.n_bytes); + harq_entity->demux_unit->push_pdu(pid, payload_buffer_ptr, cur_grant.n_bytes, cur_grant.tti); + } else { + if (harq_entity->pcap) { + harq_entity->pcap->write_dl_crnti(payload_buffer_ptr, cur_grant.n_bytes, cur_grant.rnti, ack, cur_grant.tti); + } + if (ack) { + if (cur_grant.rnti_type == SRSLTE_RNTI_TEMP) { + Debug("Delivering PDU=%d bytes to Dissassemble and Demux unit (Temporal C-RNTI)\n", cur_grant.n_bytes); + harq_entity->demux_unit->push_pdu_temp_crnti(payload_buffer_ptr, cur_grant.n_bytes); + } else { + Debug("Delivering PDU=%d bytes to Dissassemble and Demux unit\n", cur_grant.n_bytes); + harq_entity->demux_unit->push_pdu(pid, payload_buffer_ptr, cur_grant.n_bytes, cur_grant.tti); + + // Compute average number of retransmissions per packet + harq_entity->average_retx = SRSLTE_VEC_CMA((float) n_retx, harq_entity->average_retx, harq_entity->nof_pkts++); + } + } + } + } else { + harq_entity->demux_unit->deallocate(payload_buffer_ptr); + } + + Info("DL %d: %s tbs=%d, rv=%d, ack=%s, ndi=%d (%d), tti=%d (%d)\n", + pid, is_new_transmission?"newTX":"reTX ", + cur_grant.n_bytes, cur_grant.rv, ack?"OK":"KO", + cur_grant.ndi, cur_grant.last_ndi, cur_grant.tti, cur_grant.last_tti); + + if (ack && pid == HARQ_BCCH_PID) { + reset(); + } +} + + + +} diff --git a/srsue/src/mac/mac.cc b/srsue/src/mac/mac.cc new file mode 100644 index 000000000..f583dd2df --- /dev/null +++ b/srsue/src/mac/mac.cc @@ -0,0 +1,545 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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/. + * + */ + +#define Error(fmt, ...) log_h->error_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Warning(fmt, ...) log_h->warning_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Info(fmt, ...) log_h->info_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Debug(fmt, ...) log_h->debug_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) + +#include +#include +#include +#include + +#include "srslte/common/log.h" +#include "mac/mac.h" +#include "srslte/common/pcap.h" + + +namespace srsue { + +mac::mac() : ttisync(10240), + timers_db((uint32_t) NOF_MAC_TIMERS), + pdu_process_thread(&demux_unit) +{ + started = false; + pcap = NULL; + signals_pregenerated = false; + bzero(&metrics, sizeof(mac_metrics_t)); +} + +bool mac::init(phy_interface_mac *phy, rlc_interface_mac *rlc, rrc_interface_mac *rrc, srslte::log *log_h_) +{ + started = false; + phy_h = phy; + rlc_h = rlc; + rrc_h = rrc; + log_h = log_h_; + tti = 0; + is_synchronized = false; + last_temporal_crnti = 0; + phy_rnti = 0; + + srslte_softbuffer_rx_init(&pch_softbuffer, 100); + + bsr_procedure.init( rlc_h, log_h, &config, &timers_db); + phr_procedure.init(phy_h, log_h, &config, &timers_db); + mux_unit.init ( rlc_h, log_h, &bsr_procedure, &phr_procedure); + demux_unit.init (phy_h, rlc_h, log_h, &timers_db); + ra_procedure.init (phy_h, rrc, log_h, &uernti, &config, &timers_db, &mux_unit, &demux_unit); + sr_procedure.init (phy_h, rrc, log_h, &config); + ul_harq.init ( log_h, &uernti, &config, &timers_db, &mux_unit); + dl_harq.init ( log_h, &config, &timers_db, &demux_unit); + + reset(); + + started = true; + start(MAC_MAIN_THREAD_PRIO); + + + return started; +} + +void mac::stop() +{ + started = false; + ttisync.increase(); + upper_timers_thread.thread_cancel(); + pdu_process_thread.stop(); + wait_thread_finish(); +} + +void mac::start_pcap(srslte::mac_pcap* pcap_) +{ + pcap = pcap_; + dl_harq.start_pcap(pcap); + ul_harq.start_pcap(pcap); + ra_procedure.start_pcap(pcap); +} + +// Implement Section 5.8 +void mac::reconfiguration() +{ + +} + +// Implement Section 5.9 +void mac::reset() +{ + bzero(&metrics, sizeof(mac_metrics_t)); + + Info("Resetting MAC\n"); + + timers_db.stop_all(); + upper_timers_thread.reset(); + + ul_harq.reset_ndi(); + + mux_unit.msg3_flush(); + mux_unit.reset(); + + ra_procedure.reset(); + sr_procedure.reset(); + bsr_procedure.reset(); + phr_procedure.reset(); + + dl_harq.reset(); + phy_h->pdcch_dl_search_reset(); + phy_h->pdcch_ul_search_reset(); + + signals_pregenerated = false; + is_first_ul_grant = true; + + bzero(&uernti, sizeof(ue_rnti_t)); +} + +void mac::run_thread() { + int cnt=0; + + Info("Waiting PHY to synchronize with cell\n"); + phy_h->sync_start(); + while(!phy_h->get_current_tti() && started) { + usleep(50000); + } + Debug("Setting ttysync to %d\n", phy_h->get_current_tti()); + ttisync.set_producer_cntr(phy_h->get_current_tti()); + + while(started) { + + /* Warning: Here order of invocation of procedures is important!! */ + ttisync.wait(); + tti = phy_h->get_current_tti(); + + if (started) { + log_h->step(tti); + + timers_db.step_all(); + + // Step all procedures + bsr_procedure.step(tti); + phr_procedure.step(tti); + + // Check if BSR procedure need to start SR + + if (bsr_procedure.need_to_send_sr(tti)) { + Debug("Starting SR procedure by BSR request, PHY TTI=%d\n", tti); + sr_procedure.start(); + } + if (bsr_procedure.need_to_reset_sr()) { + Debug("Resetting SR procedure by BSR request\n"); + sr_procedure.reset(); + } + sr_procedure.step(tti); + + // Check SR if we need to start RA + if (sr_procedure.need_random_access()) { + ra_procedure.start_mac_order(); + } + ra_procedure.step(tti); + + if (ra_procedure.is_successful() && !signals_pregenerated) { + + // Configure PHY to look for UL C-RNTI grants + phy_h->pdcch_ul_search(SRSLTE_RNTI_USER, uernti.crnti); + phy_h->pdcch_dl_search(SRSLTE_RNTI_USER, uernti.crnti); + + // Pregenerate UL signals and C-RNTI scrambling sequences + Debug("Pre-computing C-RNTI scrambling sequences for C-RNTI=0x%x\n", uernti.crnti); + phy_h->set_crnti(uernti.crnti); + signals_pregenerated = true; + } + } + } +} + +void mac::bcch_start_rx() +{ + bcch_start_rx(tti, -1); +} + +void mac::bcch_start_rx(int si_window_start, int si_window_length) +{ + if (si_window_length >= 0 && si_window_start >= 0) { + dl_harq.set_si_window_start(si_window_start); + phy_h->pdcch_dl_search(SRSLTE_RNTI_SI, SRSLTE_SIRNTI, si_window_start, si_window_start+si_window_length); + } else { + phy_h->pdcch_dl_search(SRSLTE_RNTI_SI, SRSLTE_SIRNTI, si_window_start); + } + Info("SCHED: Searching for DL grant for SI-RNTI window_st=%d, window_len=%d\n", si_window_start, si_window_length); +} + +void mac::bcch_stop_rx() +{ + phy_h->pdcch_dl_search_reset(); +} + +void mac::pcch_start_rx() +{ + phy_h->pdcch_dl_search(SRSLTE_RNTI_PCH, SRSLTE_PRNTI); + Info("SCHED: Searching for DL grant for P-RNTI\n"); +} + +void mac::pcch_stop_rx() +{ + phy_h->pdcch_dl_search_reset(); +} + + +void mac::tti_clock(uint32_t tti) +{ + ttisync.increase(); +} + +void mac::bch_decoded_ok(uint8_t* payload, uint32_t len) +{ + // Send MIB to RLC + rlc_h->write_pdu_bcch_bch(payload, len); + + if (pcap) { + pcap->write_dl_bch(payload, len, true, phy_h->get_current_tti()); + } +} + +void mac::pch_decoded_ok(uint32_t len) +{ + // Send PCH payload to RLC + rlc_h->write_pdu_pcch(pch_payload_buffer, len); + + if (pcap) { + pcap->write_dl_pch(pch_payload_buffer, len, true, phy_h->get_current_tti()); + } +} + +void mac::tb_decoded(bool ack, srslte_rnti_type_t rnti_type, uint32_t harq_pid) +{ + if (rnti_type == SRSLTE_RNTI_RAR) { + if (ack) { + ra_procedure.tb_decoded_ok(); + } + } else { + dl_harq.tb_decoded(ack, rnti_type, harq_pid); + if (ack) { + pdu_process_thread.notify(); + metrics.rx_brate += dl_harq.get_current_tbs(harq_pid); + } else { + metrics.rx_errors++; + } + metrics.rx_pkts++; + } +} + +void mac::new_grant_dl(mac_interface_phy::mac_grant_t grant, mac_interface_phy::tb_action_dl_t* action) +{ + if (grant.rnti_type == SRSLTE_RNTI_RAR) { + ra_procedure.new_grant_dl(grant, action); + } else if (grant.rnti_type == SRSLTE_RNTI_PCH) { + + memcpy(&action->phy_grant, &grant.phy_grant, sizeof(srslte_phy_grant_t)); + action->generate_ack = false; + action->decode_enabled = true; + srslte_softbuffer_rx_reset_cb(&pch_softbuffer, 1); + action->payload_ptr = pch_payload_buffer; + action->softbuffer = &pch_softbuffer; + action->rnti = grant.rnti; + action->rv = grant.rv; + if (grant.n_bytes > pch_payload_buffer_sz) { + Error("Received grant for PCH (%d bytes) exceeds buffer (%d bytes)\n", grant.n_bytes, pch_payload_buffer_sz); + action->decode_enabled = false; + } + } else { + // If PDCCH for C-RNTI and RA procedure in Contention Resolution, notify it + if (grant.rnti_type == SRSLTE_RNTI_USER && ra_procedure.is_contention_resolution()) { + ra_procedure.pdcch_to_crnti(false); + } + dl_harq.new_grant_dl(grant, action); + } +} + +uint32_t mac::get_current_tti() +{ + return phy_h->get_current_tti(); +} + +void mac::new_grant_ul(mac_interface_phy::mac_grant_t grant, mac_interface_phy::tb_action_ul_t* action) +{ + /* Start PHR Periodic timer on first UL grant */ + if (is_first_ul_grant) { + is_first_ul_grant = false; + timers_db.get(mac::PHR_TIMER_PERIODIC)->run(); + } + if (grant.rnti_type == SRSLTE_RNTI_USER && ra_procedure.is_contention_resolution()) { + ra_procedure.pdcch_to_crnti(true); + } + ul_harq.new_grant_ul(grant, action); + metrics.tx_pkts++; +} + +void mac::new_grant_ul_ack(mac_interface_phy::mac_grant_t grant, bool ack, mac_interface_phy::tb_action_ul_t* action) +{ + int tbs = ul_harq.get_current_tbs(tti); + ul_harq.new_grant_ul_ack(grant, ack, action); + if (!ack) { + metrics.tx_errors++; + } else { + metrics.tx_brate += tbs; + } + metrics.tx_pkts++; + if (!ack && ra_procedure.is_contention_resolution()) { + ra_procedure.harq_retx(); + } + if (grant.rnti_type == SRSLTE_RNTI_USER && ra_procedure.is_contention_resolution()) { + ra_procedure.pdcch_to_crnti(true); + } +} + +void mac::harq_recv(uint32_t tti, bool ack, mac_interface_phy::tb_action_ul_t* action) +{ + int tbs = ul_harq.get_current_tbs(tti); + ul_harq.harq_recv(tti, ack, action); + if (!ack) { + metrics.tx_errors++; + metrics.tx_pkts++; + } else { + metrics.tx_brate += tbs; + } + if (!ack && ra_procedure.is_contention_resolution()) { + ra_procedure.harq_retx(); + } +} + +void mac::setup_timers() +{ + int value = liblte_rrc_time_alignment_timer_num[config.main.time_alignment_timer]; + if (value > 0) { + timers_db.get(TIME_ALIGNMENT)->set(this, value); + } +} + +void mac::timer_expired(uint32_t timer_id) +{ + switch(timer_id) { + case TIME_ALIGNMENT: + timeAlignmentTimerExpire(); + break; + default: + break; + } +} + +/* Function called on expiry of TimeAlignmentTimer */ +void mac::timeAlignmentTimerExpire() +{ + printf("timeAlignmentTimer has expired value=%d ms\n", timers_db.get(TIME_ALIGNMENT)->get_timeout()); + rrc_h->release_pucch_srs(); + dl_harq.reset(); + ul_harq.reset(); +} + +void mac::get_rntis(ue_rnti_t* rntis) +{ + memcpy(rntis, &uernti, sizeof(ue_rnti_t)); +} + +void mac::set_contention_id(uint64_t uecri) +{ + uernti.contention_id = uecri; +} + +void mac::get_config(mac_cfg_t* mac_cfg) +{ + memcpy(mac_cfg, &config, sizeof(mac_cfg_t)); +} + +void mac::set_config(mac_cfg_t* mac_cfg) +{ + memcpy(&config, mac_cfg, sizeof(mac_cfg_t)); + setup_timers(); +} + +void mac::set_config_main(LIBLTE_RRC_MAC_MAIN_CONFIG_STRUCT* main_cfg) +{ + memcpy(&config.main, main_cfg, sizeof(LIBLTE_RRC_MAC_MAIN_CONFIG_STRUCT)); + setup_timers(); +} + +void mac::set_config_rach(LIBLTE_RRC_RACH_CONFIG_COMMON_STRUCT* rach_cfg, uint32_t prach_config_index) +{ + memcpy(&config.rach, rach_cfg, sizeof(LIBLTE_RRC_RACH_CONFIG_COMMON_STRUCT)); + config.prach_config_index = prach_config_index; +} + +void mac::set_config_sr(LIBLTE_RRC_SCHEDULING_REQUEST_CONFIG_STRUCT* sr_cfg) +{ + memcpy(&config.sr, sr_cfg, sizeof(LIBLTE_RRC_SCHEDULING_REQUEST_CONFIG_STRUCT)); +} + +void mac::setup_lcid(uint32_t lcid, uint32_t lcg, uint32_t priority, int PBR_x_tti, uint32_t BSD) +{ + Info("Logical Channel Setup: LCID=%d, LCG=%d, priority=%d, PBR=%d, BSd=%d\n", + lcid, lcg, priority, PBR_x_tti, BSD); + mux_unit.set_priority(lcid, priority, PBR_x_tti, BSD); + bsr_procedure.setup_lcg(lcid, lcg); + bsr_procedure.set_priority(lcid, priority); +} + +uint32_t mac::get_unique_id() +{ + return upper_timers_thread.get_unique_id(); +} + +/* Front-end to upper-layer timers */ +srslte::timers::timer* mac::get(uint32_t timer_id) +{ + return upper_timers_thread.get(timer_id); +} + + +void mac::get_metrics(mac_metrics_t &m) +{ + Info("DL retx: %.2f \%%, perpkt: %.2f, UL retx: %.2f \%% perpkt: %.2f\n", + metrics.rx_pkts?((float) 100*metrics.rx_errors/metrics.rx_pkts):0.0, + dl_harq.get_average_retx(), + metrics.tx_pkts?((float) 100*metrics.tx_errors/metrics.tx_pkts):0.0, + dl_harq.get_average_retx()); + + metrics.ul_buffer = (int) bsr_procedure.get_buffer_state(); + m = metrics; + bzero(&metrics, sizeof(mac_metrics_t)); +} + + +/******************************************************** + * + * Class to run upper-layer timers with normal priority + * + *******************************************************/ + +mac::upper_timers::upper_timers() : timers_db(MAC_NOF_UPPER_TIMERS) +{ + start_periodic(1000, MAC_MAIN_THREAD_PRIO+1); +} + +void mac::upper_timers::run_period() +{ + timers_db.step_all(); +} + +srslte::timers::timer* mac::upper_timers::get(uint32_t timer_id) +{ + return timers_db.get(timer_id%MAC_NOF_UPPER_TIMERS); +} + +uint32_t mac::upper_timers::get_unique_id() +{ + return timers_db.get_unique_id(); +} + +void mac::upper_timers::reset() +{ + timers_db.stop_all(); +} + + + + +/******************************************************** + * + * Class that runs a thread to process DL MAC PDUs from + * DEMU unit + * + *******************************************************/ +mac::pdu_process::pdu_process(demux *demux_unit_) +{ + demux_unit = demux_unit_; + pthread_mutex_init(&mutex, NULL); + pthread_cond_init(&cvar, NULL); + have_data = false; + start(MAC_PDU_THREAD_PRIO); +} + +void mac::pdu_process::stop() +{ + pthread_mutex_lock(&mutex); + running = false; + pthread_cond_signal(&cvar); + pthread_mutex_unlock(&mutex); + + wait_thread_finish(); +} + +void mac::pdu_process::notify() +{ + pthread_mutex_lock(&mutex); + have_data = true; + pthread_cond_signal(&cvar); + pthread_mutex_unlock(&mutex); +} + +void mac::pdu_process::run_thread() +{ + running = true; + while(running) { + have_data = demux_unit->process_pdus(); + if (!have_data) { + pthread_mutex_lock(&mutex); + while(!have_data && running) { + pthread_cond_wait(&cvar, &mutex); + } + pthread_mutex_unlock(&mutex); + } + } +} + + + + + + + +} + + + diff --git a/srsue/src/mac/mux.cc b/srsue/src/mac/mux.cc new file mode 100644 index 000000000..58ba3d57f --- /dev/null +++ b/srsue/src/mac/mux.cc @@ -0,0 +1,359 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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/. + * + */ + +#define Error(fmt, ...) log_h->error_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Warning(fmt, ...) log_h->warning_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Info(fmt, ...) log_h->info_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Debug(fmt, ...) log_h->debug_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) + +#include "mac/mux.h" +#include "mac/mac.h" + +#include +#include + +namespace srsue { + +mux::mux() : pdu_msg(MAX_NOF_SUBHEADERS) +{ + pthread_mutex_init(&mutex, NULL); + + pending_crnti_ce = 0; + + log_h = NULL; + rlc = NULL; + bsr_procedure = NULL; + phr_procedure = NULL; + + msg3_flush(); +} + +void mux::init(rlc_interface_mac *rlc_, srslte::log *log_h_, bsr_proc *bsr_procedure_, phr_proc *phr_procedure_) +{ + log_h = log_h_; + rlc = rlc_; + bsr_procedure = bsr_procedure_; + phr_procedure = phr_procedure_; + reset(); +} + +void mux::reset() +{ + lch.clear(); + pending_crnti_ce = 0; +} + +bool mux::is_pending_any_sdu() +{ + for (uint32_t i=0;iget_buffer_state(lch[i].id)) { + return true; + } + } + return false; +} + +bool mux::is_pending_sdu(uint32_t lch_id) { + return rlc->get_buffer_state(lch_id)>0; +} + +int mux::find_lchid(uint32_t lcid) +{ + for (uint32_t i=0;i= 0) { + lch.erase(lch.begin()+pos); + } else { + Error("Deleting logical channel id %d. Does not exist\n", lch_id); + } +} + +void mux::set_priority(uint32_t lch_id, uint32_t new_priority, int set_PBR, uint32_t set_BSD) +{ + int pos = find_lchid(lch_id); + + // Create new channel if it does not exist + if (pos < 0) { + lchid_t ch; + ch.id = lch_id; + ch.priority = new_priority; + ch.BSD = set_BSD; + ch.PBR = set_PBR; + ch.Bj = 0; + lch.push_back(ch); + } else { + lch[pos].priority = new_priority; + lch[pos].PBR = set_PBR; + lch[pos].BSD = set_BSD; + } + + // sort according to priority (increasing is lower priority) + std::sort(lch.begin(), lch.end(), sortPriority); +} + +srslte::sch_subh::cetype bsr_format_convert(bsr_proc::bsr_format_t format) { + switch(format) { + case bsr_proc::LONG_BSR: + return srslte::sch_subh::LONG_BSR; + case bsr_proc::TRUNC_BSR: + return srslte::sch_subh::TRUNC_BSR; + case bsr_proc::SHORT_BSR: + default: + return srslte::sch_subh::SHORT_BSR; + } +} + +void mux::pusch_retx(uint32_t tx_tti, uint32_t pid) +{ + if (pid_has_bsr[pid%MAX_HARQ_PROC]) { + bsr_procedure->set_tx_tti(tx_tti); + } +} + +// Multiplexing and logical channel priorization as defined in Section 5.4.3 +uint8_t* mux::pdu_get(uint8_t *payload, uint32_t pdu_sz, uint32_t tx_tti, uint32_t pid) +{ + pthread_mutex_lock(&mutex); + + // Update Bj + for (uint32_t i=0;i= 0) { + lch[i].Bj += lch[i].PBR; + } + if (lch[i].Bj >= (int)lch[i].BSD) { + lch[i].Bj = lch[i].BSD*lch[i].PBR; + } + } + +// Logical Channel Procedure + + pdu_msg.init_tx(payload, pdu_sz, true); + + // MAC control element for C-RNTI or data from UL-CCCH + if (!allocate_sdu(0, &pdu_msg, -1)) { + if (pending_crnti_ce) { + if (pdu_msg.new_subh()) { + if (!pdu_msg.get()->set_c_rnti(pending_crnti_ce)) { + Warning("Pending C-RNTI CE could not be inserted in MAC PDU\n"); + } + } + } + } + pending_crnti_ce = 0; + + bsr_proc::bsr_t bsr; + bool regular_bsr = bsr_procedure->need_to_send_bsr_on_ul_grant(pdu_msg.rem_size(), &bsr); + bool bsr_is_inserted = false; + + // MAC control element for BSR, with exception of BSR included for padding; + if (regular_bsr) { + if (pdu_msg.new_subh()) { + pdu_msg.get()->set_bsr(bsr.buff_size, bsr_format_convert(bsr.format)); + bsr_is_inserted = true; + } + } + // MAC control element for PHR + float phr_value; + if (phr_procedure->generate_phr_on_ul_grant(&phr_value)) { + if (pdu_msg.new_subh()) { + pdu_msg.get()->set_phr(phr_value); + } + } + // Update buffer states for all logical channels + int sdu_space = pdu_msg.get_sdu_space(); + for (uint32_t i=0;iget_buffer_state(lch[i].id); + lch[i].sched_len = 0; + } + + // data from any Logical Channel, except data from UL-CCCH; + // first only those with positive Bj + for (uint32_t i=0;i= 0) { + lch[i].Bj -= lch[i].sched_len; + } + } + } + + // If resources remain, allocate regardless of their Bj value + for (uint32_t i=0;i 0) { + for (int i=(int)lch.size()-1;i>=0;i--) { + if (lch[i].sched_len > 0) { + lch[i].sched_len = -1; + break; + } + } + } + // Now allocate the SDUs from the RLC + for (uint32_t i=0;iinfo("Allocating scheduled lch=%d len=%d\n", lch[i].id, lch[i].sched_len); + allocate_sdu(lch[i].id, &pdu_msg, lch[i].sched_len); + } + } + + if (!regular_bsr) { + // Insert Padding BSR if not inserted Regular/Periodic BSR + if (bsr_procedure->generate_padding_bsr(pdu_msg.rem_size(), &bsr)) { + if (pdu_msg.new_subh()) { + pdu_msg.get()->set_bsr(bsr.buff_size, bsr_format_convert(bsr.format)); + bsr_is_inserted = true; + } + } + } + + log_h->debug("Assembled MAC PDU msg size %d/%d bytes\n", pdu_msg.get_pdu_len()-pdu_msg.rem_size(), pdu_sz); + + /* Generate MAC PDU and save to buffer */ + uint8_t *ret = pdu_msg.write_packet(log_h); + + pid_has_bsr[pid%MAX_HARQ_PROC] = bsr_is_inserted; + if (bsr_is_inserted) { + bsr_procedure->set_tx_tti(tx_tti); + } + + pthread_mutex_unlock(&mutex); + + + return ret; +} + +void mux::append_crnti_ce_next_tx(uint16_t crnti) { + pending_crnti_ce = crnti; +} + +bool mux::sched_sdu(lchid_t *ch, int *sdu_space, int max_sdu_sz) +{ + + if (*sdu_space > 0) { + // Get n-th pending SDU pointer and length + int sched_len = ch->buffer_len; + if (sched_len > 0) { // there is pending SDU to allocate + if (sched_len > max_sdu_sz && max_sdu_sz >= 0) { + sched_len = max_sdu_sz; + } + if (sched_len > *sdu_space) { + sched_len = *sdu_space; + } + + log_h->info("SDU: scheduled lcid=%d, rlc_buffer=%d, allocated=%d/%d\n", + ch->id, ch->buffer_len, sched_len, *sdu_space); + + *sdu_space -= sched_len; + ch->buffer_len -= sched_len; + ch->sched_len += sched_len; + return true; + } + } + return false; +} + +bool mux::allocate_sdu(uint32_t lcid, srslte::sch_pdu* pdu_msg, int max_sdu_sz) +{ + + // Get n-th pending SDU pointer and length + int sdu_len = rlc->get_buffer_state(lcid); + + if (sdu_len > 0) { // there is pending SDU to allocate + int buffer_state = sdu_len; + if (sdu_len > max_sdu_sz && max_sdu_sz >= 0) { + sdu_len = max_sdu_sz; + } + int sdu_space = pdu_msg->get_sdu_space(); + if (sdu_len > sdu_space) { + sdu_len = sdu_space; + } + if (sdu_len > MIN_RLC_SDU_LEN) { + if (pdu_msg->new_subh()) { // there is space for a new subheader + int sdu_len2 = sdu_len; + sdu_len = pdu_msg->get()->set_sdu(lcid, sdu_len, rlc); + if (sdu_len > 0) { // new SDU could be added + + Info("SDU: allocated lcid=%d, rlc_buffer=%d, allocated=%d/%d, max_sdu_sz=%d, remaining=%d\n", + lcid, buffer_state, sdu_len, sdu_space, max_sdu_sz, pdu_msg->rem_size()); + return true; + } else { + Warning("SDU: rlc_buffer=%d, allocated=%d/%d, remaining=%d\n", + buffer_state, sdu_len, sdu_space, pdu_msg->rem_size()); + pdu_msg->del_subh(); + } + } + } + } + return false; +} + +void mux::msg3_flush() +{ + if (log_h) { + Debug("Msg3 buffer flushed\n"); + } + msg3_has_been_transmitted = false; + bzero(msg3_buff, sizeof(MSG3_BUFF_SZ)); +} + +bool mux::msg3_is_transmitted() +{ + return msg3_has_been_transmitted; +} + +/* Returns a pointer to the Msg3 buffer */ +uint8_t* mux::msg3_get(uint8_t *payload, uint32_t pdu_sz) +{ + uint8_t* msg3_buff_start_pdu = pdu_get(msg3_buff, pdu_sz, 0, 0); + if (!msg3_buff_start_pdu) { + Error("Moving PDU from Mux unit to Msg3 buffer\n"); + return NULL; + } + memcpy(payload, msg3_buff_start_pdu, sizeof(uint8_t)*pdu_sz); + msg3_has_been_transmitted = true; + return payload; +} + + +} diff --git a/srsue/src/mac/proc_bsr.cc b/srsue/src/mac/proc_bsr.cc new file mode 100644 index 000000000..d93b7f0f4 --- /dev/null +++ b/srsue/src/mac/proc_bsr.cc @@ -0,0 +1,407 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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/. + * + */ + +#define Error(fmt, ...) log_h->error_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Warning(fmt, ...) log_h->warning_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Info(fmt, ...) log_h->info_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Debug(fmt, ...) log_h->debug_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) + +#include "mac/proc_bsr.h" +#include "mac/mac.h" +#include "mac/mux.h" + + + namespace srsue { + +bsr_proc::bsr_proc() +{ + initiated = false; + last_print = 0; + next_tx_tti = 0; + triggered_bsr_type=NONE; + +} + +void bsr_proc::init(rlc_interface_mac *rlc_, srslte::log* log_h_, mac_interface_rrc::mac_cfg_t *mac_cfg_, srslte::timers *timers_db_) +{ + log_h = log_h_; + rlc = rlc_; + mac_cfg = mac_cfg_; + timers_db = timers_db_; + reset(); + initiated = true; +} + +void bsr_proc::reset() +{ + timers_db->get(mac::BSR_TIMER_PERIODIC)->stop(); + timers_db->get(mac::BSR_TIMER_PERIODIC)->reset(); + timers_db->get(mac::BSR_TIMER_RETX)->stop(); + timers_db->get(mac::BSR_TIMER_RETX)->reset(); + + reset_sr = false; + sr_is_sent = false; + triggered_bsr_type = NONE; + for (int i=0;imain.ulsch_cnfg.periodic_bsr_timer]; + if (periodic >= 0) { + triggered_bsr_type = REGULAR; + Debug("BSR: Triggering BSR reTX\n"); + sr_is_sent = false; + } + break; + } +} + +// Checks if data is available for a a channel with higher priority than others +bool bsr_proc::check_highest_channel() { + int pending_data_lcid = -1; + + for (int i=0;i= 0) { + if (rlc->get_buffer_state(i) > 0) { + pending_data_lcid = i; + for (int j=0;jget_buffer_state(j) > 0) { + if (priorities[j] > priorities[i]) { + pending_data_lcid = -1; + } + } + } + } + } + } + if (pending_data_lcid >= 0) { + // If there is new data available for this logical channel + uint32_t nbytes = rlc->get_buffer_state(pending_data_lcid); + if (nbytes > last_pending_data[pending_data_lcid]) + { + if (triggered_bsr_type != REGULAR) { + Debug("BSR: Triggered REGULAR BSR for Max Priority LCID=%d\n", pending_data_lcid); + } + triggered_bsr_type = REGULAR; + return true; + } + } + return false; +} + +uint32_t bsr_proc::get_buffer_state() { + uint32_t buffer = 0; + for (int i=0;i= 0) { + buffer += rlc->get_buffer_state(i); + } + } + return buffer; +} + +// Checks if only one logical channel has data avaiable for Tx +bool bsr_proc::check_single_channel() { + uint32_t pending_data_lcid = 0; + uint32_t nof_nonzero_lcid = 0; + + for (int i=0;i= 0) { + if (rlc->get_buffer_state(i) > 0) { + pending_data_lcid = i; + nof_nonzero_lcid++; + } + } + } + if (nof_nonzero_lcid == 1) { + uint32_t nbytes = rlc->get_buffer_state(pending_data_lcid); + // If there is new data available for this logical channel + if (nbytes > last_pending_data[pending_data_lcid]) { + triggered_bsr_type = REGULAR; + Debug("BSR: Triggered REGULAR BSR for single LCID=%d\n", pending_data_lcid); + return true; + } + } + return false; +} + +void bsr_proc::update_pending_data() { + for (int i=0;iget_buffer_state(i); + } +} + +bool bsr_proc::generate_bsr(bsr_t *bsr, uint32_t nof_padding_bytes) { + bool ret = false; + uint32_t nof_lcg=0; + bzero(bsr, sizeof(bsr_t)); + for (int i=0;i= 0) { + uint32_t n = rlc->get_buffer_state(i); + bsr->buff_size[lcg[i]] += n; + if (n > 0) { + nof_lcg++; + ret = true; + } + } + } + if (triggered_bsr_type == PADDING) { + if (nof_padding_bytes < 4) { + // If space only for short + if (nof_lcg > 1) { + bsr->format = TRUNC_BSR; + uint32_t max_prio_ch = find_max_priority_lcid(); + for (int i=0;i<4;i++) { + if (lcg[max_prio_ch] != i) { + bsr->buff_size[i] = 0; + } + } + } else { + bsr->format = SHORT_BSR; + } + } else { + // If space for long BSR + bsr->format = LONG_BSR; + } + } else { + bsr->format = SHORT_BSR; + if (nof_lcg > 1) { + bsr->format = LONG_BSR; + } + } + return ret; +} + +// Checks if Regular BSR must be assembled, as defined in 5.4.5 +// Padding BSR is assembled when called by mux_unit when UL grant is received +// Periodic BSR is triggered by the expiration of the timers +void bsr_proc::step(uint32_t tti) +{ + if (!initiated) { + return; + } + + int periodic = liblte_rrc_periodic_bsr_timer_num[mac_cfg->main.ulsch_cnfg.periodic_bsr_timer]; + if (periodic > 0 && (uint32_t)periodic != timers_db->get(mac::BSR_TIMER_PERIODIC)->get_timeout()) + { + timers_db->get(mac::BSR_TIMER_PERIODIC)->set(this, periodic); + timers_db->get(mac::BSR_TIMER_PERIODIC)->run(); + Info("BSR: Configured timer periodic %d ms\n", periodic); + } + int retx = liblte_rrc_retransmission_bsr_timer_num[mac_cfg->main.ulsch_cnfg.retx_bsr_timer]; + if (retx > 0 && (uint32_t)retx != timers_db->get(mac::BSR_TIMER_RETX)->get_timeout()) + { + timers_db->get(mac::BSR_TIMER_RETX)->set(this, retx); + timers_db->get(mac::BSR_TIMER_RETX)->run(); + Info("BSR: Configured timer reTX %d ms\n", retx); + } + + // Check condition 1 in Sec 5.4.5 + if (triggered_bsr_type == NONE) { + check_single_channel(); + } + // Higher priority channel is reported regardless of a BSR being already triggered + check_highest_channel(); + + update_pending_data(); + + + if ((tti - last_print)%10240 > QUEUE_STATUS_PERIOD_MS) { + char str[128]; + bzero(str, 128); + for (int i=0;iget_buffer_state(i), last_pending_data[i]); + } + Info("BSR: QUEUE status: %s\n", str); + last_print = tti; + } + +} + +char* bsr_proc::bsr_type_tostring(triggered_bsr_type_t type) { + switch(type) { + case bsr_proc::REGULAR: + return (char*) "Regular"; + case bsr_proc::PADDING: + return (char*) "Padding"; + case bsr_proc::PERIODIC: + return (char*) "Periodic"; + default: + return (char*) "Regular"; + } +} + +char* bsr_proc::bsr_format_tostring(bsr_format_t format) { + switch(format) { + case bsr_proc::LONG_BSR: + return (char*) "Long"; + case bsr_proc::SHORT_BSR: + return (char*) "Short"; + case bsr_proc::TRUNC_BSR: + return (char*) "Truncated"; + default: + return (char*) "Short"; + } +} + +bool bsr_proc::need_to_send_bsr_on_ul_grant(uint32_t grant_size, bsr_t *bsr) +{ + bool ret = false; + + uint32_t bsr_sz = 0; + if (triggered_bsr_type == PERIODIC || triggered_bsr_type == REGULAR) { + /* Check if grant + MAC SDU headers is enough to accomodate all pending data */ + int total_data = 0; + for (int i=0;iget_buffer_state(i))+rlc->get_buffer_state(i); + } + total_data--; // Because last SDU has no size header + + /* All triggered BSRs shall be cancelled in case the UL grant can accommodate all pending data available for transmission + but is not sufficient to additionally accommodate the BSR MAC control element plus its subheader. + */ + generate_bsr(bsr, 0); + bsr_sz = bsr->format==LONG_BSR?3:1; + if (total_data <= (int)grant_size && total_data + 1 + bsr_sz > grant_size) { + Debug("Grant is not enough to accomodate the BSR MAC CE\n"); + } else { + Debug("BSR: Including Regular BSR: grant_size=%d, total_data=%d, bsr_sz=%d\n", + grant_size, total_data, bsr_sz); + ret = true; + } + if (timers_db->get(mac::BSR_TIMER_PERIODIC)->get_timeout() && bsr->format != TRUNC_BSR) { + timers_db->get(mac::BSR_TIMER_PERIODIC)->reset(); + timers_db->get(mac::BSR_TIMER_PERIODIC)->run(); + } + } + // Cancel all triggered BSR and SR + triggered_bsr_type = NONE; + reset_sr = true; + // Restart or Start ReTX timer + if (timers_db->get(mac::BSR_TIMER_RETX)->get_timeout()) { + timers_db->get(mac::BSR_TIMER_RETX)->reset(); + timers_db->get(mac::BSR_TIMER_RETX)->run(); + } + return ret; +} + +bool bsr_proc::generate_padding_bsr(uint32_t nof_padding_bytes, bsr_t *bsr) +{ + bool ret = false; + + if (triggered_bsr_type != NONE || nof_padding_bytes >= 2) { + + if (triggered_bsr_type == NONE) { + triggered_bsr_type = PADDING; + } + generate_bsr(bsr, nof_padding_bytes); + ret = true; + Info("BSR: Type %s, Format %s, Value=%d,%d,%d,%d\n", + bsr_type_tostring(triggered_bsr_type), bsr_format_tostring(bsr->format), + bsr->buff_size[0], bsr->buff_size[1], bsr->buff_size[2], bsr->buff_size[3]); + + if (timers_db->get(mac::BSR_TIMER_PERIODIC)->get_timeout() && bsr->format != TRUNC_BSR) { + timers_db->get(mac::BSR_TIMER_PERIODIC)->reset(); + timers_db->get(mac::BSR_TIMER_PERIODIC)->run(); + } + + } + return ret; +} + +void bsr_proc::set_tx_tti(uint32_t tti) { + Debug("BSR: Set next_tx_tti=%d\n", tti); + next_tx_tti = tti; +} + +bool bsr_proc::need_to_reset_sr() { + if (reset_sr) { + reset_sr = false; + sr_is_sent = false; + Debug("BSR: SR reset. sr_is_sent and reset_rs false\n"); + return true; + } else { + return false; + } +} + +bool bsr_proc::need_to_send_sr(uint32_t tti) { + if (!sr_is_sent && triggered_bsr_type == REGULAR) { + if (srslte_tti_interval(tti,next_tx_tti)>0 && srslte_tti_interval(tti,next_tx_tti) < 10240-4) { + reset_sr = false; + sr_is_sent = true; + Debug("BSR: Need to send sr: sr_is_sent=true, reset_sr=false, tti=%d, next_tx_tti=%d\n", tti, next_tx_tti); + return true; + } else { + Debug("BSR: Not sending SR because tti=%d, next_tx_tti=%d\n", tti, next_tx_tti); + } + } + return false; +} + +void bsr_proc::setup_lcg(uint32_t lcid, uint32_t new_lcg) +{ + if (lcid < MAX_LCID && new_lcg < 4) { + lcg[lcid] = new_lcg; + } +} + +void bsr_proc::set_priority(uint32_t lcid, uint32_t priority) { + if (lcid < MAX_LCID) { + priorities[lcid] = priority; + } +} + +uint32_t bsr_proc::find_max_priority_lcid() { + int32_t max_prio = 0; + uint32_t max_idx = 0; + for (int i=0;i max_prio) { + max_prio = priorities[i]; + max_idx = i; + } + } + return max_idx; +} + +} diff --git a/srsue/src/mac/proc_phr.cc b/srsue/src/mac/proc_phr.cc new file mode 100644 index 000000000..b432f1c06 --- /dev/null +++ b/srsue/src/mac/proc_phr.cc @@ -0,0 +1,156 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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/. + * + */ + +#define Error(fmt, ...) log_h->error_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Warning(fmt, ...) log_h->warning_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Info(fmt, ...) log_h->info_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Debug(fmt, ...) log_h->debug_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) + +#include "mac/proc_phr.h" +#include "mac/mac.h" +#include "mac/mux.h" +#include "srslte/interfaces/ue_interfaces.h" + + + namespace srsue { + +phr_proc::phr_proc() +{ + initiated = false; +} + +void phr_proc::init(phy_interface_mac* phy_h_, srslte::log* log_h_, mac_interface_rrc::mac_cfg_t *mac_cfg_, srslte::timers *timers_db_) +{ + phy_h = phy_h_; + log_h = log_h_; + mac_cfg = mac_cfg_; + timers_db = timers_db_; + initiated = true; + reset(); +} + +void phr_proc::reset() +{ + phr_is_triggered = false; + timer_periodic = -2; + timer_prohibit = -2; + dl_pathloss_change = -2; +} + +bool phr_proc::pathloss_changed() { + + int min_change = liblte_rrc_dl_pathloss_change_num[mac_cfg->main.phr_cnfg.dl_pathloss_change]; + int cur_pathloss_db = (int) phy_h->get_pathloss_db(); + + if (abs(cur_pathloss_db - last_pathloss_db) > min_change && min_change > 0) { + last_pathloss_db = cur_pathloss_db; + return true; + } else { + return false; + } +} + +/* Trigger PHR when timers exire */ +void phr_proc::timer_expired(uint32_t timer_id) { + switch(timer_id) { + case mac::PHR_TIMER_PERIODIC: + timers_db->get(mac::PHR_TIMER_PERIODIC)->reset(); + timers_db->get(mac::PHR_TIMER_PERIODIC)->run(); + Debug("PHR: Triggered by timer periodic (timer expired).\n"); + phr_is_triggered = true; + break; + case mac::PHR_TIMER_PROHIBIT: + int pathloss_db = liblte_rrc_dl_pathloss_change_num[mac_cfg->main.phr_cnfg.dl_pathloss_change]; + if (pathloss_changed()) { + Info("PHR: Triggered by pathloss difference. cur_pathloss_db=%f (timer expired)\n", last_pathloss_db); + phr_is_triggered = true; + } + break; + } +} + +void phr_proc::step(uint32_t tti) +{ + if (!initiated) { + return; + } + + if (mac_cfg->main.phr_cnfg.setup_present) { + int cfg_timer_periodic = liblte_rrc_periodic_phr_timer_num[mac_cfg->main.phr_cnfg.periodic_phr_timer]; + + // Setup timers and trigger PHR when configuration changed by higher layers + if (timer_periodic != cfg_timer_periodic && cfg_timer_periodic > 0) + { + timer_periodic = cfg_timer_periodic; + timers_db->get(mac::PHR_TIMER_PERIODIC)->set(this, timer_periodic); + timers_db->get(mac::PHR_TIMER_PERIODIC)->run(); + phr_is_triggered = true; + Info("PHR: Configured timer periodic %d ms\n", timer_periodic); + } + + } + + int cfg_timer_prohibit = liblte_rrc_prohibit_phr_timer_num[mac_cfg->main.phr_cnfg.prohibit_phr_timer]; + + if (timer_prohibit != cfg_timer_prohibit && cfg_timer_prohibit > 0) + { + timer_prohibit = cfg_timer_prohibit; + timers_db->get(mac::PHR_TIMER_PROHIBIT)->set(this, timer_prohibit); + timers_db->get(mac::PHR_TIMER_PROHIBIT)->run(); + Info("PHR: Configured timer prohibit %d ms\n", timer_prohibit); + phr_is_triggered = true; + } + if (pathloss_changed() && timers_db->get(mac::PHR_TIMER_PROHIBIT)->is_expired()) + { + Info("PHR: Triggered by pathloss difference. cur_pathloss_db=%f\n", last_pathloss_db); + phr_is_triggered = true; + } +} + +bool phr_proc::generate_phr_on_ul_grant(float *phr) +{ + + if (phr_is_triggered) { + if (phr) { + *phr = phy_h->get_phr(); + } + + Debug("PHR: Generating PHR=%f\n", phr?*phr:0.0); + + timers_db->get(mac::PHR_TIMER_PERIODIC)->reset(); + timers_db->get(mac::PHR_TIMER_PROHIBIT)->reset(); + timers_db->get(mac::PHR_TIMER_PERIODIC)->run(); + timers_db->get(mac::PHR_TIMER_PROHIBIT)->run(); + + phr_is_triggered = false; + + return true; + } else { + return false; + } +} + +} diff --git a/srsue/src/mac/proc_ra.cc b/srsue/src/mac/proc_ra.cc new file mode 100644 index 000000000..495c9945f --- /dev/null +++ b/srsue/src/mac/proc_ra.cc @@ -0,0 +1,566 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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/. + * + */ + +#define Error(fmt, ...) log_h->error_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Warning(fmt, ...) log_h->warning_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Info(fmt, ...) log_h->info_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Debug(fmt, ...) log_h->debug_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) + +#include +#include +#include + +#include "mac/proc_ra.h" +#include "mac/mac.h" +#include "mac/mux.h" + +/* Random access procedure as specified in Section 5.1 of 36.321 */ + + +namespace srsue { + +// Table 7.2-1. Backoff Parameter values +uint32_t backoff_table[16] = {0, 10, 20, 30, 40, 60, 80, 120, 160, 240, 320, 480, 960, 960, 960, 960}; + +// Table 7.6-1: DELTA_PREAMBLE values. +int delta_preamble_db_table[5] = {0, 0, -3, -3, 8}; + +void ra_proc::init(phy_interface_mac* phy_h_, + rrc_interface_mac *rrc_, + srslte::log* log_h_, + mac_interface_rrc::ue_rnti_t *rntis_, + mac_interface_rrc::mac_cfg_t *mac_cfg_, + srslte::timers* timers_db_, + mux* mux_unit_, + demux* demux_unit_) +{ + phy_h = phy_h_; + log_h = log_h_; + mac_cfg = mac_cfg_; + rntis = rntis_; + timers_db = timers_db_; + mux_unit = mux_unit_; + demux_unit= demux_unit_; + rrc = rrc_; + srslte_softbuffer_rx_init(&softbuffer_rar, 10); + + // Tell demux to call us when a UE CRID is received + demux_unit->set_uecrid_callback(uecrid_callback, this); + + reset(); +} + +void ra_proc::reset() { + state = IDLE; + msg3_transmitted = false; + started_by_pdcch = false; +} + +void ra_proc::start_pcap(srslte::mac_pcap* pcap_) +{ + pcap = pcap_; +} + +void ra_proc::read_params() { + + // Read initialization parameters + configIndex = mac_cfg->prach_config_index; + preambleIndex = 0; // pass when called from higher layers for non-contention based RA + maskIndex = 0; // same + nof_preambles = liblte_rrc_number_of_ra_preambles_num[mac_cfg->rach.num_ra_preambles]; + if (mac_cfg->rach.preambles_group_a_cnfg.present) { + nof_groupA_preambles = liblte_rrc_size_of_ra_preambles_group_a_num[mac_cfg->rach.preambles_group_a_cnfg.size_of_ra]; + } else { + nof_groupA_preambles = nof_preambles; + } + + if (nof_groupA_preambles > nof_preambles) { + nof_groupA_preambles = nof_preambles; + } + + nof_groupB_preambles = nof_preambles - nof_groupA_preambles; + if (nof_groupB_preambles) { + messagePowerOffsetGroupB= liblte_rrc_message_power_offset_group_b_num[mac_cfg->rach.preambles_group_a_cnfg.msg_pwr_offset_group_b]; + messageSizeGroupA = liblte_rrc_message_size_group_a_num[mac_cfg->rach.preambles_group_a_cnfg.msg_size]; + } + responseWindowSize = liblte_rrc_ra_response_window_size_num[mac_cfg->rach.ra_resp_win_size]; + powerRampingStep = liblte_rrc_power_ramping_step_num[mac_cfg->rach.pwr_ramping_step]; + preambleTransMax = liblte_rrc_preamble_trans_max_num[mac_cfg->rach.preamble_trans_max]; + iniReceivedTargetPower = liblte_rrc_preamble_initial_received_target_power_num[mac_cfg->rach.preamble_init_rx_target_pwr]; + contentionResolutionTimer = liblte_rrc_mac_contention_resolution_timer_num[mac_cfg->rach.mac_con_res_timer]; + + delta_preamble_db = delta_preamble_db_table[configIndex%5]; + + if (contentionResolutionTimer > 0) { + timers_db->get(mac::CONTENTION_TIMER)->set(this, contentionResolutionTimer); + } + +} + +bool ra_proc::in_progress() +{ + return (state > IDLE && state != COMPLETION_DONE); +} + +bool ra_proc::is_successful() { + return state == COMPLETION_DONE; +} + +bool ra_proc::is_response_error() { + return state == RESPONSE_ERROR; +} + +bool ra_proc::is_contention_resolution() { + return state == CONTENTION_RESOLUTION; +} + +bool ra_proc::is_error() { + return state == RA_PROBLEM; +} + +const char* state_str[12] = {"Idle", + "RA: INIT: ", + "RA: Select: ", + "RA: TX: ", + "RA: PDCCH: ", + "RA: Rx: ", + "RA: RxErr: ", + "RA: Backof: ", + "RA: ConRes: ", + "RA: Done: ", + "RA: Done: ", + "RA: Error: "}; + + +#define rError(fmt, ...) Error("%s" fmt, state_str[state], ##__VA_ARGS__) +#define rInfo(fmt, ...) Info("%s" fmt, state_str[state], ##__VA_ARGS__) +#define rDebug(fmt, ...) Debug("%s" fmt, state_str[state], ##__VA_ARGS__) + + +// Process Timing Advance Command as defined in Section 5.2 +void ra_proc::process_timeadv_cmd(uint32_t ta) { + if (preambleIndex == 0) { + // Preamble not selected by UE MAC + phy_h->set_timeadv_rar(ta); + timers_db->get(mac::TIME_ALIGNMENT)->reset(); + timers_db->get(mac::TIME_ALIGNMENT)->run(); + Debug("Applying RAR TA CMD %d\n", ta); + } else { + // Preamble selected by UE MAC + if (!timers_db->get(mac::TIME_ALIGNMENT)->is_running()) { + phy_h->set_timeadv_rar(ta); + timers_db->get(mac::TIME_ALIGNMENT)->run(); + Debug("Applying RAR TA CMD %d\n", ta); + } else { + // Ignore TA CMD + Warning("Ignoring RAR TA CMD because timeAlignmentTimer still running\n"); + } + } +} + +void ra_proc::step_initialization() { + read_params(); + pdcch_to_crnti_received = PDCCH_CRNTI_NOT_RECEIVED; + transmitted_contention_id = 0; + preambleTransmissionCounter = 1; + first_rar_received = true; + mux_unit->msg3_flush(); + msg3_flushed = false; + backoff_param_ms = 0; + + // FIXME: This is because RA in Connected state not working in amarisoft + transmitted_crnti = rntis->crnti; + if(transmitted_crnti) { + state = RESPONSE_ERROR; + } + + // Instruct phy to configure PRACH + phy_h->configure_prach_params(); + state = RESOURCE_SELECTION; +} + +void ra_proc::step_resource_selection() { + ra_group_t sel_group; + + if (preambleIndex > 0) { + // Preamble is chosen by Higher layers (ie Network) + sel_maskIndex = maskIndex; + sel_preamble = (uint32_t) preambleIndex%nof_preambles; + } else { + // Preamble is chosen by MAC UE + if (!msg3_transmitted) { + if (nof_groupB_preambles > 0 && new_ra_msg_len > messageSizeGroupA) { // Check also pathloss (Pcmax,deltaPreamble and powerOffset) + sel_group = RA_GROUP_B; + } else { + sel_group = RA_GROUP_A; + } + last_msg3_group = sel_group; + } else { + sel_group = last_msg3_group; + } + if (sel_group == RA_GROUP_A) { + if (nof_groupA_preambles) { + sel_preamble = preambleTransmissionCounter%nof_groupA_preambles; + } else { + rError("Selected group preamble A but nof_groupA_preambles=0\n"); + state = RA_PROBLEM; + return; + } + } else { + if (nof_groupB_preambles) { + sel_preamble = nof_groupA_preambles + rand()%nof_groupB_preambles; + } else { + rError("Selected group preamble B but nof_groupA_preambles=0\n"); + state = RA_PROBLEM; + return; + } + } + sel_maskIndex = 0; + } + + rDebug("Selected preambleIndex=%d maskIndex=%d GroupA=%d, GroupB=%d\n", + sel_preamble, sel_maskIndex,nof_groupA_preambles, nof_groupB_preambles); + state = PREAMBLE_TRANSMISSION; +} + +void ra_proc::step_preamble_transmission() { + received_target_power_dbm = iniReceivedTargetPower + + delta_preamble_db + + (preambleTransmissionCounter-1)*powerRampingStep; + + rar_received = false; + phy_h->prach_send(sel_preamble, sel_maskIndex - 1, received_target_power_dbm); + state = PDCCH_SETUP; +} + +void ra_proc::step_pdcch_setup() { + int ra_tti = phy_h->prach_tx_tti(); + if (ra_tti > 0) { + ra_rnti = 1+ra_tti%10; + rInfo("seq=%d, ra-rnti=0x%x, ra-tti=%d\n", sel_preamble, ra_rnti, ra_tti); + log_h->console("Random Access Transmission: seq=%d, ra-rnti=0x%x\n", sel_preamble, ra_rnti); + phy_h->pdcch_dl_search(SRSLTE_RNTI_RAR, ra_rnti, ra_tti+3, ra_tti+3+responseWindowSize); + state = RESPONSE_RECEPTION; + } +} + +void ra_proc::new_grant_dl(mac_interface_phy::mac_grant_t grant, mac_interface_phy::tb_action_dl_t* action) +{ + if (grant.n_bytes < MAX_RAR_PDU_LEN) { + rDebug("DL grant found RA-RNTI=%d\n", ra_rnti); + action->decode_enabled = true; + action->default_ack = false; + action->generate_ack = false; + action->payload_ptr = rar_pdu_buffer; + action->rnti = grant.rnti; + memcpy(&action->phy_grant, &grant.phy_grant, sizeof(srslte_phy_grant_t)); + action->rv = grant.rv; + action->softbuffer = &softbuffer_rar; + rar_grant_nbytes = grant.n_bytes; + rar_grant_tti = grant.tti; + if (action->rv == 0) { + srslte_softbuffer_rx_reset(&softbuffer_rar); + } + } else { + rError("Received RAR grant exceeds buffer length (%d>%d)\n", grant.n_bytes, MAX_RAR_PDU_LEN); + action->decode_enabled = false; + state = RESPONSE_ERROR; + } +} + +void ra_proc::tb_decoded_ok() { + if (pcap) { + pcap->write_dl_ranti(rar_pdu_buffer, rar_grant_nbytes, ra_rnti, true, rar_grant_tti); + } + + rDebug("RAR decoded successfully TBS=%d\n", rar_grant_nbytes); + + rar_pdu_msg.init_rx(rar_grant_nbytes); + rar_pdu_msg.parse_packet(rar_pdu_buffer); + // Set Backoff parameter + if (rar_pdu_msg.has_backoff()) { + backoff_param_ms = backoff_table[rar_pdu_msg.get_backoff()%16]; + } else { + backoff_param_ms = 0; + } + + current_ta = 0; + + while(rar_pdu_msg.next()) { + if (rar_pdu_msg.get()->get_rapid() == sel_preamble) { + + rar_received = true; + process_timeadv_cmd(rar_pdu_msg.get()->get_ta_cmd()); + + // FIXME: Indicate received target power + //phy_h->set_target_power_rar(iniReceivedTargetPower, (preambleTransmissionCounter-1)*powerRampingStep); + + uint8_t grant[srslte::rar_subh::RAR_GRANT_LEN]; + rar_pdu_msg.get()->get_sched_grant(grant); + + phy_h->pdcch_dl_search_reset(); + + phy_h->set_rar_grant(rar_grant_tti, grant); + + current_ta = rar_pdu_msg.get()->get_ta_cmd(); + + rInfo("RAPID=%d, TA=%d\n", sel_preamble, rar_pdu_msg.get()->get_ta_cmd()); + + if (preambleIndex > 0) { + // Preamble selected by Network + state = COMPLETION; + } else { + // Preamble selected by UE MAC + rntis->temp_rnti = rar_pdu_msg.get()->get_temp_crnti(); + phy_h->pdcch_dl_search(SRSLTE_RNTI_TEMP, rar_pdu_msg.get()->get_temp_crnti()); + + if (first_rar_received) { + first_rar_received = false; + + // Save transmitted C-RNTI (if any) + transmitted_crnti = rntis->crnti; + + // If we have a C-RNTI, tell Mux unit to append C-RNTI CE if no CCCH SDU transmission + if (transmitted_crnti) { + rDebug("Appending C-RNTI MAC CE in next transmission\n"); + mux_unit->append_crnti_ce_next_tx(transmitted_crnti); + phy_h->pdcch_ul_search(SRSLTE_RNTI_USER, transmitted_crnti); + phy_h->pdcch_dl_search(SRSLTE_RNTI_USER, transmitted_crnti); + } + } + rDebug("Going to Contention Resolution state\n"); + state = CONTENTION_RESOLUTION; + + // Start contention resolution timer + timers_db->get(mac::CONTENTION_TIMER)->reset(); + timers_db->get(mac::CONTENTION_TIMER)->run(); + } + } else { + rDebug("Found RAR for preamble %d\n", rar_pdu_msg.get()->get_rapid()); + } + } +} + +void ra_proc::step_response_reception() { + // do nothing. Processing done in tb_decoded_ok() + int ra_tti = phy_h->prach_tx_tti(); + if (ra_tti >= 0 && !rar_received) { + uint32_t interval = srslte_tti_interval(phy_h->get_current_tti(), ra_tti+3+responseWindowSize); + if (interval > 1 && interval < 100) { + rDebug("RA response not received within the response window\n"); + state = RESPONSE_ERROR; + } + } +} + +void ra_proc::step_response_error() { + + preambleTransmissionCounter++; + if (preambleTransmissionCounter >= preambleTransMax + 1) { + rError("Maximum number of transmissions reached (%d)\n", preambleTransMax); + rrc->ra_problem(); + state = RA_PROBLEM; + } else { + backoff_interval_start = phy_h->get_current_tti(); + if (backoff_param_ms) { + backoff_inteval = rand()%backoff_param_ms; + } else { + backoff_inteval = 0; + } + if (backoff_inteval) { + rDebug("Backoff wait interval %d\n", backoff_inteval); + state = BACKOFF_WAIT; + } else { + rDebug("Transmitting inmediatly (%d/%d)\n", preambleTransmissionCounter, preambleTransMax); + state = RESOURCE_SELECTION; + } + } +} + +void ra_proc::step_backoff_wait() { + if (srslte_tti_interval(phy_h->get_current_tti(), backoff_interval_start) >= backoff_inteval) { + state = RESOURCE_SELECTION; + } +} + +bool ra_proc::uecrid_callback(void *arg, uint64_t uecri) { + return ((ra_proc*) arg)->contention_resolution_id_received(uecri); +} + +// Random Access initiated by RRC by the transmission of CCCH SDU +bool ra_proc::contention_resolution_id_received(uint64_t rx_contention_id) { + bool uecri_successful = false; + + rDebug("MAC PDU Contains Contention Resolution ID CE\n"); + + // MAC PDU successfully decoded and contains MAC CE contention Id + timers_db->get(mac::CONTENTION_TIMER)->stop(); + + if (transmitted_contention_id == rx_contention_id) + { + // UE Contention Resolution ID included in MAC CE matches the CCCH SDU transmitted in Msg3 + rntis->crnti = rntis->temp_rnti; + // finish the disassembly and demultiplexing of the MAC PDU + uecri_successful = true; + state = COMPLETION; + } else { + rInfo("Transmitted UE Contention Id differs from received Contention ID (0x%lx != 0x%lx)\n", + transmitted_contention_id, rx_contention_id); + // Discard MAC PDU + uecri_successful = false; + + // Contention Resolution not successfully is like RAR not successful + // FIXME: Need to flush Msg3 HARQ buffer. Why? + state = RESPONSE_ERROR; + } + rntis->temp_rnti = 0; + + return uecri_successful; +} + +void ra_proc::step_contention_resolution() { + // If Msg3 has been sent + if (mux_unit->msg3_is_transmitted()) + { + msg3_transmitted = true; + if (transmitted_crnti) + { + // Random Access with transmission of MAC C-RNTI CE + if ((!started_by_pdcch && pdcch_to_crnti_received == PDCCH_CRNTI_UL_GRANT) || + (started_by_pdcch && pdcch_to_crnti_received != PDCCH_CRNTI_NOT_RECEIVED)) + { + rDebug("PDCCH for C-RNTI received\n"); + timers_db->get(mac::CONTENTION_TIMER)->stop(); + rntis->temp_rnti = 0; + state = COMPLETION; + } + pdcch_to_crnti_received = PDCCH_CRNTI_NOT_RECEIVED; + } else { + // RA with transmission of CCCH SDU is resolved in contention_resolution_id_received() callback function + if (!transmitted_contention_id) { + // Save transmitted UE contention id, as defined by higher layers + transmitted_contention_id = rntis->contention_id; + rntis->contention_id = 0; + } + } + } else { + rDebug("Msg3 not yet transmitted\n"); + } + +} + +void ra_proc::step_completition() { + log_h->console("Random Access Complete. c-rnti=0x%x, ta=%d\n", rntis->crnti, current_ta); + rInfo("Random Access Complete. c-rnti=0x%x, ta=%d\n", rntis->crnti, current_ta); + if (!msg3_flushed) { + mux_unit->msg3_flush(); + msg3_flushed = true; + } + msg3_transmitted = false; + state = COMPLETION_DONE; +} + +void ra_proc::step(uint32_t tti_) +{ + switch(state) { + case IDLE: + break; + case INITIALIZATION: + step_initialization(); + break; + case RESOURCE_SELECTION: + step_resource_selection(); + break; + case PREAMBLE_TRANSMISSION: + step_preamble_transmission(); + break; + case PDCCH_SETUP: + step_pdcch_setup(); + break; + case RESPONSE_RECEPTION: + step_response_reception(); + break; + case RESPONSE_ERROR: + step_response_error(); + break; + case BACKOFF_WAIT: + step_backoff_wait(); + break; + case CONTENTION_RESOLUTION: + step_contention_resolution(); + break; + case COMPLETION: + step_completition(); + case COMPLETION_DONE: + case RA_PROBLEM: + break; + } +} + +void ra_proc::start_mac_order(uint32_t msg_len_bits) +{ + if (state == IDLE || state == COMPLETION_DONE || state == RA_PROBLEM) { + started_by_pdcch = false; + new_ra_msg_len = msg_len_bits; + state = INITIALIZATION; + rInfo("Starting PRACH by MAC order\n"); + } +} + +void ra_proc::start_pdcch_order() +{ + if (state == IDLE || state == COMPLETION_DONE || state == RA_PROBLEM) { + started_by_pdcch = true; + state = INITIALIZATION; + rInfo("Starting PRACH by PDCCH order\n"); + } +} + +// Contention Resolution Timer is expired (Section 5.1.5) +void ra_proc::timer_expired(uint32_t timer_id) +{ + rInfo("Contention Resolution Timer expired. Stopping PDCCH Search and going to Response Error\n"); + rntis->temp_rnti = 0; + state = RESPONSE_ERROR; + phy_h->pdcch_dl_search_reset(); +} + +void ra_proc::pdcch_to_crnti(bool contains_uplink_grant) { + rDebug("PDCCH to C-RNTI received %s UL grant\n", contains_uplink_grant?"with":"without"); + if (contains_uplink_grant) { + pdcch_to_crnti_received = PDCCH_CRNTI_UL_GRANT; + } else if (pdcch_to_crnti_received == PDCCH_CRNTI_NOT_RECEIVED) { + pdcch_to_crnti_received = PDCCH_CRNTI_DL_GRANT; + } +} + +void ra_proc::harq_retx() +{ + timers_db->get(mac::CONTENTION_TIMER)->reset(); +} + +} + diff --git a/srsue/src/mac/proc_sr.cc b/srsue/src/mac/proc_sr.cc new file mode 100644 index 000000000..afd2b7b5a --- /dev/null +++ b/srsue/src/mac/proc_sr.cc @@ -0,0 +1,129 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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/. + * + */ + +#define Error(fmt, ...) log_h->error_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Warning(fmt, ...) log_h->warning_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Info(fmt, ...) log_h->info_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Debug(fmt, ...) log_h->debug_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) + +#include "mac/proc_sr.h" + + +namespace srsue { + +sr_proc::sr_proc() { + initiated = false; +} + +void sr_proc::init(phy_interface_mac* phy_h_, rrc_interface_mac *rrc_, srslte::log* log_h_, mac_interface_rrc::mac_cfg_t *mac_cfg_) +{ + log_h = log_h_; + rrc = rrc_; + mac_cfg = mac_cfg_; + phy_h = phy_h_; + initiated = true; + do_ra = false; +} + +void sr_proc::reset() +{ + is_pending_sr = false; +} + +bool sr_proc::need_tx(uint32_t tti) +{ + int last_tx_tti = phy_h->sr_last_tx_tti(); + if (last_tx_tti >= 0) { + if (tti > (uint32_t)last_tx_tti) { + if (tti - last_tx_tti > 8) { + return true; + } + } else { + uint32_t interval = 10240-last_tx_tti+tti; + if (interval > 8 && tti < 8) { + return true; + } + } + } + return false; +} + +void sr_proc::step(uint32_t tti) +{ + if (initiated) { + if (is_pending_sr) { + if (mac_cfg->sr.setup_present) { + if (sr_counter < dsr_transmax) { + if (sr_counter == 0 || need_tx(tti)) { + sr_counter++; + Info("SR: Signalling PHY sr_counter=%d\n", sr_counter); + phy_h->sr_send(); + } + } else { + if (need_tx(tti)) { + Info("SR: Releasing PUCCH/SRS resources, sr_counter=%d, dsr_transmax=%d\n", + sr_counter, dsr_transmax); + log_h->console("Scheduling request failed: releasing RRC connection...\n"); + rrc->release_pucch_srs(); + do_ra = true; + is_pending_sr = false; + } + } + } else { + Info("SR: PUCCH not configured. Starting RA procedure\n"); + do_ra = true; + reset(); + } + } + } +} + +bool sr_proc::need_random_access() { + if (initiated) { + if (do_ra) { + do_ra = false; + return true; + } else { + return false; + } + } + return false; +} + +void sr_proc::start() +{ + if (initiated) { + if (!is_pending_sr) { + sr_counter = 0; + is_pending_sr = true; + } + dsr_transmax = liblte_rrc_dsr_trans_max_num[mac_cfg->sr.dsr_trans_max]; + Debug("SR: Starting Procedure. dsrTransMax=%d\n", dsr_transmax); + } +} + +} + diff --git a/srsue/src/mac/ul_harq.cc b/srsue/src/mac/ul_harq.cc new file mode 100644 index 000000000..da28d62b3 --- /dev/null +++ b/srsue/src/mac/ul_harq.cc @@ -0,0 +1,394 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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/. + * + */ + +#define Error(fmt, ...) log_h->error_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Warning(fmt, ...) log_h->warning_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Info(fmt, ...) log_h->info_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Debug(fmt, ...) log_h->debug_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) + +#include "srslte/common/log.h" +#include "mac/mac.h" +#include "mac/ul_harq.h" + + + namespace srsue { + + /*********************************************************** + * + * HARQ ENTITY + * + *********************************************************/ + +bool ul_harq_entity::init(srslte::log *log_h_, + mac_interface_rrc::ue_rnti_t *rntis_, + mac_interface_rrc::mac_cfg_t *mac_cfg_, + srslte::timers *timers_db_, + mux *mux_unit_) { + log_h = log_h_; + mux_unit = mux_unit_; + mac_cfg = mac_cfg_; + rntis = rntis_; + timers_db = timers_db_; + for (uint32_t i=0;ilog_h; + pid = pid_; + payload_buffer = (uint8_t*) srslte_vec_malloc(payload_buffer_len*sizeof(uint8_t)); + if (!payload_buffer) { + Error("Allocating memory\n"); + return false; + } + pdu_ptr = payload_buffer; + return true; + } +} + +void ul_harq_entity::ul_harq_process::run_tti(uint32_t tti_tx, mac_interface_phy::mac_grant_t* grant, mac_interface_phy::tb_action_ul_t* action) +{ + + + uint32_t max_retx; + if (is_msg3) { + max_retx = harq_entity->mac_cfg->rach.max_harq_msg3_tx; + } else { + max_retx = liblte_rrc_max_harq_tx_num[harq_entity->mac_cfg->main.ulsch_cnfg.max_harq_tx]; + } + + + // Receive and route HARQ feedbacks + if (grant) { + if ((!(grant->rnti_type == SRSLTE_RNTI_TEMP) && grant->ndi != get_ndi()) || + (grant->rnti_type == SRSLTE_RNTI_USER && !has_grant()) || + grant->is_from_rar) + { + // New transmission + + // Uplink grant in a RAR + if (grant->is_from_rar) { + Debug("Getting Msg3 buffer payload, grant size=%d bytes\n", grant->n_bytes); + pdu_ptr = harq_entity->mux_unit->msg3_get(payload_buffer, grant->n_bytes); + if (pdu_ptr) { + generate_new_tx(tti_tx, true, grant, action); + } else { + Warning("UL RAR grant available but no Msg3 on buffer\n"); + } + + // Normal UL grant + } else { + // Request a MAC PDU from the Multiplexing & Assemble Unit + pdu_ptr = harq_entity->mux_unit->pdu_get(payload_buffer, grant->n_bytes, tti_tx, pid); + if (pdu_ptr) { + generate_new_tx(tti_tx, false, grant, action); + } else { + Warning("Uplink grant but no MAC PDU in Multiplex Unit buffer\n"); + } + } + } else { + // Adaptive Re-TX + if (current_tx_nb >= max_retx) { + Info("UL %d: Maximum number of ReTX reached (%d). Discarting TB.\n", pid, max_retx); + reset(); + action->expect_ack = false; + } else { + generate_retx(tti_tx, grant, action); + } + } + } else if (has_grant()) { + // Non-Adaptive Re-Tx + if (current_tx_nb >= max_retx) { + Info("UL %d: Maximum number of ReTX reached (%d). Discarting TB.\n", pid, max_retx); + reset(); + action->expect_ack = false; + } else { + generate_retx(tti_tx, action); + } + } + if (harq_entity->pcap && grant) { + if (grant->is_from_rar) { + grant->rnti = harq_entity->rntis->temp_rnti; + } + harq_entity->pcap->write_ul_crnti(pdu_ptr, grant->n_bytes, grant->rnti, get_nof_retx(), tti_tx); + } + + + +} + +int ul_harq_entity::ul_harq_process::get_current_tbs() +{ + return cur_grant.n_bytes*8; +} + +void ul_harq_entity::ul_harq_process::generate_retx(uint32_t tti_tx, mac_interface_phy::tb_action_ul_t *action) +{ + generate_retx(tti_tx, NULL, action); +} + +// Retransmission with or w/o grant (Section 5.4.2.2) +void ul_harq_entity::ul_harq_process::generate_retx(uint32_t tti_tx, mac_interface_phy::mac_grant_t *grant, + mac_interface_phy::tb_action_ul_t *action) +{ + if (grant) { + // HARQ entity requests an adaptive transmission + if (grant->rv) { + current_irv = irv_of_rv[grant->rv%4]; + } + memcpy(&cur_grant, grant, sizeof(mac_interface_phy::mac_grant_t)); + harq_feedback = false; + Info("UL %d: Adaptive retx=%d, RV=%d, TBS=%d\n", + pid, current_tx_nb, get_rv(), grant->n_bytes); + generate_tx(tti_tx, action); + } else { + Info("UL %d: Non-Adaptive retx=%d, RV=%d, TBS=%d\n", + pid, current_tx_nb, get_rv(), cur_grant.n_bytes); + // HARQ entity requests a non-adaptive transmission + if (!harq_feedback) { + generate_tx(tti_tx, action); + } + } + + // On every Msg3 retransmission, restart mac-ContentionResolutionTimer as defined in Section 5.1.5 + if (is_msg3) { + harq_entity->timers_db->get(mac::CONTENTION_TIMER)->reset(); + } + + harq_entity->mux_unit->pusch_retx(tti_tx, pid); +} + +// New transmission (Section 5.4.2.2) +void ul_harq_entity::ul_harq_process::generate_new_tx(uint32_t tti_tx, bool is_msg3_, + mac_interface_phy::mac_grant_t *grant, + mac_interface_phy::tb_action_ul_t *action) +{ + if (grant) { + + // Compute average number of retransmissions per packet considering previous packet + harq_entity->average_retx = SRSLTE_VEC_CMA((float) current_tx_nb, harq_entity->average_retx, harq_entity->nof_pkts++); + + + memcpy(&cur_grant, grant, sizeof(mac_interface_phy::mac_grant_t)); + harq_feedback = false; + is_grant_configured = true; + current_tx_nb = 0; + current_irv = 0; + is_msg3 = is_msg3_; + Info("UL %d: New TX%s, RV=%d, TBS=%d, RNTI=%d\n", + pid, is_msg3?" for Msg3":"", get_rv(), cur_grant.n_bytes, cur_grant.rnti); + generate_tx(tti_tx, action); + } +} + +// Transmission of pending frame (Section 5.4.2.2) +void ul_harq_entity::ul_harq_process::generate_tx(uint32_t tti_tx, mac_interface_phy::tb_action_ul_t *action) +{ + action->current_tx_nb = current_tx_nb; + current_tx_nb++; + action->expect_ack = true; + action->rnti = is_msg3?harq_entity->rntis->temp_rnti:cur_grant.rnti; + action->rv = cur_grant.rv>0?cur_grant.rv:get_rv(); + action->softbuffer = &softbuffer; + action->tx_enabled = true; + action->payload_ptr = pdu_ptr; + memcpy(&action->phy_grant, &cur_grant.phy_grant, sizeof(srslte_phy_grant_t)); + + current_irv = (current_irv+1)%4; + tti_last_tx = tti_tx; +} + +bool ul_harq_entity::ul_harq_process::is_sps() +{ + return false; +} + +uint32_t ul_harq_entity::ul_harq_process::last_tx_tti() +{ + return tti_last_tx; +} + +uint32_t ul_harq_entity::ul_harq_process::get_nof_retx() +{ + return current_tx_nb; +} + +} diff --git a/srsue/src/main.cc b/srsue/src/main.cc new file mode 100644 index 000000000..8065a3571 --- /dev/null +++ b/srsue/src/main.cc @@ -0,0 +1,379 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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 +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "ue.h" +#include "metrics_stdout.h" +#include "srslte/version.h" + +using namespace std; +using namespace srsue; +namespace bpo = boost::program_options; + +/********************************************************************** + * Program arguments processing + ***********************************************************************/ +string config_file; + +void parse_args(all_args_t *args, int argc, char* argv[]) { + + // Command line only options + bpo::options_description general("General options"); + general.add_options() + ("help,h", "Produce help message") + ("version,v", "Print version information and exit") + ; + + // Command line or config file options + bpo::options_description common("Configuration options"); + common.add_options() + ("rf.dl_freq", bpo::value(&args->rf.dl_freq)->default_value(2680000000), "Downlink centre frequency") + ("rf.ul_freq", bpo::value(&args->rf.ul_freq)->default_value(2560000000), "Uplink centre frequency") + ("rf.rx_gain", bpo::value(&args->rf.rx_gain)->default_value(-1), "Front-end receiver gain") + ("rf.tx_gain", bpo::value(&args->rf.tx_gain)->default_value(-1), "Front-end transmitter gain") + ("rf.nof_rx_ant", bpo::value(&args->rf.nof_rx_ant)->default_value(1), "Number of RX antennas") + + ("rf.device_name", bpo::value(&args->rf.device_name)->default_value("auto"), "Front-end device name") + ("rf.device_args", bpo::value(&args->rf.device_args)->default_value("auto"), "Front-end device arguments") + ("rf.time_adv_nsamples", bpo::value(&args->rf.time_adv_nsamples)->default_value("auto"), "Transmission time advance") + ("rf.burst_preamble_us", bpo::value(&args->rf.burst_preamble)->default_value("auto"), "Transmission time advance") + + ("pcap.enable", bpo::value(&args->pcap.enable)->default_value(false), "Enable MAC packet captures for wireshark") + ("pcap.filename", bpo::value(&args->pcap.filename)->default_value("ue.pcap"), "MAC layer capture filename") + + ("trace.enable", bpo::value(&args->trace.enable)->default_value(false), "Enable PHY and radio timing traces") + ("trace.phy_filename",bpo::value(&args->trace.phy_filename)->default_value("ue.phy_trace"), "PHY timing traces filename") + ("trace.radio_filename",bpo::value(&args->trace.radio_filename)->default_value("ue.radio_trace"), "Radio timing traces filename") + + ("gui.enable", bpo::value(&args->gui.enable)->default_value(false), "Enable GUI plots") + + ("log.phy_level", bpo::value(&args->log.phy_level), "PHY log level") + ("log.phy_hex_limit", bpo::value(&args->log.phy_hex_limit), "PHY log hex dump limit") + ("log.mac_level", bpo::value(&args->log.mac_level), "MAC log level") + ("log.mac_hex_limit", bpo::value(&args->log.mac_hex_limit), "MAC log hex dump limit") + ("log.rlc_level", bpo::value(&args->log.rlc_level), "RLC log level") + ("log.rlc_hex_limit", bpo::value(&args->log.rlc_hex_limit), "RLC log hex dump limit") + ("log.pdcp_level", bpo::value(&args->log.pdcp_level), "PDCP log level") + ("log.pdcp_hex_limit",bpo::value(&args->log.pdcp_hex_limit), "PDCP log hex dump limit") + ("log.rrc_level", bpo::value(&args->log.rrc_level), "RRC log level") + ("log.rrc_hex_limit", bpo::value(&args->log.rrc_hex_limit), "RRC log hex dump limit") + ("log.gw_level", bpo::value(&args->log.gw_level), "GW log level") + ("log.gw_hex_limit", bpo::value(&args->log.gw_hex_limit), "GW log hex dump limit") + ("log.nas_level", bpo::value(&args->log.nas_level), "NAS log level") + ("log.nas_hex_limit", bpo::value(&args->log.nas_hex_limit), "NAS log hex dump limit") + ("log.usim_level", bpo::value(&args->log.usim_level), "USIM log level") + ("log.usim_hex_limit",bpo::value(&args->log.usim_hex_limit), "USIM log hex dump limit") + + ("log.all_level", bpo::value(&args->log.all_level)->default_value("info"), "ALL log level") + ("log.all_hex_limit", bpo::value(&args->log.all_hex_limit)->default_value(32), "ALL log hex dump limit") + + ("log.filename", bpo::value(&args->log.filename)->default_value("/tmp/ue.log"),"Log filename") + + ("usim.algo", bpo::value(&args->usim.algo), "USIM authentication algorithm") + ("usim.op", bpo::value(&args->usim.op), "USIM operator variant") + ("usim.amf", bpo::value(&args->usim.amf), "USIM authentication management field") + ("usim.imsi", bpo::value(&args->usim.imsi), "USIM IMSI") + ("usim.imei", bpo::value(&args->usim.imei), "USIM IMEI") + ("usim.k", bpo::value(&args->usim.k), "USIM K") + + + /* Expert section */ + ("expert.phy.worker_cpu_mask", + bpo::value(&args->expert.phy.worker_cpu_mask)->default_value(-1), + "cpu bit mask (eg 255 = 1111 1111)") + + ("expert.phy.sync_cpu_affinity", + bpo::value(&args->expert.phy.sync_cpu_affinity)->default_value(-1), + "index of the core used by the sync thread") + + ("expert.ue_category", + bpo::value(&args->expert.ue_cateogry)->default_value(4), + "UE Category (1 to 5)") + + ("expert.metrics_period_secs", + bpo::value(&args->expert.metrics_period_secs)->default_value(1.0), + "Periodicity for metrics in seconds") + + ("expert.pregenerate_signals", + bpo::value(&args->expert.pregenerate_signals)->default_value(false), + "Pregenerate uplink signals after attach. Improves CPU performance.") + + ("expert.rssi_sensor_enabled", + bpo::value(&args->expert.phy.rssi_sensor_enabled)->default_value(true), + "Enable or disable RF frontend RSSI sensor. In some USRP devices can cause segmentation fault") + + ("expert.prach_gain", + bpo::value(&args->expert.phy.prach_gain)->default_value(-1.0), + "Disable PRACH power control") + + ("expert.cqi_max", + bpo::value(&args->expert.phy.cqi_max)->default_value(15), + "Upper bound on the maximum CQI to be reported. Default 15.") + + ("expert.cqi_fixed", + bpo::value(&args->expert.phy.cqi_fixed)->default_value(-1), + "Fixes the reported CQI to a constant value. Default disabled.") + + ("expert.snr_ema_coeff", + bpo::value(&args->expert.phy.snr_ema_coeff)->default_value(0.1), + "Sets the SNR exponential moving average coefficient (Default 0.1)") + + ("expert.snr_estim_alg", + bpo::value(&args->expert.phy.snr_estim_alg)->default_value("refs"), + "Sets the noise estimation algorithm. (Default refs)") + + ("expert.pdsch_max_its", + bpo::value(&args->expert.phy.pdsch_max_its)->default_value(4), + "Maximum number of turbo decoder iterations") + + ("expert.attach_enable_64qam", + bpo::value(&args->expert.phy.attach_enable_64qam)->default_value(false), + "PUSCH 64QAM modulation before attachment") + + ("expert.nof_phy_threads", + bpo::value(&args->expert.phy.nof_phy_threads)->default_value(2), + "Number of PHY threads") + + ("expert.equalizer_mode", + bpo::value(&args->expert.phy.equalizer_mode)->default_value("mmse"), + "Equalizer mode") + + ("expert.cfo_integer_enabled", + bpo::value(&args->expert.phy.cfo_integer_enabled)->default_value(false), + "Enables integer CFO estimation and correction.") + + ("expert.cfo_correct_tol_hz", + bpo::value(&args->expert.phy.cfo_correct_tol_hz)->default_value(50.0), + "Tolerance (in Hz) for digial CFO compensation.") + + ("expert.time_correct_period", + bpo::value(&args->expert.phy.time_correct_period)->default_value(5), + "Period for sampling time offset correction.") + + ("expert.sfo_correct_disable", + bpo::value(&args->expert.phy.sfo_correct_disable)->default_value(false), + "Disables phase correction before channel estimation.") + + ("expert.sss_algorithm", + bpo::value(&args->expert.phy.sss_algorithm)->default_value("full"), + "Selects the SSS estimation algorithm.") + + ("expert.estimator_fil_w", + bpo::value(&args->expert.phy.estimator_fil_w)->default_value(0.1), + "Chooses the coefficients for the 3-tap channel estimator centered filter.") + + + ("rf_calibration.tx_corr_dc_gain", bpo::value(&args->rf_cal.tx_corr_dc_gain)->default_value(0.0), "TX DC offset gain correction") + ("rf_calibration.tx_corr_dc_phase", bpo::value(&args->rf_cal.tx_corr_dc_phase)->default_value(0.0), "TX DC offset phase correction") + ("rf_calibration.tx_corr_iq_i", bpo::value(&args->rf_cal.tx_corr_iq_i)->default_value(0.0), "TX IQ imbalance inphase correction") + ("rf_calibration.tx_corr_iq_q", bpo::value(&args->rf_cal.tx_corr_iq_q)->default_value(0.0), "TX IQ imbalance quadrature correction") + + ; + + // Positional options - config file location + bpo::options_description position("Positional options"); + position.add_options() + ("config_file", bpo::value< string >(&config_file), "UE configuration file") + ; + bpo::positional_options_description p; + p.add("config_file", -1); + + // these options are allowed on the command line + bpo::options_description cmdline_options; + cmdline_options.add(common).add(position).add(general); + + // parse the command line and store result in vm + bpo::variables_map vm; + bpo::store(bpo::command_line_parser(argc, argv).options(cmdline_options).positional(p).run(), vm); + bpo::notify(vm); + + // help option was given - print usage and exit + if (vm.count("help")) { + cout << "Usage: " << argv[0] << " [OPTIONS] config_file" << endl << endl; + cout << common << endl << general << endl; + exit(0); + } + + // print version number and exit + if (vm.count("version")) { + cout << "Version " << + srslte_get_version_major() << "." << + srslte_get_version_minor() << "." << + srslte_get_version_patch() << endl; + exit(0); + } + + // no config file given - print usage and exit + if (!vm.count("config_file")) { + cout << "Error: Configuration file not provided" << endl; + cout << "Usage: " << argv[0] << " [OPTIONS] config_file" << endl << endl; + exit(0); + } else { + cout << "Reading configuration file " << config_file << "..." << endl; + ifstream conf(config_file.c_str(), ios::in); + if(conf.fail()) { + cout << "Failed to read configuration file " << config_file << " - exiting" << endl; + exit(1); + } + bpo::store(bpo::parse_config_file(conf, common), vm); + bpo::notify(vm); + } + + // Apply all_level to any unset layers + if (vm.count("log.all_level")) { + if(!vm.count("log.phy_level")) { + args->log.phy_level = args->log.all_level; + } + if(!vm.count("log.mac_level")) { + args->log.mac_level = args->log.all_level; + } + if(!vm.count("log.rlc_level")) { + args->log.rlc_level = args->log.all_level; + } + if(!vm.count("log.pdcp_level")) { + args->log.pdcp_level = args->log.all_level; + } + if(!vm.count("log.rrc_level")) { + args->log.rrc_level = args->log.all_level; + } + if(!vm.count("log.nas_level")) { + args->log.nas_level = args->log.all_level; + } + if(!vm.count("log.gw_level")) { + args->log.gw_level = args->log.all_level; + } + if(!vm.count("log.usim_level")) { + args->log.usim_level = args->log.all_level; + } + } + + // Apply all_hex_limit to any unset layers + if (vm.count("log.all_hex_limit")) { + if(!vm.count("log.phy_hex_limit")) { + args->log.phy_hex_limit = args->log.all_hex_limit; + } + if(!vm.count("log.mac_hex_limit")) { + args->log.mac_hex_limit = args->log.all_hex_limit; + } + if(!vm.count("log.rlc_hex_limit")) { + args->log.rlc_hex_limit = args->log.all_hex_limit; + } + if(!vm.count("log.pdcp_hex_limit")) { + args->log.pdcp_hex_limit = args->log.all_hex_limit; + } + if(!vm.count("log.rrc_hex_limit")) { + args->log.rrc_hex_limit = args->log.all_hex_limit; + } + if(!vm.count("log.nas_hex_limit")) { + args->log.nas_hex_limit = args->log.all_hex_limit; + } + if(!vm.count("log.gw_hex_limit")) { + args->log.gw_hex_limit = args->log.all_hex_limit; + } + if(!vm.count("log.usim_hex_limit")) { + args->log.usim_hex_limit = args->log.all_hex_limit; + } + } +} + +static bool running = true; +static bool do_metrics = false; + +void sig_int_handler(int signo) +{ + running = false; +} + +void *input_loop(void *m) +{ + metrics_stdout *metrics = (metrics_stdout*)m; + char key; + while(running) { + cin >> key; + if('t' == key) { + do_metrics = !do_metrics; + if(do_metrics) { + cout << "Enter t to stop trace." << endl; + } else { + cout << "Enter t to restart trace." << endl; + } + metrics->toggle_print(do_metrics); + } + } + return NULL; +} + +int main(int argc, char *argv[]) +{ + signal(SIGINT, sig_int_handler); + all_args_t args; + metrics_stdout metrics; + ue *ue = ue::get_instance(); + + cout << "--- Software Radio Systems LTE UE ---" << endl << endl; + + parse_args(&args, argc, argv); + if(!ue->init(&args)) { + exit(1); + } + metrics.init(ue, args.expert.metrics_period_secs); + + pthread_t input; + pthread_create(&input, NULL, &input_loop, &metrics); + + bool plot_started = false; + bool signals_pregenerated = false; + while(running) { + if (ue->is_attached()) { + if (!signals_pregenerated && args.expert.pregenerate_signals) { + ue->pregenerate_signals(true); + signals_pregenerated = true; + } + if (!plot_started && args.gui.enable) { + ue->start_plot(); + plot_started = true; + } + } + sleep(1); + } + pthread_cancel(input); + metrics.stop(); + ue->stop(); + ue->cleanup(); + cout << "--- exiting ---" << endl; + exit(0); +} diff --git a/srsue/src/metrics_stdout.cc b/srsue/src/metrics_stdout.cc new file mode 100644 index 000000000..0a86683d2 --- /dev/null +++ b/srsue/src/metrics_stdout.cc @@ -0,0 +1,180 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2015 The srsUE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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 "metrics_stdout.h" + +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace std; + +namespace srsue{ + +char const * const prefixes[2][9] = +{ + { "", "m", "u", "n", "p", "f", "a", "z", "y", }, + { "", "k", "M", "G", "T", "P", "E", "Z", "Y", }, +}; + +metrics_stdout::metrics_stdout() + :started(false) + ,do_print(false) + ,n_reports(10) +{ +} + +bool metrics_stdout::init(ue_metrics_interface *u, float report_period_secs) +{ + ue_ = u; + metrics_report_period = report_period_secs; + + started = true; + pthread_create(&metrics_thread, NULL, &metrics_thread_start, this); + return true; +} + +void metrics_stdout::stop() +{ + if(started) + { + started = false; + pthread_join(metrics_thread, NULL); + } +} + +void metrics_stdout::toggle_print(bool b) +{ + do_print = b; +} + +void* metrics_stdout::metrics_thread_start(void *m_) +{ + metrics_stdout *m = (metrics_stdout*)m_; + m->metrics_thread_run(); + return NULL; +} + +void metrics_stdout::metrics_thread_run() +{ + while(started) + { + usleep(metrics_report_period*1e6); + if(ue_->get_metrics(metrics)) { + print_metrics(); + } else { + print_disconnect(); + } + } +} + +void metrics_stdout::print_metrics() +{ + if(!do_print) + return; + + if(++n_reports > 10) + { + n_reports = 0; + cout << endl; + cout << "--Signal--------------DL------------------------------UL----------------------" << endl; + cout << " rsrp pl cfo mcs snr turbo brate bler mcs buff brate bler" << endl; + } + cout << float_to_string(metrics.phy.dl.rsrp, 2); + cout << float_to_string(metrics.phy.dl.pathloss, 2); + cout << float_to_eng_string(metrics.phy.sync.cfo, 2); + cout << float_to_string(metrics.phy.dl.mcs, 2); + cout << float_to_string(metrics.phy.dl.sinr, 2); + cout << float_to_string(metrics.phy.dl.turbo_iters, 2); + cout << float_to_eng_string((float) metrics.mac.rx_brate/metrics_report_period, 2); + if (metrics.mac.rx_pkts > 0) { + cout << float_to_string((float) 100*metrics.mac.rx_errors/metrics.mac.rx_pkts, 1) << "%"; + } else { + cout << float_to_string(0, 2) << "%"; + } + cout << float_to_string(metrics.phy.ul.mcs, 2); + cout << float_to_eng_string((float) metrics.mac.ul_buffer, 2); + cout << float_to_eng_string((float) metrics.mac.tx_brate/metrics_report_period, 2); + if (metrics.mac.tx_pkts > 0) { + cout << float_to_string((float) 100*metrics.mac.tx_errors/metrics.mac.tx_pkts, 1) << "%"; + } else { + cout << float_to_string(0, 2) << "%"; + } + cout << endl; + + if(metrics.rf.rf_error) { + printf("RF status: O=%d, U=%d, L=%d\n", metrics.rf.rf_o, metrics.rf.rf_u, metrics.rf.rf_l); + } + +} + +void metrics_stdout::print_disconnect() +{ + if(do_print) { + cout << "--- disconnected ---" << endl; + } +} + +std::string metrics_stdout::float_to_string(float f, int digits) +{ + std::ostringstream os; + const int precision = (f == 0.0) ? digits-1 : digits - log10(fabs(f))-2*DBL_EPSILON; + os << std::setw(6) << std::fixed << std::setprecision(precision) << f; + return os.str(); +} + +std::string metrics_stdout::float_to_eng_string(float f, int digits) +{ + const int degree = (f == 0.0) ? 0 : lrint( floor( log10( fabs( f ) ) / 3) ); + + std::string factor; + + if ( abs( degree ) < 9 ) + { + if(degree < 0) + factor = prefixes[0][ abs( degree ) ]; + else + factor = prefixes[1][ abs( degree ) ]; + } else { + return "failed"; + } + + const double scaled = f * pow( 1000.0, -degree ); + if (degree != 0) { + return float_to_string(scaled, digits) + factor; + } else { + return " " + float_to_string(scaled, digits) + factor; + } +} + +} // namespace srsue diff --git a/srsue/src/phy/CMakeLists.txt b/srsue/src/phy/CMakeLists.txt new file mode 100644 index 000000000..590b51411 --- /dev/null +++ b/srsue/src/phy/CMakeLists.txt @@ -0,0 +1,27 @@ +# +# Copyright 2013-2017 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(GLOB SOURCES "*.cc") +add_library(srsue_phy ${SOURCES}) +target_link_libraries(srsue_phy ${SRSLTE_PHY_LIBRARY}) + +if(ENABLE_GUI AND SRSGUI_FOUND) + target_link_libraries(srsue_phy ${SRSGUI_LIBRARIES}) +endif(ENABLE_GUI AND SRSGUI_FOUND) diff --git a/srsue/src/phy/phch_common.cc b/srsue/src/phy/phch_common.cc new file mode 100644 index 000000000..3c3987863 --- /dev/null +++ b/srsue/src/phy/phch_common.cc @@ -0,0 +1,334 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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 +#include +#include "srslte/srslte.h" +#include "phy/phch_common.h" + +#define Error(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->error_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Warning(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->warning_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Info(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->info_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Debug(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->debug_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) + +#define TX_MODE_CONTINUOUS 0 + +namespace srsue { + +cf_t zeros[50000]; + +phch_common::phch_common(uint32_t max_mutex_) : tx_mutex(max_mutex_) +{ + config = NULL; + args = NULL; + log_h = NULL; + radio_h = NULL; + mac = NULL; + max_mutex = max_mutex_; + nof_mutex = 0; + sr_enabled = false; + is_first_of_burst = true; + is_first_tx = true; + rar_grant_pending = false; + pathloss = 0; + cur_pathloss = 0; + cur_pusch_power = 0; + p0_preamble = 0; + cur_radio_power = 0; + rx_gain_offset = 0; + sr_last_tx_tti = -1; + cur_pusch_power = 0; + bzero(zeros, 50000*sizeof(cf_t)); + + bzero(&dl_metrics, sizeof(dl_metrics_t)); + dl_metrics_read = true; + dl_metrics_count = 0; + bzero(&ul_metrics, sizeof(ul_metrics_t)); + ul_metrics_read = true; + ul_metrics_count = 0; + bzero(&sync_metrics, sizeof(sync_metrics_t)); + sync_metrics_read = true; + sync_metrics_count = 0; +} + +void phch_common::init(phy_interface_rrc::phy_cfg_t *_config, phy_args_t *_args, srslte::log *_log, srslte::radio *_radio, mac_interface_phy *_mac) +{ + log_h = _log; + radio_h = _radio; + mac = _mac; + config = _config; + args = _args; + is_first_tx = true; + sr_last_tx_tti = -1; + + for (uint32_t i=0;i= ul_rnti_start && ul_rnti_start >= 0) || ul_rnti_start < 0) && + (((int)tti < ul_rnti_end && ul_rnti_end >= 0) || ul_rnti_end < 0)) + { + return true; + } else { + return false; + } +} + +bool phch_common::dl_rnti_active(uint32_t tti) { + Debug("tti=%d, dl_rnti_start=%d, dl_rnti_end=%d, dl_rnti=0x%x\n", tti, dl_rnti_start, dl_rnti_end, dl_rnti); + if ((((int)tti >= dl_rnti_start && dl_rnti_start >= 0) || dl_rnti_start < 0) && + (((int)tti < dl_rnti_end && dl_rnti_end >= 0) || dl_rnti_end < 0)) + { + bool ret = true; + // FIXME: This scheduling decision belongs to RRC + if (dl_rnti_type == SRSLTE_RNTI_SI) { + if (dl_rnti_end - dl_rnti_start > 1) { // This is not a SIB1 + if ((tti/10)%2 == 0 && (tti%10) == 5) { // Skip subframe #5 for which SFN mod 2 = 0 + ret = false; + } + } + } + return ret; + } else { + return false; + } +} + +srslte::radio* phch_common::get_radio() +{ + return radio_h; +} + +// Unpack RAR grant as defined in Section 6.2 of 36.213 +void phch_common::set_rar_grant(uint32_t tti, uint8_t grant_payload[SRSLTE_RAR_GRANT_LEN]) +{ + srslte_dci_rar_grant_unpack(&rar_grant, grant_payload); + rar_grant_pending = true; + // PUSCH is at n+6 or n+7 and phch_worker assumes default delay of 4 ttis + if (rar_grant.ul_delay) { + rar_grant_tti = (tti + 3) % 10240; + } else { + rar_grant_tti = (tti + 2) % 10240; + } +} + +bool phch_common::get_pending_rar(uint32_t tti, srslte_dci_rar_grant_t *rar_grant_) +{ + if (rar_grant_pending && tti >= rar_grant_tti) { + if (rar_grant_) { + rar_grant_pending = false; + memcpy(rar_grant_, &rar_grant, sizeof(srslte_dci_rar_grant_t)); + } + return true; + } + return false; +} + +/* Common variables used by all phy workers */ +uint16_t phch_common::get_ul_rnti(uint32_t tti) { + if (ul_rnti_active(tti)) { + return ul_rnti; + } else { + return 0; + } +} +srslte_rnti_type_t phch_common::get_ul_rnti_type() { + return ul_rnti_type; +} +void phch_common::set_ul_rnti(srslte_rnti_type_t type, uint16_t rnti_value, int tti_start, int tti_end) { + ul_rnti = rnti_value; + ul_rnti_type = type; + ul_rnti_start = tti_start; + ul_rnti_end = tti_end; +} +uint16_t phch_common::get_dl_rnti(uint32_t tti) { + if (dl_rnti_active(tti)) { + return dl_rnti; + } else { + return 0; + } +} +srslte_rnti_type_t phch_common::get_dl_rnti_type() { + return dl_rnti_type; +} +void phch_common::set_dl_rnti(srslte_rnti_type_t type, uint16_t rnti_value, int tti_start, int tti_end) { + dl_rnti = rnti_value; + dl_rnti_type = type; + dl_rnti_start = tti_start; + dl_rnti_end = tti_end; + Debug("Set DL rnti: start=%d, end=%d, value=0x%x\n", tti_start, tti_end, rnti_value); +} + +void phch_common::reset_pending_ack(uint32_t tti) { + pending_ack[tti%10].enabled = false; +} + +void phch_common::set_pending_ack(uint32_t tti, uint32_t I_lowest, uint32_t n_dmrs) { + pending_ack[tti%10].enabled = true; + pending_ack[tti%10].I_lowest = I_lowest; + pending_ack[tti%10].n_dmrs = n_dmrs; + Debug("Set pending ACK for tti=%d I_lowest=%d, n_dmrs=%d\n", tti, I_lowest, n_dmrs); +} + +bool phch_common::get_pending_ack(uint32_t tti) { + return get_pending_ack(tti, NULL, NULL); +} + +bool phch_common::get_pending_ack(uint32_t tti, uint32_t *I_lowest, uint32_t *n_dmrs) { + if (I_lowest) { + *I_lowest = pending_ack[tti%10].I_lowest; + } + if (n_dmrs) { + *n_dmrs = pending_ack[tti%10].n_dmrs; + } + return pending_ack[tti%10].enabled; +} + +/* The transmisison of UL subframes must be in sequence. Each worker uses this function to indicate + * that all processing is done and data is ready for transmission or there is no transmission at all (tx_enable). + * In that case, the end of burst message will be send to the radio + */ +void phch_common::worker_end(uint32_t tti, bool tx_enable, + cf_t *buffer, uint32_t nof_samples, + srslte_timestamp_t tx_time) +{ + + // Wait previous TTIs to be transmitted + if (is_first_tx) { + is_first_tx = false; + } else { + pthread_mutex_lock(&tx_mutex[tti%nof_mutex]); + } + + radio_h->set_tti(tti); + if (tx_enable) { + radio_h->tx(buffer, nof_samples, tx_time); + is_first_of_burst = false; + } else { + if (TX_MODE_CONTINUOUS) { + if (!is_first_of_burst) { + radio_h->tx(zeros, nof_samples, tx_time); + } + } else { + if (!is_first_of_burst) { + radio_h->tx_end(); + is_first_of_burst = true; + } + } + } + // Trigger next transmission + pthread_mutex_unlock(&tx_mutex[(tti+1)%nof_mutex]); + + // Trigger MAC clock + mac->tti_clock(tti); + +} + + +void phch_common::set_cell(const srslte_cell_t &c) { + cell = c; +} + +uint32_t phch_common::get_nof_prb() { + return cell.nof_prb; +} + +void phch_common::set_dl_metrics(const dl_metrics_t &m) { + if(dl_metrics_read) { + dl_metrics = m; + dl_metrics_count = 1; + dl_metrics_read = false; + } else { + dl_metrics_count++; + dl_metrics.mcs = dl_metrics.mcs + (m.mcs - dl_metrics.mcs)/dl_metrics_count; + dl_metrics.n = dl_metrics.n + (m.n - dl_metrics.n)/dl_metrics_count; + dl_metrics.rsrp = dl_metrics.rsrp + (m.rsrp - dl_metrics.rsrp)/dl_metrics_count; + dl_metrics.rsrq = dl_metrics.rsrq + (m.rsrq - dl_metrics.rsrq)/dl_metrics_count; + dl_metrics.rssi = dl_metrics.rssi + (m.rssi - dl_metrics.rssi)/dl_metrics_count; + dl_metrics.sinr = dl_metrics.sinr + (m.sinr - dl_metrics.sinr)/dl_metrics_count; + dl_metrics.pathloss = dl_metrics.pathloss + (m.pathloss - dl_metrics.pathloss)/dl_metrics_count; + dl_metrics.turbo_iters = dl_metrics.turbo_iters + (m.turbo_iters - dl_metrics.turbo_iters)/dl_metrics_count; + } +} + +void phch_common::get_dl_metrics(dl_metrics_t &m) { + m = dl_metrics; + dl_metrics_read = true; +} + +void phch_common::set_ul_metrics(const ul_metrics_t &m) { + if(ul_metrics_read) { + ul_metrics = m; + ul_metrics_count = 1; + ul_metrics_read = false; + } else { + ul_metrics_count++; + ul_metrics.mcs = ul_metrics.mcs + (m.mcs - ul_metrics.mcs)/ul_metrics_count; + ul_metrics.power = ul_metrics.power + (m.power - ul_metrics.power)/ul_metrics_count; + } +} + +void phch_common::get_ul_metrics(ul_metrics_t &m) { + m = ul_metrics; + ul_metrics_read = true; +} + +void phch_common::set_sync_metrics(const sync_metrics_t &m) { + + if(sync_metrics_read) { + sync_metrics = m; + sync_metrics_count = 1; + sync_metrics_read = false; + } else { + sync_metrics_count++; + sync_metrics.cfo = sync_metrics.cfo + (m.cfo - sync_metrics.cfo)/sync_metrics_count; + sync_metrics.sfo = sync_metrics.sfo + (m.sfo - sync_metrics.sfo)/sync_metrics_count; + } +} + +void phch_common::get_sync_metrics(sync_metrics_t &m) { + m = sync_metrics; + sync_metrics_read = true; +} + +void phch_common::reset_ul() +{ + is_first_tx = true; + is_first_of_burst = true; + for (uint32_t i=0;i +#include "srslte/srslte.h" +#include "srslte/common/log.h" +#include "phy/phch_worker.h" +#include "phy/phch_common.h" +#include "phy/phch_recv.h" + +#define Error(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->error_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Warning(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->warning_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Info(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->info_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Debug(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->debug_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) + +namespace srsue { + + +phch_recv::phch_recv() { + running = false; +} + +void phch_recv::init(srslte::radio_multi* _radio_handler, mac_interface_phy *_mac, rrc_interface_phy *_rrc, + prach* _prach_buffer, srslte::thread_pool* _workers_pool, + phch_common* _worker_com, srslte::log* _log_h, uint32_t nof_rx_antennas_, uint32_t prio, int sync_cpu_affinity) +{ + radio_h = _radio_handler; + log_h = _log_h; + mac = _mac; + rrc = _rrc; + workers_pool = _workers_pool; + worker_com = _worker_com; + prach_buffer = _prach_buffer; + nof_rx_antennas = nof_rx_antennas_; + + tx_mutex_cnt = 0; + running = true; + phy_state = IDLE; + time_adv_sec = 0; + cell_is_set = false; + sync_sfn_cnt = 0; + + for (uint32_t i=0;iget_nof_workers(); + worker_com->set_nof_mutex(nof_tx_mutex); + if(sync_cpu_affinity < 0){ + start(prio); + } else { + start_cpu(prio, sync_cpu_affinity); + } + + +} + +void phch_recv::stop() { + running = false; + wait_thread_finish(); + for (uint32_t i=0;irx_now(data, nsamples, rx_time)) { + int offset = nsamples-radio_h->get_tti_len(); + if (abs(offset)<10 && offset != 0) { + radio_h->tx_offset(offset); + } else if (nsamples<10) { + radio_h->tx_offset(nsamples); + } + return nsamples; + } else { + return -1; + } +} + +double callback_set_rx_gain(void *h, double gain) { + srslte::radio_multi *radio_handler = (srslte::radio_multi*) h; + return radio_handler->set_rx_gain_th(gain); +} + +void phch_recv::set_time_adv_sec(float _time_adv_sec) { + time_adv_sec = _time_adv_sec; +} + +void phch_recv::set_ue_sync_opts(srslte_ue_sync_t *q) { + if (worker_com->args->cfo_integer_enabled) { + srslte_ue_sync_cfo_i_detec_en(q, true); + } + + float cfo_tol = worker_com->args->cfo_correct_tol_hz; + srslte_cfo_set_tol(&q->strack.cfocorr, cfo_tol/(15000*q->fft_size)); + srslte_cfo_set_tol(&q->sfind.cfocorr, cfo_tol/(15000*q->fft_size)); + + int time_correct_period = worker_com->args->time_correct_period; + if (time_correct_period > 0) { + srslte_ue_sync_set_sample_offset_correct_period(q, time_correct_period); + } + + sss_alg_t sss_alg = SSS_FULL; + if (!worker_com->args->sss_algorithm.compare("diff")) { + sss_alg = SSS_DIFF; + } else if (!worker_com->args->sss_algorithm.compare("partial")) { + sss_alg = SSS_PARTIAL_3; + } else if (!worker_com->args->sss_algorithm.compare("full")){ + sss_alg = SSS_FULL; + } else { + Warning("Invalid SSS algorithm %s. Using 'full'\n", worker_com->args->sss_algorithm.c_str()); + } + srslte_sync_set_sss_algorithm(&q->strack, (sss_alg_t) sss_alg); + srslte_sync_set_sss_algorithm(&q->sfind, (sss_alg_t) sss_alg); +} + +bool phch_recv::init_cell() { + cell_is_set = false; + if (!srslte_ue_mib_init(&ue_mib, cell)) + { + if (!srslte_ue_sync_init_multi(&ue_sync, cell, radio_recv_wrapper_cs, nof_rx_antennas, radio_h)) + { + + // Set options defined in expert section + set_ue_sync_opts(&ue_sync); + + for (uint32_t i=0;iget_nof_workers();i++) { + if (!((phch_worker*) workers_pool->get_worker(i))->init_cell(cell)) { + Error("Error setting cell: initiating PHCH worker\n"); + return false; + } + } + radio_h->set_tti_len(SRSLTE_SF_LEN_PRB(cell.nof_prb)); + if (do_agc) { + srslte_ue_sync_start_agc(&ue_sync, callback_set_rx_gain, last_gain); + } + srslte_ue_sync_set_cfo(&ue_sync, cellsearch_cfo); + cell_is_set = true; + } else { + Error("Error setting cell: initiating ue_sync"); + } + } else { + Error("Error setting cell: initiating ue_mib\n"); + } + return cell_is_set; +} + +void phch_recv::free_cell() +{ + if (cell_is_set) { + for (uint32_t i=0;iget_nof_workers();i++) { + ((phch_worker*) workers_pool->get_worker(i))->free_cell(); + } + prach_buffer->free_cell(); + } +} + + +bool phch_recv::cell_search(int force_N_id_2) +{ + uint8_t bch_payload[SRSLTE_BCH_PAYLOAD_LEN]; + uint8_t bch_payload_bits[SRSLTE_BCH_PAYLOAD_LEN/8]; + + srslte_ue_cellsearch_result_t found_cells[3]; + srslte_ue_cellsearch_t cs; + + bzero(found_cells, 3*sizeof(srslte_ue_cellsearch_result_t)); + + log_h->console("Searching for cell...\n"); + if (srslte_ue_cellsearch_init_multi(&cs, SRSLTE_DEFAULT_MAX_FRAMES_PSS, radio_recv_wrapper_cs, nof_rx_antennas, radio_h)) { + Error("Initiating UE cell search\n"); + return false; + } + + srslte_ue_cellsearch_set_nof_valid_frames(&cs, SRSLTE_DEFAULT_NOF_VALID_PSS_FRAMES); + + // Set options defined in expert section + set_ue_sync_opts(&cs.ue_sync); + + if (do_agc) { + srslte_ue_sync_start_agc(&cs.ue_sync, callback_set_rx_gain, last_gain); + } + + radio_h->set_rx_srate(1.92e6); + radio_h->start_rx(); + + /* Find a cell in the given N_id_2 or go through the 3 of them to find the strongest */ + uint32_t max_peak_cell = 0; + int ret = SRSLTE_ERROR; + + if (force_N_id_2 >= 0 && force_N_id_2 < 3) { + ret = srslte_ue_cellsearch_scan_N_id_2(&cs, force_N_id_2, &found_cells[force_N_id_2]); + max_peak_cell = force_N_id_2; + } else { + ret = srslte_ue_cellsearch_scan(&cs, found_cells, &max_peak_cell); + } + + last_gain = srslte_agc_get_gain(&cs.ue_sync.agc); + + radio_h->stop_rx(); + srslte_ue_cellsearch_free(&cs); + + if (ret < 0) { + Error("Error decoding MIB: Error searching PSS\n"); + return false; + } else if (ret == 0) { + Error("Error decoding MIB: Could not find any PSS in this frequency\n"); + return false; + } + + // Save result + cell.id = found_cells[max_peak_cell].cell_id; + cell.cp = found_cells[max_peak_cell].cp; + cellsearch_cfo = found_cells[max_peak_cell].cfo; + + log_h->console("Found CELL ID: %d CP: %s, CFO: %.1f KHz.\nTrying to decode MIB...\n", + cell.id, srslte_cp_string(cell.cp), cellsearch_cfo/1000); + + srslte_ue_mib_sync_t ue_mib_sync; + + if (srslte_ue_mib_sync_init_multi(&ue_mib_sync, cell.id, cell.cp, radio_recv_wrapper_cs, nof_rx_antennas, radio_h)) { + Error("Initiating UE MIB synchronization\n"); + return false; + } + + // Set options defined in expert section + set_ue_sync_opts(&ue_mib_sync.ue_sync); + + if (do_agc) { + srslte_ue_sync_start_agc(&ue_mib_sync.ue_sync, callback_set_rx_gain, last_gain); + } + + srslte_ue_sync_set_cfo(&ue_mib_sync.ue_sync, cellsearch_cfo); + + /* Find and decode MIB */ + uint32_t sfn; + int sfn_offset; + radio_h->start_rx(); + ret = srslte_ue_mib_sync_decode(&ue_mib_sync, + SRSLTE_DEFAULT_MAX_FRAMES_PBCH, + bch_payload, &cell.nof_ports, &sfn_offset); + radio_h->stop_rx(); + last_gain = srslte_agc_get_gain(&ue_mib_sync.ue_sync.agc); + cellsearch_cfo = srslte_ue_sync_get_cfo(&ue_mib_sync.ue_sync); + srslte_ue_mib_sync_free(&ue_mib_sync); + + if (ret == 1) { + srslte_pbch_mib_unpack(bch_payload, &cell, NULL); + worker_com->set_cell(cell); + srslte_cell_fprint(stdout, &cell, 0); + + srslte_bit_pack_vector(bch_payload, bch_payload_bits, SRSLTE_BCH_PAYLOAD_LEN); + mac->bch_decoded_ok(bch_payload_bits, SRSLTE_BCH_PAYLOAD_LEN/8); + return true; + } else { + Warning("Error decoding MIB: Error decoding PBCH\n"); + return false; + } +} + + +int phch_recv::sync_sfn(void) { + + int ret = SRSLTE_ERROR; + uint8_t bch_payload[SRSLTE_BCH_PAYLOAD_LEN]; + + srslte_ue_sync_decode_sss_on_track(&ue_sync, true); + ret = srslte_ue_sync_zerocopy_multi(&ue_sync, sf_buffer_sfn); + if (ret < 0) { + Error("Error calling ue_sync_get_buffer"); + return -1; + } + + if (ret == 1) { + if (srslte_ue_sync_get_sfidx(&ue_sync) == 0) { + int sfn_offset=0; + Info("SYNC: Decoding MIB...\n"); + int n = srslte_ue_mib_decode(&ue_mib, sf_buffer_sfn[0], bch_payload, NULL, &sfn_offset); + if (n < 0) { + Error("Error decoding MIB while synchronising SFN"); + return -1; + } else if (n == SRSLTE_UE_MIB_FOUND) { + uint32_t sfn; + srslte_pbch_mib_unpack(bch_payload, &cell, &sfn); + + sfn = (sfn + sfn_offset)%1024; + tti = sfn*10; + + srslte_ue_sync_decode_sss_on_track(&ue_sync, true); + Info("SYNC: DONE, TTI=%d, sfn_offset=%d\n", tti, sfn_offset); + srslte_ue_mib_reset(&ue_mib); + return 1; + } + } + } else { + Debug("SYNC: PSS/SSS not found...\n"); + } + return 0; +} + +void phch_recv::resync_sfn() { + sync_sfn_cnt = 0; + phy_state = SYNCING; +} + +void phch_recv::run_thread() +{ + int sync_res; + phch_worker *worker = NULL; + cf_t *buffer[SRSLTE_MAX_PORTS]; + while(running) { + switch(phy_state) { + case CELL_SEARCH: + if (cell_search()) { + log_h->console("Initializating cell configuration...\n"); + init_cell(); + float srate = (float) srslte_sampling_freq_hz(cell.nof_prb); + + if (30720%((int) srate/1000) == 0) { + radio_h->set_master_clock_rate(30.72e6); + } else { + radio_h->set_master_clock_rate(23.04e6); + } + + log_h->console("Setting Sampling frequency %.2f MHz\n", (float) srate/1000000); + radio_h->set_rx_srate(srate); + radio_h->set_tx_srate(srate); + + ul_dl_factor = radio_h->get_tx_freq()/radio_h->get_rx_freq(); + + Info("SYNC: Cell found. Synchronizing...\n"); + phy_state = SYNCING; + sync_sfn_cnt = 0; + srslte_ue_mib_reset(&ue_mib); + } + break; + case SYNCING: + + srslte_ue_sync_decode_sss_on_track(&ue_sync, true); + + if (!radio_is_streaming) { + // Start streaming + radio_h->start_rx(); + radio_is_streaming = true; + } + + switch(sync_sfn()) { + default: + log_h->console("Going IDLE\n"); + phy_state = IDLE; + break; + case 1: + srslte_ue_sync_set_agc_period(&ue_sync, 20); + phy_state = SYNC_DONE; + break; + case 0: + break; + } + sync_sfn_cnt++; + if (sync_sfn_cnt >= SYNC_SFN_TIMEOUT) { + sync_sfn_cnt = 0; + radio_h->stop_rx(); + radio_is_streaming = false; + log_h->console("Timeout while synchronizing SFN\n"); + log_h->warning("Timeout while synchronizing SFN\n"); + } + break; + case SYNC_DONE: + tti = (tti+1)%10240; + worker = (phch_worker*) workers_pool->wait_worker(tti); + sync_res = 0; + if (worker) { + for (uint32_t i=0;iget_buffer(i); + } + + sync_res = srslte_ue_sync_zerocopy_multi(&ue_sync, buffer); + if (sync_res == 1) { + + log_h->step(tti); + + Debug("Worker %d synchronized\n", worker->get_id()); + + metrics.sfo = srslte_ue_sync_get_sfo(&ue_sync); + metrics.cfo = srslte_ue_sync_get_cfo(&ue_sync); + worker->set_cfo(ul_dl_factor*metrics.cfo/15000); + worker_com->set_sync_metrics(metrics); + + float sample_offset = (float) srslte_ue_sync_get_sfo(&ue_sync)/1000; + worker->set_sample_offset(sample_offset); + + /* Compute TX time: Any transmission happens in TTI+4 thus advance 4 ms the reception time */ + srslte_timestamp_t rx_time, tx_time, tx_time_prach; + srslte_ue_sync_get_last_timestamp(&ue_sync, &rx_time); + srslte_timestamp_copy(&tx_time, &rx_time); + srslte_timestamp_add(&tx_time, 0, 4e-3 - time_adv_sec); + worker->set_tx_time(tx_time); + + Debug("Settting TTI=%d, tx_mutex=%d to worker %d\n", tti, tx_mutex_cnt, worker->get_id()); + worker->set_tti(tti, tx_mutex_cnt); + tx_mutex_cnt = (tx_mutex_cnt+1)%nof_tx_mutex; + + // Check if we need to TX a PRACH + if (prach_buffer->is_ready_to_send(tti)) { + srslte_timestamp_copy(&tx_time_prach, &rx_time); + srslte_timestamp_add(&tx_time_prach, 0, prach::tx_advance_sf*1e-3); + prach_buffer->send(radio_h, ul_dl_factor*metrics.cfo/15000, worker_com->pathloss, tx_time_prach); + radio_h->tx_end(); + worker_com->p0_preamble = prach_buffer->get_p0_preamble(); + worker_com->cur_radio_power = SRSLTE_MIN(SRSLTE_PC_MAX, worker_com->pathloss + worker_com->p0_preamble); + } + workers_pool->start_worker(worker); + // Notify RRC in-sync every 1 frame + if ((tti%10) == 0) { + rrc->in_sync(); + log_h->debug("Sending in-sync to RRC\n"); + } + } else { + log_h->console("Sync error.\n"); + log_h->error("Sync error. Sending out-of-sync to RRC\n"); + // Notify RRC of out-of-sync frame + rrc->out_of_sync(); + worker->release(); + worker_com->reset_ul(); + phy_state = SYNCING; + } + } else { + // wait_worker() only returns NULL if it's being closed. Quit now to avoid unnecessary loops here + running = false; + } + break; + case IDLE: + usleep(1000); + break; + } + } +} + +uint32_t phch_recv::get_current_tti() +{ + return tti; +} + +bool phch_recv::status_is_sync() +{ + return phy_state == SYNC_DONE; +} + +void phch_recv::get_current_cell(srslte_cell_t* cell_) +{ + if (cell_) { + memcpy(cell_, &cell, sizeof(srslte_cell_t)); + } +} + +void phch_recv::sync_start() +{ + radio_h->set_master_clock_rate(30.72e6); + phy_state = CELL_SEARCH; +} + +void phch_recv::sync_stop() +{ + free_cell(); + radio_h->stop_rx(); + radio_is_streaming = false; + phy_state = IDLE; +} + +} diff --git a/srsue/src/phy/phch_worker.cc b/srsue/src/phy/phch_worker.cc new file mode 100644 index 000000000..14de9b51a --- /dev/null +++ b/srsue/src/phy/phch_worker.cc @@ -0,0 +1,1167 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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 +#include +#include "phy/phch_worker.h" +#include "srslte/interfaces/ue_interfaces.h" +#include "srslte/asn1/liblte_rrc.h" + +#define Error(fmt, ...) if (SRSLTE_DEBUG_ENABLED) phy->log_h->error_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Warning(fmt, ...) if (SRSLTE_DEBUG_ENABLED) phy->log_h->warning_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Info(fmt, ...) if (SRSLTE_DEBUG_ENABLED) phy->log_h->info_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Debug(fmt, ...) if (SRSLTE_DEBUG_ENABLED) phy->log_h->debug_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) + + +/* This is to visualize the channel response */ +#ifdef ENABLE_GUI +#include "srsgui/srsgui.h" +#include +void init_plots(srsue::phch_worker *worker); +pthread_t plot_thread; +sem_t plot_sem; +static int plot_worker_id = -1; +#else +#warning Compiling without srsGUI support +#endif +/*********************************************/ + + +namespace srsue { + + +phch_worker::phch_worker() : tr_exec(10240) +{ + phy = NULL; + bzero(signal_buffer, sizeof(cf_t*)*SRSLTE_MAX_PORTS); + + cell_initiated = false; + pregen_enabled = false; + trace_enabled = false; + + reset(); +} + +void phch_worker::reset() +{ + bzero(&dl_metrics, sizeof(dl_metrics_t)); + bzero(&ul_metrics, sizeof(ul_metrics_t)); + bzero(&dmrs_cfg, sizeof(srslte_refsignal_dmrs_pusch_cfg_t)); + bzero(&pusch_hopping, sizeof(srslte_pusch_hopping_cfg_t)); + bzero(&uci_cfg, sizeof(srslte_uci_cfg_t)); + bzero(&pucch_cfg, sizeof(srslte_pucch_cfg_t)); + bzero(&pucch_sched, sizeof(srslte_pucch_sched_t)); + bzero(&srs_cfg, sizeof(srslte_refsignal_srs_cfg_t)); + bzero(&period_cqi, sizeof(srslte_cqi_periodic_cfg_t)); + I_sr = 0; + rnti_is_set = false; + rar_cqi_request = false; + cfi = 0; +} + +void phch_worker::set_common(phch_common* phy_) +{ + phy = phy_; +} + +bool phch_worker::init_cell(srslte_cell_t cell_) +{ + memcpy(&cell, &cell_, sizeof(srslte_cell_t)); + + // ue_sync in phy.cc requires a buffer for 3 subframes + for (uint32_t i=0;iargs->nof_rx_ant;i++) { + signal_buffer[i] = (cf_t*) srslte_vec_malloc(3 * sizeof(cf_t) * SRSLTE_SF_LEN_PRB(cell.nof_prb)); + if (!signal_buffer[i]) { + Error("Allocating memory\n"); + return false; + } + } + + if (srslte_ue_dl_init_multi(&ue_dl, cell, phy->args->nof_rx_ant)) { + Error("Initiating UE DL\n"); + return false; + } + + if (srslte_ue_ul_init(&ue_ul, cell)) { + Error("Initiating UE UL\n"); + return false; + } + srslte_ue_ul_set_normalization(&ue_ul, true); + srslte_ue_ul_set_cfo_enable(&ue_ul, true); + + cell_initiated = true; + + return true; +} + +void phch_worker::free_cell() +{ + if (cell_initiated) { + for (uint32_t i=0;iargs->nof_rx_ant;i++) { + if (signal_buffer[i]) { + free(signal_buffer[i]); + } + } + srslte_ue_dl_free(&ue_dl); + srslte_ue_ul_free(&ue_ul); + } +} + +cf_t* phch_worker::get_buffer(uint32_t antenna_idx) +{ + return signal_buffer[antenna_idx]; +} + +void phch_worker::set_tti(uint32_t tti_, uint32_t tx_tti_) +{ + tti = tti_; + tx_tti = tx_tti_; +} + +void phch_worker::set_cfo(float cfo_) +{ + cfo = cfo_; +} + +void phch_worker::set_sample_offset(float sample_offset) +{ + if (phy->args->sfo_correct_disable) { + sample_offset = 0; + } + srslte_ue_dl_set_sample_offset(&ue_dl, sample_offset); +} + +void phch_worker::set_crnti(uint16_t rnti) +{ + srslte_ue_dl_set_rnti(&ue_dl, rnti); + srslte_ue_ul_set_rnti(&ue_ul, rnti); + rnti_is_set = true; +} + +void phch_worker::work_imp() +{ + if (!cell_initiated) { + return; + } + + Debug("TTI %d running\n", tti); + +#ifdef LOG_EXECTIME + gettimeofday(&logtime_start[1], NULL); +#endif + + tr_log_start(); + + reset_uci(); + + bool dl_grant_available = false; + bool ul_grant_available = false; + bool dl_ack = false; + + mac_interface_phy::mac_grant_t dl_mac_grant; + mac_interface_phy::tb_action_dl_t dl_action; + bzero(&dl_action, sizeof(mac_interface_phy::tb_action_dl_t)); + + mac_interface_phy::mac_grant_t ul_mac_grant; + mac_interface_phy::tb_action_ul_t ul_action; + bzero(&ul_action, sizeof(mac_interface_phy::tb_action_ul_t)); + + /* Do FFT and extract PDCCH LLR, or quit if no actions are required in this subframe */ + if (extract_fft_and_pdcch_llr()) { + + + /***** Downlink Processing *******/ + + /* PDCCH DL + PDSCH */ + dl_grant_available = decode_pdcch_dl(&dl_mac_grant); + if(dl_grant_available) { + /* Send grant to MAC and get action for this TB */ + phy->mac->new_grant_dl(dl_mac_grant, &dl_action); + + /* Decode PDSCH if instructed to do so */ + dl_ack = dl_action.default_ack; + if (dl_action.decode_enabled) { + dl_ack = decode_pdsch(&dl_action.phy_grant.dl, dl_action.payload_ptr, + dl_action.softbuffer, dl_action.rv, dl_action.rnti, + dl_mac_grant.pid); + } + if (dl_action.generate_ack_callback && dl_action.decode_enabled) { + phy->mac->tb_decoded(dl_ack, dl_mac_grant.rnti_type, dl_mac_grant.pid); + dl_ack = dl_action.generate_ack_callback(dl_action.generate_ack_callback_arg); + Debug("Calling generate ACK callback returned=%d\n", dl_ack); + } + Debug("dl_ack=%d, generate_ack=%d\n", dl_ack, dl_action.generate_ack); + if (dl_action.generate_ack) { + set_uci_ack(dl_ack); + } + } + } + + // Decode PHICH + bool ul_ack; + bool ul_ack_available = decode_phich(&ul_ack); + + /***** Uplink Processing + Transmission *******/ + + /* Generate SR if required*/ + set_uci_sr(); + + /* Check if we have UL grant. ul_phy_grant will be overwritten by new grant */ + ul_grant_available = decode_pdcch_ul(&ul_mac_grant); + + /* Generate CQI reports if required, note that in case both aperiodic + and periodic ones present, only aperiodic is sent (36.213 section 7.2) */ + if (ul_grant_available && ul_mac_grant.has_cqi_request) { + set_uci_aperiodic_cqi(); + } else { + set_uci_periodic_cqi(); + } + + /* Send UL grant or HARQ information (from PHICH) to MAC */ + if (ul_grant_available && ul_ack_available) { + phy->mac->new_grant_ul_ack(ul_mac_grant, ul_ack, &ul_action); + } else if (ul_grant_available && !ul_ack_available) { + phy->mac->new_grant_ul(ul_mac_grant, &ul_action); + } else if (!ul_grant_available && ul_ack_available) { + phy->mac->harq_recv(tti, ul_ack, &ul_action); + } + + /* Set UL CFO before transmission */ + srslte_ue_ul_set_cfo(&ue_ul, cfo); + + /* Transmit PUSCH, PUCCH or SRS */ + bool signal_ready = false; + if (ul_action.tx_enabled) { + encode_pusch(&ul_action.phy_grant.ul, ul_action.payload_ptr, ul_action.current_tx_nb, + ul_action.softbuffer, ul_action.rv, ul_action.rnti, ul_mac_grant.is_from_rar); + signal_ready = true; + if (ul_action.expect_ack) { + phy->set_pending_ack(tti + 8, ue_ul.pusch_cfg.grant.n_prb_tilde[0], ul_action.phy_grant.ul.ncs_dmrs); + } + + } else if (dl_action.generate_ack || uci_data.scheduling_request || uci_data.uci_cqi_len > 0) { + encode_pucch(); + signal_ready = true; + } else if (srs_is_ready_to_send()) { + encode_srs(); + signal_ready = true; + } + + tr_log_end(); + + phy->worker_end(tx_tti, signal_ready, signal_buffer[0], SRSLTE_SF_LEN_PRB(cell.nof_prb), tx_time); + + if (dl_action.decode_enabled && !dl_action.generate_ack_callback) { + if (dl_mac_grant.rnti_type == SRSLTE_RNTI_PCH) { + phy->mac->pch_decoded_ok(dl_mac_grant.n_bytes); + } else { + phy->mac->tb_decoded(dl_ack, dl_mac_grant.rnti_type, dl_mac_grant.pid); + } + } + + update_measurements(); + + /* Tell the plotting thread to draw the plots */ +#ifdef ENABLE_GUI + if ((int) get_id() == plot_worker_id) { + sem_post(&plot_sem); + } +#endif +} + + +bool phch_worker::extract_fft_and_pdcch_llr() { + bool decode_pdcch = false; + if (phy->get_ul_rnti(tti) || phy->get_dl_rnti(tti) || phy->get_pending_rar(tti)) { + decode_pdcch = true; + } + + /* Without a grant, we might need to do fft processing if need to decode PHICH */ + if (phy->get_pending_ack(tti) || decode_pdcch) { + + // Setup estimator filter + float w_coeff = phy->args->estimator_fil_w; + if (w_coeff > 0.0) { + srslte_chest_dl_set_smooth_filter3_coeff(&ue_dl.chest, w_coeff); + } else if (w_coeff == 0.0) { + srslte_chest_dl_set_smooth_filter(&ue_dl.chest, NULL, 0); + } + + if (!phy->args->snr_estim_alg.compare("refs")) { + srslte_chest_dl_set_noise_alg(&ue_dl.chest, SRSLTE_NOISE_ALG_REFS); + } else if (!phy->args->snr_estim_alg.compare("empty")) { + srslte_chest_dl_set_noise_alg(&ue_dl.chest, SRSLTE_NOISE_ALG_EMPTY); + } else { + srslte_chest_dl_set_noise_alg(&ue_dl.chest, SRSLTE_NOISE_ALG_PSS); + } + + if (srslte_ue_dl_decode_fft_estimate_multi(&ue_dl, signal_buffer, tti%10, &cfi) < 0) { + Error("Getting PDCCH FFT estimate\n"); + return false; + } + chest_done = true; + } else { + chest_done = false; + } + if (chest_done && decode_pdcch) { /* and not in DRX mode */ + + float noise_estimate = phy->avg_noise; + + if (!phy->args->equalizer_mode.compare("zf")) { + noise_estimate = 0; + } + + if (srslte_pdcch_extract_llr_multi(&ue_dl.pdcch, ue_dl.sf_symbols_m, ue_dl.ce_m, noise_estimate, tti%10, cfi)) { + Error("Extracting PDCCH LLR\n"); + return false; + } + } + return (decode_pdcch || phy->get_pending_ack(tti)); +} + + + + + + + + + +/********************* Downlink processing functions ****************************/ + +bool phch_worker::decode_pdcch_dl(srsue::mac_interface_phy::mac_grant_t* grant) +{ + char timestr[64]; + timestr[0]='\0'; + + dl_rnti = phy->get_dl_rnti(tti); + if (dl_rnti) { + + srslte_rnti_type_t type = phy->get_dl_rnti_type(); + + srslte_dci_msg_t dci_msg; + srslte_ra_dl_dci_t dci_unpacked; + + Debug("Looking for RNTI=0x%x\n", dl_rnti); + + if (srslte_ue_dl_find_dl_dci_type(&ue_dl, cfi, tti%10, dl_rnti, type, &dci_msg) != 1) { + return false; + } + + if (srslte_dci_msg_to_dl_grant(&dci_msg, dl_rnti, cell.nof_prb, cell.nof_ports, &dci_unpacked, &grant->phy_grant.dl)) { + Error("Converting DCI message to DL grant\n"); + return false; + } + + /* Fill MAC grant structure */ + grant->ndi = dci_unpacked.ndi; + grant->pid = dci_unpacked.harq_process; + grant->n_bytes = grant->phy_grant.dl.mcs.tbs/8; + grant->tti = tti; + grant->rv = dci_unpacked.rv_idx; + grant->rnti = dl_rnti; + grant->rnti_type = type; + grant->last_tti = 0; + + last_dl_pdcch_ncce = srslte_ue_dl_get_ncce(&ue_dl); + + char hexstr[16]; + hexstr[0]='\0'; + if (phy->log_h->get_level() >= srslte::LOG_LEVEL_INFO) { + srslte_vec_sprint_hex(hexstr, dci_msg.data, dci_msg.nof_bits); + } + Info("PDCCH: DL DCI %s cce_index=%2d, L=%d, n_data_bits=%d, hex=%s\n", srslte_dci_format_string(dci_msg.format), + last_dl_pdcch_ncce, (1<= 0 && rv <= 3) { + if (!srslte_ue_dl_cfg_grant(&ue_dl, grant, cfi, tti%10, rv)) { + if (ue_dl.pdsch_cfg.grant.mcs.mod > 0 && ue_dl.pdsch_cfg.grant.mcs.tbs >= 0) { + + float noise_estimate = srslte_chest_dl_get_noise_estimate(&ue_dl.chest); + + if (!phy->args->equalizer_mode.compare("zf")) { + noise_estimate = 0; + } + + /* Set decoder iterations */ + if (phy->args->pdsch_max_its > 0) { + srslte_sch_set_max_noi(&ue_dl.pdsch.dl_sch, phy->args->pdsch_max_its); + } + + + #ifdef LOG_EXECTIME + struct timeval t[3]; + gettimeofday(&t[1], NULL); + #endif + + bool ack = srslte_pdsch_decode_multi(&ue_dl.pdsch, &ue_dl.pdsch_cfg, softbuffer, ue_dl.sf_symbols_m, + ue_dl.ce_m, noise_estimate, rnti, payload) == 0; + #ifdef LOG_EXECTIME + gettimeofday(&t[2], NULL); + get_time_interval(t); + snprintf(timestr, 64, ", dec_time=%4d us", (int) t[0].tv_usec); + #endif + + Info("PDSCH: l_crb=%2d, harq=%d, tbs=%d, mcs=%d, rv=%d, crc=%s, snr=%.1f dB, n_iter=%d%s\n", + grant->nof_prb, harq_pid, + grant->mcs.tbs/8, grant->mcs.idx, rv, + ack?"OK":"KO", + 10*log10(srslte_chest_dl_get_snr(&ue_dl.chest)), + srslte_pdsch_last_noi(&ue_dl.pdsch), + timestr); + + //printf("tti=%d, cfo=%f\n", tti, cfo*15000); + //srslte_vec_save_file("pdsch", signal_buffer, sizeof(cf_t)*SRSLTE_SF_LEN_PRB(cell.nof_prb)); + + // Store metrics + dl_metrics.mcs = grant->mcs.idx; + + return ack; + } else { + Warning("Received grant for TBS=0\n"); + } + } else { + Error("Error configuring DL grant\n"); + } + } else { + Error("Error RV is not set or is invalid (%d)\n", rv); + } + return true; +} + +bool phch_worker::decode_phich(bool *ack) +{ + uint32_t I_lowest, n_dmrs; + if (phy->get_pending_ack(tti, &I_lowest, &n_dmrs)) { + if (ack) { + *ack = srslte_ue_dl_decode_phich(&ue_dl, tti%10, I_lowest, n_dmrs); + Info("PHICH: hi=%d, I_lowest=%d, n_dmrs=%d\n", *ack, I_lowest, n_dmrs); + } + phy->reset_pending_ack(tti); + return true; + } else { + return false; + } +} + + + + +/********************* Uplink processing functions ****************************/ + +bool phch_worker::decode_pdcch_ul(mac_interface_phy::mac_grant_t* grant) +{ + char timestr[64]; + timestr[0]='\0'; + + phy->reset_pending_ack(tti + 8); + + srslte_dci_msg_t dci_msg; + srslte_ra_ul_dci_t dci_unpacked; + srslte_dci_rar_grant_t rar_grant; + srslte_rnti_type_t type = phy->get_ul_rnti_type(); + + bool ret = false; + if (phy->get_pending_rar(tti, &rar_grant)) { + + if (srslte_dci_rar_to_ul_grant(&rar_grant, cell.nof_prb, pusch_hopping.hopping_offset, + &dci_unpacked, &grant->phy_grant.ul)) + { + Error("Converting RAR message to UL grant\n"); + return false; + } + grant->rnti_type = SRSLTE_RNTI_TEMP; + grant->is_from_rar = true; + grant->has_cqi_request = false; // In contention-based Random Access CQI request bit is reserved + Debug("RAR grant found for TTI=%d\n", tti); + ret = true; + } else { + ul_rnti = phy->get_ul_rnti(tti); + if (ul_rnti) { + if (srslte_ue_dl_find_ul_dci(&ue_dl, cfi, tti%10, ul_rnti, &dci_msg) != 1) { + return false; + } + + if (srslte_dci_msg_to_ul_grant(&dci_msg, cell.nof_prb, pusch_hopping.hopping_offset, + &dci_unpacked, &grant->phy_grant.ul, tti)) + { + Error("Converting DCI message to UL grant\n"); + return false; + } + grant->rnti_type = type; + grant->is_from_rar = false; + grant->has_cqi_request = dci_unpacked.cqi_request; + ret = true; + + char hexstr[16]; + hexstr[0]='\0'; + if (phy->log_h->get_level() >= srslte::LOG_LEVEL_INFO) { + srslte_vec_sprint_hex(hexstr, dci_msg.data, dci_msg.nof_bits); + } + // Change to last_location_ul + Info("PDCCH: UL DCI Format0 cce_index=%d, L=%d, n_data_bits=%d, hex=%s\n", + ue_dl.last_location_ul.ncce, (1<phy_grant.ul.mcs.tbs==0) { + srslte_vec_fprint_hex(stdout, dci_msg.data, dci_msg.nof_bits); + } + } + } + + /* Limit UL modulation if not supported by the UE or disabled by higher layers */ + if (!phy->config->enable_64qam) { + if (grant->phy_grant.ul.mcs.mod == SRSLTE_MOD_64QAM) { + grant->phy_grant.ul.mcs.mod = SRSLTE_MOD_16QAM; + grant->phy_grant.ul.Qm = 4; + } + } + + /* Make sure the grant is valid */ + if (ret && !srslte_dft_precoding_valid_prb(grant->phy_grant.ul.L_prb) && grant->phy_grant.ul.L_prb <= cell.nof_prb) { + Warning("Received invalid UL grant. L=%d\n", grant->phy_grant.ul.L_prb); + ret = false; + } + + if (ret) { + grant->ndi = dci_unpacked.ndi; + grant->pid = 0; // This is computed by MAC from TTI + grant->n_bytes = grant->phy_grant.ul.mcs.tbs/8; + grant->tti = tti; + grant->rnti = ul_rnti; + grant->rv = dci_unpacked.rv_idx; + if (SRSLTE_VERBOSE_ISINFO()) { + srslte_ra_pusch_fprint(stdout, &dci_unpacked, cell.nof_prb); + } + + return true; + } else { + return false; + } +} + +void phch_worker::reset_uci() +{ + bzero(&uci_data, sizeof(srslte_uci_data_t)); +} + +void phch_worker::set_uci_ack(bool ack) +{ + uci_data.uci_ack = ack?1:0; + uci_data.uci_ack_len = 1; +} + +void phch_worker::set_uci_sr() +{ + uci_data.scheduling_request = false; + if (phy->sr_enabled) { + uint32_t sr_tx_tti = (tti+4)%10240; + // Get I_sr parameter + if (srslte_ue_ul_sr_send_tti(I_sr, sr_tx_tti)) { + Info("PUCCH: SR transmission at TTI=%d, I_sr=%d\n", sr_tx_tti, I_sr); + uci_data.scheduling_request = true; + phy->sr_last_tx_tti = sr_tx_tti; + phy->sr_enabled = false; + } + } +} + +void phch_worker::set_uci_periodic_cqi() +{ + int cqi_fixed = phy->args->cqi_fixed; + int cqi_max = phy->args->cqi_max; + + if (period_cqi.configured && rnti_is_set) { + if (srslte_cqi_send(period_cqi.pmi_idx, (tti+4)%10240)) { + srslte_cqi_value_t cqi_report; + if (period_cqi.format_is_subband) { + // TODO: Implement subband periodic reports + cqi_report.type = SRSLTE_CQI_TYPE_SUBBAND; + cqi_report.subband.subband_cqi = srslte_cqi_from_snr(phy->avg_snr_db); + cqi_report.subband.subband_label = 0; + phy->log_h->console("Warning: Subband CQI periodic reports not implemented\n"); + Info("PUCCH: Periodic CQI=%d, SNR=%.1f dB\n", cqi_report.subband.subband_cqi, phy->avg_snr_db); + } else { + cqi_report.type = SRSLTE_CQI_TYPE_WIDEBAND; + if (cqi_fixed >= 0) { + cqi_report.wideband.wideband_cqi = cqi_fixed; + } else { + cqi_report.wideband.wideband_cqi = srslte_cqi_from_snr(phy->avg_snr_db); + } + if (cqi_max >= 0 && cqi_report.wideband.wideband_cqi > cqi_max) { + cqi_report.wideband.wideband_cqi = cqi_max; + } + Info("PUCCH: Periodic CQI=%d, SNR=%.1f dB\n", cqi_report.wideband.wideband_cqi, phy->avg_snr_db); + } + uci_data.uci_cqi_len = srslte_cqi_value_pack(&cqi_report, uci_data.uci_cqi); + rar_cqi_request = false; + } + } +} + +void phch_worker::set_uci_aperiodic_cqi() +{ + if (phy->config->dedicated.cqi_report_cnfg.report_mode_aperiodic_present) { + switch(phy->config->dedicated.cqi_report_cnfg.report_mode_aperiodic) { + case LIBLTE_RRC_CQI_REPORT_MODE_APERIODIC_RM30: + /* only Higher Layer-configured subband feedback support right now, according to TS36.213 section 7.2.1 + - A UE shall report a wideband CQI value which is calculated assuming transmission on set S subbands + - The UE shall also report one subband CQI value for each set S subband. The subband CQI + value is calculated assuming transmission only in the subband + - Both the wideband and subband CQI represent channel quality for the first codeword, + even when RI>1 + - For transmission mode 3 the reported CQI values are calculated conditioned on the + reported RI. For other transmission modes they are reported conditioned on rank 1. + */ + if (rnti_is_set) { + srslte_cqi_value_t cqi_report; + cqi_report.type = SRSLTE_CQI_TYPE_SUBBAND_HL; + cqi_report.subband_hl.wideband_cqi = srslte_cqi_from_snr(phy->avg_snr_db); + + // TODO: implement subband CQI properly + cqi_report.subband_hl.subband_diff_cqi = 0; // Always report zero offset on all subbands + cqi_report.subband_hl.N = (cell.nof_prb > 7) ? srslte_cqi_hl_get_no_subbands(cell.nof_prb) : 0; + + Info("PUSCH: Aperiodic CQI=%d, SNR=%.1f dB, for %d subbands\n", cqi_report.wideband.wideband_cqi, phy->avg_snr_db, cqi_report.subband_hl.N); + uci_data.uci_cqi_len = srslte_cqi_value_pack(&cqi_report, uci_data.uci_cqi); + } + break; + default: + Warning("Received CQI request but mode %s is not supported\n", + liblte_rrc_cqi_report_mode_aperiodic_text[phy->config->dedicated.cqi_report_cnfg.report_mode_aperiodic]); + break; + } + } else { + Warning("Received CQI request but aperiodic mode is not configured\n"); + } +} + +bool phch_worker::srs_is_ready_to_send() { + if (srs_cfg.configured) { + if (srslte_refsignal_srs_send_cs(srs_cfg.subframe_config, (tti+4)%10) == 1 && + srslte_refsignal_srs_send_ue(srs_cfg.I_srs, (tti+4)%10240) == 1) + { + return true; + } + } + return false; +} + +void phch_worker::set_tx_time(srslte_timestamp_t _tx_time) +{ + memcpy(&tx_time, &_tx_time, sizeof(srslte_timestamp_t)); +} + +void phch_worker::encode_pusch(srslte_ra_ul_grant_t *grant, uint8_t *payload, uint32_t current_tx_nb, + srslte_softbuffer_tx_t* softbuffer, uint32_t rv, uint16_t rnti, bool is_from_rar) +{ + char timestr[64]; + timestr[0]='\0'; + + if (srslte_ue_ul_cfg_grant(&ue_ul, grant, (tti+4)%10240, rv, current_tx_nb)) { + Error("Configuring UL grant\n"); + } + + if (srslte_ue_ul_pusch_encode_rnti_softbuffer(&ue_ul, + payload, uci_data, + softbuffer, + rnti, + signal_buffer[0])) + { + Error("Encoding PUSCH\n"); + } + + float p0_preamble = 0; + if (is_from_rar) { + p0_preamble = phy->p0_preamble; + } + float tx_power = srslte_ue_ul_pusch_power(&ue_ul, phy->pathloss, p0_preamble); + float gain = set_power(tx_power); + + // Save PUSCH power for PHR calculation + phy->cur_pusch_power = tx_power; + +#ifdef LOG_EXECTIME + gettimeofday(&logtime_start[2], NULL); + get_time_interval(logtime_start); + snprintf(timestr, 64, ", total_time=%4d us", (int) logtime_start[0].tv_usec); +#endif + + Info("PUSCH: tti_tx=%d, n_prb=%d, rb_start=%d, tbs=%d, mod=%d, mcs=%d, rv_idx=%d, ack=%s, cfo=%.1f Hz%s\n", + (tti+4)%10240, + grant->L_prb, grant->n_prb[0], + grant->mcs.tbs/8, grant->mcs.mod, grant->mcs.idx, rv, + uci_data.uci_ack_len>0?(uci_data.uci_ack?"1":"0"):"no", + cfo*15000, timestr); + + // Store metrics + ul_metrics.mcs = grant->mcs.idx; + ul_metrics.power = tx_power; + phy->set_ul_metrics(ul_metrics); +} + +void phch_worker::encode_pucch() +{ + char timestr[64]; + timestr[0]='\0'; + + if (uci_data.scheduling_request || uci_data.uci_ack_len > 0 || uci_data.uci_cqi_len > 0) + { + + // Drop CQI if there is collision with ACK + if (!period_cqi.simul_cqi_ack && uci_data.uci_ack_len > 0 && uci_data.uci_cqi_len > 0) { + uci_data.uci_cqi_len = 0; + } + +#ifdef LOG_EXECTIME + struct timeval t[3]; + gettimeofday(&t[1], NULL); +#endif + + if (srslte_ue_ul_pucch_encode(&ue_ul, uci_data, last_dl_pdcch_ncce, (tti+4)%10240, signal_buffer[0])) { + Error("Encoding PUCCH\n"); + } + +#ifdef LOG_EXECTIME + gettimeofday(&logtime_start[2], NULL); + memcpy(&t[2], &logtime_start[2], sizeof(struct timeval)); + get_time_interval(logtime_start); + get_time_interval(t); + snprintf(timestr, 64, ", enc_time=%d, total_time=%d us", (int) t[0].tv_usec, (int) logtime_start[0].tv_usec); +#endif + + float tx_power = srslte_ue_ul_pucch_power(&ue_ul, phy->pathloss, ue_ul.last_pucch_format, uci_data.uci_cqi_len, uci_data.uci_ack_len); + float gain = set_power(tx_power); + + Info("PUCCH: power=%.2f dBm, tti_tx=%d, n_cce=%3d, n_pucch=%d, n_prb=%d, ack=%s, sr=%s, cfo=%.1f Hz%s\n", + tx_power, (tti+4)%10240, + last_dl_pdcch_ncce, ue_ul.pucch.last_n_pucch, ue_ul.pucch.last_n_prb, + uci_data.uci_ack_len>0?(uci_data.uci_ack?"1":"0"):"no",uci_data.scheduling_request?"yes":"no", + cfo*15000, timestr); + } + + if (uci_data.scheduling_request) { + phy->sr_enabled = false; + } +} + +void phch_worker::encode_srs() +{ + char timestr[64]; + timestr[0]='\0'; + + if (srslte_ue_ul_srs_encode(&ue_ul, (tti+4)%10240, signal_buffer[0])) + { + Error("Encoding SRS\n"); + } + +#ifdef LOG_EXECTIME + gettimeofday(&logtime_start[2], NULL); + get_time_interval(logtime_start); + snprintf(timestr, 64, ", total_time=%4d us", (int) logtime_start[0].tv_usec); +#endif + + float tx_power = srslte_ue_ul_srs_power(&ue_ul, phy->pathloss); + float gain = set_power(tx_power); + uint32_t fi = srslte_vec_max_fi((float*) signal_buffer, SRSLTE_SF_LEN_PRB(cell.nof_prb)); + float *f = (float*) signal_buffer; + Info("SRS: power=%.2f dBm, tti_tx=%d%s\n", tx_power, (tti+4)%10240, timestr); + +} + +void phch_worker::enable_pregen_signals(bool enabled) +{ + pregen_enabled = enabled; + if (enabled) { + Info("Pre-generating UL signals worker=%d\n", get_id()); + srslte_ue_ul_pregen_signals(&ue_ul); + Info("Done pre-generating signals worker=%d\n", get_id()); + } +} + +void phch_worker::set_ul_params(bool pregen_disabled) +{ + phy_interface_rrc::phy_cfg_common_t *common = &phy->config->common; + LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT *dedicated = &phy->config->dedicated; + + Info("Setting new params worker_id=%d, pregen_disabled=%d\n", get_id(), pregen_disabled); + + /* PUSCH DMRS signal configuration */ + bzero(&dmrs_cfg, sizeof(srslte_refsignal_dmrs_pusch_cfg_t)); + dmrs_cfg.group_hopping_en = common->pusch_cnfg.ul_rs.group_hopping_enabled; + dmrs_cfg.sequence_hopping_en = common->pusch_cnfg.ul_rs.sequence_hopping_enabled; + dmrs_cfg.cyclic_shift = common->pusch_cnfg.ul_rs.cyclic_shift; + dmrs_cfg.delta_ss = common->pusch_cnfg.ul_rs.group_assignment_pusch; + + /* PUSCH Hopping configuration */ + bzero(&pusch_hopping, sizeof(srslte_pusch_hopping_cfg_t)); + pusch_hopping.n_sb = common->pusch_cnfg.n_sb; + pusch_hopping.hop_mode = common->pusch_cnfg.hopping_mode == LIBLTE_RRC_HOPPING_MODE_INTRA_AND_INTER_SUBFRAME ? + pusch_hopping.SRSLTE_PUSCH_HOP_MODE_INTRA_SF : + pusch_hopping.SRSLTE_PUSCH_HOP_MODE_INTER_SF; + pusch_hopping.hopping_offset = common->pusch_cnfg.pusch_hopping_offset; + + /* PUSCH UCI configuration */ + bzero(&uci_cfg, sizeof(srslte_uci_cfg_t)); + uci_cfg.I_offset_ack = dedicated->pusch_cnfg_ded.beta_offset_ack_idx; + uci_cfg.I_offset_cqi = dedicated->pusch_cnfg_ded.beta_offset_cqi_idx; + uci_cfg.I_offset_ri = dedicated->pusch_cnfg_ded.beta_offset_ri_idx; + + /* PUCCH configuration */ + bzero(&pucch_cfg, sizeof(srslte_pucch_cfg_t)); + pucch_cfg.delta_pucch_shift = liblte_rrc_delta_pucch_shift_num[common->pucch_cnfg.delta_pucch_shift%LIBLTE_RRC_DELTA_PUCCH_SHIFT_N_ITEMS]; + pucch_cfg.N_cs = common->pucch_cnfg.n_cs_an; + pucch_cfg.n_rb_2 = common->pucch_cnfg.n_rb_cqi; + pucch_cfg.srs_configured = dedicated->srs_ul_cnfg_ded.setup_present; + if (pucch_cfg.srs_configured) { + pucch_cfg.srs_cs_subf_cfg = liblte_rrc_srs_subfr_config_num[common->srs_ul_cnfg.subfr_cnfg%LIBLTE_RRC_SRS_SUBFR_CONFIG_N_ITEMS]; + pucch_cfg.srs_simul_ack = common->srs_ul_cnfg.ack_nack_simul_tx; + } + + /* PUCCH Scheduling configuration */ + bzero(&pucch_sched, sizeof(srslte_pucch_sched_t)); + pucch_sched.n_pucch_1[0] = 0; // TODO: n_pucch_1 for SPS + pucch_sched.n_pucch_1[1] = 0; + pucch_sched.n_pucch_1[2] = 0; + pucch_sched.n_pucch_1[3] = 0; + pucch_sched.N_pucch_1 = common->pucch_cnfg.n1_pucch_an; + pucch_sched.n_pucch_2 = dedicated->cqi_report_cnfg.report_periodic.pucch_resource_idx; + pucch_sched.n_pucch_sr = dedicated->sched_request_cnfg.sr_pucch_resource_idx; + + /* SRS Configuration */ + bzero(&srs_cfg, sizeof(srslte_refsignal_srs_cfg_t)); + srs_cfg.configured = dedicated->srs_ul_cnfg_ded.setup_present; + if (pucch_cfg.srs_configured) { + srs_cfg.subframe_config = liblte_rrc_srs_subfr_config_num[common->srs_ul_cnfg.subfr_cnfg%LIBLTE_RRC_SRS_SUBFR_CONFIG_N_ITEMS]; + srs_cfg.bw_cfg = liblte_rrc_srs_bw_config_num[common->srs_ul_cnfg.bw_cnfg%LIBLTE_RRC_SRS_BW_CONFIG_N_ITEMS]; + srs_cfg.I_srs = dedicated->srs_ul_cnfg_ded.srs_cnfg_idx; + srs_cfg.B = dedicated->srs_ul_cnfg_ded.srs_bandwidth; + srs_cfg.b_hop = dedicated->srs_ul_cnfg_ded.srs_hopping_bandwidth; + srs_cfg.n_rrc = dedicated->srs_ul_cnfg_ded.freq_domain_pos; + srs_cfg.k_tc = dedicated->srs_ul_cnfg_ded.tx_comb; + srs_cfg.n_srs = dedicated->srs_ul_cnfg_ded.cyclic_shift; + } + + /* UL power control configuration */ + bzero(&power_ctrl, sizeof(srslte_ue_ul_powerctrl_t)); + power_ctrl.p0_nominal_pusch = common->ul_pwr_ctrl.p0_nominal_pusch; + power_ctrl.alpha = liblte_rrc_ul_power_control_alpha_num[common->ul_pwr_ctrl.alpha%LIBLTE_RRC_UL_POWER_CONTROL_ALPHA_N_ITEMS]; + power_ctrl.p0_nominal_pucch = common->ul_pwr_ctrl.p0_nominal_pucch; + power_ctrl.delta_f_pucch[0] = liblte_rrc_delta_f_pucch_format_1_num[common->ul_pwr_ctrl.delta_flist_pucch.format_1%LIBLTE_RRC_DELTA_F_PUCCH_FORMAT_1_N_ITEMS]; + power_ctrl.delta_f_pucch[1] = liblte_rrc_delta_f_pucch_format_1b_num[common->ul_pwr_ctrl.delta_flist_pucch.format_1b%LIBLTE_RRC_DELTA_F_PUCCH_FORMAT_1B_N_ITEMS]; + power_ctrl.delta_f_pucch[2] = liblte_rrc_delta_f_pucch_format_2_num[common->ul_pwr_ctrl.delta_flist_pucch.format_2%LIBLTE_RRC_DELTA_F_PUCCH_FORMAT_2_N_ITEMS]; + power_ctrl.delta_f_pucch[3] = liblte_rrc_delta_f_pucch_format_2a_num[common->ul_pwr_ctrl.delta_flist_pucch.format_2a%LIBLTE_RRC_DELTA_F_PUCCH_FORMAT_2A_N_ITEMS]; + power_ctrl.delta_f_pucch[4] = liblte_rrc_delta_f_pucch_format_2b_num[common->ul_pwr_ctrl.delta_flist_pucch.format_2b%LIBLTE_RRC_DELTA_F_PUCCH_FORMAT_2B_N_ITEMS]; + + power_ctrl.delta_preamble_msg3 = common->ul_pwr_ctrl.delta_preamble_msg3; + + power_ctrl.p0_ue_pusch = dedicated->ul_pwr_ctrl_ded.p0_ue_pusch; + power_ctrl.delta_mcs_based = dedicated->ul_pwr_ctrl_ded.delta_mcs_en==LIBLTE_RRC_DELTA_MCS_ENABLED_EN0; + power_ctrl.acc_enabled = dedicated->ul_pwr_ctrl_ded.accumulation_en; + power_ctrl.p0_ue_pucch = dedicated->ul_pwr_ctrl_ded.p0_ue_pucch; + power_ctrl.p_srs_offset = dedicated->ul_pwr_ctrl_ded.p_srs_offset; + + srslte_ue_ul_set_cfg(&ue_ul, &dmrs_cfg, &srs_cfg, &pucch_cfg, &pucch_sched, &uci_cfg, &pusch_hopping, &power_ctrl); + + /* CQI configuration */ + bzero(&period_cqi, sizeof(srslte_cqi_periodic_cfg_t)); + period_cqi.configured = dedicated->cqi_report_cnfg.report_periodic_setup_present; + period_cqi.pmi_idx = dedicated->cqi_report_cnfg.report_periodic.pmi_cnfg_idx; + period_cqi.simul_cqi_ack = dedicated->cqi_report_cnfg.report_periodic.simult_ack_nack_and_cqi; + period_cqi.format_is_subband = dedicated->cqi_report_cnfg.report_periodic.format_ind_periodic == + LIBLTE_RRC_CQI_FORMAT_INDICATOR_PERIODIC_SUBBAND_CQI; + period_cqi.subband_size = dedicated->cqi_report_cnfg.report_periodic.format_ind_periodic_subband_k; + + /* SR configuration */ + I_sr = dedicated->sched_request_cnfg.sr_cnfg_idx; + + + if (pregen_enabled && !pregen_disabled) { + Info("Pre-generating UL signals worker=%d\n", get_id()); + srslte_ue_ul_pregen_signals(&ue_ul); + Info("Done pre-generating signals worker=%d\n", get_id()); + } +} + +float phch_worker::set_power(float tx_power) { + float gain = 0; + /* Check if UL power control is enabled */ + if(phy->args->ul_pwr_ctrl_en) { + /* Adjust maximum power if it changes significantly */ + if (tx_power < phy->cur_radio_power - 5 || tx_power > phy->cur_radio_power + 5) { + phy->cur_radio_power = tx_power; + float radio_tx_power = phy->cur_radio_power; + gain = phy->get_radio()->set_tx_power(radio_tx_power); + } + } + return gain; +} + +void phch_worker::start_plot() { +#ifdef ENABLE_GUI + if (plot_worker_id == -1) { + plot_worker_id = get_id(); + phy->log_h->console("Starting plot for worker_id=%d\n", plot_worker_id); + init_plots(this); + } else { + phy->log_h->console("Trying to start a plot but already started by worker_id=%d\n", plot_worker_id); + } +#else + phy->log_h->console("Trying to start a plot but plots are disabled (ENABLE_GUI constant in phch_worker.cc)\n"); +#endif +} + +int phch_worker::read_ce_abs(float *ce_abs) { + uint32_t i=0; + int sz = srslte_symbol_sz(cell.nof_prb); + bzero(ce_abs, sizeof(float)*sz); + int g = (sz - 12*cell.nof_prb)/2; + for (i = 0; i < 12*cell.nof_prb; i++) { + ce_abs[g+i] = 20 * log10(cabs(ue_dl.ce[0][i])); + if (isinf(ce_abs[g+i])) { + ce_abs[g+i] = -80; + } + } + return sz; +} + +int phch_worker::read_pdsch_d(cf_t* pdsch_d) +{ + memcpy(pdsch_d, ue_dl.pdsch.d, ue_dl.pdsch_cfg.nbits.nof_re*sizeof(cf_t)); + return ue_dl.pdsch_cfg.nbits.nof_re; +} + + + +/**************************** Measurements **************************/ + +void phch_worker::update_measurements() +{ + float snr_ema_coeff = phy->args->snr_ema_coeff; + if (chest_done) { + /* Compute ADC/RX gain offset every 20 ms */ + if ((tti%20) == 0 || phy->rx_gain_offset == 0) { + float rx_gain_offset = 0; + if (phy->get_radio()->has_rssi() && phy->args->rssi_sensor_enabled) { + float rssi_all_signal = srslte_chest_dl_get_rssi(&ue_dl.chest); + if (rssi_all_signal) { + rx_gain_offset = 10*log10(rssi_all_signal)-phy->get_radio()->get_rssi(); + } else { + rx_gain_offset = 0; + } + } else { + rx_gain_offset = phy->get_radio()->get_rx_gain(); + } + if (phy->rx_gain_offset) { + phy->rx_gain_offset = SRSLTE_VEC_EMA(phy->rx_gain_offset, rx_gain_offset, 0.1); + } else { + phy->rx_gain_offset = rx_gain_offset; + } + } + + // Average RSRQ + float cur_rsrq = 10*log10(srslte_chest_dl_get_rsrq(&ue_dl.chest)); + if (isnormal(cur_rsrq)) { + phy->avg_rsrq_db = SRSLTE_VEC_EMA(phy->avg_rsrq_db, cur_rsrq, snr_ema_coeff); + } + + // Average RSRP + float cur_rsrp = srslte_chest_dl_get_rsrp(&ue_dl.chest); + if (isnormal(cur_rsrp)) { + phy->avg_rsrp = SRSLTE_VEC_EMA(phy->avg_rsrp, cur_rsrp, snr_ema_coeff); + } + + /* Correct absolute power measurements by RX gain offset */ + float rsrp = 10*log10(srslte_chest_dl_get_rsrp(&ue_dl.chest)) + 30 - phy->rx_gain_offset; + float rssi = 10*log10(srslte_chest_dl_get_rssi(&ue_dl.chest)) + 30 - phy->rx_gain_offset; + + // TODO: Send UE measurements to RRC where filtering is done. Now do filtering here + if (isnormal(rsrp)) { + if (!phy->avg_rsrp_db) { + phy->avg_rsrp_db = rsrp; + } else { + uint32_t k = 4; // Set by RRC reconfiguration message + float coeff = pow(0.5,(float) k/4); + phy->avg_rsrp_db = SRSLTE_VEC_EMA(phy->avg_rsrp_db, rsrp, coeff); + } + } + // Compute PL + float tx_crs_power = phy->config->common.pdsch_cnfg.rs_power; + phy->pathloss = tx_crs_power - phy->avg_rsrp_db; + + // Average noise + float cur_noise = srslte_chest_dl_get_noise_estimate(&ue_dl.chest); + if (isnormal(cur_noise)) { + if (!phy->avg_noise) { + phy->avg_noise = cur_noise; + } else { + phy->avg_noise = SRSLTE_VEC_EMA(phy->avg_noise, cur_noise, snr_ema_coeff); + } + } + + // Compute SNR + phy->avg_snr_db = 10*log10(phy->avg_rsrp/phy->avg_noise); + + // Store metrics + dl_metrics.n = phy->avg_noise; + dl_metrics.rsrp = phy->avg_rsrp_db; + dl_metrics.rsrq = phy->avg_rsrq_db; + dl_metrics.rssi = rssi; + dl_metrics.pathloss = phy->pathloss; + dl_metrics.sinr = phy->avg_snr_db; + dl_metrics.turbo_iters = srslte_pdsch_last_noi(&ue_dl.pdsch); + phy->set_dl_metrics(dl_metrics); + + } +} + + +/********** Execution time trace function ************/ + +void phch_worker::start_trace() { + trace_enabled = true; +} + +void phch_worker::write_trace(std::string filename) { + tr_exec.writeToBinary(filename + ".exec"); +} + +void phch_worker::tr_log_start() +{ + if (trace_enabled) { + gettimeofday(&tr_time[1], NULL); + } +} + +void phch_worker::tr_log_end() +{ + if (trace_enabled) { + gettimeofday(&tr_time[2], NULL); + get_time_interval(tr_time); + tr_exec.push(tti, tr_time[0].tv_usec); + } +} + +} + + + + + + + + +/*********************************************************** + * + * PLOT TO VISUALIZE THE CHANNEL RESPONSEE + * + ***********************************************************/ + + +#ifdef ENABLE_GUI +plot_real_t pce; +plot_scatter_t pconst; +#define SCATTER_PDSCH_BUFFER_LEN (20*6*SRSLTE_SF_LEN_RE(SRSLTE_MAX_PRB, SRSLTE_CP_NORM)) +#define SCATTER_PDSCH_PLOT_LEN 4000 +float tmp_plot[SCATTER_PDSCH_BUFFER_LEN]; +cf_t tmp_plot2[SRSLTE_SF_LEN_RE(SRSLTE_MAX_PRB, SRSLTE_CP_NORM)]; + +void *plot_thread_run(void *arg) { + srsue::phch_worker *worker = (srsue::phch_worker*) arg; + + sdrgui_init(); + plot_real_init(&pce); + plot_real_setTitle(&pce, (char*) "Channel Response - Magnitude"); + plot_real_setLabels(&pce, (char*) "Index", (char*) "dB"); + plot_real_setYAxisScale(&pce, -40, 40); + + plot_scatter_init(&pconst); + plot_scatter_setTitle(&pconst, (char*) "PDSCH - Equalized Symbols"); + plot_scatter_setXAxisScale(&pconst, -4, 4); + plot_scatter_setYAxisScale(&pconst, -4, 4); + + plot_real_addToWindowGrid(&pce, (char*)"srsue", 0, 0); + plot_scatter_addToWindowGrid(&pconst, (char*)"srsue", 0, 1); + + + int n; + int readed_pdsch_re=0; + while(1) { + sem_wait(&plot_sem); + + if (readed_pdsch_re < SCATTER_PDSCH_PLOT_LEN) { + n = worker->read_pdsch_d(&tmp_plot2[readed_pdsch_re]); + readed_pdsch_re += n; + } else { + n = worker->read_ce_abs(tmp_plot); + if (n>0) { + plot_real_setNewData(&pce, tmp_plot, n); + } + if (readed_pdsch_re > 0) { + plot_scatter_setNewData(&pconst, tmp_plot2, readed_pdsch_re); + } + readed_pdsch_re = 0; + } + } + return NULL; +} + + +void init_plots(srsue::phch_worker *worker) { + + if (sem_init(&plot_sem, 0, 0)) { + perror("sem_init"); + exit(-1); + } + + pthread_attr_t attr; + struct sched_param param; + param.sched_priority = 0; + pthread_attr_init(&attr); + pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED); + pthread_attr_setschedpolicy(&attr, SCHED_OTHER); + pthread_attr_setschedparam(&attr, ¶m); + if (pthread_create(&plot_thread, &attr, plot_thread_run, worker)) { + perror("pthread_create"); + exit(-1); + } +} +#endif + diff --git a/srsue/src/phy/phy.cc b/srsue/src/phy/phy.cc new file mode 100644 index 000000000..cf673cce6 --- /dev/null +++ b/srsue/src/phy/phy.cc @@ -0,0 +1,364 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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 +#include +#include +#include +#include +#include +#include + +#include "srslte/srslte.h" + +#include "srslte/common/threads.h" +#include "srslte/common/log.h" +#include "phy/phy.h" +#include "phy/phch_worker.h" + +#define Error(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->error_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Warning(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->warning_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Info(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->info_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Debug(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->debug_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) + + + +using namespace std; + + +namespace srsue { + +phy::phy() : workers_pool(MAX_WORKERS), + workers(MAX_WORKERS), + workers_common(phch_recv::MUTEX_X_WORKER*MAX_WORKERS) +{ +} + +void phy::set_default_args(phy_args_t *args) +{ + args->ul_pwr_ctrl_en = false; + args->prach_gain = -1; + args->cqi_max = -1; + args->cqi_fixed = -1; + args->snr_ema_coeff = 0.1; + args->snr_estim_alg = "refs"; + args->pdsch_max_its = 4; + args->attach_enable_64qam = false; + args->nof_phy_threads = DEFAULT_WORKERS; + args->equalizer_mode = "mmse"; + args->cfo_integer_enabled = false; + args->cfo_correct_tol_hz = 50; + args->time_correct_period = 5; + args->sfo_correct_disable = false; + args->sss_algorithm = "full"; + args->estimator_fil_w = 0.1; +} + +bool phy::check_args(phy_args_t *args) +{ + if (args->nof_phy_threads > 3) { + log_h->console("Error in PHY args: nof_phy_threads must be 1, 2 or 3\n"); + return false; + } + if (args->estimator_fil_w > 1.0) { + log_h->console("Error in PHY args: estimator_fil_w must be 0<=w<=1\n"); + return false; + } + if (args->snr_ema_coeff > 1.0) { + log_h->console("Error in PHY args: snr_ema_coeff must be 0<=w<=1\n"); + return false; + } + return true; +} + +bool phy::init(srslte::radio_multi* radio_handler_, mac_interface_phy *mac, rrc_interface_phy *rrc, + srslte::log *log_h_, phy_args_t *phy_args) +{ + + mlockall(MCL_CURRENT | MCL_FUTURE); + + n_ta = 0; + log_h = log_h_; + radio_handler = radio_handler_; + + if (!phy_args) { + args = &default_args; + set_default_args(args); + } else { + args = phy_args; + } + + if (!check_args(args)) { + return false; + } + + nof_workers = args->nof_phy_threads; + + // Add workers to workers pool and start threads + for (uint32_t i=0;iworker_cpu_mask); + } + prach_buffer.init(&config.common.prach_cnfg, args, log_h); + workers_common.init(&config, args, log_h, radio_handler, mac); + + // Warning this must be initialized after all workers have been added to the pool + sf_recv.init(radio_handler, mac, rrc, &prach_buffer, &workers_pool, &workers_common, log_h, args->nof_rx_ant, SF_RECV_THREAD_PRIO, args->sync_cpu_affinity); + + // Disable UL signal pregeneration until the attachment + enable_pregen_signals(false); + + return true; +} + +void phy::set_agc_enable(bool enabled) +{ + sf_recv.set_agc_enable(enabled); +} + +void phy::start_trace() +{ + for (uint32_t i=0;i( &(ostringstream() << i) )->str(); + workers[i].write_trace(filename + "_" + i_str); + } +} + +void phy::stop() +{ + sf_recv.stop(); + workers_pool.stop(); +} + +void phy::get_metrics(phy_metrics_t &m) { + workers_common.get_dl_metrics(m.dl); + workers_common.get_ul_metrics(m.ul); + workers_common.get_sync_metrics(m.sync); + int dl_tbs = srslte_ra_tbs_from_idx(srslte_ra_tbs_idx_from_mcs(m.dl.mcs), workers_common.get_nof_prb()); + int ul_tbs = srslte_ra_tbs_from_idx(srslte_ra_tbs_idx_from_mcs(m.ul.mcs), workers_common.get_nof_prb()); + m.dl.mabr_mbps = dl_tbs/1000.0; // TBS is bits/ms - convert to mbps + m.ul.mabr_mbps = ul_tbs/1000.0; // TBS is bits/ms - convert to mbps + Info("PHY: MABR estimates. DL: %4.6f Mbps. UL: %4.6f Mbps.\n", m.dl.mabr_mbps, m.ul.mabr_mbps); +} + +void phy::set_timeadv_rar(uint32_t ta_cmd) { + n_ta = srslte_N_ta_new_rar(ta_cmd); + sf_recv.set_time_adv_sec(((float) n_ta)*SRSLTE_LTE_TS); + Info("PHY: Set TA RAR: ta_cmd: %d, n_ta: %d, ta_usec: %.1f\n", ta_cmd, n_ta, ((float) n_ta)*SRSLTE_LTE_TS*1e6); +} + +void phy::set_timeadv(uint32_t ta_cmd) { + n_ta = srslte_N_ta_new(n_ta, ta_cmd); + //sf_recv.set_time_adv_sec(((float) n_ta)*SRSLTE_LTE_TS); + Warning("Not supported: Set TA: ta_cmd: %d, n_ta: %d, ta_usec: %.1f\n", ta_cmd, n_ta, ((float) n_ta)*SRSLTE_LTE_TS*1e6); +} + +void phy::configure_prach_params() +{ + if (sf_recv.status_is_sync()) { + Debug("Configuring PRACH parameters\n"); + srslte_cell_t cell; + sf_recv.get_current_cell(&cell); + if (!prach_buffer.init_cell(cell)) { + Error("Configuring PRACH parameters\n"); + } + } else { + Error("Cell is not synchronized\n"); + } +} + +void phy::configure_ul_params(bool pregen_disabled) +{ + Info("PHY: Configuring UL parameters\n"); + for (uint32_t i=0;iget_max_tx_power() - workers_common.cur_pusch_power; + return phr; +} + +float phy::get_pathloss_db() +{ + return workers_common.cur_pathloss; +} + +void phy::pdcch_ul_search(srslte_rnti_type_t rnti_type, uint16_t rnti, int tti_start, int tti_end) +{ + workers_common.set_ul_rnti(rnti_type, rnti, tti_start, tti_end); +} + +void phy::pdcch_dl_search(srslte_rnti_type_t rnti_type, uint16_t rnti, int tti_start, int tti_end) +{ + workers_common.set_dl_rnti(rnti_type, rnti, tti_start, tti_end); +} + +void phy::pdcch_dl_search_reset() +{ + workers_common.set_dl_rnti(SRSLTE_RNTI_USER, 0); +} + +void phy::pdcch_ul_search_reset() +{ + workers_common.set_ul_rnti(SRSLTE_RNTI_USER, 0); +} + +void phy::get_current_cell(srslte_cell_t *cell) +{ + sf_recv.get_current_cell(cell); +} + +void phy::prach_send(uint32_t preamble_idx, int allowed_subframe, float target_power_dbm) +{ + + if (!prach_buffer.prepare_to_send(preamble_idx, allowed_subframe, target_power_dbm)) { + Error("Preparing PRACH to send\n"); + } +} + +int phy::prach_tx_tti() +{ + return prach_buffer.tx_tti(); +} + +void phy::reset() +{ + // TODO + n_ta = 0; + pdcch_dl_search_reset(); + for(uint32_t i=0;i +#include +#include + +#include "srslte/srslte.h" +#include "srslte/common/log.h" +#include "phy/prach.h" +#include "phy/phy.h" +#include "srslte/interfaces/ue_interfaces.h" + +#define Error(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->error_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Warning(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->warning_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Info(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->info_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Debug(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->debug_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) + +namespace srsue { + + +void prach::free_cell() +{ + if (initiated) { + for (int i=0;i<64;i++) { + if (buffer[i]) { + free(buffer[i]); + } + } + if (signal_buffer) { + free(signal_buffer); + } + srslte_cfo_free(&cfo_h); + srslte_prach_free(&prach_obj); + } +} + +void prach::init(LIBLTE_RRC_PRACH_CONFIG_SIB_STRUCT *config_, phy_args_t *args_, srslte::log* log_h_) +{ + log_h = log_h_; + config = config_; + args = args_; +} + +bool prach::init_cell(srslte_cell_t cell_) +{ + // TODO: Check if other PRACH parameters changed + if (cell_.id != cell.id || !initiated) { + if (initiated) { + free_cell(); + } + cell = cell_; + preamble_idx = -1; + + uint32_t configIdx = config->prach_cnfg_info.prach_config_index; + uint32_t rootSeq = config->root_sequence_index; + uint32_t zeroCorrConfig = config->prach_cnfg_info.zero_correlation_zone_config; + uint32_t freq_offset = config->prach_cnfg_info.prach_freq_offset; + bool highSpeed = config->prach_cnfg_info.high_speed_flag; + + if (6 + freq_offset > cell.nof_prb) { + log_h->console("Error no space for PRACH: frequency offset=%d, N_rb_ul=%d\n", freq_offset, cell.nof_prb); + log_h->error("Error no space for PRACH: frequency offset=%d, N_rb_ul=%d\n", freq_offset, cell.nof_prb); + return false; + } + + if (srslte_prach_init(&prach_obj, srslte_symbol_sz(cell.nof_prb), + configIdx, rootSeq, highSpeed, zeroCorrConfig)) + { + Error("Initiating PRACH library\n"); + return false; + } + + len = prach_obj.N_seq + prach_obj.N_cp; + for (int i=0;i<64;i++) { + buffer[i] = (cf_t*) srslte_vec_malloc(len*sizeof(cf_t)); + if(!buffer[i]) { + return false; + } + if(srslte_prach_gen(&prach_obj, i, freq_offset, buffer[i])) { + Error("Generating PRACH preamble %d\n", i); + return false; + } + } + srslte_cfo_init(&cfo_h, len); + srslte_cfo_set_tol(&cfo_h, 0); + signal_buffer = (cf_t*) srslte_vec_malloc(len*sizeof(cf_t)); + initiated = signal_buffer?true:false; + transmitted_tti = -1; + Debug("PRACH Initiated %s\n", initiated?"OK":"KO"); + } + return initiated; +} + +bool prach::prepare_to_send(uint32_t preamble_idx_, int allowed_subframe_, float target_power_dbm_) +{ + if (initiated && preamble_idx_ < 64) { + preamble_idx = preamble_idx_; + target_power_dbm = target_power_dbm_; + allowed_subframe = allowed_subframe_; + transmitted_tti = -1; + Debug("PRACH prepare to send preamble %d\n", preamble_idx); + return true; + } else { + if (!initiated) { + Error("PRACH not initiated\n"); + } else if (preamble_idx_ >= 64) { + Error("Invalid preamble %d\n", preamble_idx_); + } + return false; + } +} + +bool prach::is_ready_to_send(uint32_t current_tti_) { + if (initiated && preamble_idx >= 0 && preamble_idx < 64) { + // consider the number of subframes the transmission must be anticipated + uint32_t current_tti = (current_tti_ + tx_advance_sf)%10240; + if (srslte_prach_tti_opportunity(&prach_obj, current_tti, allowed_subframe)) { + Debug("PRACH Buffer: Ready to send at tti: %d (now is %d)\n", current_tti, current_tti_); + transmitted_tti = current_tti; + return true; + } + } + return false; +} + +int prach::tx_tti() { + return transmitted_tti; +} + +float prach::get_p0_preamble() +{ + return target_power_dbm; +} + + +void prach::send(srslte::radio *radio_handler, float cfo, float pathloss, srslte_timestamp_t tx_time) +{ + + // Get current TX gain + float old_gain = radio_handler->get_tx_gain(); + + // Correct CFO before transmission + srslte_cfo_correct(&cfo_h, buffer[preamble_idx], signal_buffer, cfo / srslte_symbol_sz(cell.nof_prb)); + + // If power control is enabled, choose amplitude and power + if (args->ul_pwr_ctrl_en) { + // Get PRACH transmission power + float tx_power = SRSLTE_MIN(SRSLTE_PC_MAX, pathloss + target_power_dbm); + + // Get output power for amplitude 1 + radio_handler->set_tx_power(tx_power); + + // Scale signal + float digital_power = srslte_vec_avg_power_cf(signal_buffer, len); + float scale = sqrtf(pow(10,tx_power/10)/digital_power); + + srslte_vec_sc_prod_cfc(signal_buffer, scale, signal_buffer, len); + log_h->console("PRACH: Pathloss=%.2f dB, Target power %.2f dBm, TX_power %.2f dBm, TX_gain %.1f dB\n", + pathloss, target_power_dbm, tx_power, radio_handler->get_tx_gain(), scale); + + } else { + float prach_gain = args->prach_gain; + if (prach_gain > 0) { + radio_handler->set_tx_gain(prach_gain); + } + Debug("TX PRACH: Power control for PRACH is disabled, setting gain to %.0f dB\n", prach_gain); + } + + radio_handler->tx(signal_buffer, len, tx_time); + radio_handler->tx_end(); + + Info("PRACH: Transmitted preamble=%d, CFO=%.2f KHz, tx_time=%f\n", + preamble_idx, cfo*15, tx_time.frac_secs); + preamble_idx = -1; + + radio_handler->set_tx_gain(old_gain); + Debug("Restoring TX gain to %.0f dB\n", old_gain); +} + +} // namespace srsue + diff --git a/srsue/src/set_net_admin_caps.cc b/srsue/src/set_net_admin_caps.cc new file mode 100644 index 000000000..1485a26d9 --- /dev/null +++ b/srsue/src/set_net_admin_caps.cc @@ -0,0 +1,53 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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 +#include +#include +#include +#include +#include + +using namespace std; + +int main(int argc, char *argv[]) +{ + if (argc != 2) { + std::cout << "Please call with the binary to provide net admin capabilities to as a parameter." << std::endl; + std::cout << "E.g. ./set_net_admin_caps myprogCalling " << std::endl; + return -1; + } + + std::string command("setcap 'cap_net_admin=eip' "); + command += argv[1]; + + std::cout << "Calling " << command << " with root rights." << std::endl; + setuid(0); + system(command.c_str()); + + return 0; +} + diff --git a/srsue/src/ue.cc b/srsue/src/ue.cc new file mode 100644 index 000000000..97f59c15e --- /dev/null +++ b/srsue/src/ue.cc @@ -0,0 +1,319 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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 "ue.h" +//#include "srslte_version_check.h" +#include "srslte/srslte.h" +#include +#include +#include +#include +#include + +using namespace srslte; + +namespace srsue{ + +ue* ue::instance = NULL; +pthread_mutex_t ue_instance_mutex = PTHREAD_MUTEX_INITIALIZER; + +ue* ue::get_instance(void) +{ + pthread_mutex_lock(&ue_instance_mutex); + if(NULL == instance) { + instance = new ue(); + } + pthread_mutex_unlock(&ue_instance_mutex); + return(instance); +} +void ue::cleanup(void) +{ + pthread_mutex_lock(&ue_instance_mutex); + if(NULL != instance) { + delete instance; + instance = NULL; + } + pthread_mutex_unlock(&ue_instance_mutex); +} + +ue::ue() + :started(false) +{ + pool = byte_buffer_pool::get_instance(); +} + +ue::~ue() +{ + byte_buffer_pool::cleanup(); +} + +bool ue::init(all_args_t *args_) +{ + args = args_; + + logger.init(args->log.filename); + rf_log.init("RF ", &logger); + phy_log.init("PHY ", &logger, true); + mac_log.init("MAC ", &logger, true); + rlc_log.init("RLC ", &logger); + pdcp_log.init("PDCP", &logger); + rrc_log.init("RRC ", &logger); + nas_log.init("NAS ", &logger); + gw_log.init("GW ", &logger); + usim_log.init("USIM", &logger); + + // Init logs + logger.log("\n\n"); + rf_log.set_level(srslte::LOG_LEVEL_INFO); + phy_log.set_level(level(args->log.phy_level)); + mac_log.set_level(level(args->log.mac_level)); + rlc_log.set_level(level(args->log.rlc_level)); + pdcp_log.set_level(level(args->log.pdcp_level)); + rrc_log.set_level(level(args->log.rrc_level)); + nas_log.set_level(level(args->log.nas_level)); + gw_log.set_level(level(args->log.gw_level)); + usim_log.set_level(level(args->log.usim_level)); + + phy_log.set_hex_limit(args->log.phy_hex_limit); + mac_log.set_hex_limit(args->log.mac_hex_limit); + rlc_log.set_hex_limit(args->log.rlc_hex_limit); + pdcp_log.set_hex_limit(args->log.pdcp_hex_limit); + rrc_log.set_hex_limit(args->log.rrc_hex_limit); + nas_log.set_hex_limit(args->log.nas_hex_limit); + gw_log.set_hex_limit(args->log.gw_hex_limit); + usim_log.set_hex_limit(args->log.usim_hex_limit); + + // Set up pcap and trace + if(args->pcap.enable) + { + mac_pcap.open(args->pcap.filename.c_str()); + mac.start_pcap(&mac_pcap); + } + if(args->trace.enable) + { + phy.start_trace(); + radio.start_trace(); + } + + // Init layers + + /* Start Radio */ + char *dev_name = NULL; + if (args->rf.device_name.compare("auto")) { + dev_name = (char*) args->rf.device_name.c_str(); + } + + char *dev_args = NULL; + if (args->rf.device_args.compare("auto")) { + dev_args = (char*) args->rf.device_args.c_str(); + } + + printf("Opening RF device with %d RX antennas...\n", args->rf.nof_rx_ant); + if(!radio.init_multi(args->rf.nof_rx_ant, dev_args, dev_name)) + { + printf("Failed to find device %s with args %s\n", + args->rf.device_name.c_str(), args->rf.device_args.c_str()); + return false; + } + + // Set RF options + if (args->rf.time_adv_nsamples.compare("auto")) { + radio.set_tx_adv(atoi(args->rf.time_adv_nsamples.c_str())); + } + if (args->rf.burst_preamble.compare("auto")) { + radio.set_burst_preamble(atof(args->rf.burst_preamble.c_str())); + } + + radio.set_manual_calibration(&args->rf_cal); + + // Set PHY options + args->expert.phy.nof_rx_ant = args->rf.nof_rx_ant; + + if (args->rf.tx_gain > 0) { + args->expert.phy.ul_pwr_ctrl_en = false; + } else { + args->expert.phy.ul_pwr_ctrl_en = true; + } + phy.init(&radio, &mac, &rrc, &phy_log, &args->expert.phy); + + if (args->rf.rx_gain < 0) { + radio.start_agc(false); + radio.set_tx_rx_gain_offset(10); + phy.set_agc_enable(true); + } else { + radio.set_rx_gain(args->rf.rx_gain); + } + if (args->rf.tx_gain > 0) { + radio.set_tx_gain(args->rf.tx_gain); + } else { + radio.set_tx_gain(args->rf.rx_gain); + std::cout << std::endl << + "Warning: TX gain was not set. " << + "Using open-loop power control (not working properly)" << std::endl << std::endl; + } + + radio.register_error_handler(rf_msg); + + radio.set_rx_freq(args->rf.dl_freq); + radio.set_tx_freq(args->rf.ul_freq); + + phy_log.console("Setting frequency: DL=%.1f Mhz, UL=%.1f MHz\n", args->rf.dl_freq/1e6, args->rf.ul_freq/1e6); + + mac.init(&phy, &rlc, &rrc, &mac_log); + rlc.init(&pdcp, &rrc, this, &rlc_log, &mac); + pdcp.init(&rlc, &rrc, &gw, &pdcp_log, SECURITY_DIRECTION_UPLINK); + rrc.init(&phy, &mac, &rlc, &pdcp, &nas, &usim, &mac, &rrc_log); + + rrc.set_ue_category(args->expert.ue_cateogry); + + nas.init(&usim, &rrc, &gw, &nas_log); + gw.init(&pdcp, &rrc, this, &gw_log); + usim.init(&args->usim, &usim_log); + + started = true; + return true; +} + +void ue::pregenerate_signals(bool enable) +{ + phy.enable_pregen_signals(enable); +} + +void ue::test_con_restablishment() { + rrc.test_con_restablishment(); +} + +void ue::stop() +{ + if(started) + { + usim.stop(); + nas.stop(); + rrc.stop(); + + // Caution here order of stop is very important to avoid locks + + + // Stop RLC and PDCP before GW to avoid locking on queue + rlc.stop(); + pdcp.stop(); + gw.stop(); + + // PHY must be stopped before radio otherwise it will lock on rf_recv() + mac.stop(); + phy.stop(); + radio.stop(); + + usleep(1e5); + if(args->pcap.enable) + { + mac_pcap.close(); + } + if(args->trace.enable) + { + phy.write_trace(args->trace.phy_filename); + radio.write_trace(args->trace.radio_filename); + } + started = false; + } +} + +bool ue::is_attached() +{ + return (EMM_STATE_REGISTERED == nas.get_state()); +} + +void ue::start_plot() { + phy.start_plot(); +} + +bool ue::get_metrics(ue_metrics_t &m) +{ + m.rf = rf_metrics; + bzero(&rf_metrics, sizeof(rf_metrics_t)); + rf_metrics.rf_error = false; // Reset error flag + + if(EMM_STATE_REGISTERED == nas.get_state()) { + if(RRC_STATE_RRC_CONNECTED == rrc.get_state()) { + phy.get_metrics(m.phy); + mac.get_metrics(m.mac); + rlc.get_metrics(m.rlc); + gw.get_metrics(m.gw); + return true; + } + } + return false; +} + +void ue::rf_msg(srslte_rf_error_t error) +{ + ue *u = ue::get_instance(); + u->handle_rf_msg(error); +} + +void ue::handle_rf_msg(srslte_rf_error_t error) +{ + if(error.type == srslte_rf_error_t::SRSLTE_RF_ERROR_OVERFLOW) { + rf_metrics.rf_o++; + rf_metrics.rf_error = true; + rf_log.warning("Overflow\n"); + }else if(error.type == srslte_rf_error_t::SRSLTE_RF_ERROR_UNDERFLOW) { + rf_metrics.rf_u++; + rf_metrics.rf_error = true; + rf_log.warning("Underflow\n"); + } else if(error.type == srslte_rf_error_t::SRSLTE_RF_ERROR_LATE) { + rf_metrics.rf_l++; + rf_metrics.rf_error = true; + rf_log.warning("Late\n"); + } else if (error.type == srslte_rf_error_t::SRSLTE_RF_ERROR_OTHER) { + std::string str(error.msg); + str.erase(std::remove(str.begin(), str.end(), '\n'), str.end()); + str.erase(std::remove(str.begin(), str.end(), '\r'), str.end()); + str.push_back('\n'); + rf_log.info(str); + } +} + +srslte::LOG_LEVEL_ENUM ue::level(std::string l) +{ + std::transform(l.begin(), l.end(), l.begin(), ::toupper); + if("NONE" == l){ + return srslte::LOG_LEVEL_NONE; + }else if("ERROR" == l){ + return srslte::LOG_LEVEL_ERROR; + }else if("WARNING" == l){ + return srslte::LOG_LEVEL_WARNING; + }else if("INFO" == l){ + return srslte::LOG_LEVEL_INFO; + }else if("DEBUG" == l){ + return srslte::LOG_LEVEL_DEBUG; + }else{ + return srslte::LOG_LEVEL_NONE; + } +} + +} // namespace srsue diff --git a/srsue/src/upper/CMakeLists.txt b/srsue/src/upper/CMakeLists.txt new file mode 100644 index 000000000..fec89c8e3 --- /dev/null +++ b/srsue/src/upper/CMakeLists.txt @@ -0,0 +1,22 @@ +# +# Copyright 2013-2017 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(GLOB SOURCES "*.cc") +add_library(srsue_upper SHARED ${SOURCES}) diff --git a/srsue/src/upper/nas.cc b/srsue/src/upper/nas.cc new file mode 100644 index 000000000..15dc154ae --- /dev/null +++ b/srsue/src/upper/nas.cc @@ -0,0 +1,633 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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 "upper/nas.h" + +using namespace srslte; + +namespace srsue{ + +nas::nas() + :state(EMM_STATE_DEREGISTERED) + ,is_guti_set(false) + ,ip_addr(0) + ,eps_bearer_id(0) + ,count_ul(0) + ,count_dl(0) +{} + +void nas::init(usim_interface_nas *usim_, + rrc_interface_nas *rrc_, + gw_interface_nas *gw_, + srslte::log *nas_log_) +{ + pool = byte_buffer_pool::get_instance(); + usim = usim_; + rrc = rrc_; + gw = gw_; + nas_log = nas_log_; +} + +void nas::stop() +{} + +emm_state_t nas::get_state() +{ + return state; +} + + +/******************************************************************************* + RRC interface +*******************************************************************************/ + +bool nas::is_attached() +{ + return state == EMM_STATE_REGISTERED; +} + +void nas::notify_connection_setup() +{ + nas_log->debug("State = %s\n", emm_state_text[state]); + if(EMM_STATE_DEREGISTERED == state) { + send_attach_request(); + } else { + send_service_request(); + } +} + +void nas::write_pdu(uint32_t lcid, byte_buffer_t *pdu) +{ + uint8 pd; + uint8 msg_type; + + nas_log->info_hex(pdu->msg, pdu->N_bytes, "DL %s PDU", rb_id_text[lcid]); + + // Parse the message + liblte_mme_parse_msg_header((LIBLTE_BYTE_MSG_STRUCT*)pdu, &pd, &msg_type); + switch(msg_type) + { + case LIBLTE_MME_MSG_TYPE_ATTACH_ACCEPT: + parse_attach_accept(lcid, pdu); + break; + case LIBLTE_MME_MSG_TYPE_ATTACH_REJECT: + parse_attach_reject(lcid, pdu); + break; + case LIBLTE_MME_MSG_TYPE_AUTHENTICATION_REQUEST: + parse_authentication_request(lcid, pdu); + break; + case LIBLTE_MME_MSG_TYPE_AUTHENTICATION_REJECT: + parse_authentication_reject(lcid, pdu); + break; + case LIBLTE_MME_MSG_TYPE_IDENTITY_REQUEST: + parse_identity_request(lcid, pdu); + break; + case LIBLTE_MME_MSG_TYPE_SECURITY_MODE_COMMAND: + parse_security_mode_command(lcid, pdu); + break; + case LIBLTE_MME_MSG_TYPE_SERVICE_REJECT: + parse_service_reject(lcid, pdu); + break; + case LIBLTE_MME_MSG_TYPE_ESM_INFORMATION_REQUEST: + parse_esm_information_request(lcid, pdu); + break; + case LIBLTE_MME_MSG_TYPE_EMM_INFORMATION: + parse_emm_information(lcid, pdu); + break; + default: + nas_log->error("Not handling NAS message with MSG_TYPE=%02X\n",msg_type); + pool->deallocate(pdu); + break; + } +} + +uint32_t nas::get_ul_count() +{ + return count_ul; +} + +bool nas::get_s_tmsi(LIBLTE_RRC_S_TMSI_STRUCT *s_tmsi) +{ + if(is_guti_set) { + s_tmsi->mmec = guti.mme_code; + s_tmsi->m_tmsi = guti.m_tmsi; + return true; + } else { + return false; + } +} + +/******************************************************************************* + Security +*******************************************************************************/ + +void nas::integrity_generate(uint8_t *key_128, + uint32_t count, + uint8_t rb_id, + uint8_t direction, + uint8_t *msg, + uint32_t msg_len, + uint8_t *mac) +{ + switch(integ_algo) + { + case INTEGRITY_ALGORITHM_ID_EIA0: + break; + case INTEGRITY_ALGORITHM_ID_128_EIA1: + security_128_eia1(key_128, + count, + rb_id, + direction, + msg, + msg_len, + mac); + break; + case INTEGRITY_ALGORITHM_ID_128_EIA2: + security_128_eia2(key_128, + count, + rb_id, + direction, + msg, + msg_len, + mac); + break; + default: + break; + } +} + +void nas::integrity_check() +{ + +} + +void nas::cipher_encrypt() +{ + +} + +void nas::cipher_decrypt() +{ + +} + + + +/******************************************************************************* + Parsers +*******************************************************************************/ + +void nas::parse_attach_accept(uint32_t lcid, byte_buffer_t *pdu) +{ + LIBLTE_MME_ATTACH_ACCEPT_MSG_STRUCT attach_accept; + LIBLTE_MME_ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_MSG_STRUCT act_def_eps_bearer_context_req; + LIBLTE_MME_ATTACH_COMPLETE_MSG_STRUCT attach_complete; + LIBLTE_MME_ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_ACCEPT_MSG_STRUCT act_def_eps_bearer_context_accept; + + nas_log->info("Received Attach Accept\n"); + count_dl++; + + liblte_mme_unpack_attach_accept_msg((LIBLTE_BYTE_MSG_STRUCT*)pdu, &attach_accept); + + if(attach_accept.eps_attach_result == LIBLTE_MME_EPS_ATTACH_RESULT_EPS_ONLY) + { + //FIXME: Handle t3412.unit + //FIXME: Handle tai_list + if(attach_accept.guti_present) + { + memcpy(&guti, &attach_accept.guti.guti, sizeof(LIBLTE_MME_EPS_MOBILE_ID_GUTI_STRUCT)); + is_guti_set = true; + // TODO: log message to console + } + if(attach_accept.lai_present) + { + } + if(attach_accept.ms_id_present) + {} + if(attach_accept.emm_cause_present) + {} + if(attach_accept.t3402_present) + {} + if(attach_accept.t3423_present) + {} + if(attach_accept.equivalent_plmns_present) + {} + if(attach_accept.emerg_num_list_present) + {} + if(attach_accept.eps_network_feature_support_present) + {} + if(attach_accept.additional_update_result_present) + {} + if(attach_accept.t3412_ext_present) + {} + + liblte_mme_unpack_activate_default_eps_bearer_context_request_msg(&attach_accept.esm_msg, &act_def_eps_bearer_context_req); + + if(LIBLTE_MME_PDN_TYPE_IPV4 == act_def_eps_bearer_context_req.pdn_addr.pdn_type) + { + ip_addr |= act_def_eps_bearer_context_req.pdn_addr.addr[0] << 24; + ip_addr |= act_def_eps_bearer_context_req.pdn_addr.addr[1] << 16; + ip_addr |= act_def_eps_bearer_context_req.pdn_addr.addr[2] << 8; + ip_addr |= act_def_eps_bearer_context_req.pdn_addr.addr[3]; + + nas_log->info("IP allocated by network %u.%u.%u.%u\n", + act_def_eps_bearer_context_req.pdn_addr.addr[0], + act_def_eps_bearer_context_req.pdn_addr.addr[1], + act_def_eps_bearer_context_req.pdn_addr.addr[2], + act_def_eps_bearer_context_req.pdn_addr.addr[3]); + + nas_log->console("Network attach successful. IP: %u.%u.%u.%u\n", + act_def_eps_bearer_context_req.pdn_addr.addr[0], + act_def_eps_bearer_context_req.pdn_addr.addr[1], + act_def_eps_bearer_context_req.pdn_addr.addr[2], + act_def_eps_bearer_context_req.pdn_addr.addr[3]); + + // Setup GW + char *err_str = NULL; + if(gw->setup_if_addr(ip_addr, err_str)) + { + nas_log->error("Failed to set gateway address - %s\n", err_str); + } + } + else + { + nas_log->error("Not handling IPV6 or IPV4V6\n"); + pool->deallocate(pdu); + return; + } + eps_bearer_id = act_def_eps_bearer_context_req.eps_bearer_id; + if(act_def_eps_bearer_context_req.transaction_id_present) + { + transaction_id = act_def_eps_bearer_context_req.proc_transaction_id; + } + + //FIXME: Handle the following parameters +// act_def_eps_bearer_context_req.eps_qos.qci +// act_def_eps_bearer_context_req.eps_qos.br_present +// act_def_eps_bearer_context_req.eps_qos.br_ext_present +// act_def_eps_bearer_context_req.apn.apn +// act_def_eps_bearer_context_req.negotiated_qos_present +// act_def_eps_bearer_context_req.llc_sapi_present +// act_def_eps_bearer_context_req.radio_prio_present +// act_def_eps_bearer_context_req.packet_flow_id_present +// act_def_eps_bearer_context_req.apn_ambr_present +// act_def_eps_bearer_context_req.protocol_cnfg_opts_present +// act_def_eps_bearer_context_req.connectivity_type_present + + // FIXME: Setup the default EPS bearer context + + state = EMM_STATE_REGISTERED; + + // Send EPS bearer context accept and attach complete + count_ul++; + act_def_eps_bearer_context_accept.eps_bearer_id = eps_bearer_id; + act_def_eps_bearer_context_accept.proc_transaction_id = transaction_id; + act_def_eps_bearer_context_accept.protocol_cnfg_opts_present = false; + liblte_mme_pack_activate_default_eps_bearer_context_accept_msg(&act_def_eps_bearer_context_accept, &attach_complete.esm_msg); + liblte_mme_pack_attach_complete_msg(&attach_complete, + LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED, + count_ul, + (LIBLTE_BYTE_MSG_STRUCT*)pdu); + integrity_generate(&k_nas_int[16], + count_ul, + lcid-1, + SECURITY_DIRECTION_UPLINK, + &pdu->msg[5], + pdu->N_bytes-5, + &pdu->msg[1]); + + // Instruct RRC to enable capabilities + rrc->enable_capabilities(); + + nas_log->info("Sending Attach Complete\n"); + rrc->write_sdu(lcid, pdu); + + } + else + { + nas_log->info("Not handling attach type %u\n", attach_accept.eps_attach_result); + state = EMM_STATE_DEREGISTERED; + pool->deallocate(pdu); + } +} + +void nas::parse_attach_reject(uint32_t lcid, byte_buffer_t *pdu) +{ + LIBLTE_MME_ATTACH_REJECT_MSG_STRUCT attach_rej; + + liblte_mme_unpack_attach_reject_msg((LIBLTE_BYTE_MSG_STRUCT*)pdu, &attach_rej); + nas_log->warning("Received Attach Reject. Cause= %02X\n", attach_rej.emm_cause); + nas_log->console("Received Attach Reject. Cause= %02X\n", attach_rej.emm_cause); + state = EMM_STATE_DEREGISTERED; + pool->deallocate(pdu); + // FIXME: Command RRC to release? +} + +void nas::parse_authentication_request(uint32_t lcid, byte_buffer_t *pdu) +{ + LIBLTE_MME_AUTHENTICATION_REQUEST_MSG_STRUCT auth_req; + LIBLTE_MME_AUTHENTICATION_RESPONSE_MSG_STRUCT auth_res; + + nas_log->info("Received Authentication Request\n");; + liblte_mme_unpack_authentication_request_msg((LIBLTE_BYTE_MSG_STRUCT*)pdu, &auth_req); + + // Reuse the pdu for the response message + pdu->reset(); + + // Generate authentication response using RAND, AUTN & KSI-ASME + uint16 mcc, mnc; + mcc = rrc->get_mcc(); + mnc = rrc->get_mnc(); + + nas_log->info("MCC=%d, MNC=%d\n", mcc, mnc); + + bool net_valid; + uint8_t res[16]; + usim->generate_authentication_response(auth_req.rand, auth_req.autn, mcc, mnc, &net_valid, res); + + if(net_valid) + { + nas_log->info("Network authentication successful\n"); + for(int i=0; i<8; i++) + { + auth_res.res[i] = res[i]; + } + liblte_mme_pack_authentication_response_msg(&auth_res, (LIBLTE_BYTE_MSG_STRUCT*)pdu); + + nas_log->info("Sending Authentication Response\n"); + rrc->write_sdu(lcid, pdu); + } + else + { + nas_log->warning("Network authentication failure\n"); + nas_log->console("Warning: Network authentication failure\n"); + pool->deallocate(pdu); + } +} + +void nas::parse_authentication_reject(uint32_t lcid, byte_buffer_t *pdu) +{ + nas_log->warning("Received Authentication Reject\n"); + pool->deallocate(pdu); + state = EMM_STATE_DEREGISTERED; + // FIXME: Command RRC to release? +} + +void nas::parse_identity_request(uint32_t lcid, byte_buffer_t *pdu) +{ + nas_log->error("TODO:parse_identity_request\n"); +} + +void nas::parse_security_mode_command(uint32_t lcid, byte_buffer_t *pdu) +{ + bool success; + LIBLTE_MME_SECURITY_MODE_COMMAND_MSG_STRUCT sec_mode_cmd; + LIBLTE_MME_SECURITY_MODE_COMPLETE_MSG_STRUCT sec_mode_comp; + LIBLTE_MME_SECURITY_MODE_REJECT_MSG_STRUCT sec_mode_rej; + + nas_log->info("Received Security Mode Command\n"); + liblte_mme_unpack_security_mode_command_msg((LIBLTE_BYTE_MSG_STRUCT*)pdu, &sec_mode_cmd); + + ksi = sec_mode_cmd.nas_ksi.nas_ksi; + cipher_algo = (CIPHERING_ALGORITHM_ID_ENUM)sec_mode_cmd.selected_nas_sec_algs.type_of_eea; + integ_algo = (INTEGRITY_ALGORITHM_ID_ENUM)sec_mode_cmd.selected_nas_sec_algs.type_of_eia; + // FIXME: Handle nonce_ue, nonce_mme + // FIXME: Currently only handling ciphering EEA0 (null) and integrity EIA1,EIA2 + // FIXME: Use selected_nas_sec_algs to choose correct algos + + nas_log->debug("Security details: ksi=%d, eea=%s, eia=%s\n", + ksi, ciphering_algorithm_id_text[cipher_algo], integrity_algorithm_id_text[integ_algo]); + + + if(CIPHERING_ALGORITHM_ID_EEA0 != cipher_algo || + (INTEGRITY_ALGORITHM_ID_128_EIA2 != integ_algo && + INTEGRITY_ALGORITHM_ID_128_EIA1 != integ_algo) || + sec_mode_cmd.nas_ksi.tsc_flag != LIBLTE_MME_TYPE_OF_SECURITY_CONTEXT_FLAG_NATIVE) + { + sec_mode_rej.emm_cause = LIBLTE_MME_EMM_CAUSE_UE_SECURITY_CAPABILITIES_MISMATCH; + nas_log->warning("Sending Security Mode Reject due to security capabilities mismatch\n"); + success = false; + } + else + { + // Generate NAS encryption key and integrity protection key + usim->generate_nas_keys(k_nas_enc, k_nas_int, cipher_algo, integ_algo); + nas_log->debug_hex(k_nas_enc, 32, "NAS encryption key - k_nas_enc"); + nas_log->debug_hex(k_nas_int, 32, "NAS integrity key - k_nas_int"); + + // Check incoming MAC + uint8_t *inMAC = &pdu->msg[1]; + uint8_t genMAC[4]; + integrity_generate(&k_nas_int[16], + count_dl, + lcid-1, + SECURITY_DIRECTION_DOWNLINK, + &pdu->msg[5], + pdu->N_bytes-5, + genMAC); + + nas_log->info_hex(inMAC, 4, "Incoming PDU MAC:"); + nas_log->info_hex(genMAC, 4, "Generated PDU MAC:"); + + bool match=true; + for(int i=0;i<4;i++) { + if(inMAC[i] != genMAC[i]) { + match = false; + } + } + if(!match) { + sec_mode_rej.emm_cause = LIBLTE_MME_EMM_CAUSE_SECURITY_MODE_REJECTED_UNSPECIFIED; + nas_log->warning("Sending Security Mode Reject due to integrity check failure\n"); + success = false; + } else { + + if(sec_mode_cmd.imeisv_req_present && LIBLTE_MME_IMEISV_REQUESTED == sec_mode_cmd.imeisv_req) + { + sec_mode_comp.imeisv_present = true; + sec_mode_comp.imeisv.type_of_id = LIBLTE_MME_MOBILE_ID_TYPE_IMEISV; + usim->get_imei_vec(sec_mode_comp.imeisv.imeisv, 15); + sec_mode_comp.imeisv.imeisv[14] = 5; + sec_mode_comp.imeisv.imeisv[15] = 3; + } + else + { + sec_mode_comp.imeisv_present = false; + } + + // Reuse pdu for response + pdu->reset(); + liblte_mme_pack_security_mode_complete_msg(&sec_mode_comp, + LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED, + count_ul, + (LIBLTE_BYTE_MSG_STRUCT*)pdu); + integrity_generate(&k_nas_int[16], + count_ul, + lcid-1, + SECURITY_DIRECTION_UPLINK, + &pdu->msg[5], + pdu->N_bytes-5, + &pdu->msg[1]); + nas_log->info("Sending Security Mode Complete nas_count_ul=%d, RB=%s\n", + count_ul, + rb_id_text[lcid]); + success = true; + } + } + + if(!success) { + // Reuse pdu for response + pdu->reset(); + liblte_mme_pack_security_mode_reject_msg(&sec_mode_rej, (LIBLTE_BYTE_MSG_STRUCT*)pdu); + } + + rrc->write_sdu(lcid, pdu); +} + +void nas::parse_service_reject(uint32_t lcid, byte_buffer_t *pdu) +{ + nas_log->error("TODO:parse_service_reject\n"); +} +void nas::parse_esm_information_request(uint32_t lcid, byte_buffer_t *pdu) +{ + nas_log->error("TODO:parse_esm_information_request\n"); +} +void nas::parse_emm_information(uint32_t lcid, byte_buffer_t *pdu) +{ + nas_log->error("TODO:parse_emm_information\n"); +} + +/******************************************************************************* + Senders +*******************************************************************************/ + +void nas::send_attach_request() +{ + LIBLTE_MME_ATTACH_REQUEST_MSG_STRUCT attach_req; + byte_buffer_t *msg = pool_allocate; + u_int32_t i; + + attach_req.eps_attach_type = LIBLTE_MME_EPS_ATTACH_TYPE_EPS_ATTACH; + + for(i=0; i<8; i++) + { + attach_req.ue_network_cap.eea[i] = false; + attach_req.ue_network_cap.eia[i] = false; + } + attach_req.ue_network_cap.eea[0] = true; // EEA0 supported + attach_req.ue_network_cap.eia[0] = true; // EIA0 supported + attach_req.ue_network_cap.eia[1] = true; // EIA1 supported + attach_req.ue_network_cap.eia[2] = true; // EIA2 supported + + attach_req.ue_network_cap.uea_present = false; // UMTS encryption algos + attach_req.ue_network_cap.uia_present = false; // UMTS integrity algos + + attach_req.ms_network_cap_present = false; // A/Gb mode (2G) or Iu mode (3G) + + attach_req.eps_mobile_id.type_of_id = LIBLTE_MME_EPS_MOBILE_ID_TYPE_IMSI; + usim->get_imsi_vec(attach_req.eps_mobile_id.imsi, 15); + + // ESM message (PDN connectivity request) for first default bearer + gen_pdn_connectivity_request(&attach_req.esm_msg); + + attach_req.old_p_tmsi_signature_present = false; + attach_req.additional_guti_present = false; + attach_req.last_visited_registered_tai_present = false; + attach_req.drx_param_present = false; + attach_req.ms_network_cap_present = false; + attach_req.old_lai_present = false; + attach_req.tmsi_status_present = false; + attach_req.ms_cm2_present = false; + attach_req.ms_cm3_present = false; + attach_req.supported_codecs_present = false; + attach_req.additional_update_type_present = false; + attach_req.voice_domain_pref_and_ue_usage_setting_present = false; + attach_req.device_properties_present = false; + attach_req.old_guti_type_present = false; + + // Pack the message + liblte_mme_pack_attach_request_msg(&attach_req, (LIBLTE_BYTE_MSG_STRUCT*)msg); + + nas_log->info("Sending attach request\n"); + rrc->write_sdu(RB_ID_SRB1, msg); +} + +void nas::gen_pdn_connectivity_request(LIBLTE_BYTE_MSG_STRUCT *msg) +{ + LIBLTE_MME_PDN_CONNECTIVITY_REQUEST_MSG_STRUCT pdn_con_req; + + nas_log->info("Generating PDN Connectivity Request\n"); + + // Set the PDN con req parameters + pdn_con_req.eps_bearer_id = 0x00; // Unassigned bearer ID + pdn_con_req.proc_transaction_id = 0x01; // First transaction ID + pdn_con_req.pdn_type = LIBLTE_MME_PDN_TYPE_IPV4; + pdn_con_req.request_type = LIBLTE_MME_REQUEST_TYPE_INITIAL_REQUEST; + + // Set the optional flags + pdn_con_req.esm_info_transfer_flag_present = false; //FIXME: Check if this is needed + pdn_con_req.apn_present = false; + pdn_con_req.protocol_cnfg_opts_present = false; + pdn_con_req.device_properties_present = false; + + // Pack the message + liblte_mme_pack_pdn_connectivity_request_msg(&pdn_con_req, msg); +} + +void nas::send_identity_response(){} + +void nas::send_service_request() +{ + byte_buffer_t *msg = pool_allocate; + count_ul++; + + // Pack the service request message directly + msg->msg[0] = (LIBLTE_MME_SECURITY_HDR_TYPE_SERVICE_REQUEST << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT); + msg->N_bytes++; + msg->msg[1] = (ksi & 0x07) << 5; + msg->msg[1] |= count_ul & 0x1F; + msg->N_bytes++; + + uint8_t mac[4]; + integrity_generate(&k_nas_int[16], + count_ul, + RB_ID_SRB1-1, + SECURITY_DIRECTION_UPLINK, + &msg->msg[0], + 2, + &mac[0]); + // Set the short MAC + msg->msg[2] = mac[2]; + msg->N_bytes++; + msg->msg[3] = mac[3]; + msg->N_bytes++; + nas_log->info("Sending service request\n"); + rrc->write_sdu(RB_ID_SRB1, msg); +} + +void nas::send_esm_information_response(){} + +} // namespace srsue diff --git a/srsue/src/upper/rrc.cc b/srsue/src/upper/rrc.cc new file mode 100644 index 000000000..a1805a1e9 --- /dev/null +++ b/srsue/src/upper/rrc.cc @@ -0,0 +1,1482 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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 +#include + +#include "upper/rrc.h" +#include "srslte/phy/utils/bit.h" +#include "srslte/common/security.h" +#include "srslte/common/bcd_helpers.h" + +#define TIMEOUT_RESYNC_REESTABLISH 100 + +using namespace srslte; + +namespace srsue{ + +rrc::rrc() + :state(RRC_STATE_IDLE) + ,drb_up(false) +{} + +static void liblte_rrc_handler(void *ctx, char *str) { + rrc *r = (rrc*) ctx; + r->liblte_rrc_log(str); +} + +void rrc::liblte_rrc_log(char* str) +{ + if (rrc_log) { + rrc_log->warning("[ASN]: %s\n", str); + } else { + printf("[ASN]: %s\n", str); + } +} + +void rrc::init(phy_interface_rrc *phy_, + mac_interface_rrc *mac_, + rlc_interface_rrc *rlc_, + pdcp_interface_rrc *pdcp_, + nas_interface_rrc *nas_, + usim_interface_rrc *usim_, + mac_interface_timers *mac_timers_, + srslte::log *rrc_log_) +{ + pool = byte_buffer_pool::get_instance(); + phy = phy_; + mac = mac_; + rlc = rlc_; + pdcp = pdcp_; + nas = nas_; + usim = usim_; + rrc_log = rrc_log_; + mac_timers = mac_timers_; + + pthread_mutex_init(&mutex, NULL); + + ue_category = SRSLTE_UE_CATEGORY; + + transaction_id = 0; + + // Register logging handler with liblte_rrc + liblte_rrc_log_register_handler(this, liblte_rrc_handler); + + // Set default values for all layers + set_rrc_default(); + set_phy_default(); + set_mac_default(); +} + +void rrc::stop() +{} + +rrc_state_t rrc::get_state() +{ + return state; +} + +void rrc::set_ue_category(int category) +{ + if(category >= 1 && category <= 5) { + ue_category = category; + } else { + rrc_log->error("Unsupported UE category %d\n", category); + } +} + + +/******************************************************************************* + NAS interface +*******************************************************************************/ + +void rrc::write_sdu(uint32_t lcid, byte_buffer_t *sdu) +{ + rrc_log->info_hex(sdu->msg, sdu->N_bytes, "RX %s SDU", rb_id_text[lcid]); + + switch(state) + { + case RRC_STATE_COMPLETING_SETUP: + send_con_setup_complete(sdu); + break; + case RRC_STATE_RRC_CONNECTED: + send_ul_info_transfer(lcid, sdu); + break; + default: + rrc_log->error("SDU received from NAS while RRC state = %s", rrc_state_text[state]); + break; + } +} + +uint16_t rrc::get_mcc() +{ + if(sib1.N_plmn_ids > 0) + return sib1.plmn_id[0].id.mcc; + else + return 0; +} + +uint16_t rrc::get_mnc() +{ + if(sib1.N_plmn_ids > 0) + return sib1.plmn_id[0].id.mnc; + else + return 0; +} + +/******************************************************************************* + MAC interface +*******************************************************************************/ +/* Reception of PUCCH/SRS release procedure (Section 5.3.13) */ +void rrc::release_pucch_srs() +{ + // Apply default configuration for PUCCH (CQI and SR) and SRS (release) + set_phy_default_pucch_srs(); + + // Configure RX signals without pregeneration because default option is release + phy->configure_ul_params(true); + +} + +void rrc::ra_problem() { + radio_link_failure(); +} + +/******************************************************************************* + PHY interface +*******************************************************************************/ + +// Detection of physical layer problems (5.3.11.1) +void rrc::out_of_sync() +{ + if (!mac_timers->get(t311)->is_running() && !mac_timers->get(t310)->is_running()) { + n310_cnt++; + if (n310_cnt == N310) { + mac_timers->get(t310)->reset(); + mac_timers->get(t310)->run(); + n310_cnt = 0; + rrc_log->info("Detected %d out-of-sync from PHY. Starting T310 timer\n", N310); + } + } +} + +// Recovery of physical layer problems (5.3.11.2) +void rrc::in_sync() +{ + if (mac_timers->get(t310)->is_running()) { + n311_cnt++; + if (n311_cnt == N311) { + mac_timers->get(t310)->stop(); + n311_cnt = 0; + rrc_log->info("Detected %d in-sync from PHY. Stopping T310 timer\n", N311); + } + } +} + +/******************************************************************************* + GW interface +*******************************************************************************/ + +bool rrc::rrc_connected() +{ + return (RRC_STATE_RRC_CONNECTED == state); +} + +void rrc::rrc_connect() { + pthread_mutex_lock(&mutex); + if(RRC_STATE_IDLE == state) { + rrc_log->info("RRC in IDLE state - sending connection request.\n"); + state = RRC_STATE_WAIT_FOR_CON_SETUP; + send_con_request(); + } + pthread_mutex_unlock(&mutex); +} + +bool rrc::have_drb() +{ + return drb_up; +} + +/******************************************************************************* + PDCP interface +*******************************************************************************/ + +void rrc::write_pdu(uint32_t lcid, byte_buffer_t *pdu) +{ + rrc_log->info_hex(pdu->msg, pdu->N_bytes, "TX %s PDU", rb_id_text[lcid]); + rrc_log->info("TX PDU Stack latency: %ld us\n", pdu->get_latency_us()); + + switch(lcid) + { + case RB_ID_SRB0: + parse_dl_ccch(pdu); + break; + case RB_ID_SRB1: + case RB_ID_SRB2: + parse_dl_dcch(lcid, pdu); + break; + default: + rrc_log->error("TX PDU with invalid bearer id: %s", lcid); + break; + } + +} + +void rrc::write_pdu_bcch_bch(byte_buffer_t *pdu) +{ + // Unpack the MIB + rrc_log->info_hex(pdu->msg, pdu->N_bytes, "BCCH BCH message received."); + rrc_log->info("BCCH BCH message Stack latency: %ld us\n", pdu->get_latency_us()); + srslte_bit_unpack_vector(pdu->msg, bit_buf.msg, pdu->N_bytes*8); + bit_buf.N_bits = pdu->N_bytes*8; + pool->deallocate(pdu); + liblte_rrc_unpack_bcch_bch_msg((LIBLTE_BIT_MSG_STRUCT*)&bit_buf, &mib); + rrc_log->info("MIB received BW=%s MHz\n", liblte_rrc_dl_bandwidth_text[mib.dl_bw]); + rrc_log->console("MIB received BW=%s MHz\n", liblte_rrc_dl_bandwidth_text[mib.dl_bw]); + + // Start the SIB search state machine + state = RRC_STATE_SIB1_SEARCH; + pthread_create(&sib_search_thread, NULL, &rrc::start_sib_thread, this); +} + +void rrc::write_pdu_bcch_dlsch(byte_buffer_t *pdu) +{ + rrc_log->info_hex(pdu->msg, pdu->N_bytes, "BCCH DLSCH message received."); + rrc_log->info("BCCH DLSCH message Stack latency: %ld us\n", pdu->get_latency_us()); + LIBLTE_RRC_BCCH_DLSCH_MSG_STRUCT dlsch_msg; + srslte_bit_unpack_vector(pdu->msg, bit_buf.msg, pdu->N_bytes*8); + bit_buf.N_bits = pdu->N_bytes*8; + pool->deallocate(pdu); + liblte_rrc_unpack_bcch_dlsch_msg((LIBLTE_BIT_MSG_STRUCT*)&bit_buf, &dlsch_msg); + + if (dlsch_msg.N_sibs > 0) { + if (LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1 == dlsch_msg.sibs[0].sib_type && RRC_STATE_SIB1_SEARCH == state) { + // Handle SIB1 + memcpy(&sib1, &dlsch_msg.sibs[0].sib.sib1, sizeof(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1_STRUCT)); + rrc_log->info("SIB1 received, CellID=%d, si_window=%d, sib2_period=%d\n", + sib1.cell_id&0xfff, + liblte_rrc_si_window_length_num[sib1.si_window_length], + liblte_rrc_si_periodicity_num[sib1.sched_info[0].si_periodicity]); + std::stringstream ss; + for(uint32_t i=0;iset_config_tdd(&dlsch_msg.sibs[0].sib.sib1.tdd_cnfg); + } + + rrc_log->console("SIB1 received, CellID=%d, %s\n", + sib1.cell_id&0xfff, + ss.str().c_str()); + + state = RRC_STATE_SIB2_SEARCH; + mac->bcch_stop_rx(); + //TODO: Use all SIB1 info + + } else if (LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2 == dlsch_msg.sibs[0].sib_type && RRC_STATE_SIB2_SEARCH == state) { + // Handle SIB2 + memcpy(&sib2, &dlsch_msg.sibs[0].sib.sib2, sizeof(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT)); + rrc_log->console("SIB2 received\n"); + rrc_log->info("SIB2 received\n"); + state = RRC_STATE_WAIT_FOR_CON_SETUP; + mac->bcch_stop_rx(); + apply_sib2_configs(); + send_con_request(); + } + } +} + +void rrc::write_pdu_pcch(byte_buffer_t *pdu) +{ + if (pdu->N_bytes > 0 && pdu->N_bytes < SRSLTE_MAX_BUFFER_SIZE_BITS) { + rrc_log->info_hex(pdu->msg, pdu->N_bytes, "PCCH message received %d bytes\n", pdu->N_bytes); + rrc_log->info("PCCH message Stack latency: %ld us\n", pdu->get_latency_us()); + rrc_log->console("PCCH message received %d bytes\n", pdu->N_bytes); + + LIBLTE_RRC_PCCH_MSG_STRUCT pcch_msg; + srslte_bit_unpack_vector(pdu->msg, bit_buf.msg, pdu->N_bytes*8); + bit_buf.N_bits = pdu->N_bytes*8; + pool->deallocate(pdu); + liblte_rrc_unpack_pcch_msg((LIBLTE_BIT_MSG_STRUCT*)&bit_buf, &pcch_msg); + + if (pcch_msg.paging_record_list_size > LIBLTE_RRC_MAX_PAGE_REC) { + pcch_msg.paging_record_list_size = LIBLTE_RRC_MAX_PAGE_REC; + } + + LIBLTE_RRC_S_TMSI_STRUCT s_tmsi; + if(!nas->get_s_tmsi(&s_tmsi)) { + rrc_log->info("No S-TMSI present in NAS\n"); + return; + } + + LIBLTE_RRC_S_TMSI_STRUCT *s_tmsi_paged; + for (uint32_t i=0;iinfo("Received paging (%d/%d) for UE 0x%x\n", i+1, pcch_msg.paging_record_list_size, + pcch_msg.paging_record_list[i].ue_identity.s_tmsi); + rrc_log->console("Received paging (%d/%d) for UE 0x%x\n", i+1, pcch_msg.paging_record_list_size, + pcch_msg.paging_record_list[i].ue_identity.s_tmsi); + if(s_tmsi.mmec == s_tmsi_paged->mmec && s_tmsi.m_tmsi == s_tmsi_paged->m_tmsi) { + rrc_log->info("S-TMSI match in paging message\n"); + rrc_log->console("S-TMSI match in paging message\n"); + mac->pcch_stop_rx(); + if(RRC_STATE_IDLE == state) { + rrc_log->info("RRC in IDLE state - sending connection request.\n"); + state = RRC_STATE_WAIT_FOR_CON_SETUP; + send_con_request(); + } + } + } + } +} + +/******************************************************************************* + RLC interface +*******************************************************************************/ + +void rrc::max_retx_attempted() +{ + //TODO: Handle the radio link failure + rrc_log->warning("Max RLC reTx attempted\n"); + //radio_link_failure(); +} + +/******************************************************************************* + Senders +*******************************************************************************/ + +void rrc::send_con_request() +{ + rrc_log->debug("Preparing RRC Connection Request\n"); + LIBLTE_RRC_UL_CCCH_MSG_STRUCT ul_ccch_msg; + LIBLTE_RRC_S_TMSI_STRUCT s_tmsi; + + // Prepare ConnectionRequest packet + ul_ccch_msg.msg_type = LIBLTE_RRC_UL_CCCH_MSG_TYPE_RRC_CON_REQ; + if(nas->get_s_tmsi(&s_tmsi)) { + ul_ccch_msg.msg.rrc_con_req.ue_id_type = LIBLTE_RRC_CON_REQ_UE_ID_TYPE_S_TMSI; + ul_ccch_msg.msg.rrc_con_req.ue_id.s_tmsi = s_tmsi; + } else { + ul_ccch_msg.msg.rrc_con_req.ue_id_type = LIBLTE_RRC_CON_REQ_UE_ID_TYPE_RANDOM_VALUE; + ul_ccch_msg.msg.rrc_con_req.ue_id.random = 1000; + } + ul_ccch_msg.msg.rrc_con_req.cause = LIBLTE_RRC_CON_REQ_EST_CAUSE_MO_SIGNALLING; + liblte_rrc_pack_ul_ccch_msg(&ul_ccch_msg, (LIBLTE_BIT_MSG_STRUCT*)&bit_buf); + + // Byte align and pack the message bits for PDCP + if((bit_buf.N_bits % 8) != 0) + { + for(uint32_t i=0; i<8-(bit_buf.N_bits % 8); i++) + bit_buf.msg[bit_buf.N_bits + i] = 0; + bit_buf.N_bits += 8 - (bit_buf.N_bits % 8); + } + byte_buffer_t *pdcp_buf = pool_allocate; + srslte_bit_pack_vector(bit_buf.msg, pdcp_buf->msg, bit_buf.N_bits); + pdcp_buf->N_bytes = bit_buf.N_bits/8; + pdcp_buf->set_timestamp(); + + // Set UE contention resolution ID in MAC + uint64_t uecri=0; + uint8_t *ue_cri_ptr = (uint8_t*) &uecri; + uint32_t nbytes = 6; + for (uint32_t i=0;imsg[i]; + } + rrc_log->debug("Setting UE contention resolution ID: %d\n", uecri); + + mac->set_contention_id(uecri); + + rrc_log->info("Sending RRC Connection Request on SRB0\n"); + state = RRC_STATE_WAIT_FOR_CON_SETUP; + pdcp->write_sdu(RB_ID_SRB0, pdcp_buf); +} + + +/* RRC connection re-establishment procedure (5.3.7) */ +void rrc::send_con_restablish_request() +{ + + srslte_cell_t cell; + phy->get_current_cell(&cell); + + LIBLTE_RRC_UL_CCCH_MSG_STRUCT ul_ccch_msg; + LIBLTE_RRC_S_TMSI_STRUCT s_tmsi; + + // Compute shortMAC-I + uint8_t varShortMAC[128], varShortMAC_packed[16]; + bzero(varShortMAC, 128); + bzero(varShortMAC_packed, 16); + uint8_t *msg_ptr = varShortMAC; + liblte_rrc_pack_cell_identity_ie(0x1a2d0, &msg_ptr); + liblte_rrc_pack_phys_cell_id_ie(cell.id, &msg_ptr); + mac_interface_rrc::ue_rnti_t ue_rnti; + mac->get_rntis(&ue_rnti); + liblte_rrc_pack_c_rnti_ie(ue_rnti.crnti, &msg_ptr); + srslte_bit_pack_vector(varShortMAC, varShortMAC_packed, msg_ptr - varShortMAC); + + uint8_t mac_key[4]; + security_128_eia2(&k_rrc_int[16], + 1, + 1, + 1, + varShortMAC_packed, + 7, + mac_key); + + mac_interface_rrc::ue_rnti_t uernti; + mac->get_rntis(&uernti); + + // Prepare ConnectionRestalishmentRequest packet + ul_ccch_msg.msg_type = LIBLTE_RRC_UL_CCCH_MSG_TYPE_RRC_CON_REEST_REQ; + ul_ccch_msg.msg.rrc_con_reest_req.ue_id.c_rnti = uernti.crnti; + ul_ccch_msg.msg.rrc_con_reest_req.ue_id.phys_cell_id = cell.id; + ul_ccch_msg.msg.rrc_con_reest_req.ue_id.short_mac_i = mac_key[2]<<8 | mac_key[3]; + ul_ccch_msg.msg.rrc_con_reest_req.cause = LIBLTE_RRC_CON_REEST_REQ_CAUSE_OTHER_FAILURE; + liblte_rrc_pack_ul_ccch_msg(&ul_ccch_msg, (LIBLTE_BIT_MSG_STRUCT*)&bit_buf); + + rrc_log->info("Initiating RRC Connection Reestablishment Procedure\n"); + rrc_log->console("RRC Connection Reestablishment\n"); + mac_timers->get(t310)->stop(); + mac_timers->get(t311)->reset(); + mac_timers->get(t311)->run(); + + set_phy_default(); + mac->reset(); + + // FIXME: Cell selection should be different?? + phy->resync_sfn(); + + // Wait for cell re-synchronization + uint32_t timeout_cnt = 0; + while(!phy->status_is_sync() && timeout_cnt < TIMEOUT_RESYNC_REESTABLISH){ + usleep(10000); + timeout_cnt++; + } + mac_timers->get(t301)->reset(); + mac_timers->get(t301)->run(); + mac_timers->get(t311)->stop(); + rrc_log->info("Cell Selection finished. Initiating transmission of RRC Connection Reestablishment Request\n"); + + // Byte align and pack the message bits for PDCP + if((bit_buf.N_bits % 8) != 0) + { + for(uint32_t i=0; i<8-(bit_buf.N_bits % 8); i++) + bit_buf.msg[bit_buf.N_bits + i] = 0; + bit_buf.N_bits += 8 - (bit_buf.N_bits % 8); + } + byte_buffer_t *pdcp_buf = pool_allocate; + srslte_bit_pack_vector(bit_buf.msg, pdcp_buf->msg, bit_buf.N_bits); + pdcp_buf->N_bytes = bit_buf.N_bits/8; + + // Set UE contention resolution ID in MAC + uint64_t uecri=0; + uint8_t *ue_cri_ptr = (uint8_t*) &uecri; + uint32_t nbytes = 6; + for (uint32_t i=0;imsg[i]; + } + rrc_log->debug("Setting UE contention resolution ID: %d\n", uecri); + mac->set_contention_id(uecri); + + rrc_log->info("Sending RRC Connection Resetablishment Request on SRB0\n"); + state = RRC_STATE_WAIT_FOR_CON_SETUP; + pdcp->write_sdu(RB_ID_SRB0, pdcp_buf); +} + + +void rrc::send_con_restablish_complete() +{ + rrc_log->debug("Preparing RRC Connection Reestablishment Complete\n"); + LIBLTE_RRC_UL_DCCH_MSG_STRUCT ul_dcch_msg; + + // Prepare ConnectionSetupComplete packet + ul_dcch_msg.msg_type = LIBLTE_RRC_UL_DCCH_MSG_TYPE_RRC_CON_REEST_COMPLETE; + ul_dcch_msg.msg.rrc_con_reest_complete.rrc_transaction_id = transaction_id; + liblte_rrc_pack_ul_dcch_msg(&ul_dcch_msg, (LIBLTE_BIT_MSG_STRUCT*)&bit_buf); + + // Byte align and pack the message bits for PDCP + if((bit_buf.N_bits % 8) != 0) + { + for(uint32_t i=0; i<8-(bit_buf.N_bits % 8); i++) + bit_buf.msg[bit_buf.N_bits + i] = 0; + bit_buf.N_bits += 8 - (bit_buf.N_bits % 8); + } + byte_buffer_t *pdcp_buf = pool_allocate; + srslte_bit_pack_vector(bit_buf.msg, pdcp_buf->msg, bit_buf.N_bits); + pdcp_buf->N_bytes = bit_buf.N_bits/8; + + state = RRC_STATE_RRC_CONNECTED; + rrc_log->console("RRC Connected\n"); + rrc_log->info("Sending RRC Connection Reestablishment Complete\n"); + pdcp->write_sdu(RB_ID_SRB1, pdcp_buf); +} + +void rrc::send_con_setup_complete(byte_buffer_t *nas_msg) +{ + rrc_log->debug("Preparing RRC Connection Setup Complete\n"); + LIBLTE_RRC_UL_DCCH_MSG_STRUCT ul_dcch_msg; + + // Prepare ConnectionSetupComplete packet + ul_dcch_msg.msg_type = LIBLTE_RRC_UL_DCCH_MSG_TYPE_RRC_CON_SETUP_COMPLETE; + ul_dcch_msg.msg.rrc_con_setup_complete.registered_mme_present = false; + ul_dcch_msg.msg.rrc_con_setup_complete.rrc_transaction_id = transaction_id; + ul_dcch_msg.msg.rrc_con_setup_complete.selected_plmn_id = 1; + memcpy(ul_dcch_msg.msg.rrc_con_setup_complete.dedicated_info_nas.msg, nas_msg->msg, nas_msg->N_bytes); + ul_dcch_msg.msg.rrc_con_setup_complete.dedicated_info_nas.N_bytes = nas_msg->N_bytes; + liblte_rrc_pack_ul_dcch_msg(&ul_dcch_msg, (LIBLTE_BIT_MSG_STRUCT*)&bit_buf); + + // Byte align and pack the message bits for PDCP + if((bit_buf.N_bits % 8) != 0) + { + for(uint32_t i=0; i<8-(bit_buf.N_bits % 8); i++) + bit_buf.msg[bit_buf.N_bits + i] = 0; + bit_buf.N_bits += 8 - (bit_buf.N_bits % 8); + } + byte_buffer_t *pdcp_buf = pool_allocate; + srslte_bit_pack_vector(bit_buf.msg, pdcp_buf->msg, bit_buf.N_bits); + pdcp_buf->N_bytes = bit_buf.N_bits/8; + pdcp_buf->set_timestamp(); + + state = RRC_STATE_RRC_CONNECTED; + rrc_log->console("RRC Connected\n"); + rrc_log->info("Sending RRC Connection Setup Complete\n"); + pdcp->write_sdu(RB_ID_SRB1, pdcp_buf); +} + +void rrc::send_ul_info_transfer(uint32_t lcid, byte_buffer_t *sdu) +{ + rrc_log->debug("Preparing RX Info Transfer\n"); + LIBLTE_RRC_UL_DCCH_MSG_STRUCT ul_dcch_msg; + + // Prepare RX INFO packet + ul_dcch_msg.msg_type = LIBLTE_RRC_UL_DCCH_MSG_TYPE_UL_INFO_TRANSFER; + ul_dcch_msg.msg.ul_info_transfer.dedicated_info_type = LIBLTE_RRC_UL_INFORMATION_TRANSFER_TYPE_NAS; + memcpy(ul_dcch_msg.msg.ul_info_transfer.dedicated_info.msg, sdu->msg, sdu->N_bytes); + ul_dcch_msg.msg.ul_info_transfer.dedicated_info.N_bytes = sdu->N_bytes; + liblte_rrc_pack_ul_dcch_msg(&ul_dcch_msg, (LIBLTE_BIT_MSG_STRUCT*)&bit_buf); + + // Reset and reuse sdu buffer + byte_buffer_t *pdu = sdu; + pdu->reset(); + + // Byte align and pack the message bits for PDCP + if((bit_buf.N_bits % 8) != 0) + { + for(uint32_t i=0; i<8-(bit_buf.N_bits % 8); i++) + bit_buf.msg[bit_buf.N_bits + i] = 0; + bit_buf.N_bits += 8 - (bit_buf.N_bits % 8); + } + srslte_bit_pack_vector(bit_buf.msg, pdu->msg, bit_buf.N_bits); + pdu->N_bytes = bit_buf.N_bits/8; + pdu->set_timestamp(); + pdu->set_timestamp(); + + rrc_log->info("Sending RX Info Transfer\n"); + pdcp->write_sdu(lcid, pdu); +} + +void rrc::send_security_mode_complete(uint32_t lcid, byte_buffer_t *pdu) +{ + rrc_log->debug("Preparing Security Mode Complete\n"); + LIBLTE_RRC_UL_DCCH_MSG_STRUCT ul_dcch_msg; + ul_dcch_msg.msg_type = LIBLTE_RRC_UL_DCCH_MSG_TYPE_SECURITY_MODE_COMPLETE; + ul_dcch_msg.msg.security_mode_complete.rrc_transaction_id = transaction_id; + liblte_rrc_pack_ul_dcch_msg(&ul_dcch_msg, (LIBLTE_BIT_MSG_STRUCT*)&bit_buf); + + // Byte align and pack the message bits for PDCP + if((bit_buf.N_bits % 8) != 0) + { + for(uint32_t i=0; i<8-(bit_buf.N_bits % 8); i++) + bit_buf.msg[bit_buf.N_bits + i] = 0; + bit_buf.N_bits += 8 - (bit_buf.N_bits % 8); + } + srslte_bit_pack_vector(bit_buf.msg, pdu->msg, bit_buf.N_bits); + pdu->N_bytes = bit_buf.N_bits/8; + pdu->set_timestamp(); + + rrc_log->info("Sending Security Mode Complete\n"); + pdcp->write_sdu(lcid, pdu); +} + +void rrc::send_rrc_con_reconfig_complete(uint32_t lcid, byte_buffer_t *pdu) +{ + rrc_log->debug("Preparing RRC Connection Reconfig Complete\n"); + LIBLTE_RRC_UL_DCCH_MSG_STRUCT ul_dcch_msg; + + ul_dcch_msg.msg_type = LIBLTE_RRC_UL_DCCH_MSG_TYPE_RRC_CON_RECONFIG_COMPLETE; + ul_dcch_msg.msg.rrc_con_reconfig_complete.rrc_transaction_id = transaction_id; + liblte_rrc_pack_ul_dcch_msg(&ul_dcch_msg, (LIBLTE_BIT_MSG_STRUCT*)&bit_buf); + + // Byte align and pack the message bits for PDCP + if((bit_buf.N_bits % 8) != 0) + { + for(uint32_t i=0; i<8-(bit_buf.N_bits % 8); i++) + bit_buf.msg[bit_buf.N_bits + i] = 0; + bit_buf.N_bits += 8 - (bit_buf.N_bits % 8); + } + srslte_bit_pack_vector(bit_buf.msg, pdu->msg, bit_buf.N_bits); + pdu->N_bytes = bit_buf.N_bits/8; + pdu->set_timestamp(); + + rrc_log->info("Sending RRC Connection Reconfig Complete\n"); + pdcp->write_sdu(lcid, pdu); +} + +void rrc::enable_capabilities() +{ + bool enable_ul_64 = ue_category>=5 && sib2.rr_config_common_sib.pusch_cnfg.enable_64_qam; + rrc_log->info("%s 64QAM PUSCH\n", enable_ul_64?"Enabling":"Disabling"); + phy->set_config_64qam_en(enable_ul_64); +} + +void rrc::send_rrc_ue_cap_info(uint32_t lcid, byte_buffer_t *pdu) +{ + rrc_log->debug("Preparing UE Capability Info\n"); + LIBLTE_RRC_UL_DCCH_MSG_STRUCT ul_dcch_msg; + + ul_dcch_msg.msg_type = LIBLTE_RRC_UL_DCCH_MSG_TYPE_UE_CAPABILITY_INFO; + ul_dcch_msg.msg.ue_capability_info.rrc_transaction_id = transaction_id; + + LIBLTE_RRC_UE_CAPABILITY_INFORMATION_STRUCT *info = &ul_dcch_msg.msg.ue_capability_info; + info->N_ue_caps = 1; + info->ue_capability_rat[0].rat_type = LIBLTE_RRC_RAT_TYPE_EUTRA; + + LIBLTE_RRC_UE_EUTRA_CAPABILITY_STRUCT *cap = &info->ue_capability_rat[0].eutra_capability; + cap->access_stratum_release = LIBLTE_RRC_ACCESS_STRATUM_RELEASE_REL8; + cap->ue_category = ue_category; + + cap->pdcp_params.max_rohc_ctxts_present = false; + cap->pdcp_params.supported_rohc_profiles[0] = false; + cap->pdcp_params.supported_rohc_profiles[1] = false; + cap->pdcp_params.supported_rohc_profiles[2] = false; + cap->pdcp_params.supported_rohc_profiles[3] = false; + cap->pdcp_params.supported_rohc_profiles[4] = false; + cap->pdcp_params.supported_rohc_profiles[5] = false; + cap->pdcp_params.supported_rohc_profiles[6] = false; + cap->pdcp_params.supported_rohc_profiles[7] = false; + cap->pdcp_params.supported_rohc_profiles[8] = false; + + cap->phy_params.specific_ref_sigs_supported = false; + cap->phy_params.tx_antenna_selection_supported = false; + + //TODO: Generate this from user input? + cap->rf_params.N_supported_band_eutras = 3; + cap->rf_params.supported_band_eutra[0].band_eutra = 3; + cap->rf_params.supported_band_eutra[0].half_duplex = false; + cap->rf_params.supported_band_eutra[1].band_eutra = 7; + cap->rf_params.supported_band_eutra[1].half_duplex = false; + cap->rf_params.supported_band_eutra[2].band_eutra = 20; + cap->rf_params.supported_band_eutra[2].half_duplex = false; + + cap->meas_params.N_band_list_eutra = 3; + cap->meas_params.band_list_eutra[0].N_inter_freq_need_for_gaps = 3; + cap->meas_params.band_list_eutra[0].inter_freq_need_for_gaps[0] = true; + cap->meas_params.band_list_eutra[0].inter_freq_need_for_gaps[1] = true; + cap->meas_params.band_list_eutra[0].inter_freq_need_for_gaps[2] = true; + cap->meas_params.band_list_eutra[1].N_inter_freq_need_for_gaps = 3; + cap->meas_params.band_list_eutra[1].inter_freq_need_for_gaps[0] = true; + cap->meas_params.band_list_eutra[1].inter_freq_need_for_gaps[1] = true; + cap->meas_params.band_list_eutra[1].inter_freq_need_for_gaps[2] = true; + cap->meas_params.band_list_eutra[2].N_inter_freq_need_for_gaps = 3; + cap->meas_params.band_list_eutra[2].inter_freq_need_for_gaps[0] = true; + cap->meas_params.band_list_eutra[2].inter_freq_need_for_gaps[1] = true; + cap->meas_params.band_list_eutra[2].inter_freq_need_for_gaps[2] = true; + + cap->feature_group_indicator_present = true; + cap->feature_group_indicator = 0x62001000; + cap->inter_rat_params.utra_fdd_present = false; + cap->inter_rat_params.utra_tdd128_present = false; + cap->inter_rat_params.utra_tdd384_present = false; + cap->inter_rat_params.utra_tdd768_present = false; + cap->inter_rat_params.geran_present = false; + cap->inter_rat_params.cdma2000_hrpd_present = false; + cap->inter_rat_params.cdma2000_1xrtt_present = false; + + liblte_rrc_pack_ul_dcch_msg(&ul_dcch_msg, (LIBLTE_BIT_MSG_STRUCT*)&bit_buf); + + // Byte align and pack the message bits for PDCP + if((bit_buf.N_bits % 8) != 0) + { + for(uint32_t i=0; i<8-(bit_buf.N_bits % 8); i++) + bit_buf.msg[bit_buf.N_bits + i] = 0; + bit_buf.N_bits += 8 - (bit_buf.N_bits % 8); + } + srslte_bit_pack_vector(bit_buf.msg, pdu->msg, bit_buf.N_bits); + pdu->N_bytes = bit_buf.N_bits/8; + pdu->set_timestamp(); + + rrc_log->info("Sending UE Capability Info\n"); + pdcp->write_sdu(lcid, pdu); +} + +/******************************************************************************* + Parsers +*******************************************************************************/ + +void rrc::parse_dl_ccch(byte_buffer_t *pdu) +{ + srslte_bit_unpack_vector(pdu->msg, bit_buf.msg, pdu->N_bytes*8); + bit_buf.N_bits = pdu->N_bytes*8; + pool->deallocate(pdu); + bzero(&dl_ccch_msg, sizeof(LIBLTE_RRC_DL_CCCH_MSG_STRUCT)); + liblte_rrc_unpack_dl_ccch_msg((LIBLTE_BIT_MSG_STRUCT*)&bit_buf, &dl_ccch_msg); + + rrc_log->info("SRB0 - Received %s\n", + liblte_rrc_dl_ccch_msg_type_text[dl_ccch_msg.msg_type]); + + switch(dl_ccch_msg.msg_type) + { + case LIBLTE_RRC_DL_CCCH_MSG_TYPE_RRC_CON_REJ: + rrc_log->info("Connection Reject received. Wait time: %d\n", + dl_ccch_msg.msg.rrc_con_rej.wait_time); + state = RRC_STATE_IDLE; + break; + case LIBLTE_RRC_DL_CCCH_MSG_TYPE_RRC_CON_SETUP: + rrc_log->info("Connection Setup received\n"); + transaction_id = dl_ccch_msg.msg.rrc_con_setup.rrc_transaction_id; + handle_con_setup(&dl_ccch_msg.msg.rrc_con_setup); + rrc_log->info("Notifying NAS of connection setup\n"); + state = RRC_STATE_COMPLETING_SETUP; + nas->notify_connection_setup(); + break; + case LIBLTE_RRC_DL_CCCH_MSG_TYPE_RRC_CON_REEST: + rrc_log->info("Connection Reestablishment received\n"); + rrc_log->console("Reestablishment OK\n"); + transaction_id = dl_ccch_msg.msg.rrc_con_reest.rrc_transaction_id; + handle_con_reest(&dl_ccch_msg.msg.rrc_con_reest); + break; + case LIBLTE_RRC_DL_CCCH_MSG_TYPE_RRC_CON_REEST_REJ: + rrc_log->info("Connection Reestablishment Reject received\n"); + rrc_log->console("Reestablishment Reject\n"); + usleep(50000); + rrc_connection_release(); + break; + default: + break; + } +} + +void rrc::parse_dl_dcch(uint32_t lcid, byte_buffer_t *pdu) +{ + srslte_bit_unpack_vector(pdu->msg, bit_buf.msg, pdu->N_bytes*8); + bit_buf.N_bits = pdu->N_bytes*8; + liblte_rrc_unpack_dl_dcch_msg((LIBLTE_BIT_MSG_STRUCT*)&bit_buf, &dl_dcch_msg); + + rrc_log->info("%s - Received %s\n", + rb_id_text[lcid], + liblte_rrc_dl_dcch_msg_type_text[dl_dcch_msg.msg_type]); + + // Reset and reuse pdu buffer if possible + pdu->reset(); + + switch(dl_dcch_msg.msg_type) + { + case LIBLTE_RRC_DL_DCCH_MSG_TYPE_DL_INFO_TRANSFER: + memcpy(pdu->msg, dl_dcch_msg.msg.dl_info_transfer.dedicated_info.msg, dl_dcch_msg.msg.dl_info_transfer.dedicated_info.N_bytes); + pdu->N_bytes = dl_dcch_msg.msg.dl_info_transfer.dedicated_info.N_bytes; + nas->write_pdu(lcid, pdu); + break; + case LIBLTE_RRC_DL_DCCH_MSG_TYPE_SECURITY_MODE_COMMAND: + transaction_id = dl_dcch_msg.msg.security_mode_cmd.rrc_transaction_id; + + cipher_algo = (CIPHERING_ALGORITHM_ID_ENUM)dl_dcch_msg.msg.security_mode_cmd.sec_algs.cipher_alg; + integ_algo = (INTEGRITY_ALGORITHM_ID_ENUM)dl_dcch_msg.msg.security_mode_cmd.sec_algs.int_alg; + + // Configure PDCP for security + usim->generate_as_keys(nas->get_ul_count(), k_rrc_enc, k_rrc_int, k_up_enc, k_up_int, cipher_algo, integ_algo); + pdcp->config_security(lcid, k_rrc_enc, k_rrc_int, cipher_algo, integ_algo); + send_security_mode_complete(lcid, pdu); + break; + case LIBLTE_RRC_DL_DCCH_MSG_TYPE_RRC_CON_RECONFIG: + transaction_id = dl_dcch_msg.msg.rrc_con_reconfig.rrc_transaction_id; + handle_rrc_con_reconfig(lcid, &dl_dcch_msg.msg.rrc_con_reconfig, pdu); + break; + case LIBLTE_RRC_DL_DCCH_MSG_TYPE_UE_CAPABILITY_ENQUIRY: + transaction_id = dl_dcch_msg.msg.ue_cap_enquiry.rrc_transaction_id; + for(uint32_t i=0; iinfo("Timer T310 expired: Radio Link Failure\n"); + radio_link_failure(); + } else if (timeout_id == t311) { + rrc_log->info("Timer T311 expired: Going to RRC IDLE\n"); + rrc_connection_release(); + } else if (timeout_id == t301) { + rrc_log->info("Timer T301 expired: Going to RRC IDLE\n"); + rrc_connection_release(); + } else if (timeout_id == safe_reset_timer) { + reset_ue(); + } else { + rrc_log->error("Timeout from unknown timer id %d\n", timeout_id); + } +} + +/******************************************************************************* + Helpers +*******************************************************************************/ + +void rrc::reset_ue() { + phy->reset(); + mac->reset(); + pdcp->reset(); + rlc->reset(); + mac->pcch_start_rx(); + mac_timers->get(safe_reset_timer)->stop(); + mac_timers->get(safe_reset_timer)->reset(); + rrc_log->console("RRC Connection released.\n"); +} + +void rrc::rrc_connection_release() { + pthread_mutex_lock(&mutex); + drb_up = false; + state = RRC_STATE_IDLE; + set_phy_default(); + set_mac_default(); + mac_timers->get(t311)->run(); + mac_timers->get(t310)->stop(); + mac_timers->get(t311)->stop(); + mac_timers->get(safe_reset_timer)->stop(); + mac_timers->get(safe_reset_timer)->reset(); + mac_timers->get(safe_reset_timer)->run(); + pthread_mutex_unlock(&mutex); +} + +void rrc::test_con_restablishment() +{ + printf("Testing connection Reestablishment\n"); + send_con_restablish_request(); +} + +/* Detection of radio link failure (5.3.11.3) */ +void rrc::radio_link_failure() { + // TODO: Generate and store failure report + + rrc_log->warning("Detected Radio-Link Failure\n"); + rrc_log->console("Warning: Detected Radio-Link Failure\n"); + if (state != RRC_STATE_RRC_CONNECTED) { + rrc_connection_release(); + } else { + send_con_restablish_request(); + } +} + +void* rrc::start_sib_thread(void *rrc_) +{ + rrc *r = (rrc*)rrc_; + r->sib_search(); + return NULL; +} + +void rrc::sib_search() +{ + bool searching = true; + uint32_t tti ; + uint32_t si_win_start, si_win_len; + uint16_t period; + uint32_t nof_sib1_trials = 0; + const int SIB1_SEARCH_TIMEOUT = 30; + + while(searching) + { + switch(state) + { + case RRC_STATE_SIB1_SEARCH: + // Instruct MAC to look for SIB1 + while(!phy->status_is_sync()){ + usleep(50000); + } + usleep(10000); + tti = mac->get_current_tti(); + si_win_start = sib_start_tti(tti, 2, 5); + mac->bcch_start_rx(si_win_start, 1); + rrc_log->debug("Instructed MAC to search for SIB1, win_start=%d, win_len=%d\n", + si_win_start, 1); + nof_sib1_trials++; + if (nof_sib1_trials >= SIB1_SEARCH_TIMEOUT) { + rrc_log->info("Timeout while searching for SIB1. Resynchronizing SFN...\n"); + rrc_log->console("Timeout while searching for SIB1. Resynchronizing SFN...\n"); + phy->resync_sfn(); + nof_sib1_trials = 0; + } + break; + case RRC_STATE_SIB2_SEARCH: + // Instruct MAC to look for SIB2 + usleep(10000); + tti = mac->get_current_tti(); + period = liblte_rrc_si_periodicity_num[sib1.sched_info[0].si_periodicity]; + si_win_start = sib_start_tti(tti, period, 0); + si_win_len = liblte_rrc_si_window_length_num[sib1.si_window_length]; + + mac->bcch_start_rx(si_win_start, si_win_len); + rrc_log->debug("Instructed MAC to search for SIB2, win_start=%d, win_len=%d\n", + si_win_start, si_win_len); + + break; + default: + searching = false; + break; + } + usleep(100000); + } +} + +// Determine SI messages scheduling as in 36.331 5.2.3 Acquisition of an SI message +uint32_t rrc::sib_start_tti(uint32_t tti, uint32_t period, uint32_t x) { + return (period*10*(1+tti/(period*10))+x)%10240; // the 1 means next opportunity +} + +void rrc::apply_sib2_configs() +{ + if(RRC_STATE_WAIT_FOR_CON_SETUP != state){ + rrc_log->error("State must be RRC_STATE_WAIT_FOR_CON_SETUP to handle SIB2. Actual state: %s\n", + rrc_state_text[state]); + return; + } + + // Apply RACH timeAlginmentTimer configuration + mac_interface_rrc::mac_cfg_t cfg; + mac->get_config(&cfg); + cfg.main.time_alignment_timer = sib2.time_alignment_timer; + memcpy(&cfg.rach, &sib2.rr_config_common_sib.rach_cnfg, sizeof(LIBLTE_RRC_RACH_CONFIG_COMMON_STRUCT)); + cfg.prach_config_index = sib2.rr_config_common_sib.prach_cnfg.root_sequence_index; + mac->set_config(&cfg); + + rrc_log->info("Set RACH ConfigCommon: NofPreambles=%d, ResponseWindow=%d, ContentionResolutionTimer=%d ms\n", + liblte_rrc_number_of_ra_preambles_num[sib2.rr_config_common_sib.rach_cnfg.num_ra_preambles], + liblte_rrc_ra_response_window_size_num[sib2.rr_config_common_sib.rach_cnfg.ra_resp_win_size], + liblte_rrc_mac_contention_resolution_timer_num[sib2.rr_config_common_sib.rach_cnfg.mac_con_res_timer]); + + // Apply PHY RR Config Common + phy_interface_rrc::phy_cfg_common_t common; + memcpy(&common.pdsch_cnfg, &sib2.rr_config_common_sib.pdsch_cnfg, sizeof(LIBLTE_RRC_PDSCH_CONFIG_COMMON_STRUCT)); + memcpy(&common.pusch_cnfg, &sib2.rr_config_common_sib.pusch_cnfg, sizeof(LIBLTE_RRC_PUSCH_CONFIG_COMMON_STRUCT)); + memcpy(&common.pucch_cnfg, &sib2.rr_config_common_sib.pucch_cnfg, sizeof(LIBLTE_RRC_PUCCH_CONFIG_COMMON_STRUCT)); + memcpy(&common.ul_pwr_ctrl, &sib2.rr_config_common_sib.ul_pwr_ctrl, sizeof(LIBLTE_RRC_UL_POWER_CONTROL_COMMON_STRUCT)); + memcpy(&common.prach_cnfg, &sib2.rr_config_common_sib.prach_cnfg, sizeof(LIBLTE_RRC_PRACH_CONFIG_SIB_STRUCT)); + if (sib2.rr_config_common_sib.srs_ul_cnfg.present) { + memcpy(&common.srs_ul_cnfg, &sib2.rr_config_common_sib.srs_ul_cnfg, sizeof(LIBLTE_RRC_SRS_UL_CONFIG_COMMON_STRUCT)); + } else { + // default is release + common.srs_ul_cnfg.present = false; + } + phy->set_config_common(&common); + + phy->configure_ul_params(); + + rrc_log->info("Set PUSCH ConfigCommon: HopOffset=%d, RSGroup=%d, RSNcs=%d, N_sb=%d\n", + sib2.rr_config_common_sib.pusch_cnfg.pusch_hopping_offset, + sib2.rr_config_common_sib.pusch_cnfg.ul_rs.group_assignment_pusch, + sib2.rr_config_common_sib.pusch_cnfg.ul_rs.cyclic_shift, + sib2.rr_config_common_sib.pusch_cnfg.n_sb); + + rrc_log->info("Set PUCCH ConfigCommon: DeltaShift=%d, CyclicShift=%d, N1=%d, NRB=%d\n", + liblte_rrc_delta_pucch_shift_num[sib2.rr_config_common_sib.pucch_cnfg.delta_pucch_shift], + sib2.rr_config_common_sib.pucch_cnfg.n_cs_an, + sib2.rr_config_common_sib.pucch_cnfg.n1_pucch_an, + sib2.rr_config_common_sib.pucch_cnfg.n_rb_cqi); + + rrc_log->info("Set PRACH ConfigCommon: SeqIdx=%d, HS=%s, FreqOffset=%d, ZC=%d, ConfigIndex=%d\n", + sib2.rr_config_common_sib.prach_cnfg.root_sequence_index, + sib2.rr_config_common_sib.prach_cnfg.prach_cnfg_info.high_speed_flag?"yes":"no", + sib2.rr_config_common_sib.prach_cnfg.prach_cnfg_info.prach_freq_offset, + sib2.rr_config_common_sib.prach_cnfg.prach_cnfg_info.zero_correlation_zone_config, + sib2.rr_config_common_sib.prach_cnfg.prach_cnfg_info.prach_config_index); + + rrc_log->info("Set SRS ConfigCommon: BW-Configuration=%d, SF-Configuration=%d, ACKNACK=%s\n", + liblte_rrc_srs_bw_config_num[sib2.rr_config_common_sib.srs_ul_cnfg.bw_cnfg], + liblte_rrc_srs_subfr_config_num[sib2.rr_config_common_sib.srs_ul_cnfg.subfr_cnfg], + sib2.rr_config_common_sib.srs_ul_cnfg.ack_nack_simul_tx?"yes":"no"); + + mac_timers->get(t301)->set(this, liblte_rrc_t301_num[sib2.ue_timers_and_constants.t301]); + mac_timers->get(t310)->set(this, liblte_rrc_t310_num[sib2.ue_timers_and_constants.t310]); + mac_timers->get(t311)->set(this, liblte_rrc_t311_num[sib2.ue_timers_and_constants.t311]); + N310 = liblte_rrc_n310_num[sib2.ue_timers_and_constants.n310]; + N311 = liblte_rrc_n311_num[sib2.ue_timers_and_constants.n311]; + + rrc_log->info("Set Constants and Timers: N310=%d, N311=%d, t301=%d, t310=%d, t311=%d\n", + N310, N311, mac_timers->get(t301)->get_timeout(), + mac_timers->get(t310)->get_timeout(), mac_timers->get(t311)->get_timeout()); + +} + + // Go through all information elements and apply defaults (9.2.4) if not defined +void rrc::apply_phy_config_dedicated(LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT *phy_cnfg, bool apply_defaults) +{ + // Get current configuration + LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT *current_cfg; + phy_interface_rrc::phy_cfg_t c; + phy->get_config(&c); + current_cfg = &c.dedicated; + + if(phy_cnfg->pucch_cnfg_ded_present) { + memcpy(¤t_cfg->pucch_cnfg_ded, &phy_cnfg->pucch_cnfg_ded, sizeof(LIBLTE_RRC_PUCCH_CONFIG_DEDICATED_STRUCT)); + } else if (apply_defaults) { + current_cfg->pucch_cnfg_ded.tdd_ack_nack_feedback_mode = LIBLTE_RRC_TDD_ACK_NACK_FEEDBACK_MODE_BUNDLING; + current_cfg->pucch_cnfg_ded.ack_nack_repetition_setup_present = false; + } + if(phy_cnfg->pusch_cnfg_ded_present) { + memcpy(¤t_cfg->pusch_cnfg_ded, &phy_cnfg->pusch_cnfg_ded, sizeof(LIBLTE_RRC_PUSCH_CONFIG_DEDICATED_STRUCT)); + } else if (apply_defaults) { + current_cfg->pusch_cnfg_ded.beta_offset_ack_idx = 10; + current_cfg->pusch_cnfg_ded.beta_offset_ri_idx = 12; + current_cfg->pusch_cnfg_ded.beta_offset_cqi_idx = 15; + } + if(phy_cnfg->ul_pwr_ctrl_ded_present) { + memcpy(¤t_cfg->ul_pwr_ctrl_ded, &phy_cnfg->ul_pwr_ctrl_ded, sizeof(LIBLTE_RRC_UL_POWER_CONTROL_DEDICATED_STRUCT)); + } else if (apply_defaults) { + current_cfg->ul_pwr_ctrl_ded.p0_ue_pusch = 0; + current_cfg->ul_pwr_ctrl_ded.delta_mcs_en = LIBLTE_RRC_DELTA_MCS_ENABLED_EN0; + current_cfg->ul_pwr_ctrl_ded.accumulation_en = true; + current_cfg->ul_pwr_ctrl_ded.p0_ue_pucch = 0; + current_cfg->ul_pwr_ctrl_ded.p_srs_offset = 7; + current_cfg->ul_pwr_ctrl_ded.filter_coeff = LIBLTE_RRC_FILTER_COEFFICIENT_FC4; + current_cfg->ul_pwr_ctrl_ded.filter_coeff_present = true; + } + if(phy_cnfg->tpc_pdcch_cnfg_pucch_present) { + memcpy(¤t_cfg->tpc_pdcch_cnfg_pucch, &phy_cnfg->tpc_pdcch_cnfg_pucch, sizeof(LIBLTE_RRC_TPC_PDCCH_CONFIG_STRUCT)); + } else if (apply_defaults) { + current_cfg->tpc_pdcch_cnfg_pucch.setup_present = false; + } + if(phy_cnfg->tpc_pdcch_cnfg_pusch_present) { + memcpy(¤t_cfg->tpc_pdcch_cnfg_pusch, &phy_cnfg->tpc_pdcch_cnfg_pusch, sizeof(LIBLTE_RRC_TPC_PDCCH_CONFIG_STRUCT)); + } else { + current_cfg->tpc_pdcch_cnfg_pusch.setup_present = false; + } + if(phy_cnfg->cqi_report_cnfg_present) { + if (phy_cnfg->cqi_report_cnfg.report_periodic_present) { + memcpy(¤t_cfg->cqi_report_cnfg.report_periodic, &phy_cnfg->cqi_report_cnfg.report_periodic, sizeof(LIBLTE_RRC_CQI_REPORT_PERIODIC_STRUCT)); + current_cfg->cqi_report_cnfg.report_periodic_setup_present = phy_cnfg->cqi_report_cnfg.report_periodic_setup_present; + } else if (apply_defaults) { + current_cfg->cqi_report_cnfg.report_periodic_setup_present = false; + } + if (phy_cnfg->cqi_report_cnfg.report_mode_aperiodic_present) { + current_cfg->cqi_report_cnfg.report_mode_aperiodic = phy_cnfg->cqi_report_cnfg.report_mode_aperiodic; + current_cfg->cqi_report_cnfg.report_mode_aperiodic_present = phy_cnfg->cqi_report_cnfg.report_mode_aperiodic_present; + } else if (apply_defaults) { + current_cfg->cqi_report_cnfg.report_mode_aperiodic_present = false; + } + current_cfg->cqi_report_cnfg.nom_pdsch_rs_epre_offset = phy_cnfg->cqi_report_cnfg.nom_pdsch_rs_epre_offset; + } + if(phy_cnfg->srs_ul_cnfg_ded_present && phy_cnfg->srs_ul_cnfg_ded.setup_present) { + memcpy(¤t_cfg->srs_ul_cnfg_ded, &phy_cnfg->srs_ul_cnfg_ded, sizeof(LIBLTE_RRC_SRS_UL_CONFIG_DEDICATED_STRUCT)); + } else if (apply_defaults) { + current_cfg->srs_ul_cnfg_ded.setup_present = false; + } + if(phy_cnfg->antenna_info_present) { + if (!phy_cnfg->antenna_info_default_value) { + if(phy_cnfg->antenna_info_explicit_value.tx_mode != LIBLTE_RRC_TRANSMISSION_MODE_1 && + phy_cnfg->antenna_info_explicit_value.tx_mode != LIBLTE_RRC_TRANSMISSION_MODE_2) { + rrc_log->error("Transmission mode TM%s not currently supported by srsUE\n", liblte_rrc_transmission_mode_text[phy_cnfg->antenna_info_explicit_value.tx_mode]); + } + memcpy(¤t_cfg->antenna_info_explicit_value, &phy_cnfg->antenna_info_explicit_value, sizeof(LIBLTE_RRC_ANTENNA_INFO_DEDICATED_STRUCT)); + } else if (apply_defaults) { + current_cfg->antenna_info_explicit_value.tx_mode = LIBLTE_RRC_TRANSMISSION_MODE_2; + current_cfg->antenna_info_explicit_value.codebook_subset_restriction_present = false; + current_cfg->antenna_info_explicit_value.ue_tx_antenna_selection_setup_present = false; + } + } else if (apply_defaults) { + current_cfg->antenna_info_explicit_value.tx_mode = LIBLTE_RRC_TRANSMISSION_MODE_2; + current_cfg->antenna_info_explicit_value.codebook_subset_restriction_present = false; + current_cfg->antenna_info_explicit_value.ue_tx_antenna_selection_setup_present = false; + } + if(phy_cnfg->sched_request_cnfg_present) { + memcpy(¤t_cfg->sched_request_cnfg, &phy_cnfg->sched_request_cnfg, sizeof(LIBLTE_RRC_SCHEDULING_REQUEST_CONFIG_STRUCT)); + } else if (apply_defaults) { + current_cfg->sched_request_cnfg.setup_present = false; + } + if(phy_cnfg->pdsch_cnfg_ded_present) { + current_cfg->pdsch_cnfg_ded = phy_cnfg->pdsch_cnfg_ded; + } else if (apply_defaults) { + current_cfg->pdsch_cnfg_ded = LIBLTE_RRC_PDSCH_CONFIG_P_A_DB_0; + } + + if (phy_cnfg->cqi_report_cnfg_present) { + if (phy_cnfg->cqi_report_cnfg.report_periodic_present) { + rrc_log->info("Set cqi-PUCCH-ResourceIndex=%d, cqi-pmi-ConfigIndex=%d, cqi-FormatIndicatorPeriodic=%s\n", + current_cfg->cqi_report_cnfg.report_periodic.pucch_resource_idx, + current_cfg->cqi_report_cnfg.report_periodic.pmi_cnfg_idx, + liblte_rrc_cqi_format_indicator_periodic_text[current_cfg->cqi_report_cnfg.report_periodic.format_ind_periodic]); + } + if (phy_cnfg->cqi_report_cnfg.report_mode_aperiodic_present) { + rrc_log->info("Set cqi-ReportModeAperiodic=%s\n", + liblte_rrc_cqi_report_mode_aperiodic_text[current_cfg->cqi_report_cnfg.report_mode_aperiodic]); + } + + } + + if (phy_cnfg->sched_request_cnfg_present) { + rrc_log->info("Set PHY config ded: SR-n_pucch=%d, SR-ConfigIndex=%d, SR-TransMax=%d\n", + current_cfg->sched_request_cnfg.sr_pucch_resource_idx, + current_cfg->sched_request_cnfg.sr_cnfg_idx, + liblte_rrc_dsr_trans_max_num[current_cfg->sched_request_cnfg.dsr_trans_max]); + } + + if (current_cfg->srs_ul_cnfg_ded_present) { + rrc_log->info("Set PHY config ded: SRS-ConfigIndex=%d, SRS-bw=%s, SRS-Nrcc=%d, SRS-hop=%s, SRS-Ncs=%s\n", + current_cfg->srs_ul_cnfg_ded.srs_cnfg_idx, + liblte_rrc_srs_bandwidth_text[current_cfg->srs_ul_cnfg_ded.srs_bandwidth], + current_cfg->srs_ul_cnfg_ded.freq_domain_pos, + liblte_rrc_srs_hopping_bandwidth_text[current_cfg->srs_ul_cnfg_ded.srs_hopping_bandwidth], + liblte_rrc_cyclic_shift_text[current_cfg->srs_ul_cnfg_ded.cyclic_shift]); + } + + phy->set_config_dedicated(current_cfg); + + // Apply changes to PHY + phy->configure_ul_params(); + +} + +void rrc::apply_mac_config_dedicated(LIBLTE_RRC_MAC_MAIN_CONFIG_STRUCT *mac_cnfg, bool apply_defaults) +{ + // Set Default MAC main configuration (9.2.2) + LIBLTE_RRC_MAC_MAIN_CONFIG_STRUCT default_cfg; + bzero(&default_cfg, sizeof(LIBLTE_RRC_MAC_MAIN_CONFIG_STRUCT)); + default_cfg.ulsch_cnfg.max_harq_tx = LIBLTE_RRC_MAX_HARQ_TX_N5; + default_cfg.ulsch_cnfg.periodic_bsr_timer = LIBLTE_RRC_PERIODIC_BSR_TIMER_INFINITY; + default_cfg.ulsch_cnfg.retx_bsr_timer = LIBLTE_RRC_RETRANSMISSION_BSR_TIMER_SF2560; + default_cfg.ulsch_cnfg.tti_bundling = false; + default_cfg.drx_cnfg.setup_present = false; + default_cfg.phr_cnfg.setup_present = false; + default_cfg.time_alignment_timer = LIBLTE_RRC_TIME_ALIGNMENT_TIMER_INFINITY; + + + if (!apply_defaults) { + if(mac_cnfg->ulsch_cnfg_present) + { + if(mac_cnfg->ulsch_cnfg.max_harq_tx_present) { + default_cfg.ulsch_cnfg.max_harq_tx = mac_cnfg->ulsch_cnfg.max_harq_tx; + default_cfg.ulsch_cnfg.max_harq_tx_present = true; + } + if(mac_cnfg->ulsch_cnfg.periodic_bsr_timer_present) { + default_cfg.ulsch_cnfg.periodic_bsr_timer = mac_cnfg->ulsch_cnfg.periodic_bsr_timer; + default_cfg.ulsch_cnfg.periodic_bsr_timer_present = true; + } + default_cfg.ulsch_cnfg.retx_bsr_timer = mac_cnfg->ulsch_cnfg.retx_bsr_timer; + default_cfg.ulsch_cnfg.tti_bundling = mac_cnfg->ulsch_cnfg.tti_bundling; + } + if(mac_cnfg->drx_cnfg_present) { + memcpy(&default_cfg.drx_cnfg, &mac_cnfg->drx_cnfg, sizeof(LIBLTE_RRC_DRX_CONFIG_STRUCT)); + default_cfg.drx_cnfg_present = true; + } + if(mac_cnfg->phr_cnfg_present) { + memcpy(&default_cfg.phr_cnfg, &mac_cnfg->phr_cnfg, sizeof(LIBLTE_RRC_PHR_CONFIG_STRUCT)); + default_cfg.phr_cnfg_present = true; + } + default_cfg.time_alignment_timer = mac_cnfg->time_alignment_timer; + } + + // Setup MAC configuration + mac->set_config_main(&default_cfg); + + rrc_log->info("Set MAC main config: harq-MaxReTX=%d, bsr-TimerReTX=%d, bsr-TimerPeriodic=%d\n", + liblte_rrc_max_harq_tx_num[default_cfg.ulsch_cnfg.max_harq_tx], + liblte_rrc_retransmission_bsr_timer_num[default_cfg.ulsch_cnfg.retx_bsr_timer], + liblte_rrc_periodic_bsr_timer_num[default_cfg.ulsch_cnfg.periodic_bsr_timer]); + if (default_cfg.phr_cnfg_present) { + rrc_log->info("Set MAC PHR config: periodicPHR-Timer=%d, prohibitPHR-Timer=%d, dl-PathlossChange=%d\n", + liblte_rrc_periodic_phr_timer_num[default_cfg.phr_cnfg.periodic_phr_timer], + liblte_rrc_prohibit_phr_timer_num[default_cfg.phr_cnfg.prohibit_phr_timer], + liblte_rrc_dl_pathloss_change_num[default_cfg.phr_cnfg.dl_pathloss_change]); + } +} + +void rrc::apply_rr_config_dedicated(LIBLTE_RRC_RR_CONFIG_DEDICATED_STRUCT *cnfg) { + if(cnfg->phy_cnfg_ded_present) { + apply_phy_config_dedicated(&cnfg->phy_cnfg_ded, false); + // Apply SR configuration to MAC + if (cnfg->phy_cnfg_ded.sched_request_cnfg_present) { + mac->set_config_sr(&cnfg->phy_cnfg_ded.sched_request_cnfg); + } + } + + if(cnfg->mac_main_cnfg_present) { + apply_mac_config_dedicated(&cnfg->mac_main_cnfg.explicit_value, cnfg->mac_main_cnfg.default_value); + } + + if(cnfg->sps_cnfg_present) { + //TODO + } + if(cnfg->rlf_timers_and_constants_present) { + //TODO + } + for(uint32_t i=0; isrb_to_add_mod_list_size; i++) { + // TODO: handle SRB modification + add_srb(&cnfg->srb_to_add_mod_list[i]); + } + for(uint32_t i=0; idrb_to_release_list_size; i++) { + release_drb(cnfg->drb_to_release_list[i]); + } + for(uint32_t i=0; idrb_to_add_mod_list_size; i++) { + // TODO: handle DRB modification + add_drb(&cnfg->drb_to_add_mod_list[i]); + } +} + +void rrc::handle_con_setup(LIBLTE_RRC_CONNECTION_SETUP_STRUCT *setup) +{ + // Apply the Radio Resource configuration + apply_rr_config_dedicated(&setup->rr_cnfg); +} + +/* Reception of RRCConnectionReestablishment by the UE 5.3.7.5 */ +void rrc::handle_con_reest(LIBLTE_RRC_CONNECTION_REESTABLISHMENT_STRUCT *setup) +{ + mac_timers->get(t301)->stop(); + + // TODO: Restablish DRB1. Not done because never was suspended + + // Apply the Radio Resource configuration + apply_rr_config_dedicated(&setup->rr_cnfg); + + // TODO: Some security stuff here... is it necessary? + + send_con_restablish_complete(); +} + + +void rrc::handle_rrc_con_reconfig(uint32_t lcid, LIBLTE_RRC_CONNECTION_RECONFIGURATION_STRUCT *reconfig, byte_buffer_t *pdu) +{ + uint32_t i; + + if (reconfig->rr_cnfg_ded_present) { + apply_rr_config_dedicated(&reconfig->rr_cnfg_ded); + } else { + printf("received con reconfig no rr confg present\n"); + } + if(reconfig->meas_cnfg_present) + { + //TODO: handle meas_cnfg + } + if(reconfig->mob_ctrl_info_present) + { + //TODO: handle mob_ctrl_info + } + + send_rrc_con_reconfig_complete(lcid, pdu); + + byte_buffer_t *nas_sdu; + for(i=0;iN_ded_info_nas;i++) + { + nas_sdu = pool_allocate; + memcpy(nas_sdu->msg, &reconfig->ded_info_nas_list[i].msg, reconfig->ded_info_nas_list[i].N_bytes); + nas_sdu->N_bytes = reconfig->ded_info_nas_list[i].N_bytes; + nas->write_pdu(lcid, nas_sdu); + } +} + +void rrc::add_srb(LIBLTE_RRC_SRB_TO_ADD_MOD_STRUCT *srb_cnfg) +{ + // Setup PDCP + pdcp->add_bearer(srb_cnfg->srb_id); + if(RB_ID_SRB2 == srb_cnfg->srb_id) + pdcp->config_security(srb_cnfg->srb_id, k_rrc_enc, k_rrc_int, cipher_algo, integ_algo); + + // Setup RLC + if(srb_cnfg->rlc_cnfg_present) + { + if(srb_cnfg->rlc_default_cnfg_present) + { + rlc->add_bearer(srb_cnfg->srb_id); + }else{ + rlc->add_bearer(srb_cnfg->srb_id, &srb_cnfg->rlc_explicit_cnfg); + } + } + + // Setup MAC + uint8_t log_chan_group = 0; + uint8_t priority = 1; + int prioritized_bit_rate = -1; + int bucket_size_duration = -1; + + if(srb_cnfg->lc_cnfg_present) + { + if(srb_cnfg->lc_default_cnfg_present) + { + if(RB_ID_SRB2 == srb_cnfg->srb_id) + priority = 3; + }else{ + if(srb_cnfg->lc_explicit_cnfg.log_chan_sr_mask_present) + { + //TODO + } + if(srb_cnfg->lc_explicit_cnfg.ul_specific_params_present) + { + if(srb_cnfg->lc_explicit_cnfg.ul_specific_params.log_chan_group_present) + log_chan_group = srb_cnfg->lc_explicit_cnfg.ul_specific_params.log_chan_group; + + priority = srb_cnfg->lc_explicit_cnfg.ul_specific_params.priority; + prioritized_bit_rate = liblte_rrc_prioritized_bit_rate_num[srb_cnfg->lc_explicit_cnfg.ul_specific_params.prioritized_bit_rate]; + bucket_size_duration = liblte_rrc_bucket_size_duration_num[srb_cnfg->lc_explicit_cnfg.ul_specific_params.bucket_size_duration]; + } + } + mac->setup_lcid(srb_cnfg->srb_id, log_chan_group, priority, prioritized_bit_rate, bucket_size_duration); + } + + srbs[srb_cnfg->srb_id] = *srb_cnfg; + rrc_log->info("Added radio bearer %s\n", rb_id_text[srb_cnfg->srb_id]); +} + +void rrc::add_drb(LIBLTE_RRC_DRB_TO_ADD_MOD_STRUCT *drb_cnfg) +{ + + if(!drb_cnfg->pdcp_cnfg_present || + !drb_cnfg->rlc_cnfg_present || + !drb_cnfg->lc_cnfg_present) + { + rrc_log->error("Cannot add DRB - incomplete configuration\n"); + return; + } + uint32_t lcid = 0; + if (drb_cnfg->lc_id_present) { + lcid = drb_cnfg->lc_id; + } else { + lcid = RB_ID_SRB2 + drb_cnfg->drb_id; + rrc_log->warning("LCID not present, using %d\n", lcid); + } + + // Setup PDCP + pdcp->add_bearer(lcid, &drb_cnfg->pdcp_cnfg); + // TODO: setup PDCP security (using k_up_enc) + + // Setup RLC + rlc->add_bearer(lcid, &drb_cnfg->rlc_cnfg); + + // Setup MAC + uint8_t log_chan_group = 0; + uint8_t priority = 1; + int prioritized_bit_rate = -1; + int bucket_size_duration = -1; + if(drb_cnfg->lc_cnfg.ul_specific_params_present) + { + if(drb_cnfg->lc_cnfg.ul_specific_params.log_chan_group_present) { + log_chan_group = drb_cnfg->lc_cnfg.ul_specific_params.log_chan_group; + } else { + rrc_log->warning("LCG not present, setting to 0\n"); + } + priority = drb_cnfg->lc_cnfg.ul_specific_params.priority; + prioritized_bit_rate = liblte_rrc_prioritized_bit_rate_num[drb_cnfg->lc_cnfg.ul_specific_params.prioritized_bit_rate]; + + if (prioritized_bit_rate > 0) { + rrc_log->warning("PBR>0 currently not supported. Setting it to Inifinty\n"); + prioritized_bit_rate = -1; + } + + bucket_size_duration = liblte_rrc_bucket_size_duration_num[drb_cnfg->lc_cnfg.ul_specific_params.bucket_size_duration]; + } + mac->setup_lcid(lcid, log_chan_group, priority, prioritized_bit_rate, bucket_size_duration); + + drbs[lcid] = *drb_cnfg; + drb_up = true; + rrc_log->info("Added radio bearer %s\n", rb_id_text[lcid]); +} + +void rrc::release_drb(uint8_t lcid) +{ + // TODO +} + +/************************** + * DEFAULT VALUES Section 9 +****************************/ + +// PHY CONFIG DEDICATED Defaults (3GPP 36.331 v10 9.2.4) +void rrc::set_phy_default_pucch_srs() +{ + + phy_interface_rrc::phy_cfg_t current_cfg; + phy->get_config(¤t_cfg); + + // Set defaults to CQI, SRS and SR + current_cfg.dedicated.cqi_report_cnfg_present = false; + current_cfg.dedicated.srs_ul_cnfg_ded_present = false; + current_cfg.dedicated.sched_request_cnfg_present = false; + + apply_phy_config_dedicated(¤t_cfg.dedicated, true); + + // Release SR configuration from MAC + LIBLTE_RRC_SCHEDULING_REQUEST_CONFIG_STRUCT cfg; + bzero(&cfg, sizeof(LIBLTE_RRC_SCHEDULING_REQUEST_CONFIG_STRUCT)); + mac->set_config_sr(&cfg); +} + +void rrc::set_phy_default() +{ + LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT defaults; + bzero(&defaults, sizeof(LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT)); + apply_phy_config_dedicated(&defaults, true); +} + +void rrc::set_mac_default() +{ + apply_mac_config_dedicated(NULL, true); + LIBLTE_RRC_SCHEDULING_REQUEST_CONFIG_STRUCT sr_cfg; + bzero(&sr_cfg, sizeof(LIBLTE_RRC_SCHEDULING_REQUEST_CONFIG_STRUCT)); + sr_cfg.setup_present = false; + mac->set_config_sr(&sr_cfg); +} + +void rrc::set_rrc_default() { + N310 = 1; + N311 = 1; + t301 = mac_timers->get_unique_id(); + t310 = mac_timers->get_unique_id(); + t311 = mac_timers->get_unique_id(); + safe_reset_timer = mac_timers->get_unique_id(); + mac_timers->get(t310)->set(this, 1000); + mac_timers->get(t311)->set(this, 1000); + mac_timers->get(safe_reset_timer)->set(this, 10); +} + +} // namespace srsue diff --git a/srsue/src/upper/usim.cc b/srsue/src/upper/usim.cc new file mode 100644 index 000000000..7b1f92896 --- /dev/null +++ b/srsue/src/upper/usim.cc @@ -0,0 +1,373 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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 "upper/usim.h" + +using namespace srslte; + +namespace srsue{ + +usim::usim() +{} + +void usim::init(usim_args_t *args, srslte::log *usim_log_) +{ + usim_log = usim_log_; + + const char *imsi_str = args->imsi.c_str(); + const char *imei_str = args->imei.c_str(); + uint32_t i; + + if(32 == args->op.length()) { + str_to_hex(args->op, op); + } else { + usim_log->error("Invalid length for OP: %d should be %d", args->op.length(), 32); + usim_log->console("Invalid length for OP: %d should be %d", args->op.length(), 32); + } + + if(4 == args->amf.length()) { + str_to_hex(args->amf, amf); + } else { + usim_log->error("Invalid length for AMF: %d should be %d", args->amf.length(), 4); + usim_log->console("Invalid length for AMF: %d should be %d", args->amf.length(), 4); + } + + if(15 == args->imsi.length()) { + imsi = 0; + for(i=0; i<15; i++) + { + imsi *= 10; + imsi += imsi_str[i] - '0'; + } + } else { + usim_log->error("Invalid length for ISMI: %d should be %d", args->imsi.length(), 15); + usim_log->console("Invalid length for IMSI: %d should be %d", args->imsi.length(), 15); + } + + if(15 == args->imei.length()) { + imei = 0; + for(i=0; i<15; i++) + { + imei *= 10; + imei += imei_str[i] - '0'; + } + } else { + usim_log->error("Invalid length for IMEI: %d should be %d", args->imei.length(), 15); + usim_log->console("Invalid length for IMEI: %d should be %d", args->imei.length(), 15); + } + + if(32 == args->k.length()) { + str_to_hex(args->k, k); + } else { + usim_log->error("Invalid length for K: %d should be %d", args->k.length(), 32); + usim_log->console("Invalid length for K: %d should be %d", args->k.length(), 32); + } + + auth_algo = auth_algo_milenage; + if("xor" == args->algo) { + auth_algo = auth_algo_xor; + } +} + +void usim::stop() +{} + +/******************************************************************************* + NAS interface +*******************************************************************************/ + +void usim::get_imsi_vec(uint8_t* imsi_, uint32_t n) +{ + if(NULL == imsi_ || n < 15) + { + usim_log->error("Invalid parameters to get_imsi_vec"); + return; + } + + uint64_t temp = imsi; + for(int i=14;i>=0;i--) + { + imsi_[i] = temp % 10; + temp /= 10; + } +} + +void usim::get_imei_vec(uint8_t* imei_, uint32_t n) +{ + if(NULL == imei_ || n < 15) + { + usim_log->error("Invalid parameters to get_imei_vec"); + return; + } + + uint64 temp = imei; + for(int i=14;i>=0;i--) + { + imei_[i] = temp % 10; + temp /= 10; + } +} + +void usim::generate_authentication_response(uint8_t *rand, + uint8_t *autn_enb, + uint16_t mcc, + uint16_t mnc, + bool *net_valid, + uint8_t *res) +{ + if(auth_algo_xor == auth_algo) { + gen_auth_res_xor(rand, autn_enb, mcc, mnc, net_valid, res); + } else { + gen_auth_res_milenage(rand, autn_enb, mcc, mnc, net_valid, res); + } +} + +void usim::generate_nas_keys(uint8_t *k_nas_enc, + uint8_t *k_nas_int, + CIPHERING_ALGORITHM_ID_ENUM cipher_algo, + INTEGRITY_ALGORITHM_ID_ENUM integ_algo) +{ + // Generate K_nas_enc and K_nas_int + security_generate_k_nas( k_asme, + cipher_algo, + integ_algo, + k_nas_enc, + k_nas_int); +} + +/******************************************************************************* + RRC interface +*******************************************************************************/ + +void usim::generate_as_keys(uint32_t count_ul, + uint8_t *k_rrc_enc, + uint8_t *k_rrc_int, + uint8_t *k_up_enc, + uint8_t *k_up_int, + CIPHERING_ALGORITHM_ID_ENUM cipher_algo, + INTEGRITY_ALGORITHM_ID_ENUM integ_algo) +{ + // Generate K_enb + security_generate_k_enb( k_asme, + count_ul, + k_enb); + + // Generate K_rrc_enc and K_rrc_int + security_generate_k_rrc( k_enb, + cipher_algo, + integ_algo, + k_rrc_enc, + k_rrc_int); + + // Generate K_up_enc and K_up_int + security_generate_k_up( k_enb, + cipher_algo, + integ_algo, + k_up_enc, + k_up_int); +} + +/******************************************************************************* + Helpers +*******************************************************************************/ + +void usim::gen_auth_res_milenage( uint8_t *rand, + uint8_t *autn_enb, + uint16_t mcc, + uint16_t mnc, + bool *net_valid, + uint8_t *res) +{ + uint32_t i; + uint8_t sqn[6]; + + *net_valid = true; + + // Use RAND and K to compute RES, CK, IK and AK + security_milenage_f2345( k, + op, + rand, + res, + ck, + ik, + ak); + + // Extract sqn from autn + for(i=0;i<6;i++) + { + sqn[i] = autn_enb[i] ^ ak[i]; + } + + // Generate MAC + security_milenage_f1( k, + op, + rand, + sqn, + amf, + mac); + + // Construct AUTN + for(i=0; i<6; i++) + { + autn[i] = sqn[i] ^ ak[i]; + } + for(i=0; i<2; i++) + { + autn[6+i] = amf[i]; + } + for(i=0; i<8; i++) + { + autn[8+i] = mac[i]; + } + + // Compare AUTNs + for(i=0; i<16; i++) + { + if(autn[i] != autn_enb[i]) + { + *net_valid = false; + } + } + + // Generate K_asme + security_generate_k_asme( ck, + ik, + ak, + sqn, + mcc, + mnc, + k_asme); +} + +// 3GPP TS 34.108 version 10.0.0 Section 8 +void usim::gen_auth_res_xor(uint8_t *rand, + uint8_t *autn_enb, + uint16_t mcc, + uint16_t mnc, + bool *net_valid, + uint8_t *res) +{ + uint32_t i; + uint8_t sqn[6]; + uint8_t xdout[16]; + uint8_t cdout[8]; + + *net_valid = true; + + // Use RAND and K to compute RES, CK, IK and AK + for(i=0; i<16; i++) { + xdout[i] = k[i]^rand[i]; + } + for(i=0; i<16; i++) { + res[i] = xdout[i]; + ck[i] = xdout[(i+1)%16]; + ik[i] = xdout[(i+2)%16]; + } + for(i=0; i<6; i++) { + ak[i] = xdout[i+3]; + } + + // Extract sqn from autn + for(i=0;i<6;i++) { + sqn[i] = autn_enb[i] ^ ak[i]; + } + + // Generate cdout + for(i=0; i<6; i++) { + cdout[i] = sqn[i]; + } + for(i=0; i<2; i++) { + cdout[6+i] = amf[i]; + } + + // Generate MAC + for(i=0;i<8;i++) { + mac[i] = xdout[i] ^ cdout[i]; + } + + // Construct AUTN + for(i=0; i<6; i++) + { + autn[i] = sqn[i] ^ ak[i]; + } + for(i=0; i<2; i++) + { + autn[6+i] = amf[i]; + } + for(i=0; i<8; i++) + { + autn[8+i] = mac[i]; + } + + // Compare AUTNs + for(i=0; i<16; i++) + { + if(autn[i] != autn_enb[i]) + { + *net_valid = false; + } + } + + // Generate K_asme + security_generate_k_asme( ck, + ik, + ak, + sqn, + mcc, + mnc, + k_asme); +} + +void usim::str_to_hex(std::string str, uint8_t *hex) +{ + uint32_t i; + const char *h_str = str.c_str(); + uint32_t len = str.length(); + + for(i=0; i= '0' && h_str[i*2+0] <= '9') + { + hex[i] = ( h_str[i*2+0] - '0') << 4; + }else if( h_str[i*2+0] >= 'A' && h_str[i*2+0] <= 'F'){ + hex[i] = (( h_str[i*2+0] - 'A') + 0xA) << 4; + }else{ + hex[i] = (( h_str[i*2+0] - 'a') + 0xA) << 4; + } + + if( h_str[i*2+1] >= '0' && h_str[i*2+1] <= '9') + { + hex[i] |= h_str[i*2+1] - '0'; + }else if( h_str[i*2+1] >= 'A' && h_str[i*2+1] <= 'F'){ + hex[i] |= ( h_str[i*2+1] - 'A') + 0xA; + }else{ + hex[i] |= ( h_str[i*2+1] - 'a') + 0xA; + } + } +} + +} // namespace srsue diff --git a/srsue/test/CMakeLists.txt b/srsue/test/CMakeLists.txt new file mode 100644 index 000000000..c9949a7e2 --- /dev/null +++ b/srsue/test/CMakeLists.txt @@ -0,0 +1,23 @@ +# +# Copyright 2013-2017 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/. +# + +add_subdirectory(phy) +add_subdirectory(mac) +add_subdirectory(upper) diff --git a/srsue/test/mac/CMakeLists.txt b/srsue/test/mac/CMakeLists.txt new file mode 100644 index 000000000..03407ce07 --- /dev/null +++ b/srsue/test/mac/CMakeLists.txt @@ -0,0 +1,23 @@ +# +# Copyright 2013-2017 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/. +# +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-switch") +add_executable(mac_test mac_test.cc) +target_link_libraries(mac_test srsue_mac srsue_phy srslte_common srslte_phy srslte_radio srslte_asn1 ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) + diff --git a/srsue/test/mac/mac_test.cc b/srsue/test/mac/mac_test.cc new file mode 100644 index 000000000..7c7e19cf0 --- /dev/null +++ b/srsue/test/mac/mac_test.cc @@ -0,0 +1,497 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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 +#include + +#include "srslte/asn1/liblte_rrc.h" +#include "srslte/radio/radio_multi.h" +#include "phy/phy.h" +#include "srslte/interfaces/ue_interfaces.h" +#include "srslte/common/log_stdout.h" +#include "mac/mac.h" +#include "srslte/common/mac_pcap.h" + + + +/********************************************************************** + * Program arguments processing + ***********************************************************************/ +typedef struct { + float rf_rx_freq; + float rf_tx_freq; + float rf_rx_gain; + float rf_tx_gain; + int verbose; + bool do_trace; + bool do_pcap; +}prog_args_t; + +void args_default(prog_args_t *args) { + args->rf_rx_freq = -1.0; + args->rf_tx_freq = -1.0; + args->rf_rx_gain = -1; // set to autogain + args->rf_tx_gain = -1; + args->verbose = 0; + args->do_trace = false; + args->do_pcap = false; +} + +void usage(prog_args_t *args, char *prog) { + printf("Usage: %s [gGtpv] -f rx_frequency (in Hz) -F tx_frequency (in Hz)\n", prog); + printf("\t-g RF RX gain [Default AGC]\n"); + printf("\t-G RF TX gain [Default same as RX gain (AGC)]\n"); + printf("\t-t Enable trace [Default disabled]\n"); + printf("\t-p Enable PCAP capture [Default disabled]\n"); + printf("\t-v [increase verbosity, default none]\n"); +} + +void parse_args(prog_args_t *args, int argc, char **argv) { + int opt; + args_default(args); + while ((opt = getopt(argc, argv, "gGftpFv")) != -1) { + switch (opt) { + case 'g': + args->rf_rx_gain = atof(argv[optind]); + break; + case 'G': + args->rf_tx_gain = atof(argv[optind]); + break; + case 'f': + args->rf_rx_freq = atof(argv[optind]); + break; + case 'F': + args->rf_tx_freq = atof(argv[optind]); + break; + case 't': + args->do_trace = true; + break; + case 'p': + args->do_pcap = true; + break; + case 'v': + args->verbose++; + break; + default: + usage(args, argv[0]); + exit(-1); + } + } + if (args->rf_rx_freq < 0 || args->rf_tx_freq < 0) { + usage(args, argv[0]); + exit(-1); + } +} + +// Determine SI messages scheduling as in 36.331 5.2.3 Acquisition of an SI message +uint32_t sib_start_tti(uint32_t tti, uint32_t period, uint32_t x) { + return (period*10*(1+tti/(period*10))+x)%10240; // the 1 means next opportunity +} + +void setup_mac_phy_sib2(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT *sib2, srsue::mac *mac, srsue::phy *phy) { + + // Apply RACH configuration + srsue::mac_interface_rrc::mac_cfg_t mac_cfg; + mac->get_config(&mac_cfg); + memcpy(&mac_cfg.rach, &sib2->rr_config_common_sib.rach_cnfg, sizeof(LIBLTE_RRC_RACH_CONFIG_COMMON_STRUCT)); + mac->set_config(&mac_cfg); + + printf("Set RACH ConfigCommon: NofPreambles=%d, ResponseWindow=%d, ContentionResolutionTimer=%d ms, MaxTrials=%d\n", + liblte_rrc_number_of_ra_preambles_num[sib2->rr_config_common_sib.rach_cnfg.num_ra_preambles], + liblte_rrc_ra_response_window_size_num[sib2->rr_config_common_sib.rach_cnfg.ra_resp_win_size], + liblte_rrc_mac_contention_resolution_timer_num[sib2->rr_config_common_sib.rach_cnfg.mac_con_res_timer], + liblte_rrc_preamble_trans_max_num[sib2->rr_config_common_sib.rach_cnfg.preamble_trans_max]); + + // Apply PHY RR Config Common + srsue::phy_interface_rrc::phy_cfg_common_t common; + memcpy(&common.pdsch_cnfg, &sib2->rr_config_common_sib.pdsch_cnfg, sizeof(LIBLTE_RRC_PDSCH_CONFIG_COMMON_STRUCT)); + memcpy(&common.pusch_cnfg, &sib2->rr_config_common_sib.pusch_cnfg, sizeof(LIBLTE_RRC_PUSCH_CONFIG_COMMON_STRUCT)); + memcpy(&common.pucch_cnfg, &sib2->rr_config_common_sib.pucch_cnfg, sizeof(LIBLTE_RRC_PUCCH_CONFIG_COMMON_STRUCT)); + memcpy(&common.ul_pwr_ctrl, &sib2->rr_config_common_sib.ul_pwr_ctrl, sizeof(LIBLTE_RRC_UL_POWER_CONTROL_COMMON_STRUCT)); + memcpy(&common.prach_cnfg, &sib2->rr_config_common_sib.prach_cnfg, sizeof(LIBLTE_RRC_PRACH_CONFIG_STRUCT)); + if (sib2->rr_config_common_sib.srs_ul_cnfg.present) { + memcpy(&common.srs_ul_cnfg, &sib2->rr_config_common_sib.srs_ul_cnfg, sizeof(LIBLTE_RRC_SRS_UL_CONFIG_COMMON_STRUCT)); + } else { + // default is release + common.srs_ul_cnfg.present = false; + } + phy->set_config_common(&common); + phy->configure_ul_params(); + + printf("Set PUSCH ConfigCommon: HopOffset=%d, RSGroup=%d, RSNcs=%d, N_sb=%d\n", + sib2->rr_config_common_sib.pusch_cnfg.pusch_hopping_offset, + sib2->rr_config_common_sib.pusch_cnfg.ul_rs.group_assignment_pusch, + sib2->rr_config_common_sib.pusch_cnfg.ul_rs.cyclic_shift, + sib2->rr_config_common_sib.pusch_cnfg.n_sb); + + printf("Set PUCCH ConfigCommon: DeltaShift=%d, CyclicShift=%d, N1=%d, NRB=%d\n", + liblte_rrc_delta_pucch_shift_num[sib2->rr_config_common_sib.pucch_cnfg.delta_pucch_shift], + sib2->rr_config_common_sib.pucch_cnfg.n_cs_an, + sib2->rr_config_common_sib.pucch_cnfg.n1_pucch_an, + sib2->rr_config_common_sib.pucch_cnfg.n_rb_cqi); + + printf("Set PRACH ConfigCommon: SeqIdx=%d, HS=%d, FreqOffset=%d, ZC=%d, ConfigIndex=%d\n", + sib2->rr_config_common_sib.prach_cnfg.root_sequence_index, + sib2->rr_config_common_sib.prach_cnfg.prach_cnfg_info.high_speed_flag?1:0, + sib2->rr_config_common_sib.prach_cnfg.prach_cnfg_info.prach_freq_offset, + sib2->rr_config_common_sib.prach_cnfg.prach_cnfg_info.zero_correlation_zone_config, + sib2->rr_config_common_sib.prach_cnfg.prach_cnfg_info.prach_config_index); + + printf("Set SRS ConfigCommon: BW-Configuration=%d, SF-Configuration=%d, ACKNACK=%d\n", + sib2->rr_config_common_sib.srs_ul_cnfg.bw_cnfg, + sib2->rr_config_common_sib.srs_ul_cnfg.subfr_cnfg, + sib2->rr_config_common_sib.srs_ul_cnfg.ack_nack_simul_tx); + +} + +void process_connsetup(LIBLTE_RRC_CONNECTION_SETUP_STRUCT *msg, srsue::mac *mac, srsue::phy *phy) { + + // FIXME: There's an error parsing the connectionSetup message. This value is hard-coded: + + if (msg->rr_cnfg.phy_cnfg_ded_present) { + phy->set_config_dedicated(&msg->rr_cnfg.phy_cnfg_ded); + } + printf("Set PHY configuration: SR-n_pucch=%d, SR-ConfigIndex=%d, SRS-ConfigIndex=%d, SRS-bw=%d, SRS-Nrcc=%d, SRS-hop=%d, SRS-Ncs=%d\n", + msg->rr_cnfg.phy_cnfg_ded.sched_request_cnfg.sr_pucch_resource_idx, + msg->rr_cnfg.phy_cnfg_ded.sched_request_cnfg.sr_cnfg_idx, + msg->rr_cnfg.phy_cnfg_ded.srs_ul_cnfg_ded.srs_cnfg_idx, + msg->rr_cnfg.phy_cnfg_ded.srs_ul_cnfg_ded.srs_bandwidth, + msg->rr_cnfg.phy_cnfg_ded.srs_ul_cnfg_ded.freq_domain_pos, + msg->rr_cnfg.phy_cnfg_ded.srs_ul_cnfg_ded.srs_hopping_bandwidth, + msg->rr_cnfg.phy_cnfg_ded.srs_ul_cnfg_ded.cyclic_shift); + + srsue::mac_interface_rrc::mac_cfg_t mac_set; + mac->get_config(&mac_set); + memcpy(&mac_set.main, &msg->rr_cnfg.mac_main_cnfg, sizeof(LIBLTE_RRC_MAC_MAIN_CONFIG_STRUCT)); + // SR is a PHY config but is needed by SR procedure in 36.321 5.4.4 + memcpy(&mac_set.sr, &msg->rr_cnfg.phy_cnfg_ded.sched_request_cnfg, sizeof(LIBLTE_RRC_SCHEDULING_REQUEST_CONFIG_STRUCT)); + mac->set_config(&mac_set); + + printf("Set MAC configuration: dsr-TransMAX: %d, harq-MaxReTX=%d, bsr-TimerReTX=%d, bsr-TimerPeriodic=%d\n", + liblte_rrc_dsr_trans_max_num[msg->rr_cnfg.phy_cnfg_ded.sched_request_cnfg.dsr_trans_max], + liblte_rrc_max_harq_tx_num[msg->rr_cnfg.mac_main_cnfg.explicit_value.ulsch_cnfg.max_harq_tx], + liblte_rrc_retransmission_bsr_timer_num[msg->rr_cnfg.mac_main_cnfg.explicit_value.ulsch_cnfg.retx_bsr_timer], + liblte_rrc_periodic_bsr_timer_num[msg->rr_cnfg.mac_main_cnfg.explicit_value.ulsch_cnfg.periodic_bsr_timer]); + + phy->configure_ul_params(); + + // Setup radio bearers + for (uint32_t i=0;irr_cnfg.srb_to_add_mod_list_size;i++) { + if (msg->rr_cnfg.srb_to_add_mod_list[i].lc_default_cnfg_present) { + printf("Setting up Default Configuration for SRB%d \n", msg->rr_cnfg.srb_to_add_mod_list[i].srb_id); + switch(msg->rr_cnfg.srb_to_add_mod_list[i].srb_id) { + case 1: + mac->setup_lcid(1, 0, 1, -1, -1); + break; + case 2: + mac->setup_lcid(2, 0, 3, -1, -1); + break; + } + } + } +// for (int i=0;irr_cnfg.drb_to_add_mod_list_size;i++) { +// printf("Setting up DRB%d\n", msg->rr_cnfg.drb_to_add_mod_list[i].drb_id); +// // todo +// } +} + + +// Hex bytes for the connection setup complete packet +// Got hex bytes from http://www.sharetechnote.com/html/RACH_LTE.html +uint8_t setupComplete_segm[2][41] ={ { + 0x88, 0x00, 0x00, 0x20, 0x21, 0x90, 0xa0, 0x12, 0x00, 0x00, 0x80, 0xf0, 0x5e, 0x3b, 0xf1, 0x04, + 0x64, 0x04, 0x1d, 0x20, 0x44, 0x2f, 0xd8, 0x4b, 0xd1, 0x02, 0x00, 0x00, 0x83, 0x03, 0x41, 0xb0, + 0xe5, 0x60, 0x13, 0x81, 0x83}, + + {0xb0, 0x01, 0x01, 0x01, 0x48, 0x4b, 0xd1, 0x00, 0x7d, 0x21, 0x70, 0x28, 0x01, 0x5c, 0x08, 0x80, + 0x00, 0xc4, 0x0f, 0x97, 0x80, 0xd0, 0x4c, 0x4b, 0xd1, 0x00, 0xc0, 0x58, 0x44, 0x0d, 0x5d, 0x62, + 0x99, 0x74, 0x04, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00} +}; +uint8_t setupComplete[80] = { + 0x88, 0x00, 0x00, 0x20, 0x21, 0x90, 0xa0, 0x12, 0x00, 0x00, 0x80, 0xf0, 0x5e, 0x3b, 0xf1, 0x04, + 0x64, 0x04, 0x1d, 0x20, 0x44, 0x2f, 0xd8, 0x4b, 0xd1, 0x02, 0x00, 0x00, 0x83, 0x03, 0x41, 0xb0, + 0xe5, 0x60, 0x13, 0x81, 0x83, 0x48, 0x4b, 0xd1, 0x00, 0x7d, 0x21, 0x70, 0x28, 0x01, 0x5c, 0x08, 0x80, + 0x00, 0xc4, 0x0f, 0x97, 0x80, 0xd0, 0x4c, 0x4b, 0xd1, 0x00, 0xc0, 0x58, 0x44, 0x0d, 0x5d, 0x62, + 0x99, 0x74, 0x04, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00}; + +uint32_t lengths[2] = {37, 41}; +uint8_t reply[2] = {0x00, 0x04}; + + +srslte::radio_multi radio; +srsue::phy phy; +srsue::mac mac; +srslte::mac_pcap mac_pcap; + +prog_args_t prog_args; + +void sig_int_handler(int signo) +{ + if (prog_args.do_trace) { + //radio.write_trace("radio"); + phy.write_trace("phy"); + } + if (prog_args.do_pcap) { + mac_pcap.close(); + } + mac.stop(); + exit(0); +} + +class rlctest : public srsue::rlc_interface_mac { +public: + bool mib_decoded; + bool sib1_decoded; + bool sib2_decoded; + bool connsetup_decoded; + int nsegm_dcch; + int send_ack; + uint8_t si_window_len, sib2_period; + + rlctest() { + mib_decoded = false; + sib1_decoded = false; + sib2_decoded = false; + connsetup_decoded = false; + nsegm_dcch = 0; + si_window_len = 0; + sib2_period = 0; + send_ack = 0; + } + uint32_t get_total_buffer_state(uint32_t lcid) { + return get_buffer_state(lcid); + } + uint32_t get_buffer_state(uint32_t lcid) { + if (lcid == 0) { + if (sib2_decoded && !connsetup_decoded) { + return 6; + } + } else if (lcid == 1) { + if (connsetup_decoded && nsegm_dcch < 2) { + return lengths[nsegm_dcch]; + } else if (send_ack == 1) { + return 2; + } + } + return 0; + } + + int read_pdu(uint32_t lcid, uint8_t *payload, uint32_t nof_bytes) + { + if (lcid == 0) { + LIBLTE_RRC_UL_CCCH_MSG_STRUCT ul_ccch_msg; + // Prepare ConnectionRequest packet + ul_ccch_msg.msg_type = LIBLTE_RRC_UL_CCCH_MSG_TYPE_RRC_CON_REQ; + ul_ccch_msg.msg.rrc_con_req.ue_id_type = LIBLTE_RRC_CON_REQ_UE_ID_TYPE_RANDOM_VALUE; + ul_ccch_msg.msg.rrc_con_req.ue_id.random = 1000; + ul_ccch_msg.msg.rrc_con_req.cause = LIBLTE_RRC_CON_REQ_EST_CAUSE_MO_SIGNALLING; + liblte_rrc_pack_ul_ccch_msg(&ul_ccch_msg, &bit_msg); + + uint64_t uecri=0; + uint8_t *ue_cri_ptr = (uint8_t*) &uecri; + uint32_t nbytes = bit_msg.N_bits/8; + uint8_t *ptr = bit_msg.msg; + for (uint32_t i=0;i= 80) { + printf("Sending Connection Setup Complete length 80\n"); + memcpy(payload, setupComplete, 80); + return 80; + } else { + uint32_t r = 0; + if (nof_bytes >= lengths[nsegm_dcch]) { + printf("Sending Connection Setup Complete %d/2 length %d\n", nsegm_dcch, lengths[nsegm_dcch]); + memcpy(payload, setupComplete_segm[nsegm_dcch], lengths[nsegm_dcch]); + r = lengths[nsegm_dcch]; + nsegm_dcch++; + } else { + r = 0; + } + return r; + } + } else if (send_ack == 1) { + printf("Send RLC ACK\n"); + memcpy(payload, reply, 2*sizeof(uint8_t)); + send_ack = 2; + return 2; + } + } + return 0; + } + + void write_pdu(uint32_t lcid, uint8_t *payload, uint32_t nof_bytes) { + if (lcid == 0) { + LIBLTE_RRC_DL_CCCH_MSG_STRUCT dl_ccch_msg; + printf("ConnSetup received %d bytes\n", nof_bytes); + srslte_vec_fprint_byte(stdout, payload, nof_bytes); + srslte_bit_unpack_vector(payload, bit_msg.msg, nof_bytes*8); + bit_msg.N_bits = nof_bytes*8; + liblte_rrc_unpack_dl_ccch_msg(&bit_msg, &dl_ccch_msg); + printf("Response: %s\n", liblte_rrc_dl_ccch_msg_type_text[dl_ccch_msg.msg_type]); + switch (dl_ccch_msg.msg_type) { + case LIBLTE_RRC_DL_CCCH_MSG_TYPE_RRC_CON_SETUP: + // Process ConnectionSetup + process_connsetup(&dl_ccch_msg.msg.rrc_con_setup, &mac, &phy); + connsetup_decoded = true; + break; + case LIBLTE_RRC_DL_CCCH_MSG_TYPE_RRC_CON_REJ: + case LIBLTE_RRC_DL_CCCH_MSG_TYPE_RRC_CON_REEST: + case LIBLTE_RRC_DL_CCCH_MSG_TYPE_RRC_CON_REEST_REJ: + break; + } + } else if (lcid == 1) { + printf("Received on DCCH0 %d bytes\n", nof_bytes); + if (send_ack == 0) { + send_ack = 1; + } + } + } + + void write_pdu_bcch_bch(uint8_t *payload, uint32_t nof_bytes) + { + LIBLTE_RRC_MIB_STRUCT mib; + srslte_vec_fprint_byte(stdout, payload, nof_bytes); + srslte_bit_unpack_vector(payload, bit_msg.msg, nof_bytes*8); + bit_msg.N_bits = nof_bytes*8; + liblte_rrc_unpack_bcch_bch_msg(&bit_msg, &mib); + printf("MIB received %d bytes, BW=%s MHz\n", nof_bytes, liblte_rrc_dl_bandwidth_text[mib.dl_bw]); + mib_decoded = true; + } + + void write_pdu_bcch_dlsch(uint8_t *payload, uint32_t nof_bytes) + { + LIBLTE_RRC_BCCH_DLSCH_MSG_STRUCT dlsch_msg; + srslte_bit_unpack_vector(payload, bit_msg.msg, nof_bytes*8); + bit_msg.N_bits = nof_bytes*8; + liblte_rrc_unpack_bcch_dlsch_msg(&bit_msg, &dlsch_msg); + if (dlsch_msg.N_sibs > 0) { + if (dlsch_msg.sibs[0].sib_type == LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1 && !sib1_decoded) { + si_window_len = liblte_rrc_si_window_length_num[dlsch_msg.sibs[0].sib.sib1.si_window_length]; + sib2_period = liblte_rrc_si_periodicity_num[dlsch_msg.sibs[0].sib.sib1.sched_info[0].si_periodicity]; + printf("SIB1 received %d bytes, CellID=%d, si_window=%d, sib2_period=%d\n", + nof_bytes, dlsch_msg.sibs[0].sib.sib1.cell_id&0xfff, si_window_len, sib2_period); + sib1_decoded = true; + mac.bcch_stop_rx(); + } else if (dlsch_msg.sibs[0].sib_type == LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2) { + + printf("SIB2 received %d bytes\n", nof_bytes); + setup_mac_phy_sib2(&dlsch_msg.sibs[0].sib.sib2, &mac, &phy); + sib2_decoded = true; + mac.bcch_stop_rx(); + } + } + } + + void write_pdu_pcch(uint8_t *payload, uint32_t nof_bytes) {} + +private: + LIBLTE_BIT_MSG_STRUCT bit_msg; + LIBLTE_BYTE_MSG_STRUCT byte_msg; +}; + + +int main(int argc, char *argv[]) +{ + srslte::log_stdout mac_log("MAC"), phy_log("PHY"); + rlctest my_rlc; + parse_args(&prog_args, argc, argv); + + switch (prog_args.verbose) { + case 1: + mac_log.set_level(srslte::LOG_LEVEL_INFO); + phy_log.set_level(srslte::LOG_LEVEL_INFO); + break; + case 2: + mac_log.set_level(srslte::LOG_LEVEL_DEBUG); + phy_log.set_level(srslte::LOG_LEVEL_DEBUG); + break; + } + + // Capture SIGINT to write traces + if (prog_args.do_trace) { + signal(SIGINT, sig_int_handler); + //radio.start_trace(); + phy.start_trace(); + } + + if (prog_args.do_pcap) { + if (!prog_args.do_trace) { + signal(SIGINT, sig_int_handler); + } + mac_pcap.open("/tmp/ue_mac.pcap"); + mac.start_pcap(&mac_pcap); + } + + // Init Radio and PHY + radio.init(); + phy.init(&radio, &mac, NULL, &phy_log); + if (prog_args.rf_rx_gain > 0 && prog_args.rf_tx_gain > 0) { + radio.set_rx_gain(prog_args.rf_rx_gain); + radio.set_tx_gain(prog_args.rf_tx_gain); + } else { + radio.start_agc(false); + radio.set_tx_rx_gain_offset(10); + phy.set_agc_enable(true); + } + // Init MAC + mac.init(&phy, &my_rlc, NULL, &mac_log); + + // Set RX freq + radio.set_rx_freq(prog_args.rf_rx_freq); + radio.set_tx_freq(prog_args.rf_tx_freq); + + + while(1) { + uint32_t tti; + if (my_rlc.mib_decoded && mac.get_current_tti()) { + if (!my_rlc.sib1_decoded) { + usleep(10000); + tti = mac.get_current_tti(); + mac.bcch_start_rx(sib_start_tti(tti, 2, 5), 1); + } else if (!my_rlc.sib2_decoded) { + usleep(10000); + tti = mac.get_current_tti(); + mac.bcch_start_rx(sib_start_tti(tti, my_rlc.sib2_period, 0), my_rlc.si_window_len); + } + } + usleep(50000); + } +} + + + diff --git a/srsue/test/phy/CMakeLists.txt b/srsue/test/phy/CMakeLists.txt new file mode 100644 index 000000000..bb463efb0 --- /dev/null +++ b/srsue/test/phy/CMakeLists.txt @@ -0,0 +1,25 @@ +# +# Copyright 2013-2017 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/. +# + +add_executable(ue_itf_test_sib1 ue_itf_test_sib1.cc) +target_link_libraries(ue_itf_test_sib1 srsue_phy srslte_common srslte_phy srslte_radio ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) + +add_executable(ue_itf_test_prach ue_itf_test_prach.cc) +target_link_libraries(ue_itf_test_prach srsue_phy srslte_common srslte_phy srslte_radio ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) diff --git a/srsue/test/phy/ue_itf_test_prach.cc b/srsue/test/phy/ue_itf_test_prach.cc new file mode 100644 index 000000000..91df6a2fc --- /dev/null +++ b/srsue/test/phy/ue_itf_test_prach.cc @@ -0,0 +1,388 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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 + +#include "srslte/phy/utils/debug.h" +#include "phy/phy.h" +#include "srslte/interfaces/ue_interfaces.h" +#include "srslte/common/log_stdout.h" +#include "srslte/radio/radio_multi.h" + +/********************************************************************** + * Program arguments processing + ***********************************************************************/ +typedef struct { + float rf_rx_freq; + float rf_tx_freq; + float rf_rx_gain; + float rf_tx_gain; + bool continous; +}prog_args_t; + +prog_args_t prog_args; +uint32_t srsapps_verbose = 0; + +void args_default(prog_args_t *args) { + args->rf_rx_freq = -1.0; + args->rf_tx_freq = -1.0; + args->rf_rx_gain = -1; // set to autogain + args->rf_tx_gain = -1; + args->continous = false; +} + +void usage(prog_args_t *args, char *prog) { + printf("Usage: %s [gGcv] -f rx_frequency -F tx_frequency (in Hz)\n", prog); + printf("\t-g RF RX gain [Default AGC]\n"); + printf("\t-G RF TX gain [Default same as RX gain (AGC)]\n"); + printf("\t-c Run continuously [Default only once]\n"); + printf("\t-v [increase verbosity, default none]\n"); +} + +void parse_args(prog_args_t *args, int argc, char **argv) { + int opt; + args_default(args); + while ((opt = getopt(argc, argv, "gGfFcv")) != -1) { + switch (opt) { + case 'g': + args->rf_rx_gain = atof(argv[optind]); + break; + case 'G': + args->rf_tx_gain = atof(argv[optind]); + break; + case 'f': + args->rf_rx_freq = atof(argv[optind]); + break; + case 'F': + args->rf_tx_freq = atof(argv[optind]); + break; + case 'c': + args->continous = true; + break; + case 'v': + srsapps_verbose++; + break; + default: + usage(args, argv[0]); + exit(-1); + } + } + if (args->rf_rx_freq < 0 || args->rf_tx_freq < 0) { + usage(args, argv[0]); + exit(-1); + } +} + + + +typedef enum{ + rar_header_type_bi = 0, + rar_header_type_rapid, + rar_header_type_n_items, +}rar_header_t; +static const char rar_header_text[rar_header_type_n_items][8] = {"BI", "RAPID"}; + +typedef struct { + rar_header_t hdr_type; + bool hopping_flag; + uint32_t tpc_command; + bool ul_delay; + bool csi_req; + uint16_t rba; + uint16_t timing_adv_cmd; + uint16_t temp_c_rnti; + uint8_t mcs; + uint8_t RAPID; + uint8_t BI; +}rar_msg_t; + + +int rar_unpack(uint8_t *buffer, rar_msg_t *msg) +{ + int ret = SRSLTE_ERROR; + uint8_t *ptr = buffer; + + if(buffer != NULL && + msg != NULL) + { + ptr++; + msg->hdr_type = (rar_header_t) *ptr++; + if(msg->hdr_type == rar_header_type_bi) { + ptr += 2; + msg->BI = srslte_bit_pack(&ptr, 4); + ret = SRSLTE_SUCCESS; + } else if (msg->hdr_type == rar_header_type_rapid) { + msg->RAPID = srslte_bit_pack(&ptr, 6); + ptr++; + + msg->timing_adv_cmd = srslte_bit_pack(&ptr, 11); + msg->hopping_flag = *ptr++; + msg->rba = srslte_bit_pack(&ptr, 10); + msg->mcs = srslte_bit_pack(&ptr, 4); + msg->tpc_command = srslte_bit_pack(&ptr, 3); + msg->ul_delay = *ptr++; + msg->csi_req = *ptr++; + msg->temp_c_rnti = srslte_bit_pack(&ptr, 16); + ret = SRSLTE_SUCCESS; + } + } + + return(ret); +} + + + +srsue::phy my_phy; +bool bch_decoded = false; + +uint8_t payload[10240]; +uint8_t payload_bits[10240]; +const uint8_t conn_request_msg[] = {0x20, 0x06, 0x1F, 0x5C, 0x2C, 0x04, 0xB2, 0xAC, 0xF6, 0x00, 0x00, 0x00}; + +enum mac_state {RA, RAR, CONNREQUEST, CONNSETUP} state = RA; + +uint32_t preamble_idx = 0; +rar_msg_t rar_msg; + +uint32_t nof_rtx_connsetup = 0; +uint32_t rv_value[4] = {0, 2, 3, 1}; + +void config_phy() { + srsue::phy_interface_rrc::phy_cfg_t config; + + config.common.prach_cnfg.prach_cnfg_info.prach_config_index = 0; + config.common.prach_cnfg.prach_cnfg_info.prach_freq_offset = 0; + config.common.prach_cnfg.prach_cnfg_info.high_speed_flag = false; + config.common.prach_cnfg.root_sequence_index = 0; + config.common.prach_cnfg.prach_cnfg_info.zero_correlation_zone_config = 11; + + config.common.pusch_cnfg.ul_rs.group_hopping_enabled = false; + config.common.pusch_cnfg.ul_rs.sequence_hopping_enabled = false; + config.common.pusch_cnfg.n_sb = 2; + config.common.pusch_cnfg.ul_rs.cyclic_shift = 0; + config.common.pusch_cnfg.ul_rs.group_assignment_pusch = 0; + config.common.pusch_cnfg.pusch_hopping_offset = 0; + + config.common.pucch_cnfg.delta_pucch_shift = LIBLTE_RRC_DELTA_PUCCH_SHIFT_DS2; + config.common.pucch_cnfg.n_cs_an = 0; + config.common.pucch_cnfg.n1_pucch_an = 1; + + my_phy.configure_ul_params(); + my_phy.configure_prach_params(); +} + +srslte_softbuffer_rx_t softbuffer_rx; +srslte_softbuffer_tx_t softbuffer_tx; + +uint16_t temp_c_rnti; + +/******** MAC Interface implementation */ +class testmac : public srsue::mac_interface_phy +{ +public: + + testmac() { + rar_rnti_set = false; + } + + bool rar_rnti_set; + + void pch_decoded_ok(uint32_t len) {} + + + void tti_clock(uint32_t tti) { + if (!rar_rnti_set) { + int prach_tti = my_phy.prach_tx_tti(); + if (prach_tti > 0) { + my_phy.pdcch_dl_search(SRSLTE_RNTI_RAR, 1+prach_tti%10, prach_tti+3, prach_tti+13); + rar_rnti_set = true; + } + } + } + + void new_grant_ul(mac_grant_t grant, tb_action_ul_t *action) { + printf("New grant UL\n"); + memcpy(payload, conn_request_msg, grant.n_bytes*sizeof(uint8_t)); + action->current_tx_nb = nof_rtx_connsetup; + action->rv = rv_value[nof_rtx_connsetup%4]; + action->softbuffer = &softbuffer_tx; + action->rnti = temp_c_rnti; + action->expect_ack = (nof_rtx_connsetup < 5)?true:false; + action->payload_ptr = payload; + memcpy(&action->phy_grant, &grant.phy_grant, sizeof(srslte_phy_grant_t)); + memcpy(&last_grant, &grant, sizeof(mac_grant_t)); + action->tx_enabled = true; + if (action->rv == 0) { + srslte_softbuffer_tx_reset(&softbuffer_tx); + } + my_phy.pdcch_dl_search(SRSLTE_RNTI_USER, temp_c_rnti); + } + + void new_grant_ul_ack(mac_grant_t grant, bool ack, tb_action_ul_t *action) { + printf("New grant UL ACK\n"); + } + + void harq_recv(uint32_t tti, bool ack, tb_action_ul_t *action) { + printf("harq recv hi=%d\n", ack?1:0); + if (!ack) { + nof_rtx_connsetup++; + action->current_tx_nb = nof_rtx_connsetup; + action->rv = rv_value[nof_rtx_connsetup%4]; + action->softbuffer = &softbuffer_tx; + action->rnti = temp_c_rnti; + action->expect_ack = true; + memcpy(&action->phy_grant, &last_grant.phy_grant, sizeof(srslte_phy_grant_t)); + action->tx_enabled = true; + if (action->rv == 0) { + srslte_softbuffer_tx_reset(&softbuffer_tx); + } + printf("Retransmission %d, rv=%d\n", nof_rtx_connsetup, action->rv); + } + } + + void new_grant_dl(mac_grant_t grant, tb_action_dl_t *action) { + action->decode_enabled = true; + action->default_ack = false; + if (grant.rnti == 2) { + action->generate_ack = false; + } else { + action->generate_ack = true; + } + action->payload_ptr = payload; + action->rnti = grant.rnti; + memcpy(&action->phy_grant, &grant.phy_grant, sizeof(srslte_phy_grant_t)); + memcpy(&last_grant, &grant, sizeof(mac_grant_t)); + action->rv = grant.rv; + action->softbuffer = &softbuffer_rx; + + if (action->rv == 0) { + srslte_softbuffer_rx_reset(&softbuffer_rx); + } + } + + void tb_decoded(bool ack, srslte_rnti_type_t rnti_type, uint32_t harq_pid) { + if (ack) { + if (rnti_type == SRSLTE_RNTI_RAR) { + my_phy.pdcch_dl_search_reset(); + srslte_bit_unpack_vector(payload, payload_bits, last_grant.n_bytes*8); + rar_unpack(payload_bits, &rar_msg); + if (rar_msg.RAPID == preamble_idx) { + + printf("Received RAR at TTI: %d\n", last_grant.tti); + my_phy.set_timeadv_rar(rar_msg.timing_adv_cmd); + + temp_c_rnti = rar_msg.temp_c_rnti; + + if (last_grant.n_bytes*8 > 20 + SRSLTE_RAR_GRANT_LEN) { + uint8_t rar_grant[SRSLTE_RAR_GRANT_LEN]; + memcpy(rar_grant, &payload_bits[20], sizeof(uint8_t)*SRSLTE_RAR_GRANT_LEN); + my_phy.set_rar_grant(last_grant.tti, rar_grant); + } + } else { + printf("Received RAR RAPID=%d\n", rar_msg.RAPID); + } + } else { + printf("Received Connection Setup\n"); + my_phy.pdcch_dl_search_reset(); + } + } + } + + void bch_decoded_ok(uint8_t *payload, uint32_t len) { + printf("BCH decoded\n"); + bch_decoded = true; + srslte_cell_t cell; + my_phy.get_current_cell(&cell); + srslte_softbuffer_rx_init(&softbuffer_rx, cell.nof_prb); + srslte_softbuffer_tx_init(&softbuffer_tx, cell.nof_prb); + } + +private: + mac_grant_t last_grant; +}; + + +testmac my_mac; +srslte::radio_multi radio; + +int main(int argc, char *argv[]) +{ + srslte::log_stdout log("PHY"); + + parse_args(&prog_args, argc, argv); + + // Init Radio and PHY + radio.init(); + my_phy.init(&radio, &my_mac, NULL, &log); + if (prog_args.rf_rx_gain > 0 && prog_args.rf_tx_gain > 0) { + radio.set_rx_gain(prog_args.rf_rx_gain); + radio.set_tx_gain(prog_args.rf_tx_gain); + } else { + radio.start_agc(false); + radio.set_tx_rx_gain_offset(10); + my_phy.set_agc_enable(true); + } + + if (srsapps_verbose == 1) { + log.set_level(srslte::LOG_LEVEL_INFO); + printf("Log level info\n"); + } + if (srsapps_verbose == 2) { + log.set_level(srslte::LOG_LEVEL_DEBUG); + printf("Log level debug\n"); + } + + // Give it time to create thread + sleep(1); + + // Set RX freq + radio.set_rx_freq(prog_args.rf_rx_freq); + radio.set_tx_freq(prog_args.rf_tx_freq); + + // Instruct the PHY to configure PRACH parameters and sync to current cell + my_phy.sync_start(); + + while(!my_phy.status_is_sync()) { + usleep(20000); + } + + // Setup PHY parameters + config_phy(); + + /* Instruct PHY to send PRACH and prepare it for receiving RAR */ + my_phy.prach_send(preamble_idx); + + /* go to idle and process each tti */ + bool running = true; + while(running) { + sleep(1); + } + my_phy.stop(); + radio.stop_rx(); +} + + + diff --git a/srsue/test/phy/ue_itf_test_sib1.cc b/srsue/test/phy/ue_itf_test_sib1.cc new file mode 100644 index 000000000..08116b22c --- /dev/null +++ b/srsue/test/phy/ue_itf_test_sib1.cc @@ -0,0 +1,214 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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 + +#include "srslte/phy/utils/debug.h" +#include "phy/phy.h" +#include "srslte/common/log_stdout.h" +#include "srslte/interfaces/ue_interfaces.h" +#include "srslte/radio/radio_multi.h" + + +/********************************************************************** + * Program arguments processing + ***********************************************************************/ + +typedef struct { + float rf_freq; + float rf_gain; +}prog_args_t; + +uint32_t srsapps_verbose = 0; + +prog_args_t prog_args; + +void args_default(prog_args_t *args) { + args->rf_freq = -1.0; + args->rf_gain = -1.0; +} + +void usage(prog_args_t *args, char *prog) { + printf("Usage: %s [gv] -f rx_frequency (in Hz)\n", prog); + printf("\t-g RF RX gain [Default AGC]\n"); + printf("\t-v [increase verbosity, default none]\n"); +} + +void parse_args(prog_args_t *args, int argc, char **argv) { + int opt; + args_default(args); + while ((opt = getopt(argc, argv, "gfv")) != -1) { + switch (opt) { + case 'g': + args->rf_gain = atof(argv[optind]); + break; + case 'f': + args->rf_freq = atof(argv[optind]); + break; + case 'v': + srsapps_verbose++; + break; + default: + usage(args, argv[0]); + exit(-1); + } + } + if (args->rf_freq < 0) { + usage(args, argv[0]); + exit(-1); + } +} + +srsue::phy my_phy; +bool bch_decoded = false; +uint32_t total_pkts=0; +uint32_t total_dci=0; +uint32_t total_oks=0; +uint8_t payload[1024]; +srslte_softbuffer_rx_t softbuffer; + +/******** MAC Interface implementation */ +class testmac : public srsue::mac_interface_phy +{ +public: + void new_grant_ul(mac_grant_t grant, tb_action_ul_t *action) { + printf("New grant UL\n"); + } + void new_grant_ul_ack(mac_grant_t grant, bool ack, tb_action_ul_t *action) { + printf("New grant UL ACK\n"); + } + + void harq_recv(uint32_t tti, bool ack, tb_action_ul_t *action) { + printf("harq recv\n"); + } + + void new_grant_dl(mac_grant_t grant, tb_action_dl_t *action) { + total_dci++; + + + action->decode_enabled = true; + action->default_ack = false; + action->generate_ack = false; + action->payload_ptr = payload; + memcpy(&action->phy_grant, &grant.phy_grant, sizeof(srslte_phy_grant_t)); + action->rv = ((uint32_t) ceilf((float)3*((my_phy.tti_to_SFN(grant.tti)/2)%4)/2))%4; + action->softbuffer = &softbuffer; + action->rnti = grant.rnti; + if (action->rv == 0) { + srslte_softbuffer_rx_reset(&softbuffer); + } + } + + + + void tb_decoded(bool ack, srslte_rnti_type_t rnti, uint32_t harq_pid) { + if (ack) { + total_oks++; + } + } + + void pch_decoded_ok(uint32_t len) {} + + void bch_decoded_ok(uint8_t *payload, uint32_t len) { + printf("BCH decoded\n"); + bch_decoded = true; + srslte_cell_t cell; + my_phy.get_current_cell(&cell); + srslte_softbuffer_rx_init(&softbuffer, cell.nof_prb); + } + void tti_clock(uint32_t tti) { + + } +}; + + +testmac my_mac; +srslte::radio_multi radio; + + + + +int main(int argc, char *argv[]) +{ + srslte::log_stdout log("PHY"); + + parse_args(&prog_args, argc, argv); + + // Init Radio and PHY + radio.init(); + my_phy.init(&radio, &my_mac, NULL, &log); + if (prog_args.rf_gain > 0) { + radio.set_rx_gain(prog_args.rf_gain); + } else { + radio.start_agc(false); + my_phy.set_agc_enable(true); + } + + if (srsapps_verbose == 1) { + log.set_level(srslte::LOG_LEVEL_INFO); + printf("Log level info\n"); + } + if (srsapps_verbose == 2) { + log.set_level(srslte::LOG_LEVEL_DEBUG); + printf("Log level debug\n"); + } + + // Give it time to create thread + sleep(1); + + // Set RX freq and gain + radio.set_rx_freq(prog_args.rf_freq); + + my_phy.sync_start(); + + bool running = true; + while(running) { + if (bch_decoded && my_phy.status_is_sync()) { + uint32_t tti = my_phy.get_current_tti(); + + // SIB1 is scheduled in subframe #5 of even frames, try to decode next frame SIB1 + tti = (((tti/20)*20) + 25)%10240; + my_phy.pdcch_dl_search(SRSLTE_RNTI_SI, SRSLTE_SIRNTI, tti, tti+1); + + total_pkts++; + } + usleep(30000); + if (bch_decoded && my_phy.status_is_sync() && total_pkts > 0) { + if (srslte_verbose == SRSLTE_VERBOSE_NONE && srsapps_verbose == 0) { + float gain = prog_args.rf_gain; + if (gain < 0) { + gain = radio.get_rx_gain(); + } + printf("PDCCH BLER %.1f \%% PDSCH BLER %.1f \%% (total pkts: %5u) Gain: %.1f dB\r", + 100-(float) 100*total_dci/total_pkts, + (float) 100*(1 - total_oks/total_pkts), + total_pkts, gain); + } + } + } + my_phy.stop(); + radio.stop_rx(); +} diff --git a/srsue/test/upper/CMakeLists.txt b/srsue/test/upper/CMakeLists.txt new file mode 100644 index 000000000..324ae4913 --- /dev/null +++ b/srsue/test/upper/CMakeLists.txt @@ -0,0 +1,50 @@ +# +# Copyright 2013-2017 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/. +# + +# IP traffic over RLC test +add_executable(ip_test ip_test.cc) +target_link_libraries(ip_test srsue_mac + srsue_phy + srslte_common + srslte_phy + srslte_radio + srslte_upper + ${CMAKE_THREAD_LIBS_INIT} + ${Boost_LIBRARIES}) + +add_executable(usim_test usim_test.cc) +target_link_libraries(usim_test srsue_upper srslte_upper srslte_phy) +add_test(usim_test usim_test) + +add_executable(rrc_reconfig_test rrc_reconfig_test.cc) +target_link_libraries(rrc_reconfig_test srsue_upper srslte_upper srslte_phy) +add_test(rrc_reconfig_test rrc_reconfig_test) + + +######################################################################## +# Option to run command after build (useful for remote builds) +######################################################################## +if (NOT ${BUILD_CMD} STREQUAL "") + message(STATUS "Added custom post-build command: ${BUILD_CMD}") + add_custom_command(TARGET ip_test POST_BUILD COMMAND ${BUILD_CMD}) +else(NOT ${BUILD_CMD} STREQUAL "") + message(STATUS "No post-build command defined") +endif (NOT ${BUILD_CMD} STREQUAL "") + diff --git a/srsue/test/upper/ip_test.cc b/srsue/test/upper/ip_test.cc new file mode 100644 index 000000000..a26f273a8 --- /dev/null +++ b/srsue/test/upper/ip_test.cc @@ -0,0 +1,645 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "srslte/phy/utils/debug.h" +#include "mac/mac.h" +#include "phy/phy.h" +#include "srslte/common/threads.h" +#include "srslte/common/common.h" +#include "srslte/common/buffer_pool.h" +#include "srslte/common/logger.h" +#include "srslte/common/log_filter.h" +#include "srslte/upper/rlc.h" +#include "upper/rrc.h" +#include "srslte/radio/radio_multi.h" + +#define START_TUNTAP +#define USE_RADIO +#define PRINT_GW 0 + +/********************************************************************** + * Program arguments processing + ***********************************************************************/ + +#define LCID 3 + +typedef struct { + float rx_freq; + float tx_freq; + float rx_gain; + float tx_gain; + int time_adv; + std::string ip_address; +}prog_args_t; + +uint32_t srsapps_verbose = 1; + +prog_args_t prog_args; + +void args_default(prog_args_t *args) { + args->tx_freq = 2.505e9; + args->rx_freq = 2.625e9; + args->rx_gain = 50.0; + args->tx_gain = 70.0; + args->time_adv = -1; // calibrated for b210 + args->ip_address = "192.168.3.2"; +} + +void usage(prog_args_t *args, char *prog) { + printf("Usage: %s [gGIrfFtv]\n", prog); + printf("\t-f RX frequency [Default %.1f MHz]\n", args->rx_freq/1e6); + printf("\t-F TX frequency [Default %.1f MHz]\n", args->tx_freq/1e6); + printf("\t-g RX gain [Default %.1f]\n", args->rx_gain); + printf("\t-G TX gain [Default %.1f]\n", args->tx_gain); + printf("\t-I IP address [Default %s]\n", args->ip_address.c_str()); + printf("\t-t time advance (in samples) [Default %d]\n", args->time_adv); + printf("\t-v [increase verbosity, default none]\n"); +} + +void parse_args(prog_args_t *args, int argc, char **argv) { + int opt; + args_default(args); + while ((opt = getopt(argc, argv, "gGfFItv")) != -1) { + switch (opt) { + case 'g': + args->rx_gain = atof(argv[optind]); + break; + case 'G': + args->tx_gain = atof(argv[optind]); + break; + case 'f': + args->rx_freq = atof(argv[optind]); + break; + case 'F': + args->tx_freq = atof(argv[optind]); + break; + case 'I': + args->ip_address = argv[optind]; + break; + case 't': + args->time_adv = atoi(argv[optind]); + break; + case 'v': + srsapps_verbose++; + break; + default: + usage(args, argv[0]); + exit(-1); + } + } + if (args->rx_freq < 0 || args->tx_freq < 0) { + usage(args, argv[0]); + exit(-1); + } +} + +int setup_if_addr(char *ip_addr); + +// Define dummy RLC always transmitts +class tester : public srsue::pdcp_interface_rlc, + public srsue::rrc_interface_rlc, + public srsue::rrc_interface_phy, + public srsue::rrc_interface_mac, + public srsue::ue_interface, + public thread +{ +public: + + tester() { + state = srsue::RRC_STATE_SIB1_SEARCH; + read_enable = true; + } + + void init(srsue::phy *phy_, srsue::mac *mac_, srslte::rlc *rlc_, srslte::log *log_h_, std::string ip_address) { + log_h = log_h_; + rlc = rlc_; + mac = mac_; + phy = phy_; + +#ifdef START_TUNTAP + if (init_tuntap((char*) ip_address.c_str())) { + log_h->error("Initiating IP address\n"); + } +#endif + + pool = srslte::byte_buffer_pool::get_instance(); + + // Start reader thread + running=true; + start(); + + } + + + void sib_search() + { + bool searching = true; + uint32_t tti ; + uint32_t si_win_start, si_win_len; + uint16_t period; + uint32_t nof_sib1_trials = 0; + const int SIB1_SEARCH_TIMEOUT = 30; + + while(searching) + { + switch(state) + { + case srsue::RRC_STATE_SIB1_SEARCH: + // Instruct MAC to look for SIB1 + while(!phy->status_is_sync()){ + usleep(50000); + } + usleep(10000); + tti = mac->get_current_tti(); + si_win_start = sib_start_tti(tti, 2, 5); + mac->bcch_start_rx(si_win_start, 1); + log_h->info("Instructed MAC to search for SIB1, win_start=%d, win_len=%d\n", + si_win_start, 1); + nof_sib1_trials++; + if (nof_sib1_trials >= SIB1_SEARCH_TIMEOUT) { + log_h->info("Timeout while searching for SIB1. Resynchronizing SFN...\n"); + log_h->console("Timeout while searching for SIB1. Resynchronizing SFN...\n"); + phy->resync_sfn(); + nof_sib1_trials = 0; + } + break; + case srsue::RRC_STATE_SIB2_SEARCH: + // Instruct MAC to look for SIB2 + usleep(10000); + tti = mac->get_current_tti(); + period = liblte_rrc_si_periodicity_num[sib1.sched_info[0].si_periodicity]; + si_win_start = sib_start_tti(tti, period, 0); + si_win_len = liblte_rrc_si_window_length_num[sib1.si_window_length]; + + mac->bcch_start_rx(si_win_start, si_win_len); + log_h->info("Instructed MAC to search for SIB2, win_start=%d, win_len=%d\n", + si_win_start, si_win_len); + + break; + default: + searching = false; + break; + } + usleep(100000); + } + } + + bool is_sib_received() { + return state == srsue::RRC_STATE_WAIT_FOR_CON_SETUP; + } + + + void release_pucch_srs() {} + void ra_problem() {} + void write_pdu_bcch_bch(srslte::byte_buffer_t *pdu) {} + void write_pdu_bcch_dlsch(srslte::byte_buffer_t *pdu) + { + log_h->info_hex(pdu->msg, pdu->N_bytes, "BCCH DLSCH message received."); + log_h->info("BCCH DLSCH message Stack latency: %ld us\n", pdu->get_latency_us()); + LIBLTE_RRC_BCCH_DLSCH_MSG_STRUCT dlsch_msg; + srslte_bit_unpack_vector(pdu->msg, bit_buf.msg, pdu->N_bytes*8); + bit_buf.N_bits = pdu->N_bytes*8; + pool->deallocate(pdu); + liblte_rrc_unpack_bcch_dlsch_msg((LIBLTE_BIT_MSG_STRUCT*)&bit_buf, &dlsch_msg); + + if (dlsch_msg.N_sibs > 0) { + if (LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1 == dlsch_msg.sibs[0].sib_type && srsue::RRC_STATE_SIB1_SEARCH == state) { + // Handle SIB1 + memcpy(&sib1, &dlsch_msg.sibs[0].sib.sib1, sizeof(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1_STRUCT)); + log_h->info("SIB1 received, CellID=%d, si_window=%d, sib2_period=%d\n", + sib1.cell_id&0xfff, + liblte_rrc_si_window_length_num[sib1.si_window_length], + liblte_rrc_si_periodicity_num[sib1.sched_info[0].si_periodicity]); + std::stringstream ss; + for(uint32_t i=0;iconsole("SIB1 received, CellID=%d, %s\n", + sib1.cell_id&0xfff, + ss.str().c_str()); + + state = srsue::RRC_STATE_SIB2_SEARCH; + mac->bcch_stop_rx(); + //TODO: Use all SIB1 info + + } else if (LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2 == dlsch_msg.sibs[0].sib_type && srsue::RRC_STATE_SIB2_SEARCH == state) { + // Handle SIB2 + memcpy(&sib2, &dlsch_msg.sibs[0].sib.sib2, sizeof(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT)); + log_h->console("SIB2 received\n"); + log_h->info("SIB2 received\n"); + state = srsue::RRC_STATE_WAIT_FOR_CON_SETUP; + mac->bcch_stop_rx(); + apply_sib2_configs(); + + srslte::byte_buffer_t *sdu = pool_allocate; + assert(sdu); + + // Send Msg3 + sdu->N_bytes = 10; + for (uint32_t i=0;iN_bytes;i++) { + sdu->msg[i] = i+1; + } + uint64_t uecri = 0; + uint8_t *ue_cri_ptr = (uint8_t*) &uecri; + uint32_t nbytes = 6; + for (uint32_t i=0;imsg[i]; + } + log_h->info("Setting UE contention resolution ID: %d\n", uecri); + mac->set_contention_id(uecri); + + rlc->write_sdu(0, sdu); + + } + } + } + void write_pdu_pcch(srslte::byte_buffer_t *sdu) {} + void max_retx_attempted(){} + void in_sync() {}; + void out_of_sync() {}; + + void write_pdu(uint32_t lcid, srslte::byte_buffer_t *sdu) + { + uint32_t n=0; + switch(lcid) { + case LCID: + n = write(tun_fd, sdu->msg, sdu->N_bytes); + if (n != sdu->N_bytes) { + log_h->error("TUN/TAP write failure n=%d, nof_bytes=%d\n", n, sdu->N_bytes); + return; + } + log_h->debug_hex(sdu->msg, sdu->N_bytes, + "Wrote %d bytes to TUN/TAP\n", + sdu->N_bytes); + pool->deallocate(sdu); + break; + case 0: + log_h->info("Received ConnectionSetupComplete\n"); + + // Setup a single UM bearer + LIBLTE_RRC_RLC_CONFIG_STRUCT cfg; + bzero(&cfg, sizeof(LIBLTE_RRC_RLC_CONFIG_STRUCT)); + cfg.rlc_mode = LIBLTE_RRC_RLC_MODE_UM_BI; + cfg.dl_um_bi_rlc.t_reordering = LIBLTE_RRC_T_REORDERING_MS100; + cfg.dl_um_bi_rlc.sn_field_len = LIBLTE_RRC_SN_FIELD_LENGTH_SIZE10; + cfg.ul_um_bi_rlc.sn_field_len = LIBLTE_RRC_SN_FIELD_LENGTH_SIZE10; + rlc->add_bearer(LCID, &cfg); + + mac->setup_lcid(LCID, 0, 1, -1, 100000); + + LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT dedicated; + bzero(&dedicated, sizeof(LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT)); + dedicated.pusch_cnfg_ded.beta_offset_ack_idx = 5; + dedicated.pusch_cnfg_ded.beta_offset_ri_idx = 12; + dedicated.pusch_cnfg_ded.beta_offset_cqi_idx = 15; + dedicated.pusch_cnfg_ded_present = true; + dedicated.sched_request_cnfg.dsr_trans_max = LIBLTE_RRC_DSR_TRANS_MAX_N4; + dedicated.sched_request_cnfg.sr_pucch_resource_idx = 0; + dedicated.sched_request_cnfg.sr_cnfg_idx = 35; + dedicated.sched_request_cnfg.setup_present = true; + dedicated.sched_request_cnfg_present = true; + phy->set_config_dedicated(&dedicated); + phy->configure_ul_params(); + + srsue::mac_interface_rrc::mac_cfg_t mac_cfg; + mac->get_config(&mac_cfg); + memcpy(&mac_cfg.sr, &dedicated.sched_request_cnfg, sizeof(LIBLTE_RRC_SCHEDULING_REQUEST_CONFIG_STRUCT)); + mac_cfg.main.ulsch_cnfg.periodic_bsr_timer = LIBLTE_RRC_PERIODIC_BSR_TIMER_SF40; + mac->set_config(&mac_cfg); + + break; + default: + log_h->error("Received message for lcid=%d\n", lcid); + break; + } + } + +private: + int tun_fd; + bool running; + srslte::log *log_h; + srslte::byte_buffer_pool *pool; + srslte::rlc *rlc; + srsue::mac *mac; + srsue::phy *phy; + srslte::bit_buffer_t bit_buf; + srsue::rrc_state_t state; + LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1_STRUCT sib1; + LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT sib2; + bool read_enable; + + + // Determine SI messages scheduling as in 36.331 5.2.3 Acquisition of an SI message + uint32_t sib_start_tti(uint32_t tti, uint32_t period, uint32_t x) { + return (period*10*(1+tti/(period*10))+x)%10240; // the 1 means next opportunity + } + + int init_tuntap(char *ip_address) { + read_enable = true; + tun_fd = setup_if_addr(ip_address); + if (tun_fd<0) { + fprintf(stderr, "Error setting up IP %s\n", ip_address); + return -1; + } + + printf("Created tun/tap interface at IP %s\n", ip_address); + return 0; + } + + void run_thread() { + struct iphdr *ip_pkt; + uint32_t idx = 0; + int32_t N_bytes; + srslte::byte_buffer_t *pdu = pool_allocate; + + log_h->info("TUN/TAP reader thread running\n"); + + while(running) { + N_bytes = read(tun_fd, &pdu->msg[idx], SRSLTE_MAX_BUFFER_SIZE_BYTES-SRSLTE_BUFFER_HEADER_OFFSET - idx); + if(N_bytes > 0 && read_enable) + { + pdu->N_bytes = idx + N_bytes; + ip_pkt = (struct iphdr*)pdu->msg; + + log_h->debug_hex(pdu->msg, pdu->N_bytes, + "Read %d bytes from TUN/TAP\n", + N_bytes); + + // Check if entire packet was received + if(ntohs(ip_pkt->tot_len) == pdu->N_bytes) + { + log_h->info_hex(pdu->msg, pdu->N_bytes, "UL PDU"); + + // Send PDU directly to PDCP + pdu->set_timestamp(); + rlc->write_sdu(LCID, pdu); + + pdu = pool_allocate; + idx = 0; + } else{ + idx += N_bytes; + } + }else{ + log_h->error("Failed to read from TUN interface - gw receive thread exiting.\n"); + break; + } + } + } + + + void apply_sib2_configs() + { + + // Apply RACH timeAlginmentTimer configuration + srsue::mac_interface_rrc::mac_cfg_t cfg; + mac->get_config(&cfg); + cfg.main.time_alignment_timer = sib2.time_alignment_timer; + memcpy(&cfg.rach, &sib2.rr_config_common_sib.rach_cnfg, sizeof(LIBLTE_RRC_RACH_CONFIG_COMMON_STRUCT)); + cfg.prach_config_index = sib2.rr_config_common_sib.prach_cnfg.root_sequence_index; + mac->set_config(&cfg); + + log_h->info("Set RACH ConfigCommon: NofPreambles=%d, ResponseWindow=%d, ContentionResolutionTimer=%d ms\n", + liblte_rrc_number_of_ra_preambles_num[sib2.rr_config_common_sib.rach_cnfg.num_ra_preambles], + liblte_rrc_ra_response_window_size_num[sib2.rr_config_common_sib.rach_cnfg.ra_resp_win_size], + liblte_rrc_mac_contention_resolution_timer_num[sib2.rr_config_common_sib.rach_cnfg.mac_con_res_timer]); + + // Apply PHY RR Config Common + srsue::phy_interface_rrc::phy_cfg_common_t common; + memcpy(&common.pdsch_cnfg, &sib2.rr_config_common_sib.pdsch_cnfg, sizeof(LIBLTE_RRC_PDSCH_CONFIG_COMMON_STRUCT)); + memcpy(&common.pusch_cnfg, &sib2.rr_config_common_sib.pusch_cnfg, sizeof(LIBLTE_RRC_PUSCH_CONFIG_COMMON_STRUCT)); + memcpy(&common.pucch_cnfg, &sib2.rr_config_common_sib.pucch_cnfg, sizeof(LIBLTE_RRC_PUCCH_CONFIG_COMMON_STRUCT)); + memcpy(&common.ul_pwr_ctrl, &sib2.rr_config_common_sib.ul_pwr_ctrl, sizeof(LIBLTE_RRC_UL_POWER_CONTROL_COMMON_STRUCT)); + memcpy(&common.prach_cnfg, &sib2.rr_config_common_sib.prach_cnfg, sizeof(LIBLTE_RRC_PRACH_CONFIG_SIB_STRUCT)); + if (sib2.rr_config_common_sib.srs_ul_cnfg.present) { + memcpy(&common.srs_ul_cnfg, &sib2.rr_config_common_sib.srs_ul_cnfg, sizeof(LIBLTE_RRC_SRS_UL_CONFIG_COMMON_STRUCT)); + } else { + // default is release + common.srs_ul_cnfg.present = false; + } + phy->set_config_common(&common); + + phy->configure_ul_params(); + + log_h->info("Set PUSCH ConfigCommon: HopOffset=%d, RSGroup=%d, RSNcs=%d, N_sb=%d\n", + sib2.rr_config_common_sib.pusch_cnfg.pusch_hopping_offset, + sib2.rr_config_common_sib.pusch_cnfg.ul_rs.group_assignment_pusch, + sib2.rr_config_common_sib.pusch_cnfg.ul_rs.cyclic_shift, + sib2.rr_config_common_sib.pusch_cnfg.n_sb); + + log_h->info("Set PUCCH ConfigCommon: DeltaShift=%d, CyclicShift=%d, N1=%d, NRB=%d\n", + liblte_rrc_delta_pucch_shift_num[sib2.rr_config_common_sib.pucch_cnfg.delta_pucch_shift], + sib2.rr_config_common_sib.pucch_cnfg.n_cs_an, + sib2.rr_config_common_sib.pucch_cnfg.n1_pucch_an, + sib2.rr_config_common_sib.pucch_cnfg.n_rb_cqi); + + log_h->info("Set PRACH ConfigCommon: SeqIdx=%d, HS=%d, FreqOffset=%d, ZC=%d, ConfigIndex=%d\n", + sib2.rr_config_common_sib.prach_cnfg.root_sequence_index, + sib2.rr_config_common_sib.prach_cnfg.prach_cnfg_info.high_speed_flag?1:0, + sib2.rr_config_common_sib.prach_cnfg.prach_cnfg_info.prach_freq_offset, + sib2.rr_config_common_sib.prach_cnfg.prach_cnfg_info.zero_correlation_zone_config, + sib2.rr_config_common_sib.prach_cnfg.prach_cnfg_info.prach_config_index); + + log_h->info("Set SRS ConfigCommon: BW-Configuration=%d, SF-Configuration=%d, ACKNACK=%d\n", + sib2.rr_config_common_sib.srs_ul_cnfg.bw_cnfg, + sib2.rr_config_common_sib.srs_ul_cnfg.subfr_cnfg, + sib2.rr_config_common_sib.srs_ul_cnfg.ack_nack_simul_tx); + + } +}; + + + +// Create classes +srslte::logger logger; +srslte::log_filter log_phy; +srslte::log_filter log_mac; +srslte::log_filter log_rlc; +srslte::log_filter log_tester; +srslte::mac_pcap mac_pcap; +srsue::phy my_phy; +srsue::mac my_mac; +srslte::rlc rlc; +srslte::radio_multi my_radio; + +// Local classes for testing +tester my_tester; + + +bool running = true; + +void sig_int_handler(int signo) +{ + running = false; +} + +int main(int argc, char *argv[]) +{ + + parse_args(&prog_args, argc, argv); + + // set to null to disable pcap + const char *pcap_filename = "/tmp/ip_test.pcap"; + + logger.init("/tmp/ip_test_ue.log"); + log_phy.init("PHY ", &logger, true); + log_mac.init("MAC ", &logger, true); + log_rlc.init("RLC ", &logger); + log_tester.init("TEST", &logger); + logger.log("\n\n"); + + if (srsapps_verbose == 1) { + log_phy.set_level(srslte::LOG_LEVEL_INFO); + log_phy.set_hex_limit(100); + log_mac.set_level(srslte::LOG_LEVEL_DEBUG); + log_mac.set_hex_limit(100); + log_rlc.set_level(srslte::LOG_LEVEL_DEBUG); + log_rlc.set_hex_limit(1000); + log_tester.set_level(srslte::LOG_LEVEL_DEBUG); + log_tester.set_hex_limit(100); + printf("Log level info\n"); + } + if (srsapps_verbose == 2) { + log_phy.set_level(srslte::LOG_LEVEL_DEBUG); + log_phy.set_hex_limit(100); + log_mac.set_level(srslte::LOG_LEVEL_DEBUG); + log_mac.set_hex_limit(100); + log_rlc.set_level(srslte::LOG_LEVEL_DEBUG); + log_rlc.set_hex_limit(100); + log_tester.set_level(srslte::LOG_LEVEL_DEBUG); + log_tester.set_hex_limit(100); + srslte_verbose = SRSLTE_VERBOSE_DEBUG; + printf("Log level debug\n"); + } + + // Init Radio and PHY +#ifdef USE_RADIO + my_radio.init(); +#else + my_radio.init(NULL, "dummy"); +#endif + + my_radio.set_tx_freq(prog_args.tx_freq); + my_radio.set_tx_gain(prog_args.tx_gain); + my_radio.set_rx_freq(prog_args.rx_freq); + my_radio.set_rx_gain(prog_args.rx_gain); + if (prog_args.time_adv >= 0) { + printf("Setting TA=%d samples\n",prog_args.time_adv); + my_radio.set_tx_adv(prog_args.time_adv); + } + + my_phy.init(&my_radio, &my_mac, &my_tester, &log_phy, NULL); + my_mac.init(&my_phy, &rlc, &my_tester, &log_mac); + rlc.init(&my_tester, &my_tester, &my_tester, &log_rlc, &my_mac); + my_tester.init(&my_phy, &my_mac, &rlc, &log_tester, prog_args.ip_address); + + + if (pcap_filename) { + mac_pcap.open(pcap_filename); + my_mac.start_pcap(&mac_pcap); + signal(SIGINT, sig_int_handler); + } + + // Set MAC defaults + LIBLTE_RRC_MAC_MAIN_CONFIG_STRUCT default_cfg; + bzero(&default_cfg, sizeof(LIBLTE_RRC_MAC_MAIN_CONFIG_STRUCT)); + default_cfg.ulsch_cnfg.max_harq_tx = LIBLTE_RRC_MAX_HARQ_TX_N5; + default_cfg.ulsch_cnfg.periodic_bsr_timer = LIBLTE_RRC_PERIODIC_BSR_TIMER_INFINITY; + default_cfg.ulsch_cnfg.retx_bsr_timer = LIBLTE_RRC_RETRANSMISSION_BSR_TIMER_SF2560; + default_cfg.ulsch_cnfg.tti_bundling = false; + default_cfg.drx_cnfg.setup_present = false; + default_cfg.phr_cnfg.setup_present = false; + default_cfg.time_alignment_timer = LIBLTE_RRC_TIME_ALIGNMENT_TIMER_INFINITY; + my_mac.set_config_main(&default_cfg); + + while(running) { + if (my_tester.is_sib_received()) { + printf("Main running\n"); + sleep(1); + } else { + my_tester.sib_search(); + } + } + + if (pcap_filename) { + mac_pcap.close(); + } + + my_phy.stop(); + my_mac.stop(); +} + + + + +/******************* This is copied from srsue gw **********************/ +int setup_if_addr(char *ip_addr) +{ + + char *dev = (char*) "tun_srsue"; + + // Construct the TUN device + int tun_fd = open("/dev/net/tun", O_RDWR); + if(0 > tun_fd) + { + perror("open"); + return(-1); + } + + struct ifreq ifr; + + memset(&ifr, 0, sizeof(ifr)); + ifr.ifr_flags = IFF_TUN | IFF_NO_PI; + strncpy(ifr.ifr_ifrn.ifrn_name, dev, IFNAMSIZ); + if(0 > ioctl(tun_fd, TUNSETIFF, &ifr)) + { + perror("ioctl"); + return -1; + } + + // Bring up the interface + int sock = socket(AF_INET, SOCK_DGRAM, 0); + if(0 > ioctl(sock, SIOCGIFFLAGS, &ifr)) + { + perror("socket"); + return -1; + } + ifr.ifr_flags |= IFF_UP | IFF_RUNNING; + if(0 > ioctl(sock, SIOCSIFFLAGS, &ifr)) + { + perror("ioctl"); + return -1; + } + + // Setup the IP address + sock = socket(AF_INET, SOCK_DGRAM, 0); + ifr.ifr_addr.sa_family = AF_INET; + ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr = inet_addr(ip_addr); + if(0 > ioctl(sock, SIOCSIFADDR, &ifr)) + { + perror("ioctl"); + return -1; + } + ifr.ifr_netmask.sa_family = AF_INET; + ((struct sockaddr_in *)&ifr.ifr_netmask)->sin_addr.s_addr = inet_addr("255.255.255.0"); + if(0 > ioctl(sock, SIOCSIFNETMASK, &ifr)) + { + perror("ioctl"); + return -1; + } + + return(tun_fd); +} diff --git a/srsue/test/upper/nas_test.cc b/srsue/test/upper/nas_test.cc new file mode 100644 index 000000000..6aa9f29e5 --- /dev/null +++ b/srsue/test/upper/nas_test.cc @@ -0,0 +1,183 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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 +#include "upper/usim.h" +#include "upper/nas.h" +#include "srslte/upper/rlc.h" +#include "upper/rrc.h" +#include "mac/mac.h" +#include "srslte/upper/pdcp_entity.h" +#include "srslte/upper/pdcp.h" +#include "srslte/common/log_stdout.h" +#include "srslte/interfaces/ue_interfaces.h" + +using namespace srsue; + + + +uint8_t pdu1[] = { +0x03, 0x22, 0x16, 0x15, 0xe8 , 0x00 , 0x00 , 0x03 , 0x13 , 0xb0 , 0x00 , 0x02 , 0x90 , 0x08, +0x79, 0xf0, 0x00, 0x00, 0x40 , 0xb5 , 0x01 , 0x25 , 0x40 , 0xcc , 0x1d , 0x08 , 0x04 , 0x3c , 0x18 , 0x00, +0x4c, 0x02, 0x20, 0x0f, 0xa8 , 0x00 , 0x65 , 0x48 , 0x07 , 0x04 , 0x04 , 0x24 , 0x1c , 0x19 , 0x05 , 0x41, +0x39, 0x39, 0x4d, 0x38, 0x14 , 0x04 , 0x28 , 0xd1 , 0x5e , 0x6d , 0x78 , 0x13 , 0xfb , 0xf9 , 0x01 , 0xb1, +0x40, 0x2f, 0xd8, 0x4c, 0x02 , 0x20 , 0x00 , 0x5b , 0x78 , 0x00 , 0x07 , 0xa1 , 0x25 , 0xa9 , 0xc1 , 0x3f, +0xd9, 0x40, 0x41, 0xf5, 0x1b , 0x58 , 0x2f , 0x27 , 0x28 , 0xa0 , 0xed , 0xde , 0x54 , 0x43 , 0x48 , 0xc0, +0x56, 0xcc, 0x00, 0x02, 0x84 , 0x00 , 0x42 , 0x0a , 0xf1 , 0x63 }; + +uint32_t PDU1_LEN = 104; + + +#define LCID 3 + +namespace srsue { + +// fake classes +class pdcp_dummy : public rrc_interface_pdcp +{ +public: + void write_pdu(uint32_t lcid, byte_buffer_t *pdu) {} + void write_pdu_bcch_bch(byte_buffer_t *pdu) {} + void write_pdu_bcch_dlsch(byte_buffer_t *pdu) {} + void write_pdu_pcch(byte_buffer_t *pdu) {} +}; + + + +class rrc_dummy : public rrc_interface_nas +{ +public: + void write_sdu(uint32_t lcid, byte_buffer_t *sdu) + { + + } + + uint16_t get_mcc() { return 0x11; } + uint16_t get_mnc() { return 0xff; } + void enable_capabilities() { + + } +}; + +class gw_dummy : public gw_interface_nas, public gw_interface_pdcp +{ + error_t setup_if_addr(uint32_t ip_addr, char *err_str) {} + void write_pdu(uint32_t lcid, byte_buffer_t *pdu) {} +}; + +} + +class usim_dummy : public usim_interface_nas +{ + void get_imsi_vec(uint8_t* imsi_, uint32_t n){ + + } + void get_imei_vec(uint8_t* imei_, uint32_t n){ + + } + void generate_authentication_response(uint8_t *rand, + uint8_t *autn_enb, + uint16_t mcc, + uint16_t mnc, + bool *net_valid, + uint8_t *res){ + + } + + + void generate_nas_keys(uint8_t *k_nas_enc, + uint8_t *k_nas_int, + CIPHERING_ALGORITHM_ID_ENUM cipher_algo, + INTEGRITY_ALGORITHM_ID_ENUM integ_algo){ + + } +}; + + + + +int main(int argc, char **argv) +{ + srslte::log_stdout nas_log("NAS"); + srslte::log_stdout pdcp_entity_log("PDCP"); + srslte::log_stdout rrc_log("RRC"); + srslte::log_stdout mac_log("MAC"); + + + nas_log.set_level(srslte::LOG_LEVEL_DEBUG); + pdcp_entity_log.set_level(srslte::LOG_LEVEL_DEBUG); + rrc_log.set_level(srslte::LOG_LEVEL_DEBUG); + + nas_log.set_hex_limit(100000); + rrc_log.set_hex_limit(100000); + + usim_dummy usim; + rrc_dummy rrc_dummy; + gw_dummy gw; + + pdcp_dummy pdcp_dummy; + + + + + buffer_pool *pool; + pool = buffer_pool::get_instance(); + + srsue::nas nas; + nas.init(&usim, &rrc_dummy, &gw, &nas_log); + + + + + byte_buffer_t* tmp = pool_allocate; + memcpy(tmp->msg, &pdu1[0], PDU1_LEN); + tmp->N_bytes = PDU1_LEN; + + //byte_buffer_t tmp2; + //memcpy(tmp2.msg, &pdu1[0], PDU1_LEN); + //tmp2.N_bytes = PDU1_LEN; + + //srsue::mac mac; + //mac.init(NULL, NULL, NULL, &mac_log); + + srsue::rrc rrc; + rrc.init(NULL, NULL, NULL, NULL, &nas, NULL, NULL, &rrc_log); + //rrc.init(&phy, &mac, &rlc, &pdcp, &nas, &usim, &mac, &rrc_log); + + + srsue::pdcp_entity pdcp_entity; + pdcp_entity.init(NULL, &rrc, &gw, &pdcp_entity_log, RB_ID_SRB1, NULL); + + pdcp_entity.write_pdu(tmp); + + //rrc.write_sdu(RB_ID_SRB2, tmp); + + + //nas.write_pdu(LCID, tmp); + + pool->cleanup(); + +} diff --git a/srsue/test/upper/rrc_reconfig_test.cc b/srsue/test/upper/rrc_reconfig_test.cc new file mode 100644 index 000000000..25629bcd7 --- /dev/null +++ b/srsue/test/upper/rrc_reconfig_test.cc @@ -0,0 +1,133 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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 +#include +#include "srslte/common/log_stdout.h" +#include "srslte/asn1/liblte_rrc.h" +#include "srslte/asn1/liblte_mme.h" + +void nas_test() { + srslte::log_stdout log1("NAS"); + log1.set_level(srslte::LOG_LEVEL_DEBUG); + log1.set_hex_limit(-1); + + uint32_t nas_message_len = 73; + uint8_t nas_message[128] = {0x27, 0x4f, 0xab, 0xef, 0x59, 0x01, 0x07, 0x42, + 0x01, 0x49, 0x06, 0x40, 0x00, 0xf1, 0x10, 0x31, + 0x32, 0x00, 0x22, 0x52, 0x01, 0xc1, 0x05, 0x07, + 0xff, 0xff, 0xff, 0xff, 0x0c, 0x0b, 0x76, 0x7a, + 0x77, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, + 0x74, 0x05, 0x01, 0x0e, 0x0e, 0x0e, 0x01, 0x5e, + 0x04, 0xfe, 0xfe, 0x81, 0x4e, 0x50, 0x0b, 0xf6, + 0x00, 0xf1, 0x10, 0x00, 0x02, 0x01, 0x01, 0x00, + 0x00, 0x62, 0x17, 0x2c, 0x59, 0x49, 0x64, 0x01, + 0x03}; + + uint8 pd; + uint8 msg_type; + LIBLTE_BYTE_MSG_STRUCT buf; + LIBLTE_MME_ATTACH_ACCEPT_MSG_STRUCT attach_accept; + LIBLTE_MME_ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_MSG_STRUCT act_def_eps_bearer_context_req; + + memcpy(buf.msg, nas_message, nas_message_len); + buf.N_bytes = nas_message_len; + liblte_mme_parse_msg_header(&buf, &pd, &msg_type); + switch(msg_type) + { + case LIBLTE_MME_MSG_TYPE_ATTACH_ACCEPT: + liblte_mme_unpack_attach_accept_msg(&buf, &attach_accept); + liblte_mme_unpack_activate_default_eps_bearer_context_request_msg(&attach_accept.esm_msg, &act_def_eps_bearer_context_req); + break; + case LIBLTE_MME_MSG_TYPE_ATTACH_REJECT: + break; + case LIBLTE_MME_MSG_TYPE_AUTHENTICATION_REQUEST: + + break; + case LIBLTE_MME_MSG_TYPE_AUTHENTICATION_REJECT: + + break; + case LIBLTE_MME_MSG_TYPE_IDENTITY_REQUEST: + + break; + case LIBLTE_MME_MSG_TYPE_SECURITY_MODE_COMMAND: + + break; + case LIBLTE_MME_MSG_TYPE_SERVICE_REJECT: + + break; + case LIBLTE_MME_MSG_TYPE_ESM_INFORMATION_REQUEST: + + break; + case LIBLTE_MME_MSG_TYPE_EMM_INFORMATION: + + break; + default: + break; + } +} + +void basic_test() { + srslte::log_stdout log1("RRC"); + log1.set_level(srslte::LOG_LEVEL_DEBUG); + log1.set_hex_limit(-1); + + LIBLTE_BIT_MSG_STRUCT bit_buf; + LIBLTE_RRC_DL_DCCH_MSG_STRUCT dl_dcch_msg; + + uint32_t rrc_message_len = 147; + uint8_t rrc_message[256] = {0x22, 0x16, 0x95, 0xa0, 0x18, 0x00, 0x05, 0xaa, + 0x50, 0x36, 0x00, 0x61, 0x08, 0x9c, 0xe3, 0x40, + 0xb0, 0x84, 0x4e, 0x71, 0xc0, 0x30, 0x84, 0x6e, + 0x71, 0xe0, 0x70, 0x84, 0x6e, 0x70, 0x6c, 0x63, + 0x1a, 0xc6, 0xb9, 0x8e, 0x7b, 0x1e, 0x84, 0xc0, + 0x01, 0x24, 0x9d, 0x3e, 0xaf, 0xbd, 0x64, 0x04, + 0x1d, 0x08, 0x05, 0x24, 0x19, 0x00, 0x03, 0xc4, + 0x40, 0xc4, 0xc8, 0x00, 0x89, 0x48, 0x07, 0x04, + 0x14, 0x1f, 0xff, 0xff, 0xff, 0xfc, 0x30, 0x2d, + 0xd9, 0xe9, 0xdd, 0xa5, 0xb9, 0xd1, 0x95, 0xc9, + 0xb9, 0x95, 0xd0, 0x14, 0x04, 0x38, 0x38, 0x38, + 0x05, 0x78, 0x13, 0xfb, 0xfa, 0x05, 0x39, 0x40, + 0x2f, 0xd8, 0x03, 0xc4, 0x40, 0x00, 0x08, 0x04, + 0x04, 0x00, 0x01, 0x88, 0x5c, 0xb1, 0x65, 0x25, + 0x90, 0x04, 0x0d, 0xa9, 0xc0, 0x2a, 0x9a, 0x01, + 0x99, 0x3b, 0x01, 0xf5, 0x12, 0xf0, 0x85, 0x0d, + 0x85, 0xef, 0xc0, 0x01, 0xf2, 0x20, 0x60, 0x18, + 0x07, 0x97, 0x09, 0x1f, 0xc3, 0x06, 0x00, 0x81, + 0x00, 0x00, 0x11}; + + srslte_bit_unpack_vector(rrc_message, bit_buf.msg, rrc_message_len*8); + bit_buf.N_bits = rrc_message_len*8; + liblte_rrc_unpack_dl_dcch_msg((LIBLTE_BIT_MSG_STRUCT*)&bit_buf, &dl_dcch_msg); + + printf("done\n"); +} + + +int main(int argc, char **argv) { + basic_test(); + nas_test(); +} diff --git a/srsue/test/upper/usim_test.cc b/srsue/test/upper/usim_test.cc new file mode 100644 index 000000000..8e7d53bfe --- /dev/null +++ b/srsue/test/upper/usim_test.cc @@ -0,0 +1,87 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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 +#include "upper/usim.h" +#include "srslte/common/log_stdout.h" +#include + +using namespace srsue; + +/* +Debug output generated from the OpenAirInterface HSS: + +Converted 02f839 to plmn 208.93 +Query: SELECT `key`,`sqn`,`rand`,`OPc` FROM `users` WHERE `users`.`imsi`='208930000000001' +Key: 8b.af.47.3f.2f.8f.d0.94.87.cc.cb.d7.09.7c.68.62. +Received SQN 00000000000000006999 converted to 6999 +SQN: 00.00.00.00.1b.57. +RAND: 7c.f6.e2.6b.20.0a.ca.27.a1.a0.91.40.f5.cf.9d.62. +OPc: 8e.27.b6.af.0e.69.2e.75.0f.32.66.7a.3b.14.60.5d. +Generated random +RijndaelKeySchedule: K 8BAF473F2F8FD09487CCCBD7097C6862 +MAC_A : 84.ba.37.b0.f6.73.4d.d1. +SQN : 00.00.00.00.1b.57. +RAND : 88.38.c3.55.c8.78.aa.57.21.49.fe.69.db.68.6b.5a. +RijndaelKeySchedule: K 8BAF473F2F8FD09487CCCBD7097C6862 +AK : d7.44.51.9b.3e.fd. +CK : 05.d3.53.3d.fe.7b.e7.2d.42.c7.bb.02.f2.8e.da.7f. +IK : 26.33.a2.0b.dc.a8.9d.78.58.ba.42.47.8b.e4.d2.4d. +XRES : e5.5d.88.27.91.8d.ac.c6. +AUTN : d7.44.51.9b.25.aa.80.00.84.ba.37.b0.f6.73.4d.d1. +0x05 0xd3 0x53 0x3d 0xfe 0x7b 0xe7 0x2d 0x42 0xc7 0xbb 0x02 0xf2 0x8e +0xda 0x7f 0x26 0x33 0xa2 0x0b 0xdc 0xa8 0x9d 0x78 0x58 0xba 0x42 0x47 +0x8b 0xe4 0xd2 0x4d 0x10 0x02 0xf8 0x39 0x00 0x03 0xd7 0x44 0x51 0x9b +0x25 0xaa 0x00 0x06 +KASME : a8.27.57.5e.ea.1a.10.17.3a.a1.bf.ce.4b.0c.21.85.e0.51.ef.bd.91.7f.fe.f5.1f.74.29.61.f9.03.7a.35. +*/ + +uint8_t rand_enb[] = {0x88, 0x38, 0xc3, 0x55, 0xc8, 0x78, 0xaa, 0x57, 0x21, 0x49, 0xfe, 0x69, 0xdb, 0x68, 0x6b, 0x5a}; +uint8_t autn_enb[] = {0xd7, 0x44, 0x51, 0x9b, 0x25, 0xaa, 0x80, 0x00, 0x84, 0xba, 0x37, 0xb0, 0xf6, 0x73, 0x4d, 0xd1}; + +uint16 mcc = 208; +uint16 mnc = 93; + +int main(int argc, char **argv) +{ + srslte::log_stdout usim_log("USIM"); + bool net_valid; + uint8_t res[16]; + + usim_args_t args; + args.algo = "milenage"; + args.amf = "8000"; + args.imei = "35609204079301"; + args.imsi = "208930000000001"; + args.k = "8BAF473F2F8FD09487CCCBD7097C6862"; + args.op = "11111111111111111111111111111111"; + + srsue::usim usim; + usim.init(&args, &usim_log); + usim.generate_authentication_response(rand_enb, autn_enb, mcc, mnc, &net_valid, res); + + assert(net_valid == true); +} diff --git a/srsue/ue.conf.example b/srsue/ue.conf.example new file mode 100644 index 000000000..90d974859 --- /dev/null +++ b/srsue/ue.conf.example @@ -0,0 +1,168 @@ +##################################################################### +# srsUE configuration file +##################################################################### +# RF configuration +# +# dl_freq: Downlink centre frequency (Hz). +# ul_freq: Uplink centre frequency (Hz). +# tx_gain: Transmit gain (dB). +# rx_gain: Optional receive gain (dB). If disabled, AGC if enabled +# +# Optional parameters: +# nof_rx_ant: Number of RX antennas (Default 1, supported 1 or 2) +# device_name: Device driver family. Supported options: "auto" (uses first found), "UHD" or "bladeRF" +# device_args: Arguments for the device driver. Options are "auto" or any string. +# Default for UHD: "recv_frame_size=9232,send_frame_size=9232" +# Default for bladeRF: "" +# #time_adv_nsamples: Transmission time advance (in number of samples) to compensate for RF delay +# from antenna to timestamp insertion. +# Default "auto". B210 USRP: 100 samples, bladeRF: 27. +# burst_preamble_us: Preamble length to transmit before start of burst. +# Default "auto". B210 USRP: 400 us, bladeRF: 0 us. +##################################################################### +[rf] +dl_freq = 2685000000 +ul_freq = 2565000000 +tx_gain = 70 +rx_gain = 50 + +#nof_rx_ant = 1 +#device_name = auto +#device_args = auto +#time_adv_nsamples = auto +#burst_preamble_us = auto + + +##################################################################### +# MAC-layer packet capture configuration +# +# Packets are captured to file in the compact format decoded by +# the Wireshark mac-lte-framed dissector and with DLT 147. +# To use the dissector, edit the preferences for DLT_USER to +# add an entry with DLT=147, Payload Protocol=mac-lte-framed. +# For more information see: https://wiki.wireshark.org/MAC-LTE +# +# enable: Enable MAC layer packet captures (true/false) +# filename: File path to use for packet captures +##################################################################### +[pcap] +enable = false +filename = /tmp/ue.pcap + +##################################################################### +# Log configuration +# +# Log levels can be set for individual layers. "all_level" sets log +# level for all layers unless otherwise configured. +# Format: e.g. phy_level = info +# +# In the same way, packet hex dumps can be limited for each level. +# "all_hex_limit" sets the hex limit for all layers unless otherwise +# configured. +# Format: e.g. phy_hex_limit = 32 +# +# Logging layers: phy, mac, rlc, pdcp, rrc, nas, gw, usim, all +# Logging levels: debug, info, warning, error, none +# +# filename: File path to use for log output +##################################################################### +[log] +all_level = info +all_hex_limit = 32 +filename = /tmp/ue.log + +##################################################################### +# USIM configuration +# +# algo: Authentication algorithm (xor/milenage) +# op: 128-bit Operator Variant Algorithm Configuration Field (hex) +# amf: 16-bit Authentication Management Field (hex) +# k: 128-bit subscriber key (hex) +# imsi: 15 digit International Mobile Subscriber Identity +# imei: 15 digit International Mobile Station Equipment Identity +##################################################################### +[usim] +algo = milenage +op = 63BFA50EE6523365FF14C1F45F88737D +amf = 8000 +k = 00112233445566778899aabbccddeeff +imsi = 001010123456789 +imei = 353490069873319 + +[gui] +enable = false + +##################################################################### +# Expert configuration options +# +# ue_category: Sets UE category (range 1-5). Default: 4 +# +# prach_gain: PRACH gain (dB). If defined, forces a gain for the tranmsission of PRACH only., +# Default is to use tx_gain in [rf] section. +# cqi_max: Upper bound on the maximum CQI to be reported. Default 15. +# cqi_fixed: Fixes the reported CQI to a constant value. Default disabled. +# snr_ema_coeff: Sets the SNR exponential moving average coefficient (Default 0.1) +# snr_estim_alg: Sets the noise estimation algorithm. (Default refs) +# Options: pss: use difference between received and known pss signal, +# refs: use difference between noise references and noiseless (after filtering) +# empty: use empty subcarriers in the boarder of pss/sss signal +# pdsch_max_its: Maximum number of turbo decoder iterations (Default 4) +# attach_enable_64qam: Enables PUSCH 64QAM modulation before attachment (Necessary for old +# Amarisoft LTE 100 eNodeB, disabled by default) +# nof_phy_threads: Selects the number of PHY threads (maximum 4, minimum 1, default 2) +# equalizer_mode: Selects equalizer mode. Valid modes are: "mmse", "zf" or any +# non-negative real number to indicate a regularized zf coefficient. +# Default is MMSE. +# cfo_integer_enabled: Enables integer CFO estimation and correction. This needs improvement +# and may lead to incorrect synchronization. Use with caution. +# cfo_correct_tol_hz: Tolerance (in Hz) for digial CFO compensation. Lower tolerance means that +# a new table will be generated more often. +# time_correct_period: Period for sampling time offset correction. Default is 10 (ue_sync.c), +# good for long channels. For best performance at highest SNR reduce it to 1. +# sfo_correct_disable: Disables phase correction before channel estimation to compensate for +# sampling frequency offset. Default is enabled. +# sss_algorithm: Selects the SSS estimation algorithm. Can choose between +# {full, partial, diff}. +# estimator_fil_w: Chooses the coefficients for the 3-tap channel estimator centered filter. +# The taps are [w, 1-2w, w] +# metrics_period_secs: Sets the period at which metrics are requested from the UE. +# +# pregenerate_signals: Pregenerate uplink signals after attach. Improves CPU performance. +# +##################################################################### +[expert] +#ue_category = 4 +#prach_gain = 30 +#cqi_max = 15 +#cqi_fixed = 10 +#snr_ema_coeff = 0.1 +#snr_estim_alg = refs +#pdsch_max_its = 4 +#attach_enable_64qam = false +#nof_phy_threads = 2 +#equalizer_mode = mmse +#cfo_integer_enabled = false +#cfo_correct_tol_hz = 50 +#time_correct_period = 5 +#sfo_correct_disable = false +#sss_algorithm = full +#estimator_fil_w = 0.1 +#pregenerate_signals = false + +##################################################################### +# Manual RF calibration +# +# Applies DC offset and IQ imbalance to TX and RX modules. +# Currently this configuration is only used if the detected device is a bladeRF +# +# tx_corr_dc_gain: TX DC offset gain correction +# tx_corr_dc_phase: TX DC offset phase correction +# tx_corr_iq_i: TX IQ imbalance inphase correction +# tx_corr_iq_q: TX IQ imbalance quadrature correction +# same can be configured for rx_* +##################################################################### +[rf_calibration] +tx_corr_dc_gain = 20 +tx_corr_dc_phase = 184 +tx_corr_iq_i = 19 +tx_corr_iq_q = 97