Compare commits

...

14 Commits

Author SHA1 Message Date
Vadim Yanitskiy 53cc75fbef srsue/extnas: implement handling of RRCTL parameters 2020-07-27 00:33:03 +07:00
Vadim Yanitskiy e2d5c2c21d srsue/extnas: implement forwarding of paging messages 2020-07-27 00:33:03 +07:00
Vadim Yanitskiy cf09156b5a srsue/extnas: implement RRCTL codec and message handling
RRCTL is a simple protocol (inspired by Osmocom's L1CTL) that allows
an external NAS entity to control the RRC layer of srsUE. The most
notable primitives are PLMN search, selection, and PDU transfer.

The protocol assumes traditional master-slave communication, where
one side (an external NAS entity) initiates various processes,
while the other (srsUE) executes them and indicates the outcome.

Each RRCTL message starts with a header that can be defined as follows:

  +-------------------------------+--------------------------+
  | Message type                  | 6 bits                   |
  +-------------------------------+--------------------------+
  | Message sub-type              | 2 bits                   |
  +-------------------------------+--------------------------+
  | Spare (RFU)                   | 8 bits                   |
  +-------------------------------+--------------------------+
  | Payload length                | 2 octets (big endian)    |
  +-------------------------------+--------------------------+
  | Payload (optional)            | (see payload length)     |
  +-------------------------------+--------------------------+

The following message types are defined at the moment:

  - RRCTL_RESET - reset internal state of the external NAS interface
                  (does nothing for now, may be useful in the future);

  - RRCTL_PLMN_SEARCH - initiates PLMN (carrier) search on pre-configured
                        EARFCN (Absolute Radio Freqency Number);

  - RRCTL_PLMN_SELECT - binds the UE to one of the previously detected
                        carriers (see RRCTL_PLMN_SEARCH) defined by a
                        given pair of MCC and MNC;

  - RRCTL_CONN_ESTABLISH - establishes connection to the serving cell
                           (previously selected using RRCTL_PLMN_SELECT)
                           with a given cause and NAS PDU;

  - RRCTL_CONN_RELEASE - releases previously established dedicated connection
                         (currently does nothing because the RRC layer does
                          not expose any API for that);

  - RRCTL_DATA - encapsulates a received (Downlink) or to be transmitted
                 (Uplink) NAS PDU (the former also contains LCID).

Each message type has at least two of the following sub-types:

  - RRCTL_REQ - request (usually comes from an external NAS entity),
                used to initiate some process (e.g. PLMN search);

  - RRCTL_IND - indication that something has happened without a prior
                request (for example, a Downlink NAS PDU was received);

  - RRCTL_CNF - confirmation (positive conslusion) of the requested task;

  - RRCTL_ERR - negative conslusion of the requested task (error).

The protocol definition (enums ans structs) and codec functions are
defined in a separate namespaces: 'rrctl::proto' and 'rrctl::codec'
respectively. The codec functions may throw exceptions of type
'rrctl::codec::error' if something goes wrong.
2020-07-27 00:33:03 +07:00
Vadim Yanitskiy 0ce48f9730 srsue/extnas: add a possibility to enable the external NAS interface
The new configuration section '[extnas]' allows to disable the
built-in NAS implementation, and provide the interface (UNIX
domain socket) to an external entity. The interface itself will
be implemented in the follow up commits.
2020-07-27 00:33:03 +07:00
Vadim Yanitskiy e383967de2 srsue/extnas: implement a simple UNIX domain socket server
Unfortunately, the existing networking API (common/network_utils.h)
lacks the UNIX domain socket support, and it turned to be easier
to implement a simple, single client server using Boost.Asio.

The server runs in its own thread with a blocking Tx queue, and
calls a user definted callback on receipt of any data from client.
Multiple client connections are not supported and will be rejected.
2020-07-27 00:33:03 +07:00
Vadim Yanitskiy 57e04b0ab9 srsue/extnas: introduce draft implementation of 'nas_ext' class
This commit introduces a skeleton class (child of 'nas_base') for
the upcoming implementation of an external NAS interface, as well
as the implementation-specific configuration container.
2020-07-27 00:33:00 +07:00
Vadim Yanitskiy 567455d857 srsue/extnas: derive abstract 'nas_base' class from 'nas'
This is the first step towards the goal of having an external NAS
interface.  The new 'nas_base' class becomes a parent of 'nas',
combining all interfaces and the basic (common) API.

The 'ue_stack_lte' now holds a unique_ptr of type 'srsue::nas_base',
so the underlying NAS implementation (built-in or external) can
be choosen at run-time depending on configuration.

The implementation specific configuration now needs to be passed
to the constructor instead, not to the init() method as was before.
2020-07-26 23:30:42 +07:00
Vadim Yanitskiy e40dea91d2 srslte/common: constify the argument of byte_buffer_t::append_bytes()
This function does not modify the input buffer. Let's make it
possible to pass 'const uint8_t *' pointers without loosing
the const qualifier and making GCC unhappy.
2020-07-26 23:16:43 +07:00
Vadim Yanitskiy 048150872d srslte/interfaces: mark to_number() of struct plmn_id_t as const
This function does not modify any fields of the structure. Without
the 'const' qualifier it's impossible to call to_number() through
a const pointer of type 'struct plmn_id_t'.
2020-07-26 23:16:39 +07:00
Vadim Yanitskiy af527838f6 fix multiple symbol definitions detected by GCC 10 2020-07-26 23:15:59 +07:00
Vadim Yanitskiy beadf63686 fix GCC 10 error: 'abort' is not a member of 'std' 2020-07-26 23:15:56 +07:00
Vadim Yanitskiy 16b05433c3 fix GCC 10 error: 'uintXX_t' does not name a type 2020-07-26 23:15:23 +07:00
Vadim Yanitskiy cca2305eef fix GCC 10 error: 'stderr' was not declared in this scope 2020-07-26 23:15:21 +07:00
Vadim Yanitskiy c6f0c0c7ae CMakeLists.txt: GCC 10: temporarily disable -Wall 2020-07-26 23:15:17 +07:00
31 changed files with 1280 additions and 66 deletions

View File

@ -12,7 +12,7 @@ jobs:
- name: Build srsLTE on x86 Ubuntu 18.04
run: |
sudo apt update
sudo apt install -y build-essential cmake libfftw3-dev libmbedtls-dev libpcsclite-dev libboost-program-options-dev libconfig++-dev libsctp-dev colordiff ninja-build valgrind
sudo apt install -y build-essential cmake libfftw3-dev libmbedtls-dev libpcsclite-dev libboost-program-options-dev libasio-dev libconfig++-dev libsctp-dev colordiff ninja-build valgrind
mkdir build && cd build && cmake -DRF_FOUND=True -GNinja .. && ninja && ctest -T memcheck
x86_ubuntu16_build:
name: Build and test on x86 Ubuntu 16.04
@ -25,7 +25,7 @@ jobs:
- name: Build srsLTE on x86 Ubuntu 16.04
run: |
sudo apt update
sudo apt install -y build-essential cmake libfftw3-dev libmbedtls-dev libpcsclite-dev libboost-program-options-dev libconfig++-dev libsctp-dev colordiff ninja-build valgrind
sudo apt install -y build-essential cmake libfftw3-dev libmbedtls-dev libpcsclite-dev libboost-program-options-dev libasio-dev libconfig++-dev libsctp-dev colordiff ninja-build valgrind
mkdir build && cd build && cmake -DRF_FOUND=True -GNinja .. && ninja && ctest -T memcheck
aarch64_ubuntu18_build:
@ -44,5 +44,5 @@ jobs:
run: |
export CTEST_PARALLEL_LEVEL=$(nproc --all)
apt update
apt install -y build-essential cmake libfftw3-dev libmbedtls-dev libpcsclite-dev libboost-program-options-dev libconfig++-dev libsctp-dev ninja-build
ls -l && pwd && mkdir build && cd build && cmake -DRF_FOUND=True -GNinja .. && ninja
apt install -y build-essential cmake libfftw3-dev libmbedtls-dev libpcsclite-dev libboost-program-options-dev libasio-dev libconfig++-dev libsctp-dev ninja-build
ls -l && pwd && mkdir build && cd build && cmake -DRF_FOUND=True -GNinja .. && ninja

View File

@ -8,6 +8,7 @@ extraction:
- libmbedtls-dev
- libpcsclite-dev
- libboost-program-options-dev
- libasio-dev
- libconfig++-dev
- libsctp-dev
- libuhd-dev

View File

@ -3,7 +3,7 @@ sudo: required
before_script:
- sudo apt-get -qq update
- sudo apt-get install -qq build-essential cmake libfftw3-dev libmbedtls-dev libpcsclite-dev libboost-program-options-dev libconfig++-dev libsctp-dev libczmq-dev libpcsclite-dev rapidjson-dev colordiff ninja-build clang-format-8
- sudo apt-get install -qq build-essential cmake libfftw3-dev libmbedtls-dev libpcsclite-dev libboost-program-options-dev libasio-dev libconfig++-dev libsctp-dev libczmq-dev libpcsclite-dev rapidjson-dev colordiff ninja-build clang-format-8
language: cpp
@ -28,4 +28,4 @@ script:
- cmake -DENABLE_5GNR=True -DENABLE_TTCN3=True -DRF_FOUND=True -G Ninja ..
- ninja
- ninja test
- sudo ninja install
- sudo ninja install

View File

@ -235,6 +235,7 @@ endif(BUILD_STATIC)
set(BOOST_REQUIRED_COMPONENTS
program_options
system
)
if(UNIX AND EXISTS "/usr/lib64")
list(APPEND BOOST_LIBRARYDIR "/usr/lib64") #fedora 64-bit fix
@ -324,7 +325,7 @@ macro(ADD_C_COMPILER_FLAG_IF_AVAILABLE flag have)
endmacro(ADD_C_COMPILER_FLAG_IF_AVAILABLE)
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-comment -Wno-reorder -Wno-unused-variable -Wtype-limits -std=c++11")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-comment -Wno-reorder -Wno-unused-variable -Wtype-limits -std=c++11")
ADD_C_COMPILER_FLAG_IF_AVAILABLE("-Wno-unused-but-set-variable" HAVE_WNO_UNUSED_BUT_SET_VARIABLE)
ADD_CXX_COMPILER_FLAG_IF_AVAILABLE("-Wno-unused-but-set-variable" HAVE_WNO_UNUSED_BUT_SET_VARIABLE)
@ -358,7 +359,7 @@ endif(CMAKE_CXX_COMPILER_ID MATCHES "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES "Clan
ADD_C_COMPILER_FLAG_IF_AVAILABLE("-Werror=incompatible-pointer-types" HAVE_ERROR_INCOMPATIBLE)
if(CMAKE_C_COMPILER_ID MATCHES "GNU" OR CMAKE_C_COMPILER_ID MATCHES "Clang")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wno-comment -Wno-write-strings -Winline -Wno-unused-result -Wformat -Wmissing-field-initializers -Wtype-limits -std=c99 -D_GNU_SOURCE")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-comment -Wno-write-strings -Winline -Wno-unused-result -Wformat -Wmissing-field-initializers -Wtype-limits -std=c99 -D_GNU_SOURCE")
if(${CMAKE_BUILD_TYPE} STREQUAL "Debug")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ggdb -O0 -DDEBUG_MODE -DBUILD_TYPE_DEBUG")

