mirror of https://github.com/pvnis/srsRAN_4G.git
new asn1 rrc library
parent
6bea1814c9
commit
0204db2e12
@ -0,0 +1,975 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2013-2017 Software Radio Systems Limited
|
||||||
|
|
||||||
|
This file is part of srsLTE
|
||||||
|
|
||||||
|
srsLTE is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Affero General Public License as
|
||||||
|
published by the Free Software Foundation, either version 3 of
|
||||||
|
the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
srsLTE is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Affero General Public License for more details.
|
||||||
|
|
||||||
|
A copy of the GNU Affero General Public License can be found in
|
||||||
|
the LICENSE file in the top-level directory of this distribution
|
||||||
|
and at http://www.gnu.org/licenses/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SRSASN_COMMON_UTILS_H
|
||||||
|
#define SRSASN_COMMON_UTILS_H
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cmath>
|
||||||
|
#include <cstring>
|
||||||
|
#include <sstream>
|
||||||
|
#include <stdarg.h> /* va_list, va_start, va_arg, va_end */
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
// TODOS/FIXME:
|
||||||
|
// - ext flag as an template arg?
|
||||||
|
// - custom allocators?
|
||||||
|
|
||||||
|
namespace asn1 {
|
||||||
|
|
||||||
|
#define ASN_16K 16383
|
||||||
|
|
||||||
|
/************************
|
||||||
|
logging
|
||||||
|
************************/
|
||||||
|
|
||||||
|
typedef enum { LOG_LEVEL_INFO, LOG_LEVEL_DEBUG, LOG_LEVEL_WARN, LOG_LEVEL_ERROR } srsasn_logger_level_t;
|
||||||
|
|
||||||
|
typedef void (*log_handler_t)(srsasn_logger_level_t log_level, void* ctx, const char* str);
|
||||||
|
|
||||||
|
void vlog_print(log_handler_t handler, void* ctx, srsasn_logger_level_t log_level, const char* format, va_list args);
|
||||||
|
|
||||||
|
void srsasn_log_register_handler(void* ctx, log_handler_t handler);
|
||||||
|
|
||||||
|
void srsasn_log_print(srsasn_logger_level_t log_level, const char* format, ...);
|
||||||
|
|
||||||
|
/************************
|
||||||
|
error handling
|
||||||
|
************************/
|
||||||
|
|
||||||
|
enum SRSASN_CODE { SRSASN_SUCCESS, SRSASN_ERROR_ENCODE_FAIL, SRSASN_ERROR_DECODE_FAIL };
|
||||||
|
|
||||||
|
void log_error_code(SRSASN_CODE code, const char* filename, int line);
|
||||||
|
|
||||||
|
#define HANDLE_CODE(ret) \
|
||||||
|
{ \
|
||||||
|
SRSASN_CODE macrocode = (ret); \
|
||||||
|
if (macrocode != SRSASN_SUCCESS) { \
|
||||||
|
log_error_code(macrocode, __FILE__, __LINE__); \
|
||||||
|
return macrocode; \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
/************************
|
||||||
|
bit_ref
|
||||||
|
************************/
|
||||||
|
|
||||||
|
struct ValOrError {
|
||||||
|
uint32_t val;
|
||||||
|
SRSASN_CODE code;
|
||||||
|
ValOrError() : val(0), code(SRSASN_SUCCESS) {}
|
||||||
|
ValOrError(uint32_t val_, SRSASN_CODE code_) : val(val_), code(code_) {}
|
||||||
|
};
|
||||||
|
ValOrError unpack_bits(uint8_t*& ptr, uint8_t& offset, uint8_t* max_ptr, uint32_t n_bits);
|
||||||
|
|
||||||
|
class bit_ref
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
bit_ref();
|
||||||
|
bit_ref(uint8_t* start_ptr_, uint32_t max_size_);
|
||||||
|
|
||||||
|
int distance(const bit_ref& other) const;
|
||||||
|
int distance(uint8_t* ref_ptr) const;
|
||||||
|
int distance() const;
|
||||||
|
int distance_bytes(uint8_t* ref_ptr) const;
|
||||||
|
int distance_bytes() const;
|
||||||
|
|
||||||
|
SRSASN_CODE pack(uint32_t val, uint32_t n_bits);
|
||||||
|
template <class T>
|
||||||
|
SRSASN_CODE unpack(T& val, uint32_t n_bits)
|
||||||
|
{
|
||||||
|
ValOrError ret = unpack_bits(ptr, offset, max_ptr, n_bits);
|
||||||
|
val = ret.val;
|
||||||
|
return ret.code;
|
||||||
|
}
|
||||||
|
SRSASN_CODE align_bytes();
|
||||||
|
SRSASN_CODE align_bytes_zero();
|
||||||
|
void set(uint8_t* start_ptr_, uint32_t max_size_);
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint8_t* ptr;
|
||||||
|
uint8_t offset;
|
||||||
|
uint8_t* start_ptr;
|
||||||
|
uint8_t* max_ptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
function helpers
|
||||||
|
*********************/
|
||||||
|
template <class T>
|
||||||
|
class dyn_array
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef T item_type;
|
||||||
|
dyn_array() : data_(NULL), size_(0), cap_(0) {}
|
||||||
|
dyn_array(uint32_t new_size) : size_(new_size), cap_(new_size) { data_ = new T[size_]; }
|
||||||
|
dyn_array(const dyn_array<T>& other)
|
||||||
|
{
|
||||||
|
size_ = other.size_;
|
||||||
|
cap_ = other.cap_;
|
||||||
|
data_ = new T[cap_];
|
||||||
|
std::copy(&other[0], &other[size_], data_);
|
||||||
|
}
|
||||||
|
~dyn_array()
|
||||||
|
{
|
||||||
|
if (data_ != NULL) {
|
||||||
|
delete[] data_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
uint32_t size() const { return size_; }
|
||||||
|
uint32_t capacity() const { return cap_; }
|
||||||
|
T& operator[](uint32_t idx) { return data_[idx]; }
|
||||||
|
const T& operator[](uint32_t idx) const { return data_[idx]; }
|
||||||
|
dyn_array<T>& operator=(const dyn_array<T>& other)
|
||||||
|
{
|
||||||
|
if (this == &other) {
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
resize(other.size());
|
||||||
|
std::copy(&other[0], &other[size_], data_);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
void resize(uint32_t new_size, uint32_t new_cap = 0)
|
||||||
|
{
|
||||||
|
if (new_size == size_) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (cap_ >= new_size) {
|
||||||
|
size_ = new_size;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
T* old_data = data_;
|
||||||
|
cap_ = new_size > new_cap ? new_size : new_cap;
|
||||||
|
if (cap_ > 0) {
|
||||||
|
data_ = new T[cap_];
|
||||||
|
if (old_data != NULL) {
|
||||||
|
std::copy(&old_data[0], &old_data[size_], data_);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
data_ = NULL;
|
||||||
|
}
|
||||||
|
size_ = new_size;
|
||||||
|
if (old_data != NULL) {
|
||||||
|
delete[] old_data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bool operator==(const dyn_array<T>& other) const
|
||||||
|
{
|
||||||
|
return size() == other.size() and std::equal(data_, data_ + size(), other.data_);
|
||||||
|
}
|
||||||
|
void push_back(const T& elem)
|
||||||
|
{
|
||||||
|
resize(size() + 1, size() * 2);
|
||||||
|
data_[size() - 1] = elem;
|
||||||
|
}
|
||||||
|
T& back() { return data_[size() - 1]; }
|
||||||
|
const T& back() const { return data_[size() - 1]; }
|
||||||
|
T* data() { return &data_[0]; }
|
||||||
|
const T* data() const { return &data_[0]; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
T* data_;
|
||||||
|
uint32_t size_, cap_;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T, uint32_t MAX_N>
|
||||||
|
class bounded_array
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef T item_type;
|
||||||
|
bounded_array(uint32_t size_ = 0) : current_size(size_) {}
|
||||||
|
static uint32_t capacity() { return MAX_N; }
|
||||||
|
uint32_t size() const { return current_size; }
|
||||||
|
T& operator[](uint32_t idx) { return data_[idx]; }
|
||||||
|
const T& operator[](uint32_t idx) const { return data_[idx]; }
|
||||||
|
bool operator==(const bounded_array<T, MAX_N>& other) const
|
||||||
|
{
|
||||||
|
return size() == other.size() and std::equal(data_, data_ + size(), other.data_);
|
||||||
|
}
|
||||||
|
void resize(uint32_t new_size) { current_size = new_size; }
|
||||||
|
void push_back(const T& elem)
|
||||||
|
{
|
||||||
|
if (current_size >= MAX_N) {
|
||||||
|
srsasn_log_print(LOG_LEVEL_ERROR, "Maximum size %d achieved for bounded_array.\n", MAX_N);
|
||||||
|
}
|
||||||
|
data_[current_size++] = elem;
|
||||||
|
}
|
||||||
|
T& back() { return data_[current_size - 1]; }
|
||||||
|
const T& back() const { return data_[current_size - 1]; }
|
||||||
|
T* data() { return &data_[0]; }
|
||||||
|
const T* data() const { return &data_[0]; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
T data_[MAX_N];
|
||||||
|
uint32_t current_size;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T, uint32_t N>
|
||||||
|
class fixed_array
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef T item_type;
|
||||||
|
static uint32_t size() { return N; }
|
||||||
|
T& operator[](uint32_t idx) { return data_[idx]; }
|
||||||
|
const T& operator[](uint32_t idx) const { return data_[idx]; }
|
||||||
|
bool operator==(const fixed_array<T, N>& other) const { return std::equal(data_, data_ + size(), other.data_); }
|
||||||
|
T& back() { return data_[size() - 1]; }
|
||||||
|
const T& back() const { return data_[size() - 1]; }
|
||||||
|
T* data() { return &data_[0]; }
|
||||||
|
const T* data() const { return &data_[0]; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
T data_[N];
|
||||||
|
};
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
ext packing
|
||||||
|
*********************/
|
||||||
|
|
||||||
|
SRSASN_CODE pack_unsupported_ext_flag(bit_ref& bref, bool ext);
|
||||||
|
SRSASN_CODE unpack_unsupported_ext_flag(bool& ext, bit_ref& bref);
|
||||||
|
|
||||||
|
/************************
|
||||||
|
enum packing
|
||||||
|
************************/
|
||||||
|
|
||||||
|
SRSASN_CODE pack_enum(bit_ref& bref, uint32_t enum_val, uint32_t nbits);
|
||||||
|
SRSASN_CODE pack_enum(bit_ref& bref, uint32_t enum_val, uint32_t nbits, uint32_t nof_noext);
|
||||||
|
SRSASN_CODE pack_enum(bit_ref& bref, uint32_t e, uint32_t nof_types, uint32_t nof_exts, bool has_ext);
|
||||||
|
ValOrError unpack_enum(uint32_t nof_types, uint32_t nof_exts, bool has_ext, bit_ref& bref);
|
||||||
|
template <typename EnumType>
|
||||||
|
SRSASN_CODE pack_enum(bit_ref& bref, EnumType e)
|
||||||
|
{
|
||||||
|
return pack_enum(bref, e, EnumType::nof_types, EnumType::nof_exts, EnumType::has_ext);
|
||||||
|
}
|
||||||
|
template <typename EnumType>
|
||||||
|
SRSASN_CODE unpack_enum(EnumType& e, bit_ref& bref)
|
||||||
|
{
|
||||||
|
ValOrError ret = unpack_enum(EnumType::nof_types, EnumType::nof_exts, EnumType::has_ext, bref);
|
||||||
|
e = (typename EnumType::options)ret.val;
|
||||||
|
return ret.code;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct EnumPacker {
|
||||||
|
template <class EnumType>
|
||||||
|
SRSASN_CODE pack(bit_ref& bref, EnumType e)
|
||||||
|
{
|
||||||
|
return pack_enum(bref, e);
|
||||||
|
}
|
||||||
|
template <class EnumType>
|
||||||
|
SRSASN_CODE unpack(EnumType& e, bit_ref& bref)
|
||||||
|
{
|
||||||
|
return unpack_enum(e, bref);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
template <class EnumType>
|
||||||
|
bool string_to_enum(EnumType& e, const std::string& s)
|
||||||
|
{
|
||||||
|
for (uint32_t i = 0; i < EnumType::nof_types; ++i) {
|
||||||
|
e = (typename EnumType::options)i;
|
||||||
|
if (e.to_string() == s) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
template <class EnumType, class NumberType>
|
||||||
|
bool number_to_enum(EnumType& e, NumberType val)
|
||||||
|
{
|
||||||
|
for (uint32_t i = 0; i < e.nof_types; ++i) {
|
||||||
|
e = (typename EnumType::options)i;
|
||||||
|
if (e.to_number() == val) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
template <class EnumType>
|
||||||
|
bool number_string_to_enum(EnumType& e, const std::string& val)
|
||||||
|
{
|
||||||
|
for (uint32_t i = 0; i < e.nof_types; ++i) {
|
||||||
|
e = (typename EnumType::options)i;
|
||||||
|
if (e.to_number_string() == val) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/************************
|
||||||
|
integer packing
|
||||||
|
************************/
|
||||||
|
|
||||||
|
// Constrained Whole Number
|
||||||
|
template <class IntType>
|
||||||
|
SRSASN_CODE pack_unalign_integer(bit_ref& bref, IntType n, IntType lb, IntType ub);
|
||||||
|
template <class IntType>
|
||||||
|
SRSASN_CODE unpack_unalign_integer(IntType& n, bit_ref& bref, IntType lb, IntType ub);
|
||||||
|
template <class IntType>
|
||||||
|
struct UnalignedIntegerPacker {
|
||||||
|
UnalignedIntegerPacker(IntType, IntType);
|
||||||
|
IntType lb;
|
||||||
|
IntType ub;
|
||||||
|
SRSASN_CODE pack(bit_ref& bref, IntType n);
|
||||||
|
SRSASN_CODE unpack(IntType& n, bit_ref& bref);
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class IntType>
|
||||||
|
SRSASN_CODE pack_align_integer(bit_ref& bref, IntType n, IntType lb, IntType ub);
|
||||||
|
template <typename IntType>
|
||||||
|
SRSASN_CODE unpack_align_integer(IntType& intval, bit_ref& bref, IntType lb, IntType ub);
|
||||||
|
template <class IntType>
|
||||||
|
struct AlignedIntegerPacker {
|
||||||
|
AlignedIntegerPacker(IntType lb_, IntType ub_);
|
||||||
|
IntType lb;
|
||||||
|
IntType ub;
|
||||||
|
SRSASN_CODE pack(bit_ref& bref, IntType n);
|
||||||
|
SRSASN_CODE unpack(IntType& n, bit_ref& bref);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Normally Small non-negative whole number
|
||||||
|
template <typename UintType>
|
||||||
|
SRSASN_CODE pack_norm_small_integer(bit_ref& bref, UintType n);
|
||||||
|
template <typename UintType>
|
||||||
|
SRSASN_CODE unpack_norm_small_integer(UintType& n, bit_ref& bref);
|
||||||
|
|
||||||
|
// Unconstrained Whole Number
|
||||||
|
// FIXME: Implement
|
||||||
|
inline SRSASN_CODE pack_unconstrained_integer(bit_ref& bref, int64_t n)
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
srsasn_log_print(LOG_LEVEL_ERROR, "Not implemented\n");
|
||||||
|
return SRSASN_SUCCESS;
|
||||||
|
}
|
||||||
|
inline SRSASN_CODE unpack_unconstrained_integer(int64_t& n, bit_ref& bref)
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
srsasn_log_print(LOG_LEVEL_ERROR, "Not implemented\n");
|
||||||
|
return SRSASN_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/************************
|
||||||
|
length determinant
|
||||||
|
************************/
|
||||||
|
|
||||||
|
// Pack as whole constrained number
|
||||||
|
template <typename IntType>
|
||||||
|
SRSASN_CODE pack_length(bit_ref& bref, IntType n, IntType lb, IntType ub);
|
||||||
|
template <typename IntType>
|
||||||
|
SRSASN_CODE unpack_length(IntType& n, bit_ref& bref, IntType lb, IntType ub);
|
||||||
|
|
||||||
|
// Pack as a small non-negative whole number
|
||||||
|
SRSASN_CODE pack_length(bit_ref& ref, uint32_t val);
|
||||||
|
SRSASN_CODE unpack_length(uint32_t& val, bit_ref& ref);
|
||||||
|
|
||||||
|
/************************
|
||||||
|
General Packer/Unpacker
|
||||||
|
************************/
|
||||||
|
|
||||||
|
struct BitPacker {
|
||||||
|
BitPacker(uint32_t nof_bits_) : nof_bits(nof_bits_) {}
|
||||||
|
template <typename T>
|
||||||
|
SRSASN_CODE pack(bit_ref& bref, const T& topack)
|
||||||
|
{
|
||||||
|
bref.pack(topack, nof_bits);
|
||||||
|
return SRSASN_SUCCESS;
|
||||||
|
}
|
||||||
|
template <typename T>
|
||||||
|
SRSASN_CODE unpack(T& tounpack, bit_ref& bref)
|
||||||
|
{
|
||||||
|
return bref.unpack(tounpack, nof_bits);
|
||||||
|
}
|
||||||
|
uint32_t nof_bits;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Packer {
|
||||||
|
template <typename T>
|
||||||
|
SRSASN_CODE pack(bit_ref& bref, const T& topack)
|
||||||
|
{
|
||||||
|
return topack.pack(bref);
|
||||||
|
}
|
||||||
|
template <typename T>
|
||||||
|
SRSASN_CODE unpack(T& tounpack, bit_ref& bref)
|
||||||
|
{
|
||||||
|
return tounpack.unpack(bref);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
common octstring
|
||||||
|
*********************/
|
||||||
|
|
||||||
|
// helper functions common to all octstring implementations
|
||||||
|
uint64_t octstring_to_number(const uint8_t* ptr, uint32_t nbytes);
|
||||||
|
void number_to_octstring(uint8_t* ptr, uint64_t number, uint32_t nbytes);
|
||||||
|
std::string octstring_to_string(const uint8_t* ptr, uint32_t N);
|
||||||
|
void string_to_octstring(uint8_t* ptr, const std::string& str);
|
||||||
|
|
||||||
|
/************************
|
||||||
|
fixed_octstring
|
||||||
|
************************/
|
||||||
|
|
||||||
|
template <uint32_t N>
|
||||||
|
class fixed_octstring
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
const uint8_t& operator[](uint32_t idx) const { return octets_[idx]; }
|
||||||
|
uint8_t& operator[](uint32_t idx) { return octets_[idx]; }
|
||||||
|
bool operator==(const fixed_octstring<N>& other) const { return octets_ == other.octets_; }
|
||||||
|
uint8_t* data() { return &octets_[0]; }
|
||||||
|
const uint8_t* data() const { return &octets_[0]; }
|
||||||
|
|
||||||
|
static uint32_t size() { return N; }
|
||||||
|
std::string to_string() const { return octstring_to_string(&octets_[0], N); }
|
||||||
|
fixed_octstring<N>& from_string(const std::string& hexstr)
|
||||||
|
{
|
||||||
|
if (hexstr.size() != 2 * N) {
|
||||||
|
srsasn_log_print(LOG_LEVEL_ERROR, "The provided hex string size is not valid (%d!=2*%d).\n", hexstr.size(), N);
|
||||||
|
} else {
|
||||||
|
string_to_octstring(&octets_[0], hexstr);
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
uint64_t to_number() const { return octstring_to_number(&octets_[0], size()); }
|
||||||
|
fixed_octstring<N>& from_number(uint64_t val)
|
||||||
|
{
|
||||||
|
number_to_octstring(&octets_[0], val, size());
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
SRSASN_CODE pack(bit_ref& bref) const;
|
||||||
|
SRSASN_CODE unpack(bit_ref& bref);
|
||||||
|
|
||||||
|
private:
|
||||||
|
fixed_array<uint8_t, N> octets_;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <uint32_t N>
|
||||||
|
SRSASN_CODE fixed_octstring<N>::pack(bit_ref& bref) const
|
||||||
|
{
|
||||||
|
// if(N > 2) { // X.691 Sec.16
|
||||||
|
// bref.align_bytes_zero();
|
||||||
|
// }
|
||||||
|
for (uint32_t i = 0; i < size(); ++i) {
|
||||||
|
bref.pack(octets_[i], 8);
|
||||||
|
}
|
||||||
|
return SRSASN_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <uint32_t N>
|
||||||
|
SRSASN_CODE fixed_octstring<N>::unpack(bit_ref& bref)
|
||||||
|
{
|
||||||
|
// if(N > 2) { // X.691 Sec.16
|
||||||
|
// bref.align_bytes_zero();
|
||||||
|
// }
|
||||||
|
for (uint32_t i = 0; i < size(); ++i) {
|
||||||
|
HANDLE_CODE(bref.unpack(octets_[i], 8));
|
||||||
|
}
|
||||||
|
return SRSASN_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/************************
|
||||||
|
dyn_octstring
|
||||||
|
************************/
|
||||||
|
|
||||||
|
class dyn_octstring
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
dyn_octstring() {}
|
||||||
|
dyn_octstring(uint32_t new_size) : octets_(new_size) {}
|
||||||
|
|
||||||
|
const uint8_t& operator[](uint32_t idx) const { return octets_[idx]; }
|
||||||
|
uint8_t& operator[](uint32_t idx) { return octets_[idx]; }
|
||||||
|
bool operator==(const dyn_octstring& other) const { return octets_ == other.octets_; }
|
||||||
|
void resize(uint32_t new_size) { octets_.resize(new_size); }
|
||||||
|
uint32_t size() const { return octets_.size(); }
|
||||||
|
uint8_t* data() { return &octets_[0]; }
|
||||||
|
const uint8_t* data() const { return &octets_[0]; }
|
||||||
|
|
||||||
|
SRSASN_CODE pack(bit_ref& ie_ref) const;
|
||||||
|
SRSASN_CODE unpack(bit_ref& ie_ref);
|
||||||
|
std::string to_string() const;
|
||||||
|
dyn_octstring& from_string(const std::string& hexstr);
|
||||||
|
uint64_t to_number() const { return octstring_to_number(&octets_[0], size()); }
|
||||||
|
dyn_octstring& from_number(uint64_t val)
|
||||||
|
{
|
||||||
|
number_to_octstring(&octets_[0], val, size());
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
dyn_array<uint8_t> octets_;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
common bitstring
|
||||||
|
*********************/
|
||||||
|
|
||||||
|
// helper functions common to all bitstring implementations
|
||||||
|
uint64_t bitstring_to_number(const uint8_t* ptr, uint32_t nbits);
|
||||||
|
void number_to_bitstring(uint8_t* ptr, uint64_t number, uint32_t nbits);
|
||||||
|
std::string bitstring_to_string(const uint8_t* ptr, uint32_t nbits);
|
||||||
|
inline bool bitstring_get(const uint8_t* ptr, uint32_t idx)
|
||||||
|
{
|
||||||
|
uint32_t byte_idx = idx / 8;
|
||||||
|
uint32_t offset = idx % 8;
|
||||||
|
return (ptr[byte_idx] & (1 << offset)) > 0;
|
||||||
|
}
|
||||||
|
inline void bitstring_set(uint8_t* ptr, uint32_t idx, bool value)
|
||||||
|
{
|
||||||
|
uint32_t byte_idx = idx / 8;
|
||||||
|
uint32_t offset = idx % 8;
|
||||||
|
if (value) {
|
||||||
|
ptr[byte_idx] |= (1 << offset);
|
||||||
|
} else {
|
||||||
|
ptr[byte_idx] &= ((uint16_t)(1 << 8) - 1) - (1 << offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
fixed_bitstring
|
||||||
|
*********************/
|
||||||
|
|
||||||
|
// fixed bitstring pack/unpack helpers
|
||||||
|
SRSASN_CODE pack_fixed_bitstring(bit_ref& bref, const uint8_t* buf, uint32_t nbits);
|
||||||
|
SRSASN_CODE pack_fixed_bitstring(bit_ref& bref, const uint8_t* buf, uint32_t nbits, bool ext);
|
||||||
|
SRSASN_CODE unpack_fixed_bitstring(uint8_t* buf, bit_ref& bref, uint32_t nbits);
|
||||||
|
SRSASN_CODE unpack_fixed_bitstring(uint8_t* buf, bool& ext, bit_ref& bref, uint32_t nbits);
|
||||||
|
|
||||||
|
template <uint32_t N>
|
||||||
|
class fixed_bitstring
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
fixed_bitstring() { memset(&octets_[0], 0, nof_octets()); }
|
||||||
|
fixed_bitstring(const std::string& s)
|
||||||
|
{
|
||||||
|
if (s.size() != N) {
|
||||||
|
srsasn_log_print(LOG_LEVEL_ERROR, "The provided string size=%d does not match the bit string size=%d\n", s.size(),
|
||||||
|
N);
|
||||||
|
}
|
||||||
|
memset(&octets_[0], 0, nof_octets());
|
||||||
|
for (uint32_t i = 0; i < N; ++i)
|
||||||
|
this->set(N - i - 1, s[i] == '1');
|
||||||
|
}
|
||||||
|
bool get(uint32_t idx) const { return bitstring_get(&octets_[0], idx); }
|
||||||
|
void set(uint32_t idx, bool value) { bitstring_set(&octets_[0], idx, value); }
|
||||||
|
bool operator==(const fixed_bitstring<N>& other) const { return octets_ == other.octets_; }
|
||||||
|
bool operator==(const char* other_str) const
|
||||||
|
{
|
||||||
|
return strlen(other_str) == N and (*this) == fixed_bitstring<N>(other_str);
|
||||||
|
}
|
||||||
|
uint32_t nof_octets() const { return (uint32_t)ceilf(N / 8.0f); }
|
||||||
|
uint32_t length() const { return N; }
|
||||||
|
std::string to_string() const { return bitstring_to_string(&octets_[0], length()); }
|
||||||
|
uint64_t to_number() const { return bitstring_to_number(&octets_[0], length()); }
|
||||||
|
fixed_bitstring<N>& from_number(uint64_t val)
|
||||||
|
{
|
||||||
|
number_to_bitstring(&octets_[0], val, length());
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
uint8_t* data() { return &octets_[0]; }
|
||||||
|
const uint8_t* data() const { return &octets_[0]; }
|
||||||
|
|
||||||
|
SRSASN_CODE pack(bit_ref& bref) const { return pack_fixed_bitstring(bref, data(), N); }
|
||||||
|
SRSASN_CODE pack(bit_ref& bref, bool ext) const { return pack_fixed_bitstring(bref, data(), N, ext); }
|
||||||
|
SRSASN_CODE unpack(bit_ref& bref) { return unpack_fixed_bitstring(data(), bref, N); }
|
||||||
|
SRSASN_CODE unpack(bit_ref& bref, bool& ext) { return unpack_fixed_bitstring(data(), ext, bref, N); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
fixed_array<uint8_t, (uint32_t)((N + 7) / 8)> octets_; // ceil(N/8.0)
|
||||||
|
};
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
dyn_bitstring
|
||||||
|
*********************/
|
||||||
|
|
||||||
|
class dyn_bitstring
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
dyn_bitstring() : n_bits(0) {}
|
||||||
|
dyn_bitstring(uint32_t n_bits_);
|
||||||
|
dyn_bitstring(const char* s);
|
||||||
|
|
||||||
|
bool operator==(const dyn_bitstring& other) const { return octets_ == other.octets_; }
|
||||||
|
bool operator==(const char* other_str) const;
|
||||||
|
bool get(uint32_t idx) const { return bitstring_get(&octets_[0], idx); }
|
||||||
|
void set(uint32_t idx, bool value) { bitstring_set(&octets_[0], idx, value); }
|
||||||
|
|
||||||
|
void resize(uint32_t new_size);
|
||||||
|
uint32_t length() const { return n_bits; }
|
||||||
|
uint32_t nof_octets() const { return (uint32_t)ceilf(length() / 8.0f); }
|
||||||
|
std::string to_string() const { return bitstring_to_string(&octets_[0], length()); }
|
||||||
|
uint64_t to_number() const { return bitstring_to_number(&octets_[0], length()); }
|
||||||
|
dyn_bitstring& from_number(uint64_t val)
|
||||||
|
{
|
||||||
|
number_to_bitstring(&octets_[0], val, length());
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
const uint8_t* data() const { return &octets_[0]; }
|
||||||
|
uint8_t* data() { return &octets_[0]; }
|
||||||
|
|
||||||
|
SRSASN_CODE pack(bit_ref& bref, uint32_t lb = 0, uint32_t ub = 0) const;
|
||||||
|
SRSASN_CODE pack(bit_ref& bref, bool ext, uint32_t lb = 0, uint32_t ub = 0) const;
|
||||||
|
SRSASN_CODE unpack(bit_ref& bref, uint32_t lb = 0, uint32_t ub = 0);
|
||||||
|
SRSASN_CODE unpack(bit_ref& bref, bool& ext, uint32_t lb = 0, uint32_t ub = 0);
|
||||||
|
|
||||||
|
private:
|
||||||
|
dyn_array<uint8_t> octets_;
|
||||||
|
uint32_t n_bits;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
fixed sequence of
|
||||||
|
*********************/
|
||||||
|
|
||||||
|
// packers/unpackers for fixed_length sequence-of
|
||||||
|
template <class T, class ItemPacker>
|
||||||
|
SRSASN_CODE pack_fixed_seq_of(bit_ref& bref, const T* item_array, uint32_t nof_items, ItemPacker packer)
|
||||||
|
{
|
||||||
|
for (uint32_t i = 0; i < nof_items; ++i) {
|
||||||
|
HANDLE_CODE(packer.pack(bref, item_array[i]));
|
||||||
|
}
|
||||||
|
return SRSASN_SUCCESS;
|
||||||
|
}
|
||||||
|
template <class T>
|
||||||
|
SRSASN_CODE pack_fixed_seq_of(bit_ref& bref, const T* item_array, uint32_t nof_items)
|
||||||
|
{
|
||||||
|
for (uint32_t i = 0; i < nof_items; ++i) {
|
||||||
|
HANDLE_CODE(item_array[i].pack(bref));
|
||||||
|
}
|
||||||
|
return SRSASN_SUCCESS;
|
||||||
|
}
|
||||||
|
template <class T, class ItemUnpacker>
|
||||||
|
SRSASN_CODE unpack_fixed_seq_of(T* item_array, bit_ref& bref, uint32_t nof_items, ItemUnpacker unpacker)
|
||||||
|
{
|
||||||
|
for (uint32_t i = 0; i < nof_items; ++i) {
|
||||||
|
HANDLE_CODE(unpacker.unpack(item_array[i], bref));
|
||||||
|
}
|
||||||
|
return SRSASN_SUCCESS;
|
||||||
|
}
|
||||||
|
template <class T>
|
||||||
|
SRSASN_CODE unpack_fixed_seq_of(T* item_array, bit_ref& bref, uint32_t nof_items)
|
||||||
|
{
|
||||||
|
for (uint32_t i = 0; i < nof_items; ++i) {
|
||||||
|
HANDLE_CODE(item_array[i].unpack(bref));
|
||||||
|
}
|
||||||
|
return SRSASN_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class ItemPacker>
|
||||||
|
struct FixedSeqOfPacker {
|
||||||
|
FixedSeqOfPacker(uint32_t nof_items_, ItemPacker packer_) : nof_items(nof_items_), packer(packer_) {}
|
||||||
|
FixedSeqOfPacker(uint32_t nof_items_) : nof_items(nof_items_), packer(Packer()) {}
|
||||||
|
template <typename T>
|
||||||
|
SRSASN_CODE pack(bit_ref& bref, const T* topack)
|
||||||
|
{
|
||||||
|
return pack_fixed_seq_of(bref, topack, nof_items, packer);
|
||||||
|
}
|
||||||
|
template <typename T>
|
||||||
|
SRSASN_CODE unpack(T* tounpack, bit_ref& bref)
|
||||||
|
{
|
||||||
|
return unpack_fixed_seq_of(tounpack, bref, nof_items, packer);
|
||||||
|
}
|
||||||
|
uint32_t nof_items;
|
||||||
|
ItemPacker packer;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
dyn sequence of
|
||||||
|
*********************/
|
||||||
|
|
||||||
|
template <class ArrayType, class ItemPacker>
|
||||||
|
SRSASN_CODE pack_dyn_seq_of(bit_ref& bref, const ArrayType& seqof, uint32_t lb, uint32_t ub, ItemPacker packer)
|
||||||
|
{
|
||||||
|
HANDLE_CODE(pack_length(bref, seqof.size(), lb, ub));
|
||||||
|
for (uint32_t i = 0; i < seqof.size(); ++i) {
|
||||||
|
HANDLE_CODE(packer.pack(bref, seqof[i]));
|
||||||
|
}
|
||||||
|
return SRSASN_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class ArrayType>
|
||||||
|
SRSASN_CODE pack_dyn_seq_of(bit_ref& bref, const ArrayType& seqof, uint32_t lb, uint32_t ub)
|
||||||
|
{
|
||||||
|
HANDLE_CODE(pack_length(bref, seqof.size(), lb, ub));
|
||||||
|
for (uint32_t i = 0; i < seqof.size(); ++i) {
|
||||||
|
HANDLE_CODE(seqof[i].pack(bref));
|
||||||
|
}
|
||||||
|
return SRSASN_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class ArrayType, class ItemUnpacker>
|
||||||
|
SRSASN_CODE unpack_dyn_seq_of(ArrayType& seqof, bit_ref& bref, uint32_t lb, uint32_t ub, ItemUnpacker unpacker)
|
||||||
|
{
|
||||||
|
uint32_t nof_items;
|
||||||
|
HANDLE_CODE(unpack_length(nof_items, bref, lb, ub));
|
||||||
|
seqof.resize(nof_items);
|
||||||
|
for (uint32_t i = 0; i < nof_items; ++i) {
|
||||||
|
HANDLE_CODE(unpacker.unpack(seqof[i], bref));
|
||||||
|
}
|
||||||
|
return SRSASN_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class ArrayType>
|
||||||
|
SRSASN_CODE unpack_dyn_seq_of(ArrayType& seqof, bit_ref& bref, uint32_t lb, uint32_t ub)
|
||||||
|
{
|
||||||
|
uint32_t nof_items;
|
||||||
|
HANDLE_CODE(unpack_length(nof_items, bref, lb, ub));
|
||||||
|
seqof.resize(nof_items);
|
||||||
|
for (uint32_t i = 0; i < nof_items; ++i) {
|
||||||
|
HANDLE_CODE(seqof[i].unpack(bref));
|
||||||
|
}
|
||||||
|
return SRSASN_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class InnerPacker>
|
||||||
|
struct SeqOfPacker {
|
||||||
|
SeqOfPacker(uint32_t lb_, uint32_t ub_, InnerPacker packer_) : lb(lb_), ub(ub_), packer(packer_) {}
|
||||||
|
template <typename T>
|
||||||
|
SRSASN_CODE pack(bit_ref& bref, const T& topack)
|
||||||
|
{
|
||||||
|
return pack_dyn_seq_of(bref, topack, lb, ub, packer);
|
||||||
|
}
|
||||||
|
template <typename T>
|
||||||
|
SRSASN_CODE unpack(T& tounpack, bit_ref& bref)
|
||||||
|
{
|
||||||
|
return unpack_dyn_seq_of(tounpack, bref, lb, ub, packer);
|
||||||
|
}
|
||||||
|
InnerPacker packer;
|
||||||
|
uint32_t lb;
|
||||||
|
uint32_t ub;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
choice utils
|
||||||
|
*********************/
|
||||||
|
|
||||||
|
union alignment_t {
|
||||||
|
char c;
|
||||||
|
float f;
|
||||||
|
uint32_t i;
|
||||||
|
uint64_t i2;
|
||||||
|
double d;
|
||||||
|
long double d2;
|
||||||
|
uint32_t* ptr;
|
||||||
|
};
|
||||||
|
#define MAX2(a, b) ((a) > (b)) ? (a) : (b)
|
||||||
|
#define MAX4(a, b, c, d) MAX2((MAX2(a, b)), MAX2(c, d))
|
||||||
|
#define MAX8(a, b, c, d, e, f, g, h) MAX2((MAX4(a, b, c, d)), (MAX4(e, f, g, h)))
|
||||||
|
#define MAX12(a, b, c, d, e, f, g, h, i, j, k, l) MAX2((MAX8(a, b, c, d, e, f, g, h)), (MAX4(i, j, k, l)))
|
||||||
|
#define MAX16(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) \
|
||||||
|
MAX2((MAX8(a, b, c, d, e, f, g, h)), (MAX8(i, j, k, l, m, n, o, p)))
|
||||||
|
#define MAX32(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1, n1, \
|
||||||
|
o1, p1) \
|
||||||
|
MAX2((MAX16(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p)), \
|
||||||
|
(MAX16(a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1, n1, o1, p1)))
|
||||||
|
|
||||||
|
template <size_t SIZE>
|
||||||
|
class choice_buffer_t
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
struct __attribute__((__may_alias__)) bytes {
|
||||||
|
uint8_t buf_[MAX2(SIZE, 8)];
|
||||||
|
uint8_t* data() { return &buf_[0]; }
|
||||||
|
const uint8_t* data() const { return &buf_[0]; }
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
T& get()
|
||||||
|
{
|
||||||
|
return *((T*)buffer.buf_.data());
|
||||||
|
}
|
||||||
|
template <typename T>
|
||||||
|
const T& get() const
|
||||||
|
{
|
||||||
|
return *((T*)buffer.buf_.data());
|
||||||
|
}
|
||||||
|
template <typename T>
|
||||||
|
void destroy()
|
||||||
|
{
|
||||||
|
((T*)buffer.buf_.data())->~T();
|
||||||
|
}
|
||||||
|
template <typename T>
|
||||||
|
void init()
|
||||||
|
{
|
||||||
|
new (buffer.buf_.data()) T();
|
||||||
|
}
|
||||||
|
template <typename T>
|
||||||
|
void init(const T& other)
|
||||||
|
{
|
||||||
|
new (buffer.buf_.data()) T(other);
|
||||||
|
}
|
||||||
|
template <typename T>
|
||||||
|
void set(const T& other)
|
||||||
|
{
|
||||||
|
get<T>() = other;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
union {
|
||||||
|
alignment_t a_;
|
||||||
|
bytes buf_;
|
||||||
|
} buffer;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
copy_ptr
|
||||||
|
*********************/
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
class copy_ptr
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
copy_ptr() : ptr(NULL) {}
|
||||||
|
explicit copy_ptr(T* ptr_) :
|
||||||
|
ptr(ptr_) {} // it takes hold of the pointer (including destruction). You should use make_copy_ptr() in most cases
|
||||||
|
// instead of this ctor
|
||||||
|
copy_ptr(const copy_ptr<T>& other) { ptr = other.make_obj_(); } // it allocates new memory for the new object
|
||||||
|
~copy_ptr() { destroy_(); }
|
||||||
|
inline copy_ptr<T>& operator=(const copy_ptr<T>& other)
|
||||||
|
{
|
||||||
|
if (this != &other) {
|
||||||
|
acquire(other.make_obj_());
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
inline bool operator==(const copy_ptr<T>& other) const { return *ptr == *other; }
|
||||||
|
inline T* operator->() { return ptr; }
|
||||||
|
inline const T* operator->() const { return ptr; }
|
||||||
|
inline T& operator*() { return *ptr; } // like pointers, don't call this if ptr==NULL
|
||||||
|
inline const T& operator*() const { return *ptr; } // like pointers, don't call this if ptr==NULL
|
||||||
|
inline T* get() { return ptr; }
|
||||||
|
inline const T* get() const { return ptr; }
|
||||||
|
inline T* release()
|
||||||
|
{
|
||||||
|
T* ret = ptr;
|
||||||
|
ptr = NULL;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
inline void acquire(T* ptr_)
|
||||||
|
{
|
||||||
|
destroy_();
|
||||||
|
ptr = ptr_;
|
||||||
|
}
|
||||||
|
inline void reset() { acquire(NULL); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
inline void destroy_()
|
||||||
|
{
|
||||||
|
if (ptr != NULL) {
|
||||||
|
delete ptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
inline T* make_obj_() const { return (ptr == NULL) ? NULL : new T(*ptr); }
|
||||||
|
T* ptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
copy_ptr<T> make_copy_ptr(const T& t)
|
||||||
|
{
|
||||||
|
return copy_ptr<T>(new T(t));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
ext group
|
||||||
|
*********************/
|
||||||
|
|
||||||
|
class ext_groups_header
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ext_groups_header(uint32_t max_nof_groups, uint32_t nof_nogroups_ = 0);
|
||||||
|
bool& operator[](uint32_t idx);
|
||||||
|
|
||||||
|
SRSASN_CODE pack_nof_groups(bit_ref& bref) const;
|
||||||
|
SRSASN_CODE pack_group_flags(bit_ref& bref) const;
|
||||||
|
SRSASN_CODE pack(bit_ref& bref) const;
|
||||||
|
SRSASN_CODE unpack_nof_groups(bit_ref& bref);
|
||||||
|
SRSASN_CODE unpack_group_flags(bit_ref& bref);
|
||||||
|
SRSASN_CODE unpack(bit_ref& bref);
|
||||||
|
|
||||||
|
private:
|
||||||
|
mutable uint32_t nof_groups;
|
||||||
|
const uint32_t nof_nogroups;
|
||||||
|
bounded_array<bool, 20> groups;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
Var Length Field
|
||||||
|
*********************/
|
||||||
|
|
||||||
|
class varlength_field_pack_guard
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
varlength_field_pack_guard(bit_ref& bref);
|
||||||
|
~varlength_field_pack_guard();
|
||||||
|
|
||||||
|
private:
|
||||||
|
bit_ref brefstart;
|
||||||
|
// bit_ref bref0;
|
||||||
|
bit_ref* bref_tracker;
|
||||||
|
uint8_t buffer[1024];
|
||||||
|
};
|
||||||
|
|
||||||
|
class varlength_field_unpack_guard
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
varlength_field_unpack_guard(bit_ref& bref);
|
||||||
|
~varlength_field_unpack_guard();
|
||||||
|
|
||||||
|
private:
|
||||||
|
bit_ref bref0;
|
||||||
|
bit_ref* bref_tracker;
|
||||||
|
uint32_t len;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*******************
|
||||||
|
JsonWriter
|
||||||
|
*******************/
|
||||||
|
|
||||||
|
class json_writer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
json_writer();
|
||||||
|
void write_fieldname(const std::string& fieldname);
|
||||||
|
void write_str(const std::string& fieldname, const std::string& value);
|
||||||
|
void write_str(const std::string& value);
|
||||||
|
void write_int(const std::string& fieldname, int64_t value);
|
||||||
|
void write_int(int64_t value);
|
||||||
|
void write_bool(const std::string& fieldname, bool value);
|
||||||
|
void write_bool(bool value);
|
||||||
|
void write_null(const std::string& fieldname);
|
||||||
|
void write_null();
|
||||||
|
void start_obj(const std::string& fieldname = "");
|
||||||
|
void end_obj();
|
||||||
|
void start_array(const std::string& fieldname = "");
|
||||||
|
void end_array();
|
||||||
|
std::string to_string() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::stringstream ss;
|
||||||
|
std::string ident;
|
||||||
|
enum separator_t { COMMA, NEWLINE, NONE };
|
||||||
|
separator_t sep;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace asn1
|
||||||
|
|
||||||
|
#endif // SRSASN_COMMON_UTILS_H
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,91 +0,0 @@
|
|||||||
/**
|
|
||||||
*
|
|
||||||
* \section COPYRIGHT
|
|
||||||
*
|
|
||||||
* Copyright 2013-2015 Software Radio Systems Limited
|
|
||||||
*
|
|
||||||
* \section LICENSE
|
|
||||||
*
|
|
||||||
* This file is part of the srsUE library.
|
|
||||||
*
|
|
||||||
* srsUE is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as
|
|
||||||
* published by the Free Software Foundation, either version 3 of
|
|
||||||
* the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* srsUE is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* A copy of the GNU Affero General Public License can be found in
|
|
||||||
* the LICENSE file in the top-level directory of this distribution
|
|
||||||
* and at http://www.gnu.org/licenses/.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <assert.h>
|
|
||||||
#include <iostream>
|
|
||||||
#include <srslte/srslte.h>
|
|
||||||
#include "srslte/common/log_filter.h"
|
|
||||||
#include "srslte/asn1/liblte_rrc.h"
|
|
||||||
|
|
||||||
|
|
||||||
void basic_test() {
|
|
||||||
srslte::log_filter log1("RRC");
|
|
||||||
log1.set_level(srslte::LOG_LEVEL_DEBUG);
|
|
||||||
log1.set_hex_limit(128);
|
|
||||||
|
|
||||||
LIBLTE_BIT_MSG_STRUCT bit_buf;
|
|
||||||
LIBLTE_BIT_MSG_STRUCT bit_buf2;
|
|
||||||
LIBLTE_BYTE_MSG_STRUCT byte_buf;
|
|
||||||
LIBLTE_RRC_UL_DCCH_MSG_STRUCT ul_dcch_msg;
|
|
||||||
|
|
||||||
uint32_t rrc_message_len = 18;
|
|
||||||
uint8_t rrc_message[] = {0x08, 0x10, 0x49, 0x3C, 0x0D, 0x97, 0x89, 0x83,
|
|
||||||
0xC0, 0x84, 0x20, 0x82, 0x08, 0x21, 0x00, 0x01,
|
|
||||||
0xBC, 0x48};
|
|
||||||
|
|
||||||
srslte_bit_unpack_vector(rrc_message, bit_buf.msg, rrc_message_len*8);
|
|
||||||
bit_buf.N_bits = rrc_message_len*8;
|
|
||||||
liblte_rrc_unpack_ul_dcch_msg((LIBLTE_BIT_MSG_STRUCT*)&bit_buf, &ul_dcch_msg);
|
|
||||||
|
|
||||||
assert(ul_dcch_msg.msg_type == LIBLTE_RRC_UL_DCCH_MSG_TYPE_MEASUREMENT_REPORT);
|
|
||||||
LIBLTE_RRC_MEASUREMENT_REPORT_STRUCT *rep = &ul_dcch_msg.msg.measurement_report;
|
|
||||||
assert(rep->meas_id == 1);
|
|
||||||
assert(rep->pcell_rsrp_result == 73);
|
|
||||||
assert(rep->pcell_rsrq_result == 15);
|
|
||||||
assert(rep->have_meas_result_neigh_cells);
|
|
||||||
assert(rep->meas_result_neigh_cells_choice == LIBLTE_RRC_MEAS_RESULT_LIST_EUTRA);
|
|
||||||
LIBLTE_RRC_MEAS_RESULT_LIST_EUTRA_STRUCT *eutra = &rep->meas_result_neigh_cells.eutra;
|
|
||||||
assert(eutra->n_result == 1);
|
|
||||||
assert(eutra->result_eutra_list[0].phys_cell_id == 357);
|
|
||||||
assert(eutra->result_eutra_list[0].have_cgi_info);
|
|
||||||
assert(eutra->result_eutra_list[0].cgi_info.have_plmn_identity_list);
|
|
||||||
assert(eutra->result_eutra_list[0].cgi_info.cell_global_id.plmn_id.mcc == 0xF898);
|
|
||||||
assert(eutra->result_eutra_list[0].cgi_info.cell_global_id.plmn_id.mnc == 0xFF78);
|
|
||||||
assert(eutra->result_eutra_list[0].cgi_info.cell_global_id.cell_id == 0x1084104);
|
|
||||||
assert(eutra->result_eutra_list[0].cgi_info.tracking_area_code == 0x1042);
|
|
||||||
assert(eutra->result_eutra_list[0].cgi_info.have_plmn_identity_list);
|
|
||||||
assert(eutra->result_eutra_list[0].cgi_info.n_plmn_identity_list == 1);
|
|
||||||
assert(eutra->result_eutra_list[0].cgi_info.plmn_identity_list[0].mcc == 0xFFFF);
|
|
||||||
assert(eutra->result_eutra_list[0].cgi_info.plmn_identity_list[0].mnc == 0xFF00);
|
|
||||||
assert(eutra->result_eutra_list[0].meas_result.have_rsrp);
|
|
||||||
assert(eutra->result_eutra_list[0].meas_result.rsrp_result == 60);
|
|
||||||
assert(eutra->result_eutra_list[0].meas_result.have_rsrp);
|
|
||||||
assert(eutra->result_eutra_list[0].meas_result.rsrq_result == 18);
|
|
||||||
|
|
||||||
liblte_rrc_pack_ul_dcch_msg(&ul_dcch_msg, (LIBLTE_BIT_MSG_STRUCT*)&bit_buf2);
|
|
||||||
srslte_bit_pack_vector(bit_buf2.msg, byte_buf.msg, bit_buf2.N_bits);
|
|
||||||
byte_buf.N_bytes = (bit_buf2.N_bits+7)/8;
|
|
||||||
log1.info_hex(byte_buf.msg, byte_buf.N_bytes, "UL_DCCH Packed message\n");
|
|
||||||
|
|
||||||
for(uint32_t i=0; i<rrc_message_len; i++) {
|
|
||||||
assert(byte_buf.msg[i] == rrc_message[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
|
||||||
basic_test();
|
|
||||||
}
|
|
@ -0,0 +1,129 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* \section COPYRIGHT
|
||||||
|
*
|
||||||
|
* Copyright 2013-2019 Software Radio Systems Limited
|
||||||
|
*
|
||||||
|
* \section LICENSE
|
||||||
|
*
|
||||||
|
* This file is part of the srsUE library.
|
||||||
|
*
|
||||||
|
* srsUE is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of
|
||||||
|
* the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* srsUE is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* A copy of the GNU Affero General Public License can be found in
|
||||||
|
* the LICENSE file in the top-level directory of this distribution
|
||||||
|
* and at http://www.gnu.org/licenses/.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "../../../srsue/hdr/upper/rrc.h"
|
||||||
|
#include "srslte/asn1/rrc_asn1.h"
|
||||||
|
#include "srslte/common/bcd_helpers.h"
|
||||||
|
#include "srslte/common/log_filter.h"
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
using namespace asn1;
|
||||||
|
using namespace asn1::rrc;
|
||||||
|
|
||||||
|
#define TESTASSERT(cond) \
|
||||||
|
{ \
|
||||||
|
if (!(cond)) { \
|
||||||
|
std::cout << "[" << __FUNCTION__ << "][Line " << __LINE__ << "]: FAIL at " << (#cond) << std::endl; \
|
||||||
|
return -1; \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
int rrc_conn_setup_test1()
|
||||||
|
{
|
||||||
|
srslte::log_filter log1("RRC");
|
||||||
|
log1.set_level(srslte::LOG_LEVEL_DEBUG);
|
||||||
|
log1.set_hex_limit(128);
|
||||||
|
|
||||||
|
uint8_t rrc_msg[] = {0x60, 0x12, 0x98, 0x0b, 0xfd, 0xd2, 0x04, 0xfa, 0x18, 0x3e, 0xd5, 0xe6, 0xc2,
|
||||||
|
0x59, 0x90, 0xc1, 0xa6, 0x00, 0x01, 0x31, 0x40, 0x42, 0x50, 0x80, 0x00, 0xf8};
|
||||||
|
uint32_t rrc_msg_len = sizeof(rrc_msg);
|
||||||
|
// 6012980bfdd204fa183ed5e6c25990c1a60001314042508000f8
|
||||||
|
|
||||||
|
bit_ref bref(&rrc_msg[0], sizeof(rrc_msg));
|
||||||
|
bit_ref bref0(&rrc_msg[0], sizeof(rrc_msg));
|
||||||
|
|
||||||
|
dl_ccch_msg_s dl_ccch_msg;
|
||||||
|
dl_ccch_msg.unpack(bref);
|
||||||
|
|
||||||
|
TESTASSERT(dl_ccch_msg.msg.type() == dl_ccch_msg_type_c::types::c1);
|
||||||
|
TESTASSERT(dl_ccch_msg.msg.c1().type() == dl_ccch_msg_type_c::c1_c_::types::rrc_conn_setup);
|
||||||
|
|
||||||
|
rrc_conn_setup_s* setup = &dl_ccch_msg.msg.c1().rrc_conn_setup();
|
||||||
|
|
||||||
|
// FIXME: add test for setup
|
||||||
|
|
||||||
|
rr_cfg_ded_s* cnfg = &setup->crit_exts.c1().rrc_conn_setup_r8().rr_cfg_ded;
|
||||||
|
TESTASSERT(cnfg->phys_cfg_ded_present);
|
||||||
|
|
||||||
|
// FIXME: add tests for RR config dedicated
|
||||||
|
|
||||||
|
phys_cfg_ded_s* phy_cnfg = &cnfg->phys_cfg_ded;
|
||||||
|
TESTASSERT(phy_cnfg->cqi_report_cfg_present);
|
||||||
|
|
||||||
|
// Test CQI config
|
||||||
|
cqi_report_cfg_s* cqi_cfg = &phy_cnfg->cqi_report_cfg;
|
||||||
|
TESTASSERT(cqi_cfg->cqi_report_periodic_present);
|
||||||
|
TESTASSERT(cqi_cfg->nom_pdsch_rs_epre_offset == 0);
|
||||||
|
TESTASSERT(cqi_cfg->cqi_report_periodic.type() == setup_e::setup);
|
||||||
|
TESTASSERT(cqi_cfg->cqi_report_periodic.setup().cqi_pucch_res_idx == 0);
|
||||||
|
TESTASSERT(cqi_cfg->cqi_report_periodic.setup().cqi_pmi_cfg_idx == 38);
|
||||||
|
|
||||||
|
// test repacking
|
||||||
|
uint8_t rrc_msg2[rrc_msg_len];
|
||||||
|
bit_ref bref2(&rrc_msg2[0], sizeof(rrc_msg2));
|
||||||
|
if (dl_ccch_msg.pack(bref2) != SRSASN_SUCCESS) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
TESTASSERT(bref.distance(bref0) == bref2.distance(&rrc_msg2[0]));
|
||||||
|
TESTASSERT(memcmp(rrc_msg2, rrc_msg, rrc_msg_len) == 0);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only packing implemented
|
||||||
|
int rrc_reestablishment_reject_test()
|
||||||
|
{
|
||||||
|
srslte::log_filter log1("RRC");
|
||||||
|
log1.set_level(srslte::LOG_LEVEL_DEBUG);
|
||||||
|
log1.set_hex_limit(128);
|
||||||
|
|
||||||
|
dl_ccch_msg_s dl_ccch_msg;
|
||||||
|
dl_ccch_msg.msg.set(dl_ccch_msg_type_c::types::c1);
|
||||||
|
|
||||||
|
dl_ccch_msg.msg.c1().set(dl_ccch_msg_type_c::c1_c_::types::rrc_conn_reest_reject);
|
||||||
|
dl_ccch_msg.msg.c1().rrc_conn_reest_reject().crit_exts.set(
|
||||||
|
rrc_conn_reest_reject_s::crit_exts_c_::types::rrc_conn_reest_reject_r8);
|
||||||
|
dl_ccch_msg.msg.c1().rrc_conn_reest_reject().crit_exts.rrc_conn_reest_reject_r8();
|
||||||
|
|
||||||
|
// test repacking
|
||||||
|
uint8_t rrc_msg[32];
|
||||||
|
bit_ref bref(rrc_msg, sizeof(rrc_msg));
|
||||||
|
if (dl_ccch_msg.pack(bref) != SRSASN_SUCCESS) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int actual_len = bref.distance_bytes(rrc_msg);
|
||||||
|
log1.info_hex(rrc_msg, actual_len, "DL-CCCH message (%d/%zd B)\n", actual_len, sizeof(rrc_msg));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char** argv)
|
||||||
|
{
|
||||||
|
TESTASSERT(rrc_conn_setup_test1() == 0);
|
||||||
|
TESTASSERT(rrc_reestablishment_reject_test() == 0);
|
||||||
|
return 0;
|
||||||
|
}
|
@ -0,0 +1,84 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* \section COPYRIGHT
|
||||||
|
*
|
||||||
|
* Copyright 2013-2019 Software Radio Systems Limited
|
||||||
|
*
|
||||||
|
* \section LICENSE
|
||||||
|
*
|
||||||
|
* This file is part of the srsUE library.
|
||||||
|
*
|
||||||
|
* srsUE is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of
|
||||||
|
* the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* srsUE is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* A copy of the GNU Affero General Public License can be found in
|
||||||
|
* the LICENSE file in the top-level directory of this distribution
|
||||||
|
* and at http://www.gnu.org/licenses/.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "../../../srsue/hdr/upper/rrc.h"
|
||||||
|
#include "srslte/asn1/rrc_asn1.h"
|
||||||
|
#include "srslte/common/bcd_helpers.h"
|
||||||
|
#include "srslte/common/log_filter.h"
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
using namespace asn1;
|
||||||
|
using namespace asn1::rrc;
|
||||||
|
|
||||||
|
#define TESTASSERT(cond) \
|
||||||
|
{ \
|
||||||
|
if (!(cond)) { \
|
||||||
|
std::cout << "[" << __FUNCTION__ << "][Line " << __LINE__ << "]: FAIL at " << (#cond) << std::endl; \
|
||||||
|
return -1; \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
int rrc_conn_reconfig_ho_test1()
|
||||||
|
{
|
||||||
|
srslte::log_filter log1("RRC");
|
||||||
|
log1.set_level(srslte::LOG_LEVEL_DEBUG);
|
||||||
|
log1.set_hex_limit(128);
|
||||||
|
|
||||||
|
uint8_t rrc_msg[] = {0x20, 0x1b, 0x3f, 0x80, 0x00, 0x00, 0x00, 0x01, 0xa9, 0x08, 0x80, 0x00, 0x00, 0x29, 0x00,
|
||||||
|
0x97, 0x80, 0x00, 0x00, 0x00, 0x01, 0x04, 0x22, 0x14, 0x00, 0xf8, 0x02, 0x0a, 0xc0, 0x60,
|
||||||
|
0x00, 0xa0, 0x0c, 0x80, 0x42, 0x02, 0x9f, 0x43, 0x07, 0xda, 0xbc, 0xf8, 0x4b, 0x32, 0x18,
|
||||||
|
0x34, 0xc0, 0x00, 0x2d, 0x68, 0x08, 0x5e, 0x18, 0x00, 0x16, 0x80, 0x00};
|
||||||
|
// 20 1b 3f 80 00 00 00 01 a9 08 80 00 00 29 00 97 80 00 00 00 01 04 22 14 00 f8 02 0a c0 60 00 a0 0c 80 42 02 9f 43
|
||||||
|
// 07 da bc f8 4b 32 18 34 c0 00 2d 68 08 5e 18 00 16 80 00
|
||||||
|
|
||||||
|
bit_ref bref(rrc_msg, sizeof(rrc_msg));
|
||||||
|
|
||||||
|
dl_dcch_msg_s dl_dcch_msg;
|
||||||
|
dl_dcch_msg.unpack(bref);
|
||||||
|
|
||||||
|
TESTASSERT(dl_dcch_msg.msg.type() == dl_dcch_msg_type_c::types::c1);
|
||||||
|
TESTASSERT(dl_dcch_msg.msg.c1().type() == dl_dcch_msg_type_c::c1_c_::types::rrc_conn_recfg);
|
||||||
|
|
||||||
|
// assign to stack-allocated variable
|
||||||
|
asn1::rrc::rrc_conn_recfg_s mob_reconf;
|
||||||
|
mob_reconf = dl_dcch_msg.msg.c1().rrc_conn_recfg();
|
||||||
|
|
||||||
|
// decode same message and assign again
|
||||||
|
bit_ref bref2(rrc_msg, sizeof(rrc_msg));
|
||||||
|
dl_dcch_msg_s dl_dcch_msg2;
|
||||||
|
dl_dcch_msg2.unpack(bref2);
|
||||||
|
TESTASSERT(dl_dcch_msg2.msg.type() == dl_dcch_msg_type_c::types::c1);
|
||||||
|
TESTASSERT(dl_dcch_msg2.msg.c1().type() == dl_dcch_msg_type_c::c1_c_::types::rrc_conn_recfg);
|
||||||
|
mob_reconf = dl_dcch_msg2.msg.c1().rrc_conn_recfg();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char** argv)
|
||||||
|
{
|
||||||
|
TESTASSERT(rrc_conn_reconfig_ho_test1() == 0);
|
||||||
|
return 0;
|
||||||
|
}
|
@ -0,0 +1,174 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* \section COPYRIGHT
|
||||||
|
*
|
||||||
|
* Copyright 2013-2015 Software Radio Systems Limited
|
||||||
|
*
|
||||||
|
* \section LICENSE
|
||||||
|
*
|
||||||
|
* This file is part of the srsUE library.
|
||||||
|
*
|
||||||
|
* srsUE is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of
|
||||||
|
* the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* srsUE is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* A copy of the GNU Affero General Public License can be found in
|
||||||
|
* the LICENSE file in the top-level directory of this distribution
|
||||||
|
* and at http://www.gnu.org/licenses/.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "../../../srsue/hdr/upper/rrc.h"
|
||||||
|
#include "srslte/asn1/rrc_asn1.h"
|
||||||
|
#include "srslte/common/bcd_helpers.h"
|
||||||
|
#include "srslte/common/log_filter.h"
|
||||||
|
#include "srslte/common/mac_pcap.h"
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
using namespace asn1::rrc;
|
||||||
|
|
||||||
|
#define TESTASSERT(cond) \
|
||||||
|
{ \
|
||||||
|
if (!(cond)) { \
|
||||||
|
std::cout << "[" << __FUNCTION__ << "][Line " << __LINE__ << "]: FAIL at " << (#cond) << std::endl; \
|
||||||
|
return -1; \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
int rrc_ue_cap_info_test(srslte::mac_pcap& pcap)
|
||||||
|
{
|
||||||
|
srslte::log_filter log1("RRC");
|
||||||
|
log1.set_level(srslte::LOG_LEVEL_DEBUG);
|
||||||
|
log1.set_hex_limit(128);
|
||||||
|
|
||||||
|
rrc_args_t args = {};
|
||||||
|
args.feature_group = 0xe6041c00;
|
||||||
|
args.nof_supported_bands = 1;
|
||||||
|
args.supported_bands[0] = 8;
|
||||||
|
args.ue_category = 4;
|
||||||
|
|
||||||
|
asn1::rrc::ul_dcch_msg_s ul_dcch_msg;
|
||||||
|
ul_dcch_msg.msg.set(ul_dcch_msg_type_c::types::c1);
|
||||||
|
ul_dcch_msg.msg.c1().set(ul_dcch_msg_type_c::c1_c_::types::ue_cap_info);
|
||||||
|
ul_dcch_msg.msg.c1().ue_cap_info().rrc_transaction_id = 0;
|
||||||
|
|
||||||
|
ul_dcch_msg.msg.c1().ue_cap_info().crit_exts.set(ue_cap_info_s::crit_exts_c_::types::c1);
|
||||||
|
ul_dcch_msg.msg.c1().ue_cap_info().crit_exts.c1().set(ue_cap_info_s::crit_exts_c_::c1_c_::types::ue_cap_info_r8);
|
||||||
|
ue_cap_info_r8_ies_s* info = &ul_dcch_msg.msg.c1().ue_cap_info().crit_exts.c1().ue_cap_info_r8();
|
||||||
|
info->ue_cap_rat_container_list.resize(1);
|
||||||
|
info->ue_cap_rat_container_list[0].rat_type = rat_type_e::eutra;
|
||||||
|
|
||||||
|
ue_eutra_cap_s cap;
|
||||||
|
cap.access_stratum_release = access_stratum_release_e::rel8;
|
||||||
|
cap.ue_category = (uint8_t)args.ue_category;
|
||||||
|
cap.pdcp_params.max_num_rohc_context_sessions_present = false;
|
||||||
|
|
||||||
|
cap.phy_layer_params.ue_specific_ref_sigs_supported = false;
|
||||||
|
cap.phy_layer_params.ue_tx_ant_sel_supported = false;
|
||||||
|
|
||||||
|
cap.rf_params.supported_band_list_eutra.resize(args.nof_supported_bands);
|
||||||
|
cap.meas_params.band_list_eutra.resize(args.nof_supported_bands);
|
||||||
|
for (uint32_t i = 0; i < args.nof_supported_bands; i++) {
|
||||||
|
cap.rf_params.supported_band_list_eutra[i].band_eutra = args.supported_bands[i];
|
||||||
|
cap.rf_params.supported_band_list_eutra[i].half_duplex = false;
|
||||||
|
cap.meas_params.band_list_eutra[i].inter_freq_band_list.resize(1);
|
||||||
|
cap.meas_params.band_list_eutra[i].inter_freq_band_list[0].inter_freq_need_for_gaps = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
cap.feature_group_inds_present = true;
|
||||||
|
cap.feature_group_inds.from_number(args.feature_group);
|
||||||
|
|
||||||
|
uint8_t buf[64];
|
||||||
|
asn1::bit_ref bref(buf, sizeof(buf));
|
||||||
|
cap.pack(bref);
|
||||||
|
bref.align_bytes_zero();
|
||||||
|
uint32_t cap_len = (uint32_t)bref.distance_bytes(buf);
|
||||||
|
info->ue_cap_rat_container_list[0].ue_cap_rat_container.resize(cap_len);
|
||||||
|
memcpy(info->ue_cap_rat_container_list[0].ue_cap_rat_container.data(), buf, cap_len);
|
||||||
|
log1.debug_hex(buf, cap_len, "UE-Cap (%d/%zd B)\n", cap_len, sizeof(buf));
|
||||||
|
|
||||||
|
// pack the message
|
||||||
|
uint8_t byte_buf[16];
|
||||||
|
ZERO_OBJECT(byte_buf);
|
||||||
|
asn1::bit_ref bref3(byte_buf, sizeof(byte_buf));
|
||||||
|
ul_dcch_msg.pack(bref3);
|
||||||
|
bref3.align_bytes_zero();
|
||||||
|
|
||||||
|
uint32_t len = (uint32_t)bref3.distance_bytes(byte_buf);
|
||||||
|
log1.debug_hex(byte_buf, len, "UL-DCCH (%d/%zd B)\n", len, sizeof(byte_buf));
|
||||||
|
|
||||||
|
pcap.write_ul_rrc_pdu(byte_buf, len);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int pack_fail_test()
|
||||||
|
{
|
||||||
|
srslte::log_filter log1("RRC");
|
||||||
|
log1.set_level(srslte::LOG_LEVEL_DEBUG);
|
||||||
|
log1.set_hex_limit(128);
|
||||||
|
|
||||||
|
rrc_args_t args = {};
|
||||||
|
args.feature_group = 0xe6041c00;
|
||||||
|
args.nof_supported_bands = 1;
|
||||||
|
args.supported_bands[0] = 8;
|
||||||
|
args.ue_category = 4;
|
||||||
|
|
||||||
|
asn1::rrc::ul_dcch_msg_s ul_dcch_msg;
|
||||||
|
ul_dcch_msg.msg.set(ul_dcch_msg_type_c::types::c1);
|
||||||
|
ul_dcch_msg.msg.c1().set(ul_dcch_msg_type_c::c1_c_::types::ue_cap_info);
|
||||||
|
ul_dcch_msg.msg.c1().ue_cap_info().rrc_transaction_id = 0;
|
||||||
|
|
||||||
|
ul_dcch_msg.msg.c1().ue_cap_info().crit_exts.set(ue_cap_info_s::crit_exts_c_::types::c1);
|
||||||
|
ul_dcch_msg.msg.c1().ue_cap_info().crit_exts.c1().set(ue_cap_info_s::crit_exts_c_::c1_c_::types::ue_cap_info_r8);
|
||||||
|
ue_cap_info_r8_ies_s* info = &ul_dcch_msg.msg.c1().ue_cap_info().crit_exts.c1().ue_cap_info_r8();
|
||||||
|
info->ue_cap_rat_container_list.resize(1);
|
||||||
|
info->ue_cap_rat_container_list[0].rat_type = rat_type_e::eutra;
|
||||||
|
|
||||||
|
ue_eutra_cap_s cap;
|
||||||
|
cap.access_stratum_release = access_stratum_release_e::rel8;
|
||||||
|
cap.ue_category = (uint8_t)args.ue_category;
|
||||||
|
cap.pdcp_params.max_num_rohc_context_sessions_present = false;
|
||||||
|
|
||||||
|
cap.phy_layer_params.ue_specific_ref_sigs_supported = false;
|
||||||
|
cap.phy_layer_params.ue_tx_ant_sel_supported = false;
|
||||||
|
|
||||||
|
cap.rf_params.supported_band_list_eutra.resize(args.nof_supported_bands);
|
||||||
|
cap.meas_params.band_list_eutra.resize(args.nof_supported_bands);
|
||||||
|
for (uint32_t i = 0; i < args.nof_supported_bands; i++) {
|
||||||
|
cap.rf_params.supported_band_list_eutra[i].band_eutra = args.supported_bands[i];
|
||||||
|
cap.rf_params.supported_band_list_eutra[i].half_duplex = false;
|
||||||
|
cap.meas_params.band_list_eutra[i].inter_freq_band_list.resize(1);
|
||||||
|
cap.meas_params.band_list_eutra[i].inter_freq_band_list[0].inter_freq_need_for_gaps = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
cap.feature_group_inds_present = true;
|
||||||
|
cap.feature_group_inds.from_number(args.feature_group);
|
||||||
|
|
||||||
|
uint8_t buff[3];
|
||||||
|
asn1::bit_ref bref(buff, sizeof(buff));
|
||||||
|
if (ul_dcch_msg.pack(bref) != asn1::SRSASN_SUCCESS) {
|
||||||
|
fprintf(stderr, "Error while packing message.\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char** argv)
|
||||||
|
{
|
||||||
|
srslte::mac_pcap pcap;
|
||||||
|
pcap.open("ul_dcch.pcap");
|
||||||
|
|
||||||
|
TESTASSERT(rrc_ue_cap_info_test(pcap) == 0);
|
||||||
|
TESTASSERT(pack_fail_test() == -1);
|
||||||
|
|
||||||
|
pcap.close();
|
||||||
|
return 0;
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,17 +1,4 @@
|
|||||||
# IP tx/rx program test
|
|
||||||
add_executable(ip_test_enb ip_test.cc)
|
|
||||||
target_link_libraries(ip_test_enb srsenb_upper
|
|
||||||
srsenb_mac
|
|
||||||
srsenb_phy
|
|
||||||
srslte_common
|
|
||||||
srslte_phy
|
|
||||||
srslte_upper
|
|
||||||
srslte_radio
|
|
||||||
${CMAKE_THREAD_LIBS_INIT}
|
|
||||||
${Boost_LIBRARIES}
|
|
||||||
${SEC_LIBRARIES})
|
|
||||||
|
|
||||||
# Simple PLMN -> MCC/MNC test
|
# Simple PLMN -> MCC/MNC test
|
||||||
add_executable(plmn_test plmn_test.cc)
|
add_executable(plmn_test plmn_test.cc)
|
||||||
target_link_libraries(plmn_test srsenb_upper srslte_asn1 )
|
target_link_libraries(plmn_test rrc_asn1)
|
||||||
|
|
||||||
|
@ -1,684 +0,0 @@
|
|||||||
/**
|
|
||||||
*
|
|
||||||
* \section COPYRIGHT
|
|
||||||
*
|
|
||||||
* Copyright 2013-2017 Software Radio Systems Limited
|
|
||||||
*
|
|
||||||
* \section LICENSE
|
|
||||||
*
|
|
||||||
* This file is part of srsLTE.
|
|
||||||
*
|
|
||||||
* srsUE is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as
|
|
||||||
* published by the Free Software Foundation, either version 3 of
|
|
||||||
* the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* srsUE is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* A copy of the GNU Affero General Public License can be found in
|
|
||||||
* the LICENSE file in the top-level directory of this distribution
|
|
||||||
* and at http://www.gnu.org/licenses/.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <arpa/inet.h>
|
|
||||||
#include <linux/ip.h>
|
|
||||||
#include <linux/if.h>
|
|
||||||
#include <linux/if_tun.h>
|
|
||||||
#include <sys/ioctl.h>
|
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#include "srsenb/hdr/mac/mac.h"
|
|
||||||
#include "srsenb/hdr/phy/phy.h"
|
|
||||||
#include "srslte/common/threads.h"
|
|
||||||
#include "srslte/interfaces/enb_interfaces.h"
|
|
||||||
#include "srslte/common/common.h"
|
|
||||||
#include "srslte/common/buffer_pool.h"
|
|
||||||
#include "srslte/common/logger_file.h"
|
|
||||||
#include "srslte/common/log_filter.h"
|
|
||||||
#include "srslte/upper/rlc.h"
|
|
||||||
#include "srslte/radio/radio.h"
|
|
||||||
#include "srslte/phy/utils/debug.h"
|
|
||||||
|
|
||||||
#define START_TUNTAP
|
|
||||||
#define USE_RADIO
|
|
||||||
|
|
||||||
/**********************************************************************
|
|
||||||
* Program arguments processing
|
|
||||||
***********************************************************************/
|
|
||||||
|
|
||||||
#define LCID 3
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
float rx_freq;
|
|
||||||
float tx_freq;
|
|
||||||
float rx_gain;
|
|
||||||
float tx_gain;
|
|
||||||
bool enable_gui;
|
|
||||||
int time_adv;
|
|
||||||
std::string ip_address;
|
|
||||||
}prog_args_t;
|
|
||||||
|
|
||||||
uint32_t srsapps_verbose = 1;
|
|
||||||
|
|
||||||
prog_args_t prog_args;
|
|
||||||
|
|
||||||
void args_default(prog_args_t *args) {
|
|
||||||
args->rx_freq = 2.505e9;
|
|
||||||
args->tx_freq = 2.625e9;
|
|
||||||
args->rx_gain = 50.0;
|
|
||||||
args->tx_gain = 70.0;
|
|
||||||
args->enable_gui = false;
|
|
||||||
args->time_adv = -1; // calibrated for b210
|
|
||||||
args->ip_address = "192.168.3.1";
|
|
||||||
}
|
|
||||||
|
|
||||||
void usage(prog_args_t *args, char *prog) {
|
|
||||||
printf("Usage: %s [gGIrfFdv] \n", prog);
|
|
||||||
printf("\t-f RX frequency [Default %.1f MHz]\n", args->rx_freq/1e6);
|
|
||||||
printf("\t-F TX frequency [Default %.1f MHz]\n", args->tx_freq/1e6);
|
|
||||||
printf("\t-g RX gain [Default %.1f]\n", args->rx_gain);
|
|
||||||
printf("\t-G TX gain [Default %.1f]\n", args->tx_gain);
|
|
||||||
printf("\t-I IP address [Default %s]\n", args->ip_address.c_str());
|
|
||||||
printf("\t-t time advance (in samples) [Default %d]\n", args->time_adv);
|
|
||||||
printf("\t-d Enable gui [Default disabled]\n");
|
|
||||||
printf("\t-v [increase verbosity, default none]\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
void parse_args(prog_args_t *args, int argc, char **argv) {
|
|
||||||
int opt;
|
|
||||||
args_default(args);
|
|
||||||
while ((opt = getopt(argc, argv, "gGfFItdv")) != -1) {
|
|
||||||
switch (opt) {
|
|
||||||
case 'd':
|
|
||||||
args->enable_gui = true;
|
|
||||||
break;
|
|
||||||
case 'g':
|
|
||||||
args->rx_gain = atof(argv[optind]);
|
|
||||||
break;
|
|
||||||
case 'G':
|
|
||||||
args->tx_gain = atof(argv[optind]);
|
|
||||||
break;
|
|
||||||
case 'f':
|
|
||||||
args->rx_freq = atof(argv[optind]);
|
|
||||||
break;
|
|
||||||
case 'F':
|
|
||||||
args->tx_freq = atof(argv[optind]);
|
|
||||||
break;
|
|
||||||
case 'I':
|
|
||||||
args->ip_address = argv[optind];
|
|
||||||
break;
|
|
||||||
case 't':
|
|
||||||
args->time_adv = atoi(argv[optind]);
|
|
||||||
break;
|
|
||||||
case 'v':
|
|
||||||
srsapps_verbose++;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
usage(args, argv[0]);
|
|
||||||
exit(-1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (args->rx_freq < 0 || args->tx_freq < 0) {
|
|
||||||
usage(args, argv[0]);
|
|
||||||
exit(-1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
LIBLTE_BYTE_MSG_STRUCT sib_buffer[2];
|
|
||||||
|
|
||||||
int setup_if_addr(char *ip_addr);
|
|
||||||
|
|
||||||
class tester : public srsue::pdcp_interface_rlc,
|
|
||||||
public srsue::rrc_interface_rlc,
|
|
||||||
public srsue::ue_interface,
|
|
||||||
public srsenb::rlc_interface_mac,
|
|
||||||
public srsenb::rrc_interface_mac,
|
|
||||||
public thread
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
tester() {
|
|
||||||
rnti = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void init(srslte::rlc *rlc_, srsenb::mac *mac_, srsenb::phy *phy_, srslte::log *log_h_, std::string ip_address) {
|
|
||||||
log_h = log_h_;
|
|
||||||
rlc = rlc_;
|
|
||||||
mac = mac_;
|
|
||||||
phy = phy_;
|
|
||||||
|
|
||||||
tun_fd = 0;
|
|
||||||
|
|
||||||
#ifdef START_TUNTAP
|
|
||||||
if (init_tuntap((char*) ip_address.c_str())) {
|
|
||||||
log_h->error("Initiating IP address\n");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
pool = srslte::byte_buffer_pool::get_instance();
|
|
||||||
|
|
||||||
// Start reader thread
|
|
||||||
running=true;
|
|
||||||
start();
|
|
||||||
}
|
|
||||||
|
|
||||||
void write_pdu_bcch_bch(srslte::byte_buffer_t *sdu) {}
|
|
||||||
void write_pdu_bcch_dlsch(srslte::byte_buffer_t *sdu) {}
|
|
||||||
void write_pdu_pcch(srslte::byte_buffer_t *sdu) {}
|
|
||||||
void write_pdu_mch(uint32_t lcid, srslte::byte_buffer_t *pdu){}
|
|
||||||
void max_retx_attempted(){}
|
|
||||||
void add_user(uint16_t rnti) {}
|
|
||||||
void release_user(uint16_t rnti) {}
|
|
||||||
void upd_user(uint16_t rnti, uint16_t old_rnti) {}
|
|
||||||
void set_activity_user(uint16_t rnti) {}
|
|
||||||
bool is_paging_opportunity(uint32_t tti, uint32_t *payload_len) {return false;}
|
|
||||||
void read_pdu_pcch(uint8_t* payload, uint32_t buffer_size) {}
|
|
||||||
std::string get_rb_name(uint32_t lcid) { return std::string("lcid"); }
|
|
||||||
|
|
||||||
void write_pdu(uint32_t lcid, srslte::byte_buffer_t *sdu)
|
|
||||||
{
|
|
||||||
int n = write(tun_fd, sdu->msg, sdu->N_bytes);
|
|
||||||
if (n != (int) sdu->N_bytes) {
|
|
||||||
log_h->error("TUN/TAP write failure n=%d, nof_bytes=%d\n", n, sdu->N_bytes);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
log_h->debug_hex(sdu->msg, sdu->N_bytes,
|
|
||||||
"Wrote %d bytes to TUN/TAP\n",
|
|
||||||
sdu->N_bytes);
|
|
||||||
pool->deallocate(sdu);
|
|
||||||
}
|
|
||||||
|
|
||||||
int read_pdu(uint16_t rnti, uint32_t lcid, uint8_t *payload, uint32_t nof_bytes)
|
|
||||||
{
|
|
||||||
return rlc->read_pdu(lcid, payload, nof_bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
void read_pdu_bcch_dlsch(uint32_t sib_index, uint8_t payload[srsenb::sched_interface::MAX_SIB_PAYLOAD_LEN])
|
|
||||||
{
|
|
||||||
if (sib_index < 2) {
|
|
||||||
memcpy(payload, sib_buffer[sib_index].msg, sib_buffer[sib_index].N_bytes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void write_pdu(uint16_t rnti, uint32_t lcid, uint8_t *payload, uint32_t nof_bytes)
|
|
||||||
{
|
|
||||||
srslte::byte_buffer_t *sdu = NULL;
|
|
||||||
log_h->info("Received PDU rnti=0x%x, lcid=%d, nof_bytes=%d\n", rnti, lcid, nof_bytes);
|
|
||||||
switch(lcid) {
|
|
||||||
case LCID:
|
|
||||||
rlc->write_pdu(lcid, payload, nof_bytes);
|
|
||||||
break;
|
|
||||||
case 0:
|
|
||||||
log_h->info("Received ConnectionRequest from rnti=0x%x\n", rnti);
|
|
||||||
|
|
||||||
// Configure User in MAC
|
|
||||||
srsenb::sched_interface::ue_cfg_t uecfg;
|
|
||||||
bzero(&uecfg, sizeof(srsenb::sched_interface::ue_cfg_t));
|
|
||||||
uecfg.maxharq_tx = 5;
|
|
||||||
uecfg.continuous_pusch = false;
|
|
||||||
uecfg.ue_bearers[0].direction = srsenb::sched_interface::ue_bearer_cfg_t::BOTH;
|
|
||||||
uecfg.ue_bearers[LCID].direction = srsenb::sched_interface::ue_bearer_cfg_t::BOTH;
|
|
||||||
mac->ue_cfg(rnti, &uecfg);
|
|
||||||
|
|
||||||
// configure DRB1 as UM
|
|
||||||
LIBLTE_RRC_RLC_CONFIG_STRUCT cfg;
|
|
||||||
bzero(&cfg, sizeof(LIBLTE_RRC_RLC_CONFIG_STRUCT));
|
|
||||||
cfg.rlc_mode = LIBLTE_RRC_RLC_MODE_UM_BI;
|
|
||||||
cfg.dl_um_bi_rlc.t_reordering = LIBLTE_RRC_T_REORDERING_MS100;
|
|
||||||
cfg.dl_um_bi_rlc.sn_field_len = LIBLTE_RRC_SN_FIELD_LENGTH_SIZE10;
|
|
||||||
cfg.ul_um_bi_rlc.sn_field_len = LIBLTE_RRC_SN_FIELD_LENGTH_SIZE10;
|
|
||||||
rlc->add_bearer(LCID, &cfg);
|
|
||||||
|
|
||||||
// Send dummy ConnectionSetup. MAC will send contention resolution ID automatically.
|
|
||||||
log_h->info("Sending ConnectionSetup\n");
|
|
||||||
sdu = pool_allocate;
|
|
||||||
sdu->msg[0] = 0xab;
|
|
||||||
sdu->N_bytes = 1;
|
|
||||||
rlc->write_sdu(0, sdu);
|
|
||||||
|
|
||||||
// Indicate RLC status to mac
|
|
||||||
mac->rlc_buffer_state(rnti, 0, 1, 0);
|
|
||||||
|
|
||||||
LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT dedicated;
|
|
||||||
bzero(&dedicated, sizeof(LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT));
|
|
||||||
dedicated.pusch_cnfg_ded.beta_offset_ack_idx = 5;
|
|
||||||
dedicated.pusch_cnfg_ded.beta_offset_ri_idx = 12;
|
|
||||||
dedicated.pusch_cnfg_ded.beta_offset_cqi_idx = 15;
|
|
||||||
dedicated.pusch_cnfg_ded_present = true;
|
|
||||||
dedicated.sched_request_cnfg.dsr_trans_max = LIBLTE_RRC_DSR_TRANS_MAX_N4;
|
|
||||||
dedicated.sched_request_cnfg.sr_pucch_resource_idx = 0;
|
|
||||||
dedicated.sched_request_cnfg.sr_cnfg_idx = 35;
|
|
||||||
dedicated.sched_request_cnfg_present = true;
|
|
||||||
phy->set_config_dedicated(rnti, &dedicated);
|
|
||||||
|
|
||||||
usleep(500);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
log_h->error("Received message for lcid=%d\n", lcid);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void rl_failure(uint16_t rnti)
|
|
||||||
{
|
|
||||||
log_h->console("Disconnecting rnti=0x%x.\n", rnti);
|
|
||||||
mac->ue_rem(rnti);
|
|
||||||
rlc->reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
int tun_fd;
|
|
||||||
bool running;
|
|
||||||
srslte::log *log_h;
|
|
||||||
srslte::byte_buffer_pool *pool;
|
|
||||||
srslte::rlc *rlc;
|
|
||||||
srsenb::mac *mac;
|
|
||||||
srsenb::phy *phy;
|
|
||||||
uint16_t rnti;
|
|
||||||
bool read_enable;
|
|
||||||
|
|
||||||
int init_tuntap(char *ip_address) {
|
|
||||||
read_enable = true;
|
|
||||||
tun_fd = setup_if_addr(ip_address);
|
|
||||||
if (tun_fd<0) {
|
|
||||||
fprintf(stderr, "Error setting up IP %s\n", ip_address);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
printf("Created tun/tap interface at IP %s\n", ip_address);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void run_thread() {
|
|
||||||
struct iphdr *ip_pkt;
|
|
||||||
uint32_t idx = 0;
|
|
||||||
int32_t N_bytes = 0;
|
|
||||||
srslte::byte_buffer_t *pdu = pool_allocate;
|
|
||||||
|
|
||||||
log_h->info("TUN/TAP reader thread running\n");
|
|
||||||
|
|
||||||
int first=1;
|
|
||||||
while(running) {
|
|
||||||
if (tun_fd > 0) {
|
|
||||||
pdu->msg[0] = 0x0;
|
|
||||||
N_bytes = read(tun_fd, &pdu->msg[idx], SRSLTE_MAX_BUFFER_SIZE_BYTES-SRSLTE_BUFFER_HEADER_OFFSET - idx);
|
|
||||||
}
|
|
||||||
if(N_bytes > 0)
|
|
||||||
{
|
|
||||||
if (read_enable && pdu->msg[0] != 0x60) {
|
|
||||||
|
|
||||||
pdu->N_bytes = idx + N_bytes;
|
|
||||||
ip_pkt = (struct iphdr*)pdu->msg;
|
|
||||||
|
|
||||||
log_h->debug_hex(pdu->msg, pdu->N_bytes,
|
|
||||||
"Read %d bytes from TUN/TAP\n",
|
|
||||||
N_bytes);
|
|
||||||
|
|
||||||
// Check if entire packet was received
|
|
||||||
if(ntohs(ip_pkt->tot_len) == pdu->N_bytes)
|
|
||||||
{
|
|
||||||
// Send PDU directly to RLC
|
|
||||||
pdu->set_timestamp();
|
|
||||||
rlc->write_sdu(LCID, pdu);
|
|
||||||
|
|
||||||
// Indicate RLC status to mac
|
|
||||||
mac->rlc_buffer_state(rnti, LCID, rlc->get_buffer_state(LCID), 0);
|
|
||||||
|
|
||||||
pdu = pool_allocate;
|
|
||||||
idx = 0;
|
|
||||||
} else{
|
|
||||||
idx += N_bytes;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}else{
|
|
||||||
log_h->error("Failed to read from TUN interface - gw receive thread exiting.\n");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// Create classes
|
|
||||||
srslte::logger_file logger;
|
|
||||||
srslte::log_filter log_phy;
|
|
||||||
srslte::log_filter log_mac;
|
|
||||||
srslte::log_filter log_rlc;
|
|
||||||
srslte::log_filter log_tester;
|
|
||||||
srsenb::phy my_phy;
|
|
||||||
srsenb::mac my_mac;
|
|
||||||
srslte::rlc my_rlc;
|
|
||||||
srslte::radio my_radio;
|
|
||||||
|
|
||||||
// Local classes for testing
|
|
||||||
tester my_tester;
|
|
||||||
|
|
||||||
|
|
||||||
void generate_cell_configuration(srsenb::sched_interface::cell_cfg_t *mac_cfg, srsenb::phy_cfg_t *phy_cfg)
|
|
||||||
{
|
|
||||||
// Main cell configuration
|
|
||||||
srslte_cell_t cell;
|
|
||||||
cell.id = 0;
|
|
||||||
cell.cp = SRSLTE_CP_NORM;
|
|
||||||
cell.nof_ports = 1;
|
|
||||||
cell.nof_prb = 25;
|
|
||||||
cell.phich_length = SRSLTE_PHICH_NORM;
|
|
||||||
cell.phich_resources = SRSLTE_PHICH_R_1;
|
|
||||||
|
|
||||||
// Generate SIB1
|
|
||||||
LIBLTE_RRC_BCCH_DLSCH_MSG_STRUCT msg[2];
|
|
||||||
bzero(&msg[0], sizeof(LIBLTE_RRC_BCCH_DLSCH_MSG_STRUCT));
|
|
||||||
bzero(&msg[1], sizeof(LIBLTE_RRC_BCCH_DLSCH_MSG_STRUCT));
|
|
||||||
|
|
||||||
msg[0].N_sibs = 1;
|
|
||||||
msg[0].sibs[0].sib_type = LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1;
|
|
||||||
LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1_STRUCT *sib1 = &msg[0].sibs[0].sib.sib1;
|
|
||||||
|
|
||||||
sib1->cell_id = 0x1234;
|
|
||||||
sib1->tracking_area_code = 0x1234;
|
|
||||||
sib1->freq_band_indicator = 2;
|
|
||||||
sib1->N_plmn_ids = 1;
|
|
||||||
sib1->plmn_id[0].id.mcc = 1;
|
|
||||||
sib1->plmn_id[0].id.mnc = 1;
|
|
||||||
sib1->plmn_id[0].resv_for_oper = LIBLTE_RRC_NOT_RESV_FOR_OPER;
|
|
||||||
sib1->cell_barred = LIBLTE_RRC_CELL_NOT_BARRED;
|
|
||||||
sib1->intra_freq_reselection = LIBLTE_RRC_INTRA_FREQ_RESELECTION_ALLOWED;
|
|
||||||
sib1->q_rx_lev_min = -140;
|
|
||||||
sib1->q_rx_lev_min_offset = 1;
|
|
||||||
sib1->p_max = 10;
|
|
||||||
sib1->p_max_present = true;
|
|
||||||
sib1->si_window_length = LIBLTE_RRC_SI_WINDOW_LENGTH_MS40;
|
|
||||||
sib1->N_sched_info = 1;
|
|
||||||
sib1->sched_info[0].si_periodicity = LIBLTE_RRC_SI_PERIODICITY_RF16;
|
|
||||||
sib1->sched_info[0].N_sib_mapping_info = 0;
|
|
||||||
sib1->system_info_value_tag = 8;
|
|
||||||
|
|
||||||
// Generate SIB2
|
|
||||||
msg[1].N_sibs = 2;
|
|
||||||
msg[1].sibs[0].sib_type = LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2;
|
|
||||||
msg[1].sibs[1].sib_type = LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_3;
|
|
||||||
LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT *sib2 = &msg[1].sibs[0].sib.sib2;
|
|
||||||
|
|
||||||
// RACH configuration
|
|
||||||
sib2->rr_config_common_sib.rach_cnfg.num_ra_preambles = LIBLTE_RRC_NUMBER_OF_RA_PREAMBLES_N64;
|
|
||||||
sib2->rr_config_common_sib.rach_cnfg.preambles_group_a_cnfg.present = false;
|
|
||||||
sib2->rr_config_common_sib.rach_cnfg.preamble_init_rx_target_pwr = LIBLTE_RRC_PREAMBLE_INITIAL_RECEIVED_TARGET_POWER_DBM_N90;
|
|
||||||
sib2->rr_config_common_sib.rach_cnfg.pwr_ramping_step = LIBLTE_RRC_POWER_RAMPING_STEP_DB6;
|
|
||||||
sib2->rr_config_common_sib.rach_cnfg.preamble_trans_max = LIBLTE_RRC_PREAMBLE_TRANS_MAX_N10;
|
|
||||||
sib2->rr_config_common_sib.rach_cnfg.ra_resp_win_size = LIBLTE_RRC_RA_RESPONSE_WINDOW_SIZE_SF10;
|
|
||||||
sib2->rr_config_common_sib.rach_cnfg.mac_con_res_timer = LIBLTE_RRC_MAC_CONTENTION_RESOLUTION_TIMER_SF40;
|
|
||||||
sib2->rr_config_common_sib.rach_cnfg.max_harq_msg3_tx = 4;
|
|
||||||
|
|
||||||
// BCCH
|
|
||||||
sib2->rr_config_common_sib.bcch_cnfg.modification_period_coeff = LIBLTE_RRC_MODIFICATION_PERIOD_COEFF_N16;
|
|
||||||
|
|
||||||
// PCCH
|
|
||||||
sib2->rr_config_common_sib.pcch_cnfg.default_paging_cycle = LIBLTE_RRC_DEFAULT_PAGING_CYCLE_RF128;
|
|
||||||
sib2->rr_config_common_sib.pcch_cnfg.nB = LIBLTE_RRC_NB_ONE_THIRTY_SECOND_T;
|
|
||||||
|
|
||||||
// PRACH Configuration
|
|
||||||
sib2->rr_config_common_sib.prach_cnfg.root_sequence_index = 41;
|
|
||||||
sib2->rr_config_common_sib.prach_cnfg.prach_cnfg_info.high_speed_flag = false;
|
|
||||||
sib2->rr_config_common_sib.prach_cnfg.prach_cnfg_info.prach_config_index = 4;
|
|
||||||
sib2->rr_config_common_sib.prach_cnfg.prach_cnfg_info.prach_freq_offset = 2;
|
|
||||||
sib2->rr_config_common_sib.prach_cnfg.prach_cnfg_info.zero_correlation_zone_config = 11;
|
|
||||||
|
|
||||||
// PDSCH configuration
|
|
||||||
sib2->rr_config_common_sib.pdsch_cnfg.p_b = 0;
|
|
||||||
sib2->rr_config_common_sib.pdsch_cnfg.rs_power = -5;
|
|
||||||
|
|
||||||
// PUSCH configuration
|
|
||||||
sib2->rr_config_common_sib.pusch_cnfg.n_sb = 1;
|
|
||||||
sib2->rr_config_common_sib.pusch_cnfg.hopping_mode = LIBLTE_RRC_HOPPING_MODE_INTER_SUBFRAME;
|
|
||||||
sib2->rr_config_common_sib.pusch_cnfg.pusch_hopping_offset = 4;
|
|
||||||
sib2->rr_config_common_sib.pusch_cnfg.enable_64_qam = false;
|
|
||||||
sib2->rr_config_common_sib.pusch_cnfg.ul_rs.cyclic_shift = 0;
|
|
||||||
sib2->rr_config_common_sib.pusch_cnfg.ul_rs.group_assignment_pusch = 0;
|
|
||||||
sib2->rr_config_common_sib.pusch_cnfg.ul_rs.group_hopping_enabled = false;
|
|
||||||
sib2->rr_config_common_sib.pusch_cnfg.ul_rs.sequence_hopping_enabled = false;
|
|
||||||
|
|
||||||
// PUCCH configuration
|
|
||||||
sib2->rr_config_common_sib.pucch_cnfg.delta_pucch_shift = LIBLTE_RRC_DELTA_PUCCH_SHIFT_DS2;
|
|
||||||
sib2->rr_config_common_sib.pucch_cnfg.n_rb_cqi = 2;
|
|
||||||
sib2->rr_config_common_sib.pucch_cnfg.n_cs_an = 0;
|
|
||||||
sib2->rr_config_common_sib.pucch_cnfg.n1_pucch_an = 12;
|
|
||||||
|
|
||||||
// SRS configuration
|
|
||||||
sib2->rr_config_common_sib.srs_ul_cnfg.present = false;
|
|
||||||
|
|
||||||
// UL power control
|
|
||||||
sib2->rr_config_common_sib.ul_pwr_ctrl.p0_nominal_pusch = -80;
|
|
||||||
sib2->rr_config_common_sib.ul_pwr_ctrl.alpha = LIBLTE_RRC_UL_POWER_CONTROL_ALPHA_1;
|
|
||||||
sib2->rr_config_common_sib.ul_pwr_ctrl.p0_nominal_pucch = -80;
|
|
||||||
sib2->rr_config_common_sib.ul_pwr_ctrl.delta_flist_pucch.format_1 = LIBLTE_RRC_DELTA_F_PUCCH_FORMAT_1_0;
|
|
||||||
sib2->rr_config_common_sib.ul_pwr_ctrl.delta_flist_pucch.format_1b = LIBLTE_RRC_DELTA_F_PUCCH_FORMAT_1B_5;
|
|
||||||
sib2->rr_config_common_sib.ul_pwr_ctrl.delta_flist_pucch.format_2 = LIBLTE_RRC_DELTA_F_PUCCH_FORMAT_2_2;
|
|
||||||
sib2->rr_config_common_sib.ul_pwr_ctrl.delta_flist_pucch.format_2a = LIBLTE_RRC_DELTA_F_PUCCH_FORMAT_2A_2;
|
|
||||||
sib2->rr_config_common_sib.ul_pwr_ctrl.delta_flist_pucch.format_2b = LIBLTE_RRC_DELTA_F_PUCCH_FORMAT_2B_2;
|
|
||||||
sib2->rr_config_common_sib.ul_pwr_ctrl.delta_preamble_msg3 = 4;
|
|
||||||
|
|
||||||
sib2->rr_config_common_sib.ul_cp_length = LIBLTE_RRC_UL_CP_LENGTH_1;
|
|
||||||
|
|
||||||
sib2->ue_timers_and_constants.t300 = LIBLTE_RRC_T300_MS1000;
|
|
||||||
sib2->ue_timers_and_constants.t301 = LIBLTE_RRC_T301_MS1000;
|
|
||||||
sib2->ue_timers_and_constants.n310 = LIBLTE_RRC_N310_N10;
|
|
||||||
sib2->ue_timers_and_constants.t311 = LIBLTE_RRC_T311_MS1000;
|
|
||||||
sib2->ue_timers_and_constants.n311 = LIBLTE_RRC_N311_N1;
|
|
||||||
|
|
||||||
sib2->time_alignment_timer = LIBLTE_RRC_TIME_ALIGNMENT_TIMER_INFINITY;
|
|
||||||
sib2->additional_spectrum_emission = 1;
|
|
||||||
sib2->arfcn_value_eutra.present = false;
|
|
||||||
sib2->ul_bw.present = false;
|
|
||||||
|
|
||||||
LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_3_STRUCT *sib3 = &msg[1].sibs[1].sib.sib3;
|
|
||||||
|
|
||||||
bzero(sib3, sizeof(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_3_STRUCT));
|
|
||||||
sib3->q_hyst = LIBLTE_RRC_Q_HYST_DB_2;
|
|
||||||
sib3->s_non_intra_search = 6;
|
|
||||||
sib3->s_non_intra_search_present = true;
|
|
||||||
sib3->thresh_serving_low = 4;
|
|
||||||
sib3->cell_resel_prio = 6;
|
|
||||||
sib3->q_rx_lev_min = -122;
|
|
||||||
sib3->p_max = 23;
|
|
||||||
sib3->p_max_present = true;
|
|
||||||
sib3->s_intra_search = 10;
|
|
||||||
sib3->s_intra_search_present = true;
|
|
||||||
sib3->presence_ant_port_1 = true;
|
|
||||||
sib3->neigh_cell_cnfg = 1;
|
|
||||||
sib3->t_resel_eutra = 1;
|
|
||||||
|
|
||||||
// Genreate payload
|
|
||||||
LIBLTE_BIT_MSG_STRUCT bitbuffer[2];
|
|
||||||
for (int i=0;i<2;i++) {
|
|
||||||
liblte_rrc_pack_bcch_dlsch_msg(&msg[i], &bitbuffer[i]);
|
|
||||||
srslte_bit_pack_vector(bitbuffer[i].msg, sib_buffer[i].msg, bitbuffer[i].N_bits);
|
|
||||||
sib_buffer[i].N_bytes = (bitbuffer[i].N_bits-1)/8+1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fill MAC scheduler configuration
|
|
||||||
bzero(mac_cfg, sizeof(srsenb::sched_interface::cell_cfg_t));
|
|
||||||
memcpy(&mac_cfg->cell, &cell, sizeof(srslte_cell_t));
|
|
||||||
mac_cfg->sibs[0].len = sib_buffer[0].N_bytes;
|
|
||||||
mac_cfg->sibs[0].period_rf = 8; // Fixed to 8 rf
|
|
||||||
mac_cfg->sibs[1].len = sib_buffer[1].N_bytes;
|
|
||||||
mac_cfg->sibs[1].period_rf = liblte_rrc_si_periodicity_num[sib1->sched_info[0].si_periodicity];
|
|
||||||
mac_cfg->si_window_ms = liblte_rrc_si_window_length_num[sib1->si_window_length];
|
|
||||||
|
|
||||||
|
|
||||||
mac_cfg->prach_rar_window = liblte_rrc_ra_response_window_size_num[sib2->rr_config_common_sib.rach_cnfg.ra_resp_win_size];
|
|
||||||
|
|
||||||
// Copy PHY common configuration
|
|
||||||
bzero(phy_cfg, sizeof(srsenb::phy_cfg_t));
|
|
||||||
memcpy(&phy_cfg->cell, &cell, sizeof(srslte_cell_t));
|
|
||||||
memcpy(&phy_cfg->prach_cnfg, &sib2->rr_config_common_sib.prach_cnfg, sizeof(LIBLTE_RRC_PRACH_CONFIG_SIB_STRUCT));
|
|
||||||
memcpy(&phy_cfg->pdsch_cnfg, &sib2->rr_config_common_sib.pdsch_cnfg, sizeof(LIBLTE_RRC_PDSCH_CONFIG_COMMON_STRUCT));
|
|
||||||
memcpy(&phy_cfg->pusch_cnfg, &sib2->rr_config_common_sib.pusch_cnfg, sizeof(LIBLTE_RRC_PUSCH_CONFIG_COMMON_STRUCT));
|
|
||||||
memcpy(&phy_cfg->pucch_cnfg, &sib2->rr_config_common_sib.pucch_cnfg, sizeof(LIBLTE_RRC_PUCCH_CONFIG_COMMON_STRUCT));
|
|
||||||
memcpy(&phy_cfg->srs_ul_cnfg, &sib2->rr_config_common_sib.srs_ul_cnfg, sizeof(LIBLTE_RRC_SRS_UL_CONFIG_COMMON_STRUCT));
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
|
||||||
{
|
|
||||||
|
|
||||||
parse_args(&prog_args, argc, argv);
|
|
||||||
|
|
||||||
logger.init("/tmp/ip_test.log");
|
|
||||||
log_phy.init("PHY ", &logger, true);
|
|
||||||
log_mac.init("MAC ", &logger, true);
|
|
||||||
log_rlc.init("RLC ", &logger);
|
|
||||||
log_tester.init("TEST", &logger);
|
|
||||||
logger.log("\n\n");
|
|
||||||
|
|
||||||
if (srsapps_verbose == 1) {
|
|
||||||
log_phy.set_level(srslte::LOG_LEVEL_INFO);
|
|
||||||
log_phy.set_hex_limit(100);
|
|
||||||
log_mac.set_level(srslte::LOG_LEVEL_DEBUG);
|
|
||||||
log_mac.set_hex_limit(100);
|
|
||||||
log_rlc.set_level(srslte::LOG_LEVEL_DEBUG);
|
|
||||||
log_rlc.set_hex_limit(1000);
|
|
||||||
log_tester.set_level(srslte::LOG_LEVEL_DEBUG);
|
|
||||||
log_tester.set_hex_limit(100);
|
|
||||||
printf("Log level info\n");
|
|
||||||
}
|
|
||||||
if (srsapps_verbose == 2) {
|
|
||||||
log_phy.set_level(srslte::LOG_LEVEL_DEBUG);
|
|
||||||
log_phy.set_hex_limit(100);
|
|
||||||
log_mac.set_level(srslte::LOG_LEVEL_DEBUG);
|
|
||||||
log_mac.set_hex_limit(100);
|
|
||||||
log_rlc.set_level(srslte::LOG_LEVEL_DEBUG);
|
|
||||||
log_rlc.set_hex_limit(100);
|
|
||||||
log_tester.set_level(srslte::LOG_LEVEL_DEBUG);
|
|
||||||
log_tester.set_hex_limit(100);
|
|
||||||
srslte_verbose = SRSLTE_VERBOSE_DEBUG;
|
|
||||||
printf("Log level debug\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Init Radio and PHY
|
|
||||||
#ifdef USE_RADIO
|
|
||||||
my_radio.init();
|
|
||||||
#else
|
|
||||||
my_radio.init(NULL, (char*) "dummy");
|
|
||||||
#endif
|
|
||||||
my_radio.set_tx_freq(prog_args.tx_freq);
|
|
||||||
my_radio.set_tx_gain(prog_args.tx_gain);
|
|
||||||
my_radio.set_rx_freq(prog_args.rx_freq);
|
|
||||||
my_radio.set_rx_gain(prog_args.rx_gain);
|
|
||||||
//my_radio.set_tx_adv_neg(true);
|
|
||||||
if (prog_args.time_adv >= 0) {
|
|
||||||
printf("Setting TA=%d samples\n", prog_args.time_adv);
|
|
||||||
my_radio.set_tx_adv(prog_args.time_adv);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Configuure cell
|
|
||||||
srsenb::phy_cfg_t phy_cfg;
|
|
||||||
srsenb::sched_interface::cell_cfg_t mac_cfg;
|
|
||||||
srsenb::mac_args_t mac_args;
|
|
||||||
srsenb::phy_args_t phy_args;
|
|
||||||
|
|
||||||
mac_args.link_failure_nof_err = 10;
|
|
||||||
phy_args.equalizer_mode = "mmse";
|
|
||||||
phy_args.estimator_fil_w = 0.2;
|
|
||||||
phy_args.max_prach_offset_us = 50;
|
|
||||||
phy_args.nof_phy_threads = 1;
|
|
||||||
phy_args.pusch_max_its = 5;
|
|
||||||
|
|
||||||
generate_cell_configuration(&mac_cfg, &phy_cfg);
|
|
||||||
|
|
||||||
my_phy.init(&phy_args, &phy_cfg, &my_radio, &my_mac, &log_phy);
|
|
||||||
my_mac.init(&mac_args, &mac_cfg.cell, &my_phy, &my_tester, &my_tester, &log_mac);
|
|
||||||
my_rlc.init(&my_tester, &my_tester, &my_tester, &log_rlc, &my_mac, 0 /* SRB0 */);
|
|
||||||
my_tester.init(&my_rlc, &my_mac, &my_phy, &log_tester, prog_args.ip_address);
|
|
||||||
|
|
||||||
if (prog_args.enable_gui) {
|
|
||||||
sleep(1);
|
|
||||||
my_phy.start_plot();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool running = true;
|
|
||||||
while(running) {
|
|
||||||
printf("Main running\n");
|
|
||||||
sleep(1);
|
|
||||||
}
|
|
||||||
my_phy.stop();
|
|
||||||
my_mac.stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/******************* This is copied from srsue gw **********************/
|
|
||||||
int setup_if_addr(char *ip_addr)
|
|
||||||
{
|
|
||||||
char *dev = (char*) "tun_srsenb";
|
|
||||||
int sock = -1;
|
|
||||||
|
|
||||||
// Construct the TUN device
|
|
||||||
int tun_fd = open("/dev/net/tun", O_RDWR);
|
|
||||||
if(0 > tun_fd)
|
|
||||||
{
|
|
||||||
perror("open");
|
|
||||||
return SRSLTE_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct ifreq ifr;
|
|
||||||
|
|
||||||
memset(&ifr, 0, sizeof(ifr));
|
|
||||||
ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
|
|
||||||
strncpy(ifr.ifr_ifrn.ifrn_name, dev, IFNAMSIZ);
|
|
||||||
if(0 > ioctl(tun_fd, TUNSETIFF, &ifr))
|
|
||||||
{
|
|
||||||
perror("ioctl1");
|
|
||||||
goto clean_exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bring up the interface
|
|
||||||
sock = socket(AF_INET, SOCK_DGRAM, 0);
|
|
||||||
if(0 > ioctl(sock, SIOCGIFFLAGS, &ifr))
|
|
||||||
{
|
|
||||||
perror("socket");
|
|
||||||
goto clean_exit;
|
|
||||||
}
|
|
||||||
ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
|
|
||||||
if(0 > ioctl(sock, SIOCSIFFLAGS, &ifr))
|
|
||||||
{
|
|
||||||
perror("ioctl2");
|
|
||||||
goto clean_exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Setup the IP address
|
|
||||||
sock = socket(AF_INET, SOCK_DGRAM, 0);
|
|
||||||
ifr.ifr_addr.sa_family = AF_INET;
|
|
||||||
((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr = inet_addr(ip_addr);
|
|
||||||
if(0 > ioctl(sock, SIOCSIFADDR, &ifr))
|
|
||||||
{
|
|
||||||
perror("ioctl");
|
|
||||||
goto clean_exit;
|
|
||||||
}
|
|
||||||
ifr.ifr_netmask.sa_family = AF_INET;
|
|
||||||
((struct sockaddr_in *)&ifr.ifr_netmask)->sin_addr.s_addr = inet_addr("255.255.255.0");
|
|
||||||
if(0 > ioctl(sock, SIOCSIFNETMASK, &ifr))
|
|
||||||
{
|
|
||||||
perror("ioctl");
|
|
||||||
goto clean_exit;
|
|
||||||
}
|
|
||||||
shutdown(sock, SHUT_RDWR);
|
|
||||||
|
|
||||||
return(tun_fd);
|
|
||||||
|
|
||||||
clean_exit:
|
|
||||||
if (sock != -1) {
|
|
||||||
shutdown(sock, SHUT_RDWR);
|
|
||||||
}
|
|
||||||
if (tun_fd != -1) {
|
|
||||||
close(tun_fd);
|
|
||||||
}
|
|
||||||
return SRSLTE_ERROR;
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue