Compare commits
16 Commits
release_20
...
extnas/rel
Author | SHA1 | Date |
---|---|---|
Vadim Yanitskiy | 2df561cfa2 | |
Vadim Yanitskiy | fbb2ed3aa9 | |
Vadim Yanitskiy | 19ed00e9bb | |
Vadim Yanitskiy | b594b15e79 | |
Vadim Yanitskiy | 27344af7f0 | |
Vadim Yanitskiy | 796a6df0df | |
Vadim Yanitskiy | 510bd4ee02 | |
Vadim Yanitskiy | aeee4da73c | |
Vadim Yanitskiy | f68931f6e8 | |
Vadim Yanitskiy | 7b38286864 | |
Vadim Yanitskiy | 74b2c5c711 | |
Vadim Yanitskiy | 900ad92912 | |
Vadim Yanitskiy | 8bc72d44b9 | |
Vadim Yanitskiy | 2b1ded220e | |
Vadim Yanitskiy | d56863ff4e | |
Vadim Yanitskiy | d4f1310fca |
|
@ -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
|
||||
|
|
|
@ -8,6 +8,7 @@ extraction:
|
|||
- libmbedtls-dev
|
||||
- libpcsclite-dev
|
||||
- libboost-program-options-dev
|
||||
- libasio-dev
|
||||
- libconfig++-dev
|
||||
- libsctp-dev
|
||||
- libuhd-dev
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -241,6 +241,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
|
||||
|
|
|
@ -119,7 +119,7 @@ Build Instructions
|
|||
|
||||
For example, on Ubuntu, one can install the mandatory build dependencies 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:
|
||||
```
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -10,6 +10,7 @@ Build-Depends:
|
|||
libfftw3-dev,
|
||||
libmbedtls-dev,
|
||||
libboost-program-options-dev,
|
||||
libasio-dev,
|
||||
libconfig++-dev,
|
||||
libsctp-dev,
|
||||
libuhd-dev,
|
||||
|
|
|
@ -174,7 +174,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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
uint32_t sync_queue_size; // Max allowed difference between PHY and Stack clocks (in TTI)
|
||||
|
|
|
@ -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"
|
||||
|
@ -153,6 +154,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;
|
||||
|
@ -174,8 +176,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
|
||||
|
|
|
@ -38,15 +38,68 @@ 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_sched_handle task_sched_);
|
||||
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_sched_handle task_sched_, 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_sched_handle task_sched;
|
||||
srslte::proc_manager_list_t callbacks;
|
||||
|
||||
// Logging reference
|
||||
srslte::log_ref nas_log;
|
||||
|
||||
// PCAP
|
||||
srslte::nas_pcap* pcap = nullptr;
|
||||
|
||||
// Security context
|
||||
uint8_t k_nas_enc[32] = { };
|
||||
uint8_t k_nas_int[32] = { };
|
||||
|
||||
struct nas_sec_ctxt {
|
||||
uint8_t ksi;
|
||||
uint8_t k_asme[32];
|
||||
uint32_t tx_count;
|
||||
uint32_t rx_count;
|
||||
uint32_t k_enb_count;
|
||||
srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo;
|
||||
srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo;
|
||||
LIBLTE_MME_EPS_MOBILE_ID_GUTI_STRUCT guti;
|
||||
} ctxt = { };
|
||||
|
||||
void integrity_generate(uint8_t* key_128, uint32_t count, uint8_t direction,
|
||||
uint8_t* msg, uint32_t msg_len, uint8_t* mac);
|
||||
bool integrity_check(srslte::byte_buffer_t* pdu);
|
||||
|
||||
void cipher_encrypt(srslte::byte_buffer_t* pdu);
|
||||
void cipher_decrypt(srslte::byte_buffer_t* pdu);
|
||||
|
||||
void set_k_enb_count(uint32_t count);
|
||||
uint32_t get_k_enb_count();
|
||||
};
|
||||
|
||||
class nas : public nas_base
|
||||
{
|
||||
public:
|
||||
nas(srslte::task_sched_handle task_sched_, 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();
|
||||
|
||||
|
@ -55,7 +108,6 @@ public:
|
|||
bool paging(srslte::s_tmsi_t* ue_identity) override;
|
||||
void set_barring(srslte::barring_t barring) override;
|
||||
void write_pdu(uint32_t lcid, srslte::unique_byte_buffer_t pdu) override;
|
||||
uint32_t get_k_enb_count() override;
|
||||
bool is_attached() override;
|
||||
bool get_k_asme(uint8_t* k_asme_, uint32_t n) override;
|
||||
uint32_t get_ipv4_addr() override;
|
||||
|
@ -72,17 +124,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;
|
||||
|
||||
|
@ -94,18 +137,6 @@ private:
|
|||
|
||||
std::vector<srslte::plmn_id_t> known_plmns;
|
||||
|
||||
// Security context
|
||||
struct nas_sec_ctxt {
|
||||
uint8_t ksi;
|
||||
uint8_t k_asme[32];
|
||||
uint32_t tx_count;
|
||||
uint32_t rx_count;
|
||||
uint32_t k_enb_count;
|
||||
srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo;
|
||||
srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo;
|
||||
LIBLTE_MME_EPS_MOBILE_ID_GUTI_STRUCT guti;
|
||||
};
|
||||
|
||||
typedef enum { DEFAULT_EPS_BEARER = 0, DEDICATED_EPS_BEARER } eps_bearer_type_t;
|
||||
|
||||
typedef struct {
|
||||
|
@ -120,7 +151,6 @@ private:
|
|||
|
||||
bool have_guti = false;
|
||||
bool have_ctxt = false;
|
||||
nas_sec_ctxt ctxt = {};
|
||||
bool auth_request = false;
|
||||
uint8_t current_sec_hdr = LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS;
|
||||
|
||||
|
@ -135,7 +165,6 @@ private:
|
|||
uint8_t transaction_id = 0;
|
||||
|
||||
// timers
|
||||
srslte::task_sched_handle task_sched;
|
||||
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
|
||||
|
@ -157,8 +186,6 @@ private:
|
|||
// Security
|
||||
bool eia_caps[8] = {};
|
||||
bool eea_caps[8] = {};
|
||||
uint8_t k_nas_enc[32] = {};
|
||||
uint8_t k_nas_int[32] = {};
|
||||
|
||||
// Airplane mode simulation
|
||||
typedef enum { DISABLED = 0, ENABLED } airplane_mode_state_t;
|
||||
|
@ -169,16 +196,9 @@ private:
|
|||
|
||||
bool running = false;
|
||||
|
||||
void
|
||||
integrity_generate(uint8_t* key_128, uint32_t count, uint8_t direction, uint8_t* msg, uint32_t msg_len, uint8_t* mac);
|
||||
bool integrity_check(srslte::byte_buffer_t* pdu);
|
||||
void cipher_encrypt(srslte::byte_buffer_t* pdu);
|
||||
void cipher_decrypt(srslte::byte_buffer_t* pdu);
|
||||
int apply_security_config(srslte::unique_byte_buffer_t& pdu, uint8_t sec_hdr_type);
|
||||
void reset_security_context();
|
||||
|
||||
void set_k_enb_count(uint32_t count);
|
||||
|
||||
bool check_cap_replay(LIBLTE_MME_UE_SECURITY_CAPABILITIES_STRUCT* caps);
|
||||
|
||||
void select_plmn();
|
||||
|
@ -317,7 +337,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;
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -0,0 +1,103 @@
|
|||
/*
|
||||
* 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_sched_handle task_sched_, const nas_ext_args_t& cfg_) :
|
||||
nas_base::nas_base(task_sched_, "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);
|
||||
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 handle_rrctl_sec_mode(rrctl::proto::msg_disc disc, const uint8_t* msg, size_t len);
|
||||
|
||||
void handle_rrctl_ext_usim(const uint8_t* msg, size_t len);
|
||||
void handle_usim_gen_auth_resp_req(const struct rrctl::proto::ext_usim_msg* msg, size_t len);
|
||||
void handle_usim_gen_nas_keys_req(const struct rrctl::proto::ext_usim_msg* 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
|
|
@ -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
|
|
@ -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
|
|
@ -0,0 +1,260 @@
|
|||
/*
|
||||
* 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,
|
||||
RRCTL_SEC_MODE,
|
||||
|
||||
/* RRCTL protocol extensions (0b11xxxx, up to 15 groups) follow */
|
||||
|
||||
/* (U)SIM specific messages (for accessing built-in card reader) */
|
||||
RRCTL_EXT_USIM = 0x3e, // 0b111110
|
||||
/* RFU (Reserved for Further Use) */
|
||||
RRCTL_RESERVED = 0x3f, // 0b111111
|
||||
};
|
||||
|
||||
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));
|
||||
|
||||
enum msg_eea_type {
|
||||
RRCTL_EEA0 = 0x00,
|
||||
RRCTL_EEA1 = 0x01,
|
||||
RRCTL_EEA2 = 0x02,
|
||||
RRCTL_EEA3 = 0x03,
|
||||
};
|
||||
|
||||
enum msg_eia_type {
|
||||
RRCTL_EIA0 = 0x00,
|
||||
RRCTL_EIA1 = 0x01,
|
||||
RRCTL_EIA2 = 0x02,
|
||||
RRCTL_EIA3 = 0x03,
|
||||
};
|
||||
|
||||
#define SEC_MODE_F_RESET_RX_CTR (1 << 0)
|
||||
#define SEC_MODE_F_RESET_TX_CTR (1 << 1)
|
||||
|
||||
struct msg_sec_mode_req {
|
||||
#if defined(__LITTLE_ENDIAN_BITFIELD)
|
||||
uint8_t flags:2, eia:3, eea:3;
|
||||
#elif defined(__BIG_ENDIAN_BITFIELD)
|
||||
uint8_t eea:3, eia:3, flags:2;
|
||||
#else
|
||||
#error "Please fix <asm/byteorder.h>"
|
||||
#endif
|
||||
uint8_t spare[3];
|
||||
uint8_t k_asme[0]; // optional (32 octets)
|
||||
} __attribute__((packed));
|
||||
|
||||
struct msg {
|
||||
struct msg_hdr hdr;
|
||||
union {
|
||||
struct msg_data data;
|
||||
struct msg_sec_mode_req;
|
||||
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));
|
||||
|
||||
/* (U)SIM specific message types */
|
||||
enum ext_usim_msg_type {
|
||||
EXT_USIM_RAW_APDU = 0x00,
|
||||
EXT_USIM_READ_FILE = 0x01,
|
||||
EXT_USIM_UPDATE_FILE = 0x02,
|
||||
EXT_USIM_GEN_AUTH_RESP = 0x03,
|
||||
|
||||
/* RFU (Reserved for Further Use) */
|
||||
EXT_USIM_RESERVED = 0xff,
|
||||
};
|
||||
|
||||
struct ext_usim_raw_apdu {
|
||||
uint16_t len;
|
||||
uint8_t apdu_sw[0];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct ext_usim_read_file_req {
|
||||
/* TODO: check GSM 11.11 and make sure that this is correct */
|
||||
uint16_t df; // Dedicated File
|
||||
uint16_t ef; // Elementary File
|
||||
} __attribute__((packed));
|
||||
|
||||
struct ext_usim_read_file_rsp {
|
||||
uint16_t len;
|
||||
uint8_t data[0];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct ext_usim_update_file_req {
|
||||
/* NOTE: re-using the existing structures here */
|
||||
struct ext_usim_read_file_req file; // DF & EF
|
||||
struct ext_usim_read_file_rsp content;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct ext_usim_gen_auth_resp_req {
|
||||
uint8_t rand[16];
|
||||
uint8_t autn[16];
|
||||
uint8_t mcc[2];
|
||||
uint8_t mnc[2];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct ext_usim_gen_auth_resp_rsp {
|
||||
uint8_t out_of_sync;
|
||||
uint8_t res_len;
|
||||
uint8_t spare[2];
|
||||
uint8_t k_asme_res[0];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct ext_usim_msg {
|
||||
uint8_t type;
|
||||
uint8_t spare[3];
|
||||
union {
|
||||
struct ext_usim_raw_apdu raw_apdu;
|
||||
struct ext_usim_read_file_req read_file_req;
|
||||
struct ext_usim_read_file_rsp read_file_rsp;
|
||||
struct ext_usim_update_file_req update_file_req;
|
||||
struct ext_usim_gen_auth_resp_req gen_auth_resp_req;
|
||||
struct ext_usim_gen_auth_resp_rsp gen_auth_resp_rsp;
|
||||
} 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) {};
|
||||
};
|
||||
|
||||
struct proto::msg_hdr* 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
|
|
@ -139,6 +139,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")
|
||||
|
@ -166,6 +169,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")
|
||||
|
@ -535,6 +540,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
|
||||
|
@ -566,6 +574,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;
|
||||
}
|
||||
}
|
||||
|
||||
// Set sync queue capacity to 1 for ZMQ
|
||||
|
|
|
@ -37,11 +37,11 @@ ue_stack_lte::ue_stack_lte() :
|
|||
logger(nullptr),
|
||||
usim(nullptr),
|
||||
phy(nullptr),
|
||||
nas(nullptr),
|
||||
rlc("RLC"),
|
||||
mac("MAC", &task_sched),
|
||||
rrc(this, &task_sched),
|
||||
pdcp(&task_sched, "PDCP"),
|
||||
nas(&task_sched),
|
||||
thread("STACK"),
|
||||
task_sched(512, 2, 64),
|
||||
tti_tprof("tti_tprof", "STCK", TTI_STAT_PERIOD)
|
||||
|
@ -102,6 +102,17 @@ 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
|
||||
if (!args.nas_ext.enable) {
|
||||
std::unique_ptr<srsue::nas> nas_impl(new srsue::nas(&task_sched, args.nas));
|
||||
nas = std::move(nas_impl);
|
||||
} else { // ... or provide an external interface (RRCTL)?
|
||||
std::unique_ptr<srsue::nas_ext> nas_impl(new srsue::nas_ext(&task_sched, args.nas_ext));
|
||||
nas = std::move(nas_impl);
|
||||
}
|
||||
|
||||
// Set up pcap
|
||||
if (args.pcap.enable) {
|
||||
|
@ -110,7 +121,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
|
||||
|
@ -126,8 +137,8 @@ int ue_stack_lte::init(const stack_args_t& args_, srslte::logger* logger_)
|
|||
mac.init(phy, &rlc, &rrc);
|
||||
rlc.init(&pdcp, &rrc, task_sched.get_timer_handler(), 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);
|
||||
|
@ -148,7 +159,7 @@ void ue_stack_lte::stop_impl()
|
|||
running = false;
|
||||
|
||||
usim->stop();
|
||||
nas.stop();
|
||||
nas->stop();
|
||||
rrc.stop();
|
||||
|
||||
rlc.stop();
|
||||
|
@ -166,7 +177,7 @@ void ue_stack_lte::stop_impl()
|
|||
bool ue_stack_lte::switch_on()
|
||||
{
|
||||
if (running) {
|
||||
ue_task_queue.try_push([this]() { nas.start_attach_proc(nullptr, srslte::establishment_cause_t::mo_sig); });
|
||||
ue_task_queue.try_push([this]() { nas->start_attach_proc(nullptr, srslte::establishment_cause_t::mo_sig); });
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -175,7 +186,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)
|
||||
int cnt = 0, timeout_ms = 5000;
|
||||
|
@ -202,7 +213,7 @@ bool ue_stack_lte::disable_data()
|
|||
{
|
||||
// generate detach request
|
||||
srslte::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)
|
||||
|
@ -212,7 +223,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);
|
||||
});
|
||||
|
@ -313,7 +324,7 @@ void ue_stack_lte::run_tti_impl(uint32_t tti, uint32_t tti_jump)
|
|||
task_sched.tic();
|
||||
}
|
||||
rrc.run_tti();
|
||||
nas.run_tti();
|
||||
nas->run_tti();
|
||||
|
||||
if (args.have_tti_time_stats) {
|
||||
std::chrono::nanoseconds dur = tti_tprof.stop();
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -235,20 +235,25 @@ proc_outcome_t nas::rrc_connect_proc::react(nas::rrc_connect_proc::connection_re
|
|||
* NAS
|
||||
********************************************************************/
|
||||
|
||||
nas::nas(srslte::task_sched_handle task_sched_) :
|
||||
nas_base::nas_base(srslte::task_sched_handle task_sched_, const char *log_name_) :
|
||||
pool(byte_buffer_pool::get_instance()),
|
||||
task_sched(task_sched_),
|
||||
nas_log{log_name_}
|
||||
{}
|
||||
|
||||
nas::nas(srslte::task_sched_handle task_sched_, const nas_args_t& cfg_) :
|
||||
nas_base::nas_base(task_sched_, "NAS"),
|
||||
cfg(cfg_),
|
||||
plmn_searcher(this),
|
||||
rrc_connector(this),
|
||||
task_sched(task_sched_),
|
||||
t3402(task_sched_.get_unique_timer()),
|
||||
t3410(task_sched_.get_unique_timer()),
|
||||
t3411(task_sched_.get_unique_timer()),
|
||||
t3421(task_sched_.get_unique_timer()),
|
||||
reattach_timer(task_sched_.get_unique_timer()),
|
||||
nas_log{"NAS"}
|
||||
reattach_timer(task_sched_.get_unique_timer())
|
||||
{}
|
||||
|
||||
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_;
|
||||
|
@ -262,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;
|
||||
srslte::string_parse_list(cfg_.eia, ',', cap_list);
|
||||
srslte::string_parse_list(cfg.eia, ',', cap_list);
|
||||
if (cap_list.empty()) {
|
||||
nas_log->error("Empty EIA list. Select at least one EIA algorithm.\n");
|
||||
}
|
||||
|
@ -275,7 +280,7 @@ void nas::init(usim_interface_nas* usim_, rrc_interface_nas* rrc_, gw_interface_
|
|||
}
|
||||
|
||||
// parse and sanity check EEA list
|
||||
srslte::string_parse_list(cfg_.eea, ',', cap_list);
|
||||
srslte::string_parse_list(cfg.eea, ',', cap_list);
|
||||
if (cap_list.empty()) {
|
||||
nas_log->error("Empty EEA list. Select at least one EEA algorithm.\n");
|
||||
}
|
||||
|
@ -287,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");
|
||||
|
@ -326,7 +329,7 @@ emm_state_t nas::get_state()
|
|||
return state;
|
||||
}
|
||||
|
||||
void nas::run_tti()
|
||||
void nas_base::run_tti()
|
||||
{
|
||||
callbacks.run();
|
||||
}
|
||||
|
@ -710,14 +713,14 @@ void nas::write_pdu(uint32_t lcid, unique_byte_buffer_t pdu)
|
|||
}
|
||||
}
|
||||
|
||||
void nas::set_k_enb_count(uint32_t count)
|
||||
void nas_base::set_k_enb_count(uint32_t count)
|
||||
{
|
||||
// UL count for RRC key derivation depends on UL Count of the Attach Request or Service Request.
|
||||
// On the case of an Authentication Request, the UL count used to generate K_enb must be reset to zero.
|
||||
ctxt.k_enb_count = count;
|
||||
}
|
||||
|
||||
uint32_t nas::get_k_enb_count()
|
||||
uint32_t nas_base::get_k_enb_count()
|
||||
{
|
||||
return ctxt.k_enb_count;
|
||||
}
|
||||
|
@ -756,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_;
|
||||
}
|
||||
|
@ -765,12 +768,12 @@ void nas::start_pcap(srslte::nas_pcap* pcap_)
|
|||
* Security
|
||||
******************************************************************************/
|
||||
|
||||
void nas::integrity_generate(uint8_t* key_128,
|
||||
uint32_t count,
|
||||
uint8_t direction,
|
||||
uint8_t* msg,
|
||||
uint32_t msg_len,
|
||||
uint8_t* mac)
|
||||
void nas_base::integrity_generate(uint8_t* key_128,
|
||||
uint32_t count,
|
||||
uint8_t direction,
|
||||
uint8_t* msg,
|
||||
uint32_t msg_len,
|
||||
uint8_t* mac)
|
||||
{
|
||||
switch (ctxt.integ_algo) {
|
||||
case INTEGRITY_ALGORITHM_ID_EIA0:
|
||||
|
@ -809,7 +812,7 @@ void nas::integrity_generate(uint8_t* key_128,
|
|||
|
||||
// This function depends to a valid k_nas_int.
|
||||
// This key is generated in the security mode command.
|
||||
bool nas::integrity_check(byte_buffer_t* pdu)
|
||||
bool nas_base::integrity_check(byte_buffer_t* pdu)
|
||||
{
|
||||
if (pdu == nullptr) {
|
||||
nas_log->error("Invalid PDU\n");
|
||||
|
@ -863,7 +866,7 @@ bool nas::integrity_check(byte_buffer_t* pdu)
|
|||
}
|
||||
}
|
||||
|
||||
void nas::cipher_encrypt(byte_buffer_t* pdu)
|
||||
void nas_base::cipher_encrypt(byte_buffer_t* pdu)
|
||||
{
|
||||
byte_buffer_t pdu_tmp;
|
||||
switch (ctxt.cipher_algo) {
|
||||
|
@ -905,7 +908,7 @@ void nas::cipher_encrypt(byte_buffer_t* pdu)
|
|||
}
|
||||
}
|
||||
|
||||
void nas::cipher_decrypt(byte_buffer_t* pdu)
|
||||
void nas_base::cipher_decrypt(byte_buffer_t* pdu)
|
||||
{
|
||||
byte_buffer_t tmp_pdu;
|
||||
switch (ctxt.cipher_algo) {
|
||||
|
|
|
@ -0,0 +1,535 @@
|
|||
/*
|
||||
* 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_SEC_MODE:
|
||||
handle_rrctl_sec_mode(disc, payload, length);
|
||||
break;
|
||||
case rrctl::proto::RRCTL_EXT_USIM:
|
||||
handle_rrctl_ext_usim(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)
|
||||
{
|
||||
/* Reset security state (no EEA, no EIA) */
|
||||
memset(&ctxt, 0x00, sizeof(ctxt));
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
set_k_enb_count(ctxt.tx_count);
|
||||
ctxt.tx_count++;
|
||||
|
||||
// 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);
|
||||
|
||||
if (pcap != nullptr)
|
||||
pcap->write_nas(nas_pdu->msg, nas_pdu->N_bytes);
|
||||
|
||||
rrc->connection_request(cause, std::move(nas_pdu));
|
||||
}
|
||||
|
||||
void nas_ext::handle_rrctl_data(rrctl::proto::msg_disc disc, const uint8_t* msg, size_t len)
|
||||
{
|
||||
if (not rrc->is_connected()) {
|
||||
nas_log->warning("Received DATA.req, but there is no active connection\n");
|
||||
rrctl_send_error(rrctl::proto::RRCTL_DATA);
|
||||
return;
|
||||
}
|
||||
|
||||
// Allocate a new NAS PDU on heap
|
||||
unique_byte_buffer_t nas_pdu = srslte::allocate_unique_buffer(*pool, true);
|
||||
nas_pdu->append_bytes(msg, len);
|
||||
|
||||
if (pcap != nullptr)
|
||||
pcap->write_nas(nas_pdu->msg, nas_pdu->N_bytes);
|
||||
|
||||
// Apply pre-configured EEA algorythm (if enabled)
|
||||
cipher_encrypt(nas_pdu.get());
|
||||
// Apply pre-configured EIA algorythm (if enabled)
|
||||
integrity_generate(&k_nas_int[16], ctxt.tx_count, SECURITY_DIRECTION_UPLINK,
|
||||
&nas_pdu->msg[5], nas_pdu->N_bytes - 5, &nas_pdu->msg[1]);
|
||||
|
||||
rrc->write_sdu(std::move(nas_pdu));
|
||||
ctxt.tx_count++;
|
||||
|
||||
rrctl_send_confirm(rrctl::proto::RRCTL_DATA);
|
||||
}
|
||||
|
||||
void nas_ext::handle_rrctl_param(rrctl::proto::msg_disc disc, const uint8_t* msg, size_t len)
|
||||
{
|
||||
const struct rrctl::proto::msg_param_req* param;
|
||||
srslte::s_tmsi_t ue_identity;
|
||||
|
||||
param = reinterpret_cast<const struct rrctl::proto::msg_param_req*> (msg);
|
||||
nas_log->warning("Rx PARAM.req (type=%02x, len=%u)\n", param->type, param->len);
|
||||
|
||||
if (param->len != (len - 2)) { /* XXX: type + length */
|
||||
nas_log->info("Received malformed PARAM.req (len=%u)\n", param->len);
|
||||
rrctl_send_error(rrctl::proto::RRCTL_PARAM);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (param->type) {
|
||||
case rrctl::proto::RRCTL_PARAM_UEID:
|
||||
ue_identity.m_tmsi = ntohl(param->u.ueid.m_tmsi);
|
||||
ue_identity.mmec = param->u.ueid.mmec;
|
||||
|
||||
nas_log->info("Setting UEID: mmec=%x m_tmsi=%x\n",
|
||||
ue_identity.mmec, ue_identity.m_tmsi);
|
||||
rrc->set_ue_identity(ue_identity);
|
||||
rrctl_send_confirm(rrctl::proto::RRCTL_PARAM);
|
||||
break;
|
||||
default:
|
||||
nas_log->warning("Unhandled PARAM.req type (0x%02x)\n", param->type);
|
||||
rrctl_send_error(rrctl::proto::RRCTL_PARAM);
|
||||
}
|
||||
}
|
||||
|
||||
void nas_ext::handle_rrctl_sec_mode(rrctl::proto::msg_disc disc, const uint8_t* msg, size_t len)
|
||||
{
|
||||
const struct rrctl::proto::msg_sec_mode_req* req;
|
||||
|
||||
req = reinterpret_cast<const struct rrctl::proto::msg_sec_mode_req*> (msg);
|
||||
|
||||
if (len < sizeof(*req)) { /* XXX: mandatory fields only */
|
||||
nas_log->error("Received malformed PARAM.req (len=%zu)\n", len);
|
||||
rrctl_send_error(rrctl::proto::RRCTL_SEC_MODE);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Skip the header */
|
||||
len -= sizeof(*req);
|
||||
|
||||
nas_log->info("Rx SecurityMode.req (EEA%u, EIA%u)\n", req->eea, req->eia);
|
||||
|
||||
ctxt.cipher_algo = static_cast<srslte::CIPHERING_ALGORITHM_ID_ENUM> (req->eea);
|
||||
ctxt.integ_algo = static_cast<srslte::INTEGRITY_ALGORITHM_ID_ENUM> (req->eia);
|
||||
|
||||
if (req->flags & SEC_MODE_F_RESET_RX_CTR)
|
||||
ctxt.rx_count = 0;
|
||||
if (req->flags & SEC_MODE_F_RESET_TX_CTR)
|
||||
ctxt.tx_count = 0;
|
||||
|
||||
if (req->eea != 0x00 or req->eia != 0x00) {
|
||||
/* Ensure that Kasme is present */
|
||||
if (len != sizeof(ctxt.k_asme)) {
|
||||
nas_log->error("Kasme is expected, but not present");
|
||||
rrctl_send_error(rrctl::proto::RRCTL_SEC_MODE);
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(&ctxt.k_asme[0], &req->k_asme[0], sizeof(ctxt.k_asme));
|
||||
|
||||
/* Derive both Knas_enc and Knas_int from Kasme */
|
||||
/* NOTE: how is this related to (U)SIM at all?!? */
|
||||
usim->generate_nas_keys(&ctxt.k_asme[0], // in
|
||||
&k_nas_enc[0], // out
|
||||
&k_nas_int[0], // out
|
||||
ctxt.cipher_algo,
|
||||
ctxt.integ_algo);
|
||||
}
|
||||
|
||||
rrctl_send_confirm(rrctl::proto::RRCTL_SEC_MODE);
|
||||
}
|
||||
|
||||
void nas_ext::handle_rrctl_ext_usim(const uint8_t* _msg, size_t len)
|
||||
{
|
||||
enum rrctl::proto::ext_usim_msg_type msg_type;
|
||||
const struct rrctl::proto::ext_usim_msg* msg;
|
||||
std::string msg_desc;
|
||||
|
||||
if (len < 4) { /* XXX: type + padding */
|
||||
nas_log->error("Received too short (U)SIM specific message (len=%zu)\n", len);
|
||||
rrctl_send_error(rrctl::proto::RRCTL_EXT_USIM);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Skip the header */
|
||||
len -= 4;
|
||||
|
||||
msg = reinterpret_cast<const struct rrctl::proto::ext_usim_msg*> (_msg);
|
||||
msg_type = static_cast<rrctl::proto::ext_usim_msg_type> (msg->type);
|
||||
|
||||
switch (msg_type) {
|
||||
case rrctl::proto::EXT_USIM_GEN_AUTH_RESP:
|
||||
handle_usim_gen_auth_resp_req(msg, len);
|
||||
break;
|
||||
case rrctl::proto::EXT_USIM_RAW_APDU:
|
||||
case rrctl::proto::EXT_USIM_READ_FILE:
|
||||
case rrctl::proto::EXT_USIM_UPDATE_FILE:
|
||||
case rrctl::proto::EXT_USIM_RESERVED:
|
||||
default:
|
||||
nas_log->warning("(U)SIM specific message 0x%02x is not handled\n", msg->type);
|
||||
}
|
||||
}
|
||||
|
||||
void nas_ext::handle_usim_gen_auth_resp_req(const struct rrctl::proto::ext_usim_msg* msg, size_t len)
|
||||
{
|
||||
const struct rrctl::proto::ext_usim_gen_auth_resp_req* req;
|
||||
struct rrctl::proto::ext_usim_gen_auth_resp_rsp* rsp;
|
||||
struct rrctl::proto::ext_usim_msg* rsp_msg;
|
||||
std::pair<uint16_t, uint16_t> mcc_mnc;
|
||||
struct rrctl::proto::msg_hdr* hdr;
|
||||
srslte::byte_buffer_t pdu;
|
||||
|
||||
/* Allocate the response message in advance */
|
||||
hdr = rrctl::codec::enc_hdr(pdu, rrctl::proto::RRCTL_EXT_USIM, rrctl::proto::RRCTL_CNF, 4);
|
||||
rsp_msg = reinterpret_cast<struct rrctl::proto::ext_usim_msg*> (&pdu.msg[pdu.N_bytes]);
|
||||
rsp_msg->type = msg->type;
|
||||
pdu.N_bytes += 4;
|
||||
|
||||
if (len < sizeof(*req)) {
|
||||
nas_log->error("Received too short (U)SIM GenAuthResp.req (len=%zu)\n", len);
|
||||
hdr->disc = (uint8_t) rrctl::proto::RRCTL_ERR;
|
||||
iface->write(pdu);
|
||||
return;
|
||||
}
|
||||
|
||||
rsp = &rsp_msg->u.gen_auth_resp_rsp;
|
||||
req = &msg->u.gen_auth_resp_req;
|
||||
|
||||
// Parse PLMN ID
|
||||
try {
|
||||
/* HACK: generalize this function */
|
||||
rrctl::codec::dec_plmn_select_req(mcc_mnc, &req->mcc[0], len);
|
||||
} catch (const rrctl::codec::error& e) {
|
||||
nas_log->warning("Failed to parse MCC/MNC: %s\n", e.what());
|
||||
hdr->disc = (uint8_t) rrctl::proto::RRCTL_ERR;
|
||||
iface->write(pdu);
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t k_asme[32];
|
||||
uint8_t res[16];
|
||||
int res_len;
|
||||
|
||||
/* NOTE: this is a blocking call => no other RRCTL messages can be processed in parallel?
|
||||
* FIXME: the authors of srsUE apparently are not aware of 'const', so we have to cast. */
|
||||
auth_result_t auth_res = usim->generate_authentication_response((uint8_t*) &req->rand[0],
|
||||
(uint8_t*) &req->autn[0],
|
||||
mcc_mnc.first, mcc_mnc.second,
|
||||
&res[0], &res_len, &k_asme[0]);
|
||||
switch (auth_res) {
|
||||
case AUTH_OK:
|
||||
nas_log->info("Authentication vector has been generated successfully\n");
|
||||
|
||||
set_k_enb_count(0);
|
||||
|
||||
pdu.N_bytes += sizeof(*rsp);
|
||||
pdu.append_bytes(&k_asme[0], sizeof(k_asme));
|
||||
pdu.append_bytes(&res[0], res_len);
|
||||
rsp->res_len = (uint8_t) res_len;
|
||||
break;
|
||||
case AUTH_SYNCH_FAILURE:
|
||||
nas_log->warning("Synchronization is required to generate an authentication vector\n");
|
||||
|
||||
pdu.N_bytes += sizeof(*rsp);
|
||||
pdu.append_bytes(&res[0], res_len);
|
||||
rsp->res_len = (uint8_t) res_len;
|
||||
rsp->out_of_sync = true;
|
||||
break;
|
||||
case AUTH_FAILED:
|
||||
default:
|
||||
nas_log->warning("Could not generate an authentication vector\n");
|
||||
hdr->disc = (uint8_t) rrctl::proto::RRCTL_ERR;
|
||||
}
|
||||
|
||||
hdr->len = htons(pdu.N_bytes - sizeof(*hdr));
|
||||
iface->write(pdu);
|
||||
}
|
||||
|
||||
void nas_ext::get_metrics(nas_metrics_t* m)
|
||||
{
|
||||
nas_metrics_t metrics = {};
|
||||
// FIXME: is there anything we could fill in?
|
||||
*m = metrics;
|
||||
}
|
||||
|
||||
void nas_ext::stop()
|
||||
{
|
||||
// Close the UNIX domain socket connection
|
||||
iface->close();
|
||||
iface.release();
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* UE interface (dummy)
|
||||
******************************************************************************/
|
||||
|
||||
void nas_ext::start_attach_proc(srslte::proc_state_t* result, srslte::establishment_cause_t cause_)
|
||||
{
|
||||
nas_log->info("The UE has requested us to perform Attach Request, however we ignore it\n");
|
||||
if (result != nullptr) {
|
||||
result->set_val();
|
||||
}
|
||||
}
|
||||
|
||||
bool nas_ext::detach_request(const bool switch_off)
|
||||
{
|
||||
nas_log->info("The UE has requested us to perform Detach Request, however we ignore it\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
void nas_ext::timer_expired(uint32_t timeout_id)
|
||||
{
|
||||
nas_log->info("Timer id=%u is expired, however we ignore it\n", timeout_id);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* RRC interface
|
||||
******************************************************************************/
|
||||
|
||||
// TODO: investigate the meaning of these signals
|
||||
void nas_ext::set_barring(barring_t barring) {}
|
||||
void nas_ext::left_rrc_connected() {}
|
||||
|
||||
bool nas_ext::paging(srslte::s_tmsi_t* ue_identity)
|
||||
{
|
||||
srslte::byte_buffer_t msg;
|
||||
|
||||
nas_log->info("Received paging from RRC\n");
|
||||
|
||||
rrctl::codec::enc_paging_ind(msg, ue_identity);
|
||||
iface->write(msg);
|
||||
|
||||
// TODO: what are we supposed to return?
|
||||
return false;
|
||||
}
|
||||
|
||||
void nas_ext::write_pdu(uint32_t lcid, srslte::unique_byte_buffer_t pdu)
|
||||
{
|
||||
srslte::byte_buffer_t msg;
|
||||
uint8 pd, sec_hdr_type;
|
||||
|
||||
nas_log->info_hex(pdu->msg, pdu->N_bytes, "Received DL %s PDU from RRC\n", rrc->get_rb_name(lcid).c_str());
|
||||
|
||||
// Parse the message security header
|
||||
liblte_mme_parse_msg_sec_header((LIBLTE_BYTE_MSG_STRUCT*) pdu.get(), &pd, &sec_hdr_type);
|
||||
switch (sec_hdr_type) {
|
||||
case LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED_WITH_NEW_EPS_SECURITY_CONTEXT:
|
||||
case LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_WITH_NEW_EPS_SECURITY_CONTEXT:
|
||||
case LIBLTE_MME_SECURITY_HDR_TYPE_SERVICE_REQUEST:
|
||||
case LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS:
|
||||
case LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY:
|
||||
break;
|
||||
case LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED:
|
||||
// Apply pre-configured EEA algorythm (if enabled)
|
||||
cipher_decrypt(pdu.get());
|
||||
break;
|
||||
default:
|
||||
nas_log->error("Received DL NAS PDU with unknown sec_hdr=%02x\n", sec_hdr_type);
|
||||
}
|
||||
|
||||
if (pcap != nullptr)
|
||||
pcap->write_nas(pdu->msg, pdu->N_bytes);
|
||||
|
||||
rrctl::codec::enc_data_ind(msg, pdu->msg, pdu->N_bytes, lcid);
|
||||
iface->write(msg);
|
||||
}
|
||||
|
||||
bool nas_ext::is_attached()
|
||||
{
|
||||
// FIXME: we probably need to maintain the state
|
||||
return false; // return a dummy value for now
|
||||
}
|
||||
|
||||
bool nas_ext::get_k_asme(uint8_t* k_asme_, uint32_t n)
|
||||
{
|
||||
// FIXME: we probably need to maintain a security context
|
||||
return false; // return a dummy value for now
|
||||
}
|
||||
|
||||
uint32_t nas_ext::get_ipv4_addr()
|
||||
{
|
||||
// FIXME: where can we get it? maybe from GW?
|
||||
return 0x00000000;
|
||||
}
|
||||
|
||||
bool nas_ext::get_ipv6_addr(uint8_t* ipv6_addr)
|
||||
{
|
||||
// FIXME: where can we get it? maybe from GW?
|
||||
return false;
|
||||
}
|
||||
|
||||
void nas_ext::plmn_search_completed(
|
||||
const rrc_interface_nas::found_plmn_t found_plmns[rrc_interface_nas::MAX_FOUND_PLMNS],
|
||||
int nof_plmns)
|
||||
{
|
||||
srslte::byte_buffer_t pdu;
|
||||
|
||||
nas_log->info("RRC has completed PLMN search, %d carriers found\n", nof_plmns);
|
||||
|
||||
// Send PLMN_SEARCH.res to an external entity
|
||||
if (nof_plmns >= 0) {
|
||||
rrctl::codec::enc_plmn_search_res(pdu, found_plmns, nof_plmns);
|
||||
iface->write(pdu);
|
||||
} else {
|
||||
nas_log->warning("PLMN search completed with an error\n");
|
||||
rrctl_send_error(rrctl::proto::RRCTL_PLMN_SEARCH);
|
||||
}
|
||||
}
|
||||
|
||||
bool nas_ext::connection_request_completed(bool outcome)
|
||||
{
|
||||
nas_log->info("RRC has %s connection establisment\n", outcome ? "completed" : "failed");
|
||||
|
||||
if (outcome)
|
||||
rrctl_send_confirm(rrctl::proto::RRCTL_CONN_ESTABLISH);
|
||||
else
|
||||
rrctl_send_error(rrctl::proto::RRCTL_CONN_ESTABLISH);
|
||||
|
||||
return false; // FIXME: what should we return here?
|
||||
}
|
||||
|
||||
} // namespace srsue
|
|
@ -0,0 +1,158 @@
|
|||
/*
|
||||
* 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/common.h"
|
||||
#include "srslte/common/log.h"
|
||||
|
||||
#include "srsue/hdr/stack/upper/nas_extif_unix.h"
|
||||
|
||||
using namespace boost::asio::local;
|
||||
|
||||
namespace srsue {
|
||||
|
||||
nas_extif_unix::nas_extif_unix(recv_cb_t cb_, const std::string& sock_path_) :
|
||||
nas_extif_base(cb_), sock_path(sock_path_), has_connection(false)
|
||||
{
|
||||
if_log->info("Init external NAS interface at '%s'\n", sock_path.c_str());
|
||||
|
||||
// Remove previous binding if present
|
||||
unlink(sock_path.c_str());
|
||||
|
||||
// Set up a UNIX domain socket
|
||||
stream_protocol::endpoint ep(sock_path);
|
||||
stream_protocol::socket* sock_ = new stream_protocol::socket(io_ctx);
|
||||
stream_protocol::acceptor* acc_ = new stream_protocol::acceptor(io_ctx, ep);
|
||||
|
||||
// Move ownership to this->acc
|
||||
std::unique_ptr<stream_protocol::acceptor> acc_ptr(acc_);
|
||||
acc = std::move(acc_ptr);
|
||||
|
||||
// Move ownership to this->sock
|
||||
std::unique_ptr<stream_protocol::socket> sock_ptr(sock_);
|
||||
sock = std::move(sock_ptr);
|
||||
|
||||
// Welcome the first connection
|
||||
accept_conn();
|
||||
|
||||
if_log->info("Starting the server...\n");
|
||||
start(IFACE_THREAD_PRIO);
|
||||
};
|
||||
|
||||
void nas_extif_unix::handle_write(void)
|
||||
{
|
||||
srslte::byte_buffer_t pdu;
|
||||
|
||||
if (not tx_queue.try_pop(&pdu))
|
||||
return;
|
||||
|
||||
boost::asio::async_write(*sock, boost::asio::buffer(pdu.msg, pdu.N_bytes),
|
||||
[this](boost::system::error_code ec, std::size_t len)
|
||||
{
|
||||
if (!ec) {
|
||||
if_log->info("Tx %zu bytes to external NAS interface\n", len);
|
||||
} else {
|
||||
if_log->warning("External NAS write() handler got error (ec=%d)\n", ec.value());
|
||||
}
|
||||
|
||||
// Keep writing unless the queue is empty
|
||||
handle_write();
|
||||
});
|
||||
}
|
||||
|
||||
void nas_extif_unix::handle_read(void)
|
||||
{
|
||||
sock->async_read_some(boost::asio::buffer(buf),
|
||||
[this](boost::system::error_code ec, std::size_t len)
|
||||
{
|
||||
if (!ec) {
|
||||
if_log->info("Rx %zu bytes from external NAS interface\n", len);
|
||||
|
||||
// Invoke the Rx callback
|
||||
srslte::byte_buffer_t pdu;
|
||||
pdu.append_bytes(buf, len);
|
||||
recv_cb(pdu);
|
||||
|
||||
// Keep reading
|
||||
handle_read();
|
||||
} else {
|
||||
if_log->info("External NAS interface has lost connection\n");
|
||||
has_connection = false;
|
||||
sock->release();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void nas_extif_unix::accept_conn(void)
|
||||
{
|
||||
acc->async_accept(
|
||||
[this](boost::system::error_code ec, stream_protocol::socket sock_)
|
||||
{
|
||||
if (!ec) {
|
||||
if (!has_connection) {
|
||||
if_log->info("Accepted connection on external NAS interface\n");
|
||||
*sock = std::move(sock_);
|
||||
has_connection = true;
|
||||
handle_read();
|
||||
} else {
|
||||
if_log->warning("NAS interface already has an active connection, rejecting...\n");
|
||||
boost::asio::write(sock_, boost::asio::buffer("REJECT"));
|
||||
}
|
||||
} else {
|
||||
if_log->warning("External NAS connection handler got error (ec=%d)\n", ec.value());
|
||||
}
|
||||
|
||||
// Keep waiting for a new connection
|
||||
accept_conn();
|
||||
});
|
||||
}
|
||||
|
||||
void nas_extif_unix::run_thread(void)
|
||||
{
|
||||
// This is a blocking call
|
||||
io_ctx.run();
|
||||
}
|
||||
|
||||
void nas_extif_unix::stop(void)
|
||||
{
|
||||
io_ctx.stop();
|
||||
wait_thread_finish();
|
||||
}
|
||||
|
||||
void nas_extif_unix::close(void)
|
||||
{
|
||||
stop();
|
||||
}
|
||||
|
||||
int nas_extif_unix::write(const srslte::byte_buffer_t& pdu)
|
||||
{
|
||||
if (!has_connection) {
|
||||
if_log->error("External NAS entity is not connected\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
tx_queue.push(pdu);
|
||||
handle_write();
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace srsue
|
|
@ -0,0 +1,229 @@
|
|||
/*
|
||||
* 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 <arpa/inet.h>
|
||||
|
||||
#include "srsue/hdr/stack/upper/rrctl.h"
|
||||
|
||||
namespace rrctl {
|
||||
|
||||
namespace proto {
|
||||
|
||||
std::string msg_hdr_desc(proto::msg_type type, proto::msg_disc disc, uint16_t len)
|
||||
{
|
||||
std::string desc;
|
||||
|
||||
switch (type) {
|
||||
case RRCTL_RESET:
|
||||
desc += "Reset";
|
||||
break;
|
||||
case RRCTL_PLMN_SEARCH:
|
||||
desc += "PLMN Search";
|
||||
break;
|
||||
case RRCTL_PLMN_SELECT:
|
||||
desc += "PLMN Select";
|
||||
break;
|
||||
case RRCTL_CONN_ESTABLISH:
|
||||
desc += "Connection Establish";
|
||||
break;
|
||||
case RRCTL_CONN_RELEASE:
|
||||
desc += "Connection Release";
|
||||
break;
|
||||
case RRCTL_DATA:
|
||||
desc += "Data (PDU)";
|
||||
break;
|
||||
case RRCTL_PAGING:
|
||||
desc += "Paging";
|
||||
break;
|
||||
case RRCTL_PARAM:
|
||||
desc += "Parameter";
|
||||
break;
|
||||
case RRCTL_SEC_MODE:
|
||||
desc += "Security Mode";
|
||||
break;
|
||||
case RRCTL_EXT_USIM:
|
||||
desc += "(U)SIM Specific";
|
||||
break;
|
||||
case RRCTL_RESERVED:
|
||||
desc += "RFU (Reserved for Further Use)";
|
||||
break;
|
||||
default:
|
||||
desc += "<UNKNOWN>";
|
||||
}
|
||||
|
||||
desc += " ";
|
||||
|
||||
switch (disc) {
|
||||
case RRCTL_REQ:
|
||||
desc += "Request";
|
||||
break;
|
||||
case RRCTL_IND:
|
||||
desc += "Indication";
|
||||
break;
|
||||
case RRCTL_CNF:
|
||||
desc += "Confirmation";
|
||||
break;
|
||||
case RRCTL_ERR:
|
||||
desc += "Error";
|
||||
break;
|
||||
}
|
||||
|
||||
if (len > 0) {
|
||||
desc += " (length ";
|
||||
desc += std::to_string(len);
|
||||
desc += ")";
|
||||
}
|
||||
|
||||
return desc;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace codec {
|
||||
|
||||
struct proto::msg_hdr* enc_hdr(srslte::byte_buffer_t& buf,
|
||||
proto::msg_type type,
|
||||
proto::msg_disc disc,
|
||||
uint16_t len)
|
||||
{
|
||||
struct proto::msg_hdr hdr = {
|
||||
#if defined(__LITTLE_ENDIAN_BITFIELD)
|
||||
.disc = (uint8_t) disc,
|
||||
.type = (uint8_t) type,
|
||||
#elif defined(__BIG_ENDIAN_BITFIELD)
|
||||
.type = (uint8_t) type,
|
||||
.disc = (uint8_t) disc,
|
||||
#else
|
||||
#error "Please fix <asm/byteorder.h>"
|
||||
#endif
|
||||
.len = ntohs(len),
|
||||
};
|
||||
|
||||
buf.append_bytes((const uint8_t*) &hdr, sizeof(hdr));
|
||||
|
||||
return reinterpret_cast<struct proto::msg_hdr*> (&buf.msg[0]);
|
||||
}
|
||||
|
||||
const uint8_t* dec_hdr(const srslte::byte_buffer_t& buf,
|
||||
proto::msg_type& type,
|
||||
proto::msg_disc& disc,
|
||||
uint16_t& len)
|
||||
{
|
||||
const struct proto::msg_hdr* hdr;
|
||||
|
||||
// Make sure at least header is present
|
||||
if (buf.N_bytes < sizeof(*hdr))
|
||||
throw codec::error("header is too short");
|
||||
|
||||
hdr = reinterpret_cast<const struct proto::msg_hdr*> (buf.msg);
|
||||
type = static_cast<proto::msg_type> (hdr->type);
|
||||
disc = static_cast<proto::msg_disc> (hdr->disc);
|
||||
len = htons(hdr->len);
|
||||
|
||||
// Make sure the whole message fits
|
||||
if (buf.N_bytes < sizeof(*hdr) + len)
|
||||
throw codec::error("body is too short");
|
||||
|
||||
// Return pointer to the payload (if present)
|
||||
return len ? hdr->data : NULL;
|
||||
}
|
||||
|
||||
void enc_plmn_search_res(srslte::byte_buffer_t& buf,
|
||||
const srsue::rrc_interface_nas::found_plmn_t* plmns,
|
||||
size_t nof_plmns)
|
||||
{
|
||||
struct proto::msg_plmn_search_res msg;
|
||||
uint16_t msg_len;
|
||||
|
||||
if (nof_plmns > 16)
|
||||
throw codec::error("too many PLMNS to encode");
|
||||
msg.nof_plmns = static_cast<uint8_t> (nof_plmns);
|
||||
|
||||
for (size_t i = 0; i < nof_plmns; i++) {
|
||||
plmns[i].plmn_id.to_rrctl_bytes(msg.plmns[i].mcc, msg.plmns[i].mnc);
|
||||
msg.plmns[i].tac = htons(plmns[i].tac);
|
||||
}
|
||||
|
||||
msg_len = sizeof(proto::msg_plmn_search_res::plmn) * nof_plmns + 1;
|
||||
enc_hdr(buf, proto::RRCTL_PLMN_SEARCH, proto::RRCTL_CNF, msg_len);
|
||||
buf.append_bytes((uint8_t *) &msg, msg_len);
|
||||
}
|
||||
|
||||
void dec_plmn_select_req(std::pair<uint16_t, uint16_t>& mcc_mnc,
|
||||
const uint8_t* payload, size_t len)
|
||||
{
|
||||
const struct proto::msg_plmn_select_req* msg;
|
||||
struct srslte::plmn_id_t plmn_id;
|
||||
|
||||
if (len < sizeof(*msg))
|
||||
throw codec::error("body is too short");
|
||||
|
||||
msg = reinterpret_cast<const struct proto::msg_plmn_select_req*> (payload);
|
||||
plmn_id.from_rrctl_bytes(msg->mcc, msg->mnc);
|
||||
mcc_mnc = plmn_id.to_number();
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
const struct proto::msg_conn_establish_req* msg;
|
||||
|
||||
if (len < sizeof(*msg))
|
||||
throw codec::error("body is too short");
|
||||
|
||||
msg = reinterpret_cast<const struct proto::msg_conn_establish_req*> (payload);
|
||||
cause = static_cast<srslte::establishment_cause_t> (msg->cause);
|
||||
pdu_len = len - 1;
|
||||
pdu = msg->pdu;
|
||||
}
|
||||
|
||||
void enc_data_ind(srslte::byte_buffer_t& buf,
|
||||
const uint8_t *pdu, size_t pdu_len,
|
||||
uint32_t lcid)
|
||||
{
|
||||
struct proto::msg_data msg;
|
||||
|
||||
msg.lcid = htonl(lcid);
|
||||
|
||||
enc_hdr(buf, proto::RRCTL_DATA, proto::RRCTL_IND, sizeof(msg) + pdu_len);
|
||||
buf.append_bytes((const uint8_t*) &msg, sizeof(msg));
|
||||
buf.append_bytes(pdu, pdu_len);
|
||||
}
|
||||
|
||||
void enc_paging_ind(srslte::byte_buffer_t& buf,
|
||||
srslte::s_tmsi_t* ue_identity)
|
||||
{
|
||||
struct proto::msg_paging_ind msg;
|
||||
|
||||
msg.ueid.m_tmsi = htonl(ue_identity->m_tmsi);
|
||||
msg.ueid.mmec = ue_identity->mmec;
|
||||
|
||||
enc_hdr(buf, proto::RRCTL_PAGING, proto::RRCTL_IND, sizeof(msg));
|
||||
buf.append_bytes((const uint8_t*) &msg, sizeof(msg));
|
||||
}
|
||||
|
||||
} // namespace codec
|
||||
|
||||
} // namespace rrctl
|
|
@ -231,11 +231,11 @@ int security_command_test()
|
|||
usim.init(&args);
|
||||
|
||||
{
|
||||
srsue::nas nas(&stack.task_sched);
|
||||
nas_args_t cfg;
|
||||
cfg.eia = "1,2,3";
|
||||
cfg.eea = "0,1,2,3";
|
||||
nas.init(&usim, &rrc_dummy, &gw, cfg);
|
||||
srsue::nas nas(&stack.task_sched, cfg);
|
||||
nas.init(&usim, &rrc_dummy, &gw);
|
||||
rrc_dummy.init(&nas);
|
||||
|
||||
// push auth request PDU to NAS to generate security context
|
||||
|
@ -299,10 +299,10 @@ int mme_attach_request_test()
|
|||
nas_cfg.apn_name = "test123";
|
||||
|
||||
test_stack_dummy stack(&pdcp_dummy);
|
||||
srsue::nas nas(&stack.task_sched);
|
||||
srsue::nas nas(&stack.task_sched, nas_cfg);
|
||||
srsue::gw gw;
|
||||
|
||||
nas.init(&usim, &rrc_dummy, &gw, nas_cfg);
|
||||
nas.init(&usim, &rrc_dummy, &gw);
|
||||
rrc_dummy.init(&nas);
|
||||
|
||||
gw_args_t gw_args;
|
||||
|
@ -377,13 +377,13 @@ int esm_info_request_test()
|
|||
pool = byte_buffer_pool::get_instance();
|
||||
|
||||
{
|
||||
srsue::nas nas(&stack.task_sched);
|
||||
nas_args_t cfg;
|
||||
cfg.apn_name = "srslte";
|
||||
cfg.apn_user = "srsuser";
|
||||
cfg.apn_pass = "srspass";
|
||||
cfg.force_imsi_attach = true;
|
||||
nas.init(&usim, &rrc_dummy, &gw, cfg);
|
||||
srsue::nas nas(&stack.task_sched, cfg);
|
||||
nas.init(&usim, &rrc_dummy, &gw);
|
||||
|
||||
// push ESM info request PDU to NAS to generate response
|
||||
unique_byte_buffer_t tmp = srslte::allocate_unique_buffer(*pool, true);
|
||||
|
@ -427,10 +427,10 @@ int dedicated_eps_bearer_test()
|
|||
|
||||
srslte::byte_buffer_pool* pool = byte_buffer_pool::get_instance();
|
||||
|
||||
srsue::nas nas(&stack.task_sched);
|
||||
nas_args_t cfg = {};
|
||||
cfg.force_imsi_attach = true; // make sure we get a fresh security context
|
||||
nas.init(&usim, &rrc_dummy, &gw, cfg);
|
||||
srsue::nas nas(&stack.task_sched, cfg);
|
||||
nas.init(&usim, &rrc_dummy, &gw);
|
||||
|
||||
// push dedicated EPS bearer PDU to NAS
|
||||
unique_byte_buffer_t tmp = srslte::allocate_unique_buffer(*pool, true);
|
||||
|
|
|
@ -173,7 +173,7 @@ public:
|
|||
class nas_test : public srsue::nas
|
||||
{
|
||||
public:
|
||||
nas_test(srslte::task_sched_handle t) : srsue::nas(t) {}
|
||||
nas_test(srslte::task_sched_handle t) : srsue::nas(t, {}) {}
|
||||
bool is_attached() override { return false; }
|
||||
};
|
||||
|
||||
|
|
|
@ -163,6 +163,16 @@ imei = 353490069873319
|
|||
#eia = 1,2
|
||||
#eea = 0,1,2
|
||||
|
||||
#####################################################################
|
||||
# External NAS interface configuration
|
||||
#
|
||||
# enable: Disable the built-in NAS implementation, provide external interface
|
||||
# sock_path: UNIX socket path of the external interface
|
||||
#####################################################################
|
||||
[extnas]
|
||||
#enable = false
|
||||
#sock_path = /tmp/ue_extnas.sock
|
||||
|
||||
#####################################################################
|
||||
# GW configuration
|
||||
#
|
||||
|
|
Loading…
Reference in New Issue