diff --git a/CHANGELOG b/CHANGELOG index 3aa324c0a..7dfff7d89 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,15 @@ Change Log for Releases ============================== +## 002.000.000 + * Added fully functional srsENB to srsLTE code + * Merged srsUE code into srsLTE and reestructured PHY code + * Added support for SoapySDR devices (eg LimeSDR) + * Fixed issues in RLC AM + * Added support for NEON and AVX in many kernels and Viterbi decoder + * Added support for CPU affinity + * Other minor bug-fixes and new features + ## 001.004.000 * Fixed issue in rv for format1C causing incorrect SIB1 decoding in some networks * Improved PDCCH decoding BER (fixed incorrect trellis initialization) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4f91dec82..83ebeb618 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,26 +30,137 @@ 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(ENABLE_SRSUE "Build srsUE application" ON) +option(ENABLE_SRSENB "Build srsENB application" ON) + +option(ENABLE_VOLK "Enable use of VOLK SIMD library" ON) +option(ENABLE_GUI "Enable GUI (using srsGUI)" ON) +option(ENABLE_BLADERF "Enable BladeRF" ON) + +option(BUILD_STATIC "Attempt to statically link external deps" OFF) +option(RPATH "Enable RPATH" OFF) + +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) ######################################################################## @@ -71,13 +182,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 ######################################################################## @@ -89,56 +193,79 @@ 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") if(${CMAKE_BUILD_TYPE} STREQUAL "Debug") - find_package(SSE) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O0") + 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_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native -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_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native -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_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3") - find_package(SSE) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3") + endif(${CMAKE_BUILD_TYPE} STREQUAL "Debug") + + 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} -march=native -mfpmath=sse -mavx -DLV_HAVE_AVX -DLV_HAVE_SSE") + 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} -march=native -mfpmath=sse -msse4.1 -DLV_HAVE_SSE") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mfpmath=sse -msse4.1 -DLV_HAVE_SSE") endif(HAVE_AVX) - endif(${CMAKE_BUILD_TYPE} STREQUAL "Debug") - + 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 ######################################################################## @@ -151,11 +278,9 @@ add_custom_target(uninstall COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake) ######################################################################## -# Macro to add -fPIC property to static libs +# Add -fPIC property to all targets ######################################################################## -macro(SRSLTE_SET_PIC) - set_target_properties(${ARGV} PROPERTIES COMPILE_FLAGS -fPIC) -endmacro(SRSLTE_SET_PIC) +set(CMAKE_POSITION_INDEPENDENT_CODE ON) ######################################################################## # Print summary @@ -166,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/README.md b/README.md index 0423f3dc2..6e5802612 100644 --- a/README.md +++ b/README.md @@ -3,31 +3,61 @@ srsLTE [![Coverity Scan Build Status](https://scan.coverity.com/projects/10045/badge.svg)](https://scan.coverity.com/projects/10045) -srsLTE is a free and open-source LTE library for SDR UE and eNodeB developed by SRS (www.softwareradiosystems.com). The library is highly modular with minimum inter-module or external dependencies. It is entirely written in C and, if available in the system, uses the acceleration library VOLK distributed in GNURadio. +srsLTE is a free and open-source LTE software suite developed by SRS (www.softwareradiosystems.com). -**srsLTE is used by srsUE, a full stack (PHY to IP) implementation of an LTE UE. srsUE is available at https://github.com/srslte/srsue** +It includes: + * srsUE - a complete SDR LTE UE application featuring all layers from PHY to IP + * srsENB - a complete SDR LTE eNodeB application + * a highly modular set of common libraries for PHY, MAC, RLC, PDCP, RRC, NAS, S1AP and GW layers. +srsLTE is released under the AGPLv3 license and uses software from the OpenLTE project (http://sourceforge.net/projects/openlte) for some security functions and for RRC/NAS message parsing. -The srsLTE software license is AGPLv3. +Common Features +--------------- -Current Features: * LTE Release 8 compliant * FDD configuration * Tested bandwidths: 1.4, 3, 5, 10, 15 and 20 MHz * Transmission mode 1 (single antenna) and 2 (transmit diversity) - * Cell search and synchronization procedure for the UE - * All DL channels/signals are supported for UE and eNodeB side: PSS, SSS, PBCH, PCFICH, PHICH, PDCCH, PDSCH - * All UL channels/signals are supported for UE side: PRACH, PUSCH, PUCCH, SRS * Frequency-based ZF and MMSE equalizer * Highly optimized Turbo Decoder available in Intel SSE4.1/AVX (+100 Mbps) and standard C (+25 Mbps) - * UE receiver tested and verified with Amarisoft LTE 100 eNodeB and commercial LTE networks (Telefonica Spain, Three.ie and Eircom in Ireland) - -Missing Features: - * Closed-loop power control - * Semi-Persistent Scheduling + * MAC, RLC, PDCP, RRC, NAS, S1AP and GW layers + * Detailed log system with per-layer log levels and hex dumps + * MAC layer wireshark packet capture + * Command-line trace metrics + * Detailed input configuration files + +srsUE Features +-------------- + + * Cell search and synchronization procedure for the UE + * Soft USIM supporting Milenage and XOR authentication + * Virtual network interface *tun_srsue* created upon network attach + * 75 Mbps DL in 20 MHz SISO configuration in i7 Quad-Core CPU. + * 36 Mbps DL in 10 MHz SISO configuration in i5 Dual-Core CPU. + +srsUE has been fully tested and validated with the following network equipment: + * Amarisoft LTE100 eNodeB and EPC + * Nokia FlexiRadio family FSMF system module with 1800MHz FHED radio module and TravelHawk EPC simulator + * Huawei DBS3900 + * Octasic Flexicell LTE-FDD NIB + +srsENB Features +--------------- + + * Round Robin MAC scheduler with FAPI-like C++ API + * SR support + * Periodic and Aperiodic CQI feedback support + * Standard S1AP and GTP-U interfaces to the Core Network + * Tested up to 75 Mbps DL in SISO configuration with commercial UEs + +srsENB has been tested and validated with the following handsets: + * LG Nexus 5 + * LG Nexus 4 + * Motorola Moto G4 plus Hardware -======== +-------- The library currently supports the Ettus Universal Hardware Driver (UHD) and the bladeRF driver. Thus, any hardware supported by UHD or bladeRF can be used. There is no sampling rate conversion, therefore the hardware should support 30.72 MHz clock in order to work correctly with LTE sampling frequencies and decode signals from live LTE base stations. @@ -35,15 +65,28 @@ We have tested the following hardware: * USRP B210 * USRP X300 * bladeRF + * limeSDR -Download & Install Instructions -================================= +Build Instructions +------------------ + +* Mandatory requirements: + * Common: + * libfftw http://www.fftw.org/ + * PolarSSL/mbedTLS https://tls.mbed.org + * srsUE: + * Boost: http://www.boost.org + * srsENB: + * Boost: http://www.boost.org + * lksctp: http://lksctp.sourceforge.net/ -* Mandatory dependencies: - * libfftw * Optional requirements: - * srsgui: for real-time plotting. Download it here: https://github.com/srslte/srsgui - * VOLK: if the VOLK library and headers are detected, they will be used for accelerating some signal processing functions. + * srsgui: https://github.com/srslte/srsgui - for real-time plotting. + * VOLK: https://github.com/gnuradio/volk - if the VOLK library and headers are detected, they will be used to accelerate some signal processing functions. + +* RF front-end driver: + * UHD: https://github.com/EttusResearch/uhd + * BladeRF: https://github.com/Nuand/bladeRF Download and build srsLTE: ``` @@ -55,64 +98,27 @@ cmake ../ make ``` -The library can also be installed using the command ```sudo make install```. - -Running srsLTE Examples -======================== - -* SIB1 reception and UE measurement from commercial LTE networks: -``` -lte/examples/pdsch_ue -f [frequency_in_Hz] -``` -Where -f is the LTE channel frequency. - -* eNodeB to UE Downlink PHY test - -You will need two computers, each equipped with a USRP. At the transmitter side, run: - -``` -lte/examples/pdsch_enodeb -f [frequency_in_Hz] [-h for more commands] -``` - -At the receiver run: -``` -lte/examples/pdsch_ue -r 1234 -f [frequency_in_Hz] -``` - -At the transmitter console, it is possible to change the Modulation and Coding Scheme (MCS) by typing a new number (between 0 and 28) and pressing Enter. - - -The output at the receiver should look something similar to the following video. In this example, we removed the transmitter and receiver antennas in the middle of the demonstration, showing how reception is still possible (despite with some erros). +The software suite can also be installed using the command ```sudo make install```. -https://www.dropbox.com/s/txh1nuzdb0igq5n/demo_pbch.ogv +Execution Instructions +---------------------- -![Screenshopt of the PBCH example output](pbch_capture.png "Screenshopt of the PBCH example output") +The srsUE and srsENB applications include example configuration files. Execute the applications with root privileges to enable real-time thread priorities and to permit creation of virtual network interfaces. -* Video over Downlink PHY (eNodeB to UE) - -The previous example sends random bits to the UE. It is possible to open a TCP socket and stream video over the LTE PHY DL wireless connection. At the transmitter side, run the following command: +### srsUE +Run the srsUE application as follows: ``` -lte/examples/pdsch_enodeb -f [frequency_in_Hz] -u 2000 [-h for more commands] +sudo ./srsue ue.conf ``` -The argument -u 2000 will open port 2000 for listening for TCP connections. Set a high-order MCS, like 16 by typing 16 in the eNodeB console and pressing Enter. +### srsENB +As the srsLTE software suite does not include EPC functionality, a separate EPC is required to run srsENB. Run the application as follows: ``` -lte/examples/pdsch_ue -r 1234 -u 2001 -U 127.0.0.1 -f [frequency_in_Hz] +sudo ./srsenb enb.conf ``` -The arguments -u 2001 -U 127.0.0.1 will forward the data that was injected at the eNodeB to address:port indicated by the argument. Once you have the system running, you can transmit some useful data, like a video stream. At the transmitter side, run: - -``` -avconv -f video4linux2 -i /dev/video0 -c:v mp4 -f mpegts tcp://127.0.0.1:2000 -``` -to stream the video captured from the webcam throught the local host port 2000. At the receiver, run: - -``` -avplay tcp://127.0.0.1:2001?listen -analyzeduration 100 -loglevel verbose -``` -to watch the video. Support ======== 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 2320cf065..138d4ca59 100644 --- a/cmake/modules/FindMKL.cmake +++ b/cmake/modules/FindMKL.cmake @@ -5,23 +5,49 @@ # MKL_LIBRARIES - The libraries needed to use mkl # MKL_DEFINITIONS - Compiler switches required for using mkl -find_path(MKL_INCLUDE_DIR +find_path(MKL_INCLUDE_DIR NAMES mkl.h HINTS $ENV{MKL_DIR}/include PATHS) -find_library(MKL_LIBRARY +find_path(MKL_FFTW_INCLUDE_DIR + NAMES fftw3.h + HINTS $ENV{MKL_DIR}/include/fftw + PATHS) + +find_library(MKL_LIBRARIES NAMES mkl_rt HINTS $ENV{MKL_DIR}/lib/intel64 PATHS) -set(MKL_LIBRARIES ${MKL_LIBRARY} ) -set(MKL_INCLUDE_DIRS ${MKL_INCLUDE_DIR} ) +find_library(MKL_CORE + NAMES libmkl_core.a + HINTS $ENV{MKL_DIR}/lib/intel64 + PATHS) + +find_library(MKL_ILP + NAMES libmkl_intel_ilp64.a + HINTS $ENV{MKL_DIR}/lib/intel64 + PATHS) + +find_library(MKL_SEQ + NAMES libmkl_sequential.a + HINTS $ENV{MKL_DIR}/lib/intel64 + PATHS) + +set(MKL_STATIC_LIBRARIES -Wl,--start-group ${MKL_CORE} ${MKL_ILP} ${MKL_SEQ} -Wl,--end-group -lpthread -lm -ldl) +set(MKL_INCLUDE_DIRS ${MKL_INCLUDE_DIR} ${MKL_FFTW_INCLUDE_DIR}) include(FindPackageHandleStandardArgs) # handle the QUIETLY and REQUIRED arguments and set MKL_FOUND to TRUE # if all listed variables are TRUE find_package_handle_standard_args(mkl DEFAULT_MSG - MKL_LIBRARY MKL_INCLUDE_DIR) + MKL_LIBRARIES MKL_CORE MKL_ILP MKL_SEQ MKL_INCLUDE_DIRS) + +if(MKL_FOUND) + MESSAGE(STATUS "Found MKL_INCLUDE_DIRS: ${MKL_INCLUDE_DIRS}" ) + MESSAGE(STATUS "Found MKL_LIBRARIES: ${MKL_LIBRARIES}" ) + MESSAGE(STATUS "Found MKL_STATIC_LIBRARIES: ${MKL_STATIC_LIBRARIES}" ) +endif(MKL_FOUND) -mark_as_advanced(MKL_INCLUDE_DIR MKL_LIBRARY ) +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 8647e9413..30be8a206 100644 --- a/cmake/modules/FindSSE.cmake +++ b/cmake/modules/FindSSE.cmake @@ -1,11 +1,12 @@ -if (NOT CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|^i[3,9]86$") - return() -endif() +#if (NOT CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|^i[3,9]86$") +# return() +#endif() include(CheckCSourceRuns) option(ENABLE_SSE "Enable compile-time SSE4.1 support." ON) option(ENABLE_AVX "Enable compile-time AVX support." ON) +option(ENABLE_AVX2 "Enable compile-time AVX2 support." ON) if (ENABLE_SSE) # @@ -39,11 +40,22 @@ if (ENABLE_SSE) set(CMAKE_REQUIRED_FLAGS "-mavx") check_c_source_runs(" #include - int main() { - __m256i a = _mm256_setzero_si256(); - return 0; + __m256 a, b, c; + const float src[8] = { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f }; + float dst[8]; + a = _mm256_loadu_ps( src ); + b = _mm256_loadu_ps( src ); + c = _mm256_add_ps( a, b ); + _mm256_storeu_ps( dst, c ); + int i = 0; + for( i = 0; i < 8; i++ ){ + if( ( src[i] + src[i] ) != dst[i] ){ + return -1; + } + } + return 0; }" HAVE_AVX) endif() @@ -52,7 +64,41 @@ if (ENABLE_SSE) message(STATUS "AVX is enabled - target CPU must support it") endif() endif() + + if (ENABLE_AVX2) + + # + # Check compiler for AVX intrinsics + # + if (CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_CLANG ) + set(CMAKE_REQUIRED_FLAGS "-mavx2") + check_c_source_runs(" + #include + int main() + { + __m256i a, b, c; + const int src[8] = { 1, 2, 3, 4, 5, 6, 7, 8 }; + int dst[8]; + a = _mm256_loadu_si256( (__m256i*)src ); + b = _mm256_loadu_si256( (__m256i*)src ); + c = _mm256_add_epi32( a, b ); + _mm256_storeu_si256( (__m256i*)dst, c ); + int i = 0; + for( i = 0; i < 8; i++ ){ + if( ( src[i] + src[i] ) != dst[i] ){ + return -1; + } + } + return 0; + }" + HAVE_AVX2) + endif() + + if (HAVE_AVX2) + message(STATUS "AVX2 is enabled - target CPU must support it") + endif() + endif() endif() -mark_as_advanced(HAVE_SSE, HAVE_AVX) \ No newline at end of file +mark_as_advanced(HAVE_SSE, HAVE_AVX, HAVE_AVX2) 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/cmake/modules/FindVolk.cmake b/cmake/modules/FindVolk.cmake index 5dbe17cd5..92b2b91ea 100644 --- a/cmake/modules/FindVolk.cmake +++ b/cmake/modules/FindVolk.cmake @@ -54,7 +54,7 @@ IF(VOLK_FOUND) CHECK_FUNCTION_EXISTS_MATH(volk_32f_x2_subtract_32f HAVE_VOLK_SUB_FLOAT_FUNCTION) CHECK_FUNCTION_EXISTS_MATH(volk_32f_x2_add_32f HAVE_VOLK_ADD_FLOAT_FUNCTION) CHECK_FUNCTION_EXISTS_MATH(volk_32fc_x2_square_dist_32f HAVE_VOLK_SQUARE_DIST_FUNCTION) - CHECK_FUNCTION_EXISTS_MATH(volk_32fc_deinterleave_real_32f HAVE_VOLK_DEINTERLEAVE_FUNCTION) + CHECK_FUNCTION_EXISTS_MATH(volk_32fc_deinterleave_real_32f HAVE_VOLK_DEINTERLEAVE_REAL_FUNCTION) CHECK_FUNCTION_EXISTS_MATH(volk_32fc_index_max_16u HAVE_VOLK_MAX_ABS_FUNCTION) CHECK_FUNCTION_EXISTS_MATH(volk_32f_x2_multiply_32f HAVE_VOLK_MULT_REAL2_FUNCTION) CHECK_FUNCTION_EXISTS_MATH(volk_16i_max_star_16i HAVE_VOLK_MAX_STAR_S_FUNCTION) @@ -63,6 +63,12 @@ IF(VOLK_FOUND) SET(VOLK_DEFINITIONS "HAVE_VOLK") + IF(${HAVE_VOLK_CONVERT_IF_FUNCTION}) + SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_CONVERT_IF_FUNCTION") + ENDIF() + IF(${HAVE_VOLK_MULT_REAL2_FUNCTION}) + SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_MULT_REAL2_FUNCTION") + ENDIF() IF(${HAVE_VOLK_CONVERT_CI_FUNCTION}) SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_CONVERT_CI_FUNCTION") ENDIF() @@ -99,8 +105,8 @@ IF(VOLK_FOUND) IF(${HAVE_VOLK_MULT2_CONJ_FUNCTION}) SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_MULT2_CONJ_FUNCTION") ENDIF() - IF(${HAVE_VOLK_DEINTERLEAVE_FUNCTION}) - SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_DEINTERLEAVE_FUNCTION") + IF(${HAVE_VOLK_DEINTERLEAVE_REAL_FUNCTION}) + SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_DEINTERLEAVE_REAL_FUNCTION") ENDIF() IF(${HAVE_VOLK_CONVERT_FI_FUNCTION}) SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_CONVERT_FI_FUNCTION") @@ -135,6 +141,9 @@ IF(VOLK_FOUND) IF(${HAVE_VOLK_DOTPROD_FC_FUNCTION}) SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_DOTPROD_FC_FUNCTION") ENDIF() + IF(${HAVE_VOLK_DOTPROD_CFC_FUNCTION}) + SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_DOTPROD_CFC_FUNCTION") + ENDIF() IF(${HAVE_VOLK_DOTPROD_F_FUNCTION}) SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_DOTPROD_F_FUNCTION") ENDIF() diff --git a/cmake/modules/SRSLTEVersion.cmake b/cmake/modules/SRSLTEVersion.cmake index 07959f188..d2ab204f5 100644 --- a/cmake/modules/SRSLTEVersion.cmake +++ b/cmake/modules/SRSLTEVersion.cmake @@ -18,7 +18,7 @@ # and at http://www.gnu.org/licenses/. # -SET(SRSLTE_VERSION_MAJOR 001) -SET(SRSLTE_VERSION_MINOR 004) +SET(SRSLTE_VERSION_MAJOR 002) +SET(SRSLTE_VERSION_MINOR 000) SET(SRSLTE_VERSION_PATCH 000) SET(SRSLTE_VERSION_STRING "${SRSLTE_VERSION_MAJOR}.${SRSLTE_VERSION_MINOR}.${SRSLTE_VERSION_PATCH}") 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 69% rename from srslte/examples/CMakeLists.txt rename to lib/examples/CMakeLists.txt index b8357fd05..652a2c195 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,22 +24,26 @@ ################################################################# 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) - -add_executable(pdsch_enodeb pdsch_enodeb.c) -target_link_libraries(pdsch_enodeb srslte pthread) - if(RF_FOUND) + add_executable(pdsch_ue pdsch_ue.c) + target_link_libraries(pdsch_ue srslte_phy srslte_rf pthread) + add_executable(pdsch_enodeb pdsch_enodeb.c) + target_link_libraries(pdsch_enodeb srslte_phy srslte_rf pthread) else(RF_FOUND) add_definitions(-DDISABLE_RF) + + add_executable(pdsch_ue pdsch_ue.c) + target_link_libraries(pdsch_ue srslte_phy pthread) + + add_executable(pdsch_enodeb pdsch_enodeb.c) + target_link_libraries(pdsch_enodeb srslte_phy pthread) endif(RF_FOUND) find_package(SRSGUI) @@ -59,19 +63,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 srslte_rf) add_executable(cell_measurement cell_measurement.c) - target_link_libraries(cell_measurement srslte) + target_link_libraries(cell_measurement srslte_phy srslte_rf) add_executable(usrp_capture usrp_capture.c) - target_link_libraries(usrp_capture srslte) + target_link_libraries(usrp_capture srslte_phy srslte_rf) add_executable(usrp_capture_sync usrp_capture_sync.c) - target_link_libraries(usrp_capture_sync srslte) + target_link_libraries(usrp_capture_sync srslte_phy srslte_rf) add_executable(usrp_txrx usrp_txrx.c) - target_link_libraries(usrp_txrx srslte) + target_link_libraries(usrp_txrx srslte_phy srslte_rf) message(STATUS " examples will be installed.") @@ -79,6 +83,4 @@ else(RF_FOUND) message(STATUS " examples will NOT BE INSTALLED.") endif(RF_FOUND) -# Add subdirectories -add_subdirectory(tutorial_examples) diff --git a/srslte/examples/cell_measurement.c b/lib/examples/cell_measurement.c similarity index 90% rename from srslte/examples/cell_measurement.c rename to lib/examples/cell_measurement.c index de9962513..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, @@ -129,9 +129,10 @@ void sig_int_handler(int signo) } } -int srslte_rf_recv_wrapper(void *h, void *data, uint32_t nsamples, srslte_timestamp_t *q) { +int srslte_rf_recv_wrapper(void *h, cf_t *data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t *q) { DEBUG(" ---- Receive %d samples ---- \n", nsamples); - return srslte_rf_recv(h, data, nsamples, 1); + + return srslte_rf_recv(h, data[0], nsamples, 1); } enum receiver_state { DECODE_MIB, DECODE_SIB, MEASURE} state; @@ -141,7 +142,7 @@ enum receiver_state { DECODE_MIB, DECODE_SIB, MEASURE} state; int main(int argc, char **argv) { int ret; - cf_t *sf_buffer; + cf_t *sf_buffer[SRSLTE_MAX_PORTS] = {NULL, NULL}; prog_args_t prog_args; srslte_cell_t cell; int64_t sf_cnt; @@ -180,6 +181,8 @@ int main(int argc, char **argv) { } srslte_rf_set_rx_gain(&rf, 50); } + + sf_buffer[0] = srslte_vec_malloc(3*sizeof(cf_t)*SRSLTE_SF_LEN_PRB(100)); sigset_t sigset; sigemptyset(&sigset); @@ -198,7 +201,7 @@ int main(int argc, char **argv) { uint32_t ntrial=0; do { - ret = rf_search_and_decode_mib(&rf, &cell_detect_config, prog_args.force_N_id_2, &cell, &cfo); + ret = rf_search_and_decode_mib(&rf, 1, &cell_detect_config, prog_args.force_N_id_2, &cell, &cfo); if (ret < 0) { fprintf(stderr, "Error searching for cell\n"); exit(-1); @@ -234,11 +237,11 @@ int main(int argc, char **argv) { srslte_rf_stop_rx_stream(&rf); srslte_rf_flush_buffer(&rf); - if (srslte_ue_sync_init(&ue_sync, cell, srslte_rf_recv_wrapper, (void*) &rf)) { + if (srslte_ue_sync_init_multi(&ue_sync, cell, srslte_rf_recv_wrapper, 1, (void*) &rf)) { fprintf(stderr, "Error initiating ue_sync\n"); return -1; } - if (srslte_ue_dl_init(&ue_dl, cell)) { + if (srslte_ue_dl_init_multi(&ue_dl, cell, 1)) { fprintf(stderr, "Error initiating UE downlink processing module\n"); return -1; } @@ -280,7 +283,7 @@ int main(int argc, char **argv) { /* Main loop */ while ((sf_cnt < prog_args.nof_subframes || prog_args.nof_subframes == -1) && !go_exit) { - ret = srslte_ue_sync_get_buffer(&ue_sync, &sf_buffer); + ret = srslte_ue_sync_zerocopy_multi(&ue_sync, sf_buffer); if (ret < 0) { fprintf(stderr, "Error calling srslte_ue_sync_work()\n"); } @@ -292,7 +295,7 @@ int main(int argc, char **argv) { case DECODE_MIB: if (srslte_ue_sync_get_sfidx(&ue_sync) == 0) { srslte_pbch_decode_reset(&ue_mib.pbch); - n = srslte_ue_mib_decode(&ue_mib, sf_buffer, bch_payload, NULL, &sfn_offset); + n = srslte_ue_mib_decode(&ue_mib, sf_buffer[0], bch_payload, NULL, &sfn_offset); if (n < 0) { fprintf(stderr, "Error decoding UE MIB\n"); return -1; @@ -307,7 +310,7 @@ int main(int argc, char **argv) { case DECODE_SIB: /* We are looking for SI Blocks, search only in appropiate places */ if ((srslte_ue_sync_get_sfidx(&ue_sync) == 5 && (sfn%2)==0)) { - n = srslte_ue_dl_decode(&ue_dl, sf_buffer, data, sfn*10+srslte_ue_sync_get_sfidx(&ue_sync)); + n = srslte_ue_dl_decode_multi(&ue_dl, sf_buffer, data, sfn*10+srslte_ue_sync_get_sfidx(&ue_sync)); if (n < 0) { fprintf(stderr, "Error decoding UE DL\n");fflush(stdout); return -1; @@ -329,11 +332,11 @@ int main(int argc, char **argv) { if (srslte_ue_sync_get_sfidx(&ue_sync) == 5) { /* Run FFT for all subframe data */ - srslte_ofdm_rx_sf(&fft, sf_buffer, sf_symbols); + srslte_ofdm_rx_sf(&fft, sf_buffer[0], sf_symbols); srslte_chest_dl_estimate(&chest, sf_symbols, ce, srslte_ue_sync_get_sfidx(&ue_sync)); - rssi = SRSLTE_VEC_EMA(srslte_vec_avg_power_cf(sf_buffer,SRSLTE_SF_LEN(srslte_symbol_sz(cell.nof_prb))),rssi,0.05); + rssi = SRSLTE_VEC_EMA(srslte_vec_avg_power_cf(sf_buffer[0],SRSLTE_SF_LEN(srslte_symbol_sz(cell.nof_prb))),rssi,0.05); rssi_utra = SRSLTE_VEC_EMA(srslte_chest_dl_get_rssi(&chest),rssi_utra,0.05); rsrq = SRSLTE_VEC_EMA(srslte_chest_dl_get_rsrq(&chest),rsrq,0.05); rsrp = SRSLTE_VEC_EMA(srslte_chest_dl_get_rsrp(&chest),rsrp,0.05); @@ -345,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); } @@ -354,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 92% rename from srslte/examples/cell_search.c rename to lib/examples/cell_search.c index 02c3d8ada..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 @@ -120,9 +120,13 @@ void parse_args(int argc, char **argv) { } } -int srslte_rf_recv_wrapper(void *h, void *data, uint32_t nsamples, srslte_timestamp_t *t) { +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((srslte_rf_t*) h, data, nsamples, 1); + void *ptr[SRSLTE_MAX_PORTS]; + for (int i=0;ifile_offset_freq = 0; args->rf_args = ""; args->rf_freq = -1.0; + args->rf_nof_rx_ant = 1; #ifdef ENABLE_AGC_DEFAULT args->rf_gain = -1.0; #else @@ -122,12 +126,15 @@ 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) { printf("Usage: %s [agpPoOcildDnruv] -f rx_frequency (in Hz) | -i input_file\n", prog); #ifndef DISABLE_RF printf("\t-a RF args [Default %s]\n", args->rf_args); + printf("\t-A Number of RX antennas [Default %d]\n", args->rf_nof_rx_ant); #ifdef ENABLE_AGC_DEFAULT printf("\t-g RF fix RX gain [Default AGC]\n"); #else @@ -152,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); @@ -163,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, "aoglipPcOCtdDnvrfuUsS")) != -1) { + while ((opt = getopt(argc, argv, "aAoglipPcOCtdDnvrfuUsSZy")) != -1) { switch (opt) { case 'i': args->input_file_name = argv[optind]; @@ -186,6 +194,9 @@ void parse_args(prog_args_t *args, int argc, char **argv) { case 'a': args->rf_args = argv[optind]; break; + case 'A': + args->rf_nof_rx_ant = atoi(argv[optind]); + break; case 'g': args->rf_gain = atof(argv[optind]); break; @@ -228,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); @@ -252,10 +269,16 @@ void sig_int_handler(int signo) } } +cf_t *sf_buffer[2] = {NULL, NULL}; + #ifndef DISABLE_RF -int srslte_rf_recv_wrapper(void *h, void *data, uint32_t nsamples, srslte_timestamp_t *t) { +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, nsamples, 1); + void *ptr[SRSLTE_MAX_PORTS]; + for (int i=0;i -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); @@ -311,8 +352,8 @@ int main(int argc, char **argv) { #ifndef DISABLE_RF if (!prog_args.input_file_name) { - printf("Opening RF device...\n"); - if (srslte_rf_open(&rf, prog_args.rf_args)) { + printf("Opening RF device with %d RX antennas...\n", prog_args.rf_nof_rx_ant); + if (srslte_rf_open_multi(&rf, prog_args.rf_args, prog_args.rf_nof_rx_ant)) { fprintf(stderr, "Error opening rf\n"); exit(-1); } @@ -344,7 +385,7 @@ int main(int argc, char **argv) { uint32_t ntrial=0; do { - ret = rf_search_and_decode_mib(&rf, &cell_detect_config, prog_args.force_N_id_2, &cell, &cfo); + ret = rf_search_and_decode_mib(&rf, prog_args.rf_nof_rx_ant, &cell_detect_config, prog_args.force_N_id_2, &cell, &cfo); if (ret < 0) { fprintf(stderr, "Error searching for cell\n"); exit(-1); @@ -354,8 +395,13 @@ int main(int argc, char **argv) { } while (ret == 0 && !go_exit); if (go_exit) { + srslte_rf_close(&rf); exit(0); } + + srslte_rf_stop_rx_stream(&rf); + srslte_rf_flush_buffer(&rf); + /* set sampling frequency */ int srate = srslte_sampling_freq_hz(cell.nof_prb); if (srate != -1) { @@ -376,8 +422,6 @@ int main(int argc, char **argv) { } INFO("Stopping RF and flushing buffer...\r",0); - srslte_rf_stop_rx_stream(&rf); - srslte_rf_flush_buffer(&rf); } #endif @@ -399,7 +443,19 @@ int main(int argc, char **argv) { } else { #ifndef DISABLE_RF - if (srslte_ue_sync_init(&ue_sync, cell, srslte_rf_recv_wrapper, (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); } @@ -411,11 +467,15 @@ int main(int argc, char **argv) { exit(-1); } - if (srslte_ue_dl_init(&ue_dl, cell)) { // This is the User RNTI + if (srslte_ue_dl_init_multi(&ue_dl, cell, prog_args.rf_nof_rx_ant)) { // This is the User RNTI fprintf(stderr, "Error initiating UE downlink processing module\n"); exit(-1); } + for (int i=0;i #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 90% rename from srslte/examples/usrp_capture_sync.c rename to lib/examples/usrp_capture_sync.c index b7d7229d3..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; @@ -98,13 +98,13 @@ void parse_args(int argc, char **argv) { } } -int srslte_rf_recv_wrapper(void *h, void *data, uint32_t nsamples, srslte_timestamp_t *t) { +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, nsamples, 1); + return srslte_rf_recv(h, data[0], nsamples, 1); } int main(int argc, char **argv) { - cf_t *buffer; + cf_t *buffer[SRSLTE_MAX_PORTS] = {NULL, NULL}; int n; srslte_rf_t rf; srslte_filesink_t sink; @@ -124,6 +124,8 @@ int main(int argc, char **argv) { } srslte_rf_set_master_clock_rate(&rf, 30.72e6); + buffer[0] = srslte_vec_malloc(3*sizeof(cf_t)*SRSLTE_SF_LEN_PRB(100)); + sigset_t sigset; sigemptyset(&sigset); sigaddset(&sigset, SIGINT); @@ -156,7 +158,7 @@ int main(int argc, char **argv) { cell.nof_prb = nof_prb; cell.nof_ports = 1; - if (srslte_ue_sync_init(&ue_sync, cell, srslte_rf_recv_wrapper, (void*) &rf)) { + if (srslte_ue_sync_init_multi(&ue_sync, cell, srslte_rf_recv_wrapper, 1, (void*) &rf)) { fprintf(stderr, "Error initiating ue_sync\n"); exit(-1); } @@ -167,7 +169,7 @@ int main(int argc, char **argv) { while((subframe_count < nof_subframes || nof_subframes == -1) && !stop_capture) { - n = srslte_ue_sync_get_buffer(&ue_sync, &buffer); + n = srslte_ue_sync_zerocopy_multi(&ue_sync, buffer); if (n < 0) { fprintf(stderr, "Error receiving samples\n"); exit(-1); @@ -179,7 +181,7 @@ int main(int argc, char **argv) { } } else { printf("Writing to file %6d subframes...\r", subframe_count); - srslte_filesink_write(&sink, buffer, SRSLTE_SF_LEN_PRB(nof_prb)); + srslte_filesink_write(&sink, buffer[0], SRSLTE_SF_LEN_PRB(nof_prb)); subframe_count++; } } 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 81% rename from srslte/include/srslte/ch_estimation/chest_dl.h rename to lib/include/srslte/phy/ch_estimation/chest_dl.h index a4afa1d84..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 { @@ -76,9 +76,9 @@ typedef struct { srslte_interp_linsrslte_vec_t srslte_interp_linvec; srslte_interp_lin_t srslte_interp_lin; - float rssi[SRSLTE_MAX_PORTS]; - float rsrp[SRSLTE_MAX_PORTS]; - float noise_estimate[SRSLTE_MAX_PORTS]; + float rssi[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; + float rsrp[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; + float noise_estimate[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; /* Use PSS for noise estimation in LS linear interpolation mode */ cf_t pss_signal[SRSLTE_PSS_LEN]; @@ -86,6 +86,7 @@ typedef struct { cf_t tmp_pss_noisy[SRSLTE_PSS_LEN]; srslte_chest_dl_noise_alg_t noise_alg; + int last_nof_antennas; } srslte_chest_dl_t; @@ -105,6 +106,12 @@ SRSLTE_API void srslte_chest_dl_set_smooth_filter3_coeff(srslte_chest_dl_t* q, SRSLTE_API void srslte_chest_dl_set_noise_alg(srslte_chest_dl_t *q, srslte_chest_dl_noise_alg_t noise_estimation_alg); +SRSLTE_API int srslte_chest_dl_estimate_multi(srslte_chest_dl_t *q, + cf_t *input[SRSLTE_MAX_PORTS], + cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], + uint32_t sf_idx, + uint32_t nof_rx_antennas); + SRSLTE_API int srslte_chest_dl_estimate(srslte_chest_dl_t *q, cf_t *input, cf_t *ce[SRSLTE_MAX_PORTS], @@ -114,7 +121,8 @@ SRSLTE_API int srslte_chest_dl_estimate_port(srslte_chest_dl_t *q, cf_t *input, cf_t *ce, uint32_t sf_idx, - uint32_t port_id); + uint32_t port_id, + uint32_t rxant_id); SRSLTE_API float srslte_chest_dl_get_noise_estimate(srslte_chest_dl_t *q); diff --git a/srslte/include/srslte/ch_estimation/chest_ul.h b/lib/include/srslte/phy/ch_estimation/chest_ul.h similarity index 91% rename from srslte/include/srslte/ch_estimation/chest_ul.h rename to lib/include/srslte/phy/ch_estimation/chest_ul.h index 90a706cc7..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; @@ -56,6 +56,7 @@ typedef struct { bool dmrs_signal_configured; cf_t *pilot_estimates; + cf_t *pilot_estimates_tmp[4]; cf_t *pilot_recv_signal; cf_t *pilot_known_signal; cf_t *tmp_noise; @@ -105,7 +106,8 @@ SRSLTE_API int srslte_chest_ul_estimate_pucch(srslte_chest_ul_t *q, cf_t *ce, srslte_pucch_format_t format, uint32_t n_pucch, - uint32_t sf_idx); + uint32_t sf_idx, + uint8_t *pucch2_ack_bits); SRSLTE_API float srslte_chest_ul_get_noise_estimate(srslte_chest_ul_t *q); 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 95% rename from srslte/include/srslte/common/phy_common.h rename to lib/include/srslte/phy/common/phy_common.h index 81cce7b66..bfb2a993a 100644 --- a/srslte/include/srslte/common/phy_common.h +++ b/lib/include/srslte/phy/common/phy_common.h @@ -50,7 +50,7 @@ #define SRSLTE_PC_MAX 23 // Maximum TX power for Category 1 UE (in dBm) #define SRSLTE_MAX_PORTS 4 -#define SRSLTE_MAX_LAYERS 8 +#define SRSLTE_MAX_LAYERS 4 #define SRSLTE_MAX_CODEWORDS 2 #define SRSLTE_LTE_CRC24A 0x1864CFB @@ -125,7 +125,7 @@ typedef enum {SRSLTE_CP_NORM, SRSLTE_CP_EXT} srslte_cp_t; || l == SRSLTE_CP_NSYMB(cp) - 3) -#define SRSLTE_NOF_LTE_BANDS 29 +#define SRSLTE_NOF_LTE_BANDS 38 #define SRSLTE_DEFAULT_MAX_FRAMES_PBCH 500 #define SRSLTE_DEFAULT_MAX_FRAMES_PSS 10 @@ -158,7 +158,6 @@ typedef enum { typedef struct SRSLTE_API { uint32_t nof_prb; uint32_t nof_ports; - uint32_t bw_idx; uint32_t id; srslte_cp_t cp; srslte_phich_length_t phich_length; @@ -168,7 +167,8 @@ typedef struct SRSLTE_API { typedef enum SRSLTE_API { SRSLTE_MIMO_TYPE_SINGLE_ANTENNA, SRSLTE_MIMO_TYPE_TX_DIVERSITY, - SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX + SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX, + SRSLTE_MIMO_TYPE_CDD } srslte_mimo_type_t; typedef enum SRSLTE_API { @@ -246,7 +246,13 @@ SRSLTE_API char *srslte_mod_string(srslte_mod_t mod); SRSLTE_API uint32_t srslte_mod_bits_x_symbol(srslte_mod_t mod); -SRSLTE_API float srslte_band_fd(uint32_t earfcn); +SRSLTE_API int srslte_band_get_band(uint32_t dl_earfcn); + +SRSLTE_API float srslte_band_fd(uint32_t dl_earfcn); + +SRSLTE_API float srslte_band_fu(uint32_t ul_earfcn); + +SRSLTE_API uint32_t srslte_band_ul_earfcn(uint32_t dl_earfcn); SRSLTE_API int srslte_band_get_fd_band(uint32_t band, srslte_earfcn_t *earfcn, 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 78% rename from srslte/include/srslte/enb/enb_dl.h rename to lib/include/srslte/phy/enb/enb_dl.h index a95c6f824..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/enb/enb_ul.h" - -#include "srslte/utils/vector.h" -#include "srslte/utils/debug.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/phy/enb/enb_ul.h" + +#include "srslte/phy/utils/vector.h" +#include "srslte/phy/utils/debug.h" #include "srslte/config.h" @@ -87,12 +87,12 @@ typedef struct SRSLTE_API { float sss_signal0[SRSLTE_SSS_LEN]; float sss_signal5[SRSLTE_SSS_LEN]; - uint32_t nof_rnti; + float tx_amp; } srslte_enb_dl_t; typedef struct { - int rnti_idx; + uint16_t rnti; srslte_ra_dl_dci_t grant; srslte_dci_location_t location; srslte_softbuffer_tx_t *softbuffer; @@ -100,20 +100,24 @@ typedef struct { } srslte_enb_dl_pdsch_t; typedef struct { + uint16_t rnti; uint8_t ack; - int rnti_idx; + uint32_t n_prb_lowest; + uint32_t n_dmrs; } srslte_enb_dl_phich_t; /* This function shall be called just after the initial synchronization */ SRSLTE_API int srslte_enb_dl_init(srslte_enb_dl_t *q, - srslte_cell_t cell, - uint32_t nof_rntis); + srslte_cell_t cell); SRSLTE_API void srslte_enb_dl_free(srslte_enb_dl_t *q); SRSLTE_API void srslte_enb_dl_set_cfi(srslte_enb_dl_t *q, uint32_t cfi); +SRSLTE_API void srslte_enb_dl_set_amp(srslte_enb_dl_t *q, + float amp); + SRSLTE_API void srslte_enb_dl_clear_sf(srslte_enb_dl_t *q); SRSLTE_API void srslte_enb_dl_put_sync(srslte_enb_dl_t *q, @@ -140,17 +144,16 @@ SRSLTE_API void srslte_enb_dl_put_base(srslte_enb_dl_t *q, SRSLTE_API void srslte_enb_dl_gen_signal(srslte_enb_dl_t *q, cf_t *signal_buffer); -SRSLTE_API int srslte_enb_dl_cfg_rnti(srslte_enb_dl_t *q, - uint32_t idx, +SRSLTE_API int srslte_enb_dl_add_rnti(srslte_enb_dl_t *q, uint16_t rnti); -SRSLTE_API int srslte_enb_dl_rem_rnti(srslte_enb_dl_t *q, - uint32_t idx); +SRSLTE_API void srslte_enb_dl_rem_rnti(srslte_enb_dl_t *q, + uint16_t rnti); SRSLTE_API int srslte_enb_dl_put_pdsch(srslte_enb_dl_t *q, srslte_ra_dl_grant_t *grant, srslte_softbuffer_tx_t *softbuffer, - uint32_t rnti_idx, + uint16_t rnti, uint32_t rv_idx, uint32_t sf_idx, uint8_t *data); @@ -159,13 +162,13 @@ SRSLTE_API int srslte_enb_dl_put_pdcch_dl(srslte_enb_dl_t *q, srslte_ra_dl_dci_t *grant, srslte_dci_format_t format, srslte_dci_location_t location, - uint32_t rnti_idx, + uint16_t rnti, uint32_t sf_idx); SRSLTE_API int srslte_enb_dl_put_pdcch_ul(srslte_enb_dl_t *q, srslte_ra_ul_dci_t *grant, srslte_dci_location_t location, - uint32_t rnti_idx, + uint16_t rnti, uint32_t sf_idx); diff --git a/srslte/include/srslte/enb/enb_ul.h b/lib/include/srslte/phy/enb/enb_ul.h similarity index 79% rename from srslte/include/srslte/enb/enb_ul.h rename to lib/include/srslte/phy/enb/enb_ul.h index 60eb0e50f..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" @@ -58,9 +58,16 @@ typedef struct { uint32_t n_dmrs; } srslte_enb_ul_phich_info_t; +typedef struct { + bool uci_cfg_en; + bool srs_cfg_en; + srslte_uci_cfg_t uci_cfg; + srslte_refsignal_srs_cfg_t srs_cfg; + srslte_pucch_sched_t pucch_sched; +} srslte_enb_ul_user_t; + typedef struct SRSLTE_API { srslte_cell_t cell; - uint32_t nof_rnti; cf_t *sf_symbols; cf_t *ce; @@ -77,24 +84,19 @@ typedef struct SRSLTE_API { srslte_pusch_hopping_cfg_t hopping_cfg; // Configuration for each user - bool *uci_cfg_en; - bool *srs_cfg_en; - srslte_uci_cfg_t *uci_cfg; - srslte_refsignal_srs_cfg_t *srs_cfg; - srslte_pucch_sched_t *pucch_sched; + srslte_enb_ul_user_t **users; } srslte_enb_ul_t; typedef struct { - int rnti_idx; + uint16_t rnti; srslte_ra_ul_dci_t grant; srslte_dci_location_t location; uint32_t rv_idx; uint32_t current_tx_nb; - bool needs_pdcch; uint8_t *data; srslte_softbuffer_rx_t *softbuffer; - + bool needs_pdcch; } srslte_enb_ul_pusch_t; /* This function shall be called just after the initial synchronization */ @@ -103,29 +105,27 @@ SRSLTE_API int srslte_enb_ul_init(srslte_enb_ul_t *q, srslte_prach_cfg_t* prach_cfg, srslte_refsignal_dmrs_pusch_cfg_t *pusch_cfg, srslte_pusch_hopping_cfg_t *hopping_cfg, - srslte_pucch_cfg_t *pucch_cfg, - uint32_t nof_rntis); + srslte_pucch_cfg_t *pucch_cfg); SRSLTE_API void srslte_enb_ul_free(srslte_enb_ul_t *q); -SRSLTE_API int srslte_enb_ul_cfg_rnti(srslte_enb_ul_t *q, - uint32_t idx, +SRSLTE_API int srslte_enb_ul_add_rnti(srslte_enb_ul_t *q, + uint16_t rnti); + +SRSLTE_API void srslte_enb_ul_rem_rnti(srslte_enb_ul_t *q, uint16_t rnti); -SRSLTE_API int srslte_enb_ul_cfg_ue(srslte_enb_ul_t *q, uint32_t idx, +SRSLTE_API int srslte_enb_ul_cfg_ue(srslte_enb_ul_t *q, uint16_t rnti, srslte_uci_cfg_t *uci_cfg, srslte_pucch_sched_t *pucch_sched, srslte_refsignal_srs_cfg_t *srs_cfg); -SRSLTE_API int srslte_enb_ul_rem_rnti(srslte_enb_ul_t *q, - uint32_t idx); - SRSLTE_API void srslte_enb_ul_fft(srslte_enb_ul_t *q, cf_t *signal_buffer); SRSLTE_API int srslte_enb_ul_get_pucch(srslte_enb_ul_t *q, - uint32_t rnti_idx, + uint16_t rnti, uint32_t pdcch_n_cce, uint32_t sf_rx, srslte_uci_data_t *uci_data); @@ -133,7 +133,7 @@ SRSLTE_API int srslte_enb_ul_get_pucch(srslte_enb_ul_t *q, SRSLTE_API int srslte_enb_ul_get_pusch(srslte_enb_ul_t *q, srslte_ra_ul_grant_t *grant, srslte_softbuffer_rx_t *softbuffer, - uint32_t rnti_idx, + uint16_t rnti, uint32_t rv_idx, uint32_t current_tx_nb, uint8_t *data, 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 95% rename from srslte/include/srslte/io/netsink.h rename to lib/include/srslte/phy/io/netsink.h index 154d33feb..3339716c1 100644 --- a/srslte/include/srslte/io/netsink.h +++ b/lib/include/srslte/phy/io/netsink.h @@ -59,8 +59,8 @@ typedef struct SRSLTE_API { }srslte_netsink_t; SRSLTE_API int srslte_netsink_init(srslte_netsink_t *q, - char *address, - int port, + const char *address, + uint16_t port, srslte_netsink_type_t type); SRSLTE_API void srslte_netsink_free(srslte_netsink_t *q); diff --git a/srslte/include/srslte/io/netsource.h b/lib/include/srslte/phy/io/netsource.h similarity index 95% rename from srslte/include/srslte/io/netsource.h rename to lib/include/srslte/phy/io/netsource.h index b581a1ef1..e10d8d644 100644 --- a/srslte/include/srslte/io/netsource.h +++ b/lib/include/srslte/phy/io/netsource.h @@ -60,8 +60,8 @@ typedef struct SRSLTE_API { }srslte_netsource_t; SRSLTE_API int srslte_netsource_init(srslte_netsource_t *q, - char *address, - int port, + const char *address, + uint16_t port, srslte_netsource_type_t type); SRSLTE_API void srslte_netsource_free(srslte_netsource_t *q); 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 63% rename from srslte/include/srslte/mimo/precoding.h rename to lib/include/srslte/phy/mimo/precoding.h index 3e95494b5..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 @@ -53,7 +53,14 @@ SRSLTE_API int srslte_precoding_single(cf_t *x, SRSLTE_API int srslte_precoding_diversity(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PORTS], - int nof_ports, int nof_symbols); + int nof_ports, + int nof_symbols); + +SRSLTE_API int srslte_precoding_cdd(cf_t *x[SRSLTE_MAX_LAYERS], + cf_t *y[SRSLTE_MAX_PORTS], + int nof_layers, + int nof_ports, + int nof_symbols); SRSLTE_API int srslte_precoding_type(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PORTS], @@ -70,12 +77,26 @@ SRSLTE_API int srslte_predecoding_single(cf_t *y, int nof_symbols, float noise_estimate); +SRSLTE_API int srslte_predecoding_single_multi(cf_t *y[SRSLTE_MAX_PORTS], + cf_t *h[SRSLTE_MAX_PORTS], + cf_t *x, + int nof_rxant, + int nof_symbols, + float noise_estimate); + SRSLTE_API int srslte_predecoding_diversity(cf_t *y, cf_t *h[SRSLTE_MAX_PORTS], cf_t *x[SRSLTE_MAX_LAYERS], int nof_ports, int nof_symbols); +SRSLTE_API int srslte_predecoding_diversity_multi(cf_t *y[SRSLTE_MAX_PORTS], + cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], + cf_t *x[SRSLTE_MAX_LAYERS], + int nof_rxant, + int nof_ports, + int nof_symbols); + SRSLTE_API int srslte_predecoding_type(cf_t *y, cf_t *h[SRSLTE_MAX_PORTS], cf_t *x[SRSLTE_MAX_LAYERS], @@ -85,4 +106,14 @@ SRSLTE_API int srslte_predecoding_type(cf_t *y, srslte_mimo_type_t type, float noise_estimate); +SRSLTE_API int srslte_predecoding_type_multi(cf_t *y[SRSLTE_MAX_PORTS], + cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], + cf_t *x[SRSLTE_MAX_LAYERS], + int nof_rxant, + int nof_ports, + int nof_layers, + int nof_symbols, + srslte_mimo_type_t type, + float noise_estimate); + #endif /* PRECODING_H_ */ 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 81% rename from srslte/include/srslte/phch/cqi.h rename to lib/include/srslte/phy/phch/cqi.h index 68ed8ca2a..f6857dfa0 100644 --- a/srslte/include/srslte/phch/cqi.h +++ b/lib/include/srslte/phy/phch/cqi.h @@ -38,9 +38,9 @@ #include #include "srslte/config.h" -#include "srslte/common/phy_common.h" +#include "srslte/phy/common/phy_common.h" -#define SRSLTE_CQI_MAX_BITS 20 +#define SRSLTE_CQI_MAX_BITS 64 typedef struct { bool configured; @@ -104,6 +104,8 @@ typedef struct { } srslte_cqi_value_t; +SRSLTE_API int srslte_cqi_size(srslte_cqi_value_t *value); + SRSLTE_API int srslte_cqi_value_pack(srslte_cqi_value_t *value, uint8_t buff[SRSLTE_CQI_MAX_BITS]); @@ -119,11 +121,28 @@ SRSLTE_API int srslte_cqi_format2_wideband_pack(srslte_cqi_format2_wideband_t *m SRSLTE_API int srslte_cqi_format2_subband_pack(srslte_cqi_format2_subband_t *msg, uint8_t buff[SRSLTE_CQI_MAX_BITS]); +SRSLTE_API int srslte_cqi_value_unpack(uint8_t buff[SRSLTE_CQI_MAX_BITS], + srslte_cqi_value_t *value); + +SRSLTE_API int srslte_cqi_hl_subband_unpack(uint8_t buff[SRSLTE_CQI_MAX_BITS], + srslte_cqi_hl_subband_t *msg); + +SRSLTE_API int srslte_cqi_ue_subband_unpack(uint8_t buff[SRSLTE_CQI_MAX_BITS], + srslte_cqi_ue_subband_t *msg); + +SRSLTE_API int srslte_cqi_format2_wideband_unpack(uint8_t buff[SRSLTE_CQI_MAX_BITS], + srslte_cqi_format2_wideband_t *msg); + +SRSLTE_API int srslte_cqi_format2_subband_unpack(uint8_t buff[SRSLTE_CQI_MAX_BITS], + srslte_cqi_format2_subband_t *msg); + SRSLTE_API bool srslte_cqi_send(uint32_t I_cqi_pmi, uint32_t tti); SRSLTE_API uint8_t srslte_cqi_from_snr(float snr); +SRSLTE_API float srslte_cqi_to_coderate(uint32_t cqi); + SRSLTE_API int srslte_cqi_hl_get_subband_size(int num_prbs); SRSLTE_API int srslte_cqi_hl_get_no_subbands(int num_prbs); diff --git a/srslte/include/srslte/phch/dci.h b/lib/include/srslte/phy/phch/dci.h similarity index 97% rename from srslte/include/srslte/phch/dci.h rename to lib/include/srslte/phy/phch/dci.h index b8e590516..6976a6b24 100644 --- a/srslte/include/srslte/phch/dci.h +++ b/lib/include/srslte/phy/phch/dci.h @@ -40,13 +40,15 @@ #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 #define SRSLTE_RAR_GRANT_LEN 20 +SRSLTE_API extern int harq_pid_len; + typedef enum { SRSLTE_DCI_FORMAT0 = 0, SRSLTE_DCI_FORMAT1, @@ -163,6 +165,7 @@ SRSLTE_API int srslte_dci_msg_pack_pdsch(srslte_ra_dl_dci_t *data, srslte_dci_format_t format, srslte_dci_msg_t *msg, uint32_t nof_prb, + uint32_t nof_ports, bool crc_is_crnti); SRSLTE_API int srslte_dci_msg_unpack_pdsch(srslte_dci_msg_t *msg, 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 71% rename from srslte/include/srslte/phch/pcfich.h rename to lib/include/srslte/phy/phch/pcfich.h index c9c790b62..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 @@ -51,12 +51,14 @@ typedef struct SRSLTE_API { srslte_cell_t cell; int nof_symbols; + + uint32_t nof_rx_antennas; /* handler to REGs resource mapper */ srslte_regs_t *regs; /* buffers */ - cf_t ce[SRSLTE_MAX_PORTS][PCFICH_RE]; + cf_t ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS][PCFICH_RE]; cf_t symbols[SRSLTE_MAX_PORTS][PCFICH_RE]; cf_t x[SRSLTE_MAX_PORTS][PCFICH_RE]; cf_t d[PCFICH_RE]; @@ -80,6 +82,11 @@ SRSLTE_API int srslte_pcfich_init(srslte_pcfich_t *q, srslte_regs_t *regs, srslte_cell_t cell); +SRSLTE_API int srslte_pcfich_init_multi(srslte_pcfich_t *q, + srslte_regs_t *regs, + srslte_cell_t cell, + uint32_t nof_rx_antennas); + SRSLTE_API void srslte_pcfich_free(srslte_pcfich_t *q); SRSLTE_API int srslte_pcfich_decode(srslte_pcfich_t *q, @@ -90,6 +97,14 @@ SRSLTE_API int srslte_pcfich_decode(srslte_pcfich_t *q, uint32_t *cfi, float *corr_result); +SRSLTE_API int srslte_pcfich_decode_multi(srslte_pcfich_t *q, + cf_t *sf_symbols[SRSLTE_MAX_PORTS], + cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], + float noise_estimate, + uint32_t subframe, + uint32_t *cfi, + float *corr_result); + SRSLTE_API int srslte_pcfich_encode(srslte_pcfich_t *q, uint32_t cfi, cf_t *sf_symbols[SRSLTE_MAX_PORTS], diff --git a/srslte/include/srslte/phch/pdcch.h b/lib/include/srslte/phy/phch/pdcch.h similarity index 81% rename from srslte/include/srslte/phch/pdcch.h rename to lib/include/srslte/phy/phch/pdcch.h index a2c6deb7f..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" @@ -63,11 +63,12 @@ typedef struct SRSLTE_API { uint32_t nof_regs; uint32_t nof_cce; uint32_t max_bits; - + uint32_t nof_rx_antennas; + srslte_regs_t *regs; /* buffers */ - cf_t *ce[SRSLTE_MAX_PORTS]; + cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; cf_t *symbols[SRSLTE_MAX_PORTS]; cf_t *x[SRSLTE_MAX_PORTS]; cf_t *d; @@ -87,12 +88,20 @@ SRSLTE_API int srslte_pdcch_init(srslte_pdcch_t *q, srslte_regs_t *regs, srslte_cell_t cell); +SRSLTE_API int srslte_pdcch_init_multi(srslte_pdcch_t *q, + srslte_regs_t *regs, + srslte_cell_t cell, + uint32_t nof_rx_antennas); + SRSLTE_API void srslte_pdcch_free(srslte_pdcch_t *q); SRSLTE_API void srslte_pdcch_set_cfi(srslte_pdcch_t *q, uint32_t cfi); +SRSLTE_API float srslte_pdcch_coderate(uint32_t nof_bits, + uint32_t l); + /* Encoding function */ SRSLTE_API int srslte_pdcch_encode(srslte_pdcch_t *q, srslte_dci_msg_t *msg, @@ -110,6 +119,13 @@ SRSLTE_API int srslte_pdcch_extract_llr(srslte_pdcch_t *q, uint32_t nsubframe, uint32_t cfi); +SRSLTE_API int srslte_pdcch_extract_llr_multi(srslte_pdcch_t *q, + cf_t *sf_symbols[SRSLTE_MAX_PORTS], + cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], + float noise_estimate, + uint32_t nsubframe, + uint32_t cfi); + /* Decoding functions: Try to decode a DCI message after calling srslte_pdcch_extract_llr */ SRSLTE_API int srslte_pdcch_decode_msg(srslte_pdcch_t *q, srslte_dci_msg_t *msg, diff --git a/srslte/include/srslte/phch/pdsch.h b/lib/include/srslte/phy/phch/pdsch.h similarity index 57% rename from srslte/include/srslte/phch/pdsch.h rename to lib/include/srslte/phy/phch/pdsch.h index b65260eac..7730d2fa1 100644 --- a/srslte/include/srslte/phch/pdsch.h +++ b/lib/include/srslte/phy/phch/pdsch.h @@ -36,28 +36,32 @@ #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]; +} srslte_pdsch_user_t; /* PDSCH object */ typedef struct SRSLTE_API { srslte_cell_t cell; + uint32_t nof_rx_antennas; + uint32_t max_re; - bool rnti_is_set; - uint16_t rnti; /* buffers */ // void buffers are shared for tx and rx - cf_t *ce[SRSLTE_MAX_PORTS]; + cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; cf_t *symbols[SRSLTE_MAX_PORTS]; cf_t *x[SRSLTE_MAX_PORTS]; cf_t *d; @@ -66,12 +70,8 @@ typedef struct SRSLTE_API { /* tx & rx objects */ srslte_modem_table_t mod[4]; - srslte_sequence_t seq[SRSLTE_NSUBFRAMES_X_FRAME]; - // This is to generate the scrambling seq for multiple CRNTIs - uint32_t nof_crnti; - srslte_sequence_t *seq_multi[SRSLTE_NSUBFRAMES_X_FRAME]; - uint16_t *rnti_multi; + srslte_pdsch_user_t **users; srslte_sch_t dl_sch; @@ -80,20 +80,20 @@ typedef struct SRSLTE_API { SRSLTE_API int srslte_pdsch_init(srslte_pdsch_t *q, srslte_cell_t cell); +SRSLTE_API int srslte_pdsch_init_multi(srslte_pdsch_t *q, + srslte_cell_t cell, + uint32_t nof_rx_antennas); + SRSLTE_API void srslte_pdsch_free(srslte_pdsch_t *q); SRSLTE_API int srslte_pdsch_set_rnti(srslte_pdsch_t *q, uint16_t rnti); -SRSLTE_API int srslte_pdsch_init_rnti_multi(srslte_pdsch_t *q, - uint32_t nof_rntis); +SRSLTE_API void srslte_pdsch_free_rnti(srslte_pdsch_t *q, + uint16_t rnti); -SRSLTE_API int srslte_pdsch_set_rnti_multi(srslte_pdsch_t *q, - uint32_t idx, - uint16_t rnti); - -SRSLTE_API uint16_t srslte_pdsch_get_rnti_multi(srslte_pdsch_t *q, - uint32_t idx); +SRSLTE_API float srslte_pdsch_coderate(uint32_t tbs, + uint32_t nof_re); SRSLTE_API int srslte_pdsch_cfg(srslte_pdsch_cfg_t *cfg, srslte_cell_t cell, @@ -106,38 +106,26 @@ SRSLTE_API int srslte_pdsch_encode(srslte_pdsch_t *q, srslte_pdsch_cfg_t *cfg, srslte_softbuffer_tx_t *softbuffer, uint8_t *data, + uint16_t rnti, cf_t *sf_symbols[SRSLTE_MAX_PORTS]); -SRSLTE_API int srslte_pdsch_encode_rnti_idx(srslte_pdsch_t *q, - srslte_pdsch_cfg_t *cfg, - srslte_softbuffer_tx_t *softbuffer, - uint8_t *data, - uint32_t rnti_idx, - cf_t *sf_symbols[SRSLTE_MAX_PORTS]); - -SRSLTE_API int srslte_pdsch_encode_rnti(srslte_pdsch_t *q, - srslte_pdsch_cfg_t *cfg, - srslte_softbuffer_tx_t *softbuffer, - uint8_t *data, - uint16_t rnti, - cf_t *sf_symbols[SRSLTE_MAX_PORTS]); - SRSLTE_API int srslte_pdsch_decode(srslte_pdsch_t *q, srslte_pdsch_cfg_t *cfg, srslte_softbuffer_rx_t *softbuffer, cf_t *sf_symbols, cf_t *ce[SRSLTE_MAX_PORTS], float noise_estimate, + uint16_t rnti, uint8_t *data); -SRSLTE_API int srslte_pdsch_decode_rnti(srslte_pdsch_t *q, - srslte_pdsch_cfg_t *cfg, - srslte_softbuffer_rx_t *softbuffer, - cf_t *sf_symbols, - cf_t *ce[SRSLTE_MAX_PORTS], - float noise_estimate, - uint16_t rnti, - uint8_t *data); +SRSLTE_API int srslte_pdsch_decode_multi(srslte_pdsch_t *q, + srslte_pdsch_cfg_t *cfg, + srslte_softbuffer_rx_t *softbuffer, + cf_t *sf_symbols[SRSLTE_MAX_PORTS], + cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], + float noise_estimate, + uint16_t rnti, + uint8_t *data); SRSLTE_API float srslte_pdsch_average_noi(srslte_pdsch_t *q); 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 75% rename from srslte/include/srslte/phch/phich.h rename to lib/include/srslte/phy/phch/phich.h index e4e6f0175..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" @@ -62,12 +62,14 @@ typedef struct SRSLTE_API { srslte_cell_t cell; + uint32_t nof_rx_antennas; + /* handler to REGs resource mapper */ srslte_regs_t *regs; /* buffers */ - cf_t ce[SRSLTE_MAX_PORTS][SRSLTE_PHICH_MAX_NSYMB]; - cf_t symbols[SRSLTE_MAX_PORTS][SRSLTE_PHICH_MAX_NSYMB]; + cf_t ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS][SRSLTE_PHICH_MAX_NSYMB]; + cf_t sf_symbols[SRSLTE_MAX_PORTS][SRSLTE_PHICH_MAX_NSYMB]; cf_t x[SRSLTE_MAX_PORTS][SRSLTE_PHICH_MAX_NSYMB]; cf_t d[SRSLTE_PHICH_MAX_NSYMB]; cf_t d0[SRSLTE_PHICH_MAX_NSYMB]; @@ -87,6 +89,11 @@ SRSLTE_API int srslte_phich_init(srslte_phich_t *q, srslte_regs_t *regs, srslte_cell_t cell); +SRSLTE_API int srslte_phich_init_multi(srslte_phich_t *q, + srslte_regs_t *regs, + srslte_cell_t cell, + uint32_t nof_rx_antennas); + SRSLTE_API void srslte_phich_free(srslte_phich_t *q); SRSLTE_API void srslte_phich_calc(srslte_phich_t *q, @@ -105,6 +112,16 @@ SRSLTE_API int srslte_phich_decode(srslte_phich_t *q, uint8_t *ack, float *distance); +SRSLTE_API int srslte_phich_decode_multi(srslte_phich_t *q, + cf_t *slot_symbols[SRSLTE_MAX_PORTS], + cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], + float noise_estimate, + uint32_t ngroup, + uint32_t nseq, + uint32_t nsubframe, + uint8_t *ack, + float *distance); + SRSLTE_API int srslte_phich_encode(srslte_phich_t *q, uint8_t ack, uint32_t ngroup, diff --git a/srslte/include/srslte/phch/prach.h b/lib/include/srslte/phy/phch/prach.h similarity index 97% rename from srslte/include/srslte/phch/prach.h rename to lib/include/srslte/phy/phch/prach.h index 346447e8b..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. @@ -65,6 +65,7 @@ typedef struct SRSLTE_API { uint32_t N_cs; // Cyclic shift size uint32_t N_seq; // Preamble length float T_seq; // Preamble length in seconds + float T_tot; // Total sequence length in seconds uint32_t N_cp; // Cyclic prefix length // Generated tables diff --git a/srslte/include/srslte/phch/pucch.h b/lib/include/srslte/phy/phch/pucch.h similarity index 91% rename from srslte/include/srslte/phch/pucch.h rename to lib/include/srslte/phy/phch/pucch.h index f99ecfe51..3542dc53f 100644 --- a/srslte/include/srslte/phch/pucch.h +++ b/lib/include/srslte/phy/phch/pucch.h @@ -36,13 +36,14 @@ #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 #define SRSLTE_PUCCH_MAX_BITS SRSLTE_CQI_MAX_BITS #define SRSLTE_PUCCH_MAX_SYMBOLS 120 @@ -78,13 +79,20 @@ typedef struct SRSLTE_API { bool srs_simul_ack; } srslte_pucch_cfg_t; +typedef struct { + srslte_sequence_t seq_f2[SRSLTE_NSUBFRAMES_X_FRAME]; +} srslte_pucch_user_t; + /* PUCCH object */ typedef struct SRSLTE_API { srslte_cell_t cell; srslte_pucch_cfg_t pucch_cfg; - srslte_sequence_t seq_f2[SRSLTE_NSUBFRAMES_X_FRAME]; srslte_modem_table_t mod; + srslte_uci_cqi_pucch_t cqi; + + srslte_pucch_user_t **users; + uint8_t bits_scram[SRSLTE_PUCCH_MAX_BITS]; cf_t d[SRSLTE_PUCCH_MAX_BITS/2]; uint32_t n_cs_cell[SRSLTE_NSLOTS_X_FRAME][SRSLTE_CP_NORM_NSYMB]; @@ -95,13 +103,14 @@ typedef struct SRSLTE_API { cf_t *z_tmp; cf_t *ce; - bool rnti_is_set; bool shortened; bool group_hopping_en; float threshold_format1; float threshold_format1a; float last_corr; + uint32_t last_n_prb; + uint32_t last_n_pucch; }srslte_pucch_t; @@ -122,6 +131,9 @@ SRSLTE_API void srslte_pucch_set_threshold(srslte_pucch_t *q, SRSLTE_API int srslte_pucch_set_crnti(srslte_pucch_t *q, uint16_t c_rnti); +SRSLTE_API void srslte_pucch_clear_rnti(srslte_pucch_t *q, + uint16_t rnti); + SRSLTE_API uint32_t srslte_pucch_nof_symbols(srslte_pucch_cfg_t *cfg, srslte_pucch_format_t format, bool shortened); @@ -132,6 +144,7 @@ SRSLTE_API int srslte_pucch_encode(srslte_pucch_t *q, srslte_pucch_format_t format, uint32_t n_pucch, // n_pucch_1 or n_pucch_2 depending on format uint32_t sf_idx, + uint16_t rnti, uint8_t bits[SRSLTE_PUCCH_MAX_BITS], cf_t *sf_symbols); @@ -139,6 +152,7 @@ SRSLTE_API int srslte_pucch_decode(srslte_pucch_t *q, srslte_pucch_format_t format, uint32_t n_pucch, // n_pucch_1 or n_pucch_2 depending on format uint32_t sf_idx, + uint16_t rnti, cf_t *sf_symbols, cf_t *ce, float noise_estimate, diff --git a/srslte/include/srslte/phch/pusch.h b/lib/include/srslte/phy/phch/pusch.h similarity index 50% rename from srslte/include/srslte/phch/pusch.h rename to lib/include/srslte/phy/phch/pusch.h index d8a5f3f53..bf04a4781 100644 --- a/srslte/include/srslte/phch/pusch.h +++ b/lib/include/srslte/phy/phch/pusch.h @@ -36,24 +36,21 @@ #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 - - - typedef struct { enum { SRSLTE_PUSCH_HOP_MODE_INTER_SF = 1, @@ -63,13 +60,15 @@ typedef struct { uint32_t n_sb; } srslte_pusch_hopping_cfg_t; +typedef struct { + srslte_sequence_t seq[SRSLTE_NSUBFRAMES_X_FRAME]; +} srslte_pusch_user_t; + /* PUSCH object */ typedef struct SRSLTE_API { srslte_cell_t cell; uint32_t max_re; - bool rnti_is_set; - uint16_t rnti; srslte_dft_precoding_t dft_precoding; @@ -84,13 +83,11 @@ typedef struct SRSLTE_API { /* tx & rx objects */ srslte_modem_table_t mod[4]; - srslte_sequence_t seq[SRSLTE_NSUBFRAMES_X_FRAME]; srslte_sequence_t seq_type2_fo; // This is to generate the scrambling seq for multiple CRNTIs - uint32_t nof_crnti; - srslte_sequence_t *seq_multi[SRSLTE_NSUBFRAMES_X_FRAME]; - uint16_t *rnti_multi; + srslte_pusch_user_t **users; + srslte_sequence_t tmp_seq; srslte_sch_t ul_sch; bool shortened; @@ -116,44 +113,16 @@ SRSLTE_API int srslte_pusch_cfg(srslte_pusch_t *q, SRSLTE_API int srslte_pusch_set_rnti(srslte_pusch_t *q, uint16_t rnti); -SRSLTE_API int srslte_pusch_init_rnti_multi(srslte_pusch_t *q, - uint32_t nof_rntis); - -SRSLTE_API int srslte_pusch_set_rnti_multi(srslte_pusch_t *q, - uint32_t idx, - uint16_t rnti); - -SRSLTE_API uint16_t srslte_pusch_get_rnti_multi(srslte_pusch_t *q, - uint32_t idx); - +SRSLTE_API void srslte_pusch_clear_rnti(srslte_pusch_t *q, + uint16_t rnti); SRSLTE_API int srslte_pusch_encode(srslte_pusch_t *q, srslte_pusch_cfg_t *cfg, srslte_softbuffer_tx_t *softbuffer, uint8_t *data, - cf_t *sf_symbols); - -SRSLTE_API int srslte_pusch_encode_rnti(srslte_pusch_t *q, - srslte_pusch_cfg_t *cfg, - srslte_softbuffer_tx_t *softbuffer, - uint8_t *data, - uint16_t rnti, - cf_t *sf_symbols); - -SRSLTE_API int srslte_pusch_uci_encode(srslte_pusch_t *q, - srslte_pusch_cfg_t *cfg, - srslte_softbuffer_tx_t *softbuffer, - uint8_t *data, srslte_uci_data_t uci_data, - cf_t *sf_symbols); - -SRSLTE_API int srslte_pusch_uci_encode_rnti(srslte_pusch_t *q, - srslte_pusch_cfg_t *cfg, - srslte_softbuffer_tx_t *softbuffer, - uint8_t *data, - srslte_uci_data_t uci_data, - uint16_t rnti, - cf_t *sf_symbols); + uint16_t rnti, + cf_t *sf_symbols); SRSLTE_API int srslte_pusch_decode(srslte_pusch_t *q, srslte_pusch_cfg_t *cfg, @@ -161,26 +130,9 @@ SRSLTE_API int srslte_pusch_decode(srslte_pusch_t *q, cf_t *sf_symbols, cf_t *ce, float noise_estimate, - uint8_t *data); - -SRSLTE_API int srslte_pusch_uci_decode(srslte_pusch_t *q, - srslte_pusch_cfg_t *cfg, - srslte_softbuffer_rx_t *softbuffer, - cf_t *sf_symbols, - cf_t *ce, - float noise_estimate, - uint8_t *data, - srslte_uci_data_t *uci_data); - -SRSLTE_API int srslte_pusch_uci_decode_rnti_idx(srslte_pusch_t *q, - srslte_pusch_cfg_t *cfg, - srslte_softbuffer_rx_t *softbuffer, - cf_t *sf_symbols, - cf_t *ce, - float noise_estimate, - uint32_t rnti_idx, - uint8_t *data, - srslte_uci_data_t *uci_data); + uint16_t rnti, + uint8_t *data, + srslte_uci_data_t *uci_data); SRSLTE_API float srslte_pusch_average_noi(srslte_pusch_t *q); 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 92% rename from srslte/include/srslte/phch/ra.h rename to lib/include/srslte/phy/phch/ra.h index b32f759b2..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 @@ -106,6 +106,7 @@ typedef struct SRSLTE_API { uint32_t Qm2; srslte_ra_mcs_t mcs; srslte_ra_mcs_t mcs2; + uint32_t nof_tb; } srslte_ra_dl_grant_t; /** Unpacked DCI message for DL grant */ @@ -132,7 +133,9 @@ typedef struct SRSLTE_API { bool pconf; bool power_offset; - uint32_t nof_tb; + uint8_t tpc_pucch; + + bool tb_en[2]; bool dci_is_1a; bool dci_is_1c; @@ -179,7 +182,7 @@ typedef struct SRSLTE_API { uint32_t n_dmrs; bool ndi; bool cqi_request; - uint32_t tpc_pusch; + uint8_t tpc_pusch; } srslte_ra_ul_dci_t; @@ -206,6 +209,10 @@ SRSLTE_API void srslte_ra_dl_grant_to_nbits(srslte_ra_dl_grant_t *grant, uint32_t sf_idx, srslte_ra_nbits_t *nbits); +SRSLTE_API uint32_t srslte_ra_dl_approx_nof_re(srslte_cell_t cell, + uint32_t nof_prb, + uint32_t nof_ctrl_symbols); + SRSLTE_API uint32_t srslte_ra_dl_grant_nof_re(srslte_ra_dl_grant_t *grant, srslte_cell_t cell, uint32_t sf_idx, @@ -222,13 +229,19 @@ SRSLTE_API void srslte_ra_ul_grant_to_nbits(srslte_ra_ul_grant_t *grant, uint32_t N_srs, srslte_ra_nbits_t *nbits); -SRSLTE_API int srslte_ul_dci_to_grant_prb_allocation(srslte_ra_ul_dci_t *dci, +SRSLTE_API int srslte_ra_ul_dci_to_grant_prb_allocation(srslte_ra_ul_dci_t *dci, srslte_ra_ul_grant_t *grant, uint32_t n_rb_ho, uint32_t nof_prb); +SRSLTE_API int srslte_ra_dl_dci_to_grant_prb_allocation(srslte_ra_dl_dci_t *dci, + srslte_ra_dl_grant_t *grant, + uint32_t nof_prb); + SRSLTE_API int srslte_ra_tbs_idx_from_mcs(uint32_t mcs); +SRSLTE_API srslte_mod_t srslte_ra_mod_from_mcs(uint32_t mcs); + SRSLTE_API int srslte_ra_mcs_from_tbs_idx(uint32_t tbs_idx); SRSLTE_API int srslte_ra_tbs_from_idx(uint32_t tbs_idx, 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 88% rename from srslte/include/srslte/phch/uci.h rename to lib/include/srslte/phy/phch/uci.h index 4b0d24195..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 @@ -56,6 +56,11 @@ typedef struct SRSLTE_API { int16_t *cqi_table_s[11]; } srslte_uci_cqi_pusch_t; +typedef struct SRSLTE_API { + uint8_t cqi_table[16][32]; + int16_t cqi_table_s[16][32]; // aligned for simd +} srslte_uci_cqi_pucch_t; + typedef struct SRSLTE_API { uint8_t uci_cqi[SRSLTE_CQI_MAX_BITS]; uint32_t uci_cqi_len; @@ -78,6 +83,18 @@ typedef struct { srslte_uci_bit_type_t type; } srslte_uci_bit_t; +SRSLTE_API void srslte_uci_cqi_pucch_init(srslte_uci_cqi_pucch_t *q); + +SRSLTE_API int srslte_uci_encode_cqi_pucch(uint8_t *cqi_data, + uint32_t cqi_len, + uint8_t b_bits[SRSLTE_UCI_CQI_CODED_PUCCH_B]); + +SRSLTE_API int16_t srslte_uci_decode_cqi_pucch(srslte_uci_cqi_pucch_t *q, + int16_t b_bits[32], // aligned for simd + uint8_t *cqi_data, + uint32_t cqi_len); + + SRSLTE_API int srslte_uci_cqi_init(srslte_uci_cqi_pusch_t *q); SRSLTE_API void srslte_uci_cqi_free(srslte_uci_cqi_pusch_t *q); @@ -99,10 +116,6 @@ SRSLTE_API int srslte_uci_decode_cqi_pusch(srslte_uci_cqi_pusch_t *q, uint8_t *cqi_data, bool *cqi_ack); -SRSLTE_API int srslte_uci_encode_cqi_pucch(uint8_t *cqi_data, - uint32_t cqi_len, - uint8_t b_bits[SRSLTE_UCI_CQI_CODED_PUCCH_B]); - SRSLTE_API int srslte_uci_encode_ack(srslte_pusch_cfg_t *cfg, uint8_t data, uint32_t O_cqi, 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 86% rename from srslte/include/srslte/rf/rf.h rename to lib/include/srslte/phy/rf/rf.h index fd49f7d8d..907a5a008 100644 --- a/srslte/include/srslte/rf/rf.h +++ b/lib/include/srslte/phy/rf/rf.h @@ -71,9 +71,18 @@ typedef void (*srslte_rf_error_handler_t)(srslte_rf_error_t error); SRSLTE_API int srslte_rf_open(srslte_rf_t *h, char *args); +SRSLTE_API int srslte_rf_open_multi(srslte_rf_t *h, + char *args, + uint32_t nof_rx_antennas); + SRSLTE_API int srslte_rf_open_devname(srslte_rf_t *h, - char *devname, - char *args); + char *devname, + char *args); + +SRSLTE_API int srslte_rf_open_devname_multi(srslte_rf_t *h, + char *devname, + char *args, + uint32_t nof_rx_antennas); SRSLTE_API const char *srslte_rf_name(srslte_rf_t *h); @@ -139,6 +148,13 @@ SRSLTE_API int srslte_rf_recv_with_time(srslte_rf_t *h, time_t *secs, double *frac_secs); +SRSLTE_API int srslte_rf_recv_with_time_multi(srslte_rf_t *h, + void **data, + uint32_t nsamples, + bool blocking, + time_t *secs, + double *frac_secs); + SRSLTE_API double srslte_rf_set_tx_srate(srslte_rf_t *h, double freq); diff --git a/srslte/include/srslte/rf/rf_utils.h b/lib/include/srslte/phy/rf/rf_utils.h similarity index 91% rename from srslte/include/srslte/rf/rf_utils.h rename to lib/include/srslte/phy/rf/rf_utils.h index 97a60cd9b..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 @@ -43,17 +43,20 @@ SRSLTE_API int rf_rssi_scan(srslte_rf_t *rf, int nsamp); SRSLTE_API int rf_mib_decoder(srslte_rf_t *rf, + uint32_t nof_rx_antennas, cell_search_cfg_t *config, srslte_cell_t *cell, float *cfo); SRSLTE_API int rf_cell_search(srslte_rf_t *rf, + uint32_t nof_rx_antennas, cell_search_cfg_t *config, int force_N_id_2, srslte_cell_t *cell, float *cfo); SRSLTE_API int rf_search_and_decode_mib(srslte_rf_t *rf, + uint32_t nof_rx_antennas, cell_search_cfg_t *config, int force_N_id_2, srslte_cell_t *cell, 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 81% rename from srslte/include/srslte/ue/ue_cell_search.h rename to lib/include/srslte/phy/ue/ue_cell_search.h index 19195dec6..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 @@ -69,6 +69,9 @@ typedef struct SRSLTE_API { typedef struct SRSLTE_API { srslte_ue_sync_t ue_sync; + cf_t *sf_buffer[SRSLTE_MAX_PORTS]; + uint32_t nof_rx_antennas; + uint32_t max_frames; uint32_t nof_valid_frames; // number of 5 ms frames to scan @@ -83,6 +86,12 @@ SRSLTE_API int srslte_ue_cellsearch_init(srslte_ue_cellsearch_t *q, int (recv_callback)(void*, void*, uint32_t,srslte_timestamp_t*), void *stream_handler); +SRSLTE_API int srslte_ue_cellsearch_init_multi(srslte_ue_cellsearch_t *q, + uint32_t max_frames_total, + int (recv_callback)(void*, cf_t*[SRSLTE_MAX_PORTS], uint32_t,srslte_timestamp_t*), + uint32_t nof_rx_antennas, + void *stream_handler); + SRSLTE_API void srslte_ue_cellsearch_free(srslte_ue_cellsearch_t *q); SRSLTE_API int srslte_ue_cellsearch_scan_N_id_2(srslte_ue_cellsearch_t *q, diff --git a/srslte/include/srslte/ue/ue_dl.h b/lib/include/srslte/phy/ue/ue_dl.h similarity index 76% rename from srslte/include/srslte/ue/ue_dl.h rename to lib/include/srslte/phy/ue/ue_dl.h index 0efe89ada..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" @@ -88,8 +88,12 @@ typedef struct SRSLTE_API { srslte_ra_dl_dci_t dl_dci; srslte_cell_t cell; - cf_t *sf_symbols; - cf_t *ce[SRSLTE_MAX_PORTS]; + uint32_t nof_rx_antennas; + + cf_t *sf_symbols; // this is for backwards compatibility + cf_t *sf_symbols_m[SRSLTE_MAX_PORTS]; + cf_t *ce[SRSLTE_MAX_PORTS]; // compatibility + cf_t *ce_m[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; srslte_dci_format_t dci_format; uint64_t pkt_errors; @@ -112,6 +116,10 @@ typedef struct SRSLTE_API { SRSLTE_API int srslte_ue_dl_init(srslte_ue_dl_t *q, srslte_cell_t cell); +SRSLTE_API int srslte_ue_dl_init_multi(srslte_ue_dl_t *q, + srslte_cell_t cell, + uint32_t nof_rx_antennas); + SRSLTE_API void srslte_ue_dl_free(srslte_ue_dl_t *q); SRSLTE_API int srslte_ue_dl_decode_fft_estimate(srslte_ue_dl_t *q, @@ -119,6 +127,11 @@ SRSLTE_API int srslte_ue_dl_decode_fft_estimate(srslte_ue_dl_t *q, uint32_t sf_idx, uint32_t *cfi); +SRSLTE_API int srslte_ue_dl_decode_fft_estimate_multi(srslte_ue_dl_t *q, + cf_t *input[SRSLTE_MAX_PORTS], + uint32_t sf_idx, + uint32_t *cfi); + SRSLTE_API int srslte_ue_dl_decode_estimate(srslte_ue_dl_t *q, uint32_t sf_idx, uint32_t *cfi); @@ -158,12 +171,23 @@ SRSLTE_API int srslte_ue_dl_decode(srslte_ue_dl_t * q, uint8_t *data, uint32_t tti); +SRSLTE_API int srslte_ue_dl_decode_multi(srslte_ue_dl_t * q, + cf_t *input[SRSLTE_MAX_PORTS], + uint8_t *data, + uint32_t tti); + SRSLTE_API int srslte_ue_dl_decode_rnti(srslte_ue_dl_t * q, cf_t *input, uint8_t *data, uint32_t tti, uint16_t rnti); +SRSLTE_API int srslte_ue_dl_decode_rnti_multi(srslte_ue_dl_t * q, + cf_t *input[SRSLTE_MAX_PORTS], + uint8_t *data, + uint32_t tti, + uint16_t rnti); + SRSLTE_API bool srslte_ue_dl_decode_phich(srslte_ue_dl_t *q, uint32_t sf_idx, uint32_t n_prb_lowest, diff --git a/srslte/include/srslte/ue/ue_mib.h b/lib/include/srslte/phy/ue/ue_mib.h similarity index 83% rename from srslte/include/srslte/ue/ue_mib.h rename to lib/include/srslte/phy/ue/ue_mib.h index 771314122..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 @@ -100,14 +100,23 @@ SRSLTE_API int srslte_ue_mib_decode(srslte_ue_mib_t * q, typedef struct { srslte_ue_mib_t ue_mib; srslte_ue_sync_t ue_sync; + cf_t *sf_buffer[SRSLTE_MAX_PORTS]; + uint32_t nof_rx_antennas; } srslte_ue_mib_sync_t; SRSLTE_API int srslte_ue_mib_sync_init(srslte_ue_mib_sync_t *q, uint32_t cell_id, srslte_cp_t cp, - int (recv_callback)(void*, void*, uint32_t, srslte_timestamp_t *), + int (recv_callback)(void*, void*, uint32_t, srslte_timestamp_t *), void *stream_handler); +SRSLTE_API int srslte_ue_mib_sync_init_multi(srslte_ue_mib_sync_t *q, + uint32_t cell_id, + srslte_cp_t cp, + int (recv_callback)(void*, cf_t*[SRSLTE_MAX_PORTS], uint32_t, srslte_timestamp_t *), + uint32_t nof_rx_antennas, + void *stream_handler); + SRSLTE_API void srslte_ue_mib_sync_free(srslte_ue_mib_sync_t *q); SRSLTE_API void srslte_ue_mib_sync_reset(srslte_ue_mib_sync_t * q); 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 79% rename from srslte/include/srslte/ue/ue_sync.h rename to lib/include/srslte/phy/ue/ue_sync.h index 44b98ab6c..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,11 +73,15 @@ typedef struct SRSLTE_API { srslte_agc_t agc; bool do_agc; uint32_t agc_period; - + int decimate; void *stream; - int (*recv_callback)(void*, void*, uint32_t, srslte_timestamp_t*); + void *stream_single; + int (*recv_callback)(void*, cf_t*[SRSLTE_MAX_PORTS], uint32_t, srslte_timestamp_t*); + int (*recv_callback_single)(void*, void*, uint32_t, srslte_timestamp_t*); srslte_timestamp_t last_timestamp; + uint32_t nof_rx_antennas; + srslte_filesource_t file_source; bool file_mode; float file_cfo; @@ -85,8 +89,6 @@ typedef struct SRSLTE_API { srslte_ue_sync_state_t state; - cf_t *input_buffer; - uint32_t frame_len; uint32_t fft_size; uint32_t nof_recv_sf; // Number of subframes received each call to srslte_ue_sync_get_buffer @@ -115,18 +117,31 @@ typedef struct SRSLTE_API { float mean_sfo; uint32_t sample_offset_correct_period; float sfo_ema; + #ifdef MEASURE_EXEC_TIME float mean_exec_time; #endif } srslte_ue_sync_t; - SRSLTE_API int srslte_ue_sync_init(srslte_ue_sync_t *q, srslte_cell_t cell, int (recv_callback)(void*, void*, uint32_t, srslte_timestamp_t*), void *stream_handler); +SRSLTE_API int srslte_ue_sync_init_multi(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); + +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, @@ -141,9 +156,6 @@ SRSLTE_API int srslte_ue_sync_start_agc(srslte_ue_sync_t *q, SRSLTE_API uint32_t srslte_ue_sync_sf_len(srslte_ue_sync_t *q); -SRSLTE_API int srslte_ue_sync_get_buffer(srslte_ue_sync_t *q, - cf_t **sf_symbols); - SRSLTE_API void srslte_ue_sync_set_agc_period(srslte_ue_sync_t *q, uint32_t period); @@ -151,6 +163,9 @@ SRSLTE_API void srslte_ue_sync_set_agc_period(srslte_ue_sync_t *q, SRSLTE_API int srslte_ue_sync_zerocopy(srslte_ue_sync_t *q, cf_t *input_buffer); +SRSLTE_API int srslte_ue_sync_zerocopy_multi(srslte_ue_sync_t *q, + cf_t *input_buffer[SRSLTE_MAX_PORTS]); + SRSLTE_API void srslte_ue_sync_set_cfo(srslte_ue_sync_t *q, float cfo); 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 b0264a6e5..2afa8068a 100644 --- a/srslte/include/srslte/ue/ue_ul.h +++ b/lib/include/srslte/phy/ue/ue_ul.h @@ -38,21 +38,19 @@ #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" -#define SRSLTE_UE_UL_NOF_HARQ_PROCESSES 8 - /* UE UL power control */ typedef struct { // Common configuration 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/lib/include/srslte/phy/utils/ringbuffer.h b/lib/include/srslte/phy/utils/ringbuffer.h new file mode 100644 index 000000000..9cbe0ddd6 --- /dev/null +++ b/lib/include/srslte/phy/utils/ringbuffer.h @@ -0,0 +1,37 @@ + +#ifndef RINGBUFFER_H +#define RINGBUFFER_H + +#include "srslte/config.h" +#include +#include + +typedef struct { + uint8_t *buffer; + int capacity; + int count; + int wpm; + int rpm; + pthread_mutex_t mutex; + pthread_cond_t cvar; +} srslte_ringbuffer_t; + + +SRSLTE_API int srslte_ringbuffer_init(srslte_ringbuffer_t *q, + int capacity); + +SRSLTE_API void srslte_ringbuffer_free(srslte_ringbuffer_t *q, + int capacity); + +SRSLTE_API int srslte_ringbuffer_write(srslte_ringbuffer_t *q, + uint8_t *ptr, + int nof_bytes); + +SRSLTE_API int srslte_ringbuffer_read(srslte_ringbuffer_t *q, + uint8_t *ptr, + int nof_bytes); + + +#endif + + diff --git a/srslte/include/srslte/utils/vector.h b/lib/include/srslte/phy/utils/vector.h similarity index 98% rename from srslte/include/srslte/utils/vector.h rename to lib/include/srslte/phy/utils/vector.h index 027487818..74cd60172 100644 --- a/srslte/include/srslte/utils/vector.h +++ b/lib/include/srslte/phy/utils/vector.h @@ -156,13 +156,14 @@ SRSLTE_API float srslte_vec_avg_power_cf(cf_t *x, uint32_t len); SRSLTE_API uint32_t srslte_vec_max_fi(float *x, uint32_t len); SRSLTE_API uint32_t srslte_vec_max_abs_ci(cf_t *x, uint32_t len); SRSLTE_API int16_t srslte_vec_max_star_si(int16_t *x, uint32_t len); +SRSLTE_API int16_t srslte_vec_max_abs_star_si(int16_t *x, uint32_t len); /* maximum between two vectors */ SRSLTE_API void srslte_vec_max_fff(float *x, float *y, float *z, uint32_t len); /* quantify vector of floats or int16 and convert to uint8_t */ SRSLTE_API void srslte_vec_quant_fuc(float *in, uint8_t *out, float gain, float offset, float clip, uint32_t len); -SRSLTE_API void srslte_vec_quant_suc(int16_t *in, uint8_t *out, int16_t norm, int16_t offset, int16_t clip, uint32_t len); +SRSLTE_API void srslte_vec_quant_suc(int16_t *in, uint8_t *out, float gain, int16_t offset, int16_t clip, uint32_t len); /* magnitude of each vector element */ SRSLTE_API void srslte_vec_abs_cf(cf_t *x, float *abs, uint32_t len); 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..d3c52b807 --- /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 STATIC + 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..723085e24 --- /dev/null +++ b/lib/src/common/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/. +# + +file(GLOB CXX_SOURCES "*.cc") +file(GLOB C_SOURCES "*.c") + +add_library(srslte_common STATIC ${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}) + 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 58% rename from srslte/lib/CMakeLists.txt rename to lib/src/phy/CMakeLists.txt index 3a73d8761..074ddec55 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,37 @@ set(srslte_srcs version.c $ ) -if(RF_FOUND) - list(APPEND srslte_srcs $) -endif(RF_FOUND) +add_library(srslte_phy STATIC ${srslte_srcs}) +set_target_properties(srslte_phy PROPERTIES + VERSION ${SRSLTE_VERSION_MAJOR}.${SRSLTE_VERSION_MINOR}) -add_library(srslte SHARED ${srslte_srcs}) -target_link_libraries(srslte pthread m) -set_target_properties(srslte PROPERTIES - VERSION ${SRSLTE_VERSION_MAJOR}.${SRSLTE_VERSION_MINOR}) +find_package(MKL) +if(MKL_FOUND) + include_directories(${MKL_INCLUDE_DIRS}) + link_directories(${MKL_LIBRARY_DIRS}) +else(MKL_FOUND) + find_package(FFTW3F REQUIRED) + if(FFTW3F_FOUND) + include_directories(${FFTW3F_INCLUDE_DIRS}) + link_directories(${FFTW3F_LIBRARY_DIRS}) + endif(FFTW3F_FOUND) +endif(MKL_FOUND) -if(NOT DisableMEX) - add_library(srslte_static STATIC ${srslte_srcs}) -endif(NOT DisableMEX) if(MKL_FOUND) - target_link_libraries(srslte ${MKL_LIBRARIES}) - if(NOT DisableMEX) - target_link_libraries(srslte_static ${MKL_LIBRARIES}) - endif(NOT DisableMEX) + if(STATIC_MKL) + target_link_libraries(srslte_phy ${MKL_STATIC_LIBRARIES}) + else(STATIC_MKL) + target_link_libraries(srslte_phy ${MKL_LIBRARIES}) + endif(STATIC_MKL) else(MKL_FOUND) - target_link_libraries(srslte ${FFTW3F_LIBRARIES}) - if(NOT DisableMEX) - target_link_libraries(srslte_static ${FFTW3F_LIBRARIES}) - endif(NOT DisableMEX) + target_link_libraries(srslte_phy ${FFTW3F_LIBRARIES}) endif(MKL_FOUND) -if(RF_FOUND) - if(UHD_FOUND) - target_link_libraries(srslte ${UHD_LIBRARIES}) - endif(UHD_FOUND) - - if(BLADERF_FOUND) - target_link_libraries(srslte ${BLADERF_LIBRARIES}) - endif(BLADERF_FOUND) -endif(RF_FOUND) if(VOLK_FOUND) - target_link_libraries(srslte ${VOLK_LIBRARIES}) - if(NOT DisableMEX) - target_link_libraries(srslte_static ${VOLK_LIBRARIES}) - endif(NOT DisableMEX) + target_link_libraries(srslte_phy ${VOLK_LIBRARIES}) endif(VOLK_FOUND) -INSTALL(TARGETS srslte DESTINATION ${LIBRARY_DIR}) -SRSLTE_SET_PIC(srslte) - +target_link_libraries(srslte_phy pthread m) +install(TARGETS srslte_phy DESTINATION ${LIBRARY_DIR}) diff --git a/srslte/lib/agc/CMakeLists.txt b/lib/src/phy/agc/CMakeLists.txt similarity index 85% rename from srslte/lib/agc/CMakeLists.txt rename to lib/src/phy/agc/CMakeLists.txt index c97f5d5d2..fed3467d4 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 @@ -20,4 +20,3 @@ file(GLOB SOURCES "*.c") add_library(srslte_agc OBJECT ${SOURCES}) -SRSLTE_SET_PIC(srslte_agc) 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 85% rename from srslte/lib/ch_estimation/CMakeLists.txt rename to lib/src/phy/ch_estimation/CMakeLists.txt index 24dbeed36..ac069bd04 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 @@ -20,5 +20,4 @@ file(GLOB SOURCES "*.c") add_library(srslte_ch_estimation OBJECT ${SOURCES}) -SRSLTE_SET_PIC(srslte_ch_estimation) add_subdirectory(test) 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 86% rename from srslte/lib/ch_estimation/chest_dl.c rename to lib/src/phy/ch_estimation/chest_dl.c index 541f98646..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 @@ -311,7 +311,7 @@ float srslte_chest_dl_rssi(srslte_chest_dl_t *q, cf_t *input, uint32_t port_id) return rssi/nsymbols; } -int srslte_chest_dl_estimate_port(srslte_chest_dl_t *q, cf_t *input, cf_t *ce, uint32_t sf_idx, uint32_t port_id) +int srslte_chest_dl_estimate_port(srslte_chest_dl_t *q, cf_t *input, cf_t *ce, uint32_t sf_idx, uint32_t port_id, uint32_t rxant_id) { /* Get references from the input signal */ srslte_refsignal_cs_get_sf(q->cell, port_id, input, q->pilot_recv_signal); @@ -331,41 +331,61 @@ int srslte_chest_dl_estimate_port(srslte_chest_dl_t *q, cf_t *input, cf_t *ce, u /* Estimate noise power */ if (q->noise_alg == SRSLTE_NOISE_ALG_REFS && q->smooth_filter_len > 0) { - q->noise_estimate[port_id] = estimate_noise_pilots(q, port_id); + q->noise_estimate[rxant_id][port_id] = estimate_noise_pilots(q, port_id); } else if (q->noise_alg == SRSLTE_NOISE_ALG_PSS) { if (sf_idx == 0 || sf_idx == 5) { - q->noise_estimate[port_id] = estimate_noise_pss(q, input, ce); + q->noise_estimate[rxant_id][port_id] = estimate_noise_pss(q, input, ce); } } else { if (sf_idx == 0 || sf_idx == 5) { - q->noise_estimate[port_id] = estimate_noise_empty_sc(q, input); + q->noise_estimate[rxant_id][port_id] = estimate_noise_empty_sc(q, input); } } } /* Compute RSRP for the channel estimates in this port */ - q->rsrp[port_id] = srslte_vec_avg_power_cf(q->pilot_recv_signal, SRSLTE_REFSIGNAL_NUM_SF(q->cell.nof_prb, port_id)); + q->rsrp[rxant_id][port_id] = srslte_vec_avg_power_cf(q->pilot_recv_signal, SRSLTE_REFSIGNAL_NUM_SF(q->cell.nof_prb, port_id)); if (port_id == 0) { /* compute rssi only for port 0 */ - q->rssi[port_id] = srslte_chest_dl_rssi(q, input, port_id); + q->rssi[rxant_id][port_id] = srslte_chest_dl_rssi(q, input, port_id); } return 0; } +int srslte_chest_dl_estimate_multi(srslte_chest_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], uint32_t sf_idx, uint32_t nof_rx_antennas) +{ + for (uint32_t rxant_id=0;rxant_idcell.nof_ports;port_id++) { + if (srslte_chest_dl_estimate_port(q, input[rxant_id], ce[port_id][rxant_id], sf_idx, port_id, rxant_id)) { + return SRSLTE_ERROR; + } + } + } + q->last_nof_antennas = nof_rx_antennas; + return SRSLTE_SUCCESS; +} + int srslte_chest_dl_estimate(srslte_chest_dl_t *q, cf_t *input, cf_t *ce[SRSLTE_MAX_PORTS], uint32_t sf_idx) { uint32_t port_id; for (port_id=0;port_idcell.nof_ports;port_id++) { - srslte_chest_dl_estimate_port(q, input, ce[port_id], sf_idx, port_id); + if (srslte_chest_dl_estimate_port(q, input, ce[port_id], sf_idx, port_id, 0)) { + return SRSLTE_ERROR; + } } + q->last_nof_antennas = 1; return SRSLTE_SUCCESS; } float srslte_chest_dl_get_noise_estimate(srslte_chest_dl_t *q) { - return srslte_vec_acc_ff(q->noise_estimate, q->cell.nof_ports)/q->cell.nof_ports; + float n = 0; + for (int i=0;ilast_nof_antennas;i++) { + n += srslte_vec_acc_ff(q->noise_estimate[i], q->cell.nof_ports)/q->cell.nof_ports; + } + return n/q->last_nof_antennas; } float srslte_chest_dl_get_snr(srslte_chest_dl_t *q) { @@ -378,20 +398,31 @@ float srslte_chest_dl_get_snr(srslte_chest_dl_t *q) { } float srslte_chest_dl_get_rssi(srslte_chest_dl_t *q) { - return 4*q->rssi[0]/q->cell.nof_prb/SRSLTE_NRE; + float n = 0; + for (int i=0;ilast_nof_antennas;i++) { + n += 4*q->rssi[i][0]/q->cell.nof_prb/SRSLTE_NRE; + } + return n/q->last_nof_antennas; } /* q->rssi[0] is the average power in all RE in all symbol containing references for port 0 . q->rssi[0]/q->cell.nof_prb is the average power per PRB * q->rsrp[0] is the average power of RE containing references only (for port 0). */ float srslte_chest_dl_get_rsrq(srslte_chest_dl_t *q) { - return q->cell.nof_prb*q->rsrp[0] / q->rssi[0]; + float n = 0; + for (int i=0;ilast_nof_antennas;i++) { + n += q->cell.nof_prb*q->rsrp[i][0] / q->rssi[i][0]; + } + return n/q->last_nof_antennas; } -float srslte_chest_dl_get_rsrp(srslte_chest_dl_t *q) { - - // return sum of power received from all tx ports - return srslte_vec_acc_ff(q->rsrp, q->cell.nof_ports); +float srslte_chest_dl_get_rsrp(srslte_chest_dl_t *q) { + // Note: use only port 0 but average across antennas + float n = 0; + for (int i=0;ilast_nof_antennas;i++) { + 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 80% rename from srslte/lib/ch_estimation/chest_ul.c rename to lib/src/phy/ch_estimation/chest_ul.c index 75d816702..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 @@ -78,6 +78,13 @@ int srslte_chest_ul_init(srslte_chest_ul_t *q, srslte_cell_t cell) perror("malloc"); goto clean_exit; } + for (int i=0;i<4;i++) { + q->pilot_estimates_tmp[i] = srslte_vec_malloc(sizeof(cf_t) * NOF_REFS_SF); + if (!q->pilot_estimates_tmp[i]) { + perror("malloc"); + goto clean_exit; + } + } q->pilot_recv_signal = srslte_vec_malloc(sizeof(cf_t) * (NOF_REFS_SF+1)); if (!q->pilot_recv_signal) { perror("malloc"); @@ -125,6 +132,11 @@ void srslte_chest_ul_free(srslte_chest_ul_t *q) if (q->pilot_estimates) { free(q->pilot_estimates); } + for (int i=0;i<4;i++) { + if (q->pilot_estimates_tmp[i]) { + free(q->pilot_estimates_tmp[i]); + } + } if (q->pilot_recv_signal) { free(q->pilot_recv_signal); } @@ -145,13 +157,13 @@ void srslte_chest_ul_set_cfg(srslte_chest_ul_t *q, } /* Uses the difference between the averaged and non-averaged pilot estimates */ -static float estimate_noise_pilots(srslte_chest_ul_t *q, cf_t *ce, uint32_t nrefs) +static float estimate_noise_pilots(srslte_chest_ul_t *q, cf_t *ce, uint32_t nrefs, uint32_t n_prb[2]) { float power = 0; for (int i=0;i<2;i++) { power += srslte_chest_estimate_noise_pilots(&q->pilot_estimates[i*nrefs], - &ce[SRSLTE_REFSIGNAL_UL_L(i, q->cell.cp)*q->cell.nof_prb*SRSLTE_NRE], + &ce[SRSLTE_REFSIGNAL_UL_L(i, q->cell.cp)*q->cell.nof_prb*SRSLTE_NRE+n_prb[i]*SRSLTE_NRE], q->tmp_noise, nrefs); } @@ -168,9 +180,9 @@ static float estimate_noise_pilots(srslte_chest_ul_t *q, cf_t *ce, uint32_t nref } } -#define cesymb(i) ce[SRSLTE_RE_IDX(q->cell.nof_prb,i,0)] - -static void interpolate_pilots(srslte_chest_ul_t *q, cf_t *ce, uint32_t nrefs) +// The interpolator currently only supports same frequency allocation for each subframe +#define cesymb(i) ce[SRSLTE_RE_IDX(q->cell.nof_prb,i,n_prb[0]*SRSLTE_NRE)] +static void interpolate_pilots(srslte_chest_ul_t *q, cf_t *ce, uint32_t nrefs, uint32_t n_prb[2]) { uint32_t L1 = SRSLTE_REFSIGNAL_UL_L(0, q->cell.cp); uint32_t L2 = SRSLTE_REFSIGNAL_UL_L(1, q->cell.cp); @@ -206,10 +218,10 @@ void srslte_chest_ul_set_smooth_filter3_coeff(srslte_chest_ul_t* q, float w) q->smooth_filter_len = 3; } -static void average_pilots(srslte_chest_ul_t *q, cf_t *input, cf_t *ce, uint32_t nrefs) { +static void average_pilots(srslte_chest_ul_t *q, cf_t *input, cf_t *ce, uint32_t nrefs, uint32_t n_prb[2]) { for (int i=0;i<2;i++) { srslte_chest_average_pilots(&input[i*nrefs], - &ce[SRSLTE_REFSIGNAL_UL_L(i, q->cell.cp)*q->cell.nof_prb*SRSLTE_NRE], + &ce[SRSLTE_REFSIGNAL_UL_L(i, q->cell.cp)*q->cell.nof_prb*SRSLTE_NRE+n_prb[i]*SRSLTE_NRE], q->smooth_filter, nrefs, 1, q->smooth_filter_len); } } @@ -237,21 +249,25 @@ int srslte_chest_ul_estimate(srslte_chest_ul_t *q, cf_t *input, cf_t *ce, srslte_vec_prod_conj_ccc(q->pilot_recv_signal, q->dmrs_pregen.r[cyclic_shift_for_dmrs][sf_idx][nof_prb], q->pilot_estimates, nrefs_sf); + if (n_prb[0] != n_prb[1]) { + printf("ERROR: intra-subframe frequency hopping not supported in the estimator!!\n"); + } + if (ce != NULL) { if (q->smooth_filter_len > 0) { - average_pilots(q, q->pilot_estimates, ce, nrefs_sym); - interpolate_pilots(q, ce, nrefs_sym); + average_pilots(q, q->pilot_estimates, ce, nrefs_sym, n_prb); + interpolate_pilots(q, ce, nrefs_sym, n_prb); /* If averaging, compute noise from difference between received and averaged estimates */ - q->noise_estimate = estimate_noise_pilots(q, ce, nrefs_sym); + q->noise_estimate = estimate_noise_pilots(q, ce, nrefs_sym, n_prb); } else { // Copy estimates to CE vector without averaging for (int i=0;i<2;i++) { - memcpy(&ce[SRSLTE_REFSIGNAL_UL_L(i, q->cell.cp)*q->cell.nof_prb*SRSLTE_NRE], + memcpy(&ce[SRSLTE_REFSIGNAL_UL_L(i, q->cell.cp)*q->cell.nof_prb*SRSLTE_NRE+n_prb[i]*SRSLTE_NRE], &q->pilot_estimates[i*nrefs_sym], - nrefs_sym*sizeof(cf_t)); + nrefs_sym*sizeof(cf_t)); } - interpolate_pilots(q, ce, nrefs_sym); + interpolate_pilots(q, ce, nrefs_sym, n_prb); q->noise_estimate = 0; } } @@ -262,7 +278,8 @@ int srslte_chest_ul_estimate(srslte_chest_ul_t *q, cf_t *input, cf_t *ce, } int srslte_chest_ul_estimate_pucch(srslte_chest_ul_t *q, cf_t *input, cf_t *ce, - srslte_pucch_format_t format, uint32_t n_pucch, uint32_t sf_idx) + srslte_pucch_format_t format, uint32_t n_pucch, uint32_t sf_idx, + uint8_t *pucch2_ack_bits) { if (!q->dmrs_signal_configured) { fprintf(stderr, "Error must call srslte_chest_ul_set_cfg() before using the UL estimator\n"); @@ -281,10 +298,36 @@ int srslte_chest_ul_estimate_pucch(srslte_chest_ul_t *q, cf_t *input, cf_t *ce, /* Generate known pilots */ uint8_t pucch2_bits[2] = {0, 0}; - srslte_refsignal_dmrs_pucch_gen(&q->dmrs_signal, format, n_pucch, sf_idx, pucch2_bits, q->pilot_known_signal), - - /* Use the known DMRS signal to compute Least-squares estimates */ - srslte_vec_prod_conj_ccc(q->pilot_recv_signal, q->pilot_known_signal, q->pilot_estimates, nrefs_sf); + if (format == SRSLTE_PUCCH_FORMAT_2A || format == SRSLTE_PUCCH_FORMAT_2B) { + float max = -1e9; + int i_max = 0; + + int m = 0; + if (format == SRSLTE_PUCCH_FORMAT_2A) { + m = 2; + } else { + m = 4; + } + + for (int i=0;idmrs_signal, format, n_pucch, sf_idx, pucch2_bits, q->pilot_known_signal); + srslte_vec_prod_conj_ccc(q->pilot_recv_signal, q->pilot_known_signal, q->pilot_estimates_tmp[i], nrefs_sf); + float x = cabsf(srslte_vec_acc_cc(q->pilot_estimates_tmp[i], nrefs_sf)); + if (x >= max) { + max = x; + i_max = i; + } + } + memcpy(q->pilot_estimates, q->pilot_estimates_tmp[i_max], nrefs_sf*sizeof(cf_t)); + pucch2_ack_bits[0] = i_max%2; + pucch2_ack_bits[1] = i_max/2; + } else { + srslte_refsignal_dmrs_pucch_gen(&q->dmrs_signal, format, n_pucch, sf_idx, pucch2_bits, q->pilot_known_signal); + /* Use the known DMRS signal to compute Least-squares estimates */ + srslte_vec_prod_conj_ccc(q->pilot_recv_signal, q->pilot_known_signal, q->pilot_estimates, nrefs_sf); + } if (ce != NULL) { /* FIXME: Currently averaging entire slot, performance good enough? */ 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 98% rename from srslte/lib/ch_estimation/refsignal_ul.c rename to lib/src/phy/ch_estimation/refsignal_ul.c index e2316e1dd..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" @@ -237,6 +237,8 @@ void srslte_refsignal_ul_set_cfg(srslte_refsignal_ul_t *q, if (pucch_cfg) { if (srslte_pucch_cfg_isvalid(pucch_cfg, q->cell.nof_prb)) { memcpy(&q->pucch_cfg, pucch_cfg, sizeof(srslte_pucch_cfg_t)); + } else { + fprintf(stderr, "Invalid PUCCH configuration in refsignal_ul\n"); } } if (srs_cfg) { 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 99% rename from srslte/lib/ch_estimation/test/chest_test_dl.c rename to lib/src/phy/ch_estimation/test/chest_test_dl.c index d296ccc18..c60e94d96 100644 --- a/srslte/lib/ch_estimation/test/chest_test_dl.c +++ b/lib/src/phy/ch_estimation/test/chest_test_dl.c @@ -161,7 +161,7 @@ int main(int argc, char **argv) { struct timeval t[3]; gettimeofday(&t[1], NULL); for (int j=0;j<100;j++) { - srslte_chest_dl_estimate_port(&est, input, ce, sf_idx, n_port); + srslte_chest_dl_estimate_port(&est, input, ce, sf_idx, n_port, 0); } gettimeofday(&t[2], NULL); get_time_interval(t); 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 85% rename from srslte/lib/channel/CMakeLists.txt rename to lib/src/phy/channel/CMakeLists.txt index a14a67c89..0ea8799c5 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 @@ -20,4 +20,3 @@ file(GLOB SOURCES "*.c") add_library(srslte_channel OBJECT ${SOURCES}) -SRSLTE_SET_PIC(srslte_channel) 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..ba2fc1351 --- /dev/null +++ b/lib/src/phy/common/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 "*.c") +add_library(srslte_phy_common OBJECT ${SOURCES}) diff --git a/srslte/lib/common/phy_common.c b/lib/src/phy/common/phy_common.c similarity index 69% rename from srslte/lib/common/phy_common.c rename to lib/src/phy/common/phy_common.c index 447a7562d..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; @@ -370,43 +370,53 @@ uint32_t srslte_re_x_prb(uint32_t ns, uint32_t symbol, uint32_t nof_ports, uint3 struct lte_band { uint32_t band; float fd_low_mhz; - uint32_t earfcn_offset; - uint32_t earfcn_max; + uint32_t dl_earfcn_offset; + uint32_t ul_earfcn_offset; + float duplex_mhz; enum band_geographical_area area; }; struct lte_band lte_bands[SRSLTE_NOF_LTE_BANDS] = { - {1, 2110, 0, 599, SRSLTE_BAND_GEO_AREA_ALL}, - {2, 1930, 600, 1199, SRSLTE_BAND_GEO_AREA_NAR}, - {3, 1805, 1200, 1949, SRSLTE_BAND_GEO_AREA_ALL}, - {4, 2110, 1950, 2399, SRSLTE_BAND_GEO_AREA_NAR}, - {5, 869, 2400, 2649, SRSLTE_BAND_GEO_AREA_NAR}, - {6, 875, 2650, 2749, SRSLTE_BAND_GEO_AREA_APAC}, - {7, 2620, 2750, 3449, SRSLTE_BAND_GEO_AREA_EMEA}, - {8, 925, 3450, 3799, SRSLTE_BAND_GEO_AREA_ALL}, - {9, 1844.9, 3800, 4149, SRSLTE_BAND_GEO_AREA_APAC}, - {10, 2110, 4150, 4749, SRSLTE_BAND_GEO_AREA_NAR}, - {11, 1475.9, 4750, 4949, SRSLTE_BAND_GEO_AREA_JAPAN}, - {12, 729, 5010, 5179, SRSLTE_BAND_GEO_AREA_NAR}, - {13, 746, 5180, 5279, SRSLTE_BAND_GEO_AREA_NAR}, - {14, 758, 5280, 5379, SRSLTE_BAND_GEO_AREA_NAR}, - {17, 734, 5730, 5849, SRSLTE_BAND_GEO_AREA_NAR}, - {18, 860, 5850, 5999, SRSLTE_BAND_GEO_AREA_JAPAN}, - {19, 875, 6000, 6149, SRSLTE_BAND_GEO_AREA_JAPAN}, - {20, 791, 6150, 6449, SRSLTE_BAND_GEO_AREA_EMEA}, - {21, 1495.9, 6450, 6599, SRSLTE_BAND_GEO_AREA_JAPAN}, - {22, 3500, 6600, 7399, SRSLTE_BAND_GEO_AREA_NA}, - {23, 2180, 7500, 7699, SRSLTE_BAND_GEO_AREA_NAR}, - {24, 1525, 7700, 8039, SRSLTE_BAND_GEO_AREA_NAR}, - {25, 1930, 8040, 8689, SRSLTE_BAND_GEO_AREA_NAR}, - {26, 859, 8690, 9039, SRSLTE_BAND_GEO_AREA_NAR}, - {27, 852, 9040, 9209, SRSLTE_BAND_GEO_AREA_NAR}, - {28, 758, 9210, 9659, SRSLTE_BAND_GEO_AREA_APAC}, - {29, 717, 9660, 9769, SRSLTE_BAND_GEO_AREA_NAR}, - {30, 2350, 9770, 9869, SRSLTE_BAND_GEO_AREA_NAR}, - {31, 462.5, 9870, 9919, SRSLTE_BAND_GEO_AREA_CALA} + {1, 2110, 0, 18000, 190, SRSLTE_BAND_GEO_AREA_ALL}, + {2, 1930, 600, 18600, 80, SRSLTE_BAND_GEO_AREA_NAR}, + {3, 1805, 1200, 19200, 95, SRSLTE_BAND_GEO_AREA_ALL}, + {4, 2110, 1950, 19950, 400, SRSLTE_BAND_GEO_AREA_NAR}, + {5, 869, 2400, 20400, 45, SRSLTE_BAND_GEO_AREA_NAR}, + {6, 875, 2650, 20650, 45, SRSLTE_BAND_GEO_AREA_APAC}, + {7, 2620, 2750, 20750, 120, SRSLTE_BAND_GEO_AREA_EMEA}, + {8, 925, 3450, 21450, 45, SRSLTE_BAND_GEO_AREA_ALL}, + {9, 1844.9, 3800, 21800, 95, SRSLTE_BAND_GEO_AREA_APAC}, + {10, 2110, 4150, 22150, 400, SRSLTE_BAND_GEO_AREA_NAR}, + {11, 1475.9, 4750, 22750, 48, SRSLTE_BAND_GEO_AREA_JAPAN}, + {12, 729, 5010, 23010, 30, SRSLTE_BAND_GEO_AREA_NAR}, + {13, 746, 5180, 23180, -31, SRSLTE_BAND_GEO_AREA_NAR}, + {14, 758, 5280, 23280, -30, SRSLTE_BAND_GEO_AREA_NAR}, + {17, 734, 5730, 23730, 30, SRSLTE_BAND_GEO_AREA_NAR}, + {18, 860, 5850, 23850, 45, SRSLTE_BAND_GEO_AREA_JAPAN}, + {19, 875, 6000, 24000, 45, SRSLTE_BAND_GEO_AREA_JAPAN}, + {20, 791, 6150, 24150, -41, SRSLTE_BAND_GEO_AREA_EMEA}, + {21, 1495.9, 6450, 24450, 48, SRSLTE_BAND_GEO_AREA_JAPAN}, + {22, 3500, 6600, 24600, 100, SRSLTE_BAND_GEO_AREA_NA}, + {23, 2180, 7500, 25500, 180, SRSLTE_BAND_GEO_AREA_NAR}, + {24, 1525, 7700, 25700, -101.5, SRSLTE_BAND_GEO_AREA_NAR}, + {25, 1930, 8040, 26040, 80, SRSLTE_BAND_GEO_AREA_NAR}, + {26, 859, 8690, 26690, 45, SRSLTE_BAND_GEO_AREA_NAR}, + {27, 852, 9040, 27040, 45, SRSLTE_BAND_GEO_AREA_NAR}, + {28, 758, 9210, 27210, 55, SRSLTE_BAND_GEO_AREA_APAC}, + {29, 717, 9660, 0, 0, SRSLTE_BAND_GEO_AREA_NAR}, + {30, 2350, 9770, 27660, 45, SRSLTE_BAND_GEO_AREA_NAR}, + {31, 462.5, 9870, 27760, 10, SRSLTE_BAND_GEO_AREA_CALA}, + {32, 1452, 9920, 0, 0, SRSLTE_BAND_GEO_AREA_EMEA}, + {64, 0, 10359, 27809, 0, SRSLTE_BAND_GEO_AREA_ALL}, + {65, 2110, 65536, 131072, 90, SRSLTE_BAND_GEO_AREA_ALL}, + {66, 2110, 66436, 131972, 90, SRSLTE_BAND_GEO_AREA_NAR}, + {67, 738, 67336, 0, 0, SRSLTE_BAND_GEO_AREA_EMEA}, + {68, 753, 67536, 132672, 30, SRSLTE_BAND_GEO_AREA_EMEA}, + {69, 2570, 67836, 0, 50, SRSLTE_BAND_GEO_AREA_EMEA}, + {70, 1995, 68336, 132972, 25, SRSLTE_BAND_GEO_AREA_NAR}, + {71, 0, 68586, 133122, 0, SRSLTE_BAND_GEO_AREA_NAR} // dummy band to bound band 70 earfcn }; -#define EOF_BAND 9919 + int srslte_str2mimotype(char *mimo_type_str, srslte_mimo_type_t *type) { if (!strcmp(mimo_type_str, "single")) { @@ -421,25 +431,69 @@ int srslte_str2mimotype(char *mimo_type_str, srslte_mimo_type_t *type) { return SRSLTE_SUCCESS; } -float get_fd(struct lte_band *band, uint32_t earfcn) { - if (earfcn >= band->earfcn_offset) { - return band->fd_low_mhz + 0.1*(earfcn - band->earfcn_offset); +float get_fd(struct lte_band *band, uint32_t dl_earfcn) { + if (dl_earfcn >= band->dl_earfcn_offset) { + return band->fd_low_mhz + 0.1*(dl_earfcn - band->dl_earfcn_offset); } else { return 0.0; } } -float srslte_band_fd(uint32_t earfcn) { - uint32_t i; - i=0; - while(i < SRSLTE_NOF_LTE_BANDS && lte_bands[i].earfcn_offset= band->ul_earfcn_offset) { + return band->fd_low_mhz - band->duplex_mhz + 0.1*(ul_earfcn - band->ul_earfcn_offset); + } else { + return 0.0; + } +} + +int srslte_band_get_band(uint32_t dl_earfcn) { + uint32_t i = SRSLTE_NOF_LTE_BANDS-1; + if (dl_earfcn > lte_bands[i].dl_earfcn_offset) { + fprintf(stderr, "Invalid DL_EARFCN=%d\n", dl_earfcn); + } + i--; + while(i > 0 && lte_bands[i].dl_earfcn_offset>dl_earfcn) { + i--; + } + return lte_bands[i].band; +} + +float srslte_band_fd(uint32_t dl_earfcn) { + uint32_t i = SRSLTE_NOF_LTE_BANDS-1; + if (dl_earfcn > lte_bands[i].dl_earfcn_offset) { + fprintf(stderr, "Invalid DL_EARFCN=%d\n", dl_earfcn); + } + i--; + while(i > 0 && lte_bands[i].dl_earfcn_offset>dl_earfcn) { + i--; + } + return get_fd(<e_bands[i], dl_earfcn); +} + + +float srslte_band_fu(uint32_t ul_earfcn) { + uint32_t i = SRSLTE_NOF_LTE_BANDS-1; + if (ul_earfcn > lte_bands[i].ul_earfcn_offset) { + fprintf(stderr, "Invalid UL_EARFCN=%d\n", ul_earfcn); + } + i--; + while(i > 0 && (lte_bands[i].ul_earfcn_offset>ul_earfcn || lte_bands[i].ul_earfcn_offset == 0)) { + i--; + } + return get_fu(<e_bands[i], ul_earfcn); +} + +uint32_t srslte_band_ul_earfcn(uint32_t dl_earfcn) { + uint32_t i = SRSLTE_NOF_LTE_BANDS-1; + if (dl_earfcn > lte_bands[i].dl_earfcn_offset) { + fprintf(stderr, "Invalid DL_EARFCN=%d\n", dl_earfcn); } - if (i == SRSLTE_NOF_LTE_BANDS) { - fprintf(stderr, "Error: EARFCN %d not found\n", earfcn); - return -1.0; + i--; + while(i > 0 && lte_bands[i].dl_earfcn_offset>dl_earfcn) { + i--; } - return get_fd(<e_bands[i], earfcn); + return lte_bands[i].ul_earfcn_offset + (dl_earfcn-lte_bands[i].dl_earfcn_offset); } int srslte_band_get_fd_band_all(uint32_t band, srslte_earfcn_t *earfcn, uint32_t max_elems) { @@ -453,23 +507,23 @@ int srslte_band_get_fd_band(uint32_t band, srslte_earfcn_t *earfcn, int start_ea while(i < SRSLTE_NOF_LTE_BANDS && lte_bands[i].band != band) { i++; } - if (i == SRSLTE_NOF_LTE_BANDS) { + if (i >= SRSLTE_NOF_LTE_BANDS - 1) { fprintf(stderr, "Error: Invalid band %d\n", band); return SRSLTE_ERROR; } if (end_earfcn == -1) { - end_earfcn = lte_bands[i].earfcn_max; + end_earfcn = lte_bands[i+1].dl_earfcn_offset-1; } else { - if (end_earfcn > lte_bands[i].earfcn_max) { - fprintf(stderr, "Error: Invalid end earfcn %d. Max is %d\n", end_earfcn, lte_bands[i].earfcn_max); + if (end_earfcn > lte_bands[i+1].dl_earfcn_offset-1) { + fprintf(stderr, "Error: Invalid end earfcn %d. Max is %d\n", end_earfcn, lte_bands[i+1].dl_earfcn_offset-1); return SRSLTE_ERROR; } } if (start_earfcn == -1) { - start_earfcn = lte_bands[i].earfcn_offset; + start_earfcn = lte_bands[i].dl_earfcn_offset; } else { - if (start_earfcn < lte_bands[i].earfcn_offset) { - fprintf(stderr, "Error: Invalid start earfcn %d. Min is %d\n", start_earfcn, lte_bands[i].earfcn_offset); + if (start_earfcn < lte_bands[i].dl_earfcn_offset) { + fprintf(stderr, "Error: Invalid start earfcn %d. Min is %d\n", start_earfcn, lte_bands[i].dl_earfcn_offset); return SRSLTE_ERROR; } } 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 86% rename from srslte/lib/dft/CMakeLists.txt rename to lib/src/phy/dft/CMakeLists.txt index 036e802ee..3af59bf34 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 @@ -20,5 +20,4 @@ set(SRCS dft_fftw.c dft_precoding.c ofdm.c) add_library(srslte_dft OBJECT ${SRCS}) -SRSLTE_SET_PIC(srslte_dft) add_subdirectory(test) 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 80% rename from srslte/lib/dft/dft_precoding.c rename to lib/src/phy/dft/dft_precoding.c index bb3753545..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) @@ -85,14 +85,16 @@ void srslte_dft_precoding_free(srslte_dft_precoding_t *q) bzero(q, sizeof(srslte_dft_precoding_t)); } +static bool valid_prb[101]={true,true,true,true,true,true,true,false,true,true,true,false,true,false,false,true,true,false,true,false,true,false,false,false, + true,true,false,true,false,false,true,false,true,false,false,false,true,false,false,false,true,false,false,false,false,true,false,false,true,false, + true,false,false,false,true,false,false,false,false,false,true,false,false,false,true,false,false,false,false,false,false,false,true,false,false,true, + false,false,false,false,true,true,false,false,false,false,false,false,false,false,true,false,false,false,false,false,true,false,false,false,true}; + bool srslte_dft_precoding_valid_prb(uint32_t nof_prb) { - if (nof_prb > 0 && - (nof_prb == 1 || (nof_prb%2) == 0 || (nof_prb%3) == 0 || (nof_prb%5) == 0)) - { - return true; - } else { - return false; + if (nof_prb <= 100) { + return valid_prb[nof_prb]; } + return false; } int srslte_dft_precoding(srslte_dft_precoding_t *q, cf_t *input, cf_t *output, 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 85% rename from srslte/lib/enb/CMakeLists.txt rename to lib/src/phy/enb/CMakeLists.txt index abd38a7d0..e15fae905 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 @@ -20,4 +20,3 @@ file(GLOB SOURCES "*.c") add_library(srslte_enb OBJECT ${SOURCES}) -SRSLTE_SET_PIC(srslte_enb) diff --git a/srslte/lib/enb/enb_dl.c b/lib/src/phy/enb/enb_dl.c similarity index 82% rename from srslte/lib/enb/enb_dl.c rename to lib/src/phy/enb/enb_dl.c index 7d42145e5..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 @@ -37,9 +37,9 @@ #define CURRENT_SLOTLEN_RE SRSLTE_SLOT_LEN_RE(q->cell.nof_prb, q->cell.cp) #define CURRENT_SFLEN_RE SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp) -#define SRSLTE_ENB_RF_AMP 0.5 +#define SRSLTE_ENB_RF_AMP 0.1 -int srslte_enb_dl_init(srslte_enb_dl_t *q, srslte_cell_t cell, uint32_t nof_rnti) +int srslte_enb_dl_init(srslte_enb_dl_t *q, srslte_cell_t cell) { int ret = SRSLTE_ERROR_INVALID_INPUTS; @@ -52,7 +52,7 @@ int srslte_enb_dl_init(srslte_enb_dl_t *q, srslte_cell_t cell, uint32_t nof_rnti q->cell = cell; q->cfi = 3; - q->nof_rnti = nof_rnti; + q->tx_amp = SRSLTE_ENB_RF_AMP; if (srslte_ofdm_tx_init(&q->ifft, q->cell.cp, q->cell.nof_prb)) { fprintf(stderr, "Error initiating FFT\n"); @@ -88,11 +88,6 @@ int srslte_enb_dl_init(srslte_enb_dl_t *q, srslte_cell_t cell, uint32_t nof_rnti goto clean_exit; } - if (srslte_pdsch_init_rnti_multi(&q->pdsch, nof_rnti)) { - fprintf(stderr, "Error initiating multiple RNTIs in PDSCH\n"); - goto clean_exit; - } - if (srslte_refsignal_cs_init(&q->csr_signal, q->cell)) { fprintf(stderr, "Error initializing CSR signal (%d)\n",ret); goto clean_exit; @@ -146,6 +141,11 @@ void srslte_enb_dl_free(srslte_enb_dl_t *q) } } +void srslte_enb_dl_set_amp(srslte_enb_dl_t *q, float amp) +{ + q->tx_amp = amp; +} + void srslte_enb_dl_set_cfi(srslte_enb_dl_t *q, uint32_t cfi) { q->cfi = cfi; @@ -214,54 +214,45 @@ void srslte_enb_dl_gen_signal(srslte_enb_dl_t *q, cf_t *signal_buffer) // TODO: PAPR control float norm_factor = (float) sqrt(q->cell.nof_prb)/15; - srslte_vec_sc_prod_cfc(signal_buffer, SRSLTE_ENB_RF_AMP*norm_factor, signal_buffer, SRSLTE_SF_LEN_PRB(q->cell.nof_prb)); + srslte_vec_sc_prod_cfc(signal_buffer, q->tx_amp*norm_factor, signal_buffer, SRSLTE_SF_LEN_PRB(q->cell.nof_prb)); } -int srslte_enb_dl_cfg_rnti(srslte_enb_dl_t *q, uint32_t idx, uint16_t rnti) +int srslte_enb_dl_add_rnti(srslte_enb_dl_t *q, uint16_t rnti) { - return srslte_pdsch_set_rnti_multi(&q->pdsch, idx, rnti); + return srslte_pdsch_set_rnti(&q->pdsch, rnti); } -int srslte_enb_dl_rem_rnti(srslte_enb_dl_t *q, uint32_t idx) +void srslte_enb_dl_rem_rnti(srslte_enb_dl_t *q, uint16_t rnti) { - return srslte_pdsch_set_rnti_multi(&q->pdsch, idx, 0); + srslte_pdsch_free_rnti(&q->pdsch, rnti); } int srslte_enb_dl_put_pdcch_dl(srslte_enb_dl_t *q, srslte_ra_dl_dci_t *grant, srslte_dci_format_t format, srslte_dci_location_t location, - uint32_t rnti_idx, uint32_t sf_idx) + uint16_t rnti, uint32_t sf_idx) { srslte_dci_msg_t dci_msg; - - uint16_t rnti = srslte_pdsch_get_rnti_multi(&q->pdsch, rnti_idx); bool rnti_is_user = true; if (rnti == SRSLTE_SIRNTI || rnti == SRSLTE_PRNTI || (rnti >= SRSLTE_RARNTI_START && rnti <= SRSLTE_RARNTI_END)) { rnti_is_user = false; } - srslte_dci_msg_pack_pdsch(grant, format, &dci_msg, q->cell.nof_prb, rnti_is_user); + srslte_dci_msg_pack_pdsch(grant, format, &dci_msg, q->cell.nof_prb, q->cell.nof_ports, rnti_is_user); if (srslte_pdcch_encode(&q->pdcch, &dci_msg, location, rnti, q->sf_symbols, sf_idx, q->cfi)) { fprintf(stderr, "Error encoding DCI message\n"); return SRSLTE_ERROR; } -/* printf("format: %s, sf_idx=%d, rnti=%d, location=%d,%d, cfi=%d\n", - srslte_dci_format_string(format), sf_idx, rnti, location.L, location.ncce, q->cfi); - srslte_ra_pdsch_fprint(stdout, grant, q->cell.nof_prb); - srslte_vec_fprint_hex(stdout, dci_msg.data, dci_msg.nof_bits); -*/ return SRSLTE_SUCCESS; } int srslte_enb_dl_put_pdcch_ul(srslte_enb_dl_t *q, srslte_ra_ul_dci_t *grant, srslte_dci_location_t location, - uint32_t rnti_idx, uint32_t sf_idx) + uint16_t rnti, uint32_t sf_idx) { srslte_dci_msg_t dci_msg; - uint16_t rnti = srslte_pdsch_get_rnti_multi(&q->pdsch, rnti_idx); - srslte_dci_msg_pack_pusch(grant, &dci_msg, q->cell.nof_prb); if (srslte_pdcch_encode(&q->pdcch, &dci_msg, location, rnti, q->sf_symbols, sf_idx, q->cfi)) { fprintf(stderr, "Error encoding DCI message\n"); @@ -272,11 +263,9 @@ int srslte_enb_dl_put_pdcch_ul(srslte_enb_dl_t *q, srslte_ra_ul_dci_t *grant, } int srslte_enb_dl_put_pdsch(srslte_enb_dl_t *q, srslte_ra_dl_grant_t *grant, srslte_softbuffer_tx_t *softbuffer, - uint32_t rnti_idx, uint32_t rv_idx, uint32_t sf_idx, + uint16_t rnti, uint32_t rv_idx, uint32_t sf_idx, uint8_t *data) -{ - //srslte_ra_dl_grant_fprint(stdout, grant); - +{ /* Configure pdsch_cfg parameters */ if (srslte_pdsch_cfg(&q->pdsch_cfg, q->cell, grant, q->cfi, sf_idx, rv_idx)) { fprintf(stderr, "Error configuring PDSCH\n"); @@ -284,7 +273,7 @@ int srslte_enb_dl_put_pdsch(srslte_enb_dl_t *q, srslte_ra_dl_grant_t *grant, srs } /* Encode PDSCH */ - if (srslte_pdsch_encode_rnti_idx(&q->pdsch, &q->pdsch_cfg, softbuffer, data, rnti_idx, q->sf_symbols)) { + if (srslte_pdsch_encode(&q->pdsch, &q->pdsch_cfg, softbuffer, data, rnti, q->sf_symbols)) { fprintf(stderr, "Error encoding PDSCH\n"); return SRSLTE_ERROR; } diff --git a/srslte/lib/enb/enb_ul.c b/lib/src/phy/enb/enb_ul.c similarity index 63% rename from srslte/lib/enb/enb_ul.c rename to lib/src/phy/enb/enb_ul.c index cf6f63c99..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 @@ -43,8 +43,7 @@ int srslte_enb_ul_init(srslte_enb_ul_t *q, srslte_cell_t cell, srslte_prach_cfg_t *prach_cfg, srslte_refsignal_dmrs_pusch_cfg_t *pusch_cfg, srslte_pusch_hopping_cfg_t *hopping_cfg, - srslte_pucch_cfg_t *pucch_cfg, - uint32_t nof_rnti) + srslte_pucch_cfg_t *pucch_cfg) { int ret = SRSLTE_ERROR_INVALID_INPUTS; @@ -56,18 +55,16 @@ int srslte_enb_ul_init(srslte_enb_ul_t *q, srslte_cell_t cell, bzero(q, sizeof(srslte_enb_ul_t)); q->cell = cell; - q->nof_rnti = nof_rnti; if (hopping_cfg) { memcpy(&q->hopping_cfg, hopping_cfg, sizeof(srslte_pusch_hopping_cfg_t)); } - q->uci_cfg_en = calloc(sizeof(bool), nof_rnti); - q->srs_cfg_en = calloc(sizeof(bool), nof_rnti); - - q->uci_cfg = calloc(sizeof(srslte_uci_cfg_t), nof_rnti); - q->srs_cfg = calloc(sizeof(srslte_refsignal_srs_cfg_t), nof_rnti); - q->pucch_sched = calloc(sizeof(srslte_pucch_sched_t), nof_rnti); + q->users = calloc(sizeof(srslte_enb_ul_user_t*), SRSLTE_SIRNTI); + if (!q->users) { + perror("malloc"); + goto clean_exit; + } if (srslte_ofdm_rx_init(&q->fft, q->cell.cp, q->cell.nof_prb)) { fprintf(stderr, "Error initiating FFT\n"); @@ -86,18 +83,14 @@ int srslte_enb_ul_init(srslte_enb_ul_t *q, srslte_cell_t cell, goto clean_exit; } - if (srslte_pusch_init_rnti_multi(&q->pusch, nof_rnti)) { - fprintf(stderr, "Error initiating multiple RNTIs in PUSCH\n"); - goto clean_exit; - } - - if (srslte_prach_init_cfg(&q->prach, prach_cfg, q->cell.nof_prb)) { - fprintf(stderr, "Error initiating PRACH\n"); - goto clean_exit; + if (prach_cfg) { + if (srslte_prach_init_cfg(&q->prach, prach_cfg, q->cell.nof_prb)) { + fprintf(stderr, "Error initiating PRACH\n"); + goto clean_exit; + } + srslte_prach_set_detect_factor(&q->prach, 60); } - srslte_prach_set_detect_factor(&q->prach, 60); - srslte_pucch_set_threshold(&q->pucch, 0.5, 0.5); if (srslte_chest_ul_init(&q->chest, cell)) { @@ -141,20 +134,13 @@ void srslte_enb_ul_free(srslte_enb_ul_t *q) { if (q) { - if (q->uci_cfg) { - free(q->uci_cfg); - } - if (q->uci_cfg_en) { - free(q->uci_cfg_en); - } - if (q->srs_cfg) { - free(q->srs_cfg); - } - if (q->srs_cfg_en) { - free(q->srs_cfg_en); - } - if (q->pucch_sched) { - free(q->pucch_sched); + if (q->users) { + for (int i=0;iusers[i]) { + free(q->users[i]); + } + } + free(q->users); } srslte_prach_free(&q->prach); @@ -172,50 +158,69 @@ void srslte_enb_ul_free(srslte_enb_ul_t *q) } } -int srslte_enb_ul_cfg_rnti(srslte_enb_ul_t *q, uint32_t idx, uint16_t rnti) +int srslte_enb_ul_add_rnti(srslte_enb_ul_t *q, uint16_t rnti) +{ + if (!q->users[rnti]) { + q->users[rnti] = malloc(sizeof(srslte_enb_ul_user_t)); + + if (srslte_pucch_set_crnti(&q->pucch, rnti)) { + fprintf(stderr, "Error setting PUCCH rnti\n"); + return -1; + } + if (srslte_pusch_set_rnti(&q->pusch, rnti)) { + fprintf(stderr, "Error setting PUSCH rnti\n"); + return -1; + } + return 0; + } else { + fprintf(stderr, "Error adding rnti=0x%x, already exists\n", rnti); + return -1; + } +} + +void srslte_enb_ul_rem_rnti(srslte_enb_ul_t *q, uint16_t rnti) { - return srslte_pusch_set_rnti_multi(&q->pusch, idx, rnti); + if (q->users[rnti]) { + free(q->users[rnti]); + q->users[rnti] = NULL; + srslte_pusch_clear_rnti(&q->pusch, rnti); + } } -int srslte_enb_ul_cfg_ue(srslte_enb_ul_t *q, uint32_t idx, +int srslte_enb_ul_cfg_ue(srslte_enb_ul_t *q, uint16_t rnti, srslte_uci_cfg_t *uci_cfg, srslte_pucch_sched_t *pucch_sched, srslte_refsignal_srs_cfg_t *srs_cfg) { - if (idx < q->nof_rnti) { + if (q->users[rnti]) { if (uci_cfg) { - memcpy(&q->uci_cfg[idx], uci_cfg, sizeof(srslte_uci_cfg_t)); - q->uci_cfg_en[idx] = true; + memcpy(&q->users[rnti]->uci_cfg, uci_cfg, sizeof(srslte_uci_cfg_t)); + q->users[rnti]->uci_cfg_en = true; } else { - q->uci_cfg_en[idx] = false; + q->users[rnti]->uci_cfg_en = false; } if (pucch_sched) { - memcpy(&q->pucch_sched[idx], pucch_sched, sizeof(srslte_pucch_sched_t)); + memcpy(&q->users[rnti]->pucch_sched, pucch_sched, sizeof(srslte_pucch_sched_t)); } if (srs_cfg) { - memcpy(&q->srs_cfg[idx], srs_cfg, sizeof(srslte_refsignal_srs_cfg_t)); - q->srs_cfg_en[idx] = true; + memcpy(&q->users[rnti]->srs_cfg, srs_cfg, sizeof(srslte_refsignal_srs_cfg_t)); + q->users[rnti]->srs_cfg_en = true; } else { - q->srs_cfg_en[idx] = false; + q->users[rnti]->srs_cfg_en = false; } return SRSLTE_SUCCESS; } else { - fprintf(stderr, "Error configuring UE: Invalid idx=%d, max users=%d\n", idx, q->nof_rnti); + fprintf(stderr, "Error configuring UE: rnti=0x%x not found\n", rnti); return SRSLTE_ERROR; } } - -int srslte_enb_ul_rem_rnti(srslte_enb_ul_t *q, uint32_t idx) -{ - return srslte_pusch_set_rnti_multi(&q->pusch, idx, 0); -} void srslte_enb_ul_fft(srslte_enb_ul_t *q, cf_t *signal_buffer) { srslte_ofdm_rx_sf(&q->fft, signal_buffer, q->sf_symbols); } -int get_pucch(srslte_enb_ul_t *q, uint32_t rnti_idx, +int get_pucch(srslte_enb_ul_t *q, uint16_t rnti, uint32_t pdcch_n_cce, uint32_t sf_rx, srslte_uci_data_t *uci_data, uint8_t bits[SRSLTE_PUCCH_MAX_BITS]) { @@ -223,15 +228,14 @@ int get_pucch(srslte_enb_ul_t *q, uint32_t rnti_idx, srslte_pucch_format_t format = srslte_pucch_get_format(uci_data, q->cell.cp); - uint32_t n_pucch = srslte_pucch_get_npucch(pdcch_n_cce, format, uci_data->scheduling_request, &q->pucch_sched[rnti_idx]); + uint32_t n_pucch = srslte_pucch_get_npucch(pdcch_n_cce, format, uci_data->scheduling_request, &q->users[rnti]->pucch_sched); - if (srslte_chest_ul_estimate_pucch(&q->chest, q->sf_symbols, q->ce, format, n_pucch, sf_rx)) { + if (srslte_chest_ul_estimate_pucch(&q->chest, q->sf_symbols, q->ce, format, n_pucch, sf_rx, &bits[20])) { fprintf(stderr,"Error estimating PUCCH DMRS\n"); return SRSLTE_ERROR; } - - int ret_val = srslte_pucch_decode(&q->pucch, format, n_pucch, sf_rx, q->sf_symbols, q->ce, noise_power, bits); + int ret_val = srslte_pucch_decode(&q->pucch, format, n_pucch, sf_rx, rnti, q->sf_symbols, q->ce, noise_power, bits); if (ret_val < 0) { fprintf(stderr,"Error decoding PUCCH\n"); return SRSLTE_ERROR; @@ -239,21 +243,21 @@ int get_pucch(srslte_enb_ul_t *q, uint32_t rnti_idx, return ret_val; } -int srslte_enb_ul_get_pucch(srslte_enb_ul_t *q, uint32_t rnti_idx, +int srslte_enb_ul_get_pucch(srslte_enb_ul_t *q, uint16_t rnti, uint32_t pdcch_n_cce, uint32_t sf_rx, srslte_uci_data_t *uci_data) { - uint8_t bits[SRSLTE_PUCCH_MAX_BITS]; + uint8_t pucch_bits[SRSLTE_PUCCH_MAX_BITS]; - if (rnti_idx < q->nof_rnti) { + if (q->users[rnti]) { - int ret_val = get_pucch(q, rnti_idx, pdcch_n_cce, sf_rx, uci_data, bits); + int ret_val = get_pucch(q, rnti, pdcch_n_cce, sf_rx, uci_data, pucch_bits); // If we are looking for SR and ACK at the same time and ret=0, means there is no SR. // try again to decode ACK only if (uci_data->scheduling_request && uci_data->uci_ack_len && ret_val != 1) { uci_data->scheduling_request = false; - ret_val = get_pucch(q, rnti_idx, pdcch_n_cce, sf_rx, uci_data, bits); + ret_val = get_pucch(q, rnti, pdcch_n_cce, sf_rx, uci_data, pucch_bits); } // update schedulign request @@ -263,46 +267,66 @@ int srslte_enb_ul_get_pucch(srslte_enb_ul_t *q, uint32_t rnti_idx, // Save ACK bits if (uci_data->uci_ack_len > 0) { - if (ret_val > 0) { - uci_data->uci_ack = bits[0]; - } else { - uci_data->uci_ack = 0; + uci_data->uci_ack = pucch_bits[0]; + } + + // PUCCH2 CQI bits are decoded inside srslte_pucch_decode() + if (uci_data->uci_cqi_len) { + memcpy(uci_data->uci_cqi, pucch_bits, uci_data->uci_cqi_len*sizeof(uint8_t)); + if (uci_data->uci_ack_len >= 1) { + uci_data->uci_ack = pucch_bits[20]; + } + if (uci_data->uci_ack_len == 2) { + uci_data->uci_ack_2 = pucch_bits[21]; } } + return SRSLTE_SUCCESS; } else { - fprintf(stderr, "Invalid rnti_idx=%d\n", rnti_idx); + fprintf(stderr, "Error getting PUCCH: rnti=0x%x not found\n", rnti); return SRSLTE_ERROR; } } int srslte_enb_ul_get_pusch(srslte_enb_ul_t *q, srslte_ra_ul_grant_t *grant, srslte_softbuffer_rx_t *softbuffer, - uint32_t rnti_idx, uint32_t rv_idx, uint32_t current_tx_nb, + uint16_t rnti, uint32_t rv_idx, uint32_t current_tx_nb, uint8_t *data, srslte_uci_data_t *uci_data, uint32_t tti) { - - if (srslte_pusch_cfg(&q->pusch, - &q->pusch_cfg, - grant, - q->uci_cfg_en[rnti_idx]?&q->uci_cfg[rnti_idx]:NULL, - &q->hopping_cfg, - q->srs_cfg_en[rnti_idx]?&q->srs_cfg[rnti_idx]:NULL, - tti, rv_idx, current_tx_nb)) { - fprintf(stderr, "Error configuring PDSCH\n"); - return SRSLTE_ERROR; + if (q->users[rnti]) { + if (srslte_pusch_cfg(&q->pusch, + &q->pusch_cfg, + grant, + q->users[rnti]->uci_cfg_en?&q->users[rnti]->uci_cfg:NULL, + &q->hopping_cfg, + q->users[rnti]->srs_cfg_en?&q->users[rnti]->srs_cfg:NULL, + tti, rv_idx, current_tx_nb)) { + fprintf(stderr, "Error configuring PDSCH\n"); + return SRSLTE_ERROR; + } + } else { + if (srslte_pusch_cfg(&q->pusch, + &q->pusch_cfg, + grant, + NULL, + &q->hopping_cfg, + NULL, + tti, rv_idx, current_tx_nb)) { + fprintf(stderr, "Error configuring PDSCH\n"); + return SRSLTE_ERROR; + } } - + uint32_t cyclic_shift_for_dmrs = 0; srslte_chest_ul_estimate(&q->chest, q->sf_symbols, q->ce, grant->L_prb, tti%10, cyclic_shift_for_dmrs, grant->n_prb); float noise_power = srslte_chest_ul_get_noise_estimate(&q->chest); - return srslte_pusch_uci_decode_rnti_idx(&q->pusch, &q->pusch_cfg, - softbuffer, q->sf_symbols, - q->ce, noise_power, - rnti_idx, data, - uci_data); + return srslte_pusch_decode(&q->pusch, &q->pusch_cfg, + softbuffer, q->sf_symbols, + q->ce, noise_power, + rnti, data, + uci_data); } diff --git a/srslte/lib/fec/CMakeLists.txt b/lib/src/phy/fec/CMakeLists.txt similarity index 86% rename from srslte/lib/fec/CMakeLists.txt rename to lib/src/phy/fec/CMakeLists.txt index 2543881e0..86ed0819d 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 @@ -20,5 +20,4 @@ file(GLOB SOURCES "*.c") add_library(srslte_fec OBJECT ${SOURCES}) -SRSLTE_SET_PIC(srslte_fec) add_subdirectory(test) 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 26ba1cc6a..dc4c19209 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 98% rename from srslte/lib/fec/convcoder.c rename to lib/src/phy/fec/convcoder.c index 45bfeb72d..bc71d63f1 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" /** 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 402e7708c..9c02d97e3 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 98% rename from srslte/lib/fec/rm_turbo.c rename to lib/src/phy/fec/rm_turbo.c index 2b2bf0b58..23929fff3 100644 --- a/srslte/lib/fec/rm_turbo.c +++ b/lib/src/phy/fec/rm_turbo.c @@ -31,11 +31,16 @@ #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 +#undef LV_HAVE_SSE +#undef LV_HAVE_AVX +#endif #ifdef LV_HAVE_SSE #include diff --git a/srslte/lib/fec/softbuffer.c b/lib/src/phy/fec/softbuffer.c similarity index 93% rename from srslte/lib/fec/softbuffer.c rename to lib/src/phy/fec/softbuffer.c index 32f16295e..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) @@ -69,7 +69,7 @@ int srslte_softbuffer_rx_init(srslte_softbuffer_rx_t *q, uint32_t nof_prb) { return SRSLTE_ERROR; } } - srslte_softbuffer_rx_reset(q); + //srslte_softbuffer_rx_reset(q); ret = SRSLTE_SUCCESS; } } 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 57% rename from srslte/lib/fec/viterbi.c rename to lib/src/phy/fec/viterbi.c index 11a3d2c1e..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" @@ -40,7 +40,8 @@ #define TB_ITER 3 -#define DEFAULT_GAIN 16 +#define DEFAULT_GAIN 100 + //#undef LV_HAVE_SSE @@ -99,8 +100,8 @@ int decode37_sse(void *o, uint8_t *symbols, uint8_t *data, uint32_t frame_length chainback_viterbi37_sse(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_sse(q->ptr, symbols, frame_length+q->K-1, &best_state); - chainback_viterbi37_sse(q->ptr, data, frame_length, best_state); + update_viterbi37_blk_sse(q->ptr, symbols, frame_length+q->K-1, NULL); + chainback_viterbi37_sse(q->ptr, data, frame_length, 0); } return q->framebits; @@ -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); @@ -255,7 +437,14 @@ int srslte_viterbi_decode_f(srslte_viterbi_t *q, float *symbols, uint8_t *data, len = 3 * (frame_length + q->K - 1); } if (!q->decode_f) { - srslte_vec_quant_fuc(symbols, q->symbols_uc, q->gain_quant, 127.5, 255, len); + + float max = -9e9; + for (int i=0;i max) { + max = fabs(symbols[i]); + } + } + srslte_vec_quant_fuc(symbols, q->symbols_uc, q->gain_quant/max, 127.5, 255, len); return srslte_viterbi_decode_uc(q, q->symbols_uc, data, frame_length); } else { return q->decode_f(q, symbols, data, frame_length); @@ -276,7 +465,14 @@ int srslte_viterbi_decode_s(srslte_viterbi_t *q, int16_t *symbols, uint8_t *data } else { len = 3 * (frame_length + q->K - 1); } - srslte_vec_quant_suc(symbols, q->symbols_uc, q->gain_quant_s, 127, 255, len); + + int16_t max = -INT16_MAX; + for (int i=0;i max) { + max = abs(symbols[i]); + } + } + srslte_vec_quant_suc(symbols, q->symbols_uc, (float) q->gain_quant/max, 127, 255, len); return srslte_viterbi_decode_uc(q, q->symbols_uc, data, frame_length); } 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 85% rename from srslte/lib/io/CMakeLists.txt rename to lib/src/phy/io/CMakeLists.txt index b913ef941..a56658e34 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 @@ -20,4 +20,3 @@ file(GLOB SOURCES "*.c") add_library(srslte_io OBJECT ${SOURCES}) -SRSLTE_SET_PIC(srslte_io) 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 95% rename from srslte/lib/io/netsink.c rename to lib/src/phy/io/netsink.c index 39bd885a9..ac01df9d2 100644 --- a/srslte/lib/io/netsink.c +++ b/lib/src/phy/io/netsink.c @@ -36,9 +36,9 @@ #include -#include "srslte/io/netsink.h" +#include "srslte/phy/io/netsink.h" -int srslte_netsink_init(srslte_netsink_t *q, char *address, int port, srslte_netsink_type_t type) { +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)); q->sockfd=socket(AF_INET, type==SRSLTE_NETSINK_TCP?SOCK_STREAM:SOCK_DGRAM,0); diff --git a/srslte/lib/io/netsource.c b/lib/src/phy/io/netsource.c similarity index 95% rename from srslte/lib/io/netsource.c rename to lib/src/phy/io/netsource.c index 0e9c804c0..62fe6734b 100644 --- a/srslte/lib/io/netsource.c +++ b/lib/src/phy/io/netsource.c @@ -34,9 +34,9 @@ #include #include -#include "srslte/io/netsource.h" +#include "srslte/phy/io/netsource.h" -int srslte_netsource_init(srslte_netsource_t *q, char *address, int port, srslte_netsource_type_t type) { +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)); q->sockfd=socket(AF_INET,type==SRSLTE_NETSOURCE_TCP?SOCK_STREAM:SOCK_DGRAM,0); diff --git a/srslte/lib/mimo/CMakeLists.txt b/lib/src/phy/mimo/CMakeLists.txt similarity index 86% rename from srslte/lib/mimo/CMakeLists.txt rename to lib/src/phy/mimo/CMakeLists.txt index 92ea2470d..f909a60a9 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 @@ -20,5 +20,4 @@ file(GLOB SOURCES "*.c") add_library(srslte_mimo OBJECT ${SOURCES}) -SRSLTE_SET_PIC(srslte_mimo) add_subdirectory(test) diff --git a/srslte/lib/mimo/layermap.c b/lib/src/phy/mimo/layermap.c similarity index 97% rename from srslte/lib/mimo/layermap.c rename to lib/src/phy/mimo/layermap.c index d4bbd5787..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" @@ -59,7 +59,7 @@ int srslte_layermap_multiplex(cf_t *d[SRSLTE_MAX_CODEWORDS], cf_t *x[SRSLTE_MAX_ n[1] = nof_layers - n[0]; if (nof_symbols[0] / n[0] == nof_symbols[1] / n[1]) { - srslte_layermap_diversity(d[0], x, n[0], nof_symbols[0]); + srslte_layermap_diversity(d[0], x, n[0], nof_symbols[0]); srslte_layermap_diversity(d[1], &x[n[0]], n[1], nof_symbols[1]); return nof_symbols[0] / n[0]; @@ -115,6 +115,7 @@ int srslte_layermap_type(cf_t *d[SRSLTE_MAX_CODEWORDS], cf_t *x[SRSLTE_MAX_LAYER } break; case SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX: + case SRSLTE_MIMO_TYPE_CDD: return srslte_layermap_multiplex(d, x, nof_cw, nof_layers, nof_symbols); break; } @@ -206,6 +207,7 @@ int srslte_layerdemap_type(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *d[SRSLTE_MAX_CODEWO } break; case SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX: + case SRSLTE_MIMO_TYPE_CDD: return srslte_layerdemap_multiplex(x, d, nof_layers, nof_cw, nof_layer_symbols, nof_symbols); break; } diff --git a/lib/src/phy/mimo/precoding.c b/lib/src/phy/mimo/precoding.c new file mode 100644 index 000000000..8781dbad2 --- /dev/null +++ b/lib/src/phy/mimo/precoding.c @@ -0,0 +1,703 @@ +/** + * + * \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 + +#include "srslte/phy/common/phy_common.h" +#include "srslte/phy/mimo/precoding.h" +#include "srslte/phy/utils/vector.h" + +#ifdef LV_HAVE_SSE +#include +#include +int srslte_predecoding_single_sse(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS], cf_t *x, int nof_rxant, int nof_symbols, float noise_estimate); +int srslte_predecoding_diversity2_sse(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], cf_t *x[SRSLTE_MAX_LAYERS], int nof_rxant, int nof_symbols); +#endif + +#ifdef LV_HAVE_AVX +#include +int srslte_predecoding_single_avx(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS], cf_t *x, int nof_rxant, int nof_symbols, float noise_estimate); +#endif + + + +/************************************************ + * + * RECEIVER SIDE FUNCTIONS + * + **************************************************/ + +#ifdef LV_HAVE_SSE + +#define PROD(a,b) _mm_addsub_ps(_mm_mul_ps(a,_mm_moveldup_ps(b)),_mm_mul_ps(_mm_shuffle_ps(a,a,0xB1),_mm_movehdup_ps(b))) + +int srslte_predecoding_single_sse(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS], cf_t *x, int nof_rxant, int nof_symbols, float noise_estimate) { + + float *xPtr = (float*) x; + const float *hPtr1 = (const float*) h[0]; + const float *yPtr1 = (const float*) y[0]; + const float *hPtr2 = (const float*) h[1]; + const float *yPtr2 = (const float*) y[1]; + + __m128 conjugator = _mm_setr_ps(0, -0.f, 0, -0.f); + + __m128 noise = _mm_set1_ps(noise_estimate); + __m128 h1Val1, h2Val1, y1Val1, y2Val1; + __m128 h1Val2, h2Val2, y1Val2, y2Val2; + __m128 hsquare, h1square, h2square, h1conj1, h2conj1, x1Val1, x2Val1; + __m128 hsquare2, h1conj2, h2conj2, x1Val2, x2Val2; + + for (int i=0;i 0) { + hsquare = _mm_add_ps(hsquare, noise); + } + + h1square = _mm_shuffle_ps(hsquare, hsquare, _MM_SHUFFLE(1, 1, 0, 0)); + h2square = _mm_shuffle_ps(hsquare, hsquare, _MM_SHUFFLE(3, 3, 2, 2)); + + /* Conjugate channel */ + h1conj1 = _mm_xor_ps(h1Val1, conjugator); + h2conj1 = _mm_xor_ps(h2Val1, conjugator); + + if (nof_rxant == 2) { + h1conj2 = _mm_xor_ps(h1Val2, conjugator); + h2conj2 = _mm_xor_ps(h2Val2, conjugator); + } + + /* Complex product */ + x1Val1 = PROD(y1Val1, h1conj1); + x2Val1 = PROD(y2Val1, h2conj1); + + if (nof_rxant == 2) { + x1Val2 = PROD(y1Val2, h1conj2); + x2Val2 = PROD(y2Val2, h2conj2); + x1Val1 = _mm_add_ps(x1Val1, x1Val2); + x2Val1 = _mm_add_ps(x2Val1, x2Val2); + } + + x1Val1 = _mm_div_ps(x1Val1, h1square); + x2Val1 = _mm_div_ps(x2Val1, h2square); + + _mm_store_ps(xPtr, x1Val1); xPtr+=4; + _mm_store_ps(xPtr, x2Val1); xPtr+=4; + + } + for (int i=8*(nof_symbols/8);i 0) { + h12square = _mm256_add_ps(h12square, noise); + } + + h1_p = _mm256_permute_ps(h12square, _MM_SHUFFLE(1, 1, 0, 0)); + h2_p = _mm256_permute_ps(h12square, _MM_SHUFFLE(3, 3, 2, 2)); + h1square = _mm256_permute2f128_ps(h1_p, h2_p, 2<<4); + h2square = _mm256_permute2f128_ps(h1_p, h2_p, 3<<4 | 1); + + /* Conjugate channel */ + h1conj1 = _mm256_xor_ps(h1Val1, conjugator); + h2conj1 = _mm256_xor_ps(h2Val1, conjugator); + + if (nof_rxant == 2) { + h1conj2 = _mm256_xor_ps(h1Val2, conjugator); + h2conj2 = _mm256_xor_ps(h2Val2, conjugator); + } + + /* Complex product */ + x1Val = PROD_AVX(y1Val1, h1conj1); + x2Val = PROD_AVX(y2Val1, h2conj1); + + if (nof_rxant == 2) { + x1Val = _mm256_add_ps(x1Val, PROD_AVX(y1Val2, h1conj2)); + x2Val = _mm256_add_ps(x2Val, PROD_AVX(y2Val2, h2conj2)); + } + + x1Val = _mm256_div_ps(x1Val, h1square); + x2Val = _mm256_div_ps(x2Val, h2square); + + _mm256_store_ps(xPtr, x1Val); xPtr+=8; + _mm256_store_ps(xPtr, x2Val); xPtr+=8; + } + for (int i=16*(nof_symbols/16);i 32 && nof_rxant <= 2) { + return srslte_predecoding_single_avx(y, h, x, nof_rxant, nof_symbols, noise_estimate); + } else { + return srslte_predecoding_single_gen(y, h, x, nof_rxant, nof_symbols, noise_estimate); + } +#else + #ifdef LV_HAVE_SSE + if (nof_symbols > 32 && nof_rxant <= 2) { + return srslte_predecoding_single_sse(y, h, x, nof_rxant, nof_symbols, noise_estimate); + } else { + return srslte_predecoding_single_gen(y, h, x, nof_rxant, nof_symbols, noise_estimate); + } + #else + return srslte_predecoding_single_gen(y, h, x, nof_rxant, nof_symbols, noise_estimate); + #endif +#endif +} + +/* ZF/MMSE SISO equalizer x=y(h'h+no)^(-1)h' (ZF if n0=0.0)*/ +int srslte_predecoding_single_multi(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS], cf_t *x, int nof_rxant, int nof_symbols, float noise_estimate) { +#ifdef LV_HAVE_AVX + if (nof_symbols > 32) { + return srslte_predecoding_single_avx(y, h, x, nof_rxant, nof_symbols, noise_estimate); + } else { + return srslte_predecoding_single_gen(y, h, x, nof_rxant, nof_symbols, noise_estimate); + } +#else + #ifdef LV_HAVE_SSE + if (nof_symbols > 32) { + return srslte_predecoding_single_sse(y, h, x, nof_rxant, nof_symbols, noise_estimate); + } else { + return srslte_predecoding_single_gen(y, h, x, nof_rxant, nof_symbols, noise_estimate); + } + #else + return srslte_predecoding_single_gen(y, h, x, nof_rxant, nof_symbols, noise_estimate); + #endif +#endif +} + +/* C implementatino of the SFBC equalizer */ +int srslte_predecoding_diversity_gen_(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], + cf_t *x[SRSLTE_MAX_LAYERS], + int nof_rxant, int nof_ports, int nof_symbols, int symbol_start) +{ + int i; + if (nof_ports == 2) { + cf_t h00, h01, h10, h11, r0, r1; + + for (i = symbol_start/2; i < nof_symbols / 2; i++) { + float hh = 0; + cf_t x0 = 0; + cf_t x1 = 0; + for (int p=0;p 32 && nof_ports == 2) { + return srslte_predecoding_diversity2_sse(y, h, x, nof_rxant, nof_symbols); + } else { + return srslte_predecoding_diversity_gen(y, h, x, nof_rxant, nof_ports, nof_symbols); + } +#else + return srslte_predecoding_diversity_gen(y, h, x, nof_rxant, nof_ports, nof_symbols); +#endif +} + +int srslte_predecoding_diversity_multi(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], cf_t *x[SRSLTE_MAX_LAYERS], + int nof_rxant, int nof_ports, int nof_symbols) +{ +#ifdef LV_HAVE_SSE + if (nof_symbols > 32 && nof_ports == 2) { + return srslte_predecoding_diversity2_sse(y, h, x, nof_rxant, nof_symbols); + } else { + return srslte_predecoding_diversity_gen(y, h, x, nof_rxant, nof_ports, nof_symbols); + } +#else + return srslte_predecoding_diversity_gen(y, h, x, nof_rxant, nof_ports, nof_symbols); +#endif +} + + +int srslte_predecoding_type(cf_t *y_, cf_t *h_[SRSLTE_MAX_PORTS], cf_t *x[SRSLTE_MAX_LAYERS], + int nof_ports, int nof_layers, int nof_symbols, srslte_mimo_type_t type, float noise_estimate) +{ + cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; + cf_t *y[SRSLTE_MAX_PORTS]; + uint32_t nof_rxant = 1; + + for (int i=0;i SRSLTE_MAX_PORTS) { + fprintf(stderr, "Maximum number of ports is %d (nof_ports=%d)\n", SRSLTE_MAX_PORTS, + nof_ports); + return -1; + } + if (nof_layers > SRSLTE_MAX_LAYERS) { + fprintf(stderr, "Maximum number of layers is %d (nof_layers=%d)\n", + SRSLTE_MAX_LAYERS, nof_layers); + return -1; + } + + switch (type) { + case SRSLTE_MIMO_TYPE_CDD: + fprintf(stderr, "CCD not supported\n"); + return -1; + case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA: + if (nof_ports == 1 && nof_layers == 1) { + return srslte_predecoding_single_multi(y, h[0], x[0], nof_rxant, nof_symbols, noise_estimate); + } else { + fprintf(stderr, + "Number of ports and layers must be 1 for transmission on single antenna ports\n"); + return -1; + } + break; + case SRSLTE_MIMO_TYPE_TX_DIVERSITY: + if (nof_ports == nof_layers) { + return srslte_predecoding_diversity_multi(y, h, x, nof_rxant, nof_ports, nof_symbols); + } else { + fprintf(stderr, + "Error number of layers must equal number of ports in transmit diversity\n"); + return -1; + } + break; + case SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX: + fprintf(stderr, "Spatial multiplexing not supported\n"); + return -1; + } + return 0; +} + + + + + + +/************************************************ + * + * TRANSMITTER SIDE FUNCTIONS + * + **************************************************/ + +int srslte_precoding_single(cf_t *x, cf_t *y, int nof_symbols) { + memcpy(y, x, nof_symbols * sizeof(cf_t)); + return nof_symbols; +} +int srslte_precoding_diversity(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PORTS], int nof_ports, + int nof_symbols) { + int i; + if (nof_ports == 2) { + for (i = 0; i < nof_symbols; i++) { + y[0][2 * i] = x[0][i]; + y[1][2 * i] = -conjf(x[1][i]); + y[0][2 * i + 1] = x[1][i]; + y[1][2 * i + 1] = conjf(x[0][i]); + } + // normalize + srslte_vec_sc_prod_cfc(y[0], 1.0/sqrtf(2), y[0], 2*nof_symbols); + srslte_vec_sc_prod_cfc(y[1], 1.0/sqrtf(2), y[1], 2*nof_symbols); + return 2 * i; + } else if (nof_ports == 4) { + //int m_ap = (nof_symbols%4)?(nof_symbols*4-2):nof_symbols*4; + int m_ap = 4 * nof_symbols; + for (i = 0; i < m_ap / 4; i++) { + y[0][4 * i] = x[0][i] / sqrtf(2); + y[1][4 * i] = 0; + y[2][4 * i] = -conjf(x[1][i]) / sqrtf(2); + y[3][4 * i] = 0; + + y[0][4 * i + 1] = x[1][i] / sqrtf(2); + y[1][4 * i + 1] = 0; + y[2][4 * i + 1] = conjf(x[0][i]) / sqrtf(2); + y[3][4 * i + 1] = 0; + + y[0][4 * i + 2] = 0; + y[1][4 * i + 2] = x[2][i] / sqrtf(2); + y[2][4 * i + 2] = 0; + y[3][4 * i + 2] = -conjf(x[3][i]) / sqrtf(2); + + y[0][4 * i + 3] = 0; + y[1][4 * i + 3] = x[3][i] / sqrtf(2); + y[2][4 * i + 3] = 0; + y[3][4 * i + 3] = conjf(x[2][i]) / sqrtf(2); + } + return 4 * i; + } else { + fprintf(stderr, "Number of ports must be 2 or 4 for transmit diversity (nof_ports=%d)\n", nof_ports); + return -1; + } +} + +int srslte_precoding_cdd(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PORTS], int nof_layers, int nof_ports, int nof_symbols) +{ + int i; + if (nof_ports == 2) { + if (nof_layers != 2) { + fprintf(stderr, "Invalid number of layers %d for 2 ports\n", nof_layers); + return -1; + } + for (i = 0; i < nof_symbols; i++) { + y[0][i] = (x[0][i]+x[1][i])/2; + y[1][i] = (x[0][i]-x[1][i])/2; + i++; + y[0][i] = (x[0][i]+x[1][i])/2; + y[1][i] = (-x[0][i]+x[1][i])/2; + } + return 2 * i; + } else if (nof_ports == 4) { + fprintf(stderr, "Not implemented\n"); + return -1; + } else { + fprintf(stderr, "Number of ports must be 2 or 4 for transmit diversity (nof_ports=%d)\n", nof_ports); + return -1; + } +} + +/* 36.211 v10.3.0 Section 6.3.4 */ +int srslte_precoding_type(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PORTS], int nof_layers, + int nof_ports, int nof_symbols, srslte_mimo_type_t type) { + + if (nof_ports > SRSLTE_MAX_PORTS) { + fprintf(stderr, "Maximum number of ports is %d (nof_ports=%d)\n", SRSLTE_MAX_PORTS, + nof_ports); + return -1; + } + if (nof_layers > SRSLTE_MAX_LAYERS) { + fprintf(stderr, "Maximum number of layers is %d (nof_layers=%d)\n", + SRSLTE_MAX_LAYERS, nof_layers); + return -1; + } + + switch (type) { + case SRSLTE_MIMO_TYPE_CDD: + return srslte_precoding_cdd(x, y, nof_layers, nof_ports, nof_symbols); + case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA: + if (nof_ports == 1 && nof_layers == 1) { + return srslte_precoding_single(x[0], y[0], nof_symbols); + } else { + fprintf(stderr, + "Number of ports and layers must be 1 for transmission on single antenna ports\n"); + return -1; + } + break; + case SRSLTE_MIMO_TYPE_TX_DIVERSITY: + if (nof_ports == nof_layers) { + return srslte_precoding_diversity(x, y, nof_ports, nof_symbols); + } else { + fprintf(stderr, + "Error number of layers must equal number of ports in transmit diversity\n"); + return -1; + } + case SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX: + fprintf(stderr, "Spatial multiplexing not supported\n"); + return -1; + } + return 0; +} + diff --git a/srslte/lib/mimo/test/CMakeLists.txt b/lib/src/phy/mimo/test/CMakeLists.txt similarity index 70% rename from srslte/lib/mimo/test/CMakeLists.txt rename to lib/src/phy/mimo/test/CMakeLists.txt index ad2120a88..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) @@ -34,27 +34,19 @@ add_test(layermap_multiplex_11 layermap_test -n 1000 -m multiplex -c 1 -l 1) add_test(layermap_multiplex_12 layermap_test -n 1000 -m multiplex -c 1 -l 2) add_test(layermap_multiplex_13 layermap_test -n 1002 -m multiplex -c 1 -l 3) add_test(layermap_multiplex_14 layermap_test -n 1000 -m multiplex -c 1 -l 4) -add_test(layermap_multiplex_15 layermap_test -n 1000 -m multiplex -c 1 -l 5) -add_test(layermap_multiplex_16 layermap_test -n 1002 -m multiplex -c 1 -l 6) -add_test(layermap_multiplex_17 layermap_test -n 994 -m multiplex -c 1 -l 7) -add_test(layermap_multiplex_18 layermap_test -n 1000 -m multiplex -c 1 -l 8) add_test(layermap_multiplex_22 layermap_test -n 1000 -m multiplex -c 2 -l 2) add_test(layermap_multiplex_23 layermap_test -n 1002 -m multiplex -c 2 -l 3) add_test(layermap_multiplex_24 layermap_test -n 1000 -m multiplex -c 2 -l 4) -add_test(layermap_multiplex_25 layermap_test -n 1002 -m multiplex -c 2 -l 5) -add_test(layermap_multiplex_26 layermap_test -n 1002 -m multiplex -c 2 -l 6) -add_test(layermap_multiplex_27 layermap_test -n 1000 -m multiplex -c 2 -l 7) -add_test(layermap_multiplex_28 layermap_test -n 1000 -m multiplex -c 2 -l 8) ######################################################################## # LAYER MAPPING TEST ######################################################################## -add_executable(precoding_test precoding_test.c) -target_link_libraries(precoding_test srslte) +add_executable(precoding_test precoder_test.c) +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/lib/src/phy/mimo/test/precoder_mex.c b/lib/src/phy/mimo/test/precoder_mex.c new file mode 100644 index 000000000..958f06262 --- /dev/null +++ b/lib/src/phy/mimo/test/precoder_mex.c @@ -0,0 +1,128 @@ +/** + * + * \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 "srslte/srslte.h" +#include "srslte/mex/mexutils.h" + +/** MEX function to be called from MATLAB to test the predecoder + */ + +#define INPUT prhs[0] +#define NLAYERS prhs[1] +#define NPORTS prhs[2] +#define TXSCHEME prhs[3] +#define NOF_INPUTS 3 + + +void help() +{ + mexErrMsgTxt + ("[output] = srslte_decoder(input, NLayers, NCellRefP, TxScheme)\n\n"); +} + +/* the gateway function */ +void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) +{ + cf_t *input = NULL; + cf_t *output = NULL; + + if (nrhs < NOF_INPUTS) { + help(); + return; + } + + // Read input symbols + int nof_symbols = mexutils_read_cf(INPUT, &input); + if (nof_symbols < 0) { + mexErrMsgTxt("Error reading input\n"); + return; + } + uint32_t nof_layers = mxGetScalar(NLAYERS); + uint32_t nof_tx_ports = mxGetScalar(NPORTS); + uint32_t nof_codewords = 1; + + mexPrintf("nof_tx_ports=%d, nof_layers=%d, nof_symbols=%d\n", nof_tx_ports, nof_layers, nof_symbols); + + cf_t *y[SRSLTE_MAX_PORTS]; + cf_t *x[SRSLTE_MAX_LAYERS]; + cf_t *d[SRSLTE_MAX_CODEWORDS]; + + d[0] = input; // Single codeword supported only + + /* Allocate memory */ + for (int i = 0; i < nof_layers; i++) { + x[i] = srslte_vec_malloc(sizeof(cf_t)*nof_symbols/nof_layers); + } + + output = srslte_vec_malloc(sizeof(cf_t)*nof_symbols*nof_tx_ports/nof_layers); + for (int i=0;i= NOF_INPUTS) { + txscheme = mxArrayToString(TXSCHEME); + } + srslte_mimo_type_t type = SRSLTE_MIMO_TYPE_SINGLE_ANTENNA; + if (!strcmp(txscheme, "Port0")) { + type = SRSLTE_MIMO_TYPE_SINGLE_ANTENNA; + } else if (!strcmp(txscheme, "TxDiversity")) { + type = SRSLTE_MIMO_TYPE_TX_DIVERSITY; + } else if (!strcmp(txscheme, "CDD")) { + type = SRSLTE_MIMO_TYPE_CDD; + } else if (!strcmp(txscheme, "SpatialMux")) { + type = SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX; + } else { + mexPrintf("Unsupported TxScheme=%s\n", txscheme); + return; + } + int symbols_layers[SRSLTE_MAX_LAYERS]; + for (int i=0;i= 1) { + mexutils_write_cf(output, &plhs[0], nof_symbols/nof_layers, nof_tx_ports); + } + + if (input) { + free(input); + } + if (output) { + free(output); + } + for (int i=0;i +#include "srslte/srslte.h" +#include "srslte/mex/mexutils.h" + +/** MEX function to be called from MATLAB to test the predecoder + */ + +#define INPUT prhs[0] +#define HEST prhs[1] +#define NEST prhs[2] +#define NLAYERS prhs[3] +#define TXSCHEME prhs[4] +#define NOF_INPUTS 5 + + +void help() +{ + mexErrMsgTxt + ("[output] = srslte_predecoder(input, hest, nest, Nl, TxScheme)\n\n"); +} + +/* the gateway function */ +void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) +{ + cf_t *input = NULL; + cf_t *hest = NULL; + cf_t *output = NULL; + uint32_t nof_symbols = 0; + + if (nrhs < NOF_INPUTS) { + help(); + return; + } + + // Read input symbols + if (mexutils_read_cf(INPUT, &input) < 0) { + mexErrMsgTxt("Error reading input\n"); + return; + } + uint32_t nof_layers = mxGetScalar(NLAYERS); + uint32_t nof_tx_ports = 1; + uint32_t nof_codewords = 1; + + uint32_t nof_rx_ants = 1; + const mwSize *dims = mxGetDimensions(INPUT); + mwSize ndims = mxGetNumberOfDimensions(INPUT); + nof_symbols = dims[0]; + + if (ndims >= 2) { + nof_rx_ants = dims[1]; + } + + // Read channel estimates + if (mexutils_read_cf(HEST, &hest) < 0) { + mexErrMsgTxt("Error reading hest\n"); + return; + } + dims = mxGetDimensions(HEST); + ndims = mxGetNumberOfDimensions(HEST); + + if (ndims == 3) { + nof_tx_ports = dims[2]; + } + + mexPrintf("nof_tx_ports=%d, nof_rx_ants=%d, nof_layers=%d, nof_symbols=%d\n", nof_tx_ports, nof_rx_ants, nof_layers, nof_symbols); + + // Read noise estimate + float noise_estimate = 0; + if (nrhs >= NOF_INPUTS) { + noise_estimate = mxGetScalar(NEST); + } + + cf_t *x[SRSLTE_MAX_LAYERS]; + cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; + cf_t *y[SRSLTE_MAX_PORTS]; + + for (int i=0;i= NOF_INPUTS) { + txscheme = mxArrayToString(TXSCHEME); + } + srslte_mimo_type_t type = SRSLTE_MIMO_TYPE_SINGLE_ANTENNA; + if (!strcmp(txscheme, "Port0")) { + type = SRSLTE_MIMO_TYPE_SINGLE_ANTENNA; + } else if (!strcmp(txscheme, "TxDiversity")) { + type = SRSLTE_MIMO_TYPE_TX_DIVERSITY; + } else if (!strcmp(txscheme, "CDD")) { + type = SRSLTE_MIMO_TYPE_CDD; + } else if (!strcmp(txscheme, "SpatialMux")) { + type = SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX; + } else { + mexPrintf("Unsupported TxScheme=%s\n", txscheme); + return; + } + int symbols_layers[SRSLTE_MAX_LAYERS]; + for (int i=0;i= 1) { + mexutils_write_cf(output, &plhs[0], nof_symbols, 1); + } + + if (input) { + free(input); + } + if (output) { + free(output); + } + for (int i=0;i #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 86% rename from srslte/lib/phch/CMakeLists.txt rename to lib/src/phy/phch/CMakeLists.txt index bc07d53d2..a0a7169cd 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 @@ -20,5 +20,4 @@ file(GLOB SOURCES "*.c") add_library(srslte_phch OBJECT ${SOURCES}) -SRSLTE_SET_PIC(srslte_phch) add_subdirectory(test) diff --git a/srslte/lib/phch/cqi.c b/lib/src/phy/phch/cqi.c similarity index 63% rename from srslte/lib/phch/cqi.c rename to lib/src/phy/phch/cqi.c index df46152b0..a684db8c9 100644 --- a/srslte/lib/phch/cqi.c +++ b/lib/src/phy/phch/cqi.c @@ -33,13 +33,15 @@ #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 * + *******************************************************/ int srslte_cqi_hl_subband_pack(srslte_cqi_hl_subband_t *msg, uint8_t buff[SRSLTE_CQI_MAX_BITS]) { uint8_t *body_ptr = buff; @@ -89,6 +91,74 @@ int srslte_cqi_value_pack(srslte_cqi_value_t *value, uint8_t buff[SRSLTE_CQI_MAX return -1; } + +/******************************************************* + * UNPACKING FUNCTIONS * + *******************************************************/ + +int srslte_cqi_hl_subband_unpack(uint8_t buff[SRSLTE_CQI_MAX_BITS], srslte_cqi_hl_subband_t *msg) +{ + uint8_t *body_ptr = buff; + msg->wideband_cqi = srslte_bit_pack(&body_ptr, 4); + msg->subband_diff_cqi = srslte_bit_pack(&body_ptr, 2*msg->N); + + return 4+2*msg->N; +} + +int srslte_cqi_ue_subband_unpack(uint8_t buff[SRSLTE_CQI_MAX_BITS], srslte_cqi_ue_subband_t *msg) +{ + uint8_t *body_ptr = buff; + msg->wideband_cqi = srslte_bit_pack(&body_ptr, 4); + msg->subband_diff_cqi = srslte_bit_pack(&body_ptr, 2); + msg->subband_diff_cqi = srslte_bit_pack(&body_ptr, msg->L); + + return 4+2+msg->L; +} + +int srslte_cqi_format2_wideband_unpack(uint8_t buff[SRSLTE_CQI_MAX_BITS], srslte_cqi_format2_wideband_t *msg) +{ + uint8_t *body_ptr = buff; + msg->wideband_cqi = srslte_bit_pack(&body_ptr, 4); + return 4; +} + +int srslte_cqi_format2_subband_unpack(uint8_t buff[SRSLTE_CQI_MAX_BITS], srslte_cqi_format2_subband_t *msg) +{ + uint8_t *body_ptr = buff; + msg->subband_cqi = srslte_bit_pack(&body_ptr, 4); + msg->subband_label = srslte_bit_pack(&body_ptr, msg->subband_label_2_bits?2:1); + return 4+(msg->subband_label_2_bits)?2:1; +} + +int srslte_cqi_value_unpack(uint8_t buff[SRSLTE_CQI_MAX_BITS], srslte_cqi_value_t *value) +{ + switch(value->type) { + case SRSLTE_CQI_TYPE_WIDEBAND: + return srslte_cqi_format2_wideband_unpack(buff, &value->wideband); + case SRSLTE_CQI_TYPE_SUBBAND: + return srslte_cqi_format2_subband_unpack(buff, &value->subband); + case SRSLTE_CQI_TYPE_SUBBAND_UE: + return srslte_cqi_ue_subband_unpack(buff, &value->subband_ue); + case SRSLTE_CQI_TYPE_SUBBAND_HL: + return srslte_cqi_hl_subband_unpack(buff, &value->subband_hl); + } + return -1; +} + +int srslte_cqi_size(srslte_cqi_value_t *value) { + switch(value->type) { + case SRSLTE_CQI_TYPE_WIDEBAND: + return 4; + case SRSLTE_CQI_TYPE_SUBBAND: + return 4+(value->subband.subband_label_2_bits)?2:1; + case SRSLTE_CQI_TYPE_SUBBAND_UE: + return 4+2+value->subband_ue.L; + case SRSLTE_CQI_TYPE_SUBBAND_HL: + return 4+2*value->subband_hl.N; + } + return -1; +} + bool srslte_cqi_send(uint32_t I_cqi_pmi, uint32_t tti) { uint32_t N_p = 0; @@ -138,6 +208,17 @@ bool srslte_cqi_send(uint32_t I_cqi_pmi, uint32_t tti) { } +// CQI-to-Spectral Efficiency: 36.213 Table 7.2.3-1 */ +static float cqi_to_coderate[16] = {0, 0.1523, 0.2344, 0.3770, 0.6016, 0.8770, 1.1758, 1.4766, 1.9141, 2.4063, 2.7305, 3.3223, 3.9023, 4.5234, 5.1152, 5.5547}; + +float srslte_cqi_to_coderate(uint32_t cqi) { + if (cqi < 16) { + return cqi_to_coderate[cqi]; + } else { + return 0; + } +} + /* SNR-to-CQI conversion, got from "Downlink SNR to CQI Mapping for Different Multiple Antenna Techniques in LTE" * Table III. */ diff --git a/srslte/lib/phch/dci.c b/lib/src/phy/phch/dci.c similarity index 87% rename from srslte/lib/phch/dci.c rename to lib/src/phy/phch/dci.c index 4dea38567..96c446259 100644 --- a/srslte/lib/phch/dci.c +++ b/lib/src/phy/phch/dci.c @@ -33,14 +33,16 @@ #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" +#define HARQ_PID_LEN 3 + /* Unpacks a DCI message and configures the DL grant object */ int srslte_dci_msg_to_dl_grant(srslte_dci_msg_t *msg, uint16_t msg_rnti, @@ -65,7 +67,7 @@ int srslte_dci_msg_to_dl_grant(srslte_dci_msg_t *msg, uint16_t msg_rnti, //srslte_dci_format_t tmp = msg->format; ret = srslte_dci_msg_unpack_pdsch(msg, dl_dci, nof_prb, nof_ports, crc_is_crnti); if (ret) { - //fprintf(stderr, "Can't unpack DCI message %s (%d)\n", srslte_dci_format_string(tmp), tmp); + //fprintf(stderr, "Can't unpack DCI message %s (%d)\n", srslte_dci_format_string(msg->format), msg->format); return ret; } @@ -110,7 +112,6 @@ int srslte_dci_rar_to_ul_grant(srslte_dci_rar_grant_t *rar, uint32_t nof_prb, nof_prb, nof_prb); if (srslte_ra_ul_dci_to_grant(ul_dci, nof_prb, n_rb_ho, grant, 0)) { - fprintf(stderr, "Error computing resource allocation\n"); return SRSLTE_ERROR; } @@ -177,7 +178,6 @@ int srslte_dci_msg_to_ul_grant(srslte_dci_msg_t *msg, uint32_t nof_prb, } if (srslte_ra_ul_dci_to_grant(ul_dci, nof_prb, n_rb_ho, grant, harq_pid)) { - fprintf(stderr, "Error computing resource allocation\n"); return ret; } @@ -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 + 3 + 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 + 3 + 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+3+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+3+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+3+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++; } @@ -445,20 +445,17 @@ int dci_format0_pack(srslte_ra_ul_dci_t *data, srslte_dci_msg_t *msg, uint32_t n *y++ = data->ndi; - // TCP commands not implemented - *y++ = 0; - *y++ = 0; + // TCP command for PUSCH + srslte_bit_unpack(data->tpc_pusch, &y, 2); // DM RS not implemented - *y++ = 0; - *y++ = 0; - *y++ = 0; + srslte_bit_unpack(data->n_dmrs, &y, 3); // CQI request *y++ = data->cqi_request; // Padding with zeros - uint32_t n = srslte_dci_format_sizeof_lut(SRSLTE_DCI_FORMAT0, nof_prb); + uint32_t n = srslte_dci_format_sizeof(SRSLTE_DCI_FORMAT0, nof_prb, 1); while (y - msg->data < n) { *y++ = 0; } @@ -477,7 +474,7 @@ int dci_format0_unpack(srslte_dci_msg_t *msg, srslte_ra_ul_dci_t *data, uint32_t uint32_t n_ul_hop; /* Make sure it's a SRSLTE_DCI_FORMAT0 message */ - if (msg->nof_bits != srslte_dci_format_sizeof_lut(SRSLTE_DCI_FORMAT0, nof_prb)) { + if (msg->nof_bits != srslte_dci_format_sizeof(SRSLTE_DCI_FORMAT0, nof_prb, 1)) { fprintf(stderr, "Invalid message length for format 0\n"); return SRSLTE_ERROR; } @@ -559,19 +556,18 @@ 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, 3); + srslte_bit_unpack(data->harq_process, &y, HARQ_PID_LEN); *y++ = data->ndi; // rv version srslte_bit_unpack(data->rv_idx, &y, 2); - // TPC not implemented - *y++ = 0; - *y++ = 0; + // TCP command for PUCCH + srslte_bit_unpack(data->tpc_pucch, &y, 2); // Padding with zeros - uint32_t n = srslte_dci_format_sizeof_lut(SRSLTE_DCI_FORMAT1, nof_prb); + uint32_t n = srslte_dci_format_sizeof(SRSLTE_DCI_FORMAT1, nof_prb, 1); while (y - msg->data < n) { *y++ = 0; } @@ -586,7 +582,7 @@ int dci_format1_unpack(srslte_dci_msg_t *msg, srslte_ra_dl_dci_t *data, uint32_t uint8_t *y = msg->data; /* Make sure it's a SRSLTE_DCI_FORMAT1 message */ - if (msg->nof_bits != srslte_dci_format_sizeof_lut(SRSLTE_DCI_FORMAT1, nof_prb)) { + if (msg->nof_bits != srslte_dci_format_sizeof(SRSLTE_DCI_FORMAT1, nof_prb, 1)) { fprintf(stderr, "Invalid message length for format 1\n"); return SRSLTE_ERROR; } @@ -619,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, 3); + data->harq_process = srslte_bit_pack(&y, HARQ_PID_LEN); data->ndi = *y++ ? true : false; // rv version @@ -627,7 +623,8 @@ int dci_format1_unpack(srslte_dci_msg_t *msg, srslte_ra_dl_dci_t *data, uint32_t // TPC not implemented - data->nof_tb = 1; + data->tb_en[0] = true; + data->tb_en[1] = false; return SRSLTE_SUCCESS; } @@ -691,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, 3); + 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) { @@ -716,7 +713,7 @@ int dci_format1As_pack(srslte_ra_dl_dci_t *data, srslte_dci_msg_t *msg, uint32_t } // Padding with zeros - uint32_t n = srslte_dci_format_sizeof_lut(SRSLTE_DCI_FORMAT1A, nof_prb); + uint32_t n = srslte_dci_format_sizeof(SRSLTE_DCI_FORMAT1A, nof_prb, 1); while (y - msg->data < n) { *y++ = 0; } @@ -735,7 +732,7 @@ int dci_format1As_unpack(srslte_dci_msg_t *msg, srslte_ra_dl_dci_t *data, uint32 uint8_t *y = msg->data; /* Make sure it's a SRSLTE_DCI_FORMAT0 message */ - if (msg->nof_bits != srslte_dci_format_sizeof_lut(SRSLTE_DCI_FORMAT1A, nof_prb)) { + if (msg->nof_bits != srslte_dci_format_sizeof(SRSLTE_DCI_FORMAT1A, nof_prb, 1)) { fprintf(stderr, "Invalid message length for format 1A\n"); return SRSLTE_ERROR; } @@ -792,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, 3); + 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) { @@ -816,7 +813,8 @@ int dci_format1As_unpack(srslte_dci_msg_t *msg, srslte_ra_dl_dci_t *data, uint32 data->type2_alloc.n_prb1a = *y++; // LSB indicates N_prb_1a for TBS } - data->nof_tb = 1; + data->tb_en[0] = true; + data->tb_en[1] = false; return SRSLTE_SUCCESS; } @@ -852,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, 3); + data->harq_process = srslte_bit_pack(&y, HARQ_PID_LEN); data->ndi = *y++ ? true : false; data->rv_idx = srslte_bit_pack(&y, 2); @@ -862,7 +860,8 @@ int dci_format1B_unpack(srslte_dci_msg_t *msg, srslte_ra_dl_dci_t *data, uint32_ data->pinfo = srslte_bit_pack(&y, tpmi_bits(nof_ports)); data->pconf = *y++ ? true : false; - data->nof_tb = 1; + data->tb_en[0] = true; + data->tb_en[1] = false; return SRSLTE_SUCCESS; } @@ -928,7 +927,7 @@ int dci_format1Cs_unpack(srslte_dci_msg_t *msg, srslte_ra_dl_dci_t *data, uint32 /* pack bits */ uint8_t *y = msg->data; - if (msg->nof_bits != srslte_dci_format_sizeof_lut(SRSLTE_DCI_FORMAT1C, nof_prb)) { + if (msg->nof_bits != srslte_dci_format_sizeof(SRSLTE_DCI_FORMAT1C, nof_prb, 1)) { fprintf(stderr, "Invalid message length for format 1C\n"); return SRSLTE_ERROR; } @@ -957,7 +956,8 @@ int dci_format1Cs_unpack(srslte_dci_msg_t *msg, srslte_ra_dl_dci_t *data, uint32 msg->nof_bits = (y - msg->data); - data->nof_tb = 1; + data->tb_en[0] = true; + data->tb_en[1] = false; return SRSLTE_SUCCESS; } @@ -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, 3); + data->harq_process = srslte_bit_pack(&y, HARQ_PID_LEN); data->ndi = *y++ ? true : false; data->rv_idx = srslte_bit_pack(&y, 2); @@ -1003,12 +1003,84 @@ int dci_format1D_unpack(srslte_dci_msg_t *msg, srslte_ra_dl_dci_t *data, uint32_ data->pinfo = srslte_bit_pack(&y, tpmi_bits(nof_ports)); data->power_offset = *y++ ? true : false; - data->nof_tb = 1; + data->tb_en[0] = true; + data->tb_en[1] = false; return SRSLTE_SUCCESS; } +int dci_format2AB_pack(srslte_ra_dl_dci_t *data, srslte_dci_msg_t *msg, uint32_t nof_prb, uint32_t nof_ports) { + + /* pack bits */ + uint8_t *y = msg->data; + + if (nof_prb > 10) { + *y++ = data->alloc_type; + } + + /* Resource allocation: type0 or type 1 */ + uint32_t P = srslte_ra_type0_P(nof_prb); + uint32_t alloc_size = (uint32_t) ceilf((float) nof_prb / P); + switch (data->alloc_type) { + case SRSLTE_RA_ALLOC_TYPE0: + srslte_bit_unpack((uint32_t) data->type0_alloc.rbg_bitmask, &y, alloc_size); + break; + case SRSLTE_RA_ALLOC_TYPE1: + srslte_bit_unpack((uint32_t) data->type1_alloc.rbg_subset, &y, (int) ceilf(log2f(P))); + *y++ = data->type1_alloc.shift ? 1 : 0; + srslte_bit_unpack((uint32_t) data->type1_alloc.vrb_bitmask, &y, + alloc_size - (int) ceilf(log2f(P)) - 1); + break; + default: + fprintf(stderr, + "Format 1 accepts type0 or type1 resource allocation only\n"); + return SRSLTE_ERROR; + + } + + // pack TPC command for PUCCH (not implemented) + y+=2; + + /* harq process number */ + srslte_bit_unpack(data->harq_process, &y, HARQ_PID_LEN); + + // Transpor block to codeword swap flag + if (msg->format == SRSLTE_DCI_FORMAT2B) { + *y++ = data->sram_id; + } else { + *y++ = data->tb_cw_swap; + } + + /* pack TB1 */ + srslte_bit_unpack(data->mcs_idx, &y, 5); + *y++ = data->ndi; + srslte_bit_unpack(data->rv_idx, &y, 2); + + /* pack TB2 */ + srslte_bit_unpack(data->mcs_idx_1, &y, 5); + *y++ = data->ndi_1; + srslte_bit_unpack(data->rv_idx_1, &y, 2); + + // Precoding information + if (msg->format == SRSLTE_DCI_FORMAT2) { + srslte_bit_unpack(data->pinfo, &y, precoding_bits_f2(nof_ports)); + } else if (msg->format == SRSLTE_DCI_FORMAT2A) { + srslte_bit_unpack(data->pinfo, &y, precoding_bits_f2a(nof_ports)); + } + + // Padding with zeros + uint32_t n = srslte_dci_format_sizeof(msg->format, nof_prb, nof_ports); + while (y - msg->data < n) { + *y++ = 0; + } + msg->nof_bits = (y - msg->data); + + + + return SRSLTE_SUCCESS; +} + int dci_format2AB_unpack(srslte_dci_msg_t *msg, srslte_ra_dl_dci_t *data, uint32_t nof_prb, uint32_t nof_ports) { /* pack bits */ @@ -1042,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, 3); + data->harq_process = srslte_bit_pack(&y, HARQ_PID_LEN); // Transpor block to codeword swap flag if (msg->format == SRSLTE_DCI_FORMAT2B) { @@ -1053,25 +1125,31 @@ int dci_format2AB_unpack(srslte_dci_msg_t *msg, srslte_ra_dl_dci_t *data, uint32 /* unpack MCS according to 7.1.7 of 36.213 */ data->mcs_idx = srslte_bit_pack(&y, 5); - data->ndi = *y++ ? true : false; - - // rv version data->rv_idx = srslte_bit_pack(&y, 2); + if (data->mcs_idx == 0 && data->rv_idx == 1) { + data->tb_en[0] = false; + } else { + data->tb_en[0] = true; + } // same for tb1 data->mcs_idx_1 = srslte_bit_pack(&y, 5); data->ndi_1 = *y++ ? true : false; data->rv_idx_1 = srslte_bit_pack(&y, 2); + if (data->mcs_idx_1 == 0 && data->rv_idx_1 == 1) { + data->tb_en[1] = false; + } else { + data->tb_en[1] = true; + } // Precoding information - if (msg->format == SRSLTE_DCI_FORMAT2A) { + if (msg->format == SRSLTE_DCI_FORMAT2) { data->pinfo = srslte_bit_pack(&y, precoding_bits_f2(nof_ports)); } else if (msg->format == SRSLTE_DCI_FORMAT2A) { data->pinfo = srslte_bit_pack(&y, precoding_bits_f2a(nof_ports)); } - data->nof_tb = 2; return SRSLTE_SUCCESS; } @@ -1079,19 +1157,27 @@ int dci_format2AB_unpack(srslte_dci_msg_t *msg, srslte_ra_dl_dci_t *data, uint32 int srslte_dci_msg_pack_pdsch(srslte_ra_dl_dci_t *data, srslte_dci_format_t format, - srslte_dci_msg_t *msg, uint32_t nof_prb, + srslte_dci_msg_t *msg, uint32_t nof_prb, uint32_t nof_ports, bool crc_is_crnti) { msg->format = format; switch (format) { case SRSLTE_DCI_FORMAT1: + msg->format = format; return dci_format1_pack(data, msg, nof_prb); case SRSLTE_DCI_FORMAT1A: + msg->format = format; return dci_format1As_pack(data, msg, nof_prb, crc_is_crnti); case SRSLTE_DCI_FORMAT1C: + msg->format = format; return dci_format1Cs_pack(data, msg, nof_prb); + case SRSLTE_DCI_FORMAT2: + case SRSLTE_DCI_FORMAT2A: + case SRSLTE_DCI_FORMAT2B: + msg->format = format; + return dci_format2AB_pack(data, msg, nof_prb, nof_ports); default: - fprintf(stderr, "DCI pack pdsch: Invalid DCI format %s in \n", + fprintf(stderr, "DCI pack pdsch: Invalid DCI format %s\n", srslte_dci_format_string(format)); return SRSLTE_ERROR; } @@ -1206,16 +1292,16 @@ int srslte_dci_msg_get_type(srslte_dci_msg_t *msg, srslte_dci_msg_type_t *type, uint16_t msg_rnti) { DEBUG("Get message type: nof_bits=%d, msg_rnti=0x%x\n", msg->nof_bits, msg_rnti); - if (msg->nof_bits == srslte_dci_format_sizeof_lut(SRSLTE_DCI_FORMAT0, nof_prb) + if (msg->nof_bits == srslte_dci_format_sizeof(SRSLTE_DCI_FORMAT0, nof_prb, 1) && !msg->data[0]) { type->type = SRSLTE_DCI_MSG_TYPE_PUSCH_SCHED; type->format = SRSLTE_DCI_FORMAT0; return SRSLTE_SUCCESS; - } else if (msg->nof_bits == srslte_dci_format_sizeof_lut(SRSLTE_DCI_FORMAT1, nof_prb)) { + } else if (msg->nof_bits == srslte_dci_format_sizeof(SRSLTE_DCI_FORMAT1, nof_prb, 1)) { type->type = SRSLTE_DCI_MSG_TYPE_PDSCH_SCHED; // only these 2 types supported type->format = SRSLTE_DCI_FORMAT1; return SRSLTE_SUCCESS; - } else if (msg->nof_bits == srslte_dci_format_sizeof_lut(SRSLTE_DCI_FORMAT1A, nof_prb)) { + } else if (msg->nof_bits == srslte_dci_format_sizeof(SRSLTE_DCI_FORMAT1A, nof_prb, 1)) { /* The RNTI is not the only condition. Also some fields in the packet. * if (msg_rnti >= SRSLTE_CRNTI_START && msg_rnti <= SRSLTE_CRNTI_END) { type->type = SRSLTE_DCI_MSG_TYPE_RA_PROC_PDCCH; @@ -1226,7 +1312,7 @@ int srslte_dci_msg_get_type(srslte_dci_msg_t *msg, srslte_dci_msg_type_t *type, type->format = SRSLTE_DCI_FORMAT1A; //} return SRSLTE_SUCCESS; - } else if (msg->nof_bits == srslte_dci_format_sizeof_lut(SRSLTE_DCI_FORMAT1C, nof_prb)) { + } else if (msg->nof_bits == srslte_dci_format_sizeof(SRSLTE_DCI_FORMAT1C, nof_prb, 1)) { if (msg_rnti == SRSLTE_MRNTI) { type->type = SRSLTE_DCI_MSG_TYPE_MCCH_CHANGE; type->format = SRSLTE_DCI_FORMAT1C; 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 97% rename from srslte/lib/phch/pbch.c rename to lib/src/phy/phch/pbch.c index c997e96b4..783ae1e04 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 @@ -262,8 +262,8 @@ void srslte_pbch_free(srslte_pbch_t *q) { void srslte_pbch_mib_unpack(uint8_t *msg, srslte_cell_t *cell, uint32_t *sfn) { int phich_res; - cell->bw_idx = srslte_bit_pack(&msg, 3); - switch (cell->bw_idx) { + uint32_t bw_idx = srslte_bit_pack(&msg, 3); + switch (bw_idx) { case 0: cell->nof_prb = 6; break; @@ -271,7 +271,7 @@ void srslte_pbch_mib_unpack(uint8_t *msg, srslte_cell_t *cell, uint32_t *sfn) { cell->nof_prb = 15; break; default: - cell->nof_prb = (cell->bw_idx - 1) * 25; + cell->nof_prb = (bw_idx - 1) * 25; break; } if (*msg) { @@ -452,7 +452,6 @@ int srslte_pbch_decode(srslte_pbch_t *q, cf_t *slot1_symbols, cf_t *ce_slot1[SRS for (i = 0; i < SRSLTE_MAX_PORTS; i++) { x[i] = q->x[i]; } - memset(&x[SRSLTE_MAX_PORTS], 0, sizeof(cf_t*) * (SRSLTE_MAX_LAYERS - SRSLTE_MAX_PORTS)); /* extract symbols */ if (q->nof_symbols != srslte_pbch_get(slot1_symbols, q->symbols[0], q->cell)) { diff --git a/srslte/lib/phch/pcfich.c b/lib/src/phy/phch/pcfich.c similarity index 74% rename from srslte/lib/phch/pcfich.c rename to lib/src/phy/phch/pcfich.c index e1fc400a3..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] = { @@ -57,10 +57,14 @@ bool srslte_pcfich_exists(int nframe, int nslot) { return true; } +int srslte_pcfich_init(srslte_pcfich_t *q, srslte_regs_t *regs, srslte_cell_t cell) { + return srslte_pcfich_init_multi(q, regs, cell, 1); +} + /** Initializes the pcfich channel receiver. * On error, returns -1 and frees the structrure */ -int srslte_pcfich_init(srslte_pcfich_t *q, srslte_regs_t *regs, srslte_cell_t cell) { +int srslte_pcfich_init_multi(srslte_pcfich_t *q, srslte_regs_t *regs, srslte_cell_t cell, uint32_t nof_rx_antennas) { int ret = SRSLTE_ERROR_INVALID_INPUTS; if (q != NULL && @@ -73,6 +77,7 @@ int srslte_pcfich_init(srslte_pcfich_t *q, srslte_regs_t *regs, srslte_cell_t ce q->cell = cell; q->regs = regs; q->nof_symbols = PCFICH_RE; + q->nof_rx_antennas = nof_rx_antennas; if (srslte_modem_table_lte(&q->mod, SRSLTE_MOD_QPSK)) { goto clean; @@ -145,21 +150,33 @@ int srslte_pcfich_cfi_encode(uint32_t cfi, uint8_t bits[PCFICH_CFI_LEN]) { } } +int srslte_pcfich_decode(srslte_pcfich_t *q, cf_t *sf_symbols, cf_t *ce[SRSLTE_MAX_PORTS], float noise_estimate, + uint32_t nsubframe, uint32_t *cfi, float *corr_result) +{ + cf_t *_sf_symbols[SRSLTE_MAX_PORTS]; + cf_t *_ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; + + _sf_symbols[0] = sf_symbols; + for (int i=0;icell.nof_ports;i++) { + _ce[i][0] = ce[i]; + } + return srslte_pcfich_decode_multi(q, _sf_symbols, _ce, noise_estimate, nsubframe, cfi, corr_result); +} + /* Decodes the PCFICH channel and saves the CFI in the cfi pointer. * * Returns 1 if successfully decoded the CFI, 0 if not and -1 on error */ -int srslte_pcfich_decode(srslte_pcfich_t *q, cf_t *slot_symbols, cf_t *ce[SRSLTE_MAX_PORTS], float noise_estimate, - uint32_t nsubframe, uint32_t *cfi, float *corr_result) +int srslte_pcfich_decode_multi(srslte_pcfich_t *q, cf_t *sf_symbols[SRSLTE_MAX_PORTS], cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], float noise_estimate, + uint32_t nsubframe, uint32_t *cfi, float *corr_result) { /* Set pointers for layermapping & precoding */ int i; cf_t *x[SRSLTE_MAX_LAYERS]; - cf_t *ce_precoding[SRSLTE_MAX_PORTS]; - + if (q != NULL && - slot_symbols != NULL && + sf_symbols != NULL && nsubframe < SRSLTE_NSUBFRAMES_X_FRAME) { @@ -167,34 +184,37 @@ int srslte_pcfich_decode(srslte_pcfich_t *q, cf_t *slot_symbols, cf_t *ce[SRSLTE for (i = 0; i < SRSLTE_MAX_PORTS; i++) { x[i] = q->x[i]; } - for (i = 0; i < SRSLTE_MAX_PORTS; i++) { - ce_precoding[i] = q->ce[i]; - } - + + cf_t *q_symbols[SRSLTE_MAX_PORTS]; + cf_t *q_ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; + /* extract symbols */ - if (q->nof_symbols - != srslte_regs_pcfich_get(q->regs, slot_symbols, q->symbols[0])) { - fprintf(stderr, "There was an error getting the PCFICH symbols\n"); - return SRSLTE_ERROR; - } - - /* extract channel estimates */ - for (i = 0; i < q->cell.nof_ports; i++) { - if (q->nof_symbols != srslte_regs_pcfich_get(q->regs, ce[i], q->ce[i])) { + for (int j=0;jnof_rx_antennas;j++) { + if (q->nof_symbols + != srslte_regs_pcfich_get(q->regs, sf_symbols[j], q->symbols[j])) { fprintf(stderr, "There was an error getting the PCFICH symbols\n"); return SRSLTE_ERROR; } - } + q_symbols[j] = q->symbols[j]; + + /* extract channel estimates */ + for (i = 0; i < q->cell.nof_ports; i++) { + if (q->nof_symbols != srslte_regs_pcfich_get(q->regs, ce[i][j], q->ce[i][j])) { + fprintf(stderr, "There was an error getting the PCFICH symbols\n"); + return SRSLTE_ERROR; + } + q_ce[i][j] = q->ce[i][j]; + } + } + /* in control channels, only diversity is supported */ if (q->cell.nof_ports == 1) { /* no need for layer demapping */ - srslte_predecoding_single(q->symbols[0], q->ce[0], q->d, q->nof_symbols, noise_estimate); + srslte_predecoding_single_multi(q_symbols, q_ce[0], q->d, q->nof_rx_antennas, q->nof_symbols, noise_estimate); } else { - srslte_predecoding_diversity(q->symbols[0], ce_precoding, x, - q->cell.nof_ports, q->nof_symbols); - srslte_layerdemap_diversity(x, q->d, q->cell.nof_ports, - q->nof_symbols / q->cell.nof_ports); + srslte_predecoding_diversity_multi(q_symbols, q_ce, x, q->nof_rx_antennas, q->cell.nof_ports, q->nof_symbols); + srslte_layerdemap_diversity(x, q->d, q->cell.nof_ports, q->nof_symbols / q->cell.nof_ports); } /* demodulate symbols */ @@ -229,14 +249,14 @@ int srslte_pcfich_encode(srslte_pcfich_t *q, uint32_t cfi, cf_t *slot_symbols[SR /* Set pointers for layermapping & precoding */ cf_t *x[SRSLTE_MAX_LAYERS]; - cf_t *symbols_precoding[SRSLTE_MAX_PORTS]; + cf_t *q_symbols[SRSLTE_MAX_PORTS]; /* number of layers equals number of ports */ for (i = 0; i < q->cell.nof_ports; i++) { x[i] = q->x[i]; } for (i = 0; i < SRSLTE_MAX_PORTS; i++) { - symbols_precoding[i] = q->symbols[i]; + q_symbols[i] = q->symbols[i]; } /* pack CFI */ @@ -250,8 +270,7 @@ int srslte_pcfich_encode(srslte_pcfich_t *q, uint32_t cfi, cf_t *slot_symbols[SR /* layer mapping & precoding */ if (q->cell.nof_ports > 1) { srslte_layermap_diversity(q->d, x, q->cell.nof_ports, q->nof_symbols); - srslte_precoding_diversity(x, symbols_precoding, q->cell.nof_ports, - q->nof_symbols / q->cell.nof_ports); + srslte_precoding_diversity(x, q_symbols, q->cell.nof_ports, q->nof_symbols / q->cell.nof_ports); } else { memcpy(q->symbols[0], q->d, q->nof_symbols * sizeof(cf_t)); } diff --git a/srslte/lib/phch/pdcch.c b/lib/src/phy/phch/pdcch.c similarity index 78% rename from srslte/lib/phch/pdcch.c rename to lib/src/phy/phch/pdcch.c index 99f56aec3..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<cell = cell; q->regs = regs; + q->nof_rx_antennas = nof_rx_antennas; /* Allocate memory for the maximum number of PDCCH bits (CFI=3) */ q->max_bits = (srslte_regs_pdcch_nregs(q->regs, 3) / 9) * 72; @@ -89,7 +92,7 @@ int srslte_pdcch_init(srslte_pdcch_t *q, srslte_regs_t *regs, srslte_cell_t cell goto clean; } - for (i = 0; i < SRSLTE_NSUBFRAMES_X_FRAME; i++) { + for (int i = 0; i < SRSLTE_NSUBFRAMES_X_FRAME; i++) { // we need to pregenerate the sequence for the maximum number of bits, which is 8 times // the maximum number of REGs (for CFI=3) if (srslte_sequence_pdcch(&q->seq[i], 2 * i, q->cell.id, 8*srslte_regs_pdcch_nregs(q->regs, 3))) { @@ -119,17 +122,21 @@ int srslte_pdcch_init(srslte_pdcch_t *q, srslte_regs_t *regs, srslte_cell_t cell goto clean; } - for (i = 0; i < SRSLTE_MAX_PORTS; i++) { - q->ce[i] = srslte_vec_malloc(sizeof(cf_t) * q->max_bits / 2); - if (!q->ce[i]) { - goto clean; + for (int i = 0; i < SRSLTE_MAX_PORTS; i++) { + for (int j=0;jnof_rx_antennas;j++) { + q->ce[i][j] = srslte_vec_malloc(sizeof(cf_t) * q->max_bits / 2); + if (!q->ce[i][j]) { + goto clean; + } } q->x[i] = srslte_vec_malloc(sizeof(cf_t) * q->max_bits / 2); if (!q->x[i]) { goto clean; } - q->symbols[i] = srslte_vec_malloc(sizeof(cf_t) * q->max_bits / 2); - if (!q->symbols[i]) { + } + for (int j=0;jnof_rx_antennas;j++) { + q->symbols[j] = srslte_vec_malloc(sizeof(cf_t) * q->max_bits / 2); + if (!q->symbols[j]) { goto clean; } } @@ -144,7 +151,6 @@ int srslte_pdcch_init(srslte_pdcch_t *q, srslte_regs_t *regs, srslte_cell_t cell } void srslte_pdcch_free(srslte_pdcch_t *q) { - int i; if (q->e) { free(q->e); @@ -155,19 +161,22 @@ void srslte_pdcch_free(srslte_pdcch_t *q) { if (q->d) { free(q->d); } - for (i = 0; i < SRSLTE_MAX_PORTS; i++) { - if (q->ce[i]) { - free(q->ce[i]); + for (int i = 0; i < SRSLTE_MAX_PORTS; i++) { + for (int j=0;jnof_rx_antennas;j++) { + if (q->ce[i][j]) { + free(q->ce[i][j]); + } } if (q->x[i]) { free(q->x[i]); } - if (q->symbols[i]) { - free(q->symbols[i]); + } + for (int j=0;jnof_rx_antennas;j++) { + if (q->symbols[j]) { + free(q->symbols[j]); } } - - for (i = 0; i < SRSLTE_NSUBFRAMES_X_FRAME; i++) { + for (int i = 0; i < SRSLTE_NSUBFRAMES_X_FRAME; i++) { srslte_sequence_free(&q->seq[i]); } @@ -178,16 +187,6 @@ void srslte_pdcch_free(srslte_pdcch_t *q) { } -/** - * Calculate DCI locations in UE-specific space and set CFI - * - * @param[out] c Buffer of length max_candidates for storing calculated DCI locations - * @param[in] max_candidates Size of buffer c - * @param[in] cfi Control Format Indicator. Affects length of PDCCH, thus there's more locations - * @param[in] nsubframe Subframe to calculate DCI locations for - * @param[in] rnti Destination RNTI - * @return Number of DCI locations stored in c - */ uint32_t srslte_pdcch_ue_locations(srslte_pdcch_t *q, srslte_dci_location_t *c, uint32_t max_candidates, uint32_t nsubframe, uint32_t cfi, uint16_t rnti) { @@ -206,7 +205,7 @@ uint32_t srslte_pdcch_ue_locations_ncce(uint32_t nof_cce, srslte_dci_location_t int l; // this must be int because of the for(;;--) loop uint32_t i, k, L, m; uint32_t Yk, ncce; - const int S[4] = { 6, 12, 8, 16 }; + const int nof_candidates[4] = { 6, 6, 2, 2}; // Compute Yk for this subframe Yk = rnti; @@ -218,10 +217,11 @@ uint32_t srslte_pdcch_ue_locations_ncce(uint32_t nof_cce, srslte_dci_location_t // All aggregation levels from 8 to 1 for (l = 3; l >= 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++) { - if (nof_cce > L) { - ncce = L * ((Yk + i) % (nof_cce / L)); + // 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)); + // Check if candidate fits in c vector and in CCE region if (k < max_candidates && ncce + L <= nof_cce) { c[k].L = l; @@ -245,19 +245,10 @@ uint32_t srslte_pdcch_ue_locations_ncce(uint32_t nof_cce, srslte_dci_location_t /** - * Calculate DCI locations for common search space and set PDCCH CFI - * * 36.213 9.1.1 - * First sets Control Format Indicator. - * Then computes up to max_candidates candidates in the common search space + * Computes up to max_candidates candidates in the common search space * for DCI messages and saves them in the structure pointed by c. * Returns the number of candidates saved in the array c. - * - * @param[inout] q PDCCH information. q->cfi is set to cfi. - * @param[out] c Buffer of length max_candidates for storing calculated DCI locations - * @param[in] max_candidates Size of buffer c - * @param[in] cfi Control Format Indicator. Affects length of PDCCH, thus there's more locations. Also it is copied to q->cfi - * @return Number of DCI locations stored in c */ uint32_t srslte_pdcch_common_locations(srslte_pdcch_t *q, srslte_dci_location_t *c, uint32_t max_candidates, uint32_t cfi) @@ -266,14 +257,6 @@ uint32_t srslte_pdcch_common_locations(srslte_pdcch_t *q, srslte_dci_location_t return srslte_pdcch_common_locations_ncce(q->nof_cce, c, max_candidates); } -/** - * Calculate DCI locations for common search space - * - * @param[out] c Buffer of length max_candidates for storing calculated DCI locations - * @param[in] max_candidates Size of buffer c - * @param[in] cfi Control Format Indicator. Affects length of PDCCH, thus there's more locations - * @return Number of DCI locations stored in c - */ uint32_t srslte_pdcch_common_locations_ncce(uint32_t nof_cce, srslte_dci_location_t *c, uint32_t max_candidates) { uint32_t i, l, L, k; @@ -369,7 +352,7 @@ int srslte_pdcch_decode_msg(srslte_pdcch_t *q, } else { ret = SRSLTE_SUCCESS; - uint32_t nof_bits = srslte_dci_format_sizeof_lut(format, q->cell.nof_prb); + uint32_t nof_bits = srslte_dci_format_sizeof(format, q->cell.nof_prb, q->cell.nof_ports); uint32_t e_bits = PDCCH_FORMAT_NOF_BITS(location->L); double mean = 0; @@ -408,13 +391,27 @@ int srslte_pdcch_decode_msg(srslte_pdcch_t *q, int cnt=0; +int srslte_pdcch_extract_llr(srslte_pdcch_t *q, cf_t *sf_symbols, cf_t *ce[SRSLTE_MAX_PORTS], float noise_estimate, + uint32_t nsubframe, uint32_t cfi) +{ + cf_t *_sf_symbols[SRSLTE_MAX_PORTS]; + cf_t *_ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; + + _sf_symbols[0] = sf_symbols; + for (int i=0;icell.nof_ports;i++) { + _ce[i][0] = ce[i]; + } + return srslte_pdcch_extract_llr_multi(q, _sf_symbols, _ce, noise_estimate, nsubframe, cfi); +} + /** Extracts the LLRs from srslte_dci_location_t location of the subframe and stores them in the srslte_pdcch_t structure. * DCI messages can be extracted from this location calling the function srslte_pdcch_decode_msg(). * Every time this function is called (with a different location), the last demodulated symbols are overwritten and * new messages from other locations can be decoded */ -int srslte_pdcch_extract_llr(srslte_pdcch_t *q, cf_t *sf_symbols, cf_t *ce[SRSLTE_MAX_PORTS], float noise_estimate, - uint32_t nsubframe, uint32_t cfi) { +int srslte_pdcch_extract_llr_multi(srslte_pdcch_t *q, cf_t *sf_symbols[SRSLTE_MAX_PORTS], cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], float noise_estimate, + uint32_t nsubframe, uint32_t cfi) +{ int ret = SRSLTE_ERROR_INVALID_INPUTS; @@ -444,27 +441,29 @@ int srslte_pdcch_extract_llr(srslte_pdcch_t *q, cf_t *sf_symbols, cf_t *ce[SRSLT memset(&x[q->cell.nof_ports], 0, sizeof(cf_t*) * (SRSLTE_MAX_LAYERS - q->cell.nof_ports)); /* extract symbols */ - int n = srslte_regs_pdcch_get(q->regs, sf_symbols, q->symbols[0]); - if (nof_symbols != n) { - fprintf(stderr, "Expected %d PDCCH symbols but got %d symbols\n", nof_symbols, n); - return ret; - } - - /* extract channel estimates */ - for (i = 0; i < q->cell.nof_ports; i++) { - n = srslte_regs_pdcch_get(q->regs, ce[i], q->ce[i]); + for (int j=0;jnof_rx_antennas;j++) { + int n = srslte_regs_pdcch_get(q->regs, sf_symbols[j], q->symbols[j]); if (nof_symbols != n) { fprintf(stderr, "Expected %d PDCCH symbols but got %d symbols\n", nof_symbols, n); return ret; } - } + /* extract channel estimates */ + for (i = 0; i < q->cell.nof_ports; i++) { + n = srslte_regs_pdcch_get(q->regs, ce[i][j], q->ce[i][j]); + if (nof_symbols != n) { + fprintf(stderr, "Expected %d PDCCH symbols but got %d symbols\n", nof_symbols, n); + return ret; + } + } + } + /* in control channels, only diversity is supported */ if (q->cell.nof_ports == 1) { /* no need for layer demapping */ - srslte_predecoding_single(q->symbols[0], q->ce[0], q->d, nof_symbols, noise_estimate/2); + srslte_predecoding_single_multi(q->symbols, q->ce[0], q->d, q->nof_rx_antennas, nof_symbols, noise_estimate/2); } else { - srslte_predecoding_diversity(q->symbols[0], q->ce, x, q->cell.nof_ports, nof_symbols); + srslte_predecoding_diversity_multi(q->symbols, q->ce, x, q->nof_rx_antennas, q->cell.nof_ports, nof_symbols); srslte_layerdemap_diversity(x, q->d, q->cell.nof_ports, nof_symbols / q->cell.nof_ports); } @@ -480,12 +479,7 @@ int srslte_pdcch_extract_llr(srslte_pdcch_t *q, cf_t *sf_symbols, cf_t *ce[SRSLT } -/** - * Unpacks RNTI into a bit array and XORs with bit array in crc - * - * @param[in] crc Location to XOR unpacked RNTI to - * @param[in] rnti RNTI to unpack and XOR - */ + static void crc_set_mask_rnti(uint8_t *crc, uint16_t rnti) { uint32_t i; uint8_t mask[16]; @@ -499,14 +493,6 @@ static void crc_set_mask_rnti(uint8_t *crc, uint16_t rnti) { } } -/** - * Appends CRC to a packed DCI message. Applies convolution encoding. Does not do rate matching. - * - * @param[in] data Unpacked bit array. MSB first. - * @param[in] nof_bits Length of data array - * @param[out] coded_data Output unpacked bit array. Size (nof_bits+16)*3 - * @param[in] rnti Destination RNTI - */ void srslte_pdcch_dci_encode_conv(srslte_pdcch_t *q, uint8_t *data, uint32_t nof_bits, uint8_t *coded_data, uint16_t rnti) { srslte_convcoder_t encoder; int poly[3] = { 0x6D, 0x4F, 0x57 }; @@ -521,21 +507,8 @@ void srslte_pdcch_dci_encode_conv(srslte_pdcch_t *q, uint8_t *data, uint32_t nof srslte_convcoder_encode(&encoder, data, coded_data, nof_bits + 16); } -/** - * Appends CRC to a packed DCI message. Applies convolution encoding. Does rate matching. - * - * 36.212 5.3.3.2 to 5.3.3.4 - * @TODO: UE transmit antenna selection CRC mask - * - * @param[in] data Unpacked bit array. MSB first. - * @param[in] nof_bits Length of data array - * @param[in] E Rate match to this size buffer - * @param[out] e Output unpacked bit array. Size E - * @param[in] rnti Destination RNTI - * @return Error code - */ -/** - * +/** 36.212 5.3.3.2 to 5.3.3.4 + * TODO: UE transmit antenna selection CRC mask */ int srslte_pdcch_dci_encode(srslte_pdcch_t *q, uint8_t *data, uint8_t *e, uint32_t nof_bits, uint32_t E, uint16_t rnti) @@ -571,14 +544,6 @@ int srslte_pdcch_dci_encode(srslte_pdcch_t *q, uint8_t *data, uint8_t *e, uint32 * If the same location is provided in multiple messages, the encoded bits will be overwritten. * * @TODO: Use a bitmask and CFI to ensure message locations are valid and old messages are not overwritten. - * - * @param[in] q PDCCH parameters - * @param[in] msg Input DCI message buffer - * @param[in] location - * @param[in] rnti Destination RNTI - * @param[out] sf_symbols Pointers to all symbols in a subframe for all antenna ports - * @param[in] nsubframe Current subframe index. Affects scrambling and UE-specific DCI message locations - * @param[in] cfi Control Format Indicator */ int srslte_pdcch_encode(srslte_pdcch_t *q, srslte_dci_msg_t *msg, srslte_dci_location_t location, uint16_t rnti, cf_t *sf_symbols[SRSLTE_MAX_PORTS], uint32_t nsubframe, uint32_t cfi) @@ -643,7 +608,7 @@ int srslte_pdcch_encode(srslte_pdcch_t *q, srslte_dci_msg_t *msg, srslte_dci_loc ret = SRSLTE_SUCCESS; } else { - fprintf(stderr, "Illegal DCI message nCCE: %d, L: %d, nof_cce: %d\n", location.ncce, location.L, q->nof_cce); + fprintf(stderr, "Illegal DCI message nCCE: %d, L: %d, nof_cce: %d, nof_bits=%d\n", location.ncce, location.L, q->nof_cce, msg->nof_bits); } } else { fprintf(stderr, "Invalid parameters: cfi=%d, L=%d, nCCE=%d\n", cfi, location.L, location.ncce); diff --git a/srslte/lib/phch/pdsch.c b/lib/src/phy/phch/pdsch.c similarity index 67% rename from srslte/lib/phch/pdsch.c rename to lib/src/phy/phch/pdsch.c index 56089cefb..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) @@ -57,6 +57,10 @@ extern int indices[100000]; extern int indices_ptr; #endif +float srslte_pdsch_coderate(uint32_t tbs, uint32_t nof_re) +{ + return (float) (tbs + 24)/(nof_re); +} int srslte_pdsch_cp(srslte_pdsch_t *q, cf_t *input, cf_t *output, srslte_ra_dl_grant_t *grant, uint32_t lstart_grant, uint32_t nsubframe, bool put) { @@ -198,13 +202,20 @@ int srslte_pdsch_get(srslte_pdsch_t *q, cf_t *sf_symbols, cf_t *symbols, return srslte_pdsch_cp(q, sf_symbols, symbols, grant, lstart, subframe, false); } +int srslte_pdsch_init(srslte_pdsch_t *q, srslte_cell_t cell) +{ + return srslte_pdsch_init_multi(q, cell, 1); +} + /** Initializes the PDCCH transmitter and receiver */ -int srslte_pdsch_init(srslte_pdsch_t *q, srslte_cell_t cell) { +int srslte_pdsch_init_multi(srslte_pdsch_t *q, srslte_cell_t cell, uint32_t nof_rx_antennas) +{ int ret = SRSLTE_ERROR_INVALID_INPUTS; int i; - if (q != NULL && - srslte_cell_isvalid(&cell)) + if (q != NULL && + srslte_cell_isvalid(&cell) && + nof_rx_antennas <= SRSLTE_MAX_PORTS) { bzero(q, sizeof(srslte_pdsch_t)); @@ -212,8 +223,8 @@ int srslte_pdsch_init(srslte_pdsch_t *q, srslte_cell_t cell) { q->cell = cell; q->max_re = q->cell.nof_prb * MAX_PDSCH_RE(q->cell.cp); - q->nof_crnti = 0; - + q->nof_rx_antennas = nof_rx_antennas; + INFO("Init PDSCH: %d ports %d PRBs, max_symbols: %d\n", q->cell.nof_ports, q->cell.nof_prb, q->max_re); @@ -226,8 +237,6 @@ int srslte_pdsch_init(srslte_pdsch_t *q, srslte_cell_t cell) { srslte_sch_init(&q->dl_sch); - q->rnti_is_set = false; - // Allocate int16_t for reception (LLRs) q->e = srslte_vec_malloc(sizeof(int16_t) * q->max_re * srslte_mod_bits_x_symbol(SRSLTE_MOD_64QAM)); if (!q->e) { @@ -240,20 +249,30 @@ int srslte_pdsch_init(srslte_pdsch_t *q, srslte_cell_t cell) { } for (i = 0; i < q->cell.nof_ports; i++) { - q->ce[i] = srslte_vec_malloc(sizeof(cf_t) * q->max_re); - if (!q->ce[i]) { - goto clean; - } q->x[i] = srslte_vec_malloc(sizeof(cf_t) * q->max_re); if (!q->x[i]) { goto clean; } - q->symbols[i] = srslte_vec_malloc(sizeof(cf_t) * q->max_re); - if (!q->symbols[i]) { - goto clean; + for (int j=0;jnof_rx_antennas;j++) { + q->ce[i][j] = srslte_vec_malloc(sizeof(cf_t) * q->max_re); + if (!q->ce[i][j]) { + goto clean; + } } } - + for (int j=0;jnof_rx_antennas;j++) { + q->symbols[j] = srslte_vec_malloc(sizeof(cf_t) * q->max_re); + if (!q->symbols[j]) { + goto clean; + } + } + + q->users = calloc(sizeof(srslte_pdsch_user_t*), 1+SRSLTE_SIRNTI); + if (!q->users) { + perror("malloc"); + goto clean; + } + ret = SRSLTE_SUCCESS; } clean: @@ -273,34 +292,28 @@ void srslte_pdsch_free(srslte_pdsch_t *q) { free(q->d); } for (i = 0; i < q->cell.nof_ports; i++) { - if (q->ce[i]) { - free(q->ce[i]); - } if (q->x[i]) { free(q->x[i]); } - if (q->symbols[i]) { - free(q->symbols[i]); + for (int j=0;jnof_rx_antennas;j++) { + if (q->ce[i][j]) { + free(q->ce[i][j]); + } } } - - for (i = 0; i < SRSLTE_NSUBFRAMES_X_FRAME; i++) { - srslte_sequence_free(&q->seq[i]); - } - - for (i = 0; i < SRSLTE_NSUBFRAMES_X_FRAME; i++) { - for (int n=0;nnof_crnti;n++) { - srslte_sequence_free(&q->seq_multi[i][n]); - } - if (q->seq_multi[i]) { - free(q->seq_multi[i]); - } + for (int j=0;jnof_rx_antennas;j++) { + if (q->symbols[j]) { + free(q->symbols[j]); + } } - - if (q->rnti_multi) { - free(q->rnti_multi); + if (q->users) { + for (uint16_t u=0;uusers[u]) { + srslte_pdsch_free_rnti(q, u); + } + } + free(q->users); } - for (i = 0; i < 4; i++) { srslte_modem_table_free(&q->mod[i]); } @@ -339,100 +352,53 @@ int srslte_pdsch_cfg(srslte_pdsch_cfg_t *cfg, srslte_cell_t cell, srslte_ra_dl_g * to execute, so shall be called once the final C-RNTI has been allocated for the session. */ int srslte_pdsch_set_rnti(srslte_pdsch_t *q, uint16_t rnti) { - uint32_t i; - for (i = 0; i < SRSLTE_NSUBFRAMES_X_FRAME; i++) { - if (srslte_sequence_pdsch(&q->seq[i], rnti, 0, 2 * i, q->cell.id, - q->max_re * srslte_mod_bits_x_symbol(SRSLTE_MOD_64QAM))) { - return SRSLTE_ERROR; - } - } - q->rnti_is_set = true; - q->rnti = rnti; - return SRSLTE_SUCCESS; -} - -/* Initializes the memory to support pre-calculation of multiple scrambling sequences */ -int srslte_pdsch_init_rnti_multi(srslte_pdsch_t *q, uint32_t nof_rntis) -{ - for (int i = 0; i < SRSLTE_NSUBFRAMES_X_FRAME; i++) { - q->seq_multi[i] = malloc(sizeof(srslte_sequence_t)*nof_rntis); - if (!q->seq_multi[i]) { - perror("malloc"); - return SRSLTE_ERROR; + uint32_t i; + if (!q->users[rnti]) { + q->users[rnti] = calloc(1, sizeof(srslte_pdsch_user_t)); + if (q->users[rnti]) { + for (i = 0; i < SRSLTE_NSUBFRAMES_X_FRAME; i++) { + if (srslte_sequence_pdsch(&q->users[rnti]->seq[i], rnti, 0, 2 * i, q->cell.id, + q->max_re * srslte_mod_bits_x_symbol(SRSLTE_MOD_64QAM))) { + return SRSLTE_ERROR; + } + } } } - - q->rnti_multi = srslte_vec_malloc(sizeof(uint16_t)*nof_rntis); - if (!q->rnti_multi) { - perror("malloc"); - return SRSLTE_ERROR; - } - bzero(q->rnti_multi, sizeof(uint16_t)*nof_rntis); - - q->nof_crnti = nof_rntis; - return SRSLTE_SUCCESS; } -int srslte_pdsch_set_rnti_multi(srslte_pdsch_t *q, uint32_t idx, uint16_t rnti) +void srslte_pdsch_free_rnti(srslte_pdsch_t* q, uint16_t rnti) { - if (idx < q->nof_crnti) { - if (q->rnti_multi[idx]) { - for (uint32_t i = 0; i < SRSLTE_NSUBFRAMES_X_FRAME; i++) { - srslte_sequence_free(&q->seq_multi[i][idx]); - } - q->rnti_multi[idx] = 0; + if (q->users[rnti]) { + for (int i = 0; i < SRSLTE_NSUBFRAMES_X_FRAME; i++) { + srslte_sequence_free(&q->users[rnti]->seq[i]); } - q->rnti_multi[idx] = rnti; - q->rnti_is_set = true; - for (uint32_t i = 0; i < SRSLTE_NSUBFRAMES_X_FRAME; i++) { - if (srslte_sequence_pdsch(&q->seq_multi[i][idx], rnti, 0, 2 * i, q->cell.id, - q->max_re * srslte_mod_bits_x_symbol(SRSLTE_MOD_64QAM))) { - return SRSLTE_ERROR; - } - } - return SRSLTE_SUCCESS; - } else { - return SRSLTE_ERROR_INVALID_INPUTS; - } -} - -uint16_t srslte_pdsch_get_rnti_multi(srslte_pdsch_t *q, uint32_t idx) -{ - if (idx < q->nof_crnti) { - return q->rnti_multi[idx]; - } else { - return SRSLTE_ERROR_INVALID_INPUTS; + free(q->users[rnti]); + q->users[rnti] = NULL; } } int srslte_pdsch_decode(srslte_pdsch_t *q, srslte_pdsch_cfg_t *cfg, srslte_softbuffer_rx_t *softbuffer, cf_t *sf_symbols, cf_t *ce[SRSLTE_MAX_PORTS], float noise_estimate, - uint8_t *data) + uint16_t rnti, uint8_t *data) { - if (q != NULL && - sf_symbols != NULL && - data != NULL && - cfg != NULL) - { - if (q->rnti_is_set) { - return srslte_pdsch_decode_rnti(q, cfg, softbuffer, sf_symbols, ce, noise_estimate, q->rnti, data); - } else { - fprintf(stderr, "Must call srslte_pdsch_set_rnti() before calling srslte_pdsch_decode()\n"); - return SRSLTE_ERROR; - } - } else { - return SRSLTE_ERROR_INVALID_INPUTS; + cf_t *_sf_symbols[SRSLTE_MAX_PORTS]; + cf_t *_ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; + + _sf_symbols[0] = sf_symbols; + for (int i=0;icell.nof_ports;i++) { + _ce[i][0] = ce[i]; } + return srslte_pdsch_decode_multi(q, cfg, softbuffer, _sf_symbols, _ce, noise_estimate, rnti, data); } /** Decodes the PDSCH from the received symbols */ -int srslte_pdsch_decode_rnti(srslte_pdsch_t *q, - srslte_pdsch_cfg_t *cfg, srslte_softbuffer_rx_t *softbuffer, - cf_t *sf_symbols, cf_t *ce[SRSLTE_MAX_PORTS], float noise_estimate, - uint16_t rnti, uint8_t *data) +int srslte_pdsch_decode_multi(srslte_pdsch_t *q, + srslte_pdsch_cfg_t *cfg, srslte_softbuffer_rx_t *softbuffer, + cf_t *sf_symbols[SRSLTE_MAX_PORTS], cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], float noise_estimate, + uint16_t rnti, uint8_t *data) { /* Set pointers for layermapping & precoding */ @@ -455,31 +421,31 @@ int srslte_pdsch_decode_rnti(srslte_pdsch_t *q, } memset(&x[q->cell.nof_ports], 0, sizeof(cf_t*) * (SRSLTE_MAX_LAYERS - q->cell.nof_ports)); - /* extract symbols */ - n = srslte_pdsch_get(q, sf_symbols, q->symbols[0], &cfg->grant, cfg->nbits.lstart, cfg->sf_idx); - if (n != cfg->nbits.nof_re) { - fprintf(stderr, "Error expecting %d symbols but got %d\n", cfg->nbits.nof_re, n); - return SRSLTE_ERROR; - } - - /* extract channel estimates */ - for (i = 0; i < q->cell.nof_ports; i++) { - n = srslte_pdsch_get(q, ce[i], q->ce[i], &cfg->grant, cfg->nbits.lstart, cfg->sf_idx); + for (int j=0;jnof_rx_antennas;j++) { + /* extract symbols */ + n = srslte_pdsch_get(q, sf_symbols[j], q->symbols[j], &cfg->grant, cfg->nbits.lstart, cfg->sf_idx); if (n != cfg->nbits.nof_re) { fprintf(stderr, "Error expecting %d symbols but got %d\n", cfg->nbits.nof_re, n); return SRSLTE_ERROR; } + + /* extract channel estimates */ + for (i = 0; i < q->cell.nof_ports; i++) { + n = srslte_pdsch_get(q, ce[i][j], q->ce[i][j], &cfg->grant, cfg->nbits.lstart, cfg->sf_idx); + if (n != cfg->nbits.nof_re) { + fprintf(stderr, "Error expecting %d symbols but got %d\n", cfg->nbits.nof_re, n); + return SRSLTE_ERROR; + } + } } /* TODO: only diversity is supported */ if (q->cell.nof_ports == 1) { /* no need for layer demapping */ - srslte_predecoding_single(q->symbols[0], q->ce[0], q->d, cfg->nbits.nof_re, noise_estimate); + srslte_predecoding_single_multi(q->symbols, q->ce[0], q->d, q->nof_rx_antennas, cfg->nbits.nof_re, noise_estimate); } else { - srslte_predecoding_diversity(q->symbols[0], q->ce, x, q->cell.nof_ports, - cfg->nbits.nof_re); - srslte_layerdemap_diversity(x, q->d, q->cell.nof_ports, - cfg->nbits.nof_re / q->cell.nof_ports); + srslte_predecoding_diversity_multi(q->symbols, q->ce, x, q->nof_rx_antennas, q->cell.nof_ports, cfg->nbits.nof_re); + srslte_layerdemap_diversity(x, q->d, q->cell.nof_ports, cfg->nbits.nof_re / q->cell.nof_ports); } if (SRSLTE_VERBOSE_ISDEBUG()) { @@ -500,16 +466,8 @@ int srslte_pdsch_decode_rnti(srslte_pdsch_t *q, */ srslte_demod_soft_demodulate_s(cfg->grant.mcs.mod, q->d, q->e, cfg->nbits.nof_re); - /* - printf("WARNING REMOVE ME!\n"); - int16_t *e=q->e; - for (int i=0;inbits.nof_bits;i++) { - e[i] = e[i]>0?10:-10; - } - */ - /* descramble */ - if (rnti != q->rnti) { + if (!q->users[rnti]) { srslte_sequence_t seq; if (srslte_sequence_pdsch(&seq, rnti, 0, 2 * cfg->sf_idx, q->cell.id, cfg->nbits.nof_bits)) { return SRSLTE_ERROR; @@ -517,7 +475,7 @@ int srslte_pdsch_decode_rnti(srslte_pdsch_t *q, srslte_scrambling_s_offset(&seq, q->e, 0, cfg->nbits.nof_bits); srslte_sequence_free(&seq); } else { - srslte_scrambling_s_offset(&q->seq[cfg->sf_idx], q->e, 0, cfg->nbits.nof_bits); + srslte_scrambling_s_offset(&q->users[rnti]->seq[cfg->sf_idx], q->e, 0, cfg->nbits.nof_bits); } if (SRSLTE_VERBOSE_ISDEBUG()) { @@ -533,27 +491,8 @@ int srslte_pdsch_decode_rnti(srslte_pdsch_t *q, } int srslte_pdsch_encode(srslte_pdsch_t *q, - srslte_pdsch_cfg_t *cfg, srslte_softbuffer_tx_t *softbuffer, - uint8_t *data, cf_t *sf_symbols[SRSLTE_MAX_PORTS]) -{ - if (q != NULL && - data != NULL && - cfg != NULL) - { - if (q->rnti_is_set) { - return srslte_pdsch_encode_rnti(q, cfg, softbuffer, data, q->rnti, sf_symbols); - } else { - fprintf(stderr, "Must call srslte_pdsch_set_rnti() to set the encoder/decoder RNTI\n"); - return SRSLTE_ERROR; - } - } else { - return SRSLTE_ERROR_INVALID_INPUTS; - } -} - -int srslte_pdsch_encode_seq(srslte_pdsch_t *q, - srslte_pdsch_cfg_t *cfg, srslte_softbuffer_tx_t *softbuffer, - uint8_t *data, srslte_sequence_t *seq, cf_t *sf_symbols[SRSLTE_MAX_PORTS]) + srslte_pdsch_cfg_t *cfg, srslte_softbuffer_tx_t *softbuffer, + uint8_t *data, uint16_t rnti, cf_t *sf_symbols[SRSLTE_MAX_PORTS]) { int i; @@ -597,8 +536,18 @@ int srslte_pdsch_encode_seq(srslte_pdsch_t *q, return SRSLTE_ERROR; } - srslte_scrambling_bytes(seq, (uint8_t*) q->e, cfg->nbits.nof_bits); - + /* scramble */ + if (!q->users[rnti]) { + srslte_sequence_t seq; + if (srslte_sequence_pdsch(&seq, rnti, 0, 2 * cfg->sf_idx, q->cell.id, cfg->nbits.nof_bits)) { + return SRSLTE_ERROR; + } + 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); + } + srslte_mod_modulate_bytes(&q->mod[cfg->grant.mcs.mod], (uint8_t*) q->e, q->d, cfg->nbits.nof_bits); /* TODO: only diversity supported */ @@ -620,42 +569,6 @@ int srslte_pdsch_encode_seq(srslte_pdsch_t *q, return ret; } -int srslte_pdsch_encode_rnti_idx(srslte_pdsch_t *q, - srslte_pdsch_cfg_t *cfg, srslte_softbuffer_tx_t *softbuffer, - uint8_t *data, uint32_t rnti_idx, cf_t *sf_symbols[SRSLTE_MAX_PORTS]) -{ - if (rnti_idx < q->nof_crnti) { - if (q->rnti_multi[rnti_idx]) { - return srslte_pdsch_encode_seq(q, cfg, softbuffer, data, &q->seq_multi[cfg->sf_idx][rnti_idx], sf_symbols); - } else { - fprintf(stderr, "Error RNTI idx %d not set\n", rnti_idx); - return SRSLTE_ERROR; - } - } else { - return SRSLTE_ERROR_INVALID_INPUTS; - } -} - -/** Converts the PDSCH data bits to symbols mapped to the slot ready for transmission - */ -int srslte_pdsch_encode_rnti(srslte_pdsch_t *q, - srslte_pdsch_cfg_t *cfg, srslte_softbuffer_tx_t *softbuffer, - uint8_t *data, uint16_t rnti, cf_t *sf_symbols[SRSLTE_MAX_PORTS]) -{ - if (rnti != q->rnti) { - srslte_sequence_t seq; - if (srslte_sequence_pdsch(&seq, rnti, 0, 2 * cfg->sf_idx, q->cell.id, cfg->nbits.nof_bits)) { - return SRSLTE_ERROR; - } - int r = srslte_pdsch_encode_seq(q, cfg, softbuffer, data, &seq, sf_symbols); - srslte_sequence_free(&seq); - return r; - } else { - return srslte_pdsch_encode_seq(q, cfg, softbuffer, data, &q->seq[cfg->sf_idx], sf_symbols); - } -} - - float srslte_pdsch_average_noi(srslte_pdsch_t *q) { return q->dl_sch.average_nof_iterations; diff --git a/srslte/lib/phch/phich.c b/lib/src/phy/phch/phich.c similarity index 81% rename from srslte/lib/phch/phich.c rename to lib/src/phy/phch/phich.c index ae5b6aa67..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 }, @@ -67,8 +67,14 @@ void srslte_phich_reset(srslte_phich_t *q, cf_t *slot_symbols[SRSLTE_MAX_PORTS]) } } +int srslte_phich_init(srslte_phich_t *q, srslte_regs_t *regs, srslte_cell_t cell) +{ + return srslte_phich_init_multi(q, regs, cell, 1); +} + /** Initializes the phich channel receiver */ -int srslte_phich_init(srslte_phich_t *q, srslte_regs_t *regs, srslte_cell_t cell) { +int srslte_phich_init_multi(srslte_phich_t *q, srslte_regs_t *regs, srslte_cell_t cell, uint32_t nof_rx_antennas) +{ int ret = SRSLTE_ERROR_INVALID_INPUTS; if (q != NULL && @@ -81,6 +87,7 @@ int srslte_phich_init(srslte_phich_t *q, srslte_regs_t *regs, srslte_cell_t cell q->cell = cell; q->regs = regs; + q->nof_rx_antennas = nof_rx_antennas; if (srslte_modem_table_lte(&q->mod, SRSLTE_MOD_BPSK)) { goto clean; @@ -155,19 +162,32 @@ void srslte_phich_ack_encode(uint8_t ack, uint8_t bits[SRSLTE_PHICH_NBITS]) { memset(bits, ack, 3 * sizeof(uint8_t)); } +int srslte_phich_decode(srslte_phich_t *q, cf_t *sf_symbols, cf_t *ce[SRSLTE_MAX_PORTS], float noise_estimate, + uint32_t ngroup, uint32_t nseq, uint32_t subframe, uint8_t *ack, float *distance) +{ + cf_t *_sf_symbols[SRSLTE_MAX_PORTS]; + cf_t *_ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; + + _sf_symbols[0] = sf_symbols; + for (int i=0;icell.nof_ports;i++) { + _ce[i][0] = ce[i]; + } + + return srslte_phich_decode_multi(q, _sf_symbols, _ce, noise_estimate, ngroup, nseq, subframe, ack, distance); +} /* Decodes the phich channel and saves the CFI in the cfi pointer. * * Returns 1 if successfully decoded the CFI, 0 if not and -1 on error */ -int srslte_phich_decode(srslte_phich_t *q, cf_t *slot_symbols, cf_t *ce[SRSLTE_MAX_PORTS], float noise_estimate, - uint32_t ngroup, uint32_t nseq, uint32_t subframe, uint8_t *ack, float *distance) { +int srslte_phich_decode_multi(srslte_phich_t *q, cf_t *sf_symbols[SRSLTE_MAX_PORTS], cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], float noise_estimate, + uint32_t ngroup, uint32_t nseq, uint32_t subframe, uint8_t *ack, float *distance) +{ /* Set pointers for layermapping & precoding */ int i, j; cf_t *x[SRSLTE_MAX_LAYERS]; - cf_t *ce_precoding[SRSLTE_MAX_PORTS]; - if (q == NULL || slot_symbols == NULL) { + if (q == NULL || sf_symbols == NULL) { return SRSLTE_ERROR_INVALID_INPUTS; } @@ -198,34 +218,37 @@ int srslte_phich_decode(srslte_phich_t *q, cf_t *slot_symbols, cf_t *ce[SRSLTE_M for (i = 0; i < SRSLTE_MAX_PORTS; i++) { x[i] = q->x[i]; } - for (i = 0; i < SRSLTE_MAX_PORTS; i++) { - ce_precoding[i] = q->ce[i]; - } + cf_t *q_ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; + cf_t *q_sf_symbols[SRSLTE_MAX_PORTS]; + /* extract symbols */ - if (SRSLTE_PHICH_MAX_NSYMB - != srslte_regs_phich_get(q->regs, slot_symbols, q->symbols[0], ngroup)) { - fprintf(stderr, "There was an error getting the phich symbols\n"); - return SRSLTE_ERROR; - } - - /* extract channel estimates */ - for (i = 0; i < q->cell.nof_ports; i++) { - if (SRSLTE_PHICH_MAX_NSYMB != srslte_regs_phich_get(q->regs, ce[i], q->ce[i], ngroup)) { + for (int j=0;jnof_rx_antennas;j++) { + if (SRSLTE_PHICH_MAX_NSYMB + != srslte_regs_phich_get(q->regs, sf_symbols[j], q->sf_symbols[j], ngroup)) { fprintf(stderr, "There was an error getting the phich symbols\n"); return SRSLTE_ERROR; + } + q_sf_symbols[j] = q->sf_symbols[j]; + + /* extract channel estimates */ + for (i = 0; i < q->cell.nof_ports; i++) { + if (SRSLTE_PHICH_MAX_NSYMB != srslte_regs_phich_get(q->regs, ce[i][j], q->ce[i][j], ngroup)) { + fprintf(stderr, "There was an error getting the phich symbols\n"); + return SRSLTE_ERROR; + } + q_ce[i][j] = q->ce[i][j]; } + } /* in control channels, only diversity is supported */ if (q->cell.nof_ports == 1) { /* no need for layer demapping */ - srslte_predecoding_single(q->symbols[0], q->ce[0], q->d0, SRSLTE_PHICH_MAX_NSYMB, noise_estimate); + srslte_predecoding_single_multi(q_sf_symbols, q_ce[0], q->d0, q->nof_rx_antennas, SRSLTE_PHICH_MAX_NSYMB, noise_estimate); } else { - srslte_predecoding_diversity(q->symbols[0], ce_precoding, x, - q->cell.nof_ports, SRSLTE_PHICH_MAX_NSYMB); - srslte_layerdemap_diversity(x, q->d0, q->cell.nof_ports, - SRSLTE_PHICH_MAX_NSYMB / q->cell.nof_ports); + srslte_predecoding_diversity_multi(q_sf_symbols, q_ce, x, q->nof_rx_antennas, q->cell.nof_ports, SRSLTE_PHICH_MAX_NSYMB); + srslte_layerdemap_diversity(x, q->d0, q->cell.nof_ports, SRSLTE_PHICH_MAX_NSYMB / q->cell.nof_ports); } DEBUG("Recv!!: \n", 0); DEBUG("d0: ", 0); @@ -328,7 +351,7 @@ int srslte_phich_encode(srslte_phich_t *q, uint8_t ack, uint32_t ngroup, uint32_ x[i] = q->x[i]; } for (i = 0; i < SRSLTE_MAX_PORTS; i++) { - symbols_precoding[i] = q->symbols[i]; + symbols_precoding[i] = q->sf_symbols[i]; } /* encode ACK/NACK bit */ @@ -391,12 +414,12 @@ int srslte_phich_encode(srslte_phich_t *q, uint8_t ack, uint32_t ngroup, uint32_ SRSLTE_PHICH_MAX_NSYMB / q->cell.nof_ports); /**FIXME: According to 6.9.2, Precoding for 4 tx ports is different! */ } else { - memcpy(q->symbols[0], q->d0, SRSLTE_PHICH_MAX_NSYMB * sizeof(cf_t)); + memcpy(q->sf_symbols[0], q->d0, SRSLTE_PHICH_MAX_NSYMB * sizeof(cf_t)); } /* mapping to resource elements */ for (i = 0; i < q->cell.nof_ports; i++) { - if (srslte_regs_phich_add(q->regs, q->symbols[i], ngroup, slot_symbols[i]) + if (srslte_regs_phich_add(q->regs, q->sf_symbols[i], ngroup, slot_symbols[i]) < 0) { fprintf(stderr, "Error putting PCHICH resource elements\n"); return SRSLTE_ERROR; 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 a29475380..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]; @@ -461,6 +461,7 @@ int srslte_prach_init(srslte_prach_t *p, p->N_seq = prach_Tseq[p->f]*p->N_ifft_ul/2048; p->N_cp = prach_Tcp[p->f]*p->N_ifft_ul/2048; p->T_seq = prach_Tseq[p->f]*SRSLTE_LTE_TS; + p->T_tot = (prach_Tseq[p->f]+prach_Tcp[p->f])*SRSLTE_LTE_TS; ret = SRSLTE_SUCCESS; } else { 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 83% rename from srslte/lib/phch/pucch.c rename to lib/src/phy/phch/pucch.c index 6beb4afc4..c58f69871 100644 --- a/srslte/lib/phch/pucch.c +++ b/lib/src/phy/phch/pucch.c @@ -34,14 +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/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) @@ -67,7 +68,7 @@ float w_n_oc[2][3][4] = { bool srslte_pucch_cfg_isvalid(srslte_pucch_cfg_t *cfg, uint32_t nof_prb) { if (cfg->delta_pucch_shift > 0 && cfg->delta_pucch_shift < 4 && cfg->N_cs < 8 && (cfg->N_cs%cfg->delta_pucch_shift) == 0 && - cfg->n_rb_2 < nof_prb) { + cfg->n_rb_2 <= nof_prb) { return true; } else { return false; @@ -377,7 +378,7 @@ static int pucch_cp(srslte_pucch_t *q, srslte_pucch_format_t format, uint32_t n_ // Determine n_prb uint32_t n_prb = srslte_pucch_n_prb(&q->pucch_cfg, format, n_pucch, q->cell.nof_prb, q->cell.cp, ns); - + q->last_n_prb = n_prb; if (n_prb < q->cell.nof_prb) { for (uint32_t i=0;icell.cp); @@ -422,14 +423,13 @@ int srslte_pucch_init(srslte_pucch_t *q, srslte_cell_t cell) { bzero(q, sizeof(srslte_pucch_t)); q->cell = cell; - q->rnti_is_set = false; srslte_pucch_cfg_default(&q->pucch_cfg); if (srslte_modem_table_lte(&q->mod, SRSLTE_MOD_QPSK)) { return SRSLTE_ERROR; } - + // Precompute group hopping values u. if (srslte_group_hopping_f_gh(q->f_gh, q->cell.id)) { return SRSLTE_ERROR; @@ -439,6 +439,14 @@ int srslte_pucch_init(srslte_pucch_t *q, srslte_cell_t cell) { return SRSLTE_ERROR; } + q->users = calloc(sizeof(srslte_pucch_user_t*), 1+SRSLTE_SIRNTI); + if (!q->users) { + perror("malloc"); + return SRSLTE_ERROR; + } + + srslte_uci_cqi_pucch_init(&q->cqi); + q->z = srslte_vec_malloc(sizeof(cf_t)*SRSLTE_PUCCH_MAX_SYMBOLS); q->z_tmp = srslte_vec_malloc(sizeof(cf_t)*SRSLTE_PUCCH_MAX_SYMBOLS); q->ce = srslte_vec_malloc(sizeof(cf_t)*SRSLTE_PUCCH_MAX_SYMBOLS); @@ -449,10 +457,11 @@ int srslte_pucch_init(srslte_pucch_t *q, srslte_cell_t cell) { } void srslte_pucch_free(srslte_pucch_t *q) { - if (q->rnti_is_set) { - for (uint32_t sf_idx=0;sf_idxseq_f2[sf_idx]); + if (q->users) { + for (int rnti=0;rntiusers); } if (q->z) { free(q->z); @@ -468,15 +477,29 @@ void srslte_pucch_free(srslte_pucch_t *q) { bzero(q, sizeof(srslte_pucch_t)); } -int srslte_pucch_set_crnti(srslte_pucch_t *q, uint16_t c_rnti) { - for (uint32_t sf_idx=0;sf_idxseq_f2[sf_idx], c_rnti, 2*sf_idx, q->cell.id)) { - fprintf(stderr, "Error computing PUCCH Format 2 scrambling sequence\n"); - return SRSLTE_ERROR; - } +void srslte_pucch_clear_rnti(srslte_pucch_t *q, uint16_t rnti) { + if (q->users[rnti]) { + for (int i = 0; i < SRSLTE_NSUBFRAMES_X_FRAME; i++) { + srslte_sequence_free(&q->users[rnti]->seq_f2[i]); + } + free(q->users[rnti]); + q->users[rnti] = NULL; + } +} + +int srslte_pucch_set_crnti(srslte_pucch_t *q, uint16_t rnti) { + if (!q->users[rnti]) { + q->users[rnti] = malloc(sizeof(srslte_pucch_user_t)); + if (q->users[rnti]) { + for (uint32_t sf_idx=0;sf_idxusers[rnti]->seq_f2[sf_idx], rnti, 2*sf_idx, q->cell.id)) { + fprintf(stderr, "Error computing PUCCH Format 2 scrambling sequence\n"); + return SRSLTE_ERROR; + } + } + } } - q->rnti_is_set = true; return SRSLTE_SUCCESS; } @@ -549,7 +572,7 @@ int srslte_pucch_format2ab_mod_bits(srslte_pucch_format_t format, uint8_t bits[2 } /* Encode PUCCH bits according to Table 5.4.1-1 in Section 5.4.1 of 36.211 */ -static int uci_mod_bits(srslte_pucch_t *q, srslte_pucch_format_t format, uint8_t bits[SRSLTE_PUCCH_MAX_BITS], uint32_t sf_idx) +static int uci_mod_bits(srslte_pucch_t *q, srslte_pucch_format_t format, uint8_t bits[SRSLTE_PUCCH_MAX_BITS], uint32_t sf_idx, uint16_t rnti) { uint8_t tmp[2]; @@ -568,9 +591,14 @@ static int uci_mod_bits(srslte_pucch_t *q, srslte_pucch_format_t format, uint8_t case SRSLTE_PUCCH_FORMAT_2: case SRSLTE_PUCCH_FORMAT_2A: case SRSLTE_PUCCH_FORMAT_2B: - memcpy(q->bits_scram, bits, SRSLTE_PUCCH_MAX_BITS*sizeof(uint8_t)); - srslte_scrambling_b(&q->seq_f2[sf_idx], q->bits_scram); - srslte_mod_modulate(&q->mod, q->bits_scram, q->d, SRSLTE_PUCCH_MAX_BITS); + if (q->users[rnti]) { + memcpy(q->bits_scram, bits, SRSLTE_PUCCH2_NOF_BITS*sizeof(uint8_t)); + srslte_scrambling_b(&q->users[rnti]->seq_f2[sf_idx], q->bits_scram); + srslte_mod_modulate(&q->mod, q->bits_scram, q->d, SRSLTE_PUCCH2_NOF_BITS); + } else { + fprintf(stderr, "Error modulating PUCCH2 bits: rnti not set\n"); + return -1; + } break; default: fprintf(stderr, "PUCCH format 2 not supported\n"); @@ -582,13 +610,19 @@ static int uci_mod_bits(srslte_pucch_t *q, srslte_pucch_format_t format, uint8_t // Declare this here, since we can not include refsignal_ul.h void srslte_refsignal_r_uv_arg_1prb(float *arg, uint32_t u); -static int pucch_encode(srslte_pucch_t* q, srslte_pucch_format_t format, - uint32_t n_pucch, uint32_t sf_idx, - uint8_t bits[SRSLTE_PUCCH_MAX_BITS], cf_t z[SRSLTE_PUCCH_MAX_SYMBOLS]) +static int pucch_encode_(srslte_pucch_t* q, srslte_pucch_format_t format, + uint32_t n_pucch, uint32_t sf_idx, uint16_t rnti, + uint8_t bits[SRSLTE_PUCCH_MAX_BITS], cf_t z[SRSLTE_PUCCH_MAX_SYMBOLS], bool signal_only) { - if (uci_mod_bits(q, format, bits, sf_idx)) { - fprintf(stderr, "Error encoding PUCCH bits\n"); - return SRSLTE_ERROR; + if (!signal_only) { + if (uci_mod_bits(q, format, bits, sf_idx, rnti)) { + fprintf(stderr, "Error encoding PUCCH bits\n"); + return SRSLTE_ERROR; + } + } else { + for (int i=0;id[i] = 1.0; + } } uint32_t N_sf_0 = get_N_sf(format, 0, q->shortened); for (uint32_t ns=2*sf_idx;ns<2*(sf_idx+1);ns++) { @@ -631,9 +665,17 @@ static int pucch_encode(srslte_pucch_t* q, srslte_pucch_format_t format, return SRSLTE_SUCCESS; } +static int pucch_encode(srslte_pucch_t* q, srslte_pucch_format_t format, + uint32_t n_pucch, uint32_t sf_idx, uint16_t rnti, + uint8_t bits[SRSLTE_PUCCH_MAX_BITS], cf_t z[SRSLTE_PUCCH_MAX_SYMBOLS]) +{ + return pucch_encode_(q, format, n_pucch, sf_idx, rnti, bits, z, false); +} + + /* Encode, modulate and resource mapping of PUCCH bits according to Section 5.4.1 of 36.211 */ int srslte_pucch_encode(srslte_pucch_t* q, srslte_pucch_format_t format, - uint32_t n_pucch, uint32_t sf_idx, uint8_t bits[SRSLTE_PUCCH_MAX_BITS], + uint32_t n_pucch, uint32_t sf_idx, uint16_t rnti, uint8_t bits[SRSLTE_PUCCH_MAX_BITS], cf_t *sf_symbols) { int ret = SRSLTE_ERROR_INVALID_INPUTS; @@ -654,11 +696,9 @@ int srslte_pucch_encode(srslte_pucch_t* q, srslte_pucch_format_t format, } } - if (format >= SRSLTE_PUCCH_FORMAT_2 && !q->rnti_is_set) { - fprintf(stderr, "Error encoding PUCCH: C-RNTI must be set before encoding PUCCH Format 2/2a/2b\n"); - return SRSLTE_ERROR; - } - if (pucch_encode(q, format, n_pucch, sf_idx, bits, q->z)) { + q->last_n_pucch = n_pucch; + + if (pucch_encode(q, format, n_pucch, sf_idx, rnti, bits, q->z)) { return SRSLTE_ERROR; } if (pucch_put(q, format, n_pucch, q->z, sf_symbols) < 0) { @@ -678,7 +718,7 @@ float srslte_pucch_get_last_corr(srslte_pucch_t* q) /* Equalize, demodulate and decode PUCCH bits according to Section 5.4.1 of 36.211 */ int srslte_pucch_decode(srslte_pucch_t* q, srslte_pucch_format_t format, - uint32_t n_pucch, uint32_t sf_idx, cf_t *sf_symbols, cf_t *ce, float noise_estimate, + uint32_t n_pucch, uint32_t sf_idx, uint16_t rnti, cf_t *sf_symbols, cf_t *ce, float noise_estimate, uint8_t bits[SRSLTE_PUCCH_MAX_BITS]) { int ret = SRSLTE_ERROR_INVALID_INPUTS; @@ -687,6 +727,8 @@ int srslte_pucch_decode(srslte_pucch_t* q, srslte_pucch_format_t format, sf_symbols != NULL) { ret = SRSLTE_ERROR; + cf_t ref[SRSLTE_PUCCH_MAX_SYMBOLS]; + int16_t llr_pucch2[32]; // Shortened PUCCH happen in every cell-specific SRS subframes for Format 1/1a/1b if (q->pucch_cfg.srs_configured && format < SRSLTE_PUCCH_FORMAT_2) { @@ -700,10 +742,8 @@ int srslte_pucch_decode(srslte_pucch_t* q, srslte_pucch_format_t format, } } - if (format >= SRSLTE_PUCCH_FORMAT_2 && !q->rnti_is_set) { - fprintf(stderr, "Error decoding PUCCH: C-RNTI must be set before encoding PUCCH Format 2/2a/2b\n"); - return SRSLTE_ERROR; - } + q->last_n_pucch = n_pucch; + int nof_re = pucch_get(q, format, n_pucch, sf_symbols, q->z_tmp); if (nof_re < 0) { fprintf(stderr, "Error getting PUCCH symbols\n"); @@ -724,13 +764,14 @@ int srslte_pucch_decode(srslte_pucch_t* q, srslte_pucch_format_t format, switch(format) { case SRSLTE_PUCCH_FORMAT_1: bzero(bits, SRSLTE_PUCCH_MAX_BITS*sizeof(uint8_t)); - pucch_encode(q, format, n_pucch, sf_idx, bits, q->z_tmp); + pucch_encode(q, format, n_pucch, sf_idx, rnti, bits, q->z_tmp); corr = crealf(srslte_vec_dot_prod_conj_ccc(q->z, q->z_tmp, nof_re))/nof_re; if (corr >= q->threshold_format1) { ret = 1; } else { ret = 0; } + q->last_corr = corr; DEBUG("format1 corr=%f, nof_re=%d, th=%f\n", corr, nof_re, q->threshold_format1); break; case SRSLTE_PUCCH_FORMAT_1A: @@ -738,25 +779,45 @@ int srslte_pucch_decode(srslte_pucch_t* q, srslte_pucch_format_t format, ret = 0; for (int b=0;b<2;b++) { bits[0] = b; - pucch_encode(q, format, n_pucch, sf_idx, bits, q->z_tmp); + pucch_encode(q, format, n_pucch, sf_idx, rnti, bits, q->z_tmp); corr = crealf(srslte_vec_dot_prod_conj_ccc(q->z, q->z_tmp, nof_re))/nof_re; - if (corr > corr_max && corr >= q->threshold_format1a) { + if (corr > corr_max) { corr_max = corr; b_max = b; } - if (corr_max > q->threshold_format1a) { + if (corr_max > q->threshold_format1) { // check with format1 in case ack+sr because ack only is binary ret = 1; } DEBUG("format1a b=%d, corr=%f, nof_re=%d, th=%f\n", b, corr, nof_re, q->threshold_format1a); } + q->last_corr = corr_max; bits[0] = b_max; break; - default: - fprintf(stderr, "Error decoding PUCCH: Format %d not supported\n", format); - ret = SRSLTE_ERROR; + case SRSLTE_PUCCH_FORMAT_2: + case SRSLTE_PUCCH_FORMAT_2A: + case SRSLTE_PUCCH_FORMAT_2B: + if (q->users[rnti]) { + pucch_encode_(q, format, n_pucch, sf_idx, rnti, NULL, ref, true); + srslte_vec_prod_conj_ccc(q->z, ref, q->z_tmp, SRSLTE_PUCCH_MAX_SYMBOLS); + for (int i=0;iz[i] = 0; + for (int j=0;jz[i] += q->z_tmp[i*SRSLTE_NRE+j]/SRSLTE_NRE; + } + } + srslte_demod_soft_demodulate_s(SRSLTE_MOD_QPSK, q->z, llr_pucch2, SRSLTE_PUCCH2_NOF_BITS/2); + srslte_scrambling_s(&q->users[rnti]->seq_f2[sf_idx], llr_pucch2); + q->last_corr = (float) srslte_uci_decode_cqi_pucch(&q->cqi, llr_pucch2, bits, 4)/2000; + ret = 1; + } else { + fprintf(stderr, "Decoding PUCCH2: rnti not set\n"); + return -1; + } break; + default: + fprintf(stderr, "PUCCH format %d not implemented\n", format); + return SRSLTE_ERROR; } - q->last_corr = corr; } return ret; diff --git a/srslte/lib/phch/pusch.c b/lib/src/phy/phch/pusch.c similarity index 66% rename from srslte/lib/phch/pusch.c rename to lib/src/phy/phch/pusch.c index 9cf66e8e9..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) @@ -209,6 +209,12 @@ int srslte_pusch_init(srslte_pusch_t *q, srslte_cell_t cell) { srslte_modem_table_bytes(&q->mod[i]); } + q->users = calloc(sizeof(srslte_pusch_user_t*), 1+SRSLTE_SIRNTI); + if (!q->users) { + perror("malloc"); + goto clean; + } + /* Precompute sequence for type2 frequency hopping */ if (srslte_sequence_LTE_pr(&q->seq_type2_fo, 210, q->cell.id)) { fprintf(stderr, "Error initiating type2 frequency hopping sequence\n"); @@ -222,8 +228,6 @@ int srslte_pusch_init(srslte_pusch_t *q, srslte_cell_t cell) { goto clean; } - q->rnti_is_set = false; - // Allocate int16 for reception (LLRs). Buffer casted to uint8_t for transmission q->q = srslte_vec_malloc(sizeof(int16_t) * q->max_re * srslte_mod_bits_x_symbol(SRSLTE_MOD_64QAM)); if (!q->q) { @@ -279,10 +283,12 @@ void srslte_pusch_free(srslte_pusch_t *q) { srslte_dft_precoding_free(&q->dft_precoding); - for (i = 0; i < SRSLTE_NSUBFRAMES_X_FRAME; i++) { - srslte_sequence_free(&q->seq[i]); + if (q->users) { + for (int rnti=0;rntiusers); } - srslte_sequence_free(&q->seq_type2_fo); for (i = 0; i < 4; i++) { @@ -382,116 +388,39 @@ int srslte_pusch_cfg(srslte_pusch_t *q, /* Precalculate the PUSCH scramble sequences for a given RNTI. This function takes a while * to execute, so shall be called once the final C-RNTI has been allocated for the session. - * For the connection procedure, use srslte_pusch_encode_rnti() or srslte_pusch_decode_rnti() functions */ + * For the connection procedure, use srslte_pusch_encode() functions */ int srslte_pusch_set_rnti(srslte_pusch_t *q, uint16_t rnti) { uint32_t i; - - for (i = 0; i < SRSLTE_NSUBFRAMES_X_FRAME; i++) { - if (srslte_sequence_pusch(&q->seq[i], rnti, 2 * i, q->cell.id, - q->max_re * srslte_mod_bits_x_symbol(SRSLTE_MOD_64QAM))) { - return SRSLTE_ERROR; - } - } - q->rnti_is_set = true; - q->rnti = rnti; - return SRSLTE_SUCCESS; -} - - -/* Initializes the memory to support pre-calculation of multiple scrambling sequences */ -int srslte_pusch_init_rnti_multi(srslte_pusch_t *q, uint32_t nof_rntis) -{ - for (int i = 0; i < SRSLTE_NSUBFRAMES_X_FRAME; i++) { - q->seq_multi[i] = malloc(sizeof(srslte_sequence_t)*nof_rntis); - if (!q->seq_multi[i]) { - perror("malloc"); - return SRSLTE_ERROR; - } - } - q->rnti_multi = srslte_vec_malloc(sizeof(uint16_t)*nof_rntis); - if (!q->rnti_multi) { - perror("malloc"); - return SRSLTE_ERROR; + if (!q->users[rnti]) { + q->users[rnti] = malloc(sizeof(srslte_pusch_user_t)); + if (q->users[rnti]) { + for (i = 0; i < SRSLTE_NSUBFRAMES_X_FRAME; i++) { + if (srslte_sequence_pusch(&q->users[rnti]->seq[i], rnti, 2 * i, q->cell.id, + q->max_re * srslte_mod_bits_x_symbol(SRSLTE_MOD_64QAM))) { + return SRSLTE_ERROR; + } + } + } } - bzero(q->rnti_multi, sizeof(uint16_t)*nof_rntis); - - q->nof_crnti = nof_rntis; - return SRSLTE_SUCCESS; } -int srslte_pusch_set_rnti_multi(srslte_pusch_t *q, uint32_t idx, uint16_t rnti) -{ - if (idx < q->nof_crnti) { - if (q->rnti_multi[idx]) { - for (uint32_t i = 0; i < SRSLTE_NSUBFRAMES_X_FRAME; i++) { - srslte_sequence_free(&q->seq_multi[i][idx]); - } - q->rnti_multi[idx] = 0; - } - q->rnti_multi[idx] = rnti; - q->rnti_is_set = true; +void srslte_pusch_clear_rnti(srslte_pusch_t *q, uint16_t rnti) { + if (q->users[rnti]) { for (int i = 0; i < SRSLTE_NSUBFRAMES_X_FRAME; i++) { - if (srslte_sequence_pusch(&q->seq_multi[i][idx], rnti, 2 * i, q->cell.id, - q->max_re * srslte_mod_bits_x_symbol(SRSLTE_MOD_64QAM))) { - return SRSLTE_ERROR; - } - } - return SRSLTE_SUCCESS; - } else { - return SRSLTE_ERROR_INVALID_INPUTS; - } -} - -uint16_t srslte_pusch_get_rnti_multi(srslte_pusch_t *q, uint32_t idx) -{ - if (idx < q->nof_crnti) { - return q->rnti_multi[idx]; - } else { - return SRSLTE_ERROR_INVALID_INPUTS; - } -} - -int srslte_pusch_encode_rnti(srslte_pusch_t *q, srslte_pusch_cfg_t *cfg, srslte_softbuffer_tx_t *softbuffer, - uint8_t *data, uint16_t rnti, - cf_t *sf_symbols) -{ - srslte_uci_data_t uci_data; - bzero(&uci_data, sizeof(srslte_uci_data_t)); - return srslte_pusch_uci_encode_rnti(q, cfg, softbuffer, data, uci_data, rnti, sf_symbols); -} - -int srslte_pusch_encode(srslte_pusch_t *q, srslte_pusch_cfg_t *cfg, srslte_softbuffer_tx_t *softbuffer, - uint8_t *data, cf_t *sf_symbols) -{ - if (q->rnti_is_set) { - srslte_uci_data_t uci_data; - bzero(&uci_data, sizeof(srslte_uci_data_t)); - return srslte_pusch_uci_encode_rnti(q, cfg, softbuffer, data, uci_data, q->rnti, sf_symbols); - } else { - fprintf(stderr, "Must call srslte_pusch_set_rnti() to set the encoder/decoder RNTI\n"); - return SRSLTE_ERROR; - } -} - -int srslte_pusch_uci_encode(srslte_pusch_t *q, srslte_pusch_cfg_t *cfg, srslte_softbuffer_tx_t *softbuffer, - uint8_t *data, srslte_uci_data_t uci_data, - cf_t *sf_symbols) -{ - if (q->rnti_is_set) { - return srslte_pusch_uci_encode_rnti(q, cfg, softbuffer, data, uci_data, q->rnti, sf_symbols); - } else { - fprintf(stderr, "Must call srslte_pusch_set_rnti() to set the encoder/decoder RNTI\n"); - return SRSLTE_ERROR; + srslte_sequence_free(&q->users[rnti]->seq[i]); + } + free(q->users[rnti]); + q->users[rnti] = NULL; } } /** Converts the PUSCH data bits to symbols mapped to the slot ready for transmission */ -int srslte_pusch_uci_encode_rnti(srslte_pusch_t *q, srslte_pusch_cfg_t *cfg, srslte_softbuffer_tx_t *softbuffer, - uint8_t *data, srslte_uci_data_t uci_data, uint16_t rnti, - cf_t *sf_symbols) +int srslte_pusch_encode(srslte_pusch_t *q, srslte_pusch_cfg_t *cfg, srslte_softbuffer_tx_t *softbuffer, + uint8_t *data, srslte_uci_data_t uci_data, uint16_t rnti, + cf_t *sf_symbols) { int ret = SRSLTE_ERROR_INVALID_INPUTS; @@ -515,7 +444,7 @@ int srslte_pusch_uci_encode_rnti(srslte_pusch_t *q, srslte_pusch_cfg_t *cfg, srs return SRSLTE_ERROR; } - if (rnti != q->rnti || !q->rnti_is_set) { + if (!q->users[rnti]) { srslte_sequence_t seq; if (srslte_sequence_pusch(&seq, rnti, 2 * cfg->sf_idx, q->cell.id, cfg->nbits.nof_bits)) { return SRSLTE_ERROR; @@ -523,7 +452,7 @@ int srslte_pusch_uci_encode_rnti(srslte_pusch_t *q, srslte_pusch_cfg_t *cfg, srs srslte_scrambling_bytes(&seq, (uint8_t*) q->q, cfg->nbits.nof_bits); srslte_sequence_free(&seq); } else { - srslte_scrambling_bytes(&q->seq[cfg->sf_idx], (uint8_t*) q->q, cfg->nbits.nof_bits); + srslte_scrambling_bytes(&q->users[rnti]->seq[cfg->sf_idx], (uint8_t*) q->q, cfg->nbits.nof_bits); } // Correct UCI placeholder/repetition bits @@ -558,23 +487,14 @@ int srslte_pusch_uci_encode_rnti(srslte_pusch_t *q, srslte_pusch_cfg_t *cfg, srs return ret; } + +/** Decodes the PUSCH from the received symbols + */ int srslte_pusch_decode(srslte_pusch_t *q, srslte_pusch_cfg_t *cfg, srslte_softbuffer_rx_t *softbuffer, cf_t *sf_symbols, - cf_t *ce, float noise_estimate, - uint8_t *data) -{ - srslte_uci_data_t uci_data; - bzero(&uci_data, sizeof(srslte_uci_data_t)); - return srslte_pusch_uci_decode(q, cfg, softbuffer, sf_symbols, ce, noise_estimate, data, &uci_data); -} - -int srslte_pusch_uci_decode_seq(srslte_pusch_t *q, - srslte_pusch_cfg_t *cfg, srslte_softbuffer_rx_t *softbuffer, - srslte_sequence_t *seq, - cf_t *sf_symbols, - cf_t *ce, float noise_estimate, - uint8_t *data, srslte_uci_data_t *uci_data) + cf_t *ce, float noise_estimate, uint16_t rnti, + uint8_t *data, srslte_uci_data_t *uci_data) { uint32_t n; @@ -585,82 +505,61 @@ int srslte_pusch_uci_decode_seq(srslte_pusch_t *q, cfg != NULL) { - if (q->rnti_is_set) { - INFO("Decoding PUSCH SF: %d, Mod %s, NofBits: %d, NofRE: %d, NofSymbols=%d, NofBitsE: %d, rv_idx: %d\n", - cfg->sf_idx, srslte_mod_string(cfg->grant.mcs.mod), cfg->grant.mcs.tbs, - cfg->nbits.nof_re, cfg->nbits.nof_symb, cfg->nbits.nof_bits, cfg->rv); - - /* extract symbols */ - n = pusch_get(q, &cfg->grant, sf_symbols, q->d); - if (n != cfg->nbits.nof_re) { - fprintf(stderr, "Error expecting %d symbols but got %d\n", cfg->nbits.nof_re, n); - return SRSLTE_ERROR; - } - - /* extract channel estimates */ - n = pusch_get(q, &cfg->grant, ce, q->ce); - if (n != cfg->nbits.nof_re) { - fprintf(stderr, "Error expecting %d symbols but got %d\n", cfg->nbits.nof_re, n); - return SRSLTE_ERROR; - } + INFO("Decoding PUSCH SF: %d, Mod %s, NofBits: %d, NofRE: %d, NofSymbols=%d, NofBitsE: %d, rv_idx: %d\n", + cfg->sf_idx, srslte_mod_string(cfg->grant.mcs.mod), cfg->grant.mcs.tbs, + cfg->nbits.nof_re, cfg->nbits.nof_symb, cfg->nbits.nof_bits, cfg->rv); + + /* extract symbols */ + n = pusch_get(q, &cfg->grant, sf_symbols, q->d); + if (n != cfg->nbits.nof_re) { + fprintf(stderr, "Error expecting %d symbols but got %d\n", cfg->nbits.nof_re, n); + return SRSLTE_ERROR; + } + + /* extract channel estimates */ + n = pusch_get(q, &cfg->grant, ce, q->ce); + if (n != cfg->nbits.nof_re) { + fprintf(stderr, "Error expecting %d symbols but got %d\n", cfg->nbits.nof_re, n); + return SRSLTE_ERROR; + } - // Equalization - srslte_predecoding_single(q->d, q->ce, q->z, cfg->nbits.nof_re, noise_estimate); - - // DFT predecoding - srslte_dft_predecoding(&q->dft_precoding, q->z, q->d, cfg->grant.L_prb, cfg->nbits.nof_symb); - - // Soft demodulation - srslte_demod_soft_demodulate_s(cfg->grant.mcs.mod, q->d, q->q, cfg->nbits.nof_re); + // Equalization + srslte_predecoding_single(q->d, q->ce, q->z, cfg->nbits.nof_re, noise_estimate); + + // DFT predecoding + srslte_dft_predecoding(&q->dft_precoding, q->z, q->d, cfg->grant.L_prb, cfg->nbits.nof_symb); + + // Soft demodulation + srslte_demod_soft_demodulate_s(cfg->grant.mcs.mod, q->d, q->q, cfg->nbits.nof_re); + + srslte_sequence_t *seq = NULL; - // Decode RI/HARQ bits before descrambling - if (srslte_ulsch_uci_decode_ri_ack(&q->ul_sch, cfg, softbuffer, q->q, seq->c, uci_data)) { - fprintf(stderr, "Error decoding RI/HARQ bits\n"); + // Create sequence if does not exist + if (!q->users[rnti]) { + seq = &q->tmp_seq; + if (srslte_sequence_pusch(seq, rnti, 2 * cfg->sf_idx, q->cell.id, cfg->nbits.nof_bits)) { return SRSLTE_ERROR; } - - // Descrambling - srslte_scrambling_s_offset(seq, q->q, 0, cfg->nbits.nof_bits); - - return srslte_ulsch_uci_decode(&q->ul_sch, cfg, softbuffer, q->q, q->g, data, uci_data); } else { - fprintf(stderr, "Must call srslte_pusch_set_rnti() before calling srslte_pusch_decode()\n"); - return SRSLTE_ERROR; - } - } else { - return SRSLTE_ERROR_INVALID_INPUTS; - } -} - -/** Decodes the PUSCH from the received symbols - */ -int srslte_pusch_uci_decode(srslte_pusch_t *q, - srslte_pusch_cfg_t *cfg, srslte_softbuffer_rx_t *softbuffer, - cf_t *sf_symbols, - cf_t *ce, float noise_estimate, - uint8_t *data, srslte_uci_data_t *uci_data) -{ - return srslte_pusch_uci_decode_seq(q, cfg, softbuffer, &q->seq[cfg->sf_idx], sf_symbols, ce, noise_estimate, data, uci_data); -} - -/** Decodes the PUSCH from the received symbols for a given RNTI index - */ -int srslte_pusch_uci_decode_rnti_idx(srslte_pusch_t *q, - srslte_pusch_cfg_t *cfg, srslte_softbuffer_rx_t *softbuffer, - cf_t *sf_symbols, - cf_t *ce, float noise_estimate, - uint32_t rnti_idx, - uint8_t *data, srslte_uci_data_t *uci_data) -{ - if (rnti_idx < q->nof_crnti) { - if (q->rnti_multi[rnti_idx]) { - return srslte_pusch_uci_decode_seq(q, cfg, softbuffer, &q->seq_multi[cfg->sf_idx][rnti_idx], sf_symbols, ce, noise_estimate, data, uci_data); - } else { - fprintf(stderr, "Error RNTI idx %d not set\n", rnti_idx); + seq = &q->users[rnti]->seq[cfg->sf_idx]; + } + + // Decode RI/HARQ bits before descrambling + if (srslte_ulsch_uci_decode_ri_ack(&q->ul_sch, cfg, softbuffer, q->q, seq->c, uci_data)) { + fprintf(stderr, "Error decoding RI/HARQ bits\n"); return SRSLTE_ERROR; } + + // Descrambling + srslte_scrambling_s_offset(seq, q->q, 0, cfg->nbits.nof_bits); + + if (!q->users[rnti]) { + srslte_sequence_free(seq); + } + + return srslte_ulsch_uci_decode(&q->ul_sch, cfg, softbuffer, q->q, q->g, data, uci_data); } else { - return SRSLTE_ERROR_INVALID_INPUTS; + return SRSLTE_ERROR_INVALID_INPUTS; } } diff --git a/srslte/lib/phch/ra.c b/lib/src/phy/phch/ra.c similarity index 87% rename from srslte/lib/phch/ra.c rename to lib/src/phy/phch/ra.c index 050130bda..976a669f4 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" @@ -106,7 +106,7 @@ uint32_t ra_re_x_prb(uint32_t subframe, uint32_t slot, uint32_t prb_idx, uint32_ return re; } -int srslte_ul_dci_to_grant_prb_allocation(srslte_ra_ul_dci_t *dci, srslte_ra_ul_grant_t *grant, uint32_t n_rb_ho, uint32_t nof_prb) +int srslte_ra_ul_dci_to_grant_prb_allocation(srslte_ra_ul_dci_t *dci, srslte_ra_ul_grant_t *grant, uint32_t n_rb_ho, uint32_t nof_prb) { bzero(grant, sizeof(srslte_ra_ul_grant_t)); @@ -166,12 +166,20 @@ int srslte_ul_dci_to_grant_prb_allocation(srslte_ra_ul_dci_t *dci, srslte_ra_ul_ INFO("n_rb_pusch: %d, prb1: %d, prb2: %d, L: %d\n", n_rb_pusch, grant->n_prb[0], grant->n_prb[1], grant->L_prb); grant->freq_hopping = 1; } - return SRSLTE_SUCCESS; + + if (grant->n_prb[0] + grant->L_prb <= nof_prb && + grant->n_prb[1] + grant->L_prb <= nof_prb) + { + return SRSLTE_SUCCESS; + } else { + return SRSLTE_ERROR; + } } srslte_mod_t last_mod[8]; uint32_t last_ul_tbs_idx[8]; uint32_t last_dl_tbs[8]; +uint32_t last_dl_tbs2[8]; static int ul_dci_to_grant_mcs(srslte_ra_ul_dci_t *dci, srslte_ra_ul_grant_t *grant, uint32_t harq_pid) { int tbs = -1; @@ -198,6 +206,7 @@ static int ul_dci_to_grant_mcs(srslte_ra_ul_dci_t *dci, srslte_ra_ul_grant_t *gr // 8.6.1 and 8.6.2 36.213 second paragraph grant->mcs.mod = SRSLTE_MOD_QPSK; tbs = srslte_ra_tbs_from_idx(last_ul_tbs_idx[harq_pid%8], grant->L_prb); + dci->rv_idx = 1; } else if (dci->mcs_idx >= 29) { // Else use last TBS/Modulation and use mcs to obtain rv_idx tbs = srslte_ra_tbs_from_idx(last_ul_tbs_idx[harq_pid%8], grant->L_prb); @@ -228,7 +237,7 @@ int srslte_ra_ul_dci_to_grant(srslte_ra_ul_dci_t *dci, uint32_t nof_prb, uint32_ { // Compute PRB allocation - if (!srslte_ul_dci_to_grant_prb_allocation(dci, grant, n_rb_ho, nof_prb)) { + if (!srslte_ra_ul_dci_to_grant_prb_allocation(dci, grant, n_rb_ho, nof_prb)) { // Compute MCS if (!ul_dci_to_grant_mcs(dci, grant, harq_pid)) { @@ -243,12 +252,30 @@ int srslte_ra_ul_dci_to_grant(srslte_ra_ul_dci_t *dci, uint32_t nof_prb, uint32_ return SRSLTE_ERROR; } } else { - fprintf(stderr, "Error computing PRB allocation\n"); + printf("Error computing UL PRB allocation\n"); return SRSLTE_ERROR; } return SRSLTE_SUCCESS; } +uint32_t srslte_ra_dl_approx_nof_re(srslte_cell_t cell, uint32_t nof_prb, uint32_t nof_ctrl_symbols) +{ + uint32_t nof_refs = 0; + uint32_t nof_symb = 2*SRSLTE_CP_NSYMB(cell.cp)-nof_ctrl_symbols; + switch(cell.nof_ports) { + case 1: + nof_refs = 2*3; + break; + case 2: + nof_refs = 4*3; + break; + case 4: + nof_refs = 4*4; + break; + } + return nof_prb * (nof_symb*SRSLTE_NRE-nof_refs); +} + /* Computes the number of RE for each PRB in the prb_dist structure */ uint32_t srslte_ra_dl_grant_nof_re(srslte_ra_dl_grant_t *grant, srslte_cell_t cell, uint32_t sf_idx, uint32_t nof_ctrl_symbols) @@ -273,7 +300,8 @@ uint32_t srslte_ra_dl_grant_nof_re(srslte_ra_dl_grant_t *grant, srslte_cell_t ce * This function only reads dci->type?_alloc and dci->alloc_type fields. * This function only writes grant->prb_idx and grant->nof_prb. */ -static int dl_dci_to_grant_prb_allocation(srslte_ra_dl_dci_t *dci, srslte_ra_dl_grant_t *grant, uint32_t nof_prb) { +/** Compute PRB allocation for Downlink as defined in 7.1.6 of 36.213 */ +int srslte_ra_dl_dci_to_grant_prb_allocation(srslte_ra_dl_dci_t *dci, srslte_ra_dl_grant_t *grant, uint32_t nof_prb) { int i, j; uint32_t bitmask; uint32_t P = srslte_ra_type0_P(nof_prb); @@ -309,15 +337,20 @@ static int dl_dci_to_grant_prb_allocation(srslte_ra_dl_dci_t *dci, srslte_ra_dl_ bitmask = dci->type1_alloc.vrb_bitmask; for (i = 0; i < n_rb_type1; i++) { if (bitmask & (1 << (n_rb_type1 - i - 1))) { - grant->prb_idx[0][((i + shift) / P) + if ((((i + shift) / P) + * P * P + dci->type1_alloc.rbg_subset * P + (i + shift) % P) < nof_prb) { + grant->prb_idx[0][((i + shift) / P) * P * P + dci->type1_alloc.rbg_subset * P + (i + shift) % P] = true; - grant->nof_prb++; + grant->nof_prb++; + } else { + return SRSLTE_ERROR; + } } } memcpy(&grant->prb_idx[1], &grant->prb_idx[0], SRSLTE_MAX_PRB*sizeof(bool)); break; case SRSLTE_RA_ALLOC_TYPE2: - if (dci->type2_alloc.mode == SRSLTE_RA_TYPE2_LOC) { + if (dci->type2_alloc.mode == SRSLTE_RA_TYPE2_LOC) { for (i = 0; i < dci->type2_alloc.L_crb; i++) { grant->prb_idx[0][i + dci->type2_alloc.RB_start] = true; grant->nof_prb++; @@ -363,17 +396,31 @@ static int dl_dci_to_grant_prb_allocation(srslte_ra_dl_dci_t *dci, srslte_ra_dl_ + N_tilde_vrb * (n_vrb / N_tilde_vrb); if (n_tilde_prb_odd < N_tilde_vrb / 2) { - grant->prb_idx[0][n_tilde_prb_odd] = true; + if (n_tilde_prb_odd < nof_prb) { + grant->prb_idx[0][n_tilde_prb_odd] = true; + } else { + return SRSLTE_ERROR; + } } else { - grant->prb_idx[0][n_tilde_prb_odd + N_gap - - N_tilde_vrb / 2] = true; + if (n_tilde_prb_odd + N_gap - N_tilde_vrb / 2 < nof_prb) { + grant->prb_idx[0][n_tilde_prb_odd + N_gap - N_tilde_vrb / 2] = true; + } else { + return SRSLTE_ERROR; + } } grant->nof_prb++; if (n_tilde_prb_even < N_tilde_vrb / 2) { - grant->prb_idx[1][n_tilde_prb_even] = true; + if(n_tilde_prb_even < nof_prb) { + grant->prb_idx[1][n_tilde_prb_even] = true; + } else { + return SRSLTE_ERROR; + } } else { - grant->prb_idx[1][n_tilde_prb_even + N_gap - - N_tilde_vrb / 2] = true; + if (n_tilde_prb_even + N_gap - N_tilde_vrb / 2 < nof_prb) { + grant->prb_idx[1][n_tilde_prb_even + N_gap - N_tilde_vrb / 2] = true; + } else { + return SRSLTE_ERROR; + } } } } @@ -449,21 +496,38 @@ static int dl_dci_to_grant_mcs(srslte_ra_dl_dci_t *dci, srslte_ra_dl_grant_t *gr grant->mcs.tbs = (uint32_t) tbs; } else { n_prb = grant->nof_prb; - grant->mcs.idx = dci->mcs_idx; - tbs = dl_fill_ra_mcs(&grant->mcs, n_prb); - if (tbs) { - last_dl_tbs[dci->harq_process%8] = tbs; + grant->nof_tb = 0; + if (dci->tb_en[0]) { + grant->mcs.idx = dci->mcs_idx; + tbs = dl_fill_ra_mcs(&grant->mcs, n_prb); + if (tbs) { + last_dl_tbs[dci->harq_process%8] = tbs; + } else { + // For mcs>=29, set last TBS received for this PID + grant->mcs.tbs = last_dl_tbs[dci->harq_process%8]; + } + grant->nof_tb++; } else { - // For mcs>=29, set last TBS received for this PID - grant->mcs.tbs = last_dl_tbs[dci->harq_process%8]; + grant->mcs.tbs = 0; } - if (dci->nof_tb == 2) { + if (dci->tb_en[1]) { grant->mcs2.idx = dci->mcs_idx_1; tbs = dl_fill_ra_mcs(&grant->mcs2, n_prb); + if (tbs) { + last_dl_tbs2[dci->harq_process%8] = tbs; + } else { + // For mcs>=29, set last TBS received for this PID + grant->mcs2.tbs = last_dl_tbs2[dci->harq_process%8]; + } + grant->nof_tb++; + } else { + grant->mcs2.tbs = 0; } } - grant->Qm = srslte_mod_bits_x_symbol(grant->mcs.mod); - if (dci->nof_tb == 2) { + if (dci->tb_en[0]) { + grant->Qm = srslte_mod_bits_x_symbol(grant->mcs.mod); + } + if (dci->tb_en[1]) { grant->Qm2 = srslte_mod_bits_x_symbol(grant->mcs2.mod); } if (tbs < 0) { @@ -491,7 +555,7 @@ int srslte_ra_dl_dci_to_grant(srslte_ra_dl_dci_t *dci, crc_is_crnti = true; } // Compute PRB allocation - if (!dl_dci_to_grant_prb_allocation(dci, grant, nof_prb)) { + if (!srslte_ra_dl_dci_to_grant_prb_allocation(dci, grant, nof_prb)) { // Compute MCS if (!dl_dci_to_grant_mcs(dci, grant, crc_is_crnti)) { // Apply Section 7.1.7.3. If RA-RNTI and Format1C rv_idx=0 @@ -601,6 +665,16 @@ int srslte_ra_tbs_idx_from_mcs(uint32_t mcs) { } } +srslte_mod_t srslte_ra_mod_from_mcs(uint32_t mcs) { + if (mcs <= 10 || mcs == 29) { + return SRSLTE_MOD_QPSK; + } else if (mcs <= 17 || mcs == 30) { + return SRSLTE_MOD_16QAM; + } else { + return SRSLTE_MOD_64QAM; + } +} + int srslte_ra_mcs_from_tbs_idx(uint32_t tbs_idx) { for (int i=0;i<29;i++) { if (tbs_idx == mcs_tbs_idx_table[i]) { 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 8641a7cab..18db503a1 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 6a44954f7..ba4c8951b 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 @@ -473,10 +473,10 @@ static int decode_tb(srslte_sch_t *q, par_tx = ((uint32_t) parity[0])<<16 | ((uint32_t) parity[1])<<8 | ((uint32_t) parity[2]); if (!par_rx) { - INFO("Warning: Received all-zero transport block\n\n", 0); + INFO("Warning: Received all-zero transport block\n\n", 0); } - if (par_rx == par_tx && par_rx) { + if (par_rx == par_tx) { INFO("TB decoded OK\n",i); return SRSLTE_SUCCESS; } else { @@ -666,16 +666,10 @@ int srslte_ulsch_uci_decode(srslte_sch_t *q, srslte_pusch_cfg_t *cfg, srslte_sof // Decode CQI (multiplexed at the front of ULSCH) if (uci_data->uci_cqi_len > 0) { - struct timeval t[3]; - gettimeofday(&t[1], NULL); ret = srslte_uci_decode_cqi_pusch(&q->uci_cqi, cfg, g_bits, beta_cqi_offset[cfg->uci_cfg.I_offset_cqi], Q_prime_ri, uci_data->uci_cqi_len, uci_data->uci_cqi, &uci_data->cqi_ack); - gettimeofday(&t[2], NULL); - get_time_interval(t); - printf("texec=%ld us\n", t[0].tv_usec); - if (ret < 0) { return ret; } @@ -683,7 +677,7 @@ int srslte_ulsch_uci_decode(srslte_sch_t *q, srslte_pusch_cfg_t *cfg, srslte_sof } e_offset += Q_prime_cqi*Qm; - + // Decode ULSCH if (cfg->cb_segm.tbs > 0) { uint32_t G = nb_q/Qm - Q_prime_ri - Q_prime_cqi; 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..6170f82fe 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_rf 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 99% rename from srslte/lib/phch/test/pbch_file_test.c rename to lib/src/phy/phch/test/pbch_file_test.c index 6e9ba5950..f3e4b9b08 100644 --- a/srslte/lib/phch/test/pbch_file_test.c +++ b/lib/src/phy/phch/test/pbch_file_test.c @@ -37,7 +37,6 @@ char *input_file_name = NULL; srslte_cell_t cell = { 6, // nof_prb 2, // nof_ports - 0, // bw_idx 150, // cell_id SRSLTE_CP_NORM, // cyclic prefix SRSLTE_PHICH_R_1, // PHICH resources 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 99% rename from srslte/lib/phch/test/pcfich_file_test.c rename to lib/src/phy/phch/test/pcfich_file_test.c index 03029c9fc..27b50baeb 100644 --- a/srslte/lib/phch/test/pcfich_file_test.c +++ b/lib/src/phy/phch/test/pcfich_file_test.c @@ -39,7 +39,6 @@ char *matlab_file_name = NULL; srslte_cell_t cell = { 6, // nof_prb 1, // nof_ports - 0, // bw_idx 0, // cell_id SRSLTE_CP_NORM, // cyclic prefix SRSLTE_PHICH_R_1, // PHICH resources 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 99% rename from srslte/lib/phch/test/pdcch_file_test.c rename to lib/src/phy/phch/test/pdcch_file_test.c index ed3aafdf4..b505e6b68 100644 --- a/srslte/lib/phch/test/pdcch_file_test.c +++ b/lib/src/phy/phch/test/pdcch_file_test.c @@ -37,7 +37,6 @@ char *input_file_name = NULL; srslte_cell_t cell = { 6, // cell.cell.cell.nof_prb 1, // cell.cell.nof_ports - 0, // bw_idx 0, // cell.id SRSLTE_CP_NORM, // cyclic prefix SRSLTE_PHICH_R_1, // PHICH resources diff --git a/srslte/lib/phch/test/pdcch_test.c b/lib/src/phy/phch/test/pdcch_test.c similarity index 98% rename from srslte/lib/phch/test/pdcch_test.c rename to lib/src/phy/phch/test/pdcch_test.c index d03532b45..5d4fb0a7c 100644 --- a/srslte/lib/phch/test/pdcch_test.c +++ b/lib/src/phy/phch/test/pdcch_test.c @@ -191,11 +191,11 @@ int main(int argc, char **argv) { ra_dl.alloc_type = SRSLTE_RA_ALLOC_TYPE0; ra_dl.type0_alloc.rbg_bitmask = 0x5; - srslte_dci_msg_pack_pdsch(&ra_dl, SRSLTE_DCI_FORMAT1, &dci_tx[0], cell.nof_prb, false); + srslte_dci_msg_pack_pdsch(&ra_dl, SRSLTE_DCI_FORMAT1, &dci_tx[0], cell.nof_prb, cell.nof_ports, false); srslte_dci_location_set(&dci_locations[0], 0, 0); ra_dl.mcs_idx = 15; - srslte_dci_msg_pack_pdsch(&ra_dl, SRSLTE_DCI_FORMAT1, &dci_tx[1], cell.nof_prb, false); + srslte_dci_msg_pack_pdsch(&ra_dl, SRSLTE_DCI_FORMAT1, &dci_tx[1], cell.nof_prb, cell.nof_ports, false); srslte_dci_location_set(&dci_locations[1], 0, 1); for (i=0;i= 3) { + const mwSize *dims = mxGetDimensions(INPUT); + nof_antennas = dims[2]; + } + + if (srslte_pdsch_init_multi(&pdsch, cell, nof_antennas)) { mexErrMsgTxt("Error initiating PDSCH\n"); return; } - srslte_pdsch_set_rnti(&pdsch, (uint16_t) (rnti32 & 0xffff)); + uint16_t rnti = (uint16_t) (rnti32 & 0xffff); + srslte_pdsch_set_rnti(&pdsch, rnti); if (srslte_softbuffer_rx_init(&softbuffer, cell.nof_prb)) { mexErrMsgTxt("Error initiating soft buffer\n"); @@ -187,18 +196,19 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) nof_retx = mexutils_getLength(INPUT); } - cf_t *ce[SRSLTE_MAX_PORTS]; - for (i=0;i= 6) { - mexutils_write_cf(ce[0], &plhs[5], SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp), 1); + uint32_t len = nof_antennas*cell.nof_ports*SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp); + cf_t *cearray_ptr = srslte_vec_malloc(len*sizeof(cf_t)); + int n=0; + for (i=0;i #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 98% rename from srslte/lib/phch/test/pucch_test.c rename to lib/src/phy/phch/test/pucch_test.c index 67cf46fdd..316a5efc4 100644 --- a/srslte/lib/phch/test/pucch_test.c +++ b/lib/src/phy/phch/test/pucch_test.c @@ -36,7 +36,6 @@ srslte_cell_t cell = { 25, // nof_prb 1, // nof_ports - 2, // bw_idx = 5 MHz 1, // cell_id SRSLTE_CP_NORM, // cyclic prefix SRSLTE_PHICH_R_1_6, // PHICH resources @@ -136,7 +135,7 @@ int main(int argc, char **argv) { goto quit; } - if (srslte_pucch_encode(&pucch, format, n_pucch, subframe, bits, sf_symbols)) { + if (srslte_pucch_encode(&pucch, format, n_pucch, subframe, 11, bits, sf_symbols)) { fprintf(stderr, "Error encoding PUCCH\n"); goto quit; } diff --git a/srslte/lib/phch/test/pucch_test_mex.c b/lib/src/phy/phch/test/pucch_test_mex.c similarity index 97% rename from srslte/lib/phch/test/pucch_test_mex.c rename to lib/src/phy/phch/test/pucch_test_mex.c index c65097b11..baf6c84db 100644 --- a/srslte/lib/phch/test/pucch_test_mex.c +++ b/lib/src/phy/phch/test/pucch_test_mex.c @@ -192,7 +192,7 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) return; } - if (srslte_pucch_decode(&pucch, format, n_pucch, sf_idx, sf_symbols, ce, 0, bits)) { + if (srslte_pucch_decode(&pucch, format, n_pucch, sf_idx, sf_symbols, ce, 0, bits)<0) { mexErrMsgTxt("Error decoding PUCCH\n"); return; } @@ -210,11 +210,11 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) } if (nlhs >= 2) { - mexutils_write_cf(pucch.z, &plhs[1], 2*srslte_refsignal_dmrs_N_rs(format, cell.cp)*SRSLTE_NRE*2, 1); + mexutils_write_cf(pucch.z, &plhs[1], 10, 1); } if (nlhs >= 3) { - mexutils_write_cf(ce, &plhs[2], nof_re, 1); + mexutils_write_cf(pucch.z_tmp, &plhs[2], 120, 1); } srslte_pucch_free(&pucch); 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 96% rename from srslte/lib/phch/test/pusch_encode_test_mex.c rename to lib/src/phy/phch/test/pusch_encode_test_mex.c index 4d8693bbf..59c0bbe15 100644 --- a/srslte/lib/phch/test/pusch_encode_test_mex.c +++ b/lib/src/phy/phch/test/pusch_encode_test_mex.c @@ -76,8 +76,9 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) mexErrMsgTxt("Field RNTI not found in pusch config\n"); return; } - srslte_pusch_set_rnti(&pusch, (uint16_t) (rnti32 & 0xffff)); + uint16_t rnti = (uint16_t) (rnti32 & 0xffff); + srslte_pusch_set_rnti(&pusch, rnti); srslte_pusch_cfg_t cfg; @@ -195,7 +196,7 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) mexPrintf("I_cqi: %2d, I_ri: %2d, I_ack=%2d\n", cfg.uci_cfg.I_offset_cqi, cfg.uci_cfg.I_offset_ri, cfg.uci_cfg.I_offset_ack); mexPrintf("NofRE: %3d, NofBits: %3d, TBS: %3d, N_srs=%d\n", cfg.nbits.nof_re, cfg.nbits.nof_bits, grant.mcs.tbs, N_srs); - int r = srslte_pusch_uci_encode(&pusch, &cfg, &softbuffer, trblkin, uci_data, sf_symbols); + int r = srslte_pusch_encode(&pusch, &cfg, &softbuffer, trblkin, uci_data, rnti, sf_symbols); if (r < 0) { mexErrMsgTxt("Error encoding PUSCH\n"); return; @@ -205,7 +206,7 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) return; } if (cfg.rv > 0) { - r = srslte_pusch_uci_encode(&pusch, &cfg, &softbuffer, trblkin, uci_data, sf_symbols); + r = srslte_pusch_encode(&pusch, &cfg, &softbuffer, trblkin, uci_data, rnti, sf_symbols); if (r < 0) { mexErrMsgTxt("Error encoding PUSCH\n"); return; diff --git a/srslte/lib/phch/test/pusch_test.c b/lib/src/phy/phch/test/pusch_test.c similarity index 95% rename from srslte/lib/phch/test/pusch_test.c rename to lib/src/phy/phch/test/pusch_test.c index def6b5982..29980a83f 100644 --- a/srslte/lib/phch/test/pusch_test.c +++ b/lib/src/phy/phch/test/pusch_test.c @@ -164,7 +164,8 @@ int main(int argc, char **argv) { exit(-1); } - srslte_pusch_set_rnti(&pusch, 1234); + uint16_t rnti = 1234; + srslte_pusch_set_rnti(&pusch, rnti); srslte_uci_data_t uci_data_tx; srslte_uci_data_t uci_data_rx; @@ -208,13 +209,13 @@ int main(int argc, char **argv) { uint32_t ntrials = 100; - if (srslte_pusch_uci_encode(&pusch, &cfg, &softbuffer_tx, data, uci_data_tx, sf_symbols)) { + if (srslte_pusch_encode(&pusch, &cfg, &softbuffer_tx, data, uci_data_tx, rnti, sf_symbols)) { fprintf(stderr, "Error encoding TB\n"); exit(-1); } if (rv_idx > 0) { cfg.rv = rv_idx; - if (srslte_pusch_uci_encode(&pusch, &cfg, &softbuffer_tx, data, uci_data_tx, sf_symbols)) { + if (srslte_pusch_encode(&pusch, &cfg, &softbuffer_tx, data, uci_data_tx, rnti, sf_symbols)) { fprintf(stderr, "Error encoding TB\n"); exit(-1); } @@ -230,7 +231,7 @@ int main(int argc, char **argv) { } gettimeofday(&t[1], NULL); - int r = srslte_pusch_uci_decode(&pusch, &cfg, &softbuffer_rx, sf_symbols, ce, 0, data, &uci_data_rx); + int r = srslte_pusch_decode(&pusch, &cfg, &softbuffer_rx, sf_symbols, ce, 0, rnti, data, &uci_data_rx); gettimeofday(&t[2], NULL); get_time_interval(t); if (r) { diff --git a/srslte/lib/phch/test/pusch_test_mex.c b/lib/src/phy/phch/test/pusch_test_mex.c similarity index 97% rename from srslte/lib/phch/test/pusch_test_mex.c rename to lib/src/phy/phch/test/pusch_test_mex.c index 6178a1f3a..7b29075eb 100644 --- a/srslte/lib/phch/test/pusch_test_mex.c +++ b/lib/src/phy/phch/test/pusch_test_mex.c @@ -99,7 +99,8 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) mexErrMsgTxt("Error initiating PDSCH\n"); return; } - srslte_pusch_set_rnti(&pusch, (uint16_t) (rnti32 & 0xffff)); + uint16_t rnti = (uint16_t) (rnti32 & 0xffff); + srslte_pusch_set_rnti(&pusch, rnti); if (srslte_softbuffer_rx_init(&softbuffer, cell.nof_prb)) { mexErrMsgTxt("Error initiating soft buffer\n"); @@ -272,7 +273,7 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) noise_power = srslte_chest_ul_get_noise_estimate(&chest); } - r = srslte_pusch_uci_decode(&pusch, &cfg, &softbuffer, input_fft, ce, noise_power, data_bytes, &uci_data); + r = srslte_pusch_decode(&pusch, &cfg, &softbuffer, input_fft, ce, noise_power, rnti, data_bytes, &uci_data); } uint8_t *data = malloc(grant.mcs.tbs); 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 91% rename from srslte/lib/phch/uci.c rename to lib/src/phy/phch/uci.c index ece0702c2..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 */ @@ -104,7 +104,75 @@ static uint8_t M_basis_seq_pucch[20][13]={ {1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0}, }; +void srslte_uci_cqi_pucch_init(srslte_uci_cqi_pucch_t *q) { + uint8_t word[16]; + + uint32_t nwords = 16; + for (uint32_t w=0;wcqi_table[w]); + for (int j=0;jcqi_table_s[w][j] = 2*q->cqi_table[w][j]-1; + } + } +} +/* Encode UCI CQI/PMI as described in 5.2.3.3 of 36.212 + */ +int srslte_uci_encode_cqi_pucch(uint8_t *cqi_data, uint32_t cqi_len, uint8_t b_bits[SRSLTE_UCI_CQI_CODED_PUCCH_B]) +{ + if (cqi_len <= SRSLTE_UCI_MAX_CQI_LEN_PUCCH) { + for (uint32_t i=0;icqi_table_s[w], b_bits, SRSLTE_UCI_CQI_CODED_PUCCH_B); + if (corr > max_corr) { + max_corr = corr; + max_w = w; + } + } + // Convert word to bits again + uint8_t *ptr = cqi_data; + srslte_bit_unpack(max_w, &ptr, cqi_len); + + INFO("Decoded CQI: w=%d, corr=%d\n", max_w, max_corr); + return max_corr; + } else { + return SRSLTE_ERROR_INVALID_INPUTS; + } +} + + + + + + + + void encode_cqi_pusch_block(srslte_uci_cqi_pusch_t *q, uint8_t *data, uint32_t nof_bits, uint8_t output[32]) { for (int i=0;i<32;i++) { output[i] = 0; @@ -297,11 +365,7 @@ int decode_cqi_long(srslte_uci_cqi_pusch_t *q, int16_t *q_bits, uint32_t Q, srslte_rm_conv_rx_s(q_bits, Q, q->encoded_cqi_s, 3 * (nof_bits + 8)); - // Set viterbi normalization based on amplitude - int16_t max = srslte_vec_max_star_si(q->encoded_cqi_s, 3 * (nof_bits + 8)); - srslte_viterbi_set_gain_quant_s(&q->viterbi, max/36); - - DEBUG("cconv_rx=", 0); + DEBUG("cconv_rx=", 0); if (SRSLTE_VERBOSE_ISDEBUG()) { srslte_vec_fprint_s(stdout, q->encoded_cqi_s, 3 * (nof_bits + 8)); } @@ -314,7 +378,7 @@ int decode_cqi_long(srslte_uci_cqi_pusch_t *q, int16_t *q_bits, uint32_t Q, } ret = srslte_crc_checksum(&q->crc, q->tmp_cqi, nof_bits + 8); - if (ret == 0) { + if (ret == 0) { memcpy(data, q->tmp_cqi, nof_bits*sizeof(uint8_t)); ret = 1; } else { @@ -324,24 +388,6 @@ int decode_cqi_long(srslte_uci_cqi_pusch_t *q, int16_t *q_bits, uint32_t Q, return ret; } -/* Encode UCI CQI/PMI as described in 5.2.3.3 of 36.212 - */ -int srslte_uci_encode_cqi_pucch(uint8_t *cqi_data, uint32_t cqi_len, uint8_t b_bits[SRSLTE_UCI_CQI_CODED_PUCCH_B]) -{ - if (cqi_len <= SRSLTE_UCI_MAX_CQI_LEN_PUCCH) { - for (uint32_t i=0;i #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 53% rename from srslte/lib/rf/CMakeLists.txt rename to lib/src/phy/rf/CMakeLists.txt index 3b97dfecf..6cec5a6df 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 @@ -19,9 +19,14 @@ # if(RF_FOUND) + + # This library is only used by the examples + add_library(srslte_rf_utils STATIC rf_utils.c) + target_link_libraries(srslte_rf_utils srslte_phy) + # Include common RF files set(SOURCES_RF "") - list(APPEND SOURCES_RF rf_imp.c rf_utils.c) + list(APPEND SOURCES_RF rf_imp.c) if (UHD_FOUND) add_definitions(-DENABLE_UHD) @@ -33,6 +38,27 @@ if(RF_FOUND) list(APPEND SOURCES_RF rf_blade_imp.c) endif (BLADERF_FOUND) - add_library(srslte_rf OBJECT ${SOURCES_RF}) - SRSLTE_SET_PIC(srslte_rf) + 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}) + target_link_libraries(srslte_rf srslte_rf_utils srslte_phy) + + if (UHD_FOUND) + target_link_libraries(srslte_rf ${UHD_LIBRARIES}) + endif (UHD_FOUND) + + if (BLADERF_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}) endif(RF_FOUND) diff --git a/srslte/lib/rf/rf_blade_imp.c b/lib/src/phy/rf/rf_blade_imp.c similarity index 96% rename from srslte/lib/rf/rf_blade_imp.c rename to lib/src/phy/rf/rf_blade_imp.c index fbe9b3fc6..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 @@ -178,6 +178,11 @@ float rf_blade_get_rssi(void *h) return 0; } +int rf_blade_open_multi(char *args, void **h, uint32_t nof_rx_antennas) +{ + return rf_blade_open(args, h); +} + int rf_blade_open(char *args, void **h) { *h = NULL; @@ -413,6 +418,17 @@ void rf_blade_get_time(void *h, time_t *secs, double *frac_secs) timestamp_to_secs(handler->rx_rate, meta.timestamp, secs, frac_secs); } + +int rf_blade_recv_with_time_multi(void *h, + void **data, + uint32_t nsamples, + bool blocking, + time_t *secs, + double *frac_secs) +{ + return rf_blade_recv_with_time(h, *data, nsamples, blocking, secs, frac_secs); +} + int rf_blade_recv_with_time(void *h, void *data, uint32_t nsamples, diff --git a/srslte/lib/rf/rf_blade_imp.h b/lib/src/phy/rf/rf_blade_imp.h similarity index 87% rename from srslte/lib/rf/rf_blade_imp.h rename to lib/src/phy/rf/rf_blade_imp.h index 552564620..07e9bb7cf 100644 --- a/srslte/lib/rf/rf_blade_imp.h +++ b/lib/src/phy/rf/rf_blade_imp.h @@ -26,13 +26,15 @@ #include "srslte/config.h" -#include "srslte/rf/rf.h" +#include "srslte/phy/rf/rf.h" #define DEVNAME "bladerf" SRSLTE_API int rf_blade_open(char *args, void **handler); +SRSLTE_API int rf_blade_open_multi(char *args, + void **handler, uint32_t nof_rx_antennas); SRSLTE_API char* rf_blade_devname(void *h); @@ -82,6 +84,13 @@ SRSLTE_API void rf_blade_register_error_handler(void *h, SRSLTE_API double rf_blade_set_rx_freq(void *h, double freq); +SRSLTE_API int rf_blade_recv_with_time_multi(void *h, + void **data, + uint32_t nsamples, + bool blocking, + time_t *secs, + double *frac_secs); + SRSLTE_API int rf_blade_recv_with_time(void *h, void *data, uint32_t nsamples, diff --git a/srslte/lib/rf/rf_dev.h b/lib/src/phy/rf/rf_dev.h similarity index 80% rename from srslte/lib/rf/rf_dev.h rename to lib/src/phy/rf/rf_dev.h index 2dd65552c..e1b761419 100644 --- a/srslte/lib/rf/rf_dev.h +++ b/lib/src/phy/rf/rf_dev.h @@ -38,6 +38,7 @@ typedef struct { void (*srslte_rf_suppress_stdout)(void *h); void (*srslte_rf_register_error_handler)(void *h, srslte_rf_error_handler_t error_handler); int (*srslte_rf_open)(char *args, void **h); + int (*srslte_rf_open_multi)(char *args, void **h, uint32_t nof_rx_antennas); int (*srslte_rf_close)(void *h); void (*srslte_rf_set_master_clock_rate)(void *h, double rate); bool (*srslte_rf_is_master_clock_dynamic)(void *h); @@ -52,6 +53,8 @@ typedef struct { void (*srslte_rf_get_time)(void *h, time_t *secs, double *frac_secs); int (*srslte_rf_recv_with_time)(void *h, void *data, uint32_t nsamples, bool blocking, time_t *secs,double *frac_secs); + int (*srslte_rf_recv_with_time_multi)(void *h, void **data, uint32_t nsamples, + bool blocking, time_t *secs,double *frac_secs); int (*srslte_rf_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); @@ -78,6 +81,7 @@ static rf_dev_t dev_uhd = { rf_uhd_suppress_stdout, rf_uhd_register_error_handler, rf_uhd_open, + rf_uhd_open_multi, rf_uhd_close, rf_uhd_set_master_clock_rate, rf_uhd_is_master_clock_dynamic, @@ -91,6 +95,7 @@ static rf_dev_t dev_uhd = { rf_uhd_set_tx_freq, rf_uhd_get_time, rf_uhd_recv_with_time, + rf_uhd_recv_with_time_multi, rf_uhd_send_timed, rf_uhd_set_tx_cal, rf_uhd_set_rx_cal @@ -114,6 +119,7 @@ static rf_dev_t dev_blade = { rf_blade_suppress_stdout, rf_blade_register_error_handler, rf_blade_open, + rf_blade_open_multi, rf_blade_close, rf_blade_set_master_clock_rate, rf_blade_is_master_clock_dynamic, @@ -127,12 +133,51 @@ static rf_dev_t dev_blade = { rf_blade_set_tx_freq, rf_blade_get_time, rf_blade_recv_with_time, + rf_blade_recv_with_time_multi, rf_blade_send_timed, rf_blade_set_tx_cal, rf_blade_set_rx_cal }; #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 @@ -176,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 87% rename from srslte/lib/rf/rf_imp.c rename to lib/src/phy/rf/rf_imp.c index fe93d0e93..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" @@ -99,6 +99,10 @@ const char* srslte_rf_get_devname(srslte_rf_t *rf) { } int srslte_rf_open_devname(srslte_rf_t *rf, char *devname, char *args) { + return srslte_rf_open_devname_multi(rf, devname, args, 1); +} + +int srslte_rf_open_devname_multi(srslte_rf_t *rf, char *devname, char *args, uint32_t nof_rx_antennas) { /* Try to open the device if name is provided */ if (devname) { if (devname[0] != '\0') { @@ -106,7 +110,7 @@ int srslte_rf_open_devname(srslte_rf_t *rf, char *devname, char *args) { while(available_devices[i] != NULL) { if (!strcmp(available_devices[i]->name, devname)) { rf->dev = available_devices[i]; - return available_devices[i]->srslte_rf_open(args, &rf->handler); + return available_devices[i]->srslte_rf_open_multi(args, &rf->handler, nof_rx_antennas); } i++; } @@ -117,7 +121,7 @@ int srslte_rf_open_devname(srslte_rf_t *rf, char *devname, char *args) { /* If in auto mode or provided device not found, try to open in order of apperance in available_devices[] array */ int i=0; while(available_devices[i] != NULL) { - if (!available_devices[i]->srslte_rf_open(args, &rf->handler)) { + if (!available_devices[i]->srslte_rf_open_multi(args, &rf->handler, nof_rx_antennas)) { rf->dev = available_devices[i]; return 0; } @@ -182,7 +186,12 @@ void srslte_rf_register_error_handler(srslte_rf_t *rf, srslte_rf_error_handler_t int srslte_rf_open(srslte_rf_t *h, char *args) { - return srslte_rf_open_devname(h, NULL, args); + return srslte_rf_open_devname_multi(h, NULL, args, 1); +} + +int srslte_rf_open_multi(srslte_rf_t *h, char *args, uint32_t nof_rx_antennas) +{ + return srslte_rf_open_devname_multi(h, NULL, args, nof_rx_antennas); } int srslte_rf_close(srslte_rf_t *rf) @@ -231,6 +240,11 @@ int srslte_rf_recv(srslte_rf_t *rf, void *data, uint32_t nsamples, bool blocking return srslte_rf_recv_with_time(rf, data, nsamples, blocking, NULL, NULL); } +int srslte_rf_recv_multi(srslte_rf_t *rf, void **data, uint32_t nsamples, bool blocking) +{ + return srslte_rf_recv_with_time_multi(rf, data, nsamples, blocking, NULL, NULL); +} + int srslte_rf_recv_with_time(srslte_rf_t *rf, void *data, uint32_t nsamples, @@ -241,6 +255,16 @@ int srslte_rf_recv_with_time(srslte_rf_t *rf, return ((rf_dev_t*) rf->dev)->srslte_rf_recv_with_time(rf->handler, data, nsamples, blocking, secs, frac_secs); } +int srslte_rf_recv_with_time_multi(srslte_rf_t *rf, + void **data, + uint32_t nsamples, + bool blocking, + time_t *secs, + double *frac_secs) +{ + return ((rf_dev_t*) rf->dev)->srslte_rf_recv_with_time_multi(rf->handler, data, nsamples, blocking, secs, frac_secs); +} + double srslte_rf_set_tx_gain(srslte_rf_t *rf, double gain) { return ((rf_dev_t*) rf->dev)->srslte_rf_set_tx_gain(rf->handler, gain); 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 71% rename from srslte/lib/rf/rf_uhd_imp.c rename to lib/src/phy/rf/rf_uhd_imp.c index d16382f52..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 { @@ -51,6 +51,13 @@ typedef struct { bool dynamic_rate; bool has_rssi; uhd_sensor_value_handle rssi_value; + uint32_t nof_rx_channels; + int nof_tx_channels; + + srslte_rf_error_handler_t uhd_error_handler; + + bool async_thread_running; + pthread_t async_thread; } rf_uhd_handler_t; void suppress_handler(const char *x) @@ -58,35 +65,69 @@ void suppress_handler(const char *x) // do nothing } -srslte_rf_error_handler_t uhd_error_handler = NULL; +cf_t zero_mem[64*1024]; -void msg_handler(const char *msg) -{ - srslte_rf_error_t error; - bzero(&error, sizeof(srslte_rf_error_t)); - - if(0 == strcmp(msg, "O")) { - error.type = SRSLTE_RF_ERROR_OVERFLOW; - } else if(0 == strcmp(msg, "D")) { +static void log_overflow(rf_uhd_handler_t *h) { + if (h->uhd_error_handler) { + srslte_rf_error_t error; + bzero(&error, sizeof(srslte_rf_error_t)); error.type = SRSLTE_RF_ERROR_OVERFLOW; - }else if(0 == strcmp(msg, "U")) { - error.type = SRSLTE_RF_ERROR_UNDERFLOW; - } else if(0 == strcmp(msg, "L")) { + h->uhd_error_handler(error); + } +} + +static void log_late(rf_uhd_handler_t *h) { + if (h->uhd_error_handler) { + srslte_rf_error_t error; + bzero(&error, sizeof(srslte_rf_error_t)); error.type = SRSLTE_RF_ERROR_LATE; + h->uhd_error_handler(error); } - if (uhd_error_handler) { - uhd_error_handler(error); +} + +static void log_underflow(rf_uhd_handler_t *h) { + if (h->uhd_error_handler) { + srslte_rf_error_t error; + bzero(&error, sizeof(srslte_rf_error_t)); + error.type = SRSLTE_RF_ERROR_UNDERFLOW; + h->uhd_error_handler(error); + } +} + +static void* async_thread(void *h) { + rf_uhd_handler_t *handler = (rf_uhd_handler_t*) h; + uhd_async_metadata_handle md; + 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, 0.5, &valid); + if (err == UHD_ERROR_NONE) { + if (valid) { + uhd_async_metadata_event_code_t event_code; + uhd_async_metadata_event_code(md, &event_code); + if (event_code == UHD_ASYNC_METADATA_EVENT_CODE_UNDERFLOW || + event_code == UHD_ASYNC_METADATA_EVENT_CODE_UNDERFLOW_IN_PACKET) { + log_underflow(handler); + } else if (event_code == UHD_ASYNC_METADATA_EVENT_CODE_TIME_ERROR) { + log_late(handler); + } + } + } else { + fprintf(stderr, "Error while receiving aync metadata: 0x%x\n", err); + return NULL; + } } + return NULL; } void rf_uhd_suppress_stdout(void *h) { rf_uhd_register_msg_handler_c(suppress_handler); } -void rf_uhd_register_error_handler(void *notused, srslte_rf_error_handler_t new_handler) +void rf_uhd_register_error_handler(void *h, srslte_rf_error_handler_t new_handler) { - uhd_error_handler = new_handler; - rf_uhd_register_msg_handler_c(msg_handler); + rf_uhd_handler_t *handler = (rf_uhd_handler_t*) h; + handler->uhd_error_handler = new_handler; } static bool find_string(uhd_string_vector_handle h, char *str) @@ -103,12 +144,16 @@ static bool find_string(uhd_string_vector_handle h, char *str) return false; } -static bool isLocked(rf_uhd_handler_t *handler, char *sensor_name, uhd_sensor_value_handle *value_h) +static bool isLocked(rf_uhd_handler_t *handler, char *sensor_name, bool is_rx, uhd_sensor_value_handle *value_h) { bool val_out = false; if (sensor_name) { - uhd_usrp_get_rx_sensor(handler->usrp, sensor_name, 0, value_h); + if (is_rx) { + uhd_usrp_get_rx_sensor(handler->usrp, sensor_name, 0, value_h); + } else { + uhd_usrp_get_mboard_sensor(handler->usrp, sensor_name, 0, value_h); + } uhd_sensor_value_to_bool(*value_h, &val_out); } else { usleep(500); @@ -138,21 +183,21 @@ bool rf_uhd_rx_wait_lo_locked(void *h) uhd_usrp_get_mboard_sensor_names(handler->usrp, 0, &mb_sensors); uhd_usrp_get_rx_sensor_names(handler->usrp, 0, &rx_sensors); - if (find_string(rx_sensors, "lo_locked")) { + /*if (find_string(rx_sensors, "lo_locked")) { sensor_name = "lo_locked"; - } else if (find_string(mb_sensors, "ref_locked")) { + } else */if (find_string(mb_sensors, "ref_locked")) { sensor_name = "ref_locked"; } else { sensor_name = NULL; } double report = 0.0; - while (!isLocked(handler, sensor_name, &value_h) && report < 30.0) { + while (!isLocked(handler, sensor_name, false, &value_h) && report < 30.0) { report += 0.1; usleep(1000); } - bool val = isLocked(handler, sensor_name, &value_h); + bool val = isLocked(handler, sensor_name, false, &value_h); uhd_string_vector_free(&mb_sensors); uhd_string_vector_free(&rx_sensors); @@ -174,12 +219,19 @@ void rf_uhd_set_rx_cal(void *h, srslte_rf_cal_t *cal) int rf_uhd_start_rx_stream(void *h) { - rf_uhd_handler_t *handler = (rf_uhd_handler_t*) h; + rf_uhd_handler_t *handler = (rf_uhd_handler_t*) h; + uhd_stream_cmd_t stream_cmd = { .stream_mode = UHD_STREAM_MODE_START_CONTINUOUS, - .stream_now = true - }; - uhd_rx_streamer_issue_stream_cmd(handler->rx_stream, &stream_cmd); + .stream_now = false + }; + uhd_usrp_get_time_now(handler->usrp, 0, &stream_cmd.time_spec_full_secs, &stream_cmd.time_spec_frac_secs); + stream_cmd.time_spec_frac_secs += 0.5; + if (stream_cmd.time_spec_frac_secs > 1) { + stream_cmd.time_spec_frac_secs -= 1; + stream_cmd.time_spec_full_secs += 1; + } + uhd_rx_streamer_issue_stream_cmd(handler->rx_stream, &stream_cmd); return 0; } @@ -197,9 +249,11 @@ int rf_uhd_stop_rx_stream(void *h) void rf_uhd_flush_buffer(void *h) { int n; - cf_t tmp[1024]; + cf_t tmp1[1024]; + cf_t tmp2[1024]; + void *data[2] = {tmp1, tmp2}; do { - n = rf_uhd_recv_with_time(h, tmp, 1024, 0, NULL, NULL); + n = rf_uhd_recv_with_time_multi(h, data, 1024, 0, NULL, NULL); } while (n > 0); } @@ -231,6 +285,11 @@ float rf_uhd_get_rssi(void *h) { } int rf_uhd_open(char *args, void **h) +{ + return rf_uhd_open_multi(args, h, 1); +} + +int rf_uhd_open_multi(char *args, void **h, uint32_t nof_rx_antennas) { if (h) { *h = NULL; @@ -259,6 +318,11 @@ int rf_uhd_open(char *args, void **h) args = ""; } handler->devname = NULL; + + // Initialize handler + handler->uhd_error_handler = NULL; + + bzero(zero_mem, sizeof(cf_t)*64*1024); /* If device type or name not given in args, choose a B200 */ if (args[0]=='\0') { @@ -287,7 +351,11 @@ int rf_uhd_open(char *args, void **h) uhd_string_vector_free(&devices_str); /* Create UHD handler */ - printf("Opening USRP with args: %s\n", args); + if (strstr(args, "silent")) { + rf_uhd_suppress_stdout(NULL); + } else { + printf("Opening USRP with args: %s\n", args); + } uhd_error error = uhd_usrp_make(&handler->usrp, args); if (error) { fprintf(stderr, "Error opening UHD: code %d\n", error); @@ -306,25 +374,33 @@ int rf_uhd_open(char *args, void **h) if (!handler->devname) { handler->devname = "uhd_unknown"; } - size_t channel = 0; - uhd_stream_args_t stream_args = { - .cpu_format = "fc32", - .otw_format = "sc16", - .args = "", - .channel_list = &channel, - .n_channels = 1 - }; // Set external clock reference 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); } + handler->has_rssi = get_has_rssi(handler); if (handler->has_rssi) { uhd_sensor_value_make_from_realnum(&handler->rssi_value, "rssi", 0, "dBm", "%f"); } + size_t channel[4] = {0, 1, 2, 3}; + uhd_stream_args_t stream_args = { + .cpu_format = "fc32", + .otw_format = "sc16", + .args = "", + .channel_list = channel, + .n_channels = 1 + }; + + handler->nof_rx_channels = nof_rx_antennas; + handler->nof_tx_channels = 1; + /* Initialize rx and tx stremers */ uhd_rx_streamer_make(&handler->rx_stream); error = uhd_usrp_get_rx_stream(handler->usrp, &stream_args, handler->rx_stream); @@ -350,6 +426,14 @@ int rf_uhd_open(char *args, void **h) uhd_rx_metadata_make(&handler->rx_md_first); uhd_tx_metadata_make(&handler->tx_md, false, 0, 0, false, false); + + // Start low priority thread to receive async commands + handler->async_thread_running = true; + if (pthread_create(&handler->async_thread, NULL, async_thread, handler)) { + perror("pthread_create"); + return -1; + } + return 0; } else { return SRSLTE_ERROR_INVALID_INPUTS; @@ -372,6 +456,8 @@ int rf_uhd_close(void *h) if (handler->has_rssi) { uhd_sensor_value_free(&handler->rssi_value); } + handler->async_thread_running = false; + pthread_join(handler->async_thread, NULL); uhd_usrp_free(&handler->usrp); /** Something else to close the USRP?? */ @@ -393,7 +479,9 @@ bool rf_uhd_is_master_clock_dynamic(void *h) { double rf_uhd_set_rx_srate(void *h, double freq) { rf_uhd_handler_t *handler = (rf_uhd_handler_t*) h; - uhd_usrp_set_rx_rate(handler->usrp, freq, 0); + for (int i=0;inof_rx_channels;i++) { + uhd_usrp_set_rx_rate(handler->usrp, freq, i); + } uhd_usrp_get_rx_rate(handler->usrp, 0, &freq); return freq; } @@ -401,7 +489,9 @@ double rf_uhd_set_rx_srate(void *h, double freq) double rf_uhd_set_tx_srate(void *h, double freq) { rf_uhd_handler_t *handler = (rf_uhd_handler_t*) h; - uhd_usrp_set_tx_rate(handler->usrp, freq, 0); + for (int i=0;inof_tx_channels;i++) { + uhd_usrp_set_tx_rate(handler->usrp, freq, i); + } uhd_usrp_get_tx_rate(handler->usrp, 0, &freq); handler->tx_rate = freq; return freq; @@ -410,7 +500,9 @@ double rf_uhd_set_tx_srate(void *h, double freq) double rf_uhd_set_rx_gain(void *h, double gain) { rf_uhd_handler_t *handler = (rf_uhd_handler_t*) h; - uhd_usrp_set_rx_gain(handler->usrp, gain, 0, ""); + for (int i=0;inof_rx_channels;i++) { + uhd_usrp_set_rx_gain(handler->usrp, gain, i, ""); + } uhd_usrp_get_rx_gain(handler->usrp, 0, "", &gain); return gain; } @@ -418,7 +510,9 @@ double rf_uhd_set_rx_gain(void *h, double gain) double rf_uhd_set_tx_gain(void *h, double gain) { rf_uhd_handler_t *handler = (rf_uhd_handler_t*) h; - uhd_usrp_set_tx_gain(handler->usrp, gain, 0, ""); + for (int i=0;inof_tx_channels;i++) { + uhd_usrp_set_tx_gain(handler->usrp, gain, i, ""); + } uhd_usrp_get_tx_gain(handler->usrp, 0, "", &gain); return gain; } @@ -448,7 +542,9 @@ double rf_uhd_set_rx_freq(void *h, double freq) }; uhd_tune_result_t tune_result; rf_uhd_handler_t *handler = (rf_uhd_handler_t*) h; - uhd_usrp_set_rx_freq(handler->usrp, &tune_request, 0, &tune_result); + for (int i=0;inof_rx_channels;i++) { + uhd_usrp_set_rx_freq(handler->usrp, &tune_request, i, &tune_result); + } uhd_usrp_get_rx_freq(handler->usrp, 0, &freq); return freq; } @@ -462,7 +558,9 @@ double rf_uhd_set_tx_freq(void *h, double freq) }; uhd_tune_result_t tune_result; rf_uhd_handler_t *handler = (rf_uhd_handler_t*) h; - uhd_usrp_set_tx_freq(handler->usrp, &tune_request, 0, &tune_result); + for (int i=0;inof_tx_channels;i++) { + uhd_usrp_set_tx_freq(handler->usrp, &tune_request, i, &tune_result); + } uhd_usrp_get_tx_freq(handler->usrp, 0, &freq); return freq; } @@ -480,6 +578,16 @@ int rf_uhd_recv_with_time(void *h, time_t *secs, double *frac_secs) { + return rf_uhd_recv_with_time_multi(h, &data, nsamples, blocking, secs, frac_secs); +} + +int rf_uhd_recv_with_time_multi(void *h, + void **data, + uint32_t nsamples, + bool blocking, + time_t *secs, + double *frac_secs) +{ rf_uhd_handler_t *handler = (rf_uhd_handler_t*) h; size_t rxd_samples; @@ -487,18 +595,20 @@ int rf_uhd_recv_with_time(void *h, int trials = 0; if (blocking) { int n = 0; - cf_t *data_c = (cf_t*) data; do { - size_t rx_samples = handler->rx_nof_samples; + size_t rx_samples = nsamples; if (rx_samples > nsamples - n) { rx_samples = nsamples - n; } - void *buff = (void*) &data_c[n]; - void **buffs_ptr = (void**) &buff; + void *buffs_ptr[4]; + for (int i=0;inof_rx_channels;i++) { + cf_t *data_c = (cf_t*) data[i]; + buffs_ptr[i] = &data_c[n]; + } + uhd_error error = uhd_rx_streamer_recv(handler->rx_stream, buffs_ptr, - rx_samples, md, 5.0, false, &rxd_samples); - + rx_samples, md, 1.0, false, &rxd_samples); if (error) { fprintf(stderr, "Error receiving from UHD: %d\n", error); return -1; @@ -506,11 +616,21 @@ int rf_uhd_recv_with_time(void *h, md = &handler->rx_md; n += rxd_samples; trials++; + + uhd_rx_metadata_error_code_t error_code; + uhd_rx_metadata_error_code(*md, &error_code); + if (error_code == UHD_RX_METADATA_ERROR_CODE_OVERFLOW) { + log_overflow(handler); + } else if (error_code == UHD_RX_METADATA_ERROR_CODE_LATE_COMMAND) { + log_late(handler); + } else if (error_code != UHD_RX_METADATA_ERROR_CODE_NONE) { + fprintf(stderr, "Error code 0x%x was returned during streaming. Aborting.\n", error_code); + } + } while (n < nsamples && trials < 100); } else { - void **buffs_ptr = (void**) &data; - return uhd_rx_streamer_recv(handler->rx_stream, buffs_ptr, - nsamples, md, 0.0, false, &rxd_samples); + return uhd_rx_streamer_recv(handler->rx_stream, data, + nsamples, md, 0.0, false, &rxd_samples); } if (secs && frac_secs) { uhd_rx_metadata_time_spec(handler->rx_md_first, secs, frac_secs); @@ -557,7 +677,7 @@ int rf_uhd_send_timed(void *h, } void *buff = (void*) &data_c[n]; - const void **buffs_ptr = (const void**) &buff; + const void *buffs_ptr[4] = {buff, zero_mem, zero_mem, zero_mem}; uhd_error error = uhd_tx_streamer_send(handler->tx_stream, buffs_ptr, tx_samples, &handler->tx_md, 3.0, &txd_samples); if (error) { @@ -571,7 +691,7 @@ int rf_uhd_send_timed(void *h, } while (n < nsamples && trials < 100); return nsamples; } else { - const void **buffs_ptr = (const void**) &data; + const void *buffs_ptr[4] = {data, zero_mem, zero_mem, zero_mem}; uhd_tx_metadata_set_start(&handler->tx_md, is_start_of_burst); uhd_tx_metadata_set_end(&handler->tx_md, is_end_of_burst); return uhd_tx_streamer_send(handler->tx_stream, buffs_ptr, nsamples, &handler->tx_md, 0.0, &txd_samples); diff --git a/srslte/lib/rf/rf_uhd_imp.h b/lib/src/phy/rf/rf_uhd_imp.h similarity index 88% rename from srslte/lib/rf/rf_uhd_imp.h rename to lib/src/phy/rf/rf_uhd_imp.h index ee13ea36e..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" @@ -37,6 +37,10 @@ SRSLTE_API int rf_uhd_open(char *args, void **handler); +SRSLTE_API int rf_uhd_open_multi(char *args, + void **handler, + uint32_t nof_rx_antennas); + SRSLTE_API char* rf_uhd_devname(void *h); SRSLTE_API int rf_uhd_close(void *h); @@ -89,6 +93,13 @@ SRSLTE_API int rf_uhd_recv_with_time(void *h, time_t *secs, double *frac_secs); +SRSLTE_API int rf_uhd_recv_with_time_multi(void *h, + void **data, + uint32_t nsamples, + bool blocking, + time_t *secs, + double *frac_secs); + SRSLTE_API double rf_uhd_set_tx_srate(void *h, double freq); diff --git a/srslte/lib/rf/rf_utils.c b/lib/src/phy/rf/rf_utils.c similarity index 84% rename from srslte/lib/rf/rf_utils.c rename to lib/src/phy/rf/rf_utils.c index 066b9a2b3..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; @@ -82,10 +82,13 @@ free_and_exit: return ret; } - -int srslte_rf_recv_wrapper_cs(void *h, void *data, uint32_t nsamples, srslte_timestamp_t *t) { +int srslte_rf_recv_wrapper_cs(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, nsamples, 1); + void *ptr[SRSLTE_MAX_PORTS]; + for (int i=0;iid, cell->cp, srslte_rf_recv_wrapper_cs, (void*) rf)) { + if (srslte_ue_mib_sync_init_multi(&ue_mib, cell->id, cell->cp, srslte_rf_recv_wrapper_cs, nof_rx_antennas, (void*) rf)) { fprintf(stderr, "Error initiating srslte_ue_mib_sync\n"); goto clean_exit; } @@ -151,8 +154,9 @@ clean_exit: /** This function is simply a wrapper to the ue_cell_search module for rf devices */ -int rf_cell_search(srslte_rf_t *rf, cell_search_cfg_t *config, - int force_N_id_2, srslte_cell_t *cell, float *cfo) +int rf_cell_search(srslte_rf_t *rf, uint32_t nof_rx_antennas, + cell_search_cfg_t *config, + int force_N_id_2, srslte_cell_t *cell, float *cfo) { int ret = SRSLTE_ERROR; srslte_ue_cellsearch_t cs; @@ -160,7 +164,7 @@ int rf_cell_search(srslte_rf_t *rf, cell_search_cfg_t *config, bzero(found_cells, 3*sizeof(srslte_ue_cellsearch_result_t)); - if (srslte_ue_cellsearch_init(&cs, config->max_frames_pss, srslte_rf_recv_wrapper_cs, (void*) rf)) { + if (srslte_ue_cellsearch_init_multi(&cs, config->max_frames_pss, srslte_rf_recv_wrapper_cs, nof_rx_antennas, (void*) rf)) { fprintf(stderr, "Error initiating UE cell detect\n"); return SRSLTE_ERROR; } @@ -234,15 +238,15 @@ int rf_cell_search(srslte_rf_t *rf, cell_search_cfg_t *config, * 0 if no cell was found or MIB could not be decoded, * -1 on error */ -int rf_search_and_decode_mib(srslte_rf_t *rf, cell_search_cfg_t *config, int force_N_id_2, srslte_cell_t *cell, float *cfo) +int rf_search_and_decode_mib(srslte_rf_t *rf, uint32_t nof_rx_antennas, cell_search_cfg_t *config, int force_N_id_2, srslte_cell_t *cell, float *cfo) { int ret = SRSLTE_ERROR; printf("Searching for cell...\n"); - ret = rf_cell_search(rf, config, force_N_id_2, cell, cfo); + ret = rf_cell_search(rf, nof_rx_antennas, config, force_N_id_2, cell, cfo); if (ret > 0) { printf("Decoding PBCH for cell %d (N_id_2=%d)\n", cell->id, cell->id%3); - ret = rf_mib_decoder(rf, config, cell, cfo); + ret = rf_mib_decoder(rf, nof_rx_antennas, config, cell, cfo); if (ret < 0) { fprintf(stderr, "Could not decode PBCH from CELL ID %d\n", cell->id); return SRSLTE_ERROR; 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 92af48f69..da348c17b 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 85% rename from srslte/lib/scrambling/CMakeLists.txt rename to lib/src/phy/scrambling/CMakeLists.txt index b0dc7452a..b8c4941ad 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 @@ -20,5 +20,4 @@ file(GLOB SOURCES "*.c") add_library(srslte_scrambling OBJECT ${SOURCES}) -SRSLTE_SET_PIC(srslte_scrambling) add_subdirectory(test) 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 86% rename from srslte/lib/sync/CMakeLists.txt rename to lib/src/phy/sync/CMakeLists.txt index 2aff1e93e..706efde38 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 @@ -20,5 +20,4 @@ file(GLOB SOURCES "*.c") add_library(srslte_sync OBJECT ${SOURCES}) -SRSLTE_SET_PIC(srslte_sync) add_subdirectory(test) 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..35407ca94 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 srslte_rf) 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 85% rename from srslte/lib/ue/CMakeLists.txt rename to lib/src/phy/ue/CMakeLists.txt index fba91255d..3072b3a43 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 @@ -20,4 +20,3 @@ file(GLOB SOURCES "*.c") add_library(srslte_ue OBJECT ${SOURCES}) -SRSLTE_SET_PIC(srslte_ue) diff --git a/srslte/lib/ue/ue_cell_search.c b/lib/src/phy/ue/ue_cell_search.c similarity index 78% rename from srslte/lib/ue/ue_cell_search.c rename to lib/src/phy/ue/ue_cell_search.c index 018f20a8a..f8c38a1bb 100644 --- a/srslte/lib/ue/ue_cell_search.c +++ b/lib/src/phy/ue/ue_cell_search.c @@ -30,13 +30,14 @@ #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*), void *stream_handler) + int (recv_callback)(void*, void*, uint32_t,srslte_timestamp_t*), + void *stream_handler) { int ret = SRSLTE_ERROR_INVALID_INPUTS; @@ -55,6 +56,65 @@ int srslte_ue_cellsearch_init(srslte_ue_cellsearch_t * q, uint32_t max_frames, goto clean_exit; } + q->sf_buffer[0] = srslte_vec_malloc(3*sizeof(cf_t)*SRSLTE_SF_LEN_PRB(100)); + q->nof_rx_antennas = 1; + + q->candidates = calloc(sizeof(srslte_ue_cellsearch_result_t), max_frames); + if (!q->candidates) { + perror("malloc"); + goto clean_exit; + } + q->mode_ntimes = calloc(sizeof(uint32_t), max_frames); + if (!q->mode_ntimes) { + perror("malloc"); + goto clean_exit; + } + q->mode_counted = calloc(sizeof(uint8_t), max_frames); + if (!q->mode_counted) { + perror("malloc"); + goto clean_exit; + } + + q->max_frames = max_frames; + q->nof_valid_frames = max_frames; + + ret = SRSLTE_SUCCESS; + } + +clean_exit: + if (ret == SRSLTE_ERROR) { + srslte_ue_cellsearch_free(q); + } + return ret; +} + +int srslte_ue_cellsearch_init_multi(srslte_ue_cellsearch_t * q, uint32_t max_frames, + int (recv_callback)(void*, cf_t*[SRSLTE_MAX_PORTS], uint32_t,srslte_timestamp_t*), + uint32_t nof_rx_antennas, + void *stream_handler) +{ + int ret = SRSLTE_ERROR_INVALID_INPUTS; + + if (q != NULL) { + ret = SRSLTE_ERROR; + srslte_cell_t cell; + + bzero(q, sizeof(srslte_ue_cellsearch_t)); + + bzero(&cell, sizeof(srslte_cell_t)); + cell.id = SRSLTE_CELL_ID_UNKNOWN; + cell.nof_prb = SRSLTE_CS_NOF_PRB; + + if (srslte_ue_sync_init_multi(&q->ue_sync, cell, recv_callback, nof_rx_antennas, stream_handler)) { + fprintf(stderr, "Error initiating ue_sync\n"); + goto clean_exit; + } + + for (int i=0;isf_buffer[i] = srslte_vec_malloc(3*sizeof(cf_t)*SRSLTE_SF_LEN_PRB(100)); + } + q->nof_rx_antennas = nof_rx_antennas; + q->candidates = calloc(sizeof(srslte_ue_cellsearch_result_t), max_frames); if (!q->candidates) { perror("malloc"); @@ -86,6 +146,11 @@ clean_exit: void srslte_ue_cellsearch_free(srslte_ue_cellsearch_t * q) { + for (int i=0;inof_rx_antennas;i++) { + if (q->sf_buffer[i]) { + free(q->sf_buffer[i]); + } + } if (q->candidates) { free(q->candidates); } @@ -203,7 +268,6 @@ int srslte_ue_cellsearch_scan_N_id_2(srslte_ue_cellsearch_t * q, srslte_ue_cellsearch_result_t *found_cell) { int ret = SRSLTE_ERROR_INVALID_INPUTS; - cf_t *sf_buffer = NULL; uint32_t nof_detected_frames = 0; uint32_t nof_scanned_frames = 0; @@ -215,7 +279,7 @@ int srslte_ue_cellsearch_scan_N_id_2(srslte_ue_cellsearch_t * q, srslte_ue_sync_reset(&q->ue_sync); do { - ret = srslte_ue_sync_get_buffer(&q->ue_sync, &sf_buffer); + ret = srslte_ue_sync_zerocopy_multi(&q->ue_sync, q->sf_buffer); if (ret < 0) { fprintf(stderr, "Error calling srslte_ue_sync_work()\n"); break; diff --git a/srslte/lib/ue/ue_dl.c b/lib/src/phy/ue/ue_dl.c similarity index 79% rename from srslte/lib/ue/ue_dl.c rename to lib/src/phy/ue/ue_dl.c index 9444be773..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 @@ -44,13 +44,20 @@ const uint32_t nof_ue_formats = 2; static srslte_dci_format_t common_formats[] = {SRSLTE_DCI_FORMAT1A,SRSLTE_DCI_FORMAT1C}; const uint32_t nof_common_formats = 2; - int srslte_ue_dl_init(srslte_ue_dl_t *q, - srslte_cell_t cell) + srslte_cell_t cell) +{ + return srslte_ue_dl_init_multi(q, cell, 1); +} + +int srslte_ue_dl_init_multi(srslte_ue_dl_t *q, + srslte_cell_t cell, + uint32_t nof_rx_antennas) { int ret = SRSLTE_ERROR_INVALID_INPUTS; - if (q != NULL && + if (q != NULL && + nof_rx_antennas <= SRSLTE_MAX_PORTS && srslte_cell_isvalid(&cell)) { ret = SRSLTE_ERROR; @@ -62,6 +69,7 @@ int srslte_ue_dl_init(srslte_ue_dl_t *q, q->pkts_total = 0; q->pending_ul_dci_rnti = 0; q->sample_offset = 0; + q->nof_rx_antennas = nof_rx_antennas; if (srslte_ofdm_rx_init(&q->fft, q->cell.cp, q->cell.nof_prb)) { fprintf(stderr, "Error initiating FFT\n"); @@ -75,7 +83,7 @@ int srslte_ue_dl_init(srslte_ue_dl_t *q, fprintf(stderr, "Error initiating REGs\n"); goto clean_exit; } - if (srslte_pcfich_init(&q->pcfich, &q->regs, q->cell)) { + if (srslte_pcfich_init_multi(&q->pcfich, &q->regs, q->cell, nof_rx_antennas)) { fprintf(stderr, "Error creating PCFICH object\n"); goto clean_exit; } @@ -84,12 +92,12 @@ int srslte_ue_dl_init(srslte_ue_dl_t *q, goto clean_exit; } - if (srslte_pdcch_init(&q->pdcch, &q->regs, q->cell)) { + if (srslte_pdcch_init_multi(&q->pdcch, &q->regs, q->cell, nof_rx_antennas)) { fprintf(stderr, "Error creating PDCCH object\n"); goto clean_exit; } - if (srslte_pdsch_init(&q->pdsch, q->cell)) { + if (srslte_pdsch_init_multi(&q->pdsch, q->cell, nof_rx_antennas)) { fprintf(stderr, "Error creating PDSCH object\n"); goto clean_exit; } @@ -103,17 +111,24 @@ int srslte_ue_dl_init(srslte_ue_dl_t *q, } srslte_cfo_set_tol(&q->sfo_correct, 1e-5/q->fft.symbol_sz); - q->sf_symbols = srslte_vec_malloc(CURRENT_SFLEN_RE * sizeof(cf_t)); - if (!q->sf_symbols) { - perror("malloc"); - goto clean_exit; - } - for (uint32_t i=0;icell.nof_ports;i++) { - q->ce[i] = srslte_vec_malloc(CURRENT_SFLEN_RE * sizeof(cf_t)); - if (!q->ce[i]) { + for (int j=0;jsf_symbols_m[j] = srslte_vec_malloc(CURRENT_SFLEN_RE * sizeof(cf_t)); + if (!q->sf_symbols_m[j]) { perror("malloc"); goto clean_exit; } + for (uint32_t i=0;icell.nof_ports;i++) { + q->ce_m[i][j] = srslte_vec_malloc(CURRENT_SFLEN_RE * sizeof(cf_t)); + if (!q->ce_m[i][j]) { + perror("malloc"); + goto clean_exit; + } + } + } + + q->sf_symbols = q->sf_symbols_m[0]; + for (int i=0;icell.nof_ports;i++) { + q->ce[i] = q->ce_m[i][0]; } ret = SRSLTE_SUCCESS; @@ -140,12 +155,14 @@ void srslte_ue_dl_free(srslte_ue_dl_t *q) { srslte_pdsch_free(&q->pdsch); srslte_cfo_free(&q->sfo_correct); srslte_softbuffer_rx_free(&q->softbuffer); - if (q->sf_symbols) { - free(q->sf_symbols); - } - for (uint32_t i=0;icell.nof_ports;i++) { - if (q->ce[i]) { - free(q->ce[i]); + for (int j=0;jnof_rx_antennas;j++) { + if (q->sf_symbols_m[j]) { + free(q->sf_symbols_m[j]); + } + for (uint32_t i=0;icell.nof_ports;i++) { + if (q->ce_m[i][j]) { + free(q->ce_m[i][j]); + } } } bzero(q, sizeof(srslte_ue_dl_t)); @@ -187,22 +204,38 @@ void srslte_ue_dl_set_sample_offset(srslte_ue_dl_t * q, float sample_offset) { * - PDSCH decoding: Decode TB scrambling with RNTI given by srslte_ue_dl_set_rnti() */ int srslte_ue_dl_decode(srslte_ue_dl_t *q, cf_t *input, uint8_t *data, uint32_t tti) { - return srslte_ue_dl_decode_rnti(q, input, data, tti, q->current_rnti); + cf_t *_input[SRSLTE_MAX_PORTS]; + _input[0] = input; + return srslte_ue_dl_decode_rnti_multi(q, _input, data, tti, q->current_rnti); +} + +int srslte_ue_dl_decode_multi(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], uint8_t *data, uint32_t tti) { + return srslte_ue_dl_decode_rnti_multi(q, input, data, tti, q->current_rnti); +} + +int srslte_ue_dl_decode_fft_estimate(srslte_ue_dl_t *q, cf_t *input, uint32_t sf_idx, uint32_t *cfi) +{ + cf_t *_input[SRSLTE_MAX_PORTS]; + _input[0] = input; + return srslte_ue_dl_decode_fft_estimate_multi(q, _input, sf_idx, cfi); } -int srslte_ue_dl_decode_fft_estimate(srslte_ue_dl_t *q, cf_t *input, uint32_t sf_idx, uint32_t *cfi) { +int srslte_ue_dl_decode_fft_estimate_multi(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], uint32_t sf_idx, uint32_t *cfi) +{ if (input && q && cfi && sf_idx < SRSLTE_NSUBFRAMES_X_FRAME) { /* Run FFT for all subframe data */ - srslte_ofdm_rx_sf(&q->fft, input, q->sf_symbols); - - /* Correct SFO multiplying by complex exponential in the time domain */ - if (q->sample_offset) { - for (int i=0;i<2*SRSLTE_CP_NSYMB(q->cell.cp);i++) { - srslte_cfo_correct(&q->sfo_correct, - &q->sf_symbols[i*q->cell.nof_prb*SRSLTE_NRE], - &q->sf_symbols[i*q->cell.nof_prb*SRSLTE_NRE], - q->sample_offset / q->fft.symbol_sz); + for (int j=0;jnof_rx_antennas;j++) { + srslte_ofdm_rx_sf(&q->fft, input[j], q->sf_symbols_m[j]); + + /* Correct SFO multiplying by complex exponential in the time domain */ + if (q->sample_offset) { + for (int i=0;i<2*SRSLTE_CP_NSYMB(q->cell.cp);i++) { + srslte_cfo_correct(&q->sfo_correct, + &q->sf_symbols_m[j][i*q->cell.nof_prb*SRSLTE_NRE], + &q->sf_symbols_m[j][i*q->cell.nof_prb*SRSLTE_NRE], + q->sample_offset / q->fft.symbol_sz); + } } } return srslte_ue_dl_decode_estimate(q, sf_idx, cfi); @@ -216,10 +249,10 @@ int srslte_ue_dl_decode_estimate(srslte_ue_dl_t *q, uint32_t sf_idx, uint32_t *c if (q && cfi && sf_idx < SRSLTE_NSUBFRAMES_X_FRAME) { /* Get channel estimates for each port */ - srslte_chest_dl_estimate(&q->chest, q->sf_symbols, q->ce, sf_idx); + srslte_chest_dl_estimate_multi(&q->chest, q->sf_symbols_m, q->ce_m, sf_idx, q->nof_rx_antennas); /* First decode PCFICH and obtain CFI */ - if (srslte_pcfich_decode(&q->pcfich, q->sf_symbols, q->ce, + if (srslte_pcfich_decode_multi(&q->pcfich, q->sf_symbols_m, q->ce_m, srslte_chest_dl_get_noise_estimate(&q->chest), sf_idx, cfi, &cfi_corr)<0) { fprintf(stderr, "Error decoding PCFICH\n"); @@ -246,6 +279,13 @@ int srslte_ue_dl_cfg_grant(srslte_ue_dl_t *q, srslte_ra_dl_grant_t *grant, uint3 } int srslte_ue_dl_decode_rnti(srslte_ue_dl_t *q, cf_t *input, uint8_t *data, uint32_t tti, uint16_t rnti) +{ + cf_t *_input[SRSLTE_MAX_PORTS]; + _input[0] = input; + return srslte_ue_dl_decode_rnti_multi(q, _input, data, tti, rnti); +} + +int srslte_ue_dl_decode_rnti_multi(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], uint8_t *data, uint32_t tti, uint16_t rnti) { srslte_dci_msg_t dci_msg; srslte_ra_dl_dci_t dci_unpacked; @@ -255,11 +295,15 @@ int srslte_ue_dl_decode_rnti(srslte_ue_dl_t *q, cf_t *input, uint8_t *data, uint uint32_t sf_idx = tti%10; - if ((ret = srslte_ue_dl_decode_fft_estimate(q, input, sf_idx, &cfi)) < 0) { + if ((ret = srslte_ue_dl_decode_fft_estimate_multi(q, input, sf_idx, &cfi)) < 0) { return ret; } - if (srslte_pdcch_extract_llr(&q->pdcch, q->sf_symbols, q->ce, srslte_chest_dl_get_noise_estimate(&q->chest), sf_idx, cfi)) { + float noise_estimate = srslte_chest_dl_get_noise_estimate(&q->chest); + // Uncoment next line to do ZF by default in pdsch_ue example + //float noise_estimate = 0; + + if (srslte_pdcch_extract_llr_multi(&q->pdcch, q->sf_symbols_m, q->ce_m, noise_estimate, sf_idx, cfi)) { fprintf(stderr, "Error extracting LLRs\n"); return SRSLTE_ERROR; } @@ -294,13 +338,10 @@ int srslte_ue_dl_decode_rnti(srslte_ue_dl_t *q, cf_t *input, uint8_t *data, uint q->nof_detected++; - // Uncoment next line to do ZF by default in pdsch_ue example - //float noise_estimate = 0; - float noise_estimate = srslte_chest_dl_get_noise_estimate(&q->chest); if (q->pdsch_cfg.grant.mcs.mod > 0 && q->pdsch_cfg.grant.mcs.tbs >= 0) { - ret = srslte_pdsch_decode_rnti(&q->pdsch, &q->pdsch_cfg, &q->softbuffer, - q->sf_symbols, q->ce, + ret = srslte_pdsch_decode_multi(&q->pdsch, &q->pdsch_cfg, &q->softbuffer, + q->sf_symbols_m, q->ce_m, noise_estimate, rnti, data); @@ -353,9 +394,11 @@ static int dci_blind_search(srslte_ue_dl_t *q, dci_blind_search_t *search_space, // If searching for Format1A but found Format0 save it for later if (dci_msg->format == SRSLTE_DCI_FORMAT0 && search_space->format == SRSLTE_DCI_FORMAT1A) { - q->pending_ul_dci_rnti = crc_rem; - memcpy(&q->pending_ul_dci_msg, dci_msg, sizeof(srslte_dci_msg_t)); - memcpy(&q->last_location_ul, &search_space->loc[i], sizeof(srslte_dci_location_t)); + if (!q->pending_ul_dci_rnti) { + q->pending_ul_dci_rnti = crc_rem; + memcpy(&q->pending_ul_dci_msg, dci_msg, sizeof(srslte_dci_msg_t)); + memcpy(&q->last_location_ul, &search_space->loc[i], sizeof(srslte_dci_location_t)); + } // Else if we found it, save location and leave } else if (dci_msg->format == search_space->format) { ret = 1; @@ -376,7 +419,7 @@ static int dci_blind_search(srslte_ue_dl_t *q, dci_blind_search_t *search_space, int srslte_ue_dl_find_ul_dci(srslte_ue_dl_t *q, uint32_t cfi, uint32_t sf_idx, uint16_t rnti, srslte_dci_msg_t *dci_msg) { - if (rnti) { + if (rnti && cfi > 0 && cfi < 4) { /* Do not search if an UL DCI is already pending */ if (q->pending_ul_dci_rnti == rnti) { q->pending_ul_dci_rnti = 0; @@ -502,7 +545,14 @@ bool srslte_ue_dl_decode_phich(srslte_ue_dl_t *q, uint32_t sf_idx, uint32_t n_pr INFO("Decoding PHICH sf_idx=%d, n_prb_lowest=%d, n_dmrs=%d, n_group=%d, n_seq=%d, Ngroups=%d, Nsf=%d\n", sf_idx, n_prb_lowest, n_dmrs, ngroup, nseq, srslte_phich_ngroups(&q->phich), srslte_phich_nsf(&q->phich)); - if (!srslte_phich_decode(&q->phich, q->sf_symbols, q->ce, 0, ngroup, nseq, sf_idx, &ack_bit, &distance)) { + + cf_t *ce0[SRSLTE_MAX_PORTS]; + for (int i=0;ice_m[i][0]; + } + + + if (!srslte_phich_decode(&q->phich, q->sf_symbols_m[0], ce0, 0, ngroup, nseq, sf_idx, &ack_bit, &distance)) { INFO("Decoded PHICH %d with distance %f\n", ack_bit, distance); } else { fprintf(stderr, "Error decoding PHICH\n"); @@ -516,11 +566,11 @@ bool srslte_ue_dl_decode_phich(srslte_ue_dl_t *q, uint32_t sf_idx, uint32_t n_pr } void srslte_ue_dl_save_signal(srslte_ue_dl_t *q, srslte_softbuffer_rx_t *softbuffer, uint32_t tti, uint32_t rv_idx, uint16_t rnti, uint32_t cfi) { - srslte_vec_save_file("sf_symbols", q->sf_symbols, SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp)*sizeof(cf_t)); + srslte_vec_save_file("sf_symbols", q->sf_symbols_m, SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp)*sizeof(cf_t)); printf("%d samples\n", SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp)); - srslte_vec_save_file("ce0", q->ce[0], SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp)*sizeof(cf_t)); + srslte_vec_save_file("ce0", q->ce_m[0], SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp)*sizeof(cf_t)); if (q->cell.nof_ports > 1) { - srslte_vec_save_file("ce1", q->ce[1], SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp)*sizeof(cf_t)); + srslte_vec_save_file("ce1", q->ce_m[1], SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp)*sizeof(cf_t)); } srslte_vec_save_file("pcfich_ce0", q->pcfich.ce[0], q->pcfich.nof_symbols*sizeof(cf_t)); srslte_vec_save_file("pcfich_ce1", q->pcfich.ce[1], q->pcfich.nof_symbols*sizeof(cf_t)); @@ -543,7 +593,7 @@ void srslte_ue_dl_save_signal(srslte_ue_dl_t *q, srslte_softbuffer_rx_t *softbuf snprintf(tmpstr,64,"rmout_%d.dat",i); srslte_vec_save_file(tmpstr, softbuffer->buffer_f[i], (3*cb_len+12)*sizeof(int16_t)); } - printf("Saved files for tti=%d, sf=%d, cfi=%d, mcs=%d, rv=%d, rnti=%d\n", tti, tti%10, cfi, + printf("Saved files for tti=%d, sf=%d, cfi=%d, mcs=%d, rv=%d, rnti=0x%x\n", tti, tti%10, cfi, q->pdsch_cfg.grant.mcs.idx, rv_idx, rnti); } diff --git a/srslte/lib/ue/ue_mib.c b/lib/src/phy/ue/ue_mib.c similarity index 75% rename from srslte/lib/ue/ue_mib.c rename to lib/src/phy/ue/ue_mib.c index 5cfeaaadd..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) @@ -161,13 +161,11 @@ int srslte_ue_mib_decode(srslte_ue_mib_t * q, cf_t *input, return ret; } - - int srslte_ue_mib_sync_init(srslte_ue_mib_sync_t *q, - uint32_t cell_id, - srslte_cp_t cp, - int (recv_callback)(void*, void*, uint32_t, srslte_timestamp_t*), - void *stream_handler) + uint32_t cell_id, + srslte_cp_t cp, + int (recv_callback)(void*, void*, uint32_t, srslte_timestamp_t*), + void *stream_handler) { srslte_cell_t cell; // If the ports are set to 0, ue_mib goes through 1, 2 and 4 ports to blindly detect nof_ports @@ -176,6 +174,9 @@ int srslte_ue_mib_sync_init(srslte_ue_mib_sync_t *q, cell.cp = cp; cell.nof_prb = SRSLTE_UE_MIB_NOF_PRB; + q->sf_buffer[0] = srslte_vec_malloc(3*sizeof(cf_t)*SRSLTE_SF_LEN_PRB(cell.nof_prb)); + q->nof_rx_antennas = 1; + if (srslte_ue_mib_init(&q->ue_mib, cell)) { fprintf(stderr, "Error initiating ue_mib\n"); return SRSLTE_ERROR; @@ -189,7 +190,44 @@ int srslte_ue_mib_sync_init(srslte_ue_mib_sync_t *q, return SRSLTE_SUCCESS; } +int srslte_ue_mib_sync_init_multi(srslte_ue_mib_sync_t *q, + uint32_t cell_id, + srslte_cp_t cp, + int (recv_callback)(void*, cf_t*[SRSLTE_MAX_PORTS], uint32_t, srslte_timestamp_t*), + uint32_t nof_rx_antennas, + void *stream_handler) +{ + srslte_cell_t cell; + // If the ports are set to 0, ue_mib goes through 1, 2 and 4 ports to blindly detect nof_ports + cell.nof_ports = 0; + cell.id = cell_id; + cell.cp = cp; + cell.nof_prb = SRSLTE_UE_MIB_NOF_PRB; + + for (int i=0;isf_buffer[i] = srslte_vec_malloc(3*sizeof(cf_t)*SRSLTE_SF_LEN_PRB(cell.nof_prb)); + } + q->nof_rx_antennas = nof_rx_antennas; + + if (srslte_ue_mib_init(&q->ue_mib, cell)) { + fprintf(stderr, "Error initiating ue_mib\n"); + return SRSLTE_ERROR; + } + if (srslte_ue_sync_init_multi(&q->ue_sync, cell, recv_callback, nof_rx_antennas, stream_handler)) { + fprintf(stderr, "Error initiating ue_sync\n"); + srslte_ue_mib_free(&q->ue_mib); + return SRSLTE_ERROR; + } + srslte_ue_sync_decode_sss_on_track(&q->ue_sync, true); + return SRSLTE_SUCCESS; +} + void srslte_ue_mib_sync_free(srslte_ue_mib_sync_t *q) { + for (int i=0;inof_rx_antennas;i++) { + if (q->sf_buffer[i]) { + free(q->sf_buffer[i]); + } + } srslte_ue_mib_free(&q->ue_mib); srslte_ue_sync_free(&q->ue_sync); } @@ -207,7 +245,6 @@ int srslte_ue_mib_sync_decode(srslte_ue_mib_sync_t * q, { int ret = SRSLTE_ERROR_INVALID_INPUTS; - cf_t *sf_buffer = NULL; uint32_t nof_frames = 0; int mib_ret = SRSLTE_UE_MIB_NOTFOUND; @@ -216,13 +253,13 @@ int srslte_ue_mib_sync_decode(srslte_ue_mib_sync_t * q, ret = SRSLTE_SUCCESS; do { mib_ret = SRSLTE_UE_MIB_NOTFOUND; - ret = srslte_ue_sync_get_buffer(&q->ue_sync, &sf_buffer); + ret = srslte_ue_sync_zerocopy_multi(&q->ue_sync, q->sf_buffer); if (ret < 0) { fprintf(stderr, "Error calling srslte_ue_sync_work()\n"); break; } else if (srslte_ue_sync_get_sfidx(&q->ue_sync) == 0) { if (ret == 1) { - mib_ret = srslte_ue_mib_decode(&q->ue_mib, sf_buffer, bch_payload, nof_tx_ports, sfn_offset); + mib_ret = srslte_ue_mib_decode(&q->ue_mib, q->sf_buffer[0], bch_payload, nof_tx_ports, sfn_offset); } else { DEBUG("Resetting PBCH decoder after %d frames\n", q->ue_mib.frame_cnt); srslte_ue_mib_reset(&q->ue_mib); diff --git a/srslte/lib/ue/ue_sync.c b/lib/src/phy/ue/ue_sync.c similarity index 84% rename from srslte/lib/ue/ue_sync.c rename to lib/src/phy/ue/ue_sync.c index 6ef05daff..b5b2be3d0 100644 --- a/srslte/lib/ue/ue_sync.c +++ b/lib/src/phy/ue/ue_sync.c @@ -31,15 +31,14 @@ #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 -cf_t dummy[MAX_TIME_OFFSET]; #define TRACK_MAX_LOST 4 #define TRACK_FRAME_SIZE 32 @@ -47,7 +46,11 @@ cf_t dummy[MAX_TIME_OFFSET]; #define DEFAULT_SAMPLE_OFFSET_CORRECT_PERIOD 0 #define DEFAULT_SFO_EMA_COEFF 0.1 -cf_t dummy_offset_buffer[1024*1024]; +cf_t dummy_buffer0[15*2048/2]; +cf_t dummy_buffer1[15*2048/2]; + +// FIXME: this will break for 4 antennas!! +cf_t *dummy_offset_buffer[SRSLTE_MAX_PORTS] = {dummy_buffer0, dummy_buffer1}; int srslte_ue_sync_init_file(srslte_ue_sync_t *q, uint32_t nof_prb, char *file_name, int offset_time, float offset_freq) { int ret = SRSLTE_ERROR_INVALID_INPUTS; @@ -74,15 +77,18 @@ int srslte_ue_sync_init_file(srslte_ue_sync_t *q, uint32_t nof_prb, char *file_n goto clean_exit; } - q->input_buffer = srslte_vec_malloc(2 * q->sf_len * sizeof(cf_t)); - if (!q->input_buffer) { - perror("malloc"); - goto clean_exit; - } - 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; @@ -109,24 +115,56 @@ int srslte_ue_sync_start_agc(srslte_ue_sync_t *q, double (set_gain_callback)(voi return n; } +int recv_callback_multi_to_single(void *h, cf_t *x[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t*t) +{ + srslte_ue_sync_t *q = (srslte_ue_sync_t*) h; + return q->recv_callback_single(q->stream_single, (void*) x[0], nsamples, t); +} + int srslte_ue_sync_init(srslte_ue_sync_t *q, srslte_cell_t cell, - int (recv_callback)(void*, void*, uint32_t,srslte_timestamp_t*), + int (recv_callback)(void*, void*, uint32_t,srslte_timestamp_t*), void *stream_handler) +{ + int ret = srslte_ue_sync_init_multi(q, cell, recv_callback_multi_to_single, 1, (void*) q); + q->recv_callback_single = recv_callback; + q->stream_single = stream_handler; + return ret; +} + +int srslte_ue_sync_init_multi(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) + +{ + + 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; if (q != NULL && stream_handler != NULL && - srslte_nofprb_isvalid(cell.nof_prb) && + srslte_nofprb_isvalid(cell.nof_prb) && + nof_rx_antennas <= SRSLTE_MAX_PORTS && 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; q->cell = cell; q->fft_size = srslte_symbol_sz(q->cell.nof_prb); q->sf_len = SRSLTE_SF_LEN(q->fft_size); @@ -152,8 +190,14 @@ int srslte_ue_sync_init(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; } @@ -209,13 +253,6 @@ int srslte_ue_sync_init(srslte_ue_sync_t *q, } - /* FIXME: Go for zerocopy only and eliminate this allocation */ - q->input_buffer = srslte_vec_malloc(2*q->frame_len * sizeof(cf_t)); - if (!q->input_buffer) { - perror("malloc"); - goto clean_exit; - } - srslte_ue_sync_reset(q); ret = SRSLTE_SUCCESS; @@ -233,9 +270,6 @@ uint32_t srslte_ue_sync_sf_len(srslte_ue_sync_t *q) { } void srslte_ue_sync_free(srslte_ue_sync_t *q) { - if (q->input_buffer) { - free(q->input_buffer); - } if (q->do_agc) { srslte_agc_free(&q->agc); } @@ -309,7 +343,7 @@ void srslte_ue_sync_set_agc_period(srslte_ue_sync_t *q, uint32_t period) { q->agc_period = period; } -static int find_peak_ok(srslte_ue_sync_t *q, cf_t *input_buffer) { +static int find_peak_ok(srslte_ue_sync_t *q, cf_t *input_buffer[SRSLTE_MAX_PORTS]) { if (srslte_sync_sss_detected(&q->sfind)) { @@ -408,7 +442,7 @@ static int track_peak_ok(srslte_ue_sync_t *q, uint32_t track_idx) { discard the offseted samples to align next frame */ if (q->next_rf_sample_offset > 0 && q->next_rf_sample_offset < MAX_TIME_OFFSET) { DEBUG("Positive time offset %d samples.\n", q->next_rf_sample_offset); - if (q->recv_callback(q->stream, dummy, (uint32_t) q->next_rf_sample_offset, &q->last_timestamp) < 0) { + if (q->recv_callback(q->stream, dummy_offset_buffer, (uint32_t) q->next_rf_sample_offset, &q->last_timestamp) < 0) { fprintf(stderr, "Error receiving from USRP\n"); return SRSLTE_ERROR; } @@ -443,7 +477,7 @@ static int track_peak_no(srslte_ue_sync_t *q) { } -static int receive_samples(srslte_ue_sync_t *q, cf_t *input_buffer) { +static int receive_samples(srslte_ue_sync_t *q, cf_t *input_buffer[SRSLTE_MAX_PORTS]) { /* A negative time offset means there are samples in our buffer for the next subframe, because we are sampling too fast. @@ -453,10 +487,13 @@ static int receive_samples(srslte_ue_sync_t *q, cf_t *input_buffer) { } /* Get N subframes from the USRP getting more samples and keeping the previous samples, if any */ - if (q->recv_callback(q->stream, &input_buffer[q->next_rf_sample_offset], q->frame_len - q->next_rf_sample_offset, &q->last_timestamp) < 0) { + cf_t *ptr[SRSLTE_MAX_PORTS]; + for (int i=0;inof_rx_antennas;i++) { + ptr[i] = &input_buffer[i][q->next_rf_sample_offset]; + } + if (q->recv_callback(q->stream, ptr, q->frame_len - q->next_rf_sample_offset, &q->last_timestamp) < 0) { return SRSLTE_ERROR; } - /* reset time offset */ q->next_rf_sample_offset = 0; @@ -465,17 +502,14 @@ static int receive_samples(srslte_ue_sync_t *q, cf_t *input_buffer) { bool first_track = true; -int srslte_ue_sync_get_buffer(srslte_ue_sync_t *q, cf_t **sf_symbols) { - int ret = srslte_ue_sync_zerocopy(q, q->input_buffer); - if (sf_symbols) { - *sf_symbols = q->input_buffer; - } - return ret; - +int srslte_ue_sync_zerocopy(srslte_ue_sync_t *q, cf_t *input_buffer) { + cf_t *_input_buffer[SRSLTE_MAX_PORTS]; + _input_buffer[0] = input_buffer; + return srslte_ue_sync_zerocopy_multi(q, _input_buffer); } /* Returns 1 if the subframe is synchronized in time, 0 otherwise */ -int srslte_ue_sync_zerocopy(srslte_ue_sync_t *q, cf_t *input_buffer) { +int srslte_ue_sync_zerocopy_multi(srslte_ue_sync_t *q, cf_t *input_buffer[SRSLTE_MAX_PORTS]) { int ret = SRSLTE_ERROR_INVALID_INPUTS; uint32_t track_idx; @@ -484,7 +518,7 @@ int srslte_ue_sync_zerocopy(srslte_ue_sync_t *q, cf_t *input_buffer) { { if (q->file_mode) { - int n = srslte_filesource_read(&q->file_source, input_buffer, q->sf_len); + int n = srslte_filesource_read(&q->file_source, input_buffer[0], q->sf_len); if (n < 0) { fprintf(stderr, "Error reading input file\n"); return SRSLTE_ERROR; @@ -492,7 +526,7 @@ int srslte_ue_sync_zerocopy(srslte_ue_sync_t *q, cf_t *input_buffer) { if (n == 0) { srslte_filesource_seek(&q->file_source, 0); q->sf_idx = 9; - int n = srslte_filesource_read(&q->file_source, input_buffer, q->sf_len); + int n = srslte_filesource_read(&q->file_source, input_buffer[0], q->sf_len); if (n < 0) { fprintf(stderr, "Error reading input file\n"); return SRSLTE_ERROR; @@ -500,8 +534,8 @@ int srslte_ue_sync_zerocopy(srslte_ue_sync_t *q, cf_t *input_buffer) { } if (q->correct_cfo) { srslte_cfo_correct(&q->file_cfo_correct, - input_buffer, - input_buffer, + input_buffer[0], + input_buffer[0], q->file_cfo / 15000 / q->fft_size); } @@ -519,7 +553,7 @@ int srslte_ue_sync_zerocopy(srslte_ue_sync_t *q, cf_t *input_buffer) { switch (q->state) { case SF_FIND: - switch(srslte_sync_find(&q->sfind, input_buffer, 0, &q->peak_idx)) { + switch(srslte_sync_find(&q->sfind, input_buffer[0], 0, &q->peak_idx)) { case SRSLTE_SYNC_ERROR: ret = SRSLTE_ERROR; fprintf(stderr, "Error finding correlation peak (%d)\n", ret); @@ -539,7 +573,7 @@ int srslte_ue_sync_zerocopy(srslte_ue_sync_t *q, cf_t *input_buffer) { break; } if (q->do_agc) { - srslte_agc_process(&q->agc, input_buffer, q->sf_len); + srslte_agc_process(&q->agc, input_buffer[0], q->sf_len); } break; @@ -557,7 +591,7 @@ int srslte_ue_sync_zerocopy(srslte_ue_sync_t *q, cf_t *input_buffer) { if (q->do_agc && (q->agc_period == 0 || (q->agc_period && (q->frame_total_cnt%q->agc_period) == 0))) { - srslte_agc_process(&q->agc, input_buffer, q->sf_len); + srslte_agc_process(&q->agc, input_buffer[0], q->sf_len); } #ifdef MEASURE_EXEC_TIME @@ -570,7 +604,7 @@ int srslte_ue_sync_zerocopy(srslte_ue_sync_t *q, cf_t *input_buffer) { /* Track PSS/SSS around the expected PSS position * In tracking phase, the subframe carrying the PSS is always the last one of the frame */ - switch(srslte_sync_find(&q->strack, input_buffer, + switch(srslte_sync_find(&q->strack, input_buffer[0], q->frame_len - q->sf_len/2 - q->fft_size - q->strack.max_offset/2, &track_idx)) { @@ -607,10 +641,12 @@ int srslte_ue_sync_zerocopy(srslte_ue_sync_t *q, cf_t *input_buffer) { q->frame_total_cnt++; } if (q->correct_cfo) { - srslte_cfo_correct(&q->sfind.cfocorr, - input_buffer, - input_buffer, + for (int i=0;inof_rx_antennas;i++) { + srslte_cfo_correct(&q->sfind.cfocorr, + input_buffer[i], + input_buffer[i], -srslte_sync_get_cfo(&q->strack) / q->fft_size); + } } break; } 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 483c83820..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) @@ -269,7 +269,7 @@ int srslte_ue_ul_pucch_encode(srslte_ue_ul_t *q, srslte_uci_data_t uci_data, // Choose n_pucch uint32_t n_pucch = srslte_pucch_get_npucch(pdcch_n_cce, format, uci_data.scheduling_request, &q->pucch_sched); - if (srslte_pucch_encode(&q->pucch, format, n_pucch, sf_idx, pucch_bits, q->sf_symbols)) { + if (srslte_pucch_encode(&q->pucch, format, n_pucch, sf_idx, q->current_rnti, pucch_bits, q->sf_symbols)) { fprintf(stderr, "Error encoding TB\n"); return ret; } @@ -394,7 +394,7 @@ int srslte_ue_ul_pusch_encode_rnti_softbuffer(srslte_ue_ul_t *q, bzero(q->sf_symbols, sizeof(cf_t)*SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp)); - if (srslte_pusch_uci_encode_rnti(&q->pusch, &q->pusch_cfg, softbuffer, data, uci_data, rnti, q->sf_symbols)) { + if (srslte_pusch_encode(&q->pusch, &q->pusch_cfg, softbuffer, data, uci_data, rnti, q->sf_symbols)) { fprintf(stderr, "Error encoding TB\n"); return ret; } diff --git a/srslte/lib/utils/CMakeLists.txt b/lib/src/phy/utils/CMakeLists.txt similarity index 87% rename from srslte/lib/utils/CMakeLists.txt rename to lib/src/phy/utils/CMakeLists.txt index 46785ffb3..f8a886ed8 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 @@ -25,5 +25,4 @@ if(VOLK_FOUND) set_target_properties(srslte_utils PROPERTIES COMPILE_DEFINITIONS "${VOLK_DEFINITIONS}") endif(VOLK_FOUND) -SRSLTE_SET_PIC(srslte_utils) add_subdirectory(test) 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 660cead9c..9ef53c35a 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); - srslte_dft_run_c(&q->filter_plan, filter, q->filter_fft); + return (q->output_len-1); // divide output length by dec factor - 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); +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); - 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/phy/utils/ringbuffer.h" +#include "srslte/phy/utils/vector.h" + +int srslte_ringbuffer_init(srslte_ringbuffer_t *q, int capacity) +{ + q->buffer = srslte_vec_malloc(capacity); + if (!q->buffer) { + return -1; + } + q->capacity = capacity; + q->count = 0; + q->wpm = 0; + q->rpm = 0; + + pthread_mutex_init(&q->mutex, NULL); + pthread_cond_init(&q->cvar, NULL); + + return 0; +} + +void srslte_ringbuffer_free(srslte_ringbuffer_t *q, int capacity) +{ + if (q) { + if (q->buffer) { + free(q->buffer); + q->buffer = NULL; + } + pthread_mutex_destroy(&q->mutex); + pthread_cond_destroy(&q->cvar); + } +} + +int srslte_ringbuffer_write(srslte_ringbuffer_t *q, uint8_t *ptr, int nof_bytes) +{ + int w_bytes = nof_bytes; + pthread_mutex_lock(&q->mutex); + if (q->count + w_bytes >= q->capacity) { + w_bytes = q->capacity - q->count; + fprintf(stderr, "Buffer overrun: lost %d bytes\n", nof_bytes - w_bytes); + } + if (w_bytes > q->capacity - q->wpm) { + int x = q->capacity - q->wpm; + memcpy(&q->buffer[q->wpm], ptr, x); + memcpy(q->buffer, &ptr[x], w_bytes - x); + } else { + memcpy(&q->buffer[q->wpm], ptr, w_bytes); + } + q->wpm += w_bytes; + if (q->wpm >= q->capacity) { + q->wpm -= q->capacity; + } + q->count += w_bytes; + pthread_cond_broadcast(&q->cvar); + pthread_mutex_unlock(&q->mutex); + return w_bytes; +} + +int srslte_ringbuffer_read(srslte_ringbuffer_t *q, uint8_t *ptr, int nof_bytes) +{ + pthread_mutex_lock(&q->mutex); + while(q->count < nof_bytes) { + pthread_cond_wait(&q->cvar, &q->mutex); + } + if (nof_bytes + q->rpm > q->capacity) { + int x = q->capacity - q->rpm; + memcpy(ptr, &q->buffer[q->rpm], x); + memcpy(&ptr[x], q->buffer, nof_bytes - x); + } else { + memcpy(ptr, &q->buffer[q->rpm], nof_bytes); + } + q->rpm += nof_bytes; + if (q->rpm >= q->capacity) { + q->rpm -= q->capacity; + } + q->count -= nof_bytes; + pthread_mutex_unlock(&q->mutex); + return nof_bytes; +} + + + 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 77c674ba0..26be1b2b4 100644 --- a/srslte/lib/utils/vector.c +++ b/lib/src/phy/utils/vector.c @@ -31,14 +31,21 @@ #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; int z=0; @@ -103,13 +110,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;im) { + m=abs(x[i]); + } + } + return m; +} + void srslte_vec_max_fff(float *x, float *y, float *z, uint32_t len) { #ifdef HAVE_VOLK_MAX_VEC_FUNCTION volk_32f_x2_max_32f(z,x,y,len); @@ -747,7 +783,7 @@ void srslte_vec_max_fff(float *x, float *y, float *z, uint32_t len) { uint32_t srslte_vec_max_abs_ci(cf_t *x, uint32_t len) { #ifdef HAVE_VOLK_MAX_ABS_FUNCTION - uint32_t target=0; + uint16_t target=0; volk_32fc_index_max_16u(&target,x,len); return target; @@ -781,12 +817,12 @@ void srslte_vec_quant_fuc(float *in, uint8_t *out, float gain, float offset, flo } } -void srslte_vec_quant_suc(int16_t *in, uint8_t *out, int16_t norm, int16_t offset, int16_t clip, uint32_t len) { +void srslte_vec_quant_suc(int16_t *in, uint8_t *out, float gain, int16_t offset, int16_t clip, uint32_t len) { int i; int16_t tmp; for (i=0;i clip) diff --git a/srslte/lib/utils/vector_simd.c b/lib/src/phy/utils/vector_simd.c similarity index 53% rename from srslte/lib/utils/vector_simd.c rename to lib/src/phy/utils/vector_simd.c index 1612f2c07..38f20e6e0 100644 --- a/srslte/lib/utils/vector_simd.c +++ b/lib/src/phy/utils/vector_simd.c @@ -31,7 +31,7 @@ #include #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 @@ -58,7 +61,7 @@ int srslte_vec_dot_prod_sss_simd(short *x, short *y, uint32_t len) for(;number < points; number++){ xVal = _mm_load_si128(xPtr); - yVal = _mm_load_si128(yPtr); + 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,9 +359,42 @@ 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..725d6de60 --- /dev/null +++ b/lib/src/upper/CMakeLists.txt @@ -0,0 +1,24 @@ +# +# 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 STATIC ${SOURCES}) +target_link_libraries(srslte_upper srslte_common srslte_asn1) +install(TARGETS srslte_upper DESTINATION ${LIBRARY_DIR}) 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..b9545375a --- /dev/null +++ b/lib/src/upper/rlc_am.cc @@ -0,0 +1,1486 @@ +/** + * + * \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/pbch_capture.png b/pbch_capture.png deleted file mode 100644 index b99e011ca..000000000 Binary files a/pbch_capture.png and /dev/null differ 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..cfba64a30 --- /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 = 30000 +#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..8819c0bcb --- /dev/null +++ b/srsenb/src/mac/CMakeLists.txt @@ -0,0 +1,24 @@ +# +# 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(srsenb_mac STATIC ${SOURCES}) +install(TARGETS srsenb_mac DESTINATION ${LIBRARY_DIR}) + 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..92669ba69 --- /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(30000), + "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..5d46d3201 --- /dev/null +++ b/srsenb/src/phy/CMakeLists.txt @@ -0,0 +1,29 @@ +# +# 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(srsenb_phy STATIC ${SOURCES}) + +if(ENABLE_GUI AND SRSGUI_FOUND) + target_link_libraries(srsenb_phy ${SRSGUI_LIBRARIES}) +endif(ENABLE_GUI AND SRSGUI_FOUND) + +install(TARGETS srsenb_phy DESTINATION ${LIBRARY_DIR}) + 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..59116bab7 --- /dev/null +++ b/srsenb/src/upper/CMakeLists.txt @@ -0,0 +1,24 @@ +# +# 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(srsenb_upper STATIC ${SOURCES}) +install(TARGETS srsenb_upper DESTINATION ${LIBRARY_DIR}) + 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/CMakeLists.txt b/srslte/CMakeLists.txt deleted file mode 100644 index 0ecf9ddf6..000000000 --- a/srslte/CMakeLists.txt +++ /dev/null @@ -1,101 +0,0 @@ -# -# Copyright 2013-2015 Software Radio Systems Limited -# -# 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/. -# - -######################################################################## -# Install headers -######################################################################## -INSTALL(DIRECTORY include/ - DESTINATION "${INCLUDE_DIR}" - FILES_MATCHING PATTERN "*.h" -) - -######################################################################## -# 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}) - -######################################################################## -# Find Dependencies -######################################################################## - -find_package(MKL) -if(MKL_FOUND) - include_directories(${MKL_INCLUDE_DIRS}) - link_directories(${MKL_LIBRARY_DIRS}) -else(MKL_FOUND) - find_package(FFTW3F REQUIRED) - if(FFTW3F_FOUND) - include_directories(${FFTW3F_INCLUDE_DIRS}) - link_directories(${FFTW3F_LIBRARY_DIRS}) - endif(FFTW3F_FOUND) -endif(MKL_FOUND) - -find_package(UHD) -if(UHD_FOUND) - include_directories(${UHD_INCLUDE_DIRS}) - link_directories(${UHD_LIBRARY_DIRS}) -endif(UHD_FOUND) - -find_package(bladeRF) -if(BLADERF_FOUND) - include_directories(${BLADERF_INCLUDE_DIRS}) - link_directories(${BLADERF_LIBRARY_DIRS}) -endif(BLADERF_FOUND) - -if(BLADERF_FOUND OR UHD_FOUND) - set(RF_FOUND TRUE CACHE INTERNAL "RF frontend found") -else(BLADERF_FOUND OR UHD_FOUND) - set(RF_FOUND FALSE CACHE INTERNAL "RF frontend found") - add_definitions(-DDISABLE_RF) -endif(BLADERF_FOUND OR UHD_FOUND) - -include(CheckFunctionExistsMath) -if(${DISABLE_VOLK}) - if(${DISABLE_VOLK} EQUAL 0) - find_package(Volk) - else(${DISABLE_VOLK} EQUAL 0) - message(STATUS "VOLK library disabled (DISABLE_VOLK=1)") - endif(${DISABLE_VOLK} EQUAL 0) -else(${DISABLE_VOLK}) - find_package(Volk) -endif(${DISABLE_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) - -######################################################################## -# Add subdirectories -######################################################################## -add_subdirectory(lib) -add_subdirectory(include) -add_subdirectory(examples) diff --git a/srslte/examples/tutorial_examples/CMakeLists.txt b/srslte/examples/tutorial_examples/CMakeLists.txt deleted file mode 100644 index 04248ef9c..000000000 --- a/srslte/examples/tutorial_examples/CMakeLists.txt +++ /dev/null @@ -1,35 +0,0 @@ -# -# Copyright 2013-2015 Software Radio Systems Limited -# -# 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/. -# - - -################################################################# -# EXAMPLES shown in WinnForum 2015 Tutorial -################################################################# - -if(SRSGUI_FOUND AND UHD_FOUND) - - add_executable(pss pss.c) - target_link_libraries(pss srslte ${SRSGUI_LIBRARIES}) - - add_executable(simple_tx simple_tx.c) - target_link_libraries(simple_tx srslte) - -endif(SRSGUI_FOUND AND UHD_FOUND) - diff --git a/srslte/examples/tutorial_examples/pss.c b/srslte/examples/tutorial_examples/pss.c deleted file mode 100644 index fc2f43242..000000000 --- a/srslte/examples/tutorial_examples/pss.c +++ /dev/null @@ -1,399 +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/. - * - */ - -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "srslte/srslte.h" -#include "srslte/rf/rf.h" - - -#ifndef DISABLE_GRAPHICS -void init_plots(); -void do_plots(float *corr, float energy, uint32_t size, cf_t ce[SRSLTE_PSS_LEN]); -void do_plots_sss(float *corr_m0, float *corr_m1); -#endif - - -bool disable_plots = false; -int cell_id = -1; -char *rf_args=""; -float rf_gain=40.0, rf_freq=-1.0; -int nof_frames = -1; -uint32_t fft_size=128; -float threshold = 0.4; -int N_id_2_sync = -1; -srslte_cp_t cp=SRSLTE_CP_NORM; - -void usage(char *prog) { - printf("Usage: %s [aedgtvnp] -f rx_frequency_hz -i cell_id\n", prog); - printf("\t-a RF args [Default %s]\n", rf_args); - printf("\t-g RF Gain [Default %.2f dB]\n", rf_gain); - printf("\t-n nof_frames [Default %d]\n", nof_frames); - printf("\t-l N_id_2 to sync [Default use cell_id]\n"); - printf("\t-e Extended CP [Default Normal]\n", fft_size); - printf("\t-s symbol_sz [Default %d]\n", fft_size); - printf("\t-t threshold [Default %.2f]\n", threshold); -#ifndef DISABLE_GRAPHICS - printf("\t-d disable plots [Default enabled]\n"); -#else - printf("\t plots are disabled. Graphics library not available\n"); -#endif - printf("\t-v srslte_verbose\n"); -} - -void parse_args(int argc, char **argv) { - int opt; - while ((opt = getopt(argc, argv, "adgetvsfil")) != -1) { - switch (opt) { - case 'a': - rf_args = argv[optind]; - break; - case 'g': - rf_gain = atof(argv[optind]); - break; - case 'f': - rf_freq = atof(argv[optind]); - break; - case 't': - threshold = atof(argv[optind]); - break; - case 'e': - cp = SRSLTE_CP_EXT; - break; - case 'i': - cell_id = atoi(argv[optind]); - break; - case 'l': - N_id_2_sync = atoi(argv[optind]); - break; - case 's': - fft_size = atoi(argv[optind]); - break; - case 'n': - nof_frames = atoi(argv[optind]); - break; - case 'd': - disable_plots = true; - break; - case 'v': - srslte_verbose++; - break; - default: - usage(argv[0]); - exit(-1); - } - } - if (cell_id < 0 || rf_freq < 0) { - usage(argv[0]); - exit(-1); - } -} - float m0_value, m1_value; - -int main(int argc, char **argv) { - cf_t *buffer; - int frame_cnt, n; - srslte_rf_t rf; - srslte_pss_synch_t pss; - srslte_cfo_t cfocorr, cfocorr64; - srslte_sss_synch_t sss; - int32_t flen; - int peak_idx, last_peak; - float peak_value; - float mean_peak; - uint32_t nof_det, nof_nodet, nof_nopeak, nof_nopeakdet; - cf_t ce[SRSLTE_PSS_LEN]; - - parse_args(argc, argv); - - if (N_id_2_sync == -1) { - N_id_2_sync = cell_id%3; - } - uint32_t N_id_2 = cell_id%3; - uint32_t N_id_1 = cell_id/3; - -#ifndef DISABLE_GRAPHICS - if (!disable_plots) - init_plots(); -#endif - - flen = 4800*(fft_size/64); - - buffer = malloc(sizeof(cf_t) * flen * 2); - if (!buffer) { - perror("malloc"); - exit(-1); - } - - if (srslte_pss_synch_init_fft(&pss, flen, fft_size)) { - fprintf(stderr, "Error initiating PSS\n"); - exit(-1); - } - - if (srslte_pss_synch_set_N_id_2(&pss, N_id_2_sync)) { - fprintf(stderr, "Error setting N_id_2=%d\n",N_id_2_sync); - exit(-1); - } - - srslte_cfo_init(&cfocorr, flen); - srslte_cfo_init(&cfocorr64, flen); - - if (srslte_sss_synch_init(&sss, fft_size)) { - fprintf(stderr, "Error initializing SSS object\n"); - return SRSLTE_ERROR; - } - - srslte_sss_synch_set_N_id_2(&sss, N_id_2); - - printf("Opening RF device...\n"); - if (srslte_rf_open(&rf, rf_args)) { - fprintf(stderr, "Error opening rf\n"); - exit(-1); - } - printf("N_id_2: %d\n", N_id_2); - printf("Set RX rate: %.2f MHz\n", srslte_rf_set_rx_srate(&rf, flen*2*100) / 1000000); - printf("Set RX gain: %.1f dB\n", srslte_rf_set_rx_gain(&rf, rf_gain)); - printf("Set RX freq: %.2f MHz\n", srslte_rf_set_rx_freq(&rf, rf_freq) / 1000000); - srslte_rf_rx_wait_lo_locked(&rf); - srslte_rf_start_rx_stream(&rf); - - printf("Frame length %d samples\n", flen); - printf("PSS detection threshold: %.2f\n", threshold); - - nof_det = nof_nodet = nof_nopeak = nof_nopeakdet = 0; - frame_cnt = 0; - last_peak = 0; - mean_peak = 0; - int peak_offset = 0; - float cfo; - float mean_cfo = 0; - uint32_t m0, m1; - uint32_t sss_error1 = 0, sss_error2 = 0, sss_error3 = 0; - uint32_t cp_is_norm = 0; - - srslte_sync_t ssync; - bzero(&ssync, sizeof(srslte_sync_t)); - ssync.fft_size = fft_size; - - while(frame_cnt < nof_frames || nof_frames == -1) { - peak_offset = 0; - n = srslte_rf_recv(&rf, buffer, flen - peak_offset, 1); - if (n < 0) { - fprintf(stderr, "Error receiving samples\n"); - exit(-1); - } - - peak_idx = srslte_pss_synch_find_pss(&pss, buffer, &peak_value); - if (peak_idx < 0) { - fprintf(stderr, "Error finding PSS peak\n"); - exit(-1); - } - - mean_peak = SRSLTE_VEC_CMA(peak_value, mean_peak, frame_cnt); - - if (peak_value >= threshold) { - nof_det++; - - if (peak_idx >= fft_size) { - - // Estimate CFO - cfo = srslte_pss_synch_cfo_compute(&pss, &buffer[peak_idx-fft_size]); - mean_cfo = SRSLTE_VEC_CMA(cfo, mean_cfo, frame_cnt); - - // Correct CFO - srslte_cfo_correct(&cfocorr, buffer, buffer, -mean_cfo / fft_size); - - // Estimate channel - if (srslte_pss_synch_chest(&pss, &buffer[peak_idx-fft_size], ce)) { - fprintf(stderr, "Error computing channel estimation\n"); - exit(-1); - } - - // Find SSS - int sss_idx = peak_idx-2*fft_size-(SRSLTE_CP_ISNORM(cp)?SRSLTE_CP_LEN(fft_size, SRSLTE_CP_NORM_LEN):SRSLTE_CP_LEN(fft_size, SRSLTE_CP_EXT_LEN)); - if (sss_idx >= 0 && sss_idx < flen-fft_size) { - srslte_sss_synch_m0m1_partial(&sss, &buffer[sss_idx], 3, NULL, &m0, &m0_value, &m1, &m1_value); - if (srslte_sss_synch_N_id_1(&sss, m0, m1) != N_id_1) { - sss_error2++; - } - INFO("Partial N_id_1: %d\n", srslte_sss_synch_N_id_1(&sss, m0, m1)); - srslte_sss_synch_m0m1_diff(&sss, &buffer[sss_idx], &m0, &m0_value, &m1, &m1_value); - if (srslte_sss_synch_N_id_1(&sss, m0, m1) != N_id_1) { - sss_error3++; - } - INFO("Diff N_id_1: %d\n", srslte_sss_synch_N_id_1(&sss, m0, m1)); - srslte_sss_synch_m0m1_partial(&sss, &buffer[sss_idx], 1, NULL, &m0, &m0_value, &m1, &m1_value); - if (srslte_sss_synch_N_id_1(&sss, m0, m1) != N_id_1) { - sss_error1++; - } - INFO("Full N_id_1: %d\n", srslte_sss_synch_N_id_1(&sss, m0, m1)); - } - - // Estimate CP - if (peak_idx > 2*(fft_size + SRSLTE_CP_LEN_EXT(fft_size))) { - srslte_cp_t cp = srslte_sync_detect_cp(&ssync, buffer, peak_idx); - if (SRSLTE_CP_ISNORM(cp)) { - cp_is_norm++; - } - } - - } else { - INFO("No space for CFO computation. Frame starts at \n",peak_idx); - } - - if(srslte_sss_synch_subframe(m0,m1) == 0) - { -#ifndef DISABLE_GRAPHICS - if (!disable_plots) - do_plots_sss(sss.corr_output_m0, sss.corr_output_m1); -#endif - } - - } else { - nof_nodet++; - } - - if (frame_cnt > 100) { - if (abs(last_peak-peak_idx) > 4) { - if (peak_value >= threshold) { - nof_nopeakdet++; - } - nof_nopeak++; - } - } - - frame_cnt++; - - printf("[%5d]: Pos: %5d, PSR: %4.1f (~%4.1f) Pdet: %4.2f, " - "FA: %4.2f, CFO: %+4.1f kHz SSSmiss: %4.2f/%4.2f/%4.2f CPNorm: %.0f\%\r", - frame_cnt, - peak_idx, - peak_value, mean_peak, - (float) nof_det/frame_cnt, - (float) nof_nopeakdet/frame_cnt, mean_cfo*15, - (float) sss_error1/nof_det,(float) sss_error2/nof_det,(float) sss_error3/nof_det, - (float) cp_is_norm/nof_det * 100); - - if (SRSLTE_VERBOSE_ISINFO()) { - printf("\n"); - } - -#ifndef DISABLE_GRAPHICS - if (!disable_plots) - do_plots(pss.conv_output_avg, pss.conv_output_avg[peak_idx], pss.fft_size+pss.frame_size-1, ce); -#endif - - last_peak = peak_idx; - - } - - srslte_pss_synch_free(&pss); - free(buffer); - srslte_rf_close(&rf); - - printf("Ok\n"); - exit(0); -} - -extern cf_t *tmp2; - - -/********************************************************************** - * Plotting Functions - ***********************************************************************/ -#ifndef DISABLE_GRAPHICS - - -#include "srsgui/srsgui.h" -plot_real_t pssout; -//plot_complex_t pce; - -plot_real_t psss1;//, psss2; - -float tmp[100000]; -cf_t tmpce[SRSLTE_PSS_LEN]; - - -void init_plots() { - sdrgui_init(); - plot_real_init(&pssout); - plot_real_setTitle(&pssout, "PSS xCorr"); - plot_real_setLabels(&pssout, "Index", "Absolute value"); - plot_real_setYAxisScale(&pssout, 0, 1); - - /* - plot_complex_init(&pce); - plot_complex_setTitle(&pce, "Channel Estimates"); - plot_complex_setYAxisScale(&pce, Ip, -2, 2); - plot_complex_setYAxisScale(&pce, Q, -2, 2); - plot_complex_setYAxisScale(&pce, Magnitude, 0, 2); - plot_complex_setYAxisScale(&pce, Phase, -M_PI, M_PI); - */ - - plot_real_init(&psss1); - plot_real_setTitle(&psss1, "SSS xCorr m0"); - plot_real_setLabels(&psss1, "Index", "Absolute value"); - plot_real_setYAxisScale(&psss1, 0, 1); - - /* - plot_real_init(&psss2); - plot_real_setTitle(&psss2, "SSS xCorr m1"); - plot_real_setLabels(&psss2, "Index", "Absolute value"); - plot_real_setYAxisScale(&psss2, 0, 1); - */ - - -} - -void do_plots(float *corr, float energy, uint32_t size, cf_t ce[SRSLTE_PSS_LEN]) { - srslte_vec_sc_prod_fff(corr,1./energy,tmp, size); - plot_real_setNewData(&pssout, tmp, size); - -// float norm = srslte_vec_avg_power_cf(ce, SRSLTE_PSS_LEN); - // srslte_vec_sc_prod_cfc(ce, 1.0/sqrt(norm), tmpce, SRSLTE_PSS_LEN); - - //plot_complex_setNewData(&pce, tmpce, SRSLTE_PSS_LEN); -} - -void do_plots_sss(float *corr_m0, float *corr_m1) { - if (m0_value > 0) - srslte_vec_sc_prod_fff(corr_m0,1./m0_value,corr_m0, SRSLTE_SSS_N); - plot_real_setNewData(&psss1, corr_m0, SRSLTE_SSS_N); - -// if (m1_value > 0) -// srslte_vec_sc_prod_fff(corr_m1,1./m1_value,corr_m1, SRSLTE_SSS_N); -// plot_real_setNewData(&psss2, corr_m1, SRSLTE_SSS_N); -} - -#endif diff --git a/srslte/examples/tutorial_examples/simple_tx.c b/srslte/examples/tutorial_examples/simple_tx.c deleted file mode 100644 index c82b14748..000000000 --- a/srslte/examples/tutorial_examples/simple_tx.c +++ /dev/null @@ -1,262 +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/. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "srslte/srslte.h" - -#include "srslte/rf/rf.h" -srslte_rf_t rf; - -char *output_file_name = NULL; - -srslte_cell_t cell = { - 6, // nof_prb - 1, // nof_ports - 1, // cell_id - SRSLTE_CP_NORM, // cyclic prefix - SRSLTE_PHICH_R_1, // PHICH resources - SRSLTE_PHICH_NORM // PHICH length -}; - - -char *rf_args = ""; -float rf_amp = 0.5, rf_gain = 30.0, rf_freq = 2400000000; - -bool null_file_sink=false; -srslte_filesink_t fsink; -srslte_ofdm_t ifft; -srslte_mod_t modulation; - -uint32_t sf_n_re, sf_n_samples; - -cf_t *sf_buffer = NULL, *output_buffer = NULL; - -void usage(char *prog) { - printf("Usage: %s [algfmv]\n", prog); - printf("\t-a RF args [Default %s]\n", rf_args); - printf("\t-l RF amplitude [Default %.2f]\n", rf_amp); - printf("\t-g RF TX gain [Default %.2f dB]\n", rf_gain); - printf("\t-f RF TX frequency [Default %.1f MHz]\n", rf_freq / 1000000); - printf("\t-m modulation (1: BPSK, 2: QPSK, 3: QAM16, 4: QAM64) [Default BPSK]\n"); - printf("\t-v [set srslte_verbose to debug, default none]\n"); -} - -void parse_args(int argc, char **argv) { - int opt; - while ((opt = getopt(argc, argv, "algfmv")) != -1) { - switch (opt) { - case 'a': - rf_args = argv[optind]; - break; - case 'g': - rf_gain = atof(argv[optind]); - break; - case 'l': - rf_amp = atof(argv[optind]); - break; - case 'f': - rf_freq = atof(argv[optind]); - break; - case 'm': - switch(atoi(argv[optind])) { - case 1: - modulation = SRSLTE_MOD_BPSK; - break; - case 2: - modulation = SRSLTE_MOD_QPSK; - break; - case 4: - modulation = SRSLTE_MOD_16QAM; - break; - case 6: - modulation = SRSLTE_MOD_64QAM; - break; - default: - fprintf(stderr, "Invalid modulation %d. Possible values: " - "(1: BPSK, 2: QPSK, 3: QAM16, 4: QAM64)\n", atoi(argv[optind])); - break; - } - break; - case 'v': - srslte_verbose++; - break; - default: - usage(argv[0]); - exit(-1); - } - } -#ifdef DISABLE_RF - if (!output_file_name) { - usage(argv[0]); - exit(-1); - } -#endif -} - -void base_init() { - - /* init memory */ - sf_buffer = malloc(sizeof(cf_t) * sf_n_re); - if (!sf_buffer) { - perror("malloc"); - exit(-1); - } - output_buffer = malloc(sizeof(cf_t) * sf_n_samples); - if (!output_buffer) { - perror("malloc"); - exit(-1); - } - printf("Opening RF device...\n"); - if (srslte_rf_open(&rf, rf_args)) { - fprintf(stderr, "Error opening rf\n"); - exit(-1); - } - - /* create ifft object */ - if (srslte_ofdm_tx_init(&ifft, SRSLTE_CP_NORM, cell.nof_prb)) { - fprintf(stderr, "Error creating iFFT object\n"); - exit(-1); - } - srslte_ofdm_set_normalize(&ifft, true); -} - -void base_free() { - - srslte_ofdm_tx_free(&ifft); - - if (sf_buffer) { - free(sf_buffer); - } - if (output_buffer) { - free(output_buffer); - } - srslte_rf_close(&rf); -} - - -int main(int argc, char **argv) { - int sf_idx=0, N_id_2=0; - cf_t pss_signal[SRSLTE_PSS_LEN]; - float sss_signal0[SRSLTE_SSS_LEN]; // for subframe 0 - float sss_signal5[SRSLTE_SSS_LEN]; // for subframe 5 - int i; - -#ifdef DISABLE_RF - if (argc < 3) { - usage(argv[0]); - exit(-1); - } -#endif - - parse_args(argc, argv); - - N_id_2 = cell.id % 3; - sf_n_re = 2 * SRSLTE_CP_NORM_NSYMB * cell.nof_prb * SRSLTE_NRE; - sf_n_samples = 2 * SRSLTE_SLOT_LEN(srslte_symbol_sz(cell.nof_prb)); - - cell.phich_length = SRSLTE_PHICH_NORM; - cell.phich_resources = SRSLTE_PHICH_R_1; - - /* this *must* be called after setting slot_len_* */ - base_init(); - - /* Generate PSS/SSS signals */ - srslte_pss_generate(pss_signal, N_id_2); - srslte_sss_generate(sss_signal0, sss_signal5, cell.id); - - printf("Set TX rate: %.2f MHz\n", - srslte_rf_set_tx_srate(&rf, srslte_sampling_freq_hz(cell.nof_prb)) / 1000000); - printf("Set TX gain: %.1f dB\n", srslte_rf_set_tx_gain(&rf, rf_gain)); - printf("Set TX freq: %.2f MHz\n", - srslte_rf_set_tx_freq(&rf, rf_freq) / 1000000); - - uint32_t nbits; - - srslte_modem_table_t modulator; - srslte_modem_table_init(&modulator); - srslte_modem_table_lte(&modulator, modulation); - - srslte_tcod_t turbocoder; - srslte_tcod_init(&turbocoder, SRSLTE_TCOD_MAX_LEN_CB); - - srslte_dft_precoding_t dft_precod; - srslte_dft_precoding_init(&dft_precod, 12); - - nbits = srslte_cbsegm_cbindex(sf_n_samples/8/srslte_mod_bits_x_symbol(modulation)/3 - 12); - uint32_t ncoded_bits = sf_n_samples/8/srslte_mod_bits_x_symbol(modulation); - - uint8_t *data = malloc(sizeof(uint8_t)*nbits); - uint8_t *data_enc = malloc(sizeof(uint8_t)*ncoded_bits); - cf_t *symbols = malloc(sizeof(cf_t)*sf_n_samples); - - bzero(data_enc, sizeof(uint8_t)*ncoded_bits); - while (1) { - for (sf_idx = 0; sf_idx < SRSLTE_NSUBFRAMES_X_FRAME; sf_idx++) { - bzero(sf_buffer, sizeof(cf_t) * sf_n_re); - -#ifdef kk - if (sf_idx == 0 || sf_idx == 5) { - srslte_pss_put_slot(pss_signal, sf_buffer, cell.nof_prb, SRSLTE_CP_NORM); - srslte_sss_put_slot(sf_idx ? sss_signal5 : sss_signal0, sf_buffer, cell.nof_prb, - SRSLTE_CP_NORM); - /* Transform to OFDM symbols */ - srslte_ofdm_tx_sf(&ifft, sf_buffer, output_buffer); - - float norm_factor = (float) sqrtf(cell.nof_prb)/15; - srslte_vec_sc_prod_cfc(output_buffer, rf_amp*norm_factor, output_buffer, SRSLTE_SF_LEN_PRB(cell.nof_prb)); - - } else { -#endif - /* Generate random data */ - for (i=0;i -#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/include/srslte/utils/vector_simd.h b/srslte/include/srslte/utils/vector_simd.h deleted file mode 100644 index cd6eb4d28..000000000 --- a/srslte/include/srslte/utils/vector_simd.h +++ /dev/null @@ -1,56 +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 VECTORSIMD_ -#define VECTORSIMD_ - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include -#include "srslte/config.h" - -SRSLTE_API int srslte_vec_dot_prod_sss_simd(short *x, short *y, uint32_t len); - -SRSLTE_API void srslte_vec_sum_sss_simd(short *x, short *y, short *z, uint32_t len); - -SRSLTE_API void srslte_vec_sub_sss_simd(short *x, short *y, short *z, uint32_t len); - -SRSLTE_API void srslte_vec_prod_sss_simd(short *x, short *y, short *z, uint32_t len); - -SRSLTE_API void srslte_vec_sc_div2_sss_simd(short *x, int n_rightshift, short *z, uint32_t len); - -SRSLTE_API void srslte_vec_lut_sss_simd(short *x, unsigned short *lut, short *y, uint32_t len); - -SRSLTE_API void srslte_vec_convert_fi_simd(float *x, int16_t *z, float scale, uint32_t len); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/srslte/lib/mimo/precoding.c b/srslte/lib/mimo/precoding.c deleted file mode 100644 index 6a6dab7ff..000000000 --- a/srslte/lib/mimo/precoding.c +++ /dev/null @@ -1,468 +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/. - * - */ - -#include -#include -#include -#include -#include - -#include "srslte/common/phy_common.h" -#include "srslte/mimo/precoding.h" -#include "srslte/utils/vector.h" - -#ifdef LV_HAVE_SSE -#include -#include -int srslte_predecoding_single_sse(cf_t *y, cf_t *h, cf_t *x, int nof_symbols, float noise_estimate); -int srslte_predecoding_diversity2_sse(cf_t *y, cf_t *h[SRSLTE_MAX_PORTS], cf_t *x[SRSLTE_MAX_LAYERS], int nof_symbols); -#endif - -#ifdef LV_HAVE_AVX -#include -int srslte_predecoding_single_avx(cf_t *y, cf_t *h, cf_t *x, int nof_symbols, float noise_estimate); -#endif - - - -/************************************************ - * - * RECEIVER SIDE FUNCTIONS - * - **************************************************/ - -#ifdef LV_HAVE_SSE - -#define PROD(a,b) _mm_addsub_ps(_mm_mul_ps(a,_mm_moveldup_ps(b)),_mm_mul_ps(_mm_shuffle_ps(a,a,0xB1),_mm_movehdup_ps(b))) - -int srslte_predecoding_single_sse(cf_t *y, cf_t *h, cf_t *x, int nof_symbols, float noise_estimate) { - - float *xPtr = (float*) x; - const float *hPtr = (const float*) h; - const float *yPtr = (const float*) y; - - __m128 conjugator = _mm_setr_ps(0, -0.f, 0, -0.f); - - __m128 noise = _mm_set1_ps(noise_estimate); - __m128 h1Val, h2Val, y1Val, y2Val, h12square, h1square, h2square, h1conj, h2conj, x1Val, x2Val; - for (int i=0;i 0) { - h12square = _mm_add_ps(h12square, noise); - } - - h1square = _mm_shuffle_ps(h12square, h12square, _MM_SHUFFLE(1, 1, 0, 0)); - h2square = _mm_shuffle_ps(h12square, h12square, _MM_SHUFFLE(3, 3, 2, 2)); - - /* Conjugate channel */ - h1conj = _mm_xor_ps(h1Val, conjugator); - h2conj = _mm_xor_ps(h2Val, conjugator); - - /* Complex product */ - x1Val = PROD(y1Val, h1conj); - x2Val = PROD(y2Val, h2conj); - - x1Val = _mm_div_ps(x1Val, h1square); - x2Val = _mm_div_ps(x2Val, h2square); - - _mm_store_ps(xPtr, x1Val); xPtr+=4; - _mm_store_ps(xPtr, x2Val); xPtr+=4; - } - for (int i=8*(nof_symbols/8);i 0) { - h12square = _mm256_add_ps(h12square, noise); - } - h1_p = _mm256_permute_ps(h12square, _MM_SHUFFLE(1, 1, 0, 0)); - h2_p = _mm256_permute_ps(h12square, _MM_SHUFFLE(3, 3, 2, 2)); - h1square = _mm256_permute2f128_ps(h1_p, h2_p, 2<<4); - h2square = _mm256_permute2f128_ps(h1_p, h2_p, 3<<4 | 1); - - /* Conjugate channel */ - h1conj = _mm256_xor_ps(h1Val, conjugator); - h2conj = _mm256_xor_ps(h2Val, conjugator); - - /* Complex product */ - x1Val = PROD_AVX(y1Val, h1conj); - x2Val = PROD_AVX(y2Val, h2conj); - - x1Val = _mm256_div_ps(x1Val, h1square); - x2Val = _mm256_div_ps(x2Val, h2square); - - _mm256_store_ps(xPtr, x1Val); xPtr+=8; - _mm256_store_ps(xPtr, x2Val); xPtr+=8; - } - for (int i=16*(nof_symbols/16);i 32) { - return srslte_predecoding_single_avx(y, h, x, nof_symbols, noise_estimate); - } else { - return srslte_predecoding_single_gen(y, h, x, nof_symbols, noise_estimate); - } -#else - #ifdef LV_HAVE_SSE - if (nof_symbols > 32) { - return srslte_predecoding_single_sse(y, h, x, nof_symbols, noise_estimate); - } else { - return srslte_predecoding_single_gen(y, h, x, nof_symbols, noise_estimate); - } - #else - return srslte_predecoding_single_gen(y, h, x, nof_symbols, noise_estimate); - #endif -#endif -} - -/* C implementatino of the SFBC equalizer */ -int srslte_predecoding_diversity_gen_(cf_t *y, cf_t *h[SRSLTE_MAX_PORTS], cf_t *x[SRSLTE_MAX_LAYERS], - int nof_ports, int nof_symbols, int symbol_start) -{ - int i; - if (nof_ports == 2) { - cf_t h00, h01, h10, h11, r0, r1; - float hh; - - for (i = symbol_start/2; i < nof_symbols / 2; i++) { - h00 = h[0][2 * i]; - h01 = h[0][2 * i+1]; - h10 = h[1][2 * i]; - h11 = h[1][2 * i+1]; - hh = crealf(h00) * crealf(h00) + cimagf(h00) * cimagf(h00) - + crealf(h11) * crealf(h11) + cimagf(h11) * cimagf(h11); - r0 = y[2 * i]; - r1 = y[2 * i + 1]; - if (hh == 0) { - hh = 1e-4; - } - x[0][i] = (conjf(h00) * r0 + h11 * conjf(r1)) / hh * sqrt(2); - x[1][i] = (-h10 * conj(r0) + conj(h01) * r1) / hh * sqrt(2); - } - return i; - } else if (nof_ports == 4) { - cf_t h0, h1, h2, h3, r0, r1, r2, r3; - float hh02, hh13; - - int m_ap = (nof_symbols % 4) ? ((nof_symbols - 2) / 4) : nof_symbols / 4; - for (i = symbol_start; i < m_ap; i++) { - h0 = h[0][4 * i]; - h1 = h[1][4 * i + 2]; - h2 = h[2][4 * i]; - h3 = h[3][4 * i + 2]; - hh02 = crealf(h0) * crealf(h0) + cimagf(h0) * cimagf(h0) - + crealf(h2) * crealf(h2) + cimagf(h2) * cimagf(h2); - hh13 = crealf(h1) * crealf(h1) + cimagf(h1) * cimagf(h1) - + crealf(h3) * crealf(h3) + cimagf(h3) * cimagf(h3); - r0 = y[4 * i]; - r1 = y[4 * i + 1]; - r2 = y[4 * i + 2]; - r3 = y[4 * i + 3]; - - x[0][i] = (conjf(h0) * r0 + h2 * conjf(r1)) / hh02 * sqrt(2); - x[1][i] = (-h2 * conjf(r0) + conjf(h0) * r1) / hh02 * sqrt(2); - x[2][i] = (conjf(h1) * r2 + h3 * conjf(r3)) / hh13 * sqrt(2); - x[3][i] = (-h3 * conjf(r2) + conjf(h1) * r3) / hh13 * sqrt(2); - - } - return i; - } else { - fprintf(stderr, "Number of ports must be 2 or 4 for transmit diversity (nof_ports=%d)\n", nof_ports); - return -1; - } -} - -int srslte_predecoding_diversity_gen(cf_t *y, cf_t *h[SRSLTE_MAX_PORTS], cf_t *x[SRSLTE_MAX_LAYERS], - int nof_ports, int nof_symbols) { - return srslte_predecoding_diversity_gen_(y, h, x, nof_ports, nof_symbols, 0); -} - -/* SSE implementation of the 2-port SFBC equalizer */ -#ifdef LV_HAVE_SSE -int srslte_predecoding_diversity2_sse(cf_t *y, cf_t *h[SRSLTE_MAX_PORTS], cf_t *x[SRSLTE_MAX_LAYERS], int nof_symbols) -{ - float *x0Ptr = (float*) x[0]; - float *x1Ptr = (float*) x[1]; - const float *h0Ptr = (const float*) h[0]; - const float *h1Ptr = (const float*) h[1]; - const float *yPtr = (const float*) y; - - __m128 conjugator = _mm_setr_ps(0, -0.f, 0, -0.f); - __m128 sqrt2 = _mm_setr_ps(sqrt(2), sqrt(2), sqrt(2), sqrt(2)); - - __m128 h0Val_0, h0Val_1, h1Val_0, h1Val_1, h00, h00conj, h01, h01conj, h10, h11, hh, hhshuf, hhsum, hhadd; - __m128 r0Val, r1Val, r0, r1, r0conj, r1conj; - __m128 x0, x1; - - for (int i=0;i 32 && nof_ports == 2) { - return srslte_predecoding_diversity2_sse(y, h, x, nof_symbols); - } else { - return srslte_predecoding_diversity_gen(y, h, x, nof_ports, nof_symbols); - } -#else - return srslte_predecoding_diversity_gen(y, h, x, nof_ports, nof_symbols); -#endif -} - -/* 36.211 v10.3.0 Section 6.3.4 */ -int srslte_predecoding_type(cf_t *y, cf_t *h[SRSLTE_MAX_PORTS], cf_t *x[SRSLTE_MAX_LAYERS], - int nof_ports, int nof_layers, int nof_symbols, srslte_mimo_type_t type, float noise_estimate) { - - if (nof_ports > SRSLTE_MAX_PORTS) { - fprintf(stderr, "Maximum number of ports is %d (nof_ports=%d)\n", SRSLTE_MAX_PORTS, - nof_ports); - return -1; - } - if (nof_layers > SRSLTE_MAX_LAYERS) { - fprintf(stderr, "Maximum number of layers is %d (nof_layers=%d)\n", - SRSLTE_MAX_LAYERS, nof_layers); - return -1; - } - - switch (type) { - case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA: - if (nof_ports == 1 && nof_layers == 1) { - return srslte_predecoding_single(y, h[0], x[0], nof_symbols, noise_estimate); - } else { - fprintf(stderr, - "Number of ports and layers must be 1 for transmission on single antenna ports\n"); - return -1; - } - break; - case SRSLTE_MIMO_TYPE_TX_DIVERSITY: - if (nof_ports == nof_layers) { - return srslte_predecoding_diversity(y, h, x, nof_ports, nof_symbols); - } else { - fprintf(stderr, - "Error number of layers must equal number of ports in transmit diversity\n"); - return -1; - } - break; - case SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX: - fprintf(stderr, "Spatial multiplexing not supported\n"); - return -1; - } - return 0; -} - - - - - - -/************************************************ - * - * TRANSMITTER SIDE FUNCTIONS - * - **************************************************/ - -int srslte_precoding_single(cf_t *x, cf_t *y, int nof_symbols) { - memcpy(y, x, nof_symbols * sizeof(cf_t)); - return nof_symbols; -} -int srslte_precoding_diversity(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PORTS], int nof_ports, - int nof_symbols) { - int i; - if (nof_ports == 2) { - for (i = 0; i < nof_symbols; i++) { - y[0][2 * i] = x[0][i]; - y[1][2 * i] = -conjf(x[1][i]); - y[0][2 * i + 1] = x[1][i]; - y[1][2 * i + 1] = conjf(x[0][i]); - } - // normalize - srslte_vec_sc_prod_cfc(y[0], 1.0/sqrtf(2), y[0], 2*nof_symbols); - srslte_vec_sc_prod_cfc(y[1], 1.0/sqrtf(2), y[1], 2*nof_symbols); - return 2 * i; - } else if (nof_ports == 4) { - //int m_ap = (nof_symbols%4)?(nof_symbols*4-2):nof_symbols*4; - int m_ap = 4 * nof_symbols; - for (i = 0; i < m_ap / 4; i++) { - y[0][4 * i] = x[0][i] / sqrtf(2); - y[1][4 * i] = 0; - y[2][4 * i] = -conjf(x[1][i]) / sqrtf(2); - y[3][4 * i] = 0; - - y[0][4 * i + 1] = x[1][i] / sqrtf(2); - y[1][4 * i + 1] = 0; - y[2][4 * i + 1] = conjf(x[0][i]) / sqrtf(2); - y[3][4 * i + 1] = 0; - - y[0][4 * i + 2] = 0; - y[1][4 * i + 2] = x[2][i] / sqrtf(2); - y[2][4 * i + 2] = 0; - y[3][4 * i + 2] = -conjf(x[3][i]) / sqrtf(2); - - y[0][4 * i + 3] = 0; - y[1][4 * i + 3] = x[3][i] / sqrtf(2); - y[2][4 * i + 3] = 0; - y[3][4 * i + 3] = conjf(x[2][i]) / sqrtf(2); - } - return 4 * i; - } else { - fprintf(stderr, "Number of ports must be 2 or 4 for transmit diversity (nof_ports=%d)\n", nof_ports); - return -1; - } -} - -/* 36.211 v10.3.0 Section 6.3.4 */ -int srslte_precoding_type(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PORTS], int nof_layers, - int nof_ports, int nof_symbols, srslte_mimo_type_t type) { - - if (nof_ports > SRSLTE_MAX_PORTS) { - fprintf(stderr, "Maximum number of ports is %d (nof_ports=%d)\n", SRSLTE_MAX_PORTS, - nof_ports); - return -1; - } - if (nof_layers > SRSLTE_MAX_LAYERS) { - fprintf(stderr, "Maximum number of layers is %d (nof_layers=%d)\n", - SRSLTE_MAX_LAYERS, nof_layers); - return -1; - } - - switch (type) { - case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA: - if (nof_ports == 1 && nof_layers == 1) { - return srslte_precoding_single(x[0], y[0], nof_symbols); - } else { - fprintf(stderr, - "Number of ports and layers must be 1 for transmission on single antenna ports\n"); - return -1; - } - break; - case SRSLTE_MIMO_TYPE_TX_DIVERSITY: - if (nof_ports == nof_layers) { - return srslte_precoding_diversity(x, y, nof_ports, nof_symbols); - } else { - fprintf(stderr, - "Error number of layers must equal number of ports in transmit diversity\n"); - return -1; - } - case SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX: - fprintf(stderr, "Spatial multiplexing not supported\n"); - return -1; - } - return 0; -} - diff --git a/srslte/lib/mimo/test/diversitydecode_mex.c b/srslte/lib/mimo/test/diversitydecode_mex.c deleted file mode 100644 index bbc99416d..000000000 --- a/srslte/lib/mimo/test/diversitydecode_mex.c +++ /dev/null @@ -1,116 +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/. - * - */ - -#include -#include "srslte/srslte.h" -#include "srslte/mex/mexutils.h" - -/** MEX function to be called from MATLAB to test the predecoder - */ - -#define INPUT prhs[0] -#define HEST prhs[1] -#define NOF_INPUTS 2 - - -void help() -{ - mexErrMsgTxt - ("[output] = srslte_predecoder(input, hest, nest)\n\n"); -} - -/* the gateway function */ -void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) -{ - cf_t *input = NULL; - cf_t *hest = NULL; - cf_t *output = NULL; - uint32_t nof_symbols = 0; - - if (nrhs < NOF_INPUTS) { - help(); - return; - } - - // Read input symbols - nof_symbols = mexutils_read_cf(INPUT, &input); - if (nof_symbols < 0) { - mexErrMsgTxt("Error reading input\n"); - return; - } - // Read channel estimates - uint32_t nof_symbols2 = mexutils_read_cf(HEST, &hest); - if (nof_symbols < 0) { - mexErrMsgTxt("Error reading hest\n"); - return; - } - if ((nof_symbols2 % nof_symbols) != 0) { - mexErrMsgTxt("Hest size must be multiple of input size\n"); - return; - } - // Calculate number of ports - uint32_t nof_ports = nof_symbols2/nof_symbols; - - cf_t *x[8]; - cf_t *h[4]; - - /* Allocate memory */ - output = srslte_vec_malloc(sizeof(cf_t)*nof_symbols); - int i; - for (i = 0; i < nof_ports; i++) { - x[i] = srslte_vec_malloc(sizeof(cf_t)*nof_symbols); - h[i] = &hest[i*nof_symbols]; - } - for (;i<8;i++) { - x[i] = NULL; - } - for (i=nof_ports;i<4;i++) { - h[i] = NULL; - } - - srslte_predecoding_diversity(input, h, x, nof_ports, nof_symbols); - srslte_layerdemap_diversity(x, output, nof_ports, nof_symbols / nof_ports); - - - if (nlhs >= 1) { - mexutils_write_cf(output, &plhs[0], nof_symbols, 1); - } - - if (input) { - free(input); - } - if (output) { - free(output); - } - for (i=0;i<8;i++) { - if (x[i]) { - free(x[i]); - } - } - - return; -} - 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..fb5783b4d --- /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 STATIC ${SOURCES}) +install(TARGETS srsue_mac DESTINATION ${LIBRARY_DIR}) 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..d3e4dee7d --- /dev/null +++ b/srsue/src/phy/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/. +# + +file(GLOB SOURCES "*.cc") +add_library(srsue_phy STATIC ${SOURCES}) + +if(ENABLE_GUI AND SRSGUI_FOUND) + target_link_libraries(srsue_phy ${SRSGUI_LIBRARIES}) +endif(ENABLE_GUI AND SRSGUI_FOUND) + +install(TARGETS srsue_phy DESTINATION ${LIBRARY_DIR}) 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..43e6acf4c --- /dev/null +++ b/srsue/src/upper/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_upper STATIC ${SOURCES}) +install(TARGETS srsue_upper DESTINATION ${LIBRARY_DIR}) 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