View File

@ -114,7 +114,7 @@ Build Instructions
For example, on Ubuntu 17.04, one can install the required libraries with:
```
sudo apt-get install cmake libfftw3-dev libmbedtls-dev libboost-program-options-dev libconfig++-dev libsctp-dev
sudo apt-get install cmake libfftw3-dev libmbedtls-dev libboost-program-options-dev libasio-dev libconfig++-dev libsctp-dev
```
or on Fedora:
```

View File

@ -1,7 +1,7 @@
SET(CPACK_PACKAGE_DESCRIPTION "srsLTE")
SET(CPACK_PACKAGE_DESCRIPTION_SUMMARY "LTE library for SDR.")
SET(CPACK_PACKAGE_NAME "srslte")
SET(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6 (>= 2.3.6), libgcc1 (>= 1:4.1), libboost-dev (>= 1.35)")
SET(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6 (>= 2.3.6), libgcc1 (>= 1:4.1), libboost-dev (>= 1.35) libasio-dev")
SET(CPACK_PACKAGE_CONTACT "Ismael Gomez ")
SET(CPACK_PACKAGE_VENDOR "Software Radio Systems Limited")
@ -45,12 +45,12 @@ ENDIF()
########################################################################
# Setup CPack Debian
########################################################################
SET(CPACK_DEBIAN_PACKAGE_DEPENDS "libboost-dev")
SET(CPACK_DEBIAN_PACKAGE_DEPENDS "libboost-dev libasio-dev")
########################################################################
# Setup CPack RPM
########################################################################
SET(CPACK_RPM_PACKAGE_REQUIRES "boost-devel")
SET(CPACK_RPM_PACKAGE_REQUIRES "boost-devel libasio-dev")
########################################################################
# Setup CPack NSIS

1
debian/control vendored
View File

@ -10,6 +10,7 @@ Build-Depends:
libfftw3-dev,
libmbedtls-dev,
libboost-program-options-dev,
libasio-dev,
libconfig++-dev,
libsctp-dev,
libuhd-dev,

View File

@ -171,7 +171,7 @@ public:
#endif
}
void append_bytes(uint8_t* buf, uint32_t size)
void append_bytes(const uint8_t* buf, uint32_t size)
{
memcpy(&msg[N_bytes], buf, size);
N_bytes += size;

View File

@ -22,7 +22,11 @@
#ifndef SRSLTE_MOVE_CALLBACK_H
#define SRSLTE_MOVE_CALLBACK_H
#include <cstdio>
#include <cstddef>
#include <cstdint>
#include <cstdlib>
#include <functional>
#include <type_traits>

View File

@ -66,7 +66,7 @@ struct plmn_id_t {
}
return SRSLTE_SUCCESS;
}
std::pair<uint16_t, uint16_t> to_number()
std::pair<uint16_t, uint16_t> to_number() const
{
uint16_t mcc_num, mnc_num;
srslte::bytes_to_mcc(&mcc[0], &mcc_num);
@ -87,6 +87,34 @@ struct plmn_id_t {
uint8_t* plmn_ptr = (uint8_t*)&s1ap_plmn;
memcpy(&plmn_bytes[0], plmn_ptr + 1, 3);
}
void to_rrctl_bytes(uint8_t *mcc_buf, uint8_t *mnc_buf) const
{
mcc_buf[0] = ((mcc[1] & 0x0f) << 4) | (mcc[0] & 0x0f);
mcc_buf[1] = (0x0f << 4) | (mcc[2] & 0x0f);
mnc_buf[0] = ((mnc[1] & 0x0f) << 4) | (mnc[0] & 0x0f);
if (nof_mnc_digits > 2)
mnc_buf[1] = (0x0f << 4) | (mnc[2] & 0x0f);
else
mnc_buf[1] = 0xff;
}
void from_rrctl_bytes(const uint8_t *mcc_buf, const uint8_t *mnc_buf)
{
mcc[0] = mcc_buf[0] & 0x0f;
mcc[1] = mcc_buf[0] >> 4;
mcc[2] = mcc_buf[1] & 0x0f;
mnc[0] = mnc_buf[0] & 0x0f;
mnc[1] = mnc_buf[0] >> 4;
if (mnc_buf[1] != 0xff) {
nof_mnc_digits = 3;
mnc[2] = mnc_buf[1] & 0x0f;
} else {
nof_mnc_digits = 2;
mnc[2] = 0x00;
}
}
int from_string(const std::string& plmn_str)
{
if (plmn_str.size() < 5 or plmn_str.size() > 6) {

View File

@ -39,7 +39,7 @@ static union branchtab27 {
__m256i v;
} Branchtab37_sse2[3];
int firstGo;
static int firstGo;
/* State info for instance of Viterbi decoder */
struct v37 {
metric_t metrics1; /* path metric buffer 1 */

View File

@ -34,7 +34,7 @@ typedef union {
__m64 v[1];
} decision_t;
union branchtab27 {
static union branchtab27 {
// unsigned char c[32];
//__m128i v[2];
@ -43,7 +43,7 @@ union branchtab27 {
} Branchtab37_sse2[3];
int firstGo;
static int firstGo;
/* State info for instance of Viterbi decoder */
struct v37 {
metric_t metrics1; /* path metric buffer 1 */

View File

@ -73,7 +73,7 @@ typedef struct {
uint32_t num_stream_curruption;
} rf_soapy_handler_t;
cf_t zero_mem[64 * 1024];
static cf_t zero_mem[64 * 1024];
static void log_overflow(rf_soapy_handler_t* h)
{

View File

@ -48,6 +48,7 @@ typedef struct {
std::string nas_level;
std::string usim_level;
std::string stack_level;
std::string extif_level;
int mac_hex_limit;
int rlc_hex_limit;
@ -57,6 +58,7 @@ typedef struct {
int nas_hex_limit;
int usim_hex_limit;
int stack_hex_limit;
int extif_hex_limit;
} stack_log_args_t;
typedef struct {
@ -66,6 +68,7 @@ typedef struct {
usim_args_t usim;
rrc_args_t rrc;
std::string ue_category_str;
nas_ext_args_t nas_ext;
nas_args_t nas;
gw_args_t gw;
bool have_tti_time_stats;

View File

@ -37,6 +37,7 @@
#include "srslte/upper/pdcp.h"
#include "srslte/upper/rlc.h"
#include "upper/nas.h"
#include "upper/nas_ext.h"
#include "upper/usim.h"
#include "srslte/common/buffer_pool.h"
@ -159,6 +160,7 @@ private:
srslte::log_ref usim_log{"USIM"};
srslte::log_ref nas_log{"NAS"};
srslte::log_ref pool_log{"POOL"};
srslte::log_ref extif_log{"EXTIF"};
// RAT-specific interfaces
phy_interface_stack_lte* phy = nullptr;
@ -182,8 +184,10 @@ private:
srslte::rlc rlc;
srslte::pdcp pdcp;
srsue::rrc rrc;
srsue::nas nas;
std::unique_ptr<usim_base> usim;
// NAS implementation (built-in or external)
std::unique_ptr<srsue::nas_base> nas;
};
} // namespace srsue

View File

@ -37,15 +37,43 @@ using srslte::byte_buffer_t;
namespace srsue {
class nas : public nas_interface_rrc, public nas_interface_ue, public srslte::timer_callback
class nas_base : public nas_interface_rrc, public nas_interface_ue, public srslte::timer_callback
{
public:
explicit nas(srslte::task_handler_interface* task_handler_);
virtual ~nas() = default;
void init(usim_interface_nas* usim_, rrc_interface_nas* rrc_, gw_interface_nas* gw_, const nas_args_t& args_);
void stop();
explicit nas_base(srslte::task_handler_interface* task_handler_, const char *log_name_);
virtual ~nas_base() = default;
virtual void init(usim_interface_nas* usim_, rrc_interface_nas* rrc_, gw_interface_nas* gw_) = 0;
virtual void get_metrics(nas_metrics_t* m) = 0;
virtual void stop() = 0;
void start_pcap(srslte::nas_pcap* pcap_);
void run_tti();
protected:
srslte::byte_buffer_pool* pool = nullptr;
rrc_interface_nas* rrc = nullptr;
usim_interface_nas* usim = nullptr;
gw_interface_nas* gw = nullptr;
// Task handler
srslte::task_handler_interface* task_handler = nullptr;
srslte::proc_manager_list_t callbacks;
// Logging reference
srslte::log_ref nas_log;
// PCAP
srslte::nas_pcap* pcap = nullptr;
};
class nas : public nas_base
{
public:
nas(srslte::task_handler_interface* task_handler_, const nas_args_t& cfg_);
void init(usim_interface_nas* usim_, rrc_interface_nas* rrc_, gw_interface_nas* gw_);
void stop();
void get_metrics(nas_metrics_t* m);
emm_state_t get_state();
@ -71,17 +99,8 @@ public:
// timer callback
void timer_expired(uint32_t timeout_id) override;
// PCAP
void start_pcap(srslte::nas_pcap* pcap_);
private:
srslte::byte_buffer_pool* pool = nullptr;
srslte::log_ref nas_log;
rrc_interface_nas* rrc = nullptr;
usim_interface_nas* usim = nullptr;
gw_interface_nas* gw = nullptr;
nas_args_t cfg = {};
nas_args_t cfg = { };
emm_state_t state = EMM_STATE_DEREGISTERED;
@ -134,7 +153,6 @@ private:
uint8_t transaction_id = 0;
// timers
srslte::task_handler_interface* task_handler = nullptr;
srslte::timer_handler::unique_timer t3402; // started when attach attempt counter reached 5
srslte::timer_handler::unique_timer t3410; // started when attach request is sent, on expiry, start t3411
srslte::timer_handler::unique_timer t3411; // started when attach failed
@ -330,7 +348,6 @@ private:
nas* nas_ptr;
enum class state_t { plmn_search, rrc_connect } state = state_t::plmn_search;
};
srslte::proc_manager_list_t callbacks;
srslte::proc_t<plmn_search_proc> plmn_searcher;
srslte::proc_t<rrc_connect_proc> rrc_connector;

View File

@ -44,6 +44,15 @@ public:
nas_sim_args_t sim;
};
class nas_ext_args_t
{
public:
nas_ext_args_t() : enable(false) {}
bool enable;
std::string sock_path;
};
// EMM states (3GPP 24.302 v10.0.0)
typedef enum {
EMM_STATE_NULL = 0,

View File

@ -0,0 +1,99 @@
/*
* Copyright 2020 Software Radio Systems Limited
* Author: Vadim Yanitskiy <axilirator@gmail.com>
* Sponsored by Positive Technologies
*
* This file is part of srsLTE.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#ifndef SRSUE_NAS_EXT_H
#define SRSUE_NAS_EXT_H
#include "srslte/common/buffer_pool.h"
#include "srslte/common/common.h"
#include "srslte/common/log.h"
#include "srslte/common/nas_pcap.h"
#include "srslte/common/security.h"
#include "srslte/common/stack_procedure.h"
#include "srslte/interfaces/ue_interfaces.h"
#include "srsue/hdr/stack/upper/nas.h"
#include "srsue/hdr/stack/upper/nas_common.h"
#include "srsue/hdr/stack/upper/nas_ext.h"
#include "srsue/hdr/stack/upper/nas_extif.h"
#include "srsue/hdr/stack/upper/nas_metrics.h"
#include "srsue/hdr/stack/upper/rrctl.h"
using srslte::byte_buffer_t;
namespace srsue {
class nas_ext : public nas_base
{
public:
nas_ext(srslte::task_handler_interface* task_handler_, const nas_ext_args_t& cfg_) :
nas_base::nas_base(task_handler_, "NAS"), cfg(cfg_){};
void init(usim_interface_nas* usim_, rrc_interface_nas* rrc_, gw_interface_nas* gw_);
void get_metrics(nas_metrics_t* m);
void stop();
// RRC interface
void left_rrc_connected();
bool paging(srslte::s_tmsi_t* ue_identity);
void set_barring(srslte::barring_t barring);
void write_pdu(uint32_t lcid, srslte::unique_byte_buffer_t pdu);
uint32_t get_k_enb_count();
bool is_attached();
bool get_k_asme(uint8_t* k_asme_, uint32_t n);
uint32_t get_ipv4_addr();
bool get_ipv6_addr(uint8_t* ipv6_addr);
void plmn_search_completed(const rrc_interface_nas::found_plmn_t found_plmns[rrc_interface_nas::MAX_FOUND_PLMNS],
int nof_plmns) final;
bool connection_request_completed(bool outcome) final;
// UE interface
void start_attach_proc(srslte::proc_state_t* result, srslte::establishment_cause_t cause_) final;
bool detach_request(const bool switch_off) final;
// timer callback
void timer_expired(uint32_t timeout_id);
private:
nas_ext_args_t cfg = {};
// Interface to an external NAS entity
std::unique_ptr<nas_extif_base> iface;
// RRCTL message handlers
void handle_rrctl_reset(rrctl::proto::msg_disc disc, const uint8_t* msg, size_t len);
void handle_rrctl_plmn_search(rrctl::proto::msg_disc disc, const uint8_t* msg, size_t len);
void handle_rrctl_plmn_select(rrctl::proto::msg_disc disc, const uint8_t* msg, size_t len);
void handle_rrctl_conn_establish(rrctl::proto::msg_disc disc, const uint8_t* msg, size_t len);
void handle_rrctl_conn_release(rrctl::proto::msg_disc disc, const uint8_t* msg, size_t len);
void handle_rrctl_data(rrctl::proto::msg_disc disc, const uint8_t* msg, size_t len);
void handle_rrctl_param(rrctl::proto::msg_disc disc, const uint8_t* msg, size_t len);
void rrctl_send_confirm(rrctl::proto::msg_type type);
void rrctl_send_error(rrctl::proto::msg_type type);
};
} // namespace srsue
#endif // SRSUE_NAS_EXT_H

View File

@ -0,0 +1,64 @@
/*
* Copyright 2020 Software Radio Systems Limited
* Author: Vadim Yanitskiy <axilirator@gmail.com>
* Sponsored by Positive Technologies
*
* This file is part of srsLTE.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#ifndef SRSUE_NAS_EXTIF_H
#define SRSUE_NAS_EXTIF_H
#include "srslte/common/common.h"
#include "srslte/common/log.h"
#include "srslte/common/logmap.h"
#include "srslte/common/threads.h"
using srslte::byte_buffer_t;
namespace srsue {
// Abstract class for an external interface
class nas_extif_base : public srslte::thread
{
public:
using recv_cb_t = std::function<void(const srslte::byte_buffer_t&)>;
nas_extif_base(recv_cb_t recv_cb_) :
recv_cb(std::move(recv_cb_)),
srslte::thread("EXTIF"),
if_log{"EXTIF"}
{ /* empty constructor */ };
// Interface for nas_ext
virtual void close(void) = 0;
virtual int write(const srslte::byte_buffer_t& pdu) = 0;
protected:
static const int IFACE_THREAD_PRIO = 65;
virtual void run_thread() = 0;
virtual void stop() = 0;
bool running = false;
recv_cb_t recv_cb;
srslte::log_ref if_log;
};
} // namespace srsue
#endif // SRSUE_NAS_EXTIF_H

View File

@ -0,0 +1,67 @@
/*
* Copyright 2020 Software Radio Systems Limited
* Author: Vadim Yanitskiy <axilirator@gmail.com>
* Sponsored by Positive Technologies
*
* This file is part of srsLTE.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#ifndef SRSUE_NAS_EXTIF_UNIX_H
#define SRSUE_NAS_EXTIF_UNIX_H
#include <boost/asio.hpp>
#include "srslte/common/block_queue.h"
#include "srslte/common/common.h"
#include "srslte/common/log.h"
#include "srsue/hdr/stack/upper/nas_extif.h"
namespace srsue {
// UNIX domain socket server
class nas_extif_unix : public nas_extif_base
{
public:
nas_extif_unix(recv_cb_t cb_, const std::string& sock_path_);
void close(void) override;
int write(const srslte::byte_buffer_t& pdu) override;
protected:
void run_thread(void) override;
void stop(void) override;
private:
std::unique_ptr<boost::asio::local::stream_protocol::acceptor> acc;
std::unique_ptr<boost::asio::local::stream_protocol::socket> sock;
boost::asio::io_context io_ctx;
std::string sock_path;
srslte::block_queue<srslte::byte_buffer_t> tx_queue;
bool has_connection;
uint8_t buf[1024];
void handle_write(void);
void handle_read(void);
void accept_conn(void);
};
} // namespace srsue
#endif // SRSUE_NAS_EXTIF_UNIX_H

View File

@ -0,0 +1,162 @@
/*
* Copyright 2020 Software Radio Systems Limited
* Author: Vadim Yanitskiy <axilirator@gmail.com>
* Sponsored by Positive Technologies
*
* This file is part of srsLTE.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#include <stdint.h>
#include <asm/byteorder.h>
#include "srslte/common/common.h"
#include "srslte/interfaces/ue_interfaces.h"
namespace rrctl {
namespace proto {
enum msg_type {
RRCTL_RESET = 0x00,
RRCTL_DATA,
RRCTL_PLMN_SEARCH,
RRCTL_PLMN_SELECT,
RRCTL_CONN_ESTABLISH,
RRCTL_CONN_RELEASE,
RRCTL_PAGING,
RRCTL_PARAM,
};
enum msg_disc {
RRCTL_REQ = 0x00,
RRCTL_IND = 0x01,
RRCTL_CNF = 0x02,
RRCTL_ERR = 0x03,
};
struct msg_hdr {
#if defined(__LITTLE_ENDIAN_BITFIELD)
uint8_t disc:2, type:6;
#elif defined(__BIG_ENDIAN_BITFIELD)
uint8_t type:6, disc:2;
#else
#error "Please fix <asm/byteorder.h>"
#endif
uint8_t rfu; // Reserved
uint16_t len;
uint8_t data[0];
} __attribute__((packed));
struct msg_plmn_search_res {
uint8_t nof_plmns;
struct plmn {
uint8_t mcc[2];
uint8_t mnc[2];
uint16_t tac;
} plmns[16];
} __attribute__((packed));
struct msg_plmn_select_req {
uint8_t mcc[2];
uint8_t mnc[2];
} __attribute__((packed));
struct msg_conn_establish_req {
uint8_t cause;
uint8_t pdu[0];
} __attribute__((packed));
struct msg_data {
uint32_t lcid;
uint8_t pdu[0];
} __attribute__((packed));
struct __mmec_m_tmsi {
uint8_t mmec;
uint32_t m_tmsi;
} __attribute__((packed));
struct msg_paging_ind {
struct __mmec_m_tmsi ueid;
} __attribute__((packed));
enum msg_param_type {
RRCTL_PARAM_UEID = 0x00,
};
struct msg_param_req {
uint8_t type;
uint8_t len;
union {
struct __mmec_m_tmsi ueid;
} u;
} __attribute__((packed));
struct msg {
struct msg_hdr hdr;
union {
struct msg_data data;
struct msg_param_req param_req;
struct msg_paging_ind paging_ind;
struct msg_plmn_search_res plmn_search_res;
struct msg_plmn_select_req plmn_select_req;
struct msg_conn_establish_req conn_establish_req;
} u;
} __attribute__((packed));
std::string msg_hdr_desc(proto::msg_type type, proto::msg_disc disc, uint16_t len = 0);
} // namespace proto
namespace codec {
class error : public std::runtime_error {
public:
explicit error(const std::string& msg) : std::runtime_error(msg) {};
};
void enc_hdr(srslte::byte_buffer_t& buf,
proto::msg_type type,
proto::msg_disc disc,
uint16_t len = 0);
const uint8_t* dec_hdr(const srslte::byte_buffer_t& buf,
proto::msg_type& type,
proto::msg_disc& disc,
uint16_t& len);
void enc_plmn_search_res(srslte::byte_buffer_t& buf,
const srsue::rrc_interface_nas::found_plmn_t* plmns,
size_t nof_plmns);
void dec_plmn_select_req(std::pair<uint16_t, uint16_t>& mcc_mnc,
const uint8_t* payload, size_t len);
void dec_conn_establish_req(srslte::establishment_cause_t& cause,
const uint8_t*& pdu, size_t& pdu_len,
const uint8_t* payload, size_t len);
void enc_data_ind(srslte::byte_buffer_t& buf,
const uint8_t *pdu, size_t pdu_len,
uint32_t lcid);
void enc_paging_ind(srslte::byte_buffer_t& buf,
srslte::s_tmsi_t* ue_identity);
} // namespace codec
} // namespace rrctl

View File

@ -125,6 +125,9 @@ static int parse_args(all_args_t* args, int argc, char* argv[])
("nas.eia", bpo::value<string>(&args->stack.nas.eia)->default_value("1,2,3"), "List of integrity algorithms included in UE capabilities")
("nas.eea", bpo::value<string>(&args->stack.nas.eea)->default_value("0,1,2,3"), "List of ciphering algorithms included in UE capabilities")
("extnas.enable", bpo::value<bool>(&args->stack.nas_ext.enable)->default_value(false), "Disable the built-in NAS implementation, provide external interface")
("extnas.sock_path", bpo::value<string>(&args->stack.nas_ext.sock_path)->default_value("/tmp/ue_extnas.sock"), "UNIX socket path of the external interface")
("pcap.enable", bpo::value<bool>(&args->stack.pcap.enable)->default_value(false), "Enable MAC packet captures for wireshark")
("pcap.filename", bpo::value<string>(&args->stack.pcap.filename)->default_value("ue.pcap"), "MAC layer capture filename")
("pcap.nas_enable", bpo::value<bool>(&args->stack.pcap.nas_enable)->default_value(false), "Enable NAS packet captures for wireshark")
@ -152,6 +155,8 @@ static int parse_args(all_args_t* args, int argc, char* argv[])
("log.usim_hex_limit", bpo::value<int>(&args->stack.log.usim_hex_limit), "USIM log hex dump limit")
("log.stack_level", bpo::value<string>(&args->stack.log.stack_level), "Stack log level")
("log.stack_hex_limit", bpo::value<int>(&args->stack.log.stack_hex_limit), "Stack log hex dump limit")
("log.extif_level", bpo::value<string>(&args->stack.log.extif_level), "External interface log level")
("log.extif_hex_limit", bpo::value<int>(&args->stack.log.extif_hex_limit), "External interface log hex dump limit")
("log.all_level", bpo::value<string>(&args->log.all_level)->default_value("info"), "ALL log level")
("log.all_hex_limit", bpo::value<int>(&args->log.all_hex_limit)->default_value(32), "ALL log hex dump limit")
@ -513,6 +518,9 @@ static int parse_args(all_args_t* args, int argc, char* argv[])
if (!vm.count("log.stack_level")) {
args->stack.log.stack_level = args->log.all_level;
}
if (!vm.count("log.extif_level")) {
args->stack.log.extif_level = args->log.all_level;
}
}
// Apply all_hex_limit to any unset layers
@ -544,6 +552,9 @@ static int parse_args(all_args_t* args, int argc, char* argv[])
if (!vm.count("log.stack_hex_limit")) {
args->stack.log.stack_hex_limit = args->log.all_hex_limit;
}
if (!vm.count("log.extif_hex_limit")) {
args->stack.log.extif_hex_limit = args->log.all_hex_limit;
}
}
return SRSLTE_SUCCESS;

View File

@ -41,7 +41,6 @@ ue_stack_lte::ue_stack_lte() :
mac("MAC "),
rrc(this),
pdcp(this, "PDCP"),
nas(this),
thread("STACK"),
pending_tasks(512),
background_tasks(2),
@ -106,6 +105,18 @@ int ue_stack_lte::init(const stack_args_t& args_, srslte::logger* logger_)
usim_log->set_hex_limit(args.log.usim_hex_limit);
nas_log->set_level(args.log.nas_level);
nas_log->set_hex_limit(args.log.nas_hex_limit);
extif_log->set_level(args.log.extif_level);
extif_log->set_hex_limit(args.log.extif_hex_limit);
// Should we use the built-in NAS implementation
// or provide an external interface (RRCTL)?
if (args.nas_ext.enable) {
std::unique_ptr<srsue::nas_ext> nas_impl(new srsue::nas_ext(this, args.nas_ext));
nas = std::move(nas_impl);
} else {
std::unique_ptr<srsue::nas> nas_impl(new srsue::nas(this, args.nas));
nas = std::move(nas_impl);
}
// Set up pcap
if (args.pcap.enable) {
@ -114,7 +125,7 @@ int ue_stack_lte::init(const stack_args_t& args_, srslte::logger* logger_)
}
if (args.pcap.nas_enable) {
nas_pcap.open(args.pcap.nas_filename.c_str());
nas.start_pcap(&nas_pcap);
nas->start_pcap(&nas_pcap);
}
// Init USIM first to allow early exit in case reader couldn't be found
@ -127,8 +138,8 @@ int ue_stack_lte::init(const stack_args_t& args_, srslte::logger* logger_)
mac.init(phy, &rlc, &rrc, this);
rlc.init(&pdcp, &rrc, &timers, 0 /* RB_ID_SRB0 */);
pdcp.init(&rlc, &rrc, gw);
nas.init(usim.get(), &rrc, gw, args.nas);
rrc.init(phy, &mac, &rlc, &pdcp, &nas, usim.get(), gw, args.rrc);
nas->init(usim.get(), &rrc, gw);
rrc.init(phy, &mac, &rlc, &pdcp, nas.get(), usim.get(), gw, args.rrc);
running = true;
start(STACK_MAIN_THREAD_PRIO);
@ -149,7 +160,7 @@ void ue_stack_lte::stop_impl()
running = false;
usim->stop();
nas.stop();
nas->stop();
rrc.stop();
rlc.stop();
@ -168,7 +179,7 @@ bool ue_stack_lte::switch_on()
{
if (running) {
pending_tasks.try_push(ue_queue_id,
[this]() { nas.start_attach_proc(nullptr, srslte::establishment_cause_t::mo_sig); });
[this]() { nas->start_attach_proc(nullptr, srslte::establishment_cause_t::mo_sig); });
return true;
}
return false;
@ -177,7 +188,7 @@ bool ue_stack_lte::switch_on()
bool ue_stack_lte::switch_off()
{
// generate detach request with switch-off flag
nas.detach_request(true);
nas->detach_request(true);
// wait for max. 5s for it to be sent (according to TS 24.301 Sec 25.5.2.2)
const uint32_t RB_ID_SRB1 = 1;
@ -206,7 +217,7 @@ bool ue_stack_lte::disable_data()
{
// generate detach request
stack_log->console("Turning on airplane mode.\n");
return nas.detach_request(false);
return nas->detach_request(false);
}
bool ue_stack_lte::get_metrics(stack_metrics_t* metrics)
@ -216,7 +227,7 @@ bool ue_stack_lte::get_metrics(stack_metrics_t* metrics)
stack_metrics_t metrics{};
mac.get_metrics(metrics.mac);
rlc.get_metrics(metrics.rlc);
nas.get_metrics(&metrics.nas);
nas->get_metrics(&metrics.nas);
rrc.get_metrics(metrics.rrc);
pending_stack_metrics.push(metrics);
});
@ -302,7 +313,7 @@ void ue_stack_lte::run_tti_impl(uint32_t tti, uint32_t tti_jump)
timers.step_all();
}
rrc.run_tti();
nas.run_tti();
nas->run_tti();
if (args.have_tti_time_stats) {
std::chrono::nanoseconds dur = tti_tprof.stop();

View File

@ -18,7 +18,7 @@
# and at http://www.gnu.org/licenses/.
#
set(SOURCES gw.cc nas.cc usim_base.cc usim.cc tft_packet_filter.cc)
set(SOURCES gw.cc nas.cc nas_ext.cc nas_extif.cc rrctl.cc usim_base.cc usim.cc tft_packet_filter.cc)
if(HAVE_PCSC)
list(APPEND SOURCES "pcsc_usim.cc")

View File

@ -234,21 +234,27 @@ proc_outcome_t nas::rrc_connect_proc::react(nas::rrc_connect_proc::connection_re
* NAS
********************************************************************/
nas::nas(srslte::task_handler_interface* task_handler_) :
nas_base::nas_base(srslte::task_handler_interface* task_handler_, const char *log_name_) :
pool(byte_buffer_pool::get_instance()),
task_handler(task_handler_),
nas_log{log_name_}
{
}
nas::nas(srslte::task_handler_interface* task_handler_, const nas_args_t& cfg_) :
nas_base::nas_base(task_handler_, "NAS"),
plmn_searcher(this),
rrc_connector(this),
task_handler(task_handler_),
t3402(task_handler_->get_unique_timer()),
t3410(task_handler_->get_unique_timer()),
t3411(task_handler_->get_unique_timer()),
t3421(task_handler_->get_unique_timer()),
reattach_timer(task_handler_->get_unique_timer()),
nas_log{"NAS"}
cfg(cfg_)
{
}
void nas::init(usim_interface_nas* usim_, rrc_interface_nas* rrc_, gw_interface_nas* gw_, const nas_args_t& cfg_)
void nas::init(usim_interface_nas* usim_, rrc_interface_nas* rrc_, gw_interface_nas* gw_)
{
usim = usim_;
rrc = rrc_;
@ -261,7 +267,7 @@ void nas::init(usim_interface_nas* usim_, rrc_interface_nas* rrc_, gw_interface_
}
// parse and sanity check EIA list
std::vector<uint8_t> cap_list = split_string(cfg_.eia);
std::vector<uint8_t> cap_list = split_string(cfg.eia);
if (cap_list.empty()) {
nas_log->error("Empty EIA list. Select at least one EIA algorithm.\n");
}
@ -274,7 +280,7 @@ void nas::init(usim_interface_nas* usim_, rrc_interface_nas* rrc_, gw_interface_
}
// parse and sanity check EEA list
cap_list = split_string(cfg_.eea);
cap_list = split_string(cfg.eea);
if (cap_list.empty()) {
nas_log->error("Empty EEA list. Select at least one EEA algorithm.\n");
}
@ -286,8 +292,6 @@ void nas::init(usim_interface_nas* usim_, rrc_interface_nas* rrc_, gw_interface_
}
}
cfg = cfg_;
if ((read_ctxt_file(&ctxt))) {
usim->generate_nas_keys(ctxt.k_asme, k_nas_enc, k_nas_int, ctxt.cipher_algo, ctxt.integ_algo);
nas_log->debug_hex(k_nas_enc, 32, "NAS encryption key - k_nas_enc");
@ -325,7 +329,7 @@ emm_state_t nas::get_state()
return state;
}
void nas::run_tti()
void nas_base::run_tti()
{
callbacks.run();
}
@ -755,7 +759,7 @@ bool nas::get_ipv6_addr(uint8_t* ipv6_addr)
PCAP
*******************************************************************************/
void nas::start_pcap(srslte::nas_pcap* pcap_)
void nas_base::start_pcap(srslte::nas_pcap* pcap_)
{
pcap = pcap_;
}

View File

@ -0,0 +1,342 @@
/*
* Copyright 2020 Software Radio Systems Limited
* Author: Vadim Yanitskiy <axilirator@gmail.com>
* Sponsored by Positive Technologies
*
* This file is part of srsLTE.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#include "srslte/common/buffer_pool.h"
#include "srslte/common/common.h"
#include "srslte/common/log.h"
#include "srslte/common/nas_pcap.h"
#include "srslte/common/security.h"
#include "srslte/common/stack_procedure.h"
#include "srslte/interfaces/ue_interfaces.h"
#include "srsue/hdr/stack/upper/nas.h"
#include "srsue/hdr/stack/upper/nas_common.h"
#include "srsue/hdr/stack/upper/nas_ext.h"
#include "srsue/hdr/stack/upper/nas_extif_unix.h"
#include "srsue/hdr/stack/upper/nas_metrics.h"
using namespace srslte;
namespace srsue {
void nas_ext::init(usim_interface_nas* usim_, rrc_interface_nas* rrc_, gw_interface_nas* gw_)
{
usim = usim_;
rrc = rrc_;
gw = gw_;
// RRCTL PDU handler
auto rrctl_rx_cb = [this](const srslte::byte_buffer_t& pdu) {
rrctl::proto::msg_type type;
rrctl::proto::msg_disc disc;
const uint8_t* payload;
std::string desc;
uint16_t length;
// Parse the message header
try {
payload = rrctl::codec::dec_hdr(pdu, type, disc, length);
desc = rrctl::proto::msg_hdr_desc(type, disc, length);
nas_log->info("Got RRCTL message: %s\n", desc.c_str());
} catch (const rrctl::codec::error& e) {
nas_log->warning("Got malformed RRCTL message: %s\n", e.what());
return;
}
// Call the corresponding handler
switch (type) {
case rrctl::proto::RRCTL_RESET:
handle_rrctl_reset(disc, payload, length);
break;
case rrctl::proto::RRCTL_PLMN_SEARCH:
handle_rrctl_plmn_search(disc, payload, length);
break;
case rrctl::proto::RRCTL_PLMN_SELECT:
handle_rrctl_plmn_select(disc, payload, length);
break;
case rrctl::proto::RRCTL_CONN_ESTABLISH:
handle_rrctl_conn_establish(disc, payload, length);
break;
case rrctl::proto::RRCTL_DATA:
handle_rrctl_data(disc, payload, length);
break;
case rrctl::proto::RRCTL_PARAM:
handle_rrctl_param(disc, payload, length);
break;
case rrctl::proto::RRCTL_CONN_RELEASE:
default:
nas_log->warning("%s is not handled\n", desc.c_str());
}
};
std::unique_ptr<nas_extif_unix> iface_(new nas_extif_unix(rrctl_rx_cb, cfg.sock_path));
iface = std::move(iface_);
}
void nas_ext::rrctl_send_confirm(rrctl::proto::msg_type type)
{
srslte::byte_buffer_t pdu;
rrctl::codec::enc_hdr(pdu, type, rrctl::proto::RRCTL_CNF);
iface->write(pdu);
}
void nas_ext::rrctl_send_error(rrctl::proto::msg_type type)
{
srslte::byte_buffer_t pdu;
rrctl::codec::enc_hdr(pdu, type, rrctl::proto::RRCTL_ERR);
iface->write(pdu);
}
void nas_ext::handle_rrctl_reset(rrctl::proto::msg_disc disc, const uint8_t* msg, size_t len)
{
// TODO: do we need to reset anything?
rrctl_send_confirm(rrctl::proto::RRCTL_RESET);
}
void nas_ext::handle_rrctl_plmn_search(rrctl::proto::msg_disc disc, const uint8_t* msg, size_t len)
{
// Response to be sent when RRC responds
rrc->plmn_search();
}
void nas_ext::handle_rrctl_plmn_select(rrctl::proto::msg_disc disc, const uint8_t* msg, size_t len)
{
std::pair<uint16_t, uint16_t> mcc_mnc;
srslte::plmn_id_t plmn_id;
// Parse PLMN ID
try {
rrctl::codec::dec_plmn_select_req(mcc_mnc, msg, len);
} catch (const rrctl::codec::error& e) {
nas_log->warning("Failed to parse RRCTL message: %s\n", e.what());
rrctl_send_error(rrctl::proto::RRCTL_PLMN_SELECT);
return;
}
if (plmn_id.from_number(mcc_mnc.first, mcc_mnc.second) != SRSLTE_SUCCESS) {
nas_log->warning("Failed to parse PLMN ID from PLMN Select Request\n");
rrctl_send_error(rrctl::proto::RRCTL_PLMN_SELECT);
}
rrc->plmn_select(plmn_id);
rrctl_send_confirm(rrctl::proto::RRCTL_PLMN_SELECT);
}
void nas_ext::handle_rrctl_conn_establish(rrctl::proto::msg_disc disc, const uint8_t* msg, size_t len)
{
srslte::establishment_cause_t cause;
const uint8_t* pdu;
size_t pdu_len;
try {
rrctl::codec::dec_conn_establish_req(cause, pdu, pdu_len, msg, len);
} catch (const rrctl::codec::error& e) {
nas_log->warning("Failed to parse RRCTL message: %s\n", e.what());
rrctl_send_error(rrctl::proto::RRCTL_CONN_ESTABLISH);
return;
}
// Allocate a new NAS PDU on heap
unique_byte_buffer_t nas_pdu = srslte::allocate_unique_buffer(*pool, true);
nas_pdu->append_bytes(pdu, pdu_len);
rrc->connection_request(cause, std::move(nas_pdu));
}
void nas_ext::handle_rrctl_data(rrctl::proto::