You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1133 lines
34 KiB
C++

/*
* Copyright 2013-2019 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/.
*
*/
#include "srslte/asn1/asn1_utils.h"
#include <cmath>
#include <stdio.h>
namespace asn1 {
/************************
logging
************************/
void vlog_print(log_handler_t handler, void* ctx, srsasn_logger_level_t log_level, const char* format, va_list args)
{
if (handler) {
char* args_msg = NULL;
if (vasprintf(&args_msg, format, args) > 0) {
handler(log_level, ctx, args_msg);
}
if (args_msg) {
free(args_msg);
}
} else {
vprintf(format, args);
}
}
static log_handler_t log_handler;
static void* callback_ctx = NULL;
void srsasn_log_register_handler(void* ctx, log_handler_t handler)
{
log_handler = handler;
callback_ctx = ctx;
}
void srsasn_log_print(srsasn_logger_level_t log_level, const char* format, ...)
{
va_list args;
va_start(args, format);
vlog_print(log_handler, callback_ctx, log_level, format, args);
va_end(args);
}
/************************
error handling
************************/
void log_error_code(SRSASN_CODE code, const char* filename, int line)
{
switch (code) {
case SRSASN_ERROR_ENCODE_FAIL:
srsasn_log_print(LOG_LEVEL_ERROR, "[%s][%d] Encoding failure.\n", filename, line);
break;
case SRSASN_ERROR_DECODE_FAIL:
srsasn_log_print(LOG_LEVEL_ERROR, "[%s][%d] Decoding failure.\n", filename, line);
break;
default:
srsasn_log_print(LOG_LEVEL_WARN, "[%s][%d] SRSASN_CODE=%d not recognized.\n", filename, line, (uint32_t)code);
}
}
/*********************
bit_ref
*********************/
bit_ref::bit_ref() : ptr(NULL), offset(0), start_ptr(NULL), max_ptr(NULL) {}
bit_ref::bit_ref(uint8_t* start_ptr_, uint32_t max_size_) :
ptr(start_ptr_),
offset(0),
start_ptr(start_ptr_),
max_ptr(max_size_ + start_ptr_)
{
}
int bit_ref::distance(const bit_ref& other) const
{
return ((int)offset - (int)other.offset) + 8 * ((int)(ptr - other.ptr));
}
int bit_ref::distance(uint8_t* ref_ptr) const
{
return (int)offset + 8 * ((int)(ptr - ref_ptr));
}
int bit_ref::distance() const
{
return (int)offset + 8 * ((int)(ptr - start_ptr));
}
int bit_ref::distance_bytes(uint8_t* ref_ptr) const
{
return ((int)(ptr - ref_ptr)) + ((offset) ? 1 : 0);
}
int bit_ref::distance_bytes() const
{
return ((int)(ptr - start_ptr)) + ((offset) ? 1 : 0);
}
SRSASN_CODE bit_ref::pack(uint32_t val, uint32_t n_bits)
{
uint32_t mask;
while (n_bits > 0) {
if (ptr >= max_ptr) {
srsasn_log_print(LOG_LEVEL_ERROR, "Buffer size limit was achieved\n");
return SRSASN_ERROR_ENCODE_FAIL;
}
mask = ((1u << n_bits) - 1u);
val = val & mask;
uint8_t keepmask = ((uint8_t)-1) - (uint8_t)((1 << (8 - offset)) - 1);
if ((uint32_t)(8 - offset) > n_bits) {
uint8_t bit = (uint8_t)(val << (8u - offset - n_bits));
*ptr = ((*ptr) & keepmask) + bit;
offset += n_bits;
n_bits = 0;
} else {
uint8_t bit = (uint8_t)(val >> (n_bits - 8u + offset));
*ptr = (*ptr & keepmask) + bit;
n_bits -= (8 - offset);
offset = 0;
ptr++;
}
}
return SRSASN_SUCCESS;
}
ValOrError unpack_bits(uint8_t*& ptr, uint8_t& offset, uint8_t* max_ptr, uint32_t n_bits)
{
uint32_t val = 0;
while (n_bits > 0) {
if (ptr >= max_ptr) {
srsasn_log_print(LOG_LEVEL_ERROR, "Buffer size limit was achieved\n");
return ValOrError(val, SRSASN_ERROR_DECODE_FAIL);
}
if ((uint32_t)(8 - offset) > n_bits) {
uint8_t mask = (uint8_t)(1u << (8u - offset)) - (uint8_t)(1u << (8u - offset - n_bits));
val += ((uint32_t)((*ptr) & mask)) >> ((uint8_t)8 - offset - n_bits);
offset += n_bits;
n_bits = 0;
} else {
uint8_t mask = (uint8_t)((1u << (8u - offset)) - 1);
val += ((uint32_t)((*ptr) & mask)) << (n_bits - 8 + offset);
n_bits -= 8 - offset;
offset = 0;
ptr++;
}
}
return ValOrError(val, SRSASN_SUCCESS);
}
SRSASN_CODE bit_ref::align_bytes()
{
if (offset == 0)
return SRSASN_SUCCESS;
if (ptr >= max_ptr) {
srsasn_log_print(LOG_LEVEL_ERROR, "Buffer size limit was achieved\n");
return SRSASN_ERROR_DECODE_FAIL;
}
offset = 0;
ptr++;
return SRSASN_SUCCESS;
}
SRSASN_CODE bit_ref::align_bytes_zero()
{
if (offset == 0)
return SRSASN_SUCCESS;
if (ptr >= max_ptr) {
srsasn_log_print(LOG_LEVEL_ERROR, "Buffer size limit was achieved\n");
return SRSASN_ERROR_ENCODE_FAIL;
}
uint8_t mask = (uint8_t)(256u - (1u << (8u - offset)));
*ptr &= mask;
offset = 0;
ptr++;
return SRSASN_SUCCESS;
}
void bit_ref::set(uint8_t* start_ptr_, uint32_t max_size_)
{
ptr = start_ptr_;
offset = 0;
start_ptr = start_ptr_;
max_ptr = max_size_ + start_ptr_;
}
/*********************
ext packing
*********************/
SRSASN_CODE pack_unsupported_ext_flag(bit_ref& bref, bool ext)
{
HANDLE_CODE(bref.pack(ext, 1));
if (ext) {
srsasn_log_print(LOG_LEVEL_ERROR, "asn1 error: ASN extensions not currently supported\n");
return SRSASN_ERROR_ENCODE_FAIL;
}
return SRSASN_SUCCESS;
}
SRSASN_CODE unpack_unsupported_ext_flag(bool& ext, bit_ref& bref)
{
SRSASN_CODE ret = bref.unpack(ext, 1);
if (ext) {
srsasn_log_print(LOG_LEVEL_ERROR, "asn1 error: ASN extensions not currently supported\n");
return SRSASN_ERROR_DECODE_FAIL;
}
return ret;
}
/************************
enum packing
************************/
// Pack without extension
SRSASN_CODE pack_enum(bit_ref& bref, uint32_t enum_val, uint32_t nbits)
{
return bref.pack(enum_val, nbits);
}
// Pack with extension
SRSASN_CODE pack_enum(bit_ref& bref, uint32_t enum_val, uint32_t nbits, uint32_t nof_noext)
{
bool ext = enum_val >= nof_noext;
HANDLE_CODE(bref.pack((bool)ext, 1));
SRSASN_CODE ret;
if (not ext) {
ret = bref.pack(enum_val, nbits);
} else {
ret = pack_norm_small_integer(bref, enum_val - nof_noext);
}
return ret;
}
SRSASN_CODE pack_enum(bit_ref& bref, uint32_t e, uint32_t nof_types, uint32_t nof_exts, bool has_ext)
{
if (e >= nof_types) {
srsasn_log_print(LOG_LEVEL_ERROR, "The provided enum is not within the range of possible values (%d>=%d)\n", e,
nof_types);
return SRSASN_ERROR_ENCODE_FAIL;
}
SRSASN_CODE ret;
if (has_ext) {
uint32_t nof_bits = (uint32_t)ceilf(log2f(nof_types - nof_exts));
ret = pack_enum(bref, e, nof_bits, nof_types - nof_exts);
} else {
uint32_t nof_bits = (uint32_t)ceilf(log2f(nof_types));
ret = pack_enum(bref, e, nof_bits);
}
return ret;
}
ValOrError unpack_enum(uint32_t nof_types, uint32_t nof_exts, bool has_ext, bit_ref& bref)
{
ValOrError ret;
if (has_ext) {
uint32_t nof_bits = (uint32_t)ceilf(log2f(nof_types - nof_exts));
bool ext;
ret.code = bref.unpack(ext, 1);
if (ret.code != SRSASN_SUCCESS) {
return ret;
}
if (not ext) {
ret.code = bref.unpack(ret.val, nof_bits);
} else {
ret.code = unpack_norm_small_integer(ret.val, bref);
ret.val += nof_types - nof_exts;
}
} else {
uint32_t nof_bits = (uint32_t)ceilf(log2f(nof_types));
ret.code = bref.unpack(ret.val, nof_bits);
}
if (ret.val >= nof_types) {
srsasn_log_print(LOG_LEVEL_ERROR, "The provided enum is not within the range of possible values (%d>=%d)\n",
ret.val, nof_types);
ret.code = SRSASN_ERROR_DECODE_FAIL;
}
return ret;
}
/************************
pack int
************************/
/**
* Encoder function for a constrained whole unaligned number
* @tparam IntType type of integer (e.g. uint8_t, uint32_t, etc.)
* @param bref bit_ref where to encode integer
* @param n integer current value
* @param lb
* @param ub
* @return success or failure
*/
template <class IntType>
SRSASN_CODE pack_unalign_integer(bit_ref& bref, IntType n, IntType lb, IntType ub)
{
if (ub < lb or n < lb or n > ub) {
srsasn_log_print(LOG_LEVEL_ERROR, "The condition lb <= n <= ub (%d <= %d <= %d) was not met\n", lb, n, ub);
return SRSASN_ERROR_ENCODE_FAIL;
}
uint64_t ra = ub - lb + 1; // NOTE: Can overflow if IntType is kept
if (ra != 1) {
uint32_t n_bits = (uint32_t)ceilf(log2f((float)ra));
IntType toencode = n - lb;
bref.pack(toencode, n_bits);
}
return SRSASN_SUCCESS;
}
/**
* Encoder function for a constrained whole unaligned number
* @tparam IntType type of integer (e.g. uint8_t, uint32_t, etc.)
* @param bref bit_ref where to encode integer
* @param n integer current value
* @param lb
* @param ub
* @return success or failure
*/
template <class IntType>
SRSASN_CODE unpack_unalign_integer(IntType& n, bit_ref& bref, IntType lb, IntType ub)
{
if (ub < lb) {
srsasn_log_print(LOG_LEVEL_ERROR, "The condition lb <= ub (%d <= %d) was not met\n", lb, ub);
return SRSASN_ERROR_DECODE_FAIL;
}
uint64_t ra = ub - lb + 1; // NOTE: Can overflow if IntType is kept.
if (ra == 1) {
n = lb;
return SRSASN_SUCCESS;
}
uint32_t n_bits = (uint32_t)ceilf(log2f(ra));
SRSASN_CODE ret = bref.unpack(n, n_bits);
n += lb;
if (n < lb or n > ub) {
srsasn_log_print(LOG_LEVEL_ERROR, "The condition lb <= n <= ub (%d <= %d <= %d) was not met\n", lb, n, ub);
return SRSASN_ERROR_DECODE_FAIL;
}
return ret;
}
template SRSASN_CODE pack_unalign_integer<int8_t>(bit_ref& bref, int8_t n, int8_t lb, int8_t ub);
template SRSASN_CODE pack_unalign_integer<int16_t>(bit_ref& bref, int16_t n, int16_t lb, int16_t ub);
template SRSASN_CODE pack_unalign_integer<int32_t>(bit_ref& bref, int32_t n, int32_t lb, int32_t ub);
template SRSASN_CODE pack_unalign_integer<int64_t>(bit_ref& bref, int64_t n, int64_t lb, int64_t ub);
template SRSASN_CODE pack_unalign_integer<uint8_t>(bit_ref& bref, uint8_t n, uint8_t lb, uint8_t ub);
template SRSASN_CODE pack_unalign_integer<uint16_t>(bit_ref& bref, uint16_t n, uint16_t lb, uint16_t ub);
template SRSASN_CODE pack_unalign_integer<uint32_t>(bit_ref& bref, uint32_t n, uint32_t lb, uint32_t ub);
template SRSASN_CODE pack_unalign_integer<uint64_t>(bit_ref& bref, uint64_t n, uint64_t lb, uint64_t ub);
template SRSASN_CODE unpack_unalign_integer<int8_t>(int8_t& n, bit_ref& bref, int8_t lb, int8_t ub);
template SRSASN_CODE unpack_unalign_integer<int16_t>(int16_t& n, bit_ref& bref, int16_t lb, int16_t ub);
template SRSASN_CODE unpack_unalign_integer<int32_t>(int32_t& n, bit_ref& bref, int32_t lb, int32_t ub);
template SRSASN_CODE unpack_unalign_integer<int64_t>(int64_t& n, bit_ref& bref, int64_t lb, int64_t ub);
template SRSASN_CODE unpack_unalign_integer<uint8_t>(uint8_t& n, bit_ref& bref, uint8_t lb, uint8_t ub);
template SRSASN_CODE unpack_unalign_integer<uint16_t>(uint16_t& n, bit_ref& bref, uint16_t lb, uint16_t ub);
template SRSASN_CODE unpack_unalign_integer<uint32_t>(uint32_t& n, bit_ref& bref, uint32_t lb, uint32_t ub);
template SRSASN_CODE unpack_unalign_integer<uint64_t>(uint64_t& n, bit_ref& bref, uint64_t lb, uint64_t ub);
template <class IntType>
UnalignedIntegerPacker<IntType>::UnalignedIntegerPacker(IntType lb_, IntType ub_) : lb(lb_), ub(ub_)
{
}
template <class IntType>
SRSASN_CODE UnalignedIntegerPacker<IntType>::pack(bit_ref& bref, IntType n) const
{
return pack_unalign_integer(bref, n, lb, ub);
}
template <class IntType>
SRSASN_CODE UnalignedIntegerPacker<IntType>::unpack(IntType& n, bit_ref& bref) const
{
return unpack_unalign_integer(n, bref, lb, ub);
}
template struct UnalignedIntegerPacker<int8_t>;
template struct UnalignedIntegerPacker<int16_t>;
template struct UnalignedIntegerPacker<int32_t>;
template struct UnalignedIntegerPacker<int64_t>;
template struct UnalignedIntegerPacker<uint8_t>;
template struct UnalignedIntegerPacker<uint16_t>;
template struct UnalignedIntegerPacker<uint32_t>;
template struct UnalignedIntegerPacker<uint64_t>;
/**
* Encoder of a constrained whole aligned number
* @tparam IntType type of integer (e.g. uint8_t, uint32_t, etc.)
* @param bref bit_ref where to encode integer
* @param n value of integer to pack
* @param lb
* @param ub
* @return
*/
template <class IntType>
SRSASN_CODE pack_align_integer(bit_ref& bref, IntType n, IntType lb, IntType ub)
{
// FIXME: Bound checker.
IntType ra = ub - lb + 1;
if (ra == 1) {
return SRSASN_SUCCESS;
}
uint32_t n_bits = (uint32_t)ceilf(log2f(ra)); // bit-field size
IntType toencode = n - lb;
SRSASN_CODE ret;
if (ra < 256) {
ret = bref.pack(toencode, n_bits);
} else if (ra <= 65536) {
uint32_t n_octets = (n_bits + 7) / 8;
HANDLE_CODE(bref.align_bytes_zero());
HANDLE_CODE(bref.pack(0, n_octets * 8 - n_bits));
HANDLE_CODE(bref.pack(toencode, n_bits));
ret = bref.align_bytes_zero();
} else {
// TODO: Check if this is correct
uint32_t n_bits_len = (uint32_t)ceilf(log2f((n_bits + 7) / 8));
n_bits = (uint32_t)floorf(log2f(toencode) + 1);
uint32_t n_octets = (uint32_t)((n_bits + 7) / 8);
HANDLE_CODE(bref.pack(n_octets - 1, n_bits_len));
HANDLE_CODE(bref.align_bytes_zero());
HANDLE_CODE(bref.pack(0, (n_octets * 8) - n_bits));
ret = bref.pack(toencode, n_bits);
}
return ret;
}
template SRSASN_CODE pack_align_integer<uint8_t>(bit_ref& bref, uint8_t n, uint8_t lb, uint8_t ub);
template SRSASN_CODE pack_align_integer<uint16_t>(bit_ref& bref, uint16_t n, uint16_t lb, uint16_t ub);
template SRSASN_CODE pack_align_integer<uint32_t>(bit_ref& bref, uint32_t n, uint32_t lb, uint32_t ub);
template SRSASN_CODE pack_align_integer<uint64_t>(bit_ref& bref, uint64_t n, uint64_t lb, uint64_t ub);
template SRSASN_CODE pack_align_integer<int8_t>(bit_ref& bref, int8_t n, int8_t lb, int8_t ub);
template SRSASN_CODE pack_align_integer<int16_t>(bit_ref& bref, int16_t n, int16_t lb, int16_t ub);
template SRSASN_CODE pack_align_integer<int32_t>(bit_ref& bref, int32_t n, int32_t lb, int32_t ub);
template SRSASN_CODE pack_align_integer<int64_t>(bit_ref& bref, int64_t n, int64_t lb, int64_t ub);
template <typename IntType>
SRSASN_CODE unpack_align_integer(IntType& n, bit_ref& bref, IntType lb, IntType ub)
{
uint32_t ra = ub - lb + 1;
if (ra == 1) {
n = lb;
return SRSASN_SUCCESS;
}
SRSASN_CODE ret = SRSASN_SUCCESS;
uint32_t n_bits = (uint32_t)ceil(log2(ra));
if (ra < 256) {
ret = bref.unpack(n, n_bits);
} else if (ra < 65536) {
uint32_t n_octets = (n_bits + 7) / 8;
HANDLE_CODE(bref.align_bytes());
HANDLE_CODE(bref.unpack(n, n_octets * 8));
HANDLE_CODE(bref.align_bytes());
} else {
uint32_t n_bits_len = (uint32_t)ceilf(log2f((n_bits + 7) / 8));
uint32_t n_octets;
HANDLE_CODE(bref.unpack(n_octets, n_bits_len));
n_octets += 1;
HANDLE_CODE(bref.align_bytes());
HANDLE_CODE(bref.unpack(n, n_octets * 8));
n += lb;
}
n += lb;
return ret;
}
template SRSASN_CODE unpack_align_integer<uint8_t>(uint8_t& intval, bit_ref& bref, uint8_t lb, uint8_t ub);
template SRSASN_CODE unpack_align_integer<uint16_t>(uint16_t& intval, bit_ref& bref, uint16_t lb, uint16_t ub);
template SRSASN_CODE unpack_align_integer<uint32_t>(uint32_t& intval, bit_ref& bref, uint32_t lb, uint32_t ub);
template SRSASN_CODE unpack_align_integer<uint64_t>(uint64_t& intval, bit_ref& bref, uint64_t lb, uint64_t ub);
template SRSASN_CODE unpack_align_integer<int8_t>(int8_t& intval, bit_ref& bref, int8_t lb, int8_t ub);
template SRSASN_CODE unpack_align_integer<int16_t>(int16_t& intval, bit_ref& bref, int16_t lb, int16_t ub);
template SRSASN_CODE unpack_align_integer<int32_t>(int32_t& intval, bit_ref& bref, int32_t lb, int32_t ub);
template SRSASN_CODE unpack_align_integer<int64_t>(int64_t& intval, bit_ref& bref, int64_t lb, int64_t ub);
template <class IntType>
AlignedIntegerPacker<IntType>::AlignedIntegerPacker(IntType lb_, IntType ub_) : lb(lb_), ub(ub_)
{
}
template <class IntType>
SRSASN_CODE AlignedIntegerPacker<IntType>::pack(bit_ref& bref, IntType n)
{
return pack_align_integer(bref, n, lb, ub);
}
template <class IntType>
SRSASN_CODE AlignedIntegerPacker<IntType>::unpack(IntType& n, bit_ref& bref)
{
return unpack_align_integer(n, bref, lb, ub);
}
template struct AlignedIntegerPacker<int8_t>;
template struct AlignedIntegerPacker<int16_t>;
template struct AlignedIntegerPacker<int32_t>;
template struct AlignedIntegerPacker<int64_t>;
template struct AlignedIntegerPacker<uint8_t>;
template struct AlignedIntegerPacker<uint16_t>;
template struct AlignedIntegerPacker<uint32_t>;
template struct AlignedIntegerPacker<uint64_t>;
template <typename UintType>
SRSASN_CODE pack_norm_small_integer(bit_ref& bref, UintType n)
{
if (n <= 63) {
HANDLE_CODE(bref.pack(0, 1));
HANDLE_CODE(bref.pack(n, 6));
} else {
HANDLE_CODE(bref.pack(1, 1));
srsasn_log_print(LOG_LEVEL_ERROR, "Long small integers not supported\n");
return SRSASN_ERROR_ENCODE_FAIL;
}
return SRSASN_SUCCESS;
}
template <typename UintType>
SRSASN_CODE unpack_norm_small_integer(UintType& n, bit_ref& bref)
{
bool ext;
SRSASN_CODE ret = bref.unpack(ext, 1);
HANDLE_CODE(ret);
if (not ext) {
ret = bref.unpack(n, 6);
} else {
srsasn_log_print(LOG_LEVEL_ERROR, "Long small integers not supported\n");
return SRSASN_ERROR_DECODE_FAIL;
}
return ret;
}
template SRSASN_CODE pack_norm_small_integer<uint8_t>(bit_ref& bref, uint8_t n);
template SRSASN_CODE pack_norm_small_integer<uint16_t>(bit_ref& bref, uint16_t n);
template SRSASN_CODE pack_norm_small_integer<uint32_t>(bit_ref& bref, uint32_t n);
template SRSASN_CODE pack_norm_small_integer<uint64_t>(bit_ref& bref, uint64_t n);
template SRSASN_CODE unpack_norm_small_integer<uint8_t>(uint8_t& n, bit_ref& bref);
template SRSASN_CODE unpack_norm_small_integer<uint16_t>(uint16_t& n, bit_ref& bref);
template SRSASN_CODE unpack_norm_small_integer<uint32_t>(uint32_t& n, bit_ref& bref);
template SRSASN_CODE unpack_norm_small_integer<uint64_t>(uint64_t& n, bit_ref& bref);
/*********************
varlength_packing
*********************/
template <typename IntType>
SRSASN_CODE pack_length(bit_ref& bref, IntType n, IntType lb, IntType ub)
{
// TODO: FIXME if range higher than 64K
return pack_unalign_integer(bref, n, lb, ub);
}
template SRSASN_CODE pack_length<uint8_t>(bit_ref& bref, uint8_t n, uint8_t lb, uint8_t ub);
template SRSASN_CODE pack_length<uint16_t>(bit_ref& bref, uint16_t n, uint16_t lb, uint16_t ub);
template SRSASN_CODE pack_length<uint32_t>(bit_ref& bref, uint32_t n, uint32_t lb, uint32_t ub);
template SRSASN_CODE pack_length<uint64_t>(bit_ref& bref, uint64_t n, uint64_t lb, uint64_t ub);
template SRSASN_CODE pack_length<int8_t>(bit_ref& bref, int8_t n, int8_t lb, int8_t ub);
template SRSASN_CODE pack_length<int16_t>(bit_ref& bref, int16_t n, int16_t lb, int16_t ub);
template SRSASN_CODE pack_length<int32_t>(bit_ref& bref, int32_t n, int32_t lb, int32_t ub);
template SRSASN_CODE pack_length<int64_t>(bit_ref& bref, int64_t n, int64_t lb, int64_t ub);
template <typename IntType>
SRSASN_CODE unpack_length(IntType& n, bit_ref& bref, IntType lb, IntType ub)
{
// TODO: FIXME if range higher than 64K
return unpack_unalign_integer(n, bref, lb, ub);
}
template SRSASN_CODE unpack_length<uint8_t>(uint8_t& n, bit_ref& bref, uint8_t lb, uint8_t ub);
template SRSASN_CODE unpack_length<uint16_t>(uint16_t& n, bit_ref& bref, uint16_t lb, uint16_t ub);
template SRSASN_CODE unpack_length<uint32_t>(uint32_t& n, bit_ref& bref, uint32_t lb, uint32_t ub);
template SRSASN_CODE unpack_length<uint64_t>(uint64_t& n, bit_ref& bref, uint64_t lb, uint64_t ub);
template SRSASN_CODE unpack_length<int8_t>(int8_t& n, bit_ref& bref, int8_t lb, int8_t ub);
template SRSASN_CODE unpack_length<int16_t>(int16_t& n, bit_ref& bref, int16_t lb, int16_t ub);
template SRSASN_CODE unpack_length<int32_t>(int32_t& n, bit_ref& bref, int32_t lb, int32_t ub);
template SRSASN_CODE unpack_length<int64_t>(int64_t& n, bit_ref& bref, int64_t lb, int64_t ub);
SRSASN_CODE pack_length(bit_ref& bref, uint32_t val)
{
if (val < 128) {
HANDLE_CODE(bref.pack(0, 1));
HANDLE_CODE(bref.pack(val, 7));
} else if (val < ASN_16K) {
HANDLE_CODE(bref.pack(1, 1));
HANDLE_CODE(bref.pack(0, 1));
HANDLE_CODE(bref.pack(val, 14));
} else {
srsasn_log_print(LOG_LEVEL_ERROR, "Not handling sizes longer than 16383 octets\n");
return SRSASN_ERROR_ENCODE_FAIL;
}
return SRSASN_SUCCESS;
}
SRSASN_CODE unpack_length(uint32_t& val, bit_ref& bref)
{
bool ext;
SRSASN_CODE ret = bref.unpack(ext, 1);
HANDLE_CODE(ret);
if (not ext) {
ret = bref.unpack(val, 7);
} else {
ret = bref.unpack(ext, 1);
HANDLE_CODE(ret);
if (not ext) {
ret = bref.unpack(val, 14);
} else {
srsasn_log_print(LOG_LEVEL_ERROR, "Not handling octet strings longer than 16383 octets\n");
val = 0;
return SRSASN_ERROR_DECODE_FAIL;
}
}
return ret;
}
/************************
common octstring
************************/
uint64_t octstring_to_number(const uint8_t* ptr, uint32_t nbytes)
{
if (nbytes > 8) {
srsasn_log_print(LOG_LEVEL_ERROR, "octstring of size=%d does not fit in an uint64_t\n", nbytes);
return 0;
}
uint64_t val = 0;
for (uint32_t i = 0; i < nbytes; ++i) {
val += ((uint64_t)ptr[nbytes - 1 - i]) << (uint64_t)(i * 8);
}
return val;
}
void number_to_octstring(uint8_t* ptr, uint64_t number, uint32_t nbytes)
{
if (nbytes > 8) {
srsasn_log_print(LOG_LEVEL_ERROR, "octstring of size=%d does not fit in an uint64_t\n", nbytes);
return;
}
for (uint32_t i = 0; i < nbytes; ++i) {
ptr[nbytes - 1 - i] = (number >> (uint64_t)(i * 8u)) & 0xFF;
}
}
void to_hex(char* cstr, uint8_t val)
{
sprintf(cstr, "%02x", val);
}
// helper functions
std::string octstring_to_string(const uint8_t* ptr, uint32_t N)
{
std::string s;
s.resize(N * 2);
char cstr[3];
for (uint32_t i = 0; i < N; i++) {
to_hex(cstr, ptr[i]);
s.replace(i * 2, 2, cstr);
}
return s;
}
void string_to_octstring(uint8_t* ptr, const std::string& str)
{
if (str.size() % 2 != 0) {
srsasn_log_print(LOG_LEVEL_WARN, "The provided hex string size=%d is not a multiple of 2\n.", str.size());
}
char cstr[] = "\0\0\0";
for (uint32_t i = 0; i < str.size(); i += 2) {
memcpy(&cstr[0], &str[i], 2);
ptr[i / 2] = strtoul(cstr, NULL, 16);
}
}
/************************
dyn_octstring
************************/
SRSASN_CODE dyn_octstring::pack(bit_ref& bref) const
{
HANDLE_CODE(pack_length(bref, size()));
for (uint32_t i = 0; i < size(); ++i) {
HANDLE_CODE(bref.pack(octets_[i], 8));
}
return SRSASN_SUCCESS;
}
SRSASN_CODE dyn_octstring::unpack(bit_ref& bref)
{
uint32_t len;
HANDLE_CODE(unpack_length(len, bref));
resize(len);
for (uint32_t i = 0; i < size(); ++i) {
HANDLE_CODE(bref.unpack(octets_[i], 8));
}
return SRSASN_SUCCESS;
}
std::string dyn_octstring::to_string() const
{
return octstring_to_string(&octets_[0], size());
}
dyn_octstring& dyn_octstring::from_string(const std::string& hexstr)
{
resize(hexstr.size() / 2);
string_to_octstring(&octets_[0], hexstr);
return *this;
}
/*********************
bitstring
*********************/
SRSASN_CODE pack_common_bitstring(bit_ref& bref, const uint8_t* buf, uint32_t nbits)
{
uint32_t n_octs = (uint32_t)ceilf(nbits / 8.0f);
uint32_t offset = ((nbits - 1) % 8) + 1;
HANDLE_CODE(bref.pack(buf[n_octs - 1], offset));
for (uint32_t i = 1; i < n_octs; ++i) {
HANDLE_CODE(bref.pack(buf[n_octs - 1 - i], 8));
}
return SRSASN_SUCCESS;
}
SRSASN_CODE unpack_common_bitstring(uint8_t* buf, bit_ref& bref, uint32_t nbits)
{
uint32_t n_octs = (uint32_t)ceilf(nbits / 8.0f);
uint32_t offset = ((nbits - 1) % 8) + 1;
HANDLE_CODE(bref.unpack(buf[n_octs - 1], offset));
for (uint32_t i = 1; i < n_octs; ++i) {
HANDLE_CODE(bref.unpack(buf[n_octs - 1 - i], 8));
}
return SRSASN_SUCCESS;
}
uint64_t bitstring_to_number(const uint8_t* ptr, uint32_t nbits)
{
if (nbits > 64) {
srsasn_log_print(LOG_LEVEL_ERROR, "bitstring of size=%d does not fit in an uint64_t\n", nbits);
return 0;
}
uint64_t val = 0;
uint32_t nof_bytes = (uint32_t)ceilf(nbits / 8.0f);
for (uint32_t i = 0; i < nof_bytes; ++i) {
val += ptr[i] << (i * 8);
}
return val;
}
void number_to_bitstring(uint8_t* ptr, uint64_t number, uint32_t nbits)
{
if (nbits > 64) {
srsasn_log_print(LOG_LEVEL_ERROR, "bitstring of size=%d does not fit in an uint64_t\n", nbits);
return;
}
uint32_t nof_bytes = (uint32_t)ceilf(nbits / 8.0f);
for (uint32_t i = 0; i < nof_bytes; ++i) {
ptr[i] = (number >> (i * 8)) & 0xFF;
}
uint32_t offset = nbits % 8; // clean up any extra set bit
if (offset > 0) {
ptr[nof_bytes - 1] &= (uint8_t)((1 << offset) - 1);
}
}
std::string bitstring_to_string(const uint8_t* ptr, uint32_t nbits)
{
std::string str(nbits, '\0');
for (uint32_t i = 0; i < nbits; ++i) {
str[i] = bitstring_get(ptr, nbits - 1 - i) ? '1' : '0';
}
return str;
}
/*********************
fixed_bitstring
*********************/
SRSASN_CODE pack_fixed_bitstring(bit_ref& bref, const uint8_t* buf, uint32_t nbits)
{
// if(nbits > 16) { // X.691 Section 15
// bref.align_bytes_zero();
// }
return pack_common_bitstring(bref, buf, nbits);
// if(nbits > 16) { // X.691 Section 15
// bref.align_bytes_zero();
// }
}
SRSASN_CODE pack_fixed_bitstring(bit_ref& bref, const uint8_t* buf, uint32_t nbits, bool ext)
{
HANDLE_CODE(pack_unsupported_ext_flag(bref, ext));
HANDLE_CODE(pack_fixed_bitstring(bref, buf, nbits));
return SRSASN_SUCCESS;
}
SRSASN_CODE unpack_fixed_bitstring(uint8_t* buf, bit_ref& bref, uint32_t nbits)
{
// if(nbits > 16) { // X.691 Section 15
// bref.align_bytes_zero();
// }
return unpack_common_bitstring(buf, bref, nbits);
// if(nbits > 16) { // X.691 Section 15
// bref.align_bytes_zero();
// }
}
SRSASN_CODE unpack_fixed_bitstring(uint8_t* buf, bool& ext, bit_ref& bref, uint32_t nbits)
{
HANDLE_CODE(unpack_unsupported_ext_flag(ext, bref));
HANDLE_CODE(unpack_fixed_bitstring(buf, bref, nbits));
return SRSASN_SUCCESS;
}
/*********************
dyn_bitstring
*********************/
dyn_bitstring::dyn_bitstring(uint32_t n_bits_) : n_bits(n_bits_)
{
uint32_t n_bytes = nof_octets();
octets_.resize(n_bytes);
memset(&octets_[0], 0, n_bytes);
}
dyn_bitstring::dyn_bitstring(const char* s)
{
n_bits = (uint32_t)strlen(s);
uint32_t n_bytes = nof_octets();
octets_.resize(n_bytes);
memset(&octets_[0], 0, n_bytes);
for (uint32_t i = 0; i < n_bits; ++i)
this->set(i, s[n_bits - i - 1] == '1');
}
bool dyn_bitstring::operator==(const char* other_str) const
{
return strlen(other_str) == length() and (*this) == dyn_bitstring(other_str);
}
void dyn_bitstring::resize(uint32_t new_size)
{
n_bits = new_size;
octets_.resize(nof_octets());
memset(&octets_[0], 0, nof_octets());
}
SRSASN_CODE dyn_bitstring::pack(bit_ref& bref, uint32_t lb, uint32_t ub) const
{
uint32_t len = length();
if (len < lb) {
srsasn_log_print(LOG_LEVEL_ERROR, "dynamic bitstring length=%d is lower than set lower bound=%d\n", len, lb);
return SRSASN_ERROR_ENCODE_FAIL;
}
if (ub > 0) {
if (ub < len) {
srsasn_log_print(LOG_LEVEL_ERROR, "asn1 error: dynamic bitstring length=%d is higher than set upper bound=%d\n",
len, ub);
return SRSASN_ERROR_ENCODE_FAIL;
}
uint32_t len_bits = ceilf(log2(ub - lb));
HANDLE_CODE(bref.pack(len - lb, len_bits));
HANDLE_CODE(bref.align_bytes_zero());
} else {
HANDLE_CODE(pack_length(bref, len));
}
HANDLE_CODE(pack_common_bitstring(bref, &octets_[0], len));
// bref.align_bytes_zero();
return SRSASN_SUCCESS;
}
SRSASN_CODE dyn_bitstring::pack(bit_ref& bref, bool ext, uint32_t lb, uint32_t ub) const
{
HANDLE_CODE(pack_unsupported_ext_flag(bref, ext));
HANDLE_CODE(pack(bref, lb, ub));
return SRSASN_SUCCESS;
}
SRSASN_CODE dyn_bitstring::unpack(bit_ref& bref, uint32_t lb, uint32_t ub)
{
uint32_t len;
if (ub > 0) {
uint32_t len_bits = ceilf(log2f(ub - lb));
HANDLE_CODE(bref.unpack(len, len_bits));
len += lb;
resize(len);
HANDLE_CODE(bref.align_bytes_zero());
} else {
HANDLE_CODE(unpack_length(len, bref));
resize(len);
}
HANDLE_CODE(unpack_common_bitstring(&octets_[0], bref, len));
// bref.align_bytes_zero();
return SRSASN_SUCCESS;
}
SRSASN_CODE dyn_bitstring::unpack(bit_ref& bref, bool& ext, uint32_t lb, uint32_t ub)
{
HANDLE_CODE(unpack_unsupported_ext_flag(ext, bref));
HANDLE_CODE(unpack(bref, lb, ub));
return SRSASN_SUCCESS;
}
/*********************
choice utils
*********************/
void log_invalid_access_choice_id(uint32_t val, uint32_t choice_id)
{
srsasn_log_print(LOG_LEVEL_ERROR, "The access choide id is invalid (%d!=%d)\n", val, choice_id);
}
void log_invalid_choice_id(uint32_t val, const char* choice_type)
{
srsasn_log_print(LOG_LEVEL_ERROR, "Invalid choice id=%d for choice type %s\n", val, choice_type);
}
/*********************
ext group
*********************/
ext_groups_header::ext_groups_header(uint32_t max_nof_groups, uint32_t nof_nogroups_) : nof_nogroups(nof_nogroups_)
{
if (max_nof_groups > 20) {
srsasn_log_print(LOG_LEVEL_ERROR, "increase the size of ext group packer/unpacker\n");
}
groups.resize(max_nof_groups);
for (uint32_t i = 0; i < groups.size(); ++i) {
groups[i] = false;
}
nof_groups = groups.size() + 1; // unset
}
bool& ext_groups_header::operator[](uint32_t idx)
{
return groups[idx];
}
SRSASN_CODE ext_groups_header::pack_nof_groups(bit_ref& bref) const
{
nof_groups = 0;
for (uint32_t i = 0; i < groups.size(); ++i) {
if (groups[i]) {
nof_groups = i + 1;
}
}
if (nof_groups > groups.size()) {
srsasn_log_print(LOG_LEVEL_ERROR, "Exceeded maximum number of groups (%d>%d)\n", nof_groups, groups.size());
return SRSASN_ERROR_ENCODE_FAIL;
}
HANDLE_CODE(pack_norm_small_integer(bref, nof_groups + nof_nogroups - 1));
return SRSASN_SUCCESS;
}
SRSASN_CODE ext_groups_header::pack_group_flags(bit_ref& bref) const
{
// NOTE: nof_groups is cached
for (uint32_t i = 0; i < nof_groups; ++i) {
HANDLE_CODE(bref.pack(groups[i], 1));
}
return SRSASN_SUCCESS;
}
SRSASN_CODE ext_groups_header::pack(bit_ref& bref) const
{
HANDLE_CODE(pack_nof_groups(bref));
return pack_group_flags(bref);
}
SRSASN_CODE ext_groups_header::unpack_nof_groups(bit_ref& bref)
{
HANDLE_CODE(unpack_norm_small_integer(nof_groups, bref));
nof_groups += 1 - nof_nogroups;
if (nof_groups > groups.size()) {
srsasn_log_print(LOG_LEVEL_ERROR, "Exceeded maximum number of groups (%d>%d)\n", nof_groups, groups.size());
return SRSASN_ERROR_DECODE_FAIL;
}
return SRSASN_SUCCESS;
}
SRSASN_CODE ext_groups_header::unpack_group_flags(bit_ref& bref)
{
for (uint32_t i = 0; i < nof_groups; ++i) {
HANDLE_CODE(bref.unpack(groups[i], 1));
}
return SRSASN_SUCCESS;
}
SRSASN_CODE ext_groups_header::unpack(bit_ref& bref)
{
HANDLE_CODE(unpack_nof_groups(bref));
return unpack_group_flags(bref);
}
/*********************
Open Field
*********************/
varlength_field_pack_guard::varlength_field_pack_guard(bit_ref& bref)
{
brefstart = bref;
bref = bit_ref(&buffer[0], sizeof(buffer));
bref_tracker = &bref;
}
varlength_field_pack_guard::~varlength_field_pack_guard()
{
// fill the spare bits
const bit_ref bref0 = bit_ref(&buffer[0], sizeof(buffer));
uint32_t leftover = 7 - ((bref_tracker->distance(bref0) - (uint32_t)1) % (uint32_t)8);
bref_tracker->pack(0, leftover);
// check how many bytes were written in total
uint32_t nof_bytes = bref_tracker->distance(bref0) / (uint32_t)8;
if (nof_bytes > sizeof(buffer)) {
srsasn_log_print(LOG_LEVEL_ERROR, "The packed variable sized field is too long for the reserved buffer (%d > %d)\n",
nof_bytes, sizeof(buffer));
}
// go back in time to pack length
pack_length(brefstart, nof_bytes);
// pack encoded bytes
for (uint32_t i = 0; i < nof_bytes; ++i) {
brefstart.pack(buffer[i], 8);
}
*bref_tracker = brefstart;
}
varlength_field_unpack_guard::varlength_field_unpack_guard(bit_ref& bref)
{
unpack_length(len, bref);
bref0 = bref;
bref_tracker = &bref;
}
varlength_field_unpack_guard::~varlength_field_unpack_guard()
{
uint32_t pad;
bref_tracker->unpack(pad, len * 8 - bref_tracker->distance(bref0));
}
/*******************
JsonWriter
*******************/
json_writer::json_writer() : ident(""), sep(NONE) {}
void json_writer::write_fieldname(const std::string& fieldname)
{
if (sep == COMMA) {
ss << ",\n" << ident;
} else if (sep == NEWLINE) {
ss << "\n" << ident;
}
if (fieldname.size() > 0) {
ss << "\"" << fieldname << "\": ";
}
sep = NONE;
}
void json_writer::write_str(const std::string& fieldname, const std::string& value)
{
write_fieldname(fieldname);
ss << "\"" << value << "\"";
sep = COMMA;
}
void json_writer::write_str(const std::string& value)
{
write_str("", value);
}
void json_writer::write_int(const std::string& fieldname, int64_t value)
{
write_fieldname(fieldname);
ss << value;
sep = COMMA;
}
void json_writer::write_int(int64_t value)
{
write_int("", value);
}
void json_writer::write_bool(const std::string& fieldname, bool value)
{
write_fieldname(fieldname);
ss << (value ? "true" : "false");
sep = COMMA;
}
void json_writer::write_bool(bool value)
{
write_bool("", value);
}
void json_writer::write_null(const std::string& fieldname)
{
write_fieldname(fieldname);
ss << "null";
sep = COMMA;
}
void json_writer::write_null()
{
write_null("");
}
void json_writer::start_obj(const std::string& fieldname)
{
write_fieldname(fieldname);
ss << "{";
ident += " ";
sep = NEWLINE;
}
void json_writer::end_obj()
{
ident.erase(ident.size() - 2, 2);
ss << "\n" << ident << "}";
sep = COMMA;
}
void json_writer::start_array(const std::string& fieldname)
{
write_fieldname(fieldname);
ss << "[";
ident += " ";
sep = NEWLINE;
}
void json_writer::end_array()
{
ident.erase(ident.size() - 2, 2);
ss << "\n" << ident << "]";
sep = COMMA;
}
std::string json_writer::to_string() const
{
return ss.str();
}
} // namespace asn1