From 40f95ed7c422fb3ae22196a7dff9e0f27fd3a389 Mon Sep 17 00:00:00 2001 From: Vadim Yanitskiy Date: Wed, 3 Aug 2022 03:29:03 +0700 Subject: [PATCH] libosmo-csn1: check-in CSN.1 codec from osmo-pcu.git This commit introduces a new library called 'libosmo-csn1', which is going to be used by osmo-pcu and osmocom-bb for parsing and generation of PDUs defined using CSN.1 (see 3GPP TS 24.007). The actual CSN.1 codec is imported from osmo-pcu.git [1]. Change-Id: Ib195d1e2a53aead4f89c799cef1e5f1be110aad9 Related: [1] osmo-pcu.git 0eaa3d379828517b5478d0202a26f6f3eb561a4e Depends: libosmocore.git Ie8c0effb764547a0f9cc8c6825e11a6617501e95 --- Makefile.am | 30 + configure.ac | 84 ++ include/Makefile.am | 3 + include/osmocom/Makefile.am | 3 + include/osmocom/csn1/Makefile.am | 6 + include/osmocom/csn1/csn1.h | 615 ++++++++++ include/osmocom/csn1/wireshark_compat.h | 34 + libosmo-csn1.pc.in | 10 + m4/.gitkeep | 0 src/Makefile.am | 3 + src/csn1/Makefile.am | 34 + src/csn1/csn1.c | 103 ++ src/csn1/csn1_dec.c | 1424 +++++++++++++++++++++++ src/csn1/csn1_enc.c | 1301 +++++++++++++++++++++ 14 files changed, 3650 insertions(+) create mode 100644 Makefile.am create mode 100644 configure.ac create mode 100644 include/Makefile.am create mode 100644 include/osmocom/Makefile.am create mode 100644 include/osmocom/csn1/Makefile.am create mode 100644 include/osmocom/csn1/csn1.h create mode 100644 include/osmocom/csn1/wireshark_compat.h create mode 100644 libosmo-csn1.pc.in create mode 100644 m4/.gitkeep create mode 100644 src/Makefile.am create mode 100644 src/csn1/Makefile.am create mode 100644 src/csn1/csn1.c create mode 100644 src/csn1/csn1_dec.c create mode 100644 src/csn1/csn1_enc.c diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..130baa2 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,30 @@ +AUTOMAKE_OPTIONS = foreign dist-bzip2 1.6 + +ACLOCAL_AMFLAGS = -I m4 +AM_CPPFLAGS = \ + $(all_includes) \ + -I$(top_srcdir)/include \ + $(NULL) + +SUBDIRS = \ + include \ + src \ + $(NULL) + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = \ + libosmo-csn1.pc \ + $(NULL) + +BUILT_SOURCES = $(top_srcdir)/.version +EXTRA_DIST = \ + .version \ + git-version-gen \ + $(NULL) + +@RELMAKE@ + +$(top_srcdir)/.version: + echo $(VERSION) > $@-t && mv $@-t $@ +dist-hook: + echo $(VERSION) > $(distdir)/.tarball-version diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..5a97177 --- /dev/null +++ b/configure.ac @@ -0,0 +1,84 @@ +AC_INIT([libosmo-gprs], + m4_esyscmd([./git-version-gen .tarball-version]), + [osmocom-net-gprs@lists.osmocom.org]) + +AC_CONFIG_AUX_DIR([.]) +AC_CONFIG_MACRO_DIRS([m4]) + +AM_INIT_AUTOMAKE([dist-bzip2]) + +CFLAGS="$CFLAGS -std=gnu11" + +dnl kernel style compile messages +m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) + +dnl include release helper +RELMAKE='-include osmo-release.mk' +AC_SUBST([RELMAKE]) + +dnl checks for programs +AC_PROG_MAKE_SET +AC_PROG_CC +AC_PROG_INSTALL +LT_INIT + +dnl check for pkg-config (explained in detail in libosmocore/configure.ac) +AC_PATH_PROG(PKG_CONFIG_INSTALLED, pkg-config, no) +if test "x$PKG_CONFIG_INSTALLED" = "xno"; then + AC_MSG_WARN([You need to install pkg-config]) +fi +PKG_PROG_PKG_CONFIG([0.20]) + +dnl checks for libraries +AC_SEARCH_LIBS([dlopen], [dl dld], [LIBRARY_DL="$LIBS";LIBS=""]) +AC_SUBST(LIBRARY_DL) + +PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 1.7.0) + +dnl checks for header files +AC_HEADER_STDC + +dnl Checks for typedefs, structures and compiler characteristics + +AC_ARG_ENABLE(sanitize, + [AS_HELP_STRING( + [--enable-sanitize], + [Compile with address sanitizer enabled], + )], + [sanitize=$enableval], [sanitize="no"]) +if test x"$sanitize" = x"yes" +then + CFLAGS="$CFLAGS -fsanitize=address -fsanitize=undefined" + CPPFLAGS="$CPPFLAGS -fsanitize=address -fsanitize=undefined" +fi + +AC_ARG_ENABLE(werror, + [AS_HELP_STRING( + [--enable-werror], + [Turn all compiler warnings into errors, with exceptions: + a) deprecation (allow upstream to mark deprecation without breaking builds); + b) "#warning" pragmas (allow to remind ourselves of errors without breaking builds) + ] + )], + [werror=$enableval], [werror="no"]) +if test x"$werror" = x"yes" +then + WERROR_FLAGS="-Werror" + WERROR_FLAGS+=" -Wno-error=deprecated -Wno-error=deprecated-declarations" + WERROR_FLAGS+=" -Wno-error=cpp" # "#warning" + CFLAGS="$CFLAGS $WERROR_FLAGS" + CPPFLAGS="$CPPFLAGS $WERROR_FLAGS" +fi + +AC_MSG_RESULT([CFLAGS="$CFLAGS"]) +AC_MSG_RESULT([CPPFLAGS="$CPPFLAGS"]) + +AC_CONFIG_HEADERS([config.h]) +AC_CONFIG_FILES([libosmo-csn1.pc + include/Makefile + include/osmocom/Makefile + include/osmocom/csn1/Makefile + src/Makefile + src/csn1/Makefile + Makefile]) +AC_OUTPUT diff --git a/include/Makefile.am b/include/Makefile.am new file mode 100644 index 0000000..9d963a0 --- /dev/null +++ b/include/Makefile.am @@ -0,0 +1,3 @@ +SUBDIRS = \ + osmocom \ + $(NULL) diff --git a/include/osmocom/Makefile.am b/include/osmocom/Makefile.am new file mode 100644 index 0000000..120b825 --- /dev/null +++ b/include/osmocom/Makefile.am @@ -0,0 +1,3 @@ +SUBDIRS = \ + csn1 \ + $(NULL) diff --git a/include/osmocom/csn1/Makefile.am b/include/osmocom/csn1/Makefile.am new file mode 100644 index 0000000..d16b724 --- /dev/null +++ b/include/osmocom/csn1/Makefile.am @@ -0,0 +1,6 @@ +csn1_HEADERS = \ + wireshark_compat.h \ + csn1.h \ + $(NULL) + +csn1dir = $(includedir)/osmocom/csn1 diff --git a/include/osmocom/csn1/csn1.h b/include/osmocom/csn1/csn1.h new file mode 100644 index 0000000..47956c3 --- /dev/null +++ b/include/osmocom/csn1/csn1.h @@ -0,0 +1,615 @@ +/* csn1.h + * Declarations and types for CSN1 dissection in wireshark. + * By Vincent Helfre, based on original code by Jari Sassi + * with the gracious authorization of STE + * Copyright (c) 2011 ST-Ericsson + * + * $Id: packet-csn1.h 36306 2011-03-24 09:20:14Z etxrab $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _PACKET_CSN1_H_ +#define _PACKET_CSN1_H_ + +#include +#include "wireshark_compat.h" + +/* Error codes */ +#define CSN_OK 0 +#define CSN_ERROR_GENERAL -1 +#define CSN_ERROR_DATA_NOT_VALID -2 +#define CSN_ERROR_IN_SCRIPT -3 +#define CSN_ERROR_INVALID_UNION_INDEX -4 +#define CSN_ERROR_NEED_MORE_BITS_TO_UNPACK -5 +#define CSN_ERROR_ILLEGAL_BIT_VALUE -6 +#define CSN_ERROR_INTERNAL -7 +#define CSN_ERROR_STREAM_NOT_SUPPORTED -8 +#define CSN_ERROR_MESSAGE_TOO_LONG -9 +#define CSN_ERROR_ -10 + +/* CallBack return status */ +typedef gint16 CSN_CallBackStatus_t; + +#define CSNCBS_OK 0 +#define CSNCBS_NOT_OK -10 +#define CSNCBS_NOT_TO_US -11 +#define CSNCBS_NOT_COMPLETE -12 + +#define CSNCBS_REVISION_LIMIT_STOP -20 /* Stop packing/unpacking - revision limit */ +#define CSNCBS_NOT_SUPPORTED_IE -21 /* Handling of the unpacked IE is not supported by MS-software */ + + + +#ifndef ElementsOf +#define ElementsOf(array) (sizeof(array) / sizeof(array[0])) +#endif +typedef void(*void_fn_t)(void); + +/* Context holding CSN1 parameters */ +typedef struct +{ + gint remaining_bits_len; /* IN to an csn stream operation */ + gint bit_offset; /* IN/OUT to an csn stream operation */ + gint direction; /* 0 - decode; 1 - encode */ +} csnStream_t; + +typedef gint16 (*StreamSerializeFcn_t)(csnStream_t* ar, struct bitvec *vector, unsigned *readIndex, void* data); +typedef CSN_CallBackStatus_t (*DissectorCallbackFcn_t)(struct bitvec *vector, unsigned *readIndex, void* param1, void* param2); + +typedef enum +{ + CSN_END = 0, + CSN_BIT, + CSN_UINT, + CSN_TYPE, + CSN_CHOICE, + CSN_UNION, + CSN_UNION_LH, + CSN_UINT_ARRAY, + CSN_TYPE_ARRAY, + CSN_BITMAP, /* Bitmap with constant: */ + CSN_VARIABLE_BITMAP, /* */ + CSN_VARIABLE_BITMAP_1, /* i.e. to the end of message (R99) */ + CSN_LEFT_ALIGNED_VAR_BMP, /* As variable bitmap but the result is left aligned (R99) */ + CSN_LEFT_ALIGNED_VAR_BMP_1,/* As above only size is to the end of message (R99) */ + CSN_PADDING_BITS, /* Padding bits fill to the end of the buffer */ + CSN_VARIABLE_ARRAY, /* Array with length specified in parameter: */ + CSN_VARIABLE_TARRAY, /* Type Array with length specified in parameter: *N */ + CSN_VARIABLE_TARRAY_OFFSET,/* As above but with offset. The offset is stored as third parameter of CSN_DESCR (descr.value) */ + CSN_RECURSIVE_ARRAY, /* Recursive way to specify an array of uint: ::= {1 |0}; */ + CSN_RECURSIVE_TARRAY, /* Recursive way to specify an array of type: ::= {1 } ** 0 ; */ + CSN_RECURSIVE_TARRAY_1, /* same as above but first element always exist: ::= {1 } ** 0 ; */ + CSN_RECURSIVE_TARRAY_2, /* same as above but with reversed separators : ::= { 0 } ** 1 ; */ + CSN_EXIST, + CSN_EXIST_LH, + CSN_NEXT_EXIST, + CSN_NEXT_EXIST_LH, + CSN_NULL, + CSN_FIXED, + CSN_CALLBACK, + CSN_UINT_OFFSET, /* unpack will add offset, inverse pack will subtract offset */ + CSN_UINT_LH, /* Low High extraction of int */ + CSN_SERIALIZE, + CSN_TRAP_ERROR +} csn_type_t; + +/****************************************************************************************** + * CSN_DESCR structure: + * + * type: + * This is the CSN type. All existing types are specified in the section above. + * + * i: + * Depending on the contents of the type parameter, the parameter "i" may have following meaning: + * - specifies the number of bits for the CSN_UINT or CSN_UINT_OR_NULL types + * - the offset for an array size by which the size is incremented + * for the CSN_VAR_ARRAY type + * - the length of each element of an array for the CSN_REC_ARRAY type + * - the number of the elements in an array for the CSN_TYPE_ARRAY type + * - the offset to the variable keeping the number of elements of an array for in the CSN_VAR_TARRAY type + * - the number of different data types in a union for the CSN_UNION, CSN_UNION_LH, and for the CSN_CHOICE types + * - the length in bits of the fixed number defined for the CSN_FIXED type + * - the number of lines to skip in the CSN_DESCR type specified for the CSN_NEXT_EXIST, CSN_NEXT_EXIST_LH, + * CSN_NEXT_EXIST_OR_NULL, and CSN_NEXT_EXIST_OR_NULL_LH types + * - the number of bits in a bitmap for the CSN_BITMAP type + * - the value by which the number of bits in a bitmap has to be incremented or decremented for the + * CSN_VAR_BITMAP, CSN_LEFT_VAR_BMP, and CSN_LEFT_BMP_1 types + * - the offset to param1 for the CSN_CALLBACK type + * - ERRORCODE used by the CSN_ERROR type + * - the bit-length of the LENGTH field in a CSN_SERIALISE type + * + * descr + * This parameter has different meaning depending on the value of the type parameter: + * - the offset for the CSN_UINT_OFFSET type + * - the number of the elements in an array of the CSN_UINT_ARRAY type + * - the offset to the parameter where the size of the array has to be stored for the CSN_REC_ARRAY type + * - the address of the internal structure, describing the member type (by means of the CSN_DESCR type) in the + * CSN_TYPE_ARRAY, CSN_VAR_TARRAY, and CSN_TYPE types + * - the address of the variable of type CSN_ChoiceElement_t describing all elements in the CSN_CHOICE type union + * - the offset to the variable where the number of bits has to be or is stored for the CSN_VAR_BITMAP, + * CSN_LEFT_VAR_BMP, and CSN_LEFT_BMP_1 types + * - the function number (case number) for the CSN_CALLBACK and CSN_CALLBACK_NO_ARGS types + * - the free text used by the CSN_TRAP_ERROR + * + * offset + * This is an offset to the _MEMBER parameter counting from the beginning of struct + * where the unpacked or packed value shall be stored or fetched. The meaning of the _MEMBER parameter + * varies depending on the type which is specified and so is the meaning of the offset parameter. + * Some types (and corresponding macros) do not have the _MEMBER parameter and then the offset parameter + * is not used or is different from the offset to the _MEMBER. + * - the fixed value for the CSN_FIXED type + * - an offset to the variable UnionType for CSN_UNION and CSN_UNION_LH types + * - an offset to the variable Exist for CSN_NEXT_EXIST and CSN_NEXT_EXIST_LH types + * - an offset to param2 in the CSN_CALLBACK type + * + * may_be_null + * TRUE: if dissection may be attempted at an offset beyond the length of existing data bits + * FALSE: othewise + * + * sz + * - is the name of the parameter within the descr where their unpacked or packed value shall be stored or fetched. + * This paramater is pointed out by the offset parameter in the same CSN_DESCR variable as the sz. + * - the free text used by the CSN_TRAP_ERROR (the same as parameter "i") + * + * serialize + * - stores the size of _MEMBER type in case of the M_TYPE_ARRAY and M_VAR_TARRAY, + * - the address of the function which is provided by the M_SERIALIZE type. + ******************************************************************************************/ + + +typedef struct +{ + gint16 type; + gint16 i; + union + { + const void* ptr; + guint32 value; + } descr; + unsigned offset; + gboolean may_be_null; + const char* sz; + guint32 value; + void_fn_t aux_fn; +} CSN_DESCR; + +typedef struct +{ + guint8 bits; + guint8 value; + gboolean keep_bits; + CSN_DESCR descr; +} CSN_ChoiceElement_t; + +void csnStreamInit(csnStream_t* ar,gint BitOffset,gint BitCount); + +/****************************************************************************** +* FUNCTION: csnStreamDecoder +* DESCRIPTION: +* UnPacks data from bit stream. According to CSN description. +* ARGS: +* ar stream will hold the parameters to the pack function +* ar->remaining_bits_len [IN] Number of bits to unpack [OUT] number of bits left to unpack. +* ar->bit_offset [IN/OUT] is the current bit where to proceed with the next bit to unpack. + +* pDescr CSN description. +* tvb buffer containing the bit stream to unpack. +* data unpacked data. +* ett_csn1 tree +* +* RETURNS: int Number of bits left to be unpacked. Negative Error code if failed to unpack all bits +******************************************************************************/ + +gint16 csnStreamDecoder(csnStream_t* ar, const CSN_DESCR* pDescr, struct bitvec *vector, unsigned *readIndex, void* data); + +gint16 csnStreamEncoder(csnStream_t* ar, const CSN_DESCR* pDescr, struct bitvec *vector, unsigned *writeIndex, void* data); + +/* CSN struct macro's */ +#define CSN_DESCR_BEGIN(_STRUCT)\ + CSN_DESCR CSNDESCR_##_STRUCT[] = { + +#define CSN_DESCR_END(_STRUCT)\ + {CSN_END, 0, {0}, 0, FALSE, "", 0, NULL} }; + +/****************************************************************************** + * CSN_ERROR(Par1, Par2, Par3) + * May be called at any time when an abort of packing or unpacking of a message + * is desired + * Par1: C structure name + * Par2: free text which will appear in the error handler + * Par3: Error code + *****************************************************************************/ +#define CSN_ERROR(_STRUCT, _Text, _ERRCODE)\ + {CSN_TRAP_ERROR, _ERRCODE, {_Text}, 0, FALSE, _Text, 0, NULL} + +/****************************************************************************** + * M_BIT(Par1, Par2) + * Defines one bit element in the CSN1 syntax. + * Par1: C structure name + * Par2: C structure element name + *****************************************************************************/ +#define M_BIT(_STRUCT, _MEMBER)\ + {CSN_BIT, 0, {0}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, 0, NULL} + +/****************************************************************************** + * M_BIT_OR_NULL(Par1, Par2) + * Similar to the M_BIT except that not only bit 0 or 1 but also the + * end of the message may be encountered when looking for the next element in + * the message. + * Covers the case {null | 0 | 1} + *****************************************************************************/ + #define M_BIT_OR_NULL(_STRUCT, _MEMBER)\ + {CSN_BIT, 0, {0}, offsetof(_STRUCT, _MEMBER), TRUE, #_MEMBER, 0, NULL} + +/****************************************************************************** + * M_NEXT_EXIST(Par1, Par2, Par3) + * Indicates whether the next element or a group of elements defined in the + * structure is present or not. + * Par1: C structure name + * Par2: C structure element name + * Par3: number of lines to skip in the CSN_DESCR type specified if the + * element(s) does not exist + *****************************************************************************/ +#define M_NEXT_EXIST(_STRUCT, _MEMBER, _NoOfExisting)\ + {CSN_NEXT_EXIST, _NoOfExisting, {0}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, 0, NULL} + +/****************************************************************************** + * M_NEXT_EXIST_LH(Par1, Par2, Par3) + * similar to the M_NEXT_EXIST except that instead of bit 0/1 which is fetched + * from the message in order to find out whether the next element/elements are + * present in the message, the logical operation XOR with the background + * pattern 0x2B is performed on the read bit before the decision is made. + *****************************************************************************/ +#define M_NEXT_EXIST_LH(_STRUCT, _MEMBER, _NoOfExisting)\ + {CSN_NEXT_EXIST_LH, _NoOfExisting, {0}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, 0, NULL} + +/****************************************************************************** + * M_NEXT_EXIST_OR_NULL(Par1, Par2, Par3) + * Similar to the M_NEXT_EXIST except that not only bit 0 or 1 but also the end + * of the message may be encountered when looking for the next element in the + * message. + * Covers the case {null | 0 | 1 < IE >} + *****************************************************************************/ +#define M_NEXT_EXIST_OR_NULL(_STRUCT, _MEMBER, _NoOfExisting)\ + {CSN_NEXT_EXIST, _NoOfExisting, {0}, offsetof(_STRUCT, _MEMBER), TRUE, #_MEMBER, 0, NULL} + +/****************************************************************************** + * M_NEXT_EXIST_OR_NULL_LH(Par1, Par2, Par3) + * Similar to the M_NEXT_EXIST_LH except that not only bit 0 or 1 but also the + * end of the message may be encountered when looking for the next element in + * the message. + * Covers the case {null | L | H < IE >} + *****************************************************************************/ +#define M_NEXT_EXIST_OR_NULL_LH(_STRUCT, _MEMBER, _NoOfExisting)\ + {CSN_NEXT_EXIST_LH, _NoOfExisting, {(void*)1}, offsetof(_STRUCT, _MEMBER), TRUE, #_MEMBER, 0, NULL} + +/****************************************************************************** + * M_UINT(Par1, Par2, Par3) + * Defines an integer number. + * Par1: C structure name + * Par2: C structure element name + * Par3: number of bits used to code the element (between 1 and 32) + *****************************************************************************/ +#define M_UINT(_STRUCT, _MEMBER, _BITS)\ + {CSN_UINT, _BITS, {0}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, 0, NULL} + + /****************************************************************************** + * M_UINT_OR_NULL(Par1, Par2, Par3) + * Similar to the M_UINT except that not only the request set of bits but also the + * end of the message may be encountered when looking for the next element in + * the message. + * Covers the case {null | 0 | 1 < IE >} + *****************************************************************************/ + #define M_UINT_OR_NULL(_STRUCT, _MEMBER, _BITS)\ + {CSN_UINT, _BITS, {0}, offsetof(_STRUCT, _MEMBER), TRUE, #_MEMBER, 0, NULL} + +/****************************************************************************** + * M_UINT(Par1, Par2, Par3) + * This macro has the same functionality as M_UINT except that in addition the + * logical "exclusive or" operation with the background value "0x2B" is + * performed before the final value of the integer number is delivered from the + * received CSN.1 message + *****************************************************************************/ +#define M_UINT_LH(_STRUCT, _MEMBER, _BITS)\ + {CSN_UINT_LH, _BITS, {0}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, 0, NULL} + +/****************************************************************************** + * M_UINT_OFFSET(Par1, Par2, Par3, Par4) + * Defines an integer number. + * Par1: C structure name + * Par2: C structure element name + * Par3: number of bits used to code the element (between 1 and 32) + * Par4: value added to the returned integer (offset) + *****************************************************************************/ +#define M_UINT_OFFSET(_STRUCT, _MEMBER, _BITS, _OFFSET)\ + {CSN_UINT_OFFSET, _BITS, {(void*)_OFFSET}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, 0, NULL} + +/****************************************************************************** + * M_UINT_ARRAY(Par1, Par2, Par3, Par4) + * Defines an array of integer numbers. The size of the array is fixed. + * Par1: C structure name + * Par2: C structure element name + * Par3: number of bits used to code the each integer element (between 1 and 32) + * Par4: number of elements in the array (fixed integer value) + *****************************************************************************/ +#define M_UINT_ARRAY(_STRUCT, _MEMBER, _BITS, _ElementCount)\ + {CSN_UINT_ARRAY, _BITS, {(void*)_ElementCount}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, 0, NULL} + +/****************************************************************************** + * M_VAR_UINT_ARRAY(Par1, Par2, Par3, Par4) + * Defines an array of integer numbers. The size of the array is variable. + * Par1: C structure name + * Par2: C structure element name + * Par3: number of bits used to code the each integer element (between 1 and 32) + * Par4: number of elements in the array supplied by reference to the + * structure member holding the length value + *****************************************************************************/ +#define M_VAR_UINT_ARRAY(_STRUCT, _MEMBER, _BITS, _ElementCountField)\ + {CSN_UINT_ARRAY, _BITS, {(void*)offsetof(_STRUCT, _ElementCountField)}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, 1, NULL} + +/****************************************************************************** + * M_VAR_ARRAY(Par1, Par2, Par3, Par4) + * Defines an array of 8 bit large integer numbers. The size of the array is variable. + * Par1: C structure name + * Par2: C structure element name + * Par3: name of the structure member holding the size of the array + * Par4: offset that is added to the Par3 to get the actual size of the array + *****************************************************************************/ +#define M_VAR_ARRAY(_STRUCT, _MEMBER, _ElementCountField, _OFFSET)\ + {CSN_VARIABLE_ARRAY, _OFFSET, {(void*)offsetof(_STRUCT, _ElementCountField)}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, 0, NULL} + +/****************************************************************************** + * M_VAR_TARRAY(Par1, Par2, Par3, Par4) + * Similar to M_TYPE_ARRAY except that the size of the array is variable. + * Par1: C structure name + * Par2: C structure element name + * Par3: the type of each element of the array + * Par4: name of the structure member holding the size of the array + *****************************************************************************/ +#define M_VAR_TARRAY(_STRUCT, _MEMBER, _MEMBER_TYPE, _ElementCountField)\ + {CSN_VARIABLE_TARRAY, offsetof(_STRUCT, _ElementCountField), {(const void*)CSNDESCR_##_MEMBER_TYPE}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, sizeof(_MEMBER_TYPE), NULL} + +/****************************************************************************** + * M_VAR_TARRAY_OFFSET(Par1, Par2, Par3, Par4) + * Same as M_VAR_TARRAY with offset + *****************************************************************************/ +#define M_VAR_TARRAY_OFFSET(_STRUCT, _MEMBER, _MEMBER_TYPE, _ElementCountField)\ + {CSN_VARIABLE_TARRAY_OFFSET, offsetof(_STRUCT, _ElementCountField), {(const void*)CSNDESCR_##_MEMBER_TYPE}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, sizeof(_MEMBER_TYPE), NULL} + +/****************************************************************************** + * M_REC_ARRAY(Par1, Par2, Par3, Par4) + * similar to the M_VAR_ARRAY. The difference is that the size of the array is + * not known in advance and it has to be calculated during unpacking. Its value + * is stored in a variable which belongs to the same structure as the array. + * A zero element terminates the array. The CSN.1 syntax describes it + * recursively as: + * ::={1 | 0} + * + * Par1: C structure name + * Par2: C structure element name + * Par3: name of the structure member where the calculated the size of the + * array will be stored + * Par4: length of each element in bits + *****************************************************************************/ +#define M_REC_ARRAY(_STRUCT, _MEMBER, _ElementCountField, _BITS)\ + {CSN_RECURSIVE_ARRAY, _BITS, {(const void*)offsetof(_STRUCT, _ElementCountField)}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, 0, NULL} + +/****************************************************************************** + * M_VAR_TYPE_ARRAY(Par1, Par2, Par3, Par4) + * Defines an array of structures. The size of the array is variable. + * Par1: C structure name + * Par2: C structure element name + * Par3: name of the structure + * Par4: number of elements in the array (fixed integer value) + *****************************************************************************/ +#define M_TYPE_ARRAY(_STRUCT, _MEMBER, _MEMBER_TYPE, _ElementCount)\ + {CSN_TYPE_ARRAY, _ElementCount, {(const void*)CSNDESCR_##_MEMBER_TYPE}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, sizeof(_MEMBER_TYPE), NULL} + +/****************************************************************************** + * M_REC_TARRAY(Par1, Par2, Par3, Par4) + * Defines an recursive array of structures. The size of the array is variable. + * ::= {1 } ** 0 ; + * Par1: C structure name + * Par2: C structure element name + * Par3: name of the structure + * Par4: will hold the number of element in the array after unpacking + *****************************************************************************/ +#define M_REC_TARRAY(_STRUCT, _MEMBER, _MEMBER_TYPE, _ElementCountField)\ + {CSN_RECURSIVE_TARRAY, offsetof(_STRUCT, _ElementCountField), {(const void*)CSNDESCR_##_MEMBER_TYPE}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, sizeof(_MEMBER_TYPE), (void_fn_t)ElementsOf(((_STRUCT*)0)->_MEMBER)} + +/****************************************************************************** + * M_REC_TARRAY1(Par1, Par2, Par3, Par4) + * Same as M_REC_TARRAY but first element always exist: + * ::= {1 } ** 0 ; + *****************************************************************************/ +#define M_REC_TARRAY_1(_STRUCT, _MEMBER, _MEMBER_TYPE, _ElementCountField)\ + {CSN_RECURSIVE_TARRAY_1, offsetof(_STRUCT, _ElementCountField), {(const void*)CSNDESCR_##_MEMBER_TYPE}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, sizeof(_MEMBER_TYPE), (void_fn_t)ElementsOf(((_STRUCT*)0)->_MEMBER)} + +/****************************************************************************** + * M_REC_TARRAY2(Par1, Par2, Par3, Par4) + * Same as M_REC_TARRAY but with reversed separators : + * ::= { 0 } ** 1 ; + *****************************************************************************/ +#define M_REC_TARRAY_2(_STRUCT, _MEMBER, _MEMBER_TYPE, _ElementCountField)\ + {CSN_RECURSIVE_TARRAY_2, offsetof(_STRUCT, _ElementCountField), {(const void*)CSNDESCR_##_MEMBER_TYPE}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, sizeof(_MEMBER_TYPE), (void_fn_t)ElementsOf(((_STRUCT*)0)->_MEMBER)} + +/****************************************************************************** + * M_TYPE(Par1, Par2, Par3) + * Defines a reference to a structure which is described elsewhere + * ::= {1 } ** 0 ; + * Par1: C structure name + * Par2: C structure element name + * Par3: type of member + *****************************************************************************/ +#define M_TYPE(_STRUCT, _MEMBER, _MEMBER_TYPE)\ + {CSN_TYPE, 0, {(const void*)CSNDESCR_##_MEMBER_TYPE}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, 0, NULL} + +/****************************************************************************** + * M_TYPE_OR_NULL(Par1, Par2, Par3) + * Similar to the M_TYPE except that not only the request set of bits but also the + * end of the message may be encountered when looking for the next element in + * the message. + * Covers the case {null | 0 | 1 < IE >} + *****************************************************************************/ +#define M_TYPE_OR_NULL(_STRUCT, _MEMBER, _MEMBER_TYPE)\ + {CSN_TYPE, 0, {(const void*)CSNDESCR_##_MEMBER_TYPE}, offsetof(_STRUCT, _MEMBER), TRUE, #_MEMBER, 0, NULL} + +/****************************************************************************** + * M_UNION(Par1, Par2) + * Informs the CSN.1 library that a union follows and how many possible choices + * there are in the union. The actual value of the choice, which points out the + * chosen element of the union is stored in the uint8 variable and is usually + * called UnionType. The elements of the union have to be listed directly after + * the M_UNION statement. + * Par1: C structure name + * Par2: number of possible choice in the union + *****************************************************************************/ +#define M_UNION(_STRUCT, _COUNT)\ + {CSN_UNION, _COUNT, {0}, offsetof(_STRUCT, UnionType), FALSE, "UnionType", 0, NULL} + +/****************************************************************************** + * M_UNION_LH(Par1, Par2) + * Same as M_UNION but masked with background value 0x2B + *****************************************************************************/ +#define M_UNION_LH(_STRUCT, _COUNT)\ + {CSN_UNION_LH, _COUNT, {0}, offsetof(_STRUCT, UnionType), FALSE, "UnionType", 0, NULL} + +/****************************************************************************** + * M_CHOICE(Par1, Par2, Par3, Par4) + * Similar to the M_UNION. In the M_UNION the selected element of all possible + * choices in the union is referred as a sequential numbers, i.e., the first + * choice is addressed as choice 0 the second as choice 1, the third as choice + * 2 and so on, both in the encoded message and in the variable UnionType which + * is the part of the message. In the CSN_CHOICE case, this rule does not + * apply. There is free but predefined mapping of the element of the union and + * the value which addresses this element. + * The value of the address is called a selector. Up to 256 (UCHAR_MAX) unique + * selectors can be handled, longer choice list would cause CSN_ERROR_IN_SCRIPT. + * After unpacking, this value is then converted to the sequential number of the + * element in the union and stored in the UnionType variable (Par2). + * Par1: C structure name + * Par2: C structure field name holding sequential number of the chosen element. + * BEWARE! Never use an enumerated type here, because its length is + * compiler/machine dependent, while decoder would cast it to guint8. + * Par3: address of an array of type CSN_ChoiceElement_t where all possible + * values of the selector are provided, together with the selector + * length expressed in bits and the address of the CSN_DESCR type + * where the element is defined. For every element in the union + * there is one line in the Choice variable. These lines have to + * appear in the _CHOICE in the same order as the elements in the + * union. The element of the union selected in the message through + * the _CHOICE parameter is after unpacking translated to the + * corresponding sequential number of this element and stored in + * the variable pointed out by the _MEMBER + * Par4: number of possible choices in the union + *****************************************************************************/ +#define M_CHOICE(_STRUCT, _MEMBER, _CHOICE, _ElementCount)\ + {CSN_CHOICE, _ElementCount, {(const void*)_CHOICE}, offsetof(_STRUCT, _MEMBER), FALSE, #_CHOICE, 0, NULL} + +/****************************************************************************** + * M_FIXED(Par1, Par2, Par3) + * Defines a fixed value of type integer which should be fetched from or stored + * in the message + * Par1: C structure name + * Par2: gives the length of the fixed number in bits. + * Par3: the value of the number. If the expected value is not present in +* the message the unpacking procedure is aborted + *****************************************************************************/ +#define M_FIXED(_STRUCT, _BITS, _BITVALUE)\ + {CSN_FIXED, _BITS, {0}, _BITVALUE, FALSE, #_BITVALUE, 0, NULL} + +/****************************************************************************** + * M_SERIALIZE(Par1, Par2, Par3) + * Allows using a complete free format of data being encoded or decoded. + * When the M_SERIALIZE is encounted during encoding or decoding of a message + * the CSNstream program passes the control over to the specified function + * together with all necessary parameters about the current position within + * the message being unpacked or packed. When transferring of "serialized" + * data to or from the message is finished by the function the CSNstream gets + * back control over the data stream and continues to work with the message. + *****************************************************************************/ +#define M_SERIALIZE(_STRUCT, _MEMBER, _LENGTH_LEN, _SERIALIZEFCN)\ + {CSN_SERIALIZE, _LENGTH_LEN, {0}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, 0, (void_fn_t)_SERIALIZEFCN} + +#define M_CALLBACK(_STRUCT, _CSNCALLBACKFCN, _PARAM1, _PARAM2)\ + {CSN_CALLBACK, offsetof(_STRUCT, _PARAM1), {0}, offsetof(_STRUCT, _PARAM2), FALSE, "CallBack_"#_CSNCALLBACKFCN, 0, (void_fn_t)_CSNCALLBACKFCN} + +/****************************************************************************** + * M_BITMAP(Par1, Par2, Par3) + * Defines a type which consists of a bitmap. The size of the bitmap in bits + * is fixed and provided by the parameter Par3 + * Par1: C structure name + * Par2: C structure element name + * Par3: length of the bitmap expressed in bits + *****************************************************************************/ +#define M_BITMAP(_STRUCT, _MEMBER, _BITS)\ + {CSN_BITMAP, _BITS, {0}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, 0, NULL} + +/* variable length, right aligned bitmap i.e. _ElementCountField = 11 => 00000111 11111111 */ +#define M_VAR_BITMAP(_STRUCT, _MEMBER, _ElementCountField, _OFFSET)\ + {CSN_VARIABLE_BITMAP, _OFFSET, {(void*)offsetof(_STRUCT, _ElementCountField)}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, 0, NULL} + +/* variable length, right aligned bitmap filling the rest of message + * - when unpacking the _ElementCountField will be set in runtime + * - when packing _ElementCountField contains the size of bitmap + */ +#define M_VAR_BITMAP_1(_STRUCT, _MEMBER, _ElementCountField, _OFFSET)\ + {CSN_VARIABLE_BITMAP_1, _OFFSET, {(void*)offsetof(_STRUCT, _ElementCountField)}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, 0, NULL} + +/* variable length, left aligned bitmap i.e. _ElementCountField = 11 => 11111111 11100000 */ +#define M_LEFT_VAR_BMP(_STRUCT, _MEMBER, _ElementCountField, _OFFSET)\ + {CSN_LEFT_ALIGNED_VAR_BMP, _OFFSET, {(void*)offsetof(_STRUCT, _ElementCountField)}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, 0, NULL} + +/* variable length, left aligned bitmap filling the rest of message + *- when unpacking the _ElementCountField will be set in runtime + * - when packing _ElementCountField contains the size of bitmap + */ +#define M_LEFT_VAR_BMP_1(_STRUCT, _MEMBER, _ElementCountField, _OFFSET)\ + {CSN_LEFT_ALIGNED_VAR_BMP_1, _OFFSET, {(void*)offsetof(_STRUCT, _ElementCountField)}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, 0, NULL} + +/* todo: dissect padding bits looking for unexpected extensions */ +#define M_PADDING_BITS(_STRUCT)\ + {CSN_PADDING_BITS, 0, {0}, 0, TRUE, "Padding", 0, NULL} + +#define M_NULL(_STRUCT, _MEMBER, _SKIP_BITS)\ + {CSN_NULL, _SKIP_BITS, {0}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, 0, NULL} + +#define M_THIS_EXIST(_STRUCT)\ + {CSN_EXIST, 0, {0}, offsetof(_STRUCT, Exist), FALSE, "Exist", 0, NULL} + +#define M_THIS_EXIST_LH(_STRUCT)\ + {CSN_EXIST_LH, 0, {0}, offsetof(_STRUCT, Exist), FALSE, "Exist", 0, NULL} + +/* return value 0 if ok else discontionue the unpacking */ +typedef gint16 (*CsnCallBackFcn_t)(void* pv ,...); + +#define CSNDESCR(_FuncType) CSNDESCR_##_FuncType + +#define pvDATA(_pv, _offset) ((void*) ((unsigned char*)_pv + _offset)) +#define pui8DATA(_pv, _offset) ((guint8*) pvDATA(_pv, _offset)) +#define pui16DATA(_pv, _offset) ((guint16*) pvDATA(_pv, _offset)) +#define pui32DATA(_pv, _offset) ((guint32*) pvDATA(_pv, _offset)) +#define pui64DATA(_pv, _offset) ((guint64*) pvDATA(_pv, _offset)) +/* used to tag existence of next element in variable length lists */ +#define STANDARD_TAG 1 +#define REVERSED_TAG 0 + +gint16 ProcessError_impl(const char *file, int line, unsigned *readIndex, + const char* sz, gint16 err, const CSN_DESCR* pDescr); +#define ProcessError(readIndex, sz, err, pDescr) \ + ProcessError_impl(__FILE__, __LINE__, readIndex, sz, err, pDescr) + +#endif /*_PACKET_CSN1_H_*/ diff --git a/include/osmocom/csn1/wireshark_compat.h b/include/osmocom/csn1/wireshark_compat.h new file mode 100644 index 0000000..2840124 --- /dev/null +++ b/include/osmocom/csn1/wireshark_compat.h @@ -0,0 +1,34 @@ +/* wireshark_compat.h + * Copyright (C) 2020 by sysmocom - s.f.m.c. GmbH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/* This header contains a few definitions required by rlcmac and csn1 files + * originally imported from wireshark packet-gsm_rlcmac.* and package-csn1.*, + * in order to keep code as similar as possible to ease maintainability and port + * of patches. +*/ +#pragma once + +#define MIN(a,b) (((a)<(b))?(a):(b)) + +#define FALSE (0) +#define TRUE (1) +typedef signed int gint32; +typedef signed short gint16; +typedef int gint; +typedef unsigned int guint; +typedef gint gboolean; +typedef unsigned char guint8; +typedef unsigned short guint16; +typedef unsigned int guint32; +typedef unsigned long guint64; diff --git a/libosmo-csn1.pc.in b/libosmo-csn1.pc.in new file mode 100644 index 0000000..c2e1ff8 --- /dev/null +++ b/libosmo-csn1.pc.in @@ -0,0 +1,10 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: Osmocom CSN.1 Codec Library +Description: C Utility Library +Version: @VERSION@ +Libs: -L${libdir} -losmo-csn1 +Cflags: -I${includedir}/ diff --git a/m4/.gitkeep b/m4/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..120b825 --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,3 @@ +SUBDIRS = \ + csn1 \ + $(NULL) diff --git a/src/csn1/Makefile.am b/src/csn1/Makefile.am new file mode 100644 index 0000000..88cddea --- /dev/null +++ b/src/csn1/Makefile.am @@ -0,0 +1,34 @@ +# This is _NOT_ the library release version, it's an API version. +# Please read Chapter 6 "Library interface versions" of the libtool +# documentation before making any modification +LIBVERSION=0:0:0 + +AM_CPPFLAGS = \ + $(all_includes) \ + -I$(top_srcdir)/include \ + $(NULL) + +AM_CFLAGS = \ + -Wall \ + $(LIBOSMOCORE_CFLAGS) \ + $(NULL) + +lib_LTLIBRARIES = \ + libosmo-csn1.la \ + $(NULL) + +libosmo_csn1_la_SOURCES = \ + csn1.c \ + csn1_enc.c \ + csn1_dec.c \ + $(NULL) + +# TODO: -export-symbols-regex '^osmo_' +libosmo_csn1_la_LDFLAGS = \ + -version-info $(LIBVERSION) \ + -no-undefined \ + $(NULL) + +libosmo_csn1_la_LIBADD = \ + $(LIBOSMOCORE_LIBS) \ + $(NULL) diff --git a/src/csn1/csn1.c b/src/csn1/csn1.c new file mode 100644 index 0000000..307cd11 --- /dev/null +++ b/src/csn1/csn1.c @@ -0,0 +1,103 @@ +/* csn1_enc.c + * Routines for CSN1 dissection in wireshark. + * + * Copyright (C) 2011 Ivan Klyuchnikov + * + * By Vincent Helfre, based on original code by Jari Sassi + * with the gracious authorization of STE + * Copyright (c) 2011 ST-Ericsson + * + * $Id: packet-csn1.c 39140 2011-09-25 22:01:50Z wmeier $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#define __STDC_FORMAT_MACROS +#include + +#include +#include + +#include + +const unsigned char ixBitsTab[] = {0, 1, 1, 2, 2, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5}; + +/* Returns no_of_bits (up to 8) masked with 0x2B */ +guint8 +get_masked_bits8(struct bitvec *vector, unsigned *readIndex, gint bit_offset, const gint no_of_bits) +{ + static const guint8 maskBits[] = {0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF}; + //gint byte_offset = bit_offset >> 3; /* divide by 8 */ + gint relative_bit_offset = bit_offset & 0x07; /* modulo 8 */ + guint8 result; + gint bit_shift = 8 - relative_bit_offset - (gint) no_of_bits; + *readIndex -= relative_bit_offset; + if (bit_shift >= 0) + { + result = (0x2B ^ ((guint8)bitvec_read_field(vector, readIndex, 8))) >> bit_shift; + *readIndex-= bit_shift; + result &= maskBits[no_of_bits]; + } + else + { + guint8 hight_part = (0x2B ^ ((guint8)bitvec_read_field(vector, readIndex, 8))) & maskBits[8 - relative_bit_offset]; + hight_part = (guint8) (hight_part << (-bit_shift)); + result = (0x2B ^ ((guint8)bitvec_read_field(vector, readIndex, 8))) >> (8 + bit_shift); + *readIndex = *readIndex - (8 - (-bit_shift)); + result |= hight_part; + } + return result; +} + +/** + * ================================================================================================ + * set initial/start values in help data structure used for packing/unpacking operation + * ================================================================================================ + */ +void +csnStreamInit(csnStream_t* ar, gint bit_offset, gint remaining_bits_len) +{ + ar->remaining_bits_len = remaining_bits_len; + ar->bit_offset = bit_offset; + ar->direction = 0; +} + +static const struct value_string csn1_error_names[] = { + { CSN_OK, "General 0" }, + { CSN_ERROR_GENERAL, "General -1" }, + { CSN_ERROR_DATA_NOT_VALID, "DATA_NOT VALID" }, + { CSN_ERROR_IN_SCRIPT, "IN SCRIPT" }, + { CSN_ERROR_INVALID_UNION_INDEX, "INVALID UNION INDEX" }, + { CSN_ERROR_NEED_MORE_BITS_TO_UNPACK, "NEED_MORE BITS TO UNPACK" }, + { CSN_ERROR_ILLEGAL_BIT_VALUE, "ILLEGAL BIT VALUE" }, + { CSN_ERROR_INTERNAL, "INTERNAL" }, + { CSN_ERROR_STREAM_NOT_SUPPORTED, "STREAM_NOT_SUPPORTED" }, + { CSN_ERROR_MESSAGE_TOO_LONG, "MESSAGE_TOO_LONG" }, + { 0, NULL } +}; + + +gint16 ProcessError_impl(const char *file, int line, unsigned *readIndex, + const char* sz, gint16 err, const CSN_DESCR* pDescr) +{ + /* Don't add trailing newline, top caller is responsible for appending it */ + if (err != CSN_OK) + LOGPSRC(DLCSN1, LOGL_ERROR, file, line, "%s: error %s (%d) at %s (idx %u)", + sz, get_value_string(csn1_error_names, err), err, + pDescr ? pDescr->sz : "-", *readIndex); + return err; +} diff --git a/src/csn1/csn1_dec.c b/src/csn1/csn1_dec.c new file mode 100644 index 0000000..abf9060 --- /dev/null +++ b/src/csn1/csn1_dec.c @@ -0,0 +1,1424 @@ +/* csn1_dec.c + * Routines for CSN1 dissection in wireshark. + * + * Copyright (C) 2011 Ivan Klyuchnikov + * + * By Vincent Helfre, based on original code by Jari Sassi + * with the gracious authorization of STE + * Copyright (c) 2011 ST-Ericsson + * + * $Id: packet-csn1.c 39140 2011-09-25 22:01:50Z wmeier $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#define __STDC_FORMAT_MACROS +#include + +#include +#include + +#include + +extern const unsigned char ixBitsTab[]; +guint8 get_masked_bits8(struct bitvec *vector, unsigned *readIndex, gint bit_offset, const gint no_of_bits); + +/** + * ================================================================================================ + * Return TRUE if tag in bit stream indicates existence of next list element, + * otherwise return FALSE. + * Will work for tag values equal to both 0 and 1. + * ================================================================================================ + */ + +static gboolean +existNextElement(struct bitvec *vector, unsigned *readIndex, guint8 Tag) +{ + int res = bitvec_get_bit_pos(vector, (*readIndex)++); + if (Tag == STANDARD_TAG) + { + return (res > 0); + } + return (res == 0); +} + + +gint16 +csnStreamDecoder(csnStream_t* ar, const CSN_DESCR* pDescr, struct bitvec *vector, unsigned *readIndex, void* data) +{ + gint remaining_bits_len = ar->remaining_bits_len; + gint bit_offset = ar->bit_offset; + guint8* pui8 = NULL; + guint16* pui16; + guint32* pui32; + guint64* pui64; + guint8 Tag = STANDARD_TAG; + unsigned ib; + + if (remaining_bits_len < 0) + { + return ProcessError(readIndex, __func__, CSN_ERROR_NEED_MORE_BITS_TO_UNPACK, pDescr); + } + + do + { + switch (pDescr->type) + { + case CSN_BIT: + { + if (remaining_bits_len > 0) + { + pui8 = pui8DATA(data, pDescr->offset); + *pui8 = bitvec_read_field(vector, readIndex, 1); + LOGPC(DLCSN1, LOGL_DEBUG, "%s = %u | ", pDescr->sz , (unsigned)*pui8); + /* end add the bit value to protocol tree */ + } + else if (pDescr->may_be_null) + { + pui8 = pui8DATA(data, pDescr->offset); + *pui8 = 0; + LOGPC(DLCSN1, LOGL_DEBUG, "%s = NULL | ", pDescr->sz); + } + else + { + return ProcessError(readIndex,"csnStreamDecoder", CSN_ERROR_NEED_MORE_BITS_TO_UNPACK, pDescr); + } + + pDescr++; + remaining_bits_len--; + bit_offset++; + break; + } + + case CSN_NULL: + { /* Empty member! */ + bit_offset += pDescr->i; + pDescr++; + break; + } + + case CSN_UINT: + { + guint8 no_of_bits = (guint8) pDescr->i; + + if (remaining_bits_len >= no_of_bits) + { + if (no_of_bits <= 8) + { + guint8 ui8 = bitvec_read_field(vector, readIndex, no_of_bits); + pui8 = pui8DATA(data, pDescr->offset); + *pui8 = ui8; + LOGPC(DLCSN1, LOGL_DEBUG, "%s = %u | ", pDescr->sz , (unsigned)*pui8); + } + else if (no_of_bits <= 16) + { + guint16 ui16 = bitvec_read_field(vector, readIndex, no_of_bits); + pui16 = pui16DATA(data, pDescr->offset); + *pui16 = ui16; + LOGPC(DLCSN1, LOGL_DEBUG, "%s = %u | ", pDescr->sz , *pui16); + } + else if (no_of_bits <= 32) + { + guint32 ui32 = bitvec_read_field(vector, readIndex, no_of_bits); + pui32 = pui32DATA(data, pDescr->offset); + *pui32 = ui32; + LOGPC(DLCSN1, LOGL_DEBUG, "%s = 0x%08x | ", pDescr->sz , *pui32); + } + else + { + return ProcessError(readIndex,"csnStreamDecoder", CSN_ERROR_GENERAL, pDescr); + } + remaining_bits_len -= no_of_bits; + bit_offset += no_of_bits; + } + else if (pDescr->may_be_null) + { + if (no_of_bits <= 8) + { + pui8 = pui8DATA(data, pDescr->offset); + *pui8 = 0; + } + else if (no_of_bits <= 16) + { + pui16 = pui16DATA(data, pDescr->offset); + *pui16 = 0; + } + else if (no_of_bits <= 32) + { + pui32 = pui32DATA(data, pDescr->offset); + *pui32 = 0; + } + LOGPC(DLCSN1, LOGL_DEBUG, "%s = NULL | ", pDescr->sz); + } + else + { + return ProcessError(readIndex,"csnStreamDecoder", CSN_ERROR_NEED_MORE_BITS_TO_UNPACK, pDescr); + } + + pDescr++; + break; + } + + case CSN_UINT_OFFSET: + { + guint8 no_of_bits = (guint8) pDescr->i; + + if (remaining_bits_len >= no_of_bits) + { + if (no_of_bits <= 8) + { + guint8 ui8 = bitvec_read_field(vector, readIndex, no_of_bits); + pui8 = pui8DATA(data, pDescr->offset); + *pui8 = ui8 + (guint8)pDescr->descr.value; + LOGPC(DLCSN1, LOGL_DEBUG, "%s = %u | ", pDescr->sz , (unsigned)*pui8); + } + else if (no_of_bits <= 16) + { + guint16 ui16 = bitvec_read_field(vector, readIndex, no_of_bits); + pui16 = pui16DATA(data, pDescr->offset); + *pui16 = ui16 + (guint16)pDescr->descr.value; + LOGPC(DLCSN1, LOGL_DEBUG, "%s = %u | ", pDescr->sz , *pui16); + } + else if (no_of_bits <= 32) + { + guint32 ui32 = bitvec_read_field(vector, readIndex, no_of_bits); + pui32 = pui32DATA(data, pDescr->offset); + *pui32 = ui32 + (guint16)pDescr->descr.value; + LOGPC(DLCSN1, LOGL_DEBUG, "%s = %u | ", pDescr->sz , *pui32); + } + else + { + return ProcessError(readIndex,"csnStreamDecoder", CSN_ERROR_GENERAL, pDescr); + } + } + else + { + return ProcessError(readIndex,"csnStreamDecoder", CSN_ERROR_NEED_MORE_BITS_TO_UNPACK, pDescr); + } + + remaining_bits_len -= no_of_bits; + bit_offset += no_of_bits; + pDescr++; + break; + } + + case CSN_UINT_LH: + { + guint8 no_of_bits = (guint8) pDescr->i; + + if (remaining_bits_len >= no_of_bits) + { + if (no_of_bits <= 8) + { + guint8 ui8 = get_masked_bits8(vector, readIndex, bit_offset, no_of_bits); + pui8 = pui8DATA(data, pDescr->offset); + *pui8 = ui8; + LOGPC(DLCSN1, LOGL_DEBUG, "%s = %u | ", pDescr->sz , (unsigned)*pui8); + } + else + {/* Maybe we should support more than 8 bits ? */ + return ProcessError(readIndex,"csnStreamDecoder", CSN_ERROR_GENERAL, pDescr); + } + } + else + { + return ProcessError(readIndex,"csnStreamDecoder", CSN_ERROR_NEED_MORE_BITS_TO_UNPACK, pDescr); + } + + remaining_bits_len -= no_of_bits; + bit_offset += no_of_bits; + pDescr++; + break; + } + + case CSN_UINT_ARRAY: + { + guint8 no_of_bits = (guint8) pDescr->i; + guint16 nCount = (guint16)pDescr->descr.value; /* nCount supplied by value i.e. M_UINT_ARRAY(...) */ + + if (pDescr->value != 0) + { /* nCount specified by a reference to field holding value i.e. M_VAR_UINT_ARRAY(...) */ + nCount = *pui16DATA(data, nCount); + } + + if (remaining_bits_len >= (no_of_bits * nCount)) + { + remaining_bits_len -= (no_of_bits*nCount); + if (no_of_bits <= 8) + { + pui8 = pui8DATA(data, pDescr->offset); + do + { + *pui8 = bitvec_read_field(vector, readIndex, no_of_bits); + LOGPC(DLCSN1, LOGL_DEBUG, "%s = %u | ", pDescr->sz , (unsigned)*pui8); + pui8++; + bit_offset += no_of_bits; + } while (--nCount > 0); + } + else if (no_of_bits <= 16) + { + return ProcessError(readIndex,"csnStreamDecoder NOTIMPLEMENTED", 999, pDescr); + } + else if (no_of_bits <= 32) + { + return ProcessError(readIndex,"csnStreamDecoder NOTIMPLEMENTED", 999, pDescr); + } + else + { + return ProcessError(readIndex,"csnStreamDecoder", CSN_ERROR_GENERAL, pDescr); + } + } + else + { + return ProcessError(readIndex,"csnStreamDecoder", CSN_ERROR_NEED_MORE_BITS_TO_UNPACK, pDescr); + } + pDescr++; + break; + } + + case CSN_VARIABLE_TARRAY_OFFSET: + case CSN_VARIABLE_TARRAY: + case CSN_TYPE_ARRAY: + { + gint16 Status; + csnStream_t arT = *ar; + gint16 nCount = pDescr->i; + guint16 nSize = (guint16)(gint32)pDescr->value; + + pui8 = pui8DATA(data, pDescr->offset); + if (pDescr->type == CSN_VARIABLE_TARRAY) + { /* Count specified in field */ + nCount = *pui8DATA(data, pDescr->i); + } + else if (pDescr->type == CSN_VARIABLE_TARRAY_OFFSET) + { /* Count specified in field */ + nCount = *pui8DATA(data, pDescr->i); + /* nCount--; the 1 offset is already taken into account in CSN_UINT_OFFSET */ + } + + while (nCount > 0) + { /* resulting array of length 0 is possible + * but no bits shall be read from bitstream + */ + + LOGPC(DLCSN1, LOGL_DEBUG, "%s | ", pDescr->sz); + csnStreamInit(&arT, bit_offset, remaining_bits_len); + Status = csnStreamDecoder(&arT, (const CSN_DESCR*)pDescr->descr.ptr, vector, readIndex, pui8); + if (Status >= 0) + { + pui8 += nSize; + remaining_bits_len = arT.remaining_bits_len; + bit_offset = arT.bit_offset; + } + else + { + return Status; + } + nCount--; + } + + pDescr++; + break; + } + + case CSN_BITMAP: + { /* bitmap with given length. The result is left aligned! */ + guint8 no_of_bits = (guint8) pDescr->i; /* length of bitmap */ + + if (no_of_bits > 0) + { + if (no_of_bits > remaining_bits_len) + { + return ProcessError(readIndex, "csnStreamDecoder", CSN_ERROR_NEED_MORE_BITS_TO_UNPACK, pDescr); + } + + if (no_of_bits <= 32) + { + for(ib = 0; ib < 4; ib++) + { + guint8 ui8 = bitvec_read_field(vector, readIndex, 8); + pui8 = pui8DATA(data, pDescr->offset+ib); + *pui8 = ui8; + LOGPC(DLCSN1, LOGL_DEBUG, "%s[%u] = %u | ", pDescr->sz , ib, (unsigned)*pui8); + } + } + else if (no_of_bits <= 64) + { + for(ib = 0; ib < 8; ib++) + { + guint8 ui8 = bitvec_read_field(vector, readIndex, 8); + pui8 = pui8DATA(data, pDescr->offset+ib); + *pui8 = ui8; + LOGPC(DLCSN1, LOGL_DEBUG, "%s[%u] = %u | ", pDescr->sz , ib, (unsigned)*pui8); + } + } + else + { + return ProcessError(readIndex,"csnStreamDecoder NOT IMPLEMENTED", 999, pDescr); + } + + remaining_bits_len -= no_of_bits; + bit_offset += no_of_bits; + } + /* bitmap was successfully extracted or it was empty */ + + pDescr++; + break; + } + + case CSN_TYPE: + { + gint16 Status; + csnStream_t arT = *ar; + if (pDescr->may_be_null && remaining_bits_len == 0) + { + LOGPC(DLCSN1, LOGL_DEBUG, " : %s = NULL | ", pDescr->sz); + } else { + LOGPC(DLCSN1, LOGL_DEBUG, " : %s | ", pDescr->sz); + csnStreamInit(&arT, bit_offset, remaining_bits_len); + Status = csnStreamDecoder(&arT, (const CSN_DESCR*)pDescr->descr.ptr, vector, readIndex, pvDATA(data, pDescr->offset)); + LOGPC(DLCSN1, LOGL_DEBUG, ": End %s | ", pDescr->sz); + if (Status >= 0) + { + remaining_bits_len = arT.remaining_bits_len; + bit_offset = arT.bit_offset; + } + else + { + /* Has already been processed: ProcessError("csnStreamDecoder", Status, pDescr); */ + return Status; + } + } + pDescr++; + break; + } + + case CSN_CHOICE: + { + gint16 count = pDescr->i; + guint8 i = 0; + CSN_ChoiceElement_t* pChoice = (CSN_ChoiceElement_t*) pDescr->descr.ptr; + + /* Make sure that the list of choice items is not empty */ + if (!count) + return ProcessError(readIndex, "csnStreamDecoder", CSN_ERROR_IN_SCRIPT, pDescr); + else if (count > 255) /* We can handle up to 256 (UCHAR_MAX) selectors */ + return ProcessError(readIndex, "csnStreamDecoder", CSN_ERROR_IN_SCRIPT, pDescr); + + while (count > 0) + { + guint8 no_of_bits = pChoice->bits; + guint8 value = bitvec_read_field(vector, readIndex, no_of_bits); + if (value == pChoice->value) + { + CSN_DESCR descr[2]; + gint16 Status; + csnStream_t arT = *ar; + + descr[0] = pChoice->descr; + memset(&descr[1], 0x00, sizeof(CSN_DESCR)); + descr[1].type = CSN_END; + pui8 = pui8DATA(data, pDescr->offset); + *pui8 = i; + LOGPC(DLCSN1, LOGL_DEBUG, "Choice %s = %u | ", pDescr->sz , (unsigned)value); + if (!pChoice->keep_bits) { + bit_offset += no_of_bits; + remaining_bits_len -= no_of_bits; + } + + csnStreamInit(&arT, bit_offset, remaining_bits_len); + Status = csnStreamDecoder(&arT, descr, vector, readIndex, data); + + if (Status >= 0) + { + remaining_bits_len = arT.remaining_bits_len; + bit_offset = arT.bit_offset; + } + else + { + return Status; + } + break; + } + + *readIndex -= no_of_bits; + count--; + pChoice++; + i++; + } + + /* Neither of the choice items matched => unknown value */ + if (!count) + return ProcessError(readIndex, "csnStreamDecoder", CSN_ERROR_STREAM_NOT_SUPPORTED, pDescr); + + pDescr++; + break; + } + + case CSN_SERIALIZE: + { + StreamSerializeFcn_t serialize = (StreamSerializeFcn_t)pDescr->aux_fn; + csnStream_t arT = *ar; + guint8 length_len = pDescr->i; + gint16 Status = -1; + + guint8 length = bitvec_read_field(vector, readIndex, length_len); + + LOGPC(DLCSN1, LOGL_DEBUG, "%s length = %u | ", pDescr->sz , length); + bit_offset += length_len; + remaining_bits_len -= length_len; + + csnStreamInit(&arT, bit_offset, length > 0 ? length : remaining_bits_len); + arT.direction = 1; + LOGPC(DLCSN1, LOGL_DEBUG, "offset = %u | ", pDescr->offset); + Status = serialize(&arT, vector, readIndex, pvDATA(data, pDescr->offset)); + + if (Status >= 0) + { + if (length > 0) { + remaining_bits_len -= length; + bit_offset += length; + } else { + remaining_bits_len = arT.remaining_bits_len; + bit_offset = arT.bit_offset; + } + + /* Skip bits not handled by serialize(), if any */ + if (Status > 0) { + LOGPC(DLCSN1, LOGL_DEBUG, "skipped = %d | ", Status); + *readIndex += Status; + } + + pDescr++; + } + else + { + /* Has already been processed: */ + return Status; + } + + break; + } + + case CSN_UNION_LH: + case CSN_UNION: + { + gint16 Bits; + guint8 index; + gint16 count = pDescr->i; + const CSN_DESCR* pDescrNext = pDescr; + + pDescrNext += count + 1; /* now this is next after the union */ + if ((count <= 0) || (count > 16)) + { + return ProcessError(readIndex,"csnStreamDecoder", CSN_ERROR_INVALID_UNION_INDEX, pDescr); + } + + /* Now get the bits to extract the index */ + Bits = ixBitsTab[count]; + index = 0; + + while (Bits > 0) + { + index <<= 1; + + if (CSN_UNION_LH == pDescr->type) + { + index |= get_masked_bits8(vector, readIndex, bit_offset, 1); + } + else + { + index |= bitvec_read_field(vector, readIndex, 1); + } + remaining_bits_len--; + bit_offset++; + Bits--; + } + + /* Assign UnionType */ + pui8 = pui8DATA(data, pDescr->offset); + *pui8 = index; + + + /* script index to continue on, limited in case we do not have a power of 2 */ + pDescr += (MIN(index + 1, count)); + LOGPC(DLCSN1, LOGL_DEBUG, "%s = %u | ", pDescr->sz , (unsigned)*pui8); + + switch (pDescr->type) + { /* get the right element of the union based on computed index */ + + case CSN_BIT: + { + pui8 = pui8DATA(data, pDescr->offset); + *pui8 = 0x00; + if (bitvec_read_field(vector, readIndex, 1) > 0) + { + *pui8 = 0x01; + } + LOGPC(DLCSN1, LOGL_DEBUG, "%s = %u | ", pDescr->sz , (unsigned)*pui8); + remaining_bits_len -= 1; + bit_offset++; + pDescr++; + break; + } + + case CSN_NULL: + { /* Empty member! */ + bit_offset += pDescr->i; + pDescr++; + break; + } + + case CSN_UINT: + { + guint8 no_of_bits = (guint8) pDescr->i; + if (remaining_bits_len >= no_of_bits) + { + if (no_of_bits <= 8) + { + guint8 ui8 = bitvec_read_field(vector, readIndex, no_of_bits); + pui8 = pui8DATA(data, pDescr->offset); + *pui8 = ui8; + LOGPC(DLCSN1, LOGL_DEBUG, "%s = %u | ", pDescr->sz , (unsigned)*pui8); + } + else if (no_of_bits <= 16) + { + guint16 ui16 = bitvec_read_field(vector, readIndex, no_of_bits); + pui16 = pui16DATA(data, pDescr->offset); + *pui16 = ui16; + LOGPC(DLCSN1, LOGL_DEBUG, "%s = %u | ", pDescr->sz , *pui16); + } + else if (no_of_bits <= 32) + { + guint32 ui32 = bitvec_read_field(vector, readIndex, no_of_bits); + pui32 = pui32DATA(data, pDescr->offset); + *pui32 = ui32; + LOGPC(DLCSN1, LOGL_DEBUG, "%s = %u | ", pDescr->sz , *pui32); + } + else + { + return ProcessError(readIndex,"csnStreamDecoder", CSN_ERROR_GENERAL, pDescr); + } + } + else + { + return ProcessError(readIndex,"csnStreamDecoder", CSN_ERROR_GENERAL, pDescr); + } + + remaining_bits_len -= no_of_bits; + bit_offset += no_of_bits; + pDescr++; + break; + } + + case CSN_UINT_OFFSET: + { + guint8 no_of_bits = (guint8) pDescr->i; + + if (remaining_bits_len >= no_of_bits) + { + if (no_of_bits <= 8) + { + guint8 ui8 = bitvec_read_field(vector, readIndex, no_of_bits); + pui8 = pui8DATA(data, pDescr->offset); + *pui8 = ui8 + (guint8)pDescr->descr.value; + LOGPC(DLCSN1, LOGL_DEBUG, "%s = %u | ", pDescr->sz , (unsigned)*pui8); + } + else if (no_of_bits <= 16) + { + guint16 ui16 = bitvec_read_field(vector, readIndex, no_of_bits); + pui16 = pui16DATA(data, pDescr->offset); + *pui16 = ui16 + (guint16)pDescr->descr.value; + LOGPC(DLCSN1, LOGL_DEBUG, "%s = %u | ", pDescr->sz , *pui16); + } + else if (no_of_bits <= 32) + { + guint32 ui32 = bitvec_read_field(vector, readIndex, no_of_bits); + pui32 = pui32DATA(data, pDescr->offset); + *pui32 = ui32 + (guint16)pDescr->descr.value; + LOGPC(DLCSN1, LOGL_DEBUG, "%s = %u | ", pDescr->sz , *pui32); + } + else + { + return ProcessError(readIndex,"csnStreamDecoder", CSN_ERROR_GENERAL, pDescr); + } + } + else + { + return ProcessError(readIndex,"csnStreamDecoder", CSN_ERROR_NEED_MORE_BITS_TO_UNPACK, pDescr); + } + + remaining_bits_len -= no_of_bits; + bit_offset += no_of_bits; + pDescr++; + break; + } + + case CSN_UINT_LH: + { + guint8 no_of_bits = (guint8) pDescr->i; + + if (remaining_bits_len >= no_of_bits) + { + if (no_of_bits <= 8) + { + guint8 ui8 = get_masked_bits8(vector, readIndex, bit_offset, no_of_bits); + pui8 = pui8DATA(data, pDescr->offset); + *pui8 = ui8; + LOGPC(DLCSN1, LOGL_DEBUG, "%s = %u | ", pDescr->sz , (unsigned)*pui8); + } + else + { /* Maybe we should support more than 8 bits ? */ + return ProcessError(readIndex,"csnStreamDecoder", CSN_ERROR_GENERAL, pDescr); + } + } + else + { + return ProcessError(readIndex,"csnStreamDecoder", CSN_ERROR_NEED_MORE_BITS_TO_UNPACK, pDescr); + } + + remaining_bits_len -= no_of_bits; + bit_offset += no_of_bits; + pDescr++; + break; + } + + case CSN_UINT_ARRAY: + { + guint8 no_of_bits = (guint8) pDescr->i; + guint16 nCount = (guint16)pDescr->descr.value; /* nCount supplied by value i.e. M_UINT_ARRAY(...) */ + + if (pDescr->value != 0) + { /* nCount specified by a reference to field holding value i.e. M_VAR_UINT_ARRAY(...) */ + nCount = *pui16DATA(data, nCount); + } + + if (remaining_bits_len >= (no_of_bits * nCount)) + { + remaining_bits_len -= (no_of_bits * nCount); + if (no_of_bits <= 8) + { + pui8 = pui8DATA(data, pDescr->offset); + + while (nCount > 0) + { + *pui8 = bitvec_read_field(vector, readIndex, no_of_bits); + LOGPC(DLCSN1, LOGL_DEBUG, "%s = %u | ", pDescr->sz , (unsigned)*pui8); + pui8++; + bit_offset += no_of_bits; + nCount--; + } + } + else if (no_of_bits <= 16) + { + pui16 = pui16DATA(data, pDescr->offset); + + while (nCount > 0) + { + *pui16 = bitvec_read_field(vector, readIndex, no_of_bits); + LOGPC(DLCSN1, LOGL_DEBUG, "%s = %u | ", pDescr->sz , *pui16); + pui16++; + bit_offset += no_of_bits; + nCount--; + } + } + else if (no_of_bits <= 32) + { /* not supported */ + return ProcessError(readIndex,"csnStreamDecoder NOT IMPLEMENTED", 999, pDescr); + } + else + { + return ProcessError(readIndex,"csnStreamDecoder", CSN_ERROR_GENERAL, pDescr); + } + } + else + { + return ProcessError(readIndex,"csnStreamDecoder", CSN_ERROR_NEED_MORE_BITS_TO_UNPACK, pDescr); + } + + pDescr++; + break; + } + + case CSN_VARIABLE_TARRAY_OFFSET: + case CSN_VARIABLE_TARRAY: + case CSN_TYPE_ARRAY: + { + gint16 Status; + csnStream_t arT = *ar; + guint16 nCount = (guint16) pDescr->i; + guint16 nSize = (guint16)(guint32)pDescr->value; + + pui8 = pui8DATA(data, pDescr->offset); + + if (CSN_VARIABLE_TARRAY == pDescr->type) + { /* Count specified in field */ + nCount = *pui8DATA(data, pDescr->i); + } + else if (CSN_VARIABLE_TARRAY_OFFSET == pDescr->type) + { /* Count specified in field */ + nCount = *pui8DATA(data, pDescr->i); + nCount--; /* Offset 1 */ + } + + while (nCount--) /* Changed to handle length = 0. */ + { + LOGPC(DLCSN1, LOGL_DEBUG, "%s | ", pDescr->sz); + csnStreamInit(&arT, bit_offset, remaining_bits_len); + Status = csnStreamDecoder(&arT, (const CSN_DESCR*)pDescr->descr.ptr, vector, readIndex, pui8); + if (Status >= 0) + { + pui8 += nSize; + remaining_bits_len = arT.remaining_bits_len; + bit_offset = arT.bit_offset; + } + else + { + return Status; + } + } + + pDescr++; + break; + } + + case CSN_BITMAP: + { /* bitmap with given length. The result is left aligned! */ + guint8 no_of_bits = (guint8) pDescr->i; /* length of bitmap */ + + if (no_of_bits > 0) + { + if (no_of_bits > remaining_bits_len) + { + return ProcessError(readIndex, "csnStreamDecoder", CSN_ERROR_NEED_MORE_BITS_TO_UNPACK, pDescr); + } + + if (no_of_bits <= 32) + { + guint32 ui32 = bitvec_read_field(vector, readIndex, no_of_bits); + pui32 = pui32DATA(data, pDescr->offset); + *pui32 = ui32; + } + else if (no_of_bits <= 64) + { + guint64 ui64 = bitvec_read_field(vector, readIndex, no_of_bits); + pui64 = pui64DATA(data, pDescr->offset); + *pui64 = ui64; + LOGPC(DLCSN1, LOGL_DEBUG, "%s = %lu | ", pDescr->sz , *pui64); + } + else + { + return ProcessError(readIndex,"csnStreamDecoder NOT IMPLEMENTED", 999, pDescr); + } + + remaining_bits_len -= no_of_bits; + bit_offset += no_of_bits; + } + /* bitmap was successfully extracted or it was empty */ + + pDescr++; + break; + } + + case CSN_TYPE: + { + gint16 Status; + csnStream_t arT = *ar; + if (pDescr->may_be_null && remaining_bits_len == 0) + { + LOGPC(DLCSN1, LOGL_DEBUG, " : %s = NULL | ", pDescr->sz); + } else { + LOGPC(DLCSN1, LOGL_DEBUG, " : %s | ", pDescr->sz); + csnStreamInit(&arT, bit_offset, remaining_bits_len); + Status = csnStreamDecoder(&arT, (const CSN_DESCR*)pDescr->descr.ptr, vector, readIndex, pvDATA(data, pDescr->offset)); + LOGPC(DLCSN1, LOGL_DEBUG, " : End %s | ", pDescr->sz); + if (Status >= 0) + { + remaining_bits_len = arT.remaining_bits_len; + bit_offset = arT.bit_offset; + } + else + { /* return error code Has already been processed: */ + return Status; + } + } + pDescr++; + break; + } + + default: + { /* descriptions of union elements other than above are illegal */ + return ProcessError(readIndex,"csnStreamDecoder", CSN_ERROR_IN_SCRIPT, pDescr); + } + } + + pDescr = pDescrNext; + break; + } + + case CSN_EXIST: + case CSN_EXIST_LH: + { + guint8 fExist; + + pui8 = pui8DATA(data, pDescr->offset); + + if (CSN_EXIST_LH == pDescr->type) + { + fExist = get_masked_bits8(vector, readIndex, bit_offset, 1); + } + else + { + fExist = bitvec_read_field(vector, readIndex, 1); + } + + *pui8 = fExist; + LOGPC(DLCSN1, LOGL_DEBUG, "%s = %u | ", pDescr->sz , (unsigned)*pui8); + pDescr++; + bit_offset++; + remaining_bits_len -= 1; + + if (!fExist) + { + ar->remaining_bits_len = remaining_bits_len; + ar->bit_offset = bit_offset; + return remaining_bits_len; + } + + break; + } + + case CSN_NEXT_EXIST: + { + guint8 fExist; + guint8 isnull; + + pui8 = pui8DATA(data, pDescr->offset); + + /* this if-statement represents the M_NEXT_EXIST_OR_NULL description element */ + if ((pDescr->may_be_null) && (remaining_bits_len == 0)) + { /* no more bits to decode is fine here - end of message detected and allowed */ + + /* Skip i entries + this entry */ + pDescr += pDescr->i + 1; + + /* Set the data member to "not exist" */ + *pui8 = 0; + break; + } + + /* the "regular" M_NEXT_EXIST description element */ + + fExist = 0x00; + isnull = 1; + if (bitvec_read_field(vector, readIndex, 1)) + { + fExist = 0x01; + if (remaining_bits_len == 1) { + /* If { 1 < end > } and all next items may be null, store it as { 0 } */ + const CSN_DESCR* pDescrNext = pDescr + 1; + guint8 i; + for (i = 0; i < pDescr->i; i++, pDescrNext++) + { + if (!pDescrNext->may_be_null) + isnull = 0; + } + } else { + isnull = 0; + } + } + + *pui8 = !isnull; + remaining_bits_len -= 1; + LOGPC(DLCSN1, LOGL_DEBUG, "%s = %u%s | ", pDescr->sz, (unsigned)fExist, fExist && isnull ? " (NULL)" : ""); + ++bit_offset; + + if (isnull) + { /* Skip 'i' entries */ + pDescr += pDescr->i; + } + + pDescr++; + break; + } + + case CSN_NEXT_EXIST_LH: + { + guint8 fExist; + guint8 isnull; + pui8 = pui8DATA(data, pDescr->offset); + + /* this if-statement represents the M_NEXT_EXIST_OR_NULL_LH description element */ + if ((pDescr->descr.ptr != NULL) && (remaining_bits_len == 0)) + { /* no more bits to decode is fine here - end of message detected and allowed */ + + /* skip 'i' entries + this entry */ + pDescr += pDescr->i + 1; + + /* set the data member to "not exist" */ + *pui8 = 0; + break; + } + + /* the "regular" M_NEXT_EXIST_LH description element */ + isnull = 1; + if ((fExist = get_masked_bits8(vector, readIndex, bit_offset, 1))) + { + if (remaining_bits_len == 1) { + /* If { 1 < end > } and all next items may be null, store it as { 0 } */ + const CSN_DESCR* pDescrNext = pDescr + 1; + guint8 i; + for (i = 0; i < pDescr->i; i++, pDescrNext++) + { + if (!pDescrNext->may_be_null) + isnull = 0; + } + } else { + isnull = 0; + } + } + LOGPC(DLCSN1, LOGL_DEBUG, "%s = %u%s | ", pDescr->sz , (unsigned)fExist, fExist && isnull ? " (NULL)" : ""); + *pui8++ = !isnull; + remaining_bits_len -= 1; + + bit_offset++; + + if (isnull) + { /* Skip 'i' entries */ + pDescr += pDescr->i; + } + pDescr++; + + break; + } + + case CSN_VARIABLE_BITMAP_1: + { /* Bitmap from here and to the end of message */ + + *pui8DATA(data, (gint16)pDescr->descr.value) = (guint8) remaining_bits_len; /* length of bitmap == remaining bits */ + + /*no break - + * with a length set we have a regular variable length bitmap so we continue */ + } + /* FALL THROUGH */ + case CSN_VARIABLE_BITMAP: + { /* {CSN_VARIABLE_BITMAP, 0, offsetof(_STRUCT, _ElementCountField), offsetof(_STRUCT, _MEMBER), #_MEMBER} + * + * Bit array with length (in bits) specified in parameter (pDescr->descr) + * The result is right aligned! + */ + gint16 no_of_bits = *pui8DATA(data, (gint16)pDescr->descr.value); + + no_of_bits += pDescr->i; /* adjusted by offset */ + + if (no_of_bits > 0) + { + remaining_bits_len -= no_of_bits; + + if (remaining_bits_len < 0) + { + return ProcessError(readIndex,"csnStreamDecoder", CSN_ERROR_NEED_MORE_BITS_TO_UNPACK, pDescr); + } + + { /* extract bits */ + guint8* pui8 = pui8DATA(data, pDescr->offset); + gint16 nB1 = no_of_bits & 0x07;/* no_of_bits Mod 8 */ + + if (nB1 > 0) + { /* take care of the first byte - it will be right aligned */ + *pui8 = bitvec_read_field(vector, readIndex, nB1); + LOGPC(DLCSN1, LOGL_DEBUG, "%s = %u | ", pDescr->sz , (unsigned)*pui8); + pui8++; + no_of_bits -= nB1; + bit_offset += nB1; /* (nB1 is no_of_bits Mod 8) */ + } + + /* remaining no_of_bits is a multiple of 8 or 0 */ + while (no_of_bits > 0) + { + *pui8 = bitvec_read_field(vector, readIndex, 8); + LOGPC(DLCSN1, LOGL_DEBUG, "%s = %u | ", pDescr->sz , (unsigned)*pui8); + pui8++; + no_of_bits -= 8; + } + } + } + pDescr++; + break; + } + + case CSN_LEFT_ALIGNED_VAR_BMP_1: + { /* Bitmap from here and to the end of message */ + + *pui8DATA(data, (gint16)pDescr->descr.value) = (guint8) remaining_bits_len; /* length of bitmap == remaining bits */ + + /* no break - + * with a length set we have a regular left aligned variable length bitmap so we continue + */ + } + /* FALL THROUGH */ + case CSN_LEFT_ALIGNED_VAR_BMP: + { /* {CSN_LEFT_ALIGNED_VAR_BMP, _OFFSET, (void*)offsetof(_STRUCT, _ElementCountField), offsetof(_STRUCT, _MEMBER), #_MEMBER} + * + * bit array with length (in bits) specified in parameter (pDescr->descr) + */ + gint16 no_of_bits = *pui8DATA(data, (gint16)pDescr->descr.value);/* Size of bitmap */ + + no_of_bits += pDescr->i;/* size adjusted by offset */ + + if (no_of_bits > 0) + { + remaining_bits_len -= no_of_bits; + + if (remaining_bits_len < 0) + { + return ProcessError(readIndex,"csnStreamDecoder", CSN_ERROR_NEED_MORE_BITS_TO_UNPACK, pDescr); + } + + { /* extract bits */ + guint8* pui8 = pui8DATA(data, pDescr->offset); + + while (no_of_bits >= 8) + { + *pui8 = bitvec_read_field(vector, readIndex, 8); + LOGPC(DLCSN1, LOGL_DEBUG, "%s = %u | ", pDescr->sz , (unsigned)*pui8); + pui8++; + no_of_bits -= 8; + } + if (no_of_bits > 0) + { + *pui8 = bitvec_read_field(vector, readIndex, no_of_bits); + LOGPC(DLCSN1, LOGL_DEBUG, "%s = %u | ", pDescr->sz , (unsigned)*pui8); + pui8++; + bit_offset += no_of_bits; + no_of_bits = 0; + } + } + } + + /* bitmap was successfully extracted or it was empty */ + pDescr++; + break; + } + + case CSN_PADDING_BITS: + { /* Padding from here and to the end of message */ + LOGPC(DLCSN1, LOGL_DEBUG, "%s = ", pDescr->sz); + if (remaining_bits_len > 0) + { + while (remaining_bits_len > 0) + { + guint bits_to_handle = remaining_bits_len%8; + if (bits_to_handle > 0) + { + LOGPC(DLCSN1, LOGL_DEBUG, "%d|", bitvec_get_uint(vector, bits_to_handle)); + remaining_bits_len -= bits_to_handle; + bit_offset += bits_to_handle; + } + else if (bits_to_handle == 0) + { + LOGPC(DLCSN1, LOGL_DEBUG, "%d|", bitvec_get_uint(vector, 8)); + remaining_bits_len -= 8; + bit_offset += 8; + } + } + } + if (remaining_bits_len < 0) + { + return ProcessError(readIndex,"csnStreamDecoder", CSN_ERROR_NEED_MORE_BITS_TO_UNPACK, pDescr); + } + + /* Padding was successfully extracted or it was empty */ + pDescr++; + break; + } + + case CSN_VARIABLE_ARRAY: + { /* {int type; int i; void* descr; int offset; const char* sz; } CSN_DESCR; + * {CSN_VARIABLE_ARRAY, _OFFSET, (void*)offsetof(_STRUCT, _ElementCountField), offsetof(_STRUCT, _MEMBER), #_MEMBER} + * Array with length specified in parameter: + * + * + */ + gint16 count = *pui8DATA(data, (gint16)pDescr->descr.value); + + count += pDescr->i; /* Adjusted by offset */ + + if (count > 0) + { + remaining_bits_len -= count * 8; + + if (remaining_bits_len < 0) + { + return ProcessError(readIndex,"csnStreamDecoder", CSN_ERROR_NEED_MORE_BITS_TO_UNPACK, pDescr); + } + + pui8 = pui8DATA(data, pDescr->offset); + + while (count > 0) + { + *pui8 = bitvec_read_field(vector, readIndex, 8); + LOGPC(DLCSN1, LOGL_DEBUG, "%s = 0x%x | ", pDescr->sz , (unsigned)*pui8); + pui8++; + bit_offset += 8; + count--; + } + } + + pDescr++; + break; + } + + case CSN_RECURSIVE_ARRAY: + { /* Recursive way to specify an array: ::= {1 | 0} + * or more generally: ::= { | } + * where ::= bit(value) + * ::= 0 | 1 + * ::= reversed tag i.e. tag == 1 -> EndTag == 0 and vice versa + * {CSN_RECURSIVE_ARRAY, _BITS, (void*)offsetof(_STRUCT, _ElementCountField), offsetof(_STRUCT, _MEMBER), #_MEMBER} + * REMARK: recursive way to specify an array but an iterative implementation! + */ + gint16 no_of_bits = pDescr->i; + guint8 ElementCount = 0; + + pui8 = pui8DATA(data, pDescr->offset); + + while (existNextElement(vector, readIndex, Tag)) + { /* tag control shows existence of next list elements */ + LOGPC(DLCSN1, LOGL_DEBUG, "%s = Exist | ", pDescr->sz); + bit_offset++; + remaining_bits_len--; + + /* extract and store no_of_bits long element from bitstream */ + *pui8 = bitvec_read_field(vector, readIndex, no_of_bits); + LOGPC(DLCSN1, LOGL_DEBUG, "%s = %u | ", pDescr->sz , (unsigned)*pui8); + pui8++; + remaining_bits_len -= no_of_bits; + ElementCount++; + + if (remaining_bits_len < 0) + { + return ProcessError(readIndex,"csnStreamDecoder", CSN_ERROR_NEED_MORE_BITS_TO_UNPACK, pDescr); + } + + bit_offset += no_of_bits; + } + + LOGPC(DLCSN1, LOGL_DEBUG, "%s = %d | ", pDescr->sz , bitvec_get_uint(vector, 1)); + /* existNextElement() returned FALSE, 1 bit consumed */ + bit_offset++; + remaining_bits_len--; + + /* Store the counted number of elements of the array */ + *pui8DATA(data, (gint16)pDescr->descr.value) = ElementCount; + + pDescr++; + break; + } + + case CSN_RECURSIVE_TARRAY: + { /* Recursive way to specify an array of type: ::= { 1 } ** 0 ; + * M_REC_TARRAY(_STRUCT, _MEMBER, _MEMBER_TYPE, _ElementCountField) + * {t, offsetof(_STRUCT, _ElementCountField), (void*)CSNDESCR_##_MEMBER_TYPE, offsetof(_STRUCT, _MEMBER), #_MEMBER, (StreamSerializeFcn_t)sizeof(_MEMBER_TYPE), (void_fn_t)ElementsOf(((_STRUCT*)0)->_MEMBER)} + */ + gint16 nSizeElement = (gint16)(gint32)pDescr->value; + guint32 nSizeArray = (guint32)((uintptr_t)pDescr->aux_fn); + guint8 ElementCount = 0; + pui8 = pui8DATA(data, pDescr->offset); + + while (existNextElement(vector, readIndex, Tag)) + { /* tag control shows existence of next list elements */ + LOGPC(DLCSN1, LOGL_DEBUG, "%s = Exist | ", pDescr->sz); + /* existNextElement() returned TRUE, 1 bit consumed */ + bit_offset++; + remaining_bits_len--; + ElementCount++; + + if (ElementCount > nSizeArray) + { + LOGPC(DLCSN1, LOGL_ERROR, "error: %s: too many elements (>%u) in recursive array. Increase its size! } |", pDescr->sz, nSizeArray); + return ProcessError(readIndex,"csnStreamDecoder", CSN_ERROR_STREAM_NOT_SUPPORTED, pDescr); + } + + { /* unpack the following data structure */ + csnStream_t arT = *ar; + gint16 Status; + csnStreamInit(&arT, bit_offset, remaining_bits_len); + Status = csnStreamDecoder(&arT, (const CSN_DESCR*)pDescr->descr.ptr, vector, readIndex, pui8); + + if (Status >= 0) + { /* successful completion */ + pui8 += nSizeElement; /* -> to next data element */ + remaining_bits_len = arT.remaining_bits_len; + bit_offset = arT.bit_offset; + } + else + { /* something went awry */ + return Status; + } + } + + if (remaining_bits_len < 0) + { + return ProcessError(readIndex,"csnStreamDecoder", CSN_ERROR_NEED_MORE_BITS_TO_UNPACK, pDescr); + } + } + + LOGPC(DLCSN1, LOGL_DEBUG, "%s = %d | ", pDescr->sz , bitvec_get_uint(vector, 1)); + + /* existNextElement() returned FALSE, 1 bit consumed */ + remaining_bits_len--; + bit_offset++; + + /* Store the counted number of elements of the array */ + *pui8DATA(data, (gint16)(gint32)pDescr->i) = ElementCount; + + pDescr++; + break; + } + + case CSN_RECURSIVE_TARRAY_2: + { /* Recursive way to specify an array of type: ::= { 0 } ** 1 ; */ + + Tag = REVERSED_TAG; + + /* NO break - + * handling is exactly the same as for CSN_RECURSIVE_TARRAY_1 so we continue + */ + } + /* FALL THROUGH */ + case CSN_RECURSIVE_TARRAY_1: + { /* Recursive way to specify an array of type: ::= { 1 } ** 0 ; + * M_REC_TARRAY(_STRUCT, _MEMBER, _MEMBER_TYPE, _ElementCountField) + * {t, offsetof(_STRUCT, _ElementCountField), (void*)CSNDESCR_##_MEMBER_TYPE, offsetof(_STRUCT, _MEMBER), #_MEMBER, (StreamSerializeFcn_t)sizeof(_MEMBER_TYPE), (void_fn_t)ElementsOf(((_STRUCT*)0)->_MEMBER)} + */ + gint16 nSizeElement = (gint16)(gint32)pDescr->value; + guint32 nSizeArray = (guint32)((uintptr_t)pDescr->aux_fn); + guint8 ElementCount = 0; + csnStream_t arT = *ar; + gboolean EndOfList = FALSE; + gint16 Status; + pui8 = pui8DATA(data, pDescr->offset); + + do + { /* get data element */ + ElementCount++; + + if (ElementCount > nSizeArray) + { + LOGPC(DLCSN1, LOGL_ERROR, "error: %s: too many elements (>%u) in recursive array. Increase its size! } |", pDescr->sz, nSizeArray); + return ProcessError(readIndex,"csnStreamDecoder", CSN_ERROR_STREAM_NOT_SUPPORTED, pDescr); + } + + LOGPC(DLCSN1, LOGL_DEBUG, "%s { | ", pDescr->sz); + + csnStreamInit(&arT, bit_offset, remaining_bits_len); + Status = csnStreamDecoder(&arT, (const CSN_DESCR*)pDescr->descr.ptr, vector, readIndex, pui8); + + if (Status >= 0) + { /* successful completion */ + pui8 += nSizeElement; /* -> to next */ + remaining_bits_len = arT.remaining_bits_len; + bit_offset = arT.bit_offset; + } + else + { /* something went awry */ + return Status; + } + + if (remaining_bits_len < 0) + { + return ProcessError(readIndex,"csnStreamDecoder", CSN_ERROR_NEED_MORE_BITS_TO_UNPACK, pDescr); + } + + /* control of next element's tag */ + LOGPC(DLCSN1, LOGL_DEBUG, "%s } | ", pDescr->sz); + EndOfList = !(existNextElement(vector, readIndex, Tag)); + + bit_offset++; + remaining_bits_len--; /* 1 bit consumed (tag) */ + } while (!EndOfList); + + + /* Store the count of the array */ + *pui8DATA(data, pDescr->i) = ElementCount; + Tag = STANDARD_TAG; /* in case it was set to "reversed" */ + pDescr++; + break; + } + + case CSN_FIXED: + { /* Verify the fixed bits */ + guint8 no_of_bits = (guint8) pDescr->i; + guint32 ui32; + + if (no_of_bits <= 32) + { + ui32 = bitvec_read_field(vector, readIndex, no_of_bits); + } + else + { + return ProcessError(readIndex,"no_of_bits > 32", -1, pDescr); + } + if (ui32 != (unsigned)(gint32)pDescr->offset) + { + return ProcessError(readIndex,"csnStreamDecoder FIXED value does not match", -1, pDescr); + } + + LOGPC(DLCSN1, LOGL_DEBUG, "%s = %u | ", pDescr->sz , (unsigned int)ui32); + remaining_bits_len -= no_of_bits; + bit_offset += no_of_bits; + pDescr++; + break; + } + + case CSN_CALLBACK: + { + guint16 no_of_bits; + DissectorCallbackFcn_t callback = (DissectorCallbackFcn_t)pDescr->aux_fn; + LOGPC(DLCSN1, LOGL_DEBUG, "CSN_CALLBACK(%s) | ", pDescr->sz); + no_of_bits = callback(vector, readIndex, pvDATA(data, pDescr->i), pvDATA(data, pDescr->offset)); + remaining_bits_len -= no_of_bits; + bit_offset += no_of_bits; + pDescr++; + break; + } + + case CSN_TRAP_ERROR: + { + return ProcessError(readIndex,"csnStreamDecoder", pDescr->i, pDescr); + } + + case CSN_END: + { + ar->remaining_bits_len = remaining_bits_len; + ar->bit_offset = bit_offset; + return remaining_bits_len; + } + + default: + { + assert(0); + } + + + } + + } while (remaining_bits_len >= 0); + + return ProcessError(readIndex,"csnStreamDecoder", CSN_ERROR_NEED_MORE_BITS_TO_UNPACK, pDescr); +} diff --git a/src/csn1/csn1_enc.c b/src/csn1/csn1_enc.c new file mode 100644 index 0000000..a5a0abf --- /dev/null +++ b/src/csn1/csn1_enc.c @@ -0,0 +1,1301 @@ +/* csn1_enc.c + * Routines for CSN1 dissection in wireshark. + * + * Copyright (C) 2011 Ivan Klyuchnikov + * + * By Vincent Helfre, based on original code by Jari Sassi + * with the gracious authorization of STE + * Copyright (c) 2011 ST-Ericsson + * + * $Id: packet-csn1.c 39140 2011-09-25 22:01:50Z wmeier $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#define __STDC_FORMAT_MACROS +#include + +#include +#include + +#include + +extern const unsigned char ixBitsTab[]; +guint8 get_masked_bits8(struct bitvec *vector, unsigned *readIndex, gint bit_offset, const gint no_of_bits); + +/** + * ================================================================================================ + * set initial/start values in help data structure used for packing/unpacking operation + * ================================================================================================ + */ + +gint16 csnStreamEncoder(csnStream_t* ar, const CSN_DESCR* pDescr, struct bitvec *vector, unsigned *writeIndex, void* data) +{ + gint remaining_bits_len = ar->remaining_bits_len; + gint bit_offset = ar->bit_offset; + guint8* pui8; + guint16* pui16; + guint32* pui32; + guint64* pui64; + unsigned ib; + + guint8 Tag = STANDARD_TAG; + + if (remaining_bits_len < 0) + { + return ProcessError(writeIndex, __func__, CSN_ERROR_NEED_MORE_BITS_TO_UNPACK, pDescr); + } + + do + { + switch (pDescr->type) + { + case CSN_BIT: + { + if (remaining_bits_len > 0) + { + pui8 = pui8DATA(data, pDescr->offset); + bitvec_write_field(vector, writeIndex, *pui8, 1); + LOGPC(DLCSN1, LOGL_DEBUG, "%s = %u | ", pDescr->sz , (unsigned)*pui8); + /* end add the bit value to protocol tree */ + } + else if (pDescr->may_be_null) + { + LOGPC(DLCSN1, LOGL_DEBUG, "%s = NULL | ", pDescr->sz); + } + else + { + return ProcessError(writeIndex,"csnStreamEncoder", CSN_ERROR_NEED_MORE_BITS_TO_UNPACK, pDescr); + } + + pDescr++; + remaining_bits_len--; + bit_offset++; + break; + } + + case CSN_NULL: + { /* Empty member! */ + pDescr++; + break; + } + + case CSN_UINT: + { + guint8 no_of_bits = (guint8) pDescr->i; + + if (remaining_bits_len >= no_of_bits) + { + if (no_of_bits <= 8) + { + pui8 = pui8DATA(data, pDescr->offset); + bitvec_write_field(vector, writeIndex, *pui8, no_of_bits); + LOGPC(DLCSN1, LOGL_DEBUG, "%s = %u | ", pDescr->sz , (unsigned)*pui8); + } + else if (no_of_bits <= 16) + { + pui16 = pui16DATA(data, pDescr->offset); + bitvec_write_field(vector, writeIndex, *pui16, no_of_bits); + LOGPC(DLCSN1, LOGL_DEBUG, "%s = %u | ", pDescr->sz , *pui16); + } + else if (no_of_bits <= 32) + { + pui32 = pui32DATA(data, pDescr->offset); + bitvec_write_field(vector, writeIndex, *pui32, no_of_bits); + LOGPC(DLCSN1, LOGL_DEBUG, "%s = %u | ", pDescr->sz , *pui32); + } + else + { + return ProcessError(writeIndex,"csnStreamEncoder", CSN_ERROR_GENERAL, pDescr); + } + + remaining_bits_len -= no_of_bits; + bit_offset += no_of_bits; + } + else if (pDescr->may_be_null) + { + LOGPC(DLCSN1, LOGL_DEBUG, "%s = NULL | ", pDescr->sz); + } + else + { + return ProcessError(writeIndex,"csnStreamEncoder", CSN_ERROR_NEED_MORE_BITS_TO_UNPACK, pDescr); + } + + pDescr++; + break; + } + + case CSN_UINT_OFFSET: + { + guint8 no_of_bits = (guint8) pDescr->i; + + if (remaining_bits_len >= no_of_bits) + { + if (no_of_bits <= 8) + { + pui8 = pui8DATA(data, pDescr->offset); + bitvec_write_field(vector, writeIndex, *pui8 - (guint8)pDescr->descr.value, no_of_bits); + LOGPC(DLCSN1, LOGL_DEBUG, "%s = %u | ", pDescr->sz , (unsigned)(*pui8 - (guint8)pDescr->descr.value)); + } + else if (no_of_bits <= 16) + { + pui16 = pui16DATA(data, pDescr->offset); + bitvec_write_field(vector, writeIndex, *pui16 - (guint16)pDescr->descr.value, no_of_bits); + LOGPC(DLCSN1, LOGL_DEBUG, "%s = %u | ", pDescr->sz , (unsigned short)(*pui16 - (guint16)pDescr->descr.value)); + } + else if (no_of_bits <= 32) + { + pui32 = pui32DATA(data, pDescr->offset); + bitvec_write_field(vector, writeIndex, *pui32 - (guint16)pDescr->descr.value, no_of_bits); + LOGPC(DLCSN1, LOGL_DEBUG, "%s = %u | ", pDescr->sz , (unsigned int)(*pui32 - (guint16)pDescr->descr.value)); + } + else + { + return ProcessError(writeIndex,"csnStreamEncoder", CSN_ERROR_GENERAL, pDescr); + } + } + else + { + return ProcessError(writeIndex,"csnStreamEncoder", CSN_ERROR_NEED_MORE_BITS_TO_UNPACK, pDescr); + } + + remaining_bits_len -= no_of_bits; + bit_offset += no_of_bits; + pDescr++; + break; + } + + case CSN_UINT_LH: + { + guint8 no_of_bits = (guint8) pDescr->i; + + if (remaining_bits_len >= no_of_bits) + { + if (no_of_bits <= 8) + { + pui8 = pui8DATA(data, pDescr->offset); + bitvec_write_field(vector, writeIndex, *pui8, no_of_bits); + // TODO : Change get_masked_bits8() + *writeIndex -= no_of_bits; + guint8 ui8 = get_masked_bits8(vector, writeIndex, bit_offset, no_of_bits); + *writeIndex -= no_of_bits; + bitvec_write_field(vector, writeIndex, ui8, no_of_bits); + LOGPC(DLCSN1, LOGL_DEBUG, "%s = %u | ", pDescr->sz , (unsigned)*pui8); + + } + else + {/* Maybe we should support more than 8 bits ? */ + return ProcessError(writeIndex,"csnStreamEncoder", CSN_ERROR_GENERAL, pDescr); + } + } + else + { + return ProcessError(writeIndex,"csnStreamEncoder", CSN_ERROR_NEED_MORE_BITS_TO_UNPACK, pDescr); + } + + remaining_bits_len -= no_of_bits; + bit_offset += no_of_bits; + pDescr++; + break; + } + + case CSN_UINT_ARRAY: + { + guint8 no_of_bits = (guint8) pDescr->i; + guint16 nCount = (guint16)pDescr->descr.value; /* nCount supplied by value i.e. M_UINT_ARRAY(...) */ + + if (pDescr->value != 0) + { /* nCount specified by a reference to field holding value i.e. M_VAR_UINT_ARRAY(...) */ + nCount = *pui16DATA(data, nCount); + } + + if (remaining_bits_len >= (no_of_bits * nCount)) + { + if (no_of_bits <= 8) + { + pui8 = pui8DATA(data, pDescr->offset); + do + { + bitvec_write_field(vector, writeIndex, *pui8, no_of_bits); + LOGPC(DLCSN1, LOGL_DEBUG, "%s = %u | ", pDescr->sz , (unsigned)*pui8); + pui8++; + remaining_bits_len -= no_of_bits; + bit_offset += no_of_bits; + } while (--nCount > 0); + } + else if (no_of_bits <= 16) + { + return ProcessError(writeIndex,"csnStreamEncoder NOTIMPLEMENTED", 999, pDescr); + } + else if (no_of_bits <= 32) + { + return ProcessError(writeIndex,"csnStreamEncoder NOTIMPLEMENTED", 999, pDescr); + } + else + { + return ProcessError(writeIndex,"csnStreamEncoder", CSN_ERROR_GENERAL, pDescr); + } + } + else + { + return ProcessError(writeIndex,"csnStreamEncoder", CSN_ERROR_NEED_MORE_BITS_TO_UNPACK, pDescr); + } + pDescr++; + break; + } + + case CSN_VARIABLE_TARRAY_OFFSET: + case CSN_VARIABLE_TARRAY: + case CSN_TYPE_ARRAY: + { + gint16 Status; + csnStream_t arT = *ar; + gint16 nCount = pDescr->i; + guint16 nSize = (guint16)(gint32)pDescr->value; + + pui8 = pui8DATA(data, pDescr->offset); + if (pDescr->type == CSN_VARIABLE_TARRAY) + { /* Count specified in field */ + nCount = *pui8DATA(data, pDescr->i); + } + else if (pDescr->type == CSN_VARIABLE_TARRAY_OFFSET) + { /* Count specified in field */ + nCount = *pui8DATA(data, pDescr->i); + /* nCount--; the 1 offset is already taken into account in CSN_UINT_OFFSET */ + } + + while (nCount > 0) + { /* resulting array of length 0 is possible + * but no bits shall be read from bitstream + */ + + LOGPC(DLCSN1, LOGL_DEBUG, "%s : | ", pDescr->sz); + csnStreamInit(&arT, bit_offset, remaining_bits_len); + Status = csnStreamEncoder(&arT, (const CSN_DESCR*)pDescr->descr.ptr, vector, writeIndex, pui8); + if (Status >= 0) + { + pui8 += nSize; + remaining_bits_len = arT.remaining_bits_len; + bit_offset = arT.bit_offset; + + } + else + { + return Status; + } + nCount--; + } + + pDescr++; + break; + } + + case CSN_BITMAP: + { /* bitmap with given length. The result is left aligned! */ + guint8 no_of_bits = (guint8) pDescr->i; /* length of bitmap */ + + if (no_of_bits > 0) + { + if (no_of_bits > remaining_bits_len) + { + return ProcessError(writeIndex, "csnStreamDecoder", CSN_ERROR_NEED_MORE_BITS_TO_UNPACK, pDescr); + } + + if (no_of_bits <= 32) + { + for(ib = 0; ib < 4; ib++) + { + pui8 = pui8DATA(data, pDescr->offset+ib); + bitvec_write_field(vector, writeIndex, *pui8, 8); + LOGPC(DLCSN1, LOGL_DEBUG, "%s[%u] = %u | ", pDescr->sz , ib, (unsigned)*pui8); + } + } + else if (no_of_bits <= 64) + { + for(ib = 0; ib < 8; ib++) + { + pui8 = pui8DATA(data, pDescr->offset+ib); + bitvec_write_field(vector, writeIndex, *pui8, 8); + LOGPC(DLCSN1, LOGL_DEBUG, "%s[%u] = %u | ", pDescr->sz , ib, (unsigned)*pui8); + } + } + else + { + return ProcessError(writeIndex,"csnStreamEncoder NOT IMPLEMENTED", 999, pDescr); + } + + remaining_bits_len -= no_of_bits; + bit_offset += no_of_bits; + } + /* bitmap was successfully extracted or it was empty */ + + pDescr++; + break; + } + + case CSN_TYPE: + { + gint16 Status; + csnStream_t arT = *ar; + LOGPC(DLCSN1, LOGL_DEBUG, " : %s | ", pDescr->sz); + csnStreamInit(&arT, bit_offset, remaining_bits_len); + Status = csnStreamEncoder(&arT, (const CSN_DESCR*)pDescr->descr.ptr, vector, writeIndex, pvDATA(data, pDescr->offset)); + LOGPC(DLCSN1, LOGL_DEBUG, " : End %s | ", pDescr->sz); + if (Status >= 0) + { + + remaining_bits_len = arT.remaining_bits_len; + bit_offset = arT.bit_offset; + pDescr++; + } + else + { + /* Has already been processed: ProcessError("csnStreamEncoder", Status, pDescr); */ + return Status; + } + + break; + } + + case CSN_CHOICE: + { + gint16 count = pDescr->i; + const CSN_ChoiceElement_t* pChoice = (const CSN_ChoiceElement_t*) pDescr->descr.ptr; + + /* Make sure that the list of choice items is not empty */ + if (!count) + return ProcessError(writeIndex, "csnStreamEncoder", CSN_ERROR_IN_SCRIPT, pDescr); + else if (count > 255) /* We can handle up to 256 (UCHAR_MAX) selectors */ + return ProcessError(writeIndex, "csnStreamEncoder", CSN_ERROR_IN_SCRIPT, pDescr); + + /* Make sure that choice index is not out of range */ + pui8 = pui8DATA(data, pDescr->offset); + if (*pui8 >= count) + return ProcessError(writeIndex, "csnStreamEncoder", CSN_ERROR_INVALID_UNION_INDEX, pDescr); + + pChoice += *pui8; + guint8 no_of_bits = pChoice->bits; + guint8 value = pChoice->value; + LOGPC(DLCSN1, LOGL_DEBUG, "%s = %u | ", pChoice->descr.sz , (unsigned)value); + bitvec_write_field(vector, writeIndex, value, no_of_bits); + + CSN_DESCR descr[2]; + gint16 Status; + csnStream_t arT = *ar; + + descr[0] = pChoice->descr; + memset(&descr[1], 0x00, sizeof(CSN_DESCR)); + descr[1].type = CSN_END; + bit_offset += no_of_bits; + remaining_bits_len -= no_of_bits; + + csnStreamInit(&arT, bit_offset, remaining_bits_len); + Status = csnStreamEncoder(&arT, descr, vector, writeIndex, data); + + if (Status >= 0) + { + remaining_bits_len = arT.remaining_bits_len; + bit_offset = arT.bit_offset; + } + else + { + return Status; + } + + pDescr++; + break; + } + + case CSN_SERIALIZE: + { + StreamSerializeFcn_t serialize = (StreamSerializeFcn_t)pDescr->aux_fn; + csnStream_t arT = *ar; + guint8 length_len = pDescr->i; + gint16 Status = -1; + unsigned lengthIndex; + + // store writeIndex for length value (7 bit) + lengthIndex = *writeIndex; + *writeIndex += length_len; + bit_offset += length_len; + remaining_bits_len -= length_len; + arT.direction = 0; + csnStreamInit(&arT, bit_offset, remaining_bits_len); + Status = serialize(&arT, vector, writeIndex, pvDATA(data, pDescr->offset)); + + bitvec_write_field(vector, &lengthIndex, *writeIndex - lengthIndex - length_len, length_len); + LOGPC(DLCSN1, LOGL_DEBUG, "%s length = %u | ", pDescr->sz , (unsigned)(*writeIndex - lengthIndex)); + + if (Status >= 0) + { + remaining_bits_len = arT.remaining_bits_len; + bit_offset = arT.bit_offset; + pDescr++; + } + else + { + // Has already been processed: + return Status; + } + + break; + } + + case CSN_UNION_LH: + case CSN_UNION: + { + gint16 Bits; + guint8 index; + gint16 count = pDescr->i; + const CSN_DESCR* pDescrNext = pDescr; + + pDescrNext += count + 1; /* now this is next after the union */ + if ((count <= 0) || (count > 16)) + { + return ProcessError(writeIndex,"csnStreamEncoder", CSN_ERROR_INVALID_UNION_INDEX, pDescr); + } + + /* Now get the bits to extract the index */ + Bits = ixBitsTab[count]; + index = 0; + + /* Assign UnionType */ + pui8 = pui8DATA(data, pDescr->offset); + //read index from data and write to vector + bitvec_write_field(vector, writeIndex, *pui8, Bits); + + //decode index + *writeIndex -= Bits; + + while (Bits > 0) + { + index <<= 1; + + if (CSN_UNION_LH == pDescr->type) + { + index |= get_masked_bits8(vector, writeIndex, bit_offset, 1); + } + else + { + index |= bitvec_read_field(vector, writeIndex, 1); + } + + remaining_bits_len--; + bit_offset++; + Bits--; + } + + *writeIndex -= Bits; + bitvec_write_field(vector, writeIndex, index, Bits); + + + /* script index to continue on, limited in case we do not have a power of 2 */ + pDescr += (MIN(index + 1, count)); + LOGPC(DLCSN1, LOGL_DEBUG, "%s = %u | ", pDescr->sz , (unsigned)index); + + switch (pDescr->type) + { /* get the right element of the union based on computed index */ + + case CSN_BIT: + { + pui8 = pui8DATA(data, pDescr->offset); + bitvec_write_field(vector, writeIndex, *pui8, 1); + LOGPC(DLCSN1, LOGL_DEBUG, "%s = %u | ", pDescr->sz , (unsigned)*pui8); + remaining_bits_len--; + bit_offset++; + pDescr++; + break; + } + + case CSN_NULL: + { /* Empty member! */ + pDescr++; + break; + } + + case CSN_UINT: + { + guint8 no_of_bits = (guint8) pDescr->i; + if (remaining_bits_len >= no_of_bits) + { + if (no_of_bits <= 8) + { + pui8 = pui8DATA(data, pDescr->offset); + bitvec_write_field(vector, writeIndex, *pui8, no_of_bits); + LOGPC(DLCSN1, LOGL_DEBUG, "%s = %u | ", pDescr->sz , (unsigned)*pui8); + } + else if (no_of_bits <= 16) + { + pui16 = pui16DATA(data, pDescr->offset); + bitvec_write_field(vector, writeIndex, *pui16, no_of_bits); + LOGPC(DLCSN1, LOGL_DEBUG, "%s = %u | ", pDescr->sz , *pui16); + } + else if (no_of_bits <= 32) + { + pui32 = pui32DATA(data, pDescr->offset); + bitvec_write_field(vector, writeIndex, *pui32, no_of_bits); + LOGPC(DLCSN1, LOGL_DEBUG, "%s = %u | ", pDescr->sz , *pui32); + } + else + { + return ProcessError(writeIndex,"csnStreamEncoder", CSN_ERROR_GENERAL, pDescr); + } + } + else + { + return ProcessError(writeIndex,"csnStreamEncoder", CSN_ERROR_GENERAL, pDescr); + } + + remaining_bits_len -= no_of_bits; + bit_offset += no_of_bits; + pDescr++; + break; + } + + case CSN_UINT_OFFSET: + { + guint8 no_of_bits = (guint8) pDescr->i; + + if (remaining_bits_len >= no_of_bits) + { + if (no_of_bits <= 8) + { + pui8 = pui8DATA(data, pDescr->offset); + bitvec_write_field(vector, writeIndex, *pui8 - (guint8)pDescr->descr.value, no_of_bits); + LOGPC(DLCSN1, LOGL_DEBUG, "%s = %u | ", pDescr->sz , (unsigned)(*pui8 - (guint8)pDescr->descr.value)); + } + else if (no_of_bits <= 16) + { + pui16 = pui16DATA(data, pDescr->offset); + bitvec_write_field(vector, writeIndex, *pui16 - (guint16)pDescr->descr.value, no_of_bits); + LOGPC(DLCSN1, LOGL_DEBUG, "%s = %u | ", pDescr->sz , (unsigned short)(*pui16 - (guint16)pDescr->descr.value)); + } + else if (no_of_bits <= 32) + { + pui32 = pui32DATA(data, pDescr->offset); + bitvec_write_field(vector, writeIndex, *pui32 - (guint16)pDescr->descr.value, no_of_bits); + LOGPC(DLCSN1, LOGL_DEBUG, "%s = %u | ", pDescr->sz , (unsigned int)(*pui32 - (guint16)pDescr->descr.value)); + } + else + { + return ProcessError(writeIndex,"csnStreamEncoder", CSN_ERROR_GENERAL, pDescr); + } + } + else + { + return ProcessError(writeIndex,"csnStreamEncoder", CSN_ERROR_NEED_MORE_BITS_TO_UNPACK, pDescr); + } + + remaining_bits_len -= no_of_bits; + bit_offset += no_of_bits; + pDescr++; + break; + } + + case CSN_UINT_LH: + { + guint8 no_of_bits = (guint8) pDescr->i; + + if (remaining_bits_len >= no_of_bits) + { + remaining_bits_len -= no_of_bits; + if (no_of_bits <= 8) + { + pui8 = pui8DATA(data, pDescr->offset); + bitvec_write_field(vector, writeIndex, *pui8, no_of_bits); + // TODO : Change get_masked_bits8() + *writeIndex -= no_of_bits; + guint8 ui8 = get_masked_bits8(vector, writeIndex, bit_offset, no_of_bits); + *writeIndex -= no_of_bits; + bitvec_write_field(vector, writeIndex, ui8, no_of_bits); + LOGPC(DLCSN1, LOGL_DEBUG, "%s = %u | ", pDescr->sz , (unsigned)*pui8); + + } + else + {/* Maybe we should support more than 8 bits ? */ + return ProcessError(writeIndex,"csnStreamEncoder", CSN_ERROR_GENERAL, pDescr); + } + } + else + { + return ProcessError(writeIndex,"csnStreamEncoder", CSN_ERROR_NEED_MORE_BITS_TO_UNPACK, pDescr); + } + + remaining_bits_len -= no_of_bits; + bit_offset += no_of_bits; + pDescr++; + break; + } + + case CSN_UINT_ARRAY: + { + guint8 no_of_bits = (guint8) pDescr->i; + guint16 nCount = (guint16)pDescr->descr.value; /* nCount supplied by value i.e. M_UINT_ARRAY(...) */ + + if (pDescr->value != 0) + { /* nCount specified by a reference to field holding value i.e. M_VAR_UINT_ARRAY(...) */ + nCount = *pui16DATA(data, nCount); + } + + if (remaining_bits_len >= (no_of_bits * nCount)) + { + if (no_of_bits <= 8) + { + pui8 = pui8DATA(data, pDescr->offset); + do + { + bitvec_write_field(vector, writeIndex, *pui8, no_of_bits); + LOGPC(DLCSN1, LOGL_DEBUG, "%s = %u | ", pDescr->sz , (unsigned)*pui8); + pui8++; + remaining_bits_len -= no_of_bits; + bit_offset += no_of_bits; + } while (--nCount > 0); + } + else if (no_of_bits <= 16) + { + return ProcessError(writeIndex,"csnStreamEncoder NOTIMPLEMENTED", 999, pDescr); + } + else if (no_of_bits <= 32) + { + return ProcessError(writeIndex,"csnStreamEncoder NOTIMPLEMENTED", 999, pDescr); + } + else + { + return ProcessError(writeIndex,"csnStreamEncoder", CSN_ERROR_GENERAL, pDescr); + } + } + else + { + return ProcessError(writeIndex,"csnStreamEncoder", CSN_ERROR_NEED_MORE_BITS_TO_UNPACK, pDescr); + } + pDescr++; + break; + } + + case CSN_VARIABLE_TARRAY_OFFSET: + case CSN_VARIABLE_TARRAY: + case CSN_TYPE_ARRAY: + { + gint16 Status; + csnStream_t arT = *ar; + gint16 nCount = pDescr->i; + guint16 nSize = (guint16)(gint32)pDescr->value; + + pui8 = pui8DATA(data, pDescr->offset); + if (pDescr->type == CSN_VARIABLE_TARRAY) + { /* Count specified in field */ + nCount = *pui8DATA(data, pDescr->i); + } + else if (pDescr->type == CSN_VARIABLE_TARRAY_OFFSET) + { /* Count specified in field */ + nCount = *pui8DATA(data, pDescr->i); + /* nCount--; the 1 offset is already taken into account in CSN_UINT_OFFSET */ + } + + while (nCount > 0) + { /* resulting array of length 0 is possible + * but no bits shall be read from bitstream + */ + + LOGPC(DLCSN1, LOGL_DEBUG, "%s : | ", pDescr->sz); + csnStreamInit(&arT, bit_offset, remaining_bits_len); + Status = csnStreamEncoder(&arT, (const CSN_DESCR*)pDescr->descr.ptr, vector, writeIndex, pui8); + if (Status >= 0) + { + pui8 += nSize; + remaining_bits_len = arT.remaining_bits_len; + bit_offset = arT.bit_offset; + } + else + { + return Status; + } + nCount--; + } + + pDescr++; + break; + } + + case CSN_BITMAP: + { /* bitmap with given length. The result is left aligned! */ + guint8 no_of_bits = (guint8) pDescr->i; /* length of bitmap */ + + if (no_of_bits > 0) + { + if (no_of_bits > remaining_bits_len) + { + return ProcessError(writeIndex, "csnStreamDecoder", CSN_ERROR_NEED_MORE_BITS_TO_UNPACK, pDescr); + } + + if (no_of_bits <= 32) + { + pui32 = pui32DATA(data, pDescr->offset); + bitvec_write_field(vector, writeIndex, *pui32, no_of_bits); + LOGPC(DLCSN1, LOGL_DEBUG, "%s = %u | ", pDescr->sz , *pui32); + } + else if (no_of_bits <= 64) + { + pui64 = pui64DATA(data, pDescr->offset); + bitvec_write_field(vector, writeIndex, *pui64, no_of_bits); + LOGPC(DLCSN1, LOGL_DEBUG, "%s = %lu | ", pDescr->sz , *pui64); + } + else + { + return ProcessError(writeIndex,"csnStreamEncoder NOT IMPLEMENTED", 999, pDescr); + } + + remaining_bits_len -= no_of_bits; + bit_offset += no_of_bits; + } + /* bitmap was successfully extracted or it was empty */ + + pDescr++; + break; + } + + case CSN_TYPE: + { + gint16 Status; + csnStream_t arT = *ar; + LOGPC(DLCSN1, LOGL_DEBUG, " : %s | ", pDescr->sz); + csnStreamInit(&arT, bit_offset, remaining_bits_len); + Status = csnStreamEncoder(&arT, (const CSN_DESCR*)pDescr->descr.ptr, vector, writeIndex, pvDATA(data, pDescr->offset)); + LOGPC(DLCSN1, LOGL_DEBUG, " : End %s | ", pDescr->sz); + if (Status >= 0) + { + remaining_bits_len = arT.remaining_bits_len; + bit_offset = arT.bit_offset; + pDescr++; + } + else + { + /* Has already been processed: ProcessError("csnStreamEncoder", Status, pDescr); */ + return Status; + } + + break; + } + + default: + { /* descriptions of union elements other than above are illegal */ + return ProcessError(writeIndex,"csnStreamEncoder", CSN_ERROR_IN_SCRIPT, pDescr); + } + } + + pDescr = pDescrNext; + break; + } + + case CSN_EXIST: + case CSN_EXIST_LH: + { + guint8 fExist; + unsigned exist = 0; + pui8 = pui8DATA(data, pDescr->offset); + exist = *pui8; + bitvec_write_field(vector, writeIndex, *pui8, 1); + writeIndex--; + if (CSN_EXIST_LH == pDescr->type) + { + fExist = get_masked_bits8(vector, writeIndex, bit_offset, 1); + } + else + { + fExist = bitvec_read_field(vector, writeIndex, 1); + } + writeIndex--; + bitvec_write_field(vector, writeIndex, fExist, 1); + LOGPC(DLCSN1, LOGL_DEBUG, "%s = %u | ", pDescr->sz, (unsigned)fExist); + remaining_bits_len--; + bit_offset++; + pDescr++; + + if (!exist) + { + ar->remaining_bits_len = remaining_bits_len; + ar->bit_offset = bit_offset; + return remaining_bits_len; + } + break; + } + + case CSN_NEXT_EXIST: + { + guint8 fExist; + + pui8 = pui8DATA(data, pDescr->offset); + + /* this if-statement represents the M_NEXT_EXIST_OR_NULL description element */ + if ((pDescr->may_be_null) && (remaining_bits_len == 0)) + { /* no more bits to decode is fine here - end of message detected and allowed */ + + /* Skip i entries + this entry */ + pDescr += pDescr->i + 1; + + break; + } + + bitvec_write_field(vector, writeIndex, *pui8, 1); + fExist = *pui8; + LOGPC(DLCSN1, LOGL_DEBUG, "%s = %u | ", pDescr->sz , (unsigned)*pui8); + + remaining_bits_len--; + bit_offset++; + + if (fExist == 0) + { /* Skip 'i' entries */ + pDescr += pDescr->i; + } + + pDescr++; + break; + } + + case CSN_NEXT_EXIST_LH: + { + guint8 fExist; + pui8 = pui8DATA(data, pDescr->offset); + + /* this if-statement represents the M_NEXT_EXIST_OR_NULL_LH description element */ + if ((pDescr->descr.ptr != NULL) && (remaining_bits_len == 0)) + { /* no more bits to decode is fine here - end of message detected and allowed */ + + /* skip 'i' entries + this entry */ + pDescr += pDescr->i + 1; + + /* set the data member to "not exist" */ + //*pui8 = 0; + break; + } + + /* the "regular" M_NEXT_EXIST_LH description element */ + bitvec_write_field(vector, writeIndex, *pui8, 1); + writeIndex--; + fExist = get_masked_bits8(vector, writeIndex, bit_offset, 1); + writeIndex--; + bitvec_write_field(vector, writeIndex, fExist, 1); + pui8++; + + remaining_bits_len--; + bit_offset++; + + if (fExist == 0) + { /* Skip 'i' entries */ + pDescr += pDescr->i; + } + pDescr++; + + break; + } + + case CSN_VARIABLE_BITMAP_1: + { /* Bitmap from here and to the end of message */ + + //*pui8DATA(data, (gint16)pDescr->descr.value) = (guint8) remaining_bits_len; /* length of bitmap == remaining bits */ + + /*no break - + * with a length set we have a regular variable length bitmap so we continue */ + } + /* FALL THROUGH */ + case CSN_VARIABLE_BITMAP: + { /* {CSN_VARIABLE_BITMAP, 0, offsetof(_STRUCT, _ElementCountField), offsetof(_STRUCT, _MEMBER), #_MEMBER} + * + * Bit array with length (in bits) specified in parameter (pDescr->descr) + * The result is right aligned! + */ + gint16 no_of_bits = *pui8DATA(data, (gint16)pDescr->descr.value); + + no_of_bits += pDescr->i; /* adjusted by offset */ + + if (no_of_bits > 0) + { + + if (remaining_bits_len < 0) + { + return ProcessError(writeIndex,"csnStreamEncoder", CSN_ERROR_NEED_MORE_BITS_TO_UNPACK, pDescr); + } + + { /* extract bits */ + guint8* pui8 = pui8DATA(data, pDescr->offset); + gint16 nB1 = no_of_bits & 0x07;/* no_of_bits Mod 8 */ + + if (nB1 > 0) + { /* take care of the first byte - it will be right aligned */ + bitvec_write_field(vector, writeIndex, *pui8, nB1); + LOGPC(DLCSN1, LOGL_DEBUG, "%s = %u | ", pDescr->sz , (unsigned)*pui8); + pui8++; + no_of_bits -= nB1; + bit_offset += nB1; /* (nB1 is no_of_bits Mod 8) */ + remaining_bits_len -= nB1; + } + + /* remaining no_of_bits is a multiple of 8 or 0 */ + while (no_of_bits > 0) + { + bitvec_write_field(vector, writeIndex, *pui8, 8); + LOGPC(DLCSN1, LOGL_DEBUG, "%s = %u | ", pDescr->sz , (unsigned)*pui8); + pui8++; + no_of_bits -= 8; + remaining_bits_len -= 8; + } + } + } + pDescr++; + break; + } + + case CSN_LEFT_ALIGNED_VAR_BMP_1: + { /* Bitmap from here and to the end of message */ + + //*pui8DATA(data, (gint16)pDescr->descr.value) = (guint8) remaining_bits_len; /* length of bitmap == remaining bits */ + + /* no break - + * with a length set we have a regular left aligned variable length bitmap so we continue + */ + } + /* FALL THROUGH */ + case CSN_LEFT_ALIGNED_VAR_BMP: + { /* {CSN_LEFT_ALIGNED_VAR_BMP, _OFFSET, (void*)offsetof(_STRUCT, _ElementCountField), offsetof(_STRUCT, _MEMBER), #_MEMBER} + * + * bit array with length (in bits) specified in parameter (pDescr->descr) + */ + + gint16 no_of_bits = *pui8DATA(data, (gint16)pDescr->descr.value);/* Size of bitmap */ + + no_of_bits += pDescr->i;/* size adjusted by offset */ + + if (no_of_bits > 0) + { + remaining_bits_len -= no_of_bits; + + if (remaining_bits_len < 0) + { + return ProcessError(writeIndex,"csnStreamEncoder", CSN_ERROR_NEED_MORE_BITS_TO_UNPACK, pDescr); + } + + { /* extract bits */ + guint8* pui8 = pui8DATA(data, pDescr->offset); + gint16 nB1 = no_of_bits & 0x07;/* no_of_bits Mod 8 */ + + while (no_of_bits > 0) + { + bitvec_write_field(vector, writeIndex, *pui8, 8); + LOGPC(DLCSN1, LOGL_DEBUG, "%s = %u | ", pDescr->sz , (unsigned)*pui8); + pui8++; + no_of_bits -= 8; + } + if (nB1 > 0) + { + bitvec_write_field(vector, writeIndex, *pui8, nB1); + LOGPC(DLCSN1, LOGL_DEBUG, "%s = %u | ", pDescr->sz , (unsigned)*pui8); + pui8++; + no_of_bits -= nB1; + bit_offset += nB1; /* (nB1 is no_of_bits Mod 8) */ + } + } + + } + + /* bitmap was successfully extracted or it was empty */ + pDescr++; + break; + } + + case CSN_PADDING_BITS: + { /* Padding from here and to the end of message */ + LOGPC(DLCSN1, LOGL_DEBUG, "%s = ", pDescr->sz); + guint8 filler = 0x2b; + if (remaining_bits_len > 0) + { + while (remaining_bits_len > 0) + { + guint8 bits_to_handle = remaining_bits_len%8; + if (bits_to_handle > 0) + { + /* section 11 of 44.060 + * The padding bits may be the 'null' string. Otherwise, the + * padding bits starts with bit '0', followed by 'spare padding' + * < padding bits > ::= { null | 0 < spare padding > ! < Ignore : 1 bit** = < no string > > } ; + */ + guint8 fl = filler&(0xff>>(8-bits_to_handle + 1)); + bitvec_write_field(vector, writeIndex, fl, bits_to_handle); + LOGPC(DLCSN1, LOGL_DEBUG, "%u|", fl); + remaining_bits_len -= bits_to_handle; + bit_offset += bits_to_handle; + } + else if (bits_to_handle == 0) + { + bitvec_write_field(vector, writeIndex, filler, 8); + LOGPC(DLCSN1, LOGL_DEBUG, "%u|", filler); + remaining_bits_len -= 8; + bit_offset += 8; + } + } + } + if (remaining_bits_len < 0) + { + return ProcessError(writeIndex,"csnStreamEncoder", CSN_ERROR_NEED_MORE_BITS_TO_UNPACK, pDescr); + } + + /* Padding was successfully extracted or it was empty */ + pDescr++; + break; + } + + case CSN_VARIABLE_ARRAY: + { /* {int type; int i; void* descr; int offset; const char* sz; } CSN_DESCR; + * {CSN_VARIABLE_ARRAY, _OFFSET, (void*)offsetof(_STRUCT, _ElementCountField), offsetof(_STRUCT, _MEMBER), #_MEMBER} + * Array with length specified in parameter: + * + * + */ + gint16 count = *pui8DATA(data, (gint16)pDescr->descr.value); + + count += pDescr->i; /* Adjusted by offset */ + + if (count > 0) + { + if (remaining_bits_len < 0) + { + return ProcessError(writeIndex,"csnStreamEncoder", CSN_ERROR_NEED_MORE_BITS_TO_UNPACK, pDescr); + } + + pui8 = pui8DATA(data, pDescr->offset); + + while (count > 0) + { + bitvec_write_field(vector, writeIndex, *pui8, 8); + LOGPC(DLCSN1, LOGL_DEBUG, "%s = 0x%x | ", pDescr->sz , (unsigned)*pui8); + pui8++; + bit_offset += 8; + remaining_bits_len -= 8; + count--; + } + } + + pDescr++; + break; + } + + case CSN_RECURSIVE_ARRAY: + { /* Recursive way to specify an array: ::= {1 | 0} + * or more generally: ::= { | } + * where ::= bit(value) + * ::= 0 | 1 + * ::= reversed tag i.e. tag == 1 -> EndTag == 0 and vice versa + * {CSN_RECURSIVE_ARRAY, _BITS, (void*)offsetof(_STRUCT, _ElementCountField), offsetof(_STRUCT, _MEMBER), #_MEMBER} + * REMARK: recursive way to specify an array but an iterative implementation! + */ + gint16 no_of_bits = pDescr->i; + guint8 ElementCount = 0; + pui8 = pui8DATA(data, pDescr->offset); + ElementCount = *pui8DATA(data, (gint16)pDescr->descr.value); + while (ElementCount > 0) + { /* tag control shows existence of next list elements */ + bitvec_write_field(vector, writeIndex, Tag, 1); + LOGPC(DLCSN1, LOGL_DEBUG, "%s = %u | ", pDescr->sz , (unsigned)Tag); + bit_offset++; + remaining_bits_len--; + + /* extract and store no_of_bits long element from bitstream */ + bitvec_write_field(vector, writeIndex, *pui8, no_of_bits); + LOGPC(DLCSN1, LOGL_DEBUG, "%s = %u | ", pDescr->sz , (unsigned)*pui8); + pui8++; + ElementCount--; + + if (remaining_bits_len < 0) + { + return ProcessError(writeIndex,"csnStreamEncoder", CSN_ERROR_NEED_MORE_BITS_TO_UNPACK, pDescr); + } + + bit_offset += no_of_bits; + remaining_bits_len -= no_of_bits; + } + + bitvec_write_field(vector, writeIndex, !Tag, 1); + LOGPC(DLCSN1, LOGL_DEBUG, "%s = %u | ", pDescr->sz , (unsigned)(!Tag)); + bit_offset++; + remaining_bits_len--; + + pDescr++; + break; + } + + case CSN_RECURSIVE_TARRAY: + { /* Recursive way to specify an array of type: ::= { 1 } ** 0 ; + * M_REC_TARRAY(_STRUCT, _MEMBER, _MEMBER_TYPE, _ElementCountField) + * {t, offsetof(_STRUCT, _ElementCountField), (void*)CSNDESCR_##_MEMBER_TYPE, offsetof(_STRUCT, _MEMBER), #_MEMBER, (StreamSerializeFcn_t)sizeof(_MEMBER_TYPE)} + */ + gint16 nSizeElement = (gint16)(gint32)pDescr->value; + guint8 ElementCount = 0; + pui8 = pui8DATA(data, pDescr->offset); + /* Store the counted number of elements of the array */ + ElementCount = *pui8DATA(data, (gint16)(gint32)pDescr->i); + + while (ElementCount > 0) + { /* tag control shows existence of next list elements */ + bitvec_write_field(vector, writeIndex, Tag, 1); + LOGPC(DLCSN1, LOGL_DEBUG, "%s = %u | ", pDescr->sz , (unsigned)Tag); + bit_offset++; + + remaining_bits_len--; + ElementCount--; + + { /* unpack the following data structure */ + csnStream_t arT = *ar; + gint16 Status; + csnStreamInit(&arT, bit_offset, remaining_bits_len); + Status = csnStreamEncoder(&arT, (const CSN_DESCR*)pDescr->descr.ptr, vector, writeIndex, pui8); + + if (Status >= 0) + { /* successful completion */ + pui8 += nSizeElement; /* -> to next data element */ + remaining_bits_len = arT.remaining_bits_len; + bit_offset = arT.bit_offset; + } + else + { /* something went awry */ + return Status; + } + } + + if (remaining_bits_len < 0) + { + return ProcessError(writeIndex,"csnStreamEncoder", CSN_ERROR_NEED_MORE_BITS_TO_UNPACK, pDescr); + } + } + + bitvec_write_field(vector, writeIndex, !Tag, 1); + LOGPC(DLCSN1, LOGL_DEBUG, "%s = %u | ", pDescr->sz , (unsigned)(!Tag)); + bit_offset++; + + pDescr++; + break; + } + + case CSN_RECURSIVE_TARRAY_2: + { /* Recursive way to specify an array of type: ::= { 0 } ** 1 ; */ + + Tag = REVERSED_TAG; + + /* NO break - + * handling is exactly the same as for CSN_RECURSIVE_TARRAY_1 so we continue + */ + } + /* FALL THROUGH */ + case CSN_RECURSIVE_TARRAY_1: + { /* Recursive way to specify an array of type: ::= { 1 } ** 0 ; + * M_REC_TARRAY(_STRUCT, _MEMBER, _MEMBER_TYPE, _ElementCountField) + * {t, offsetof(_STRUCT, _ElementCountField), (void*)CSNDESCR_##_MEMBER_TYPE, offsetof(_STRUCT, _MEMBER), #_MEMBER, (StreamSerializeFcn_t)sizeof(_MEMBER_TYPE)} + */ + gint16 nSizeElement = (gint16)(gint32)pDescr->value; + guint8 ElementCount = 0; + guint8 ElementNum = 0; + csnStream_t arT = *ar; + gint16 Status; + + pui8 = pui8DATA(data, pDescr->offset); + /* Store the count of the array */ + ElementCount = *pui8DATA(data, pDescr->i); + ElementNum = ElementCount; + + while (ElementCount > 0) + { /* get data element */ + if (ElementCount != ElementNum) + { + bitvec_write_field(vector, writeIndex, Tag, 1); + LOGPC(DLCSN1, LOGL_DEBUG, "%s = %u | ", pDescr->sz , (unsigned)Tag); + bit_offset++; + remaining_bits_len--; + } + ElementCount--; + LOGPC(DLCSN1, LOGL_DEBUG, "%s { | ", pDescr->sz); + csnStreamInit(&arT, bit_offset, remaining_bits_len); + Status = csnStreamEncoder(&arT, (const CSN_DESCR*)pDescr->descr.ptr, vector, writeIndex, pui8); + LOGPC(DLCSN1, LOGL_DEBUG, "%s } | ", pDescr->sz); + if (Status >= 0) + { /* successful completion */ + pui8 += nSizeElement; /* -> to next */ + remaining_bits_len = arT.remaining_bits_len; + bit_offset = arT.bit_offset; + } + else + { /* something went awry */ + return Status; + } + + if (remaining_bits_len < 0) + { + return ProcessError(writeIndex,"csnStreamEncoder", CSN_ERROR_NEED_MORE_BITS_TO_UNPACK, pDescr); + } + + } + bitvec_write_field(vector, writeIndex, !Tag, 1); + bit_offset++; + remaining_bits_len--; + Tag = STANDARD_TAG; /* in case it was set to "reversed" */ + pDescr++; + break; + } + + case CSN_FIXED: + { /* Verify the fixed bits */ + guint8 no_of_bits = (guint8) pDescr->i; + bitvec_write_field(vector, writeIndex, pDescr->offset, no_of_bits); + LOGPC(DLCSN1, LOGL_DEBUG, "%s = %u | ", pDescr->sz , (unsigned)pDescr->offset); + remaining_bits_len -= no_of_bits; + bit_offset += no_of_bits; + pDescr++; + break; + } + + case CSN_CALLBACK: + { + guint16 no_of_bits; + DissectorCallbackFcn_t callback = (DissectorCallbackFcn_t)pDescr->aux_fn; + LOGPC(DLCSN1, LOGL_DEBUG, "CSN_CALLBACK(%s) | ", pDescr->sz); + no_of_bits = callback(vector, writeIndex, pvDATA(data, pDescr->i), pvDATA(data, pDescr->offset)); + remaining_bits_len -= no_of_bits; + bit_offset += no_of_bits; + pDescr++; + break; + } + + case CSN_TRAP_ERROR: + { + return ProcessError(writeIndex,"csnStreamEncoder", pDescr->i, pDescr); + } + + case CSN_END: + { + ar->remaining_bits_len = remaining_bits_len; + ar->bit_offset = bit_offset; + return remaining_bits_len; + } + + default: + { + assert(0); + } + + } + + } while (remaining_bits_len >= 0); + + return ProcessError(writeIndex,"csnStreamEncoder", CSN_ERROR_NEED_MORE_BITS_TO_UNPACK, pDescr); +}