diff options
Diffstat (limited to 'epan/dissectors/packet-csn1.c')
-rw-r--r-- | epan/dissectors/packet-csn1.c | 1627 |
1 files changed, 1627 insertions, 0 deletions
diff --git a/epan/dissectors/packet-csn1.c b/epan/dissectors/packet-csn1.c new file mode 100644 index 00000000..15b4a718 --- /dev/null +++ b/epan/dissectors/packet-csn1.c @@ -0,0 +1,1627 @@ +/* packet-csn1.c + * Routines 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 + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 1998 Gerald Combs + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "config.h" + +#include <epan/packet.h> +#include <epan/to_str.h> +#include "packet-csn1.h" + +void proto_register_csn1(void); + +static int hf_null_data = -1; + +static expert_field ei_csn1_more_bits_to_unpack = EI_INIT; +static expert_field ei_csn1_general = EI_INIT; +static expert_field ei_csn1_not_implemented = EI_INIT; +static expert_field ei_csn1_union_index = EI_INIT; +static expert_field ei_csn1_script_error = EI_INIT; +static expert_field ei_csn1_more32bits = EI_INIT; +static expert_field ei_csn1_fixed_not_matched = EI_INIT; +static expert_field ei_csn1_stream_not_supported = EI_INIT; + +#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)) + +/* used to tag existence of next element in variable length lists */ +#define STANDARD_TAG 1 +#define REVERSED_TAG 0 + +static const unsigned char ixBitsTab[] = {0, 1, 1, 2, 2, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5}; + +static gint proto_csn1 = -1; + +/* Returns no_of_bits (up to 8) masked with 0x2B */ +static guint8 +tvb_get_masked_bits8(tvbuff_t *tvb, 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; + + if (bit_shift >= 0) + { + result = (0x2B ^ tvb_get_guint8(tvb, byte_offset)) >> bit_shift; + result &= maskBits[no_of_bits]; + } + else + { + guint8 hight_part = (0x2B ^ tvb_get_guint8(tvb, byte_offset)) & maskBits[8 - relative_bit_offset]; + hight_part = (guint8) (hight_part << (-bit_shift)); + result = (0x2B ^ tvb_get_guint8(tvb, byte_offset+1)) >> (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, packet_info* pinfo) +{ + ar->remaining_bits_len = remaining_bits_len; + ar->bit_offset = bit_offset; + ar->pinfo = pinfo; +} + +static gint16 +ProcessError(proto_tree *tree, packet_info* pinfo, tvbuff_t *tvb, gint bit_offset, gint16 err, expert_field* err_field, const CSN_DESCR* pDescr) +{ + if (err_field != NULL) + proto_tree_add_expert_format(tree, pinfo, err_field, tvb, bit_offset>>3, 1, "%s (%s)", expert_get_summary(err_field), pDescr?pDescr->sz:"-"); + + return err; +} + +#if 0 +static const char* CSN_DESCR_type[]= +{ + "CSN_END", + "CSN_BIT", + "CSN_UINT", + "CSN_TYPE", + "CSN_CHOICE", + "CSN_UNION", + "CSN_UNION_LH", + "CSN_UINT_ARRAY", + "CSN_TYPE_ARRAY", + "CSN_BITMAP", + "CSN_VARIABLE_BITMAP", + "CSN_VARIABLE_BITMAP_1", + "CSN_LEFT_ALIGNED_VAR_BMP", + "CSN_LEFT_ALIGNED_VAR_BMP_1", + "CSN_VARIABLE_ARRAY", + "CSN_VARIABLE_TARRAY", + "CSN_VARIABLE_TARRAY_OFFSET", + "CSN_RECURSIVE_ARRAY", + "CSN_RECURSIVE_TARRAY", + "CSN_RECURSIVE_TARRAY_1", + "CSN_RECURSIVE_TARRAY_2", + "CSN_EXIST", + "CSN_EXIST_LH", + "CSN_NEXT_EXIST", + "CSN_NEXT_EXIST_LH", + "CSN_NULL", + "CSN_FIXED", + "CSN_CALLBACK", + "CSN_UINT_OFFSET", + "CSN_UINT_LH", + "CSN_SERIALIZE", + "CSN_TRAP_ERROR" + "CSN_???" +}; +#endif + +/** + * ================================================================================================ + * 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(tvbuff_t *tvb, gint bit_offset, guint8 Tag) +{ + guint8 res = tvb_get_bits8(tvb, bit_offset, 1); + if (Tag == STANDARD_TAG) + { + return (res > 0); + } + return (res == 0); +} + + +gint16 +csnStreamDissector(proto_tree *tree, csnStream_t* ar, const CSN_DESCR* pDescr, tvbuff_t *tvb, void* data, int ett_csn1) +{ + gint remaining_bits_len = ar->remaining_bits_len; + gint bit_offset = ar->bit_offset; + guint8* pui8 = NULL; + guint16* pui16; + guint32* pui32; + guint8 Tag = STANDARD_TAG; + + /* Negative number definitely indicates an error */ + if (remaining_bits_len < 0) + { + return ProcessError(tree, ar->pinfo, tvb, bit_offset, CSN_ERROR_NEED_MORE_BITS_TO_UNPACK, &ei_csn1_more_bits_to_unpack, pDescr); + } + + do + { + switch (pDescr->type) + { + case CSN_BIT: + { + if (remaining_bits_len > 0) + { + pui8 = pui8DATA(data, pDescr->offset); + + *pui8 = tvb_get_bits8(tvb, bit_offset, 1); + proto_tree_add_bits_item(tree, *(pDescr->hf_ptr), tvb, bit_offset, 1, ENC_BIG_ENDIAN); + + /* end add the bit value to protocol tree */ + } + else if(pDescr->may_be_null) + { + pui8 = pui8DATA(data, pDescr->offset); + *pui8 = 0; + proto_tree_add_none_format(tree, hf_null_data, tvb, 0, 0, "[NULL data]: %s Not Present", proto_registrar_get_name(*(pDescr->hf_ptr))); + } + else + { + return ProcessError(tree, ar->pinfo, tvb, bit_offset, CSN_ERROR_NEED_MORE_BITS_TO_UNPACK, &ei_csn1_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 = tvb_get_bits8(tvb, bit_offset, no_of_bits); + pui8 = pui8DATA(data, pDescr->offset); + *pui8 = ui8; + proto_tree_add_bits_item(tree, *(pDescr->hf_ptr), tvb, bit_offset, no_of_bits, ENC_BIG_ENDIAN); + } + else if (no_of_bits <= 16) + { + guint16 ui16 = tvb_get_bits16(tvb, bit_offset, no_of_bits, ENC_BIG_ENDIAN); + pui16 = pui16DATA(data, pDescr->offset); + memcpy(pui16, &ui16, 2); + proto_tree_add_bits_item(tree, *(pDescr->hf_ptr), tvb, bit_offset, no_of_bits, ENC_BIG_ENDIAN); + } + else if (no_of_bits <= 32) + { + guint32 ui32 = tvb_get_bits32(tvb, bit_offset, no_of_bits, ENC_BIG_ENDIAN); + pui32 = pui32DATA(data, pDescr->offset); + memcpy(pui32, &ui32, 4); + proto_tree_add_bits_item(tree, *(pDescr->hf_ptr), tvb, bit_offset, no_of_bits, ENC_BIG_ENDIAN); + } + else + { + return ProcessError(tree, ar->pinfo, tvb, bit_offset, CSN_ERROR_GENERAL, &ei_csn1_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); + memset(pui16, 0, 2); + } + else if (no_of_bits <= 32) + { + pui32 = pui32DATA(data, pDescr->offset); + memset(pui32, 0, 4); + } + proto_tree_add_none_format(tree, hf_null_data, tvb, 0, 0, "[NULL data]: %s Not Present", proto_registrar_get_name(*(pDescr->hf_ptr))); + } + else + { + return ProcessError(tree, ar->pinfo, tvb, bit_offset, CSN_ERROR_NEED_MORE_BITS_TO_UNPACK, &ei_csn1_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 = tvb_get_bits8(tvb, bit_offset, no_of_bits); + pui8 = pui8DATA(data, pDescr->offset); + *pui8 = ui8 + (guint8)pDescr->descr.value; + + proto_tree_add_uint_bits_format_value(tree, *(pDescr->hf_ptr), tvb, bit_offset, no_of_bits, + *pui8, ENC_BIG_ENDIAN, "%u (Raw %u + Offset %u)", *pui8, ui8, + (guint8) pDescr->descr.value); + } + else if (no_of_bits <= 16) + { + guint16 ui16 = tvb_get_bits16(tvb, bit_offset, no_of_bits, ENC_BIG_ENDIAN) + (guint16)pDescr->descr.value; + pui16 = pui16DATA(data, pDescr->offset); + memcpy(pui16, &ui16, 2); + + proto_tree_add_uint_bits_format_value(tree, *(pDescr->hf_ptr), tvb, bit_offset, no_of_bits, + *pui16, ENC_BIG_ENDIAN, "%u (Raw %u + Offset %u)", *pui16, ui16, + (guint16) pDescr->descr.value); + } + else if (no_of_bits <= 32) + { + guint32 ui32 = tvb_get_bits32(tvb, bit_offset, no_of_bits, ENC_BIG_ENDIAN) + (guint16)pDescr->descr.value; + pui32 = pui32DATA(data, pDescr->offset); + memcpy(pui32, &ui32, 4); + + proto_tree_add_uint_bits_format_value(tree, *(pDescr->hf_ptr), tvb, bit_offset, no_of_bits, + *pui32, ENC_BIG_ENDIAN, "%u (Raw %u + Offset %u)", *pui32, ui32, + (guint16) pDescr->descr.value); + } + else + { + return ProcessError(tree, ar->pinfo, tvb, bit_offset, CSN_ERROR_GENERAL, &ei_csn1_general, pDescr); + } + } + else + { + return ProcessError(tree, ar->pinfo, tvb, bit_offset, CSN_ERROR_NEED_MORE_BITS_TO_UNPACK, &ei_csn1_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 = tvb_get_masked_bits8(tvb, bit_offset, no_of_bits); + pui8 = pui8DATA(data, pDescr->offset); + *pui8 = ui8; + proto_tree_add_bits_item(tree, *(pDescr->hf_ptr), tvb, bit_offset, no_of_bits, ENC_BIG_ENDIAN); + + } + else + {/* Maybe we should support more than 8 bits ? */ + return ProcessError(tree, ar->pinfo, tvb, bit_offset, CSN_ERROR_GENERAL, &ei_csn1_general, pDescr); + } + } + else + { + return ProcessError(tree, ar->pinfo, tvb, bit_offset, CSN_ERROR_NEED_MORE_BITS_TO_UNPACK, &ei_csn1_more_bits_to_unpack, pDescr); + } + + remaining_bits_len -= no_of_bits; + bit_offset += no_of_bits; + pDescr++; + break; + } + + case CSN_SPLIT_BITS: + { + guint8 no_of_value_bits = (guint8) pDescr->i; + guint64 value; + + proto_tree_add_split_bits_item_ret_val(tree, *pDescr->hf_ptr, tvb, bit_offset, pDescr->descr.crumb_spec, &value); + if (no_of_value_bits <= 8) + { + pui8 = pui8DATA(data, pDescr->offset); + *pui8 = (guint8)value; + } + else if (no_of_value_bits <= 16) + { + guint16 ui16 = (guint16) value; + pui16 = pui16DATA(data, pDescr->offset); + memcpy(pui16, &ui16, 2); + } + else if (no_of_value_bits <= 32) + { + guint32 ui32 = (guint32) value; + pui32 = pui32DATA(data, pDescr->offset); + memcpy(pui32, &ui32, 4); + } + else + { + return ProcessError(tree, ar->pinfo, tvb, bit_offset, CSN_ERROR_GENERAL, &ei_csn1_general, pDescr); + } + + pDescr++; + break; + } + + case CSN_SPLIT_BITS_CRUMB: + { + if (remaining_bits_len >= pDescr->descr.crumb_spec[pDescr->i].crumb_bit_length) + { + proto_tree_add_split_bits_crumb(tree, *pDescr->hf_ptr, tvb, bit_offset, + pDescr->descr.crumb_spec, pDescr->i); + + remaining_bits_len -= pDescr->descr.crumb_spec[pDescr->i].crumb_bit_length; + bit_offset += pDescr->descr.crumb_spec[pDescr->i].crumb_bit_length; + } + else + { + return ProcessError(tree, ar->pinfo, tvb, bit_offset, CSN_ERROR_NEED_MORE_BITS_TO_UNPACK, &ei_csn1_more_bits_to_unpack, pDescr); + } + + 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(...) */ + int i = 0; + + if (pDescr->value != 0) + { /* nCount specified by a reference to field holding value i.e. M_VAR_UINT_ARRAY(...) */ + memcpy(&nCount, pui16DATA(data, nCount), 2); + } + + 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++ = tvb_get_bits8(tvb, bit_offset, no_of_bits); + proto_tree_add_uint_bits_format_value(tree, *(pDescr->hf_ptr), tvb, bit_offset, no_of_bits, *pui8, ENC_BIG_ENDIAN, " (Count %d)", i++); + bit_offset += no_of_bits; + } while (--nCount > 0); + } + else if (no_of_bits <= 16) + { + return ProcessError(tree, ar->pinfo, tvb, bit_offset, 999, &ei_csn1_not_implemented, pDescr); + } + else if (no_of_bits <= 32) + { + return ProcessError(tree, ar->pinfo, tvb, bit_offset, 999, &ei_csn1_not_implemented, pDescr); + } + else + { + return ProcessError(tree, ar->pinfo, tvb, bit_offset, CSN_ERROR_GENERAL, &ei_csn1_general, pDescr); + } + } + else + { + return ProcessError(tree, ar->pinfo, tvb, bit_offset, CSN_ERROR_NEED_MORE_BITS_TO_UNPACK, &ei_csn1_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; + int i =0; + + 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 + */ + proto_item *ti; + proto_tree *test_tree; + + test_tree = proto_tree_add_subtree_format(tree, tvb, bit_offset>>3, 1, ett_csn1, &ti, "%s[%d]",pDescr->sz, i++); + + csnStreamInit(&arT, bit_offset, remaining_bits_len, ar->pinfo); + Status = csnStreamDissector(test_tree, &arT, (const CSN_DESCR*)pDescr->descr.ptr, tvb, pui8, ett_csn1); + if (Status >= 0) + { + pui8 += nSize; + proto_item_set_len(ti,((arT.bit_offset-1)>>3) - (bit_offset>>3)+1); + 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(tree, ar->pinfo, tvb, bit_offset, CSN_ERROR_NEED_MORE_BITS_TO_UNPACK, &ei_csn1_more_bits_to_unpack, pDescr); + } + + if (no_of_bits <= 32) + { + proto_tree_add_bits_item(tree, *(pDescr->hf_ptr), tvb, bit_offset, no_of_bits, ENC_BIG_ENDIAN); + } + else if (no_of_bits <= 64) + { + proto_tree_add_bits_item(tree, *(pDescr->hf_ptr), tvb, bit_offset, no_of_bits, ENC_BIG_ENDIAN); + } + else + { + return ProcessError(tree, ar->pinfo, tvb, bit_offset, 999, &ei_csn1_not_implemented, 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; + proto_item *ti; + proto_tree *test_tree; + if (pDescr->may_be_null && remaining_bits_len == 0) + { + proto_tree_add_none_format(tree, hf_null_data, tvb, 0, 0, "[NULL data]: %s Not Present", pDescr->sz); + } else { + test_tree = proto_tree_add_subtree_format(tree, tvb, bit_offset>>3, 1, ett_csn1, &ti, "%s", pDescr->sz); + csnStreamInit(&arT, bit_offset, remaining_bits_len, ar->pinfo); + Status = csnStreamDissector(test_tree, &arT, (const CSN_DESCR*)pDescr->descr.ptr, tvb, pvDATA(data, pDescr->offset), ett_csn1); + if (Status >= 0) + { + proto_item_set_len(ti,((arT.bit_offset-1)>>3) - (bit_offset>>3)+1); + remaining_bits_len = arT.remaining_bits_len; + bit_offset = arT.bit_offset; + } + else + { + /* Has already been processed: ProcessError("csnStreamDissector", Status, pDescr); */ + return Status; + } + } + pDescr++; + break; + } + + case CSN_CHOICE: + { + gint16 count = pDescr->i; + guint8 i = 0; + 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(tree, ar->pinfo, tvb, bit_offset, CSN_ERROR_IN_SCRIPT, &ei_csn1_script_error, pDescr); + + while (count > 0) + { + guint8 no_of_bits = pChoice->bits; + guint8 value = tvb_get_bits8(tvb, bit_offset, no_of_bits); + + if (value == pChoice->value) + { + CSN_DESCR descr[2]; + gint16 Status; + csnStream_t arT = *ar; + proto_item *ti = NULL; + proto_tree *test_tree; + + descr[0] = pChoice->descr; + memset(&descr[1], 0x00, sizeof(CSN_DESCR)); + descr[1].type = CSN_END; + pui8 = pui8DATA(data, pDescr->offset); + *pui8 = i; + + if (pDescr->sz) + { + proto_tree_add_bits_item(tree, *(pDescr->hf_ptr), tvb, bit_offset, no_of_bits, ENC_BIG_ENDIAN); + } + + if (!pChoice->keep_bits) + { + bit_offset += no_of_bits; + remaining_bits_len -= no_of_bits; + } + + if (pDescr->sz) + { + test_tree = proto_tree_add_subtree(tree, tvb, bit_offset>>3, 1, ett_csn1, &ti, pDescr->sz); + } else { + test_tree = tree; + } + + csnStreamInit(&arT, bit_offset, remaining_bits_len, ar->pinfo); + Status = csnStreamDissector(test_tree, &arT, (const CSN_DESCR*)descr, tvb, data, ett_csn1); + + if (Status >= 0) + { + if (ti) + proto_item_set_len(ti,((arT.bit_offset-1)>>3) - (bit_offset>>3)+1); + remaining_bits_len = arT.remaining_bits_len; + bit_offset = arT.bit_offset; + } + else + { + return Status; + } + break; + } + + count--; + pChoice++; + i++; + } + + /* Neither of the choice items matched => unknown value */ + if (!count) { + return ProcessError(tree, ar->pinfo, tvb, bit_offset, + CSN_ERROR_STREAM_NOT_SUPPORTED, + &ei_csn1_stream_not_supported, pDescr); + } + + pDescr++; + break; + } + + case CSN_SERIALIZE: + { + StreamSerializeFcn_t serialize = (StreamSerializeFcn_t)pDescr->aux_fn; + csnStream_t arT = *ar; + guint length_len = pDescr->i; + gint16 Status = -1; + proto_item *ti; + proto_tree *test_tree; + guint8 length = 0; + + if (length_len) + { + length = tvb_get_bits8(tvb, bit_offset, length_len); + + proto_tree_add_bits_item(tree, *(pDescr->hf_ptr), tvb, bit_offset, length_len, ENC_BIG_ENDIAN); + + bit_offset += length_len; + remaining_bits_len -= length_len; + + test_tree = proto_tree_add_subtree(tree, tvb, bit_offset>>3, ((bit_offset+length-1)>>3)-(bit_offset>>3) + 1, ett_csn1, &ti, pDescr->sz); + } else { + test_tree = proto_tree_add_subtree(tree, tvb, bit_offset>>3, 1, ett_csn1, &ti, pDescr->sz); + } + + csnStreamInit(&arT, bit_offset, length > 0 ? length : remaining_bits_len, ar->pinfo); + Status = serialize(test_tree, &arT, tvb, pvDATA(data, pDescr->offset), ett_csn1); + + if (Status >= 0) + { + if (length > 0) { + remaining_bits_len -= length; + bit_offset += length; + } else { + proto_item_set_len(ti,((arT.bit_offset - bit_offset)>>3)+1); + 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 t_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(tree, ar->pinfo, tvb, bit_offset, CSN_ERROR_INVALID_UNION_INDEX, &ei_csn1_union_index, pDescr); + } + + /* Now get the bits to extract the index */ + Bits = ixBitsTab[count]; + proto_tree_add_uint_bits_format_value(tree, *(pDescr->hf_ptr), tvb, bit_offset, Bits, tvb_get_bits8(tvb, bit_offset, Bits), ENC_BIG_ENDIAN, " (Union)"); + t_index = 0; + + while (Bits > 0) + { + t_index <<= 1; + + if (CSN_UNION_LH == pDescr->type) + { + t_index |= tvb_get_masked_bits8(tvb, bit_offset, 1); + } + else + { + t_index |= tvb_get_bits8(tvb, bit_offset, 1); + } + + remaining_bits_len--; + bit_offset++; + Bits--; + } + + /* Assign UnionType */ + pui8 = pui8DATA(data, pDescr->offset); + *pui8 = t_index; + + /* script index to continue on, limited in case we do not have a power of 2 */ + pDescr += (MIN(t_index + 1, count)); + + switch (pDescr->type) + { /* get the right element of the union based on computed index */ + + case CSN_BIT: + { + pui8 = pui8DATA(data, pDescr->offset); + + proto_tree_add_bits_item(tree, *(pDescr->hf_ptr), tvb, bit_offset, 1, ENC_BIG_ENDIAN); + + *pui8 = 0x00; + if (tvb_get_bits8(tvb, bit_offset, 1) > 0) + { + *pui8 = 0x01; + } + remaining_bits_len --; + 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 = tvb_get_bits8(tvb, bit_offset, no_of_bits); + pui8 = pui8DATA(data, pDescr->offset); + *pui8 = ui8; + proto_tree_add_bits_item(tree, *(pDescr->hf_ptr), tvb, bit_offset, no_of_bits, ENC_BIG_ENDIAN); + + } + else if (no_of_bits <= 16) + { + guint16 ui16 = tvb_get_bits16(tvb, bit_offset, no_of_bits, ENC_BIG_ENDIAN); + pui16 = pui16DATA(data, pDescr->offset); + memcpy(pui16, &ui16, 2); + proto_tree_add_bits_item(tree, *(pDescr->hf_ptr), tvb, bit_offset, no_of_bits, ENC_BIG_ENDIAN); + } + else if (no_of_bits <= 32) + { + guint32 ui32 = tvb_get_bits32(tvb, bit_offset, no_of_bits, ENC_BIG_ENDIAN); + pui32 = pui32DATA(data, pDescr->offset); + memcpy(pui32, &ui32, 4); + proto_tree_add_bits_item(tree, *(pDescr->hf_ptr), tvb, bit_offset, no_of_bits, ENC_BIG_ENDIAN); + + } + else + { + return ProcessError(tree, ar->pinfo, tvb, bit_offset, CSN_ERROR_GENERAL, &ei_csn1_general, pDescr); + } + } + else + { + return ProcessError(tree, ar->pinfo, tvb, bit_offset, CSN_ERROR_GENERAL, &ei_csn1_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 = tvb_get_bits8(tvb, bit_offset, no_of_bits); + pui8 = pui8DATA(data, pDescr->offset); + *pui8 = ui8 + (guint8)pDescr->descr.value; + proto_tree_add_uint_bits_format_value(tree, *(pDescr->hf_ptr), tvb, bit_offset, no_of_bits, ui8, ENC_BIG_ENDIAN, "%d", ui8); + } + else if (no_of_bits <= 16) + { + guint16 ui16 = tvb_get_bits16(tvb, bit_offset, no_of_bits, ENC_BIG_ENDIAN) + (guint16)pDescr->descr.value; + pui16 = pui16DATA(data, pDescr->offset); + memcpy(pui16, &ui16, 2); + proto_tree_add_uint_bits_format_value(tree, *(pDescr->hf_ptr), tvb, bit_offset, no_of_bits, ui16, ENC_BIG_ENDIAN, "%d", ui16); + } + else if (no_of_bits <= 32) + { + guint32 ui32 = tvb_get_bits32(tvb, bit_offset, no_of_bits, ENC_BIG_ENDIAN) + (guint16)pDescr->descr.value; + pui32 = pui32DATA(data, pDescr->offset); + memcpy(pui32, &ui32, 4); + proto_tree_add_uint_bits_format_value(tree, *(pDescr->hf_ptr), tvb, bit_offset, no_of_bits, ui32, ENC_BIG_ENDIAN, "%d", ui32); + } + else + { + return ProcessError(tree, ar->pinfo, tvb, bit_offset, CSN_ERROR_GENERAL, &ei_csn1_general, pDescr); + } + } + else + { + return ProcessError(tree, ar->pinfo, tvb, bit_offset, CSN_ERROR_NEED_MORE_BITS_TO_UNPACK, &ei_csn1_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 = tvb_get_masked_bits8(tvb, bit_offset, no_of_bits); + pui8 = pui8DATA(data, pDescr->offset); + *pui8 = ui8; + proto_tree_add_bits_item(tree, *(pDescr->hf_ptr), tvb, bit_offset, no_of_bits, ENC_BIG_ENDIAN); + } + else + { /* Maybe we should support more than 8 bits ? */ + ProcessError(tree, ar->pinfo, tvb, bit_offset, CSN_ERROR_GENERAL, &ei_csn1_general, pDescr); + } + } + else + { + return ProcessError(tree, ar->pinfo, tvb, bit_offset, CSN_ERROR_NEED_MORE_BITS_TO_UNPACK, &ei_csn1_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(...) */ + gint i = 0; + + if (pDescr->value != 0) + { /* nCount specified by a reference to field holding value i.e. M_VAR_UINT_ARRAY(...) */ + memcpy(&nCount, pui16DATA(data, nCount), 2); + } + + 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 = tvb_get_bits8(tvb, bit_offset, no_of_bits); + proto_tree_add_uint_bits_format_value(tree, *(pDescr->hf_ptr), tvb, bit_offset, no_of_bits, *pui8, ENC_BIG_ENDIAN, " (Count %d)", i++); + pui8++; + bit_offset += no_of_bits; + nCount--; + } + } + else if (no_of_bits <= 16) + { + pui16 = pui16DATA(data, pDescr->offset); + + while (nCount > 0) + { + guint16 ui16; + ui16 = tvb_get_bits16(tvb, bit_offset, no_of_bits, ENC_BIG_ENDIAN); + proto_tree_add_uint_bits_format_value(tree, *(pDescr->hf_ptr), tvb, bit_offset, no_of_bits, ui16, ENC_BIG_ENDIAN, " (Count %d)", i++); + memcpy(pui16++, &ui16, sizeof(ui16)); + bit_offset += no_of_bits; + nCount--; + } + } + else if (no_of_bits <= 32) + { /* not supported */ + return ProcessError(tree, ar->pinfo, tvb, bit_offset, 999, &ei_csn1_not_implemented, pDescr); + } + else + { + return ProcessError(tree, ar->pinfo, tvb, bit_offset, CSN_ERROR_GENERAL, &ei_csn1_general, pDescr); + } + } + else + { + return ProcessError(tree, ar->pinfo, tvb, bit_offset, CSN_ERROR_NEED_MORE_BITS_TO_UNPACK, &ei_csn1_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; + gint i = 0; + + 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. */ + { + proto_item *ti; + proto_tree *test_tree; + + test_tree = proto_tree_add_subtree_format(tree, tvb, bit_offset>>3, 1, ett_csn1, &ti, "%s[%d]",pDescr->sz, i++); + + csnStreamInit(&arT, bit_offset, remaining_bits_len, ar->pinfo); + Status = csnStreamDissector(test_tree, &arT, (const CSN_DESCR *)pDescr->descr.ptr, tvb, pui8, ett_csn1); + if (Status >= 0) + { + pui8 += nSize; + proto_item_set_len(ti,((arT.bit_offset-1)>>3) - (bit_offset>>3)+1); + 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) + { /* a non empty bitmap */ + proto_tree_add_bits_item(tree, *(pDescr->hf_ptr), tvb, bit_offset, no_of_bits, ENC_BIG_ENDIAN); + remaining_bits_len -= no_of_bits; + bit_offset += no_of_bits; + + if (remaining_bits_len < 0) + { + return ProcessError(tree, ar->pinfo, tvb, bit_offset, CSN_ERROR_NEED_MORE_BITS_TO_UNPACK, &ei_csn1_more_bits_to_unpack, pDescr); + } + + } + /* bitmap was successfully extracted or it was empty */ + + pDescr++; + break; + } + + case CSN_TYPE: + { + gint16 Status; + csnStream_t arT = *ar; + proto_item *ti; + proto_tree *test_tree; + + if (pDescr->may_be_null && remaining_bits_len == 0) + { + proto_tree_add_none_format(tree, hf_null_data, tvb, 0, 0, "[NULL data]: %s Not Present", pDescr->sz); + } else { + test_tree = proto_tree_add_subtree(tree, tvb, bit_offset>>3, 1, ett_csn1, &ti, pDescr->sz); + csnStreamInit(&arT, bit_offset, remaining_bits_len, ar->pinfo); + Status = csnStreamDissector(test_tree, &arT, (const CSN_DESCR *)pDescr->descr.ptr, tvb, pvDATA(data, pDescr->offset), ett_csn1); + if (Status >= 0) + { + proto_item_set_len(ti,((arT.bit_offset-1)>>3) - (bit_offset>>3)+1); + 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(tree, ar->pinfo, tvb, bit_offset, CSN_ERROR_IN_SCRIPT, &ei_csn1_script_error, 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 = tvb_get_masked_bits8(tvb, bit_offset, 1); + proto_tree_add_uint(tree, *(pDescr->hf_ptr), tvb, bit_offset>>3, 1, fExist); + } + else + { + fExist = tvb_get_bits8(tvb, bit_offset, 1); + proto_tree_add_bits_item(tree, *(pDescr->hf_ptr), tvb, bit_offset, 1, ENC_BIG_ENDIAN); + } + + *pui8 = fExist; + remaining_bits_len --; + bit_offset++; + pDescr++; + + if (!fExist) + { + ar->remaining_bits_len = remaining_bits_len; + ar->bit_offset = bit_offset; + return remaining_bits_len; + } + + break; + } + + case CSN_NEXT_EXIST: + { + 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 */ + proto_tree_add_bits_item(tree, *(pDescr->hf_ptr), tvb, bit_offset, 1, ENC_BIG_ENDIAN); + + isnull = 1; + if (tvb_get_bits8(tvb, 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; + } + } + + *pui8 = isnull ? 0 : 1; + + remaining_bits_len --; + bit_offset++; + + if (isnull) + { /* Skip 'i' entries */ + pDescr += pDescr->i; + } + + pDescr++; + break; + } + + case CSN_NEXT_EXIST_LH: + { + 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 */ + proto_tree_add_bits_item(tree, *(pDescr->hf_ptr), tvb, bit_offset, 1, ENC_BIG_ENDIAN); + + isnull = 1; + if (tvb_get_masked_bits8(tvb, 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; + } + } + + *pui8++ = isnull ? 0 : 1; + + remaining_bits_len --; + 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} + * <N: bit (5)> <bitmap: bit(N + offset)> + * 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 */ + + while (no_of_bits > 0) + { + proto_tree_add_bits_item(tree, *(pDescr->hf_ptr), tvb, bit_offset, 1, ENC_BIG_ENDIAN); + bit_offset++; + no_of_bits--; + remaining_bits_len--; + + if (remaining_bits_len < 0) + { + return ProcessError(tree, ar->pinfo, tvb, bit_offset, CSN_ERROR_NEED_MORE_BITS_TO_UNPACK, &ei_csn1_more_bits_to_unpack, pDescr); + } + } + 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} + * <N: bit (5)> <bitmap: bit(N + offset)> + * 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) + { + if (no_of_bits <= 32) + { + proto_tree_add_bits_item(tree, *(pDescr->hf_ptr), tvb, bit_offset, no_of_bits, ENC_BIG_ENDIAN); + } + else if (no_of_bits <= 64) + { + proto_tree_add_bits_item(tree, *(pDescr->hf_ptr), tvb, bit_offset, no_of_bits, ENC_BIG_ENDIAN); + } + else + { + proto_tree_add_uint64_format_value(tree, *(pDescr->hf_ptr), tvb, bit_offset>>3, ((bit_offset+no_of_bits-1)>>3)-(bit_offset>>3)+1, no_of_bits, "%u bits", + no_of_bits); + } + bit_offset += no_of_bits; + remaining_bits_len -= no_of_bits; + + if (remaining_bits_len < 0) + { + return ProcessError(tree, ar->pinfo, tvb, bit_offset, CSN_ERROR_NEED_MORE_BITS_TO_UNPACK, &ei_csn1_more_bits_to_unpack, pDescr); + } + } + + /* bitmap was successfully extracted or it was empty */ + pDescr++; + break; + } + + + case CSN_PADDING_BITS: + { /* Padding from here and to the end of message */ + + if (remaining_bits_len > 0) + { + proto_tree *padding_tree = proto_tree_add_subtree(tree, tvb, bit_offset>>3, -1, ett_csn1, NULL, "Padding Bits"); + while (remaining_bits_len > 0) + { + gint bits_to_handle = remaining_bits_len + (bit_offset%8); + if (bits_to_handle > 32) + { + bits_to_handle = 32 - (bit_offset%8); + } + else + { + bits_to_handle -= (bit_offset%8); + } + proto_tree_add_bits_item(padding_tree, *(pDescr->hf_ptr), tvb, bit_offset, bits_to_handle, ENC_BIG_ENDIAN); + bit_offset += bits_to_handle; + remaining_bits_len -= bits_to_handle; + } + } + if (remaining_bits_len < 0) + { + return ProcessError(tree, ar->pinfo, tvb, bit_offset, CSN_ERROR_NEED_MORE_BITS_TO_UNPACK, &ei_csn1_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: + * <count: bit (x)> + * <list: octet(count + offset)> + */ + gint16 count = *pui8DATA(data, (gint16)pDescr->descr.value); + + count += pDescr->i; /* Adjusted by offset */ + + if (count > 0) + { + pui8 = pui8DATA(data, pDescr->offset); + + while (count > 0) + { + proto_tree_add_bits_item(tree, *(pDescr->hf_ptr), tvb, bit_offset, 8, ENC_BIG_ENDIAN); + *pui8++ = tvb_get_bits8(tvb, bit_offset, 8); + bit_offset += 8; + count--; + remaining_bits_len -= 8; + if (remaining_bits_len < 0) + { + return ProcessError(tree, ar->pinfo, tvb, bit_offset, CSN_ERROR_NEED_MORE_BITS_TO_UNPACK, &ei_csn1_more_bits_to_unpack, pDescr); + } + } + } + + pDescr++; + break; + } + + case CSN_RECURSIVE_ARRAY: + { /* Recursive way to specify an array: <list> ::= {1 <number: bit (4)> <list> | 0} + * or more generally: <list> ::= { <tag> <element> <list> | <EndTag> } + * where <element> ::= bit(value) + * <tag> ::= 0 | 1 + * <EndTag> ::= 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(tvb, bit_offset, Tag)) + { /* tag control shows existence of next list elements */ + proto_tree_add_bits_item(tree, *(pDescr->hf_exist_ptr), tvb, bit_offset, 1, ENC_BIG_ENDIAN); + bit_offset++; + remaining_bits_len--; + + /* extract and store no_of_bits long element from bitstream */ + *pui8++ = tvb_get_bits8(tvb, bit_offset, no_of_bits); + ElementCount++; + + if (remaining_bits_len < 0) + { + return ProcessError(tree, ar->pinfo, tvb, bit_offset, CSN_ERROR_NEED_MORE_BITS_TO_UNPACK, &ei_csn1_more_bits_to_unpack, pDescr); + } + + proto_tree_add_bits_item(tree, *(pDescr->hf_ptr), tvb, bit_offset, no_of_bits, ENC_BIG_ENDIAN); + bit_offset += no_of_bits; + remaining_bits_len -= no_of_bits; + } + + proto_tree_add_bits_item(tree, *(pDescr->hf_exist_ptr), tvb, bit_offset, 1, ENC_BIG_ENDIAN); + + /* 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: <lists> ::= { 1 <type> } ** 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), NULL, NULL, (void_fn_t)ElementsOf(((_STRUCT*)0)->_MEMBER)} + */ + gint16 nSizeElement = (gint16)(gint32)pDescr->value; + guint32 nSizeArray = (guint32)((guintptr)pDescr->aux_fn); + guint8 ElementCount = 0; + + while (existNextElement(tvb, bit_offset, Tag)) + { /* tag control shows existence of next list elements */ + proto_tree_add_bits_item(tree, *(pDescr->hf_ptr), tvb, bit_offset, 1, ENC_BIG_ENDIAN); + + /* existNextElement() returned TRUE, 1 bit consumed */ + bit_offset++; + remaining_bits_len--; + ElementCount++; + + if (ElementCount > nSizeArray) + { + /* error: too many elements in recursive array. Increase its size! */ + return ProcessError(tree , ar->pinfo, tvb, bit_offset, CSN_ERROR_STREAM_NOT_SUPPORTED, &ei_csn1_stream_not_supported, pDescr); + } + + { /* unpack the following data structure */ + csnStream_t arT = *ar; + gint16 Status; + proto_item *ti; + proto_tree *test_tree; + + test_tree = proto_tree_add_subtree(tree, tvb, bit_offset>>3, 1, ett_csn1, &ti, pDescr->sz); + + csnStreamInit(&arT, bit_offset, remaining_bits_len, ar->pinfo); + Status = csnStreamDissector(test_tree, &arT, (const CSN_DESCR *)pDescr->descr.ptr, tvb, pvDATA(data, pDescr->offset), ett_csn1); + + if (Status >= 0) + { /* successful completion */ + pui8 += nSizeElement; /* -> to next data element */ + proto_item_set_len(ti,((arT.bit_offset-1)>>3) - (bit_offset>>3)+1); + 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(tree, ar->pinfo, tvb, bit_offset, CSN_ERROR_NEED_MORE_BITS_TO_UNPACK, &ei_csn1_more_bits_to_unpack, pDescr); + } + } + + /* existNextElement() returned FALSE, 1 bit consumed */ + bit_offset++; + remaining_bits_len --; + + /* 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: <list> ::= <type> { 0 <type> } ** 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: <lists> ::= <type> { 1 <type> } ** 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), NULL, NULL, (void_fn_t)ElementsOf(((_STRUCT*)0)->_MEMBER)} + */ + gint16 nSizeElement = (gint16)(gint32)pDescr->value; + guint32 nSizeArray = (guint32)((guintptr)pDescr->aux_fn); + guint8 ElementCount = 0; + csnStream_t arT = *ar; + gboolean EndOfList = FALSE; + gint16 Status; + proto_item *ti; + proto_tree *test_tree; + + do + { /* get data element */ + ElementCount++; + + if (ElementCount >= nSizeArray) + { + /* error: too many elements in recursive array. Increase its size! */ + return ProcessError(tree , ar->pinfo, tvb, bit_offset, CSN_ERROR_STREAM_NOT_SUPPORTED, &ei_csn1_stream_not_supported, pDescr); + } + + test_tree = proto_tree_add_subtree_format(tree, tvb, bit_offset>>3, 1, ett_csn1, &ti, "%s[%d]", pDescr->sz, ElementCount-1); + + csnStreamInit(&arT, bit_offset, remaining_bits_len, ar->pinfo); + Status = csnStreamDissector(test_tree, &arT, (const CSN_DESCR *)pDescr->descr.ptr, tvb, pvDATA(data, pDescr->offset), ett_csn1); + + if (Status >= 0) + { /* successful completion */ + pui8 += nSizeElement; /* -> to next */ + proto_item_set_len(ti,((arT.bit_offset-1)>>3) - (bit_offset>>3)+1); + 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(tree, ar->pinfo, tvb, bit_offset, CSN_ERROR_NEED_MORE_BITS_TO_UNPACK, &ei_csn1_more_bits_to_unpack, pDescr); + } + + /* control of next element's tag */ + proto_tree_add_uint_bits_format_value(tree, *(pDescr->hf_ptr), tvb, bit_offset, 1, tvb_get_bits8(tvb, bit_offset, 1), ENC_BIG_ENDIAN, "%s[%d]", + proto_registrar_get_name(*(pDescr->hf_ptr)), ElementCount); + EndOfList = !(existNextElement(tvb, bit_offset, 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 <= 8) + { + ui32 = tvb_get_bits8(tvb, bit_offset, no_of_bits); + } + else if (no_of_bits <= 16) + { + ui32 = tvb_get_bits16(tvb, bit_offset, no_of_bits, ENC_BIG_ENDIAN); + } + else if (no_of_bits <= 32) + { + ui32 = tvb_get_bits32(tvb, bit_offset, no_of_bits, ENC_BIG_ENDIAN); + } + else + { + return ProcessError(tree, ar->pinfo, tvb, bit_offset, -1, &ei_csn1_more32bits, pDescr); + } + if (ui32 != (unsigned)(gint32)pDescr->offset) + { + return ProcessError(tree, ar->pinfo, tvb, bit_offset, -1, &ei_csn1_fixed_not_matched, pDescr); + } + proto_tree_add_bits_item(tree, *(pDescr->hf_ptr), tvb, bit_offset, no_of_bits, ENC_BIG_ENDIAN); + + 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; + + no_of_bits = callback(tree, tvb, pvDATA(data, pDescr->i), pvDATA(data, pDescr->offset), bit_offset, ett_csn1, ar->pinfo); + bit_offset += no_of_bits; + remaining_bits_len -= no_of_bits; + + pDescr++; + break; + } + + case CSN_TRAP_ERROR: + { + return ProcessError(tree, ar->pinfo, tvb, bit_offset, -1, pDescr->error, pDescr); + } + + case CSN_END: + { + ar->remaining_bits_len = remaining_bits_len; + ar->bit_offset = bit_offset; + return remaining_bits_len; + } + + default: + { + DISSECTOR_ASSERT(0); + } + + } + + } while (remaining_bits_len >= 0); + + return ProcessError(tree, ar->pinfo, tvb, bit_offset, CSN_ERROR_NEED_MORE_BITS_TO_UNPACK, &ei_csn1_more_bits_to_unpack, pDescr); +} + +void +proto_register_csn1(void) +{ + static hf_register_info hf[] = { + { &hf_null_data, + { "NULL data", "csn1.null_data", + FT_NONE, BASE_NONE, NULL, 0x00, + NULL, HFILL } + }, + }; + + static ei_register_info ei[] = { + { &ei_csn1_more_bits_to_unpack, { "csn1.more_bits_to_unpack", PI_MALFORMED, PI_ERROR, "NEED_MORE BITS TO UNPACK", EXPFILL }}, + { &ei_csn1_general, { "csn1.general_error", PI_PROTOCOL, PI_WARN, "General -1", EXPFILL }}, + { &ei_csn1_not_implemented, { "csn1.not_implemented", PI_UNDECODED, PI_WARN, "NOT IMPLEMENTED", EXPFILL }}, + { &ei_csn1_union_index, { "csn1.union_index_invalid", PI_PROTOCOL, PI_WARN, "INVALID UNION INDEX", EXPFILL }}, + { &ei_csn1_script_error, { "csn1.script_error", PI_MALFORMED, PI_ERROR, "ERROR IN SCRIPT", EXPFILL }}, + { &ei_csn1_more32bits, { "csn1.more32bits", PI_PROTOCOL, PI_WARN, "no_of_bits > 32", EXPFILL }}, + { &ei_csn1_fixed_not_matched, { "csn1.fixed_not_matched", PI_PROTOCOL, PI_WARN, "FIXED value does not match", EXPFILL }}, + { &ei_csn1_stream_not_supported, { "csn1.stream_not_supported", PI_PROTOCOL, PI_WARN, "STREAM NOT SUPPORTED", EXPFILL }}, + }; + + expert_module_t* expert_csn1; + + proto_csn1 = proto_register_protocol("CSN.1", "CSN1", "csn1"); + + proto_register_field_array(proto_csn1, hf, array_length(hf)); + expert_csn1 = expert_register_protocol(proto_csn1); + expert_register_field_array(expert_csn1, ei, array_length(ei)); + + proto_set_cant_toggle(proto_csn1); +} + +/* + * Editor modelines - https://www.wireshark.org/tools/modelines.html + * + * Local Variables: + * c-basic-offset: 2 + * tab-width: 8 + * indent-tabs-mode: nil + * End: + * + * ex: set shiftwidth=2 tabstop=8 expandtab: + * :indentSize=2:tabSize=8:noTabs=true: + */ |