From 817b04f8c538671bfdbad6f7da2c1a99109d4849 Mon Sep 17 00:00:00 2001 From: Joseph Hickey Date: Wed, 20 Sep 2023 12:07:25 -0400 Subject: [PATCH] Fix #245, implement safer codec loops Implement the encoding and decoding of CBOR containers as a loop. This permits the "error" flag to be easily polled after each iteration, and if it is ever set, the operation should exit safely. This is important because after any encode/decode issue, the tiny CBOR state will no longer be in sync with the data, and this library may assert if invoked with a bad state object. --- v7/src/v7_bp_canonical_block.c | 270 +++++++++++++++++++++------------ v7/src/v7_bp_container.c | 17 ++- v7/src/v7_bp_endpointid.c | 49 +++++- v7/src/v7_bp_hop_count_block.c | 50 +++++- v7/src/v7_bp_primary_block.c | 204 +++++++++++++++++-------- 5 files changed, 410 insertions(+), 180 deletions(-) diff --git a/v7/src/v7_bp_canonical_block.c b/v7/src/v7_bp_canonical_block.c index fb66ab7e..1293d3b0 100644 --- a/v7/src/v7_bp_canonical_block.c +++ b/v7/src/v7_bp_canonical_block.c @@ -25,6 +25,18 @@ #include "v7_decode_internal.h" #include "v7_encode_internal.h" +typedef enum bp_canonical_field +{ + bp_canonical_field_undef, + bp_canonical_field_blocktype, + bp_canonical_field_blocknum, + bp_canonical_field_flags, + bp_canonical_field_crctype, + bp_canonical_field_info_content, + bp_canonical_field_crcvalue, + bp_canonical_field_done +} bp_canonical_field_t; + static const v7_bitmap_table_t V7_BLOCK_PROCESSING_FLAGS_BITMAP_TABLE[] = { {offsetof(bp_block_processing_flags_t, must_remove), 0x10}, {offsetof(bp_block_processing_flags_t, must_delete), 0x04}, @@ -44,10 +56,43 @@ void v7_encode_bp_block_processing_flags(v7_encode_state_t *enc, const bp_block_ v7_encode_bitmap(enc, (const uint8_t *)v, V7_BLOCK_PROCESSING_FLAGS_BITMAP_TABLE); } +void v7_encode_bp_canonical_info(v7_encode_state_t *enc, const v7_canonical_block_info_t *info) +{ + /* + * The content is wrapped as a CBOR byte string. + * The data may itself be CBOR-encoded (so this may result as CBOR-in-CBOR) + * + * This encodes the data and snapshots the position of the END of that CBOR byte + * string. + */ + cbor_encode_byte_string(enc->cbor, info->content_vptr, info->content_size); + + if (!enc->error) + { + if (enc->total_bytes_encoded < info->content_size) + { + /* this should never happen */ + enc->error = true; + } + else if (info->content_offset_out != NULL) + { + /* + * Export the location where the encoded data actually appeared in the stream. + * + * CBOR markup occurs at the beginning of each record, so by knowing + * where it ends it is easy to find the beginning of actual data, as the CBOR + * markup itself is variable size, but the content is a known size here. + */ + *info->content_offset_out = enc->total_bytes_encoded - info->content_size; + } + } +} + void v7_encode_bp_canonical_bundle_block(v7_encode_state_t *enc, const bp_canonical_bundle_block_t *v, const v7_canonical_block_info_t *info) { - size_t content_offset_cbor_end; + bp_canonical_field_t field_id = bp_canonical_field_undef; + bp_blocktype_t encode_blocktype; /* @@ -71,44 +116,44 @@ void v7_encode_bp_canonical_bundle_block(v7_encode_state_t *enc, const bp_canoni if (encode_blocktype < bp_blocktype_MAX_NORMAL) { - v7_encode_bp_blocktype(enc, &encode_blocktype); - v7_encode_bp_blocknum(enc, &v->blockNum); - v7_encode_bp_block_processing_flags(enc, &v->processingControlFlags); - v7_encode_bp_crctype(enc, &v->crctype); - - /* - * The content is wrapped as a CBOR byte string. - * The data may itself be CBOR-encoded (so this may result as CBOR-in-CBOR) - * - * This encodes the data and snapshots the position of the END of that CBOR byte - * string. - */ - cbor_encode_byte_string(enc->cbor, info->content_vptr, info->content_size); - content_offset_cbor_end = enc->total_bytes_encoded; - if (content_offset_cbor_end < info->content_size) + while (field_id < bp_canonical_field_done && !enc->error) { - /* this should never happen */ - enc->error = true; - } - - /* Attach the CRC if requested. */ - if (v->crctype != bp_crctype_none) - { - v7_encode_crc(enc); - } + switch (field_id) + { + case bp_canonical_field_blocktype: + v7_encode_bp_blocktype(enc, &encode_blocktype); + break; + case bp_canonical_field_blocknum: + v7_encode_bp_blocknum(enc, &v->blockNum); + break; + case bp_canonical_field_flags: + v7_encode_bp_block_processing_flags(enc, &v->processingControlFlags); + break; + case bp_canonical_field_crctype: + v7_encode_bp_crctype(enc, &v->crctype); + break; + case bp_canonical_field_info_content: + v7_encode_bp_canonical_info(enc, info); + break; + case bp_canonical_field_crcvalue: + /* Attach the CRC if requested. */ + if (v->crctype != bp_crctype_none) + { + v7_encode_crc(enc); + } + break; + default: + break; + } - /* - * Export the location where the encoded data actually appeared in the stream. - * - * CBOR markup occurs at the beginning of each record, so by knowing - * where it ends it is easy to find the beginning of actual data, as the CBOR - * markup itself is variable size, but the content is a known size here. - */ - if (!enc->error && info->content_offset_out != NULL) - { - *info->content_offset_out = content_offset_cbor_end - info->content_size; + ++field_id; } } + else + { + /* could not identify what type of RFC9171 block type to use */ + enc->error = true; + } } static void v7_encode_bp_canonical_block_buffer_impl(v7_encode_state_t *enc, const void *arg) @@ -145,84 +190,111 @@ void v7_decode_bp_block_processing_flags(v7_decode_state_t *dec, bp_block_proces v7_decode_bitmap(dec, (uint8_t *)v, V7_BLOCK_PROCESSING_FLAGS_BITMAP_TABLE); } -void v7_decode_bp_canonical_bundle_block(v7_decode_state_t *dec, bp_canonical_bundle_block_t *v, - v7_canonical_block_info_t *info) +void v7_decode_bp_canonical_info(v7_decode_state_t *dec, v7_canonical_block_info_t *info) { const uint8_t *cbor_content_start_ptr; size_t cbor_content_length; size_t cbor_major_size; - v7_decode_bp_blocktype(dec, &v->blockType); - v7_decode_bp_blocknum(dec, &v->blockNum); - v7_decode_bp_block_processing_flags(dec, &v->processingControlFlags); - v7_decode_bp_crctype(dec, &v->crctype); + /* + * The content within this context must be a CBOR byte string. + * This byte string, in turn, _might_ have CBOR-encoded data within it, + * but it won't be decoded right now, just grab the location and + * make sure everything seems legit at the outer layer + */ + if (cbor_value_get_type(dec->cbor) != CborByteStringType) + { + dec->error = true; + return; + } - /* The block content should be encoded as a byte string, which internally may - * contain more CBOR encoding, but that will be done as a separate decode. - * For now just grab the pointers. */ - if (!dec->error) + cbor_content_start_ptr = cbor_value_get_next_byte(dec->cbor); + if (cbor_value_advance(dec->cbor) != CborNoError) { - if (cbor_value_at_end(dec->cbor) || cbor_value_get_type(dec->cbor) != CborByteStringType) - { - dec->error = true; - } - else - { - cbor_content_start_ptr = cbor_value_get_next_byte(dec->cbor); - if (cbor_value_advance(dec->cbor) != CborNoError) - { - dec->error = true; - } + dec->error = true; + return; + } - /* - * This calculated length reflects the start of this CBOR value to the - * start of the next CBOR value. Notably this includes the CBOR overhead/markup - * for this value, which will need to be removed. TinyCBOR will want to - * copy the value, so we go around it for this value and decode the major - * type locally. - */ - cbor_content_length = cbor_value_get_next_byte(dec->cbor) - cbor_content_start_ptr; + /* + * This calculated length reflects the start of this CBOR value to the + * start of the next CBOR value. Notably this includes the CBOR overhead/markup + * for this value, which will need to be removed. TinyCBOR will want to + * copy the value, so we go around it for this value and decode the major + * type locally. + */ + cbor_content_length = cbor_value_get_next_byte(dec->cbor) - cbor_content_start_ptr; - /* Advance the pointer according to the CBOR length to get to the real data. */ - cbor_major_size = *cbor_content_start_ptr & 0x1F; - if (cbor_major_size < 24) - { - /* no extra bytes beyond the major type */ - cbor_major_size = 0; - } - else if (cbor_major_size < 28) - { - /* 1, 2, 4, or 8 additional bytes beyond the major type */ - cbor_major_size = 1 << (cbor_major_size - 24); - } - else - { - /* Value not well formed, or indefinite length (not supported here) */ - cbor_major_size = cbor_content_length; - } + /* Advance the pointer according to the CBOR length to get to the real data. */ + cbor_major_size = *cbor_content_start_ptr & 0x1F; + if (cbor_major_size < 24) + { + /* no extra bytes beyond the major type */ + cbor_major_size = 0; + } + else if (cbor_major_size < 28) + { + /* 1, 2, 4, or 8 additional bytes beyond the major type */ + cbor_major_size = 1 << (cbor_major_size - 24); + } + else + { + /* Value not well formed, or indefinite length (not supported here) */ + cbor_major_size = cbor_content_length; + } - ++cbor_major_size; /* Account for the CBOR major type octet itself (always there) */ - if (cbor_major_size <= cbor_content_length) - { - cbor_content_start_ptr += cbor_major_size; - cbor_content_length -= cbor_major_size; + ++cbor_major_size; /* Account for the CBOR major type octet itself (always there) */ + if (cbor_major_size <= cbor_content_length) + { + cbor_content_start_ptr += cbor_major_size; + cbor_content_length -= cbor_major_size; - /* Export the position of the now-located content information */ - *info->content_offset_out = cbor_content_start_ptr - dec->base; - info->content_vptr = cbor_content_start_ptr; - info->content_size = cbor_content_length; - } - else - { - /* This should not happen */ - dec->error = true; - } - } + /* Export the position of the now-located content information */ + *info->content_offset_out = cbor_content_start_ptr - dec->base; + info->content_vptr = cbor_content_start_ptr; + info->content_size = cbor_content_length; + } + else + { + /* This should not happen */ + dec->error = true; } +} - if (v->crctype != bp_crctype_none) +void v7_decode_bp_canonical_bundle_block(v7_decode_state_t *dec, bp_canonical_bundle_block_t *v, + v7_canonical_block_info_t *info) +{ + bp_canonical_field_t field_id = bp_canonical_field_undef; + + while (field_id < bp_canonical_field_done && !dec->error && !cbor_value_at_end(dec->cbor)) { - v7_decode_crc(dec, &v->crcval); + switch (field_id) + { + case bp_canonical_field_blocktype: + v7_decode_bp_blocktype(dec, &v->blockType); + break; + case bp_canonical_field_blocknum: + v7_decode_bp_blocknum(dec, &v->blockNum); + break; + case bp_canonical_field_flags: + v7_decode_bp_block_processing_flags(dec, &v->processingControlFlags); + break; + case bp_canonical_field_crctype: + v7_decode_bp_crctype(dec, &v->crctype); + break; + case bp_canonical_field_info_content: + v7_decode_bp_canonical_info(dec, info); + break; + case bp_canonical_field_crcvalue: + if (v->crctype != bp_crctype_none) + { + v7_decode_crc(dec, &v->crcval); + } + break; + default: + break; + } + + ++field_id; } } diff --git a/v7/src/v7_bp_container.c b/v7/src/v7_bp_container.c index 4b7a4e9d..817ff910 100644 --- a/v7/src/v7_bp_container.c +++ b/v7/src/v7_bp_container.c @@ -101,15 +101,16 @@ void v7_decode_container(v7_decode_state_t *dec, size_t entries, v7_decode_func_ func(dec, arg); /* This should have consumed every item */ - if (!cbor_value_at_end(&content)) + if (!dec->error) { - dec->error = true; - } - - /* return to parent scope */ - if (cbor_value_leave_container(parent, &content) != CborNoError) - { - dec->error = true; + if (!cbor_value_at_end(&content)) + { + dec->error = true; + } + else if (cbor_value_leave_container(parent, &content) != CborNoError) + { + dec->error = true; + } } dec->cbor = parent; diff --git a/v7/src/v7_bp_endpointid.c b/v7/src/v7_bp_endpointid.c index b5996655..cd8e0aa5 100644 --- a/v7/src/v7_bp_endpointid.c +++ b/v7/src/v7_bp_endpointid.c @@ -25,6 +25,13 @@ #include "v7_encode_internal.h" #include "v7_decode_internal.h" +typedef enum bp_ipn_ssp_field +{ + bp_ipn_ssp_field_undef, + bp_ipn_ssp_field_nodenumber, + bp_ipn_ssp_field_servicenumber, + bp_ipn_ssp_field_done +} bp_ipn_ssp_field_t; /* * ----------------------------------------------------------------------------------- * IMPLEMENTATION @@ -49,10 +56,25 @@ void v7_encode_bp_ipn_servicenumber(v7_encode_state_t *enc, const bp_ipn_service void v7_encode_bp_ipn_uri_ssp_impl(v7_encode_state_t *enc, const void *arg) { - const bp_ipn_uri_ssp_t *v = arg; + const bp_ipn_uri_ssp_t *v = arg; + bp_ipn_ssp_field_t field_id = bp_ipn_ssp_field_undef; - v7_encode_bp_ipn_nodenumber(enc, &v->node_number); - v7_encode_bp_ipn_servicenumber(enc, &v->service_number); + while (field_id < bp_ipn_ssp_field_done && !enc->error) + { + switch (field_id) + { + case bp_ipn_ssp_field_nodenumber: + v7_encode_bp_ipn_nodenumber(enc, &v->node_number); + break; + case bp_ipn_ssp_field_servicenumber: + v7_encode_bp_ipn_servicenumber(enc, &v->service_number); + break; + default: + break; + } + + ++field_id; + } } void v7_encode_bp_ipn_uri_ssp(v7_encode_state_t *enc, const bp_ipn_uri_ssp_t *v) @@ -101,10 +123,25 @@ void v7_decode_bp_ipn_servicenumber(v7_decode_state_t *dec, bp_ipn_servicenumber void v7_decode_bp_ipn_uri_ssp_impl(v7_decode_state_t *dec, void *arg) { - bp_ipn_uri_ssp_t *v = arg; + bp_ipn_uri_ssp_t *v = arg; + bp_ipn_ssp_field_t field_id = bp_ipn_ssp_field_undef; - v7_decode_bp_ipn_nodenumber(dec, &v->node_number); - v7_decode_bp_ipn_servicenumber(dec, &v->service_number); + while (field_id < bp_ipn_ssp_field_done && !dec->error && !cbor_value_at_end(dec->cbor)) + { + switch (field_id) + { + case bp_ipn_ssp_field_nodenumber: + v7_decode_bp_ipn_nodenumber(dec, &v->node_number); + break; + case bp_ipn_ssp_field_servicenumber: + v7_decode_bp_ipn_servicenumber(dec, &v->service_number); + break; + default: + break; + } + + ++field_id; + } } void v7_decode_bp_ipn_uri_ssp(v7_decode_state_t *dec, bp_ipn_uri_ssp_t *v) diff --git a/v7/src/v7_bp_hop_count_block.c b/v7/src/v7_bp_hop_count_block.c index 540710c7..56d1a902 100644 --- a/v7/src/v7_bp_hop_count_block.c +++ b/v7/src/v7_bp_hop_count_block.c @@ -25,6 +25,14 @@ #include "v7_decode_internal.h" #include "v7_encode_internal.h" +typedef enum bp_hop_count_field +{ + bp_hop_count_field_undef, + bp_hop_count_field_limit, + bp_hop_count_field_count, + bp_hop_count_field_done +} bp_hop_count_field_t; + /* * ----------------------------------------------------------------------------------- * IMPLEMENTATION @@ -34,10 +42,25 @@ void v7_encode_bp_hop_count_block_impl(v7_encode_state_t *enc, const void *arg) { - const bp_hop_count_block_t *v = arg; + const bp_hop_count_block_t *v = arg; + bp_hop_count_field_t field_id = bp_hop_count_field_undef; - v7_encode_bp_integer(enc, &v->hopLimit); - v7_encode_bp_integer(enc, &v->hopCount); + while (field_id < bp_hop_count_field_done && !enc->error) + { + switch (field_id) + { + case bp_hop_count_field_limit: + v7_encode_bp_integer(enc, &v->hopLimit); + break; + case bp_hop_count_field_count: + v7_encode_bp_integer(enc, &v->hopCount); + break; + default: + break; + } + + ++field_id; + } } void v7_encode_bp_hop_count_block(v7_encode_state_t *enc, const bp_hop_count_block_t *v) @@ -47,10 +70,25 @@ void v7_encode_bp_hop_count_block(v7_encode_state_t *enc, const bp_hop_count_blo void v7_decode_bp_hop_count_block_impl(v7_decode_state_t *dec, void *arg) { - bp_hop_count_block_t *v = arg; + bp_hop_count_block_t *v = arg; + bp_hop_count_field_t field_id = bp_hop_count_field_undef; + + while (field_id < bp_hop_count_field_done && !dec->error && !cbor_value_at_end(dec->cbor)) + { + switch (field_id) + { + case bp_hop_count_field_limit: + v7_decode_bp_integer(dec, &v->hopLimit); + break; + case bp_hop_count_field_count: + v7_decode_bp_integer(dec, &v->hopCount); + break; + default: + break; + } - v7_decode_bp_integer(dec, &v->hopLimit); - v7_decode_bp_integer(dec, &v->hopCount); + ++field_id; + } } void v7_decode_bp_hop_count_block(v7_decode_state_t *dec, bp_hop_count_block_t *v) diff --git a/v7/src/v7_bp_primary_block.c b/v7/src/v7_bp_primary_block.c index 1357d494..e44394f5 100644 --- a/v7/src/v7_bp_primary_block.c +++ b/v7/src/v7_bp_primary_block.c @@ -25,6 +25,23 @@ #include "v7_decode_internal.h" #include "v7_encode_internal.h" +typedef enum bp_pri_field +{ + bp_pri_field_undef, + bp_pri_field_version, + bp_pri_field_flags, + bp_pri_field_crctype, + bp_pri_field_destid, + bp_pri_field_sourceid, + bp_pri_field_reportid, + bp_pri_field_timestamp, + bp_pri_field_lifetime, + bp_pri_field_fragmentoffset, + bp_pri_field_totallength, + bp_pri_field_crcvalue, + bp_pri_field_done +} bp_pri_field_t; + static const v7_bitmap_table_t V7_BUNDLE_CONTROL_FLAGS_BITMAP_TABLE[] = { {offsetof(bp_bundle_processing_control_flags_t, deletion_status_req), 0x40000}, {offsetof(bp_bundle_processing_control_flags_t, delivery_status_req), 0x20000}, @@ -80,36 +97,67 @@ void v7_encode_bp_adu_length(v7_encode_state_t *enc, const bp_adu_length_t *v) void v7_encode_bp_primary_block_impl(v7_encode_state_t *enc, const void *arg) { - const bp_primary_block_t *v = arg; - - v7_encode_small_int(enc, v->version); - if (v->version != 7) - { - /* don't know how to encode the rest if not v7 */ - enc->error = true; - return; - } - - /* the other 7 fixed fields defined by BPv7 */ - v7_encode_bp_bundle_processing_control_flags(enc, &v->controlFlags); - v7_encode_bp_crctype(enc, &v->crctype); - v7_encode_bp_endpointid_buffer(enc, &v->destinationEID); - v7_encode_bp_endpointid_buffer(enc, &v->sourceEID); - v7_encode_bp_endpointid_buffer(enc, &v->reportEID); - v7_encode_bp_creation_timestamp(enc, &v->creationTimeStamp); - v7_encode_bp_lifetime(enc, &v->lifetime); + const bp_primary_block_t *v = arg; + bp_pri_field_t field_id = bp_pri_field_undef; - /* next fields depend on whether the flag is set */ - if (v->controlFlags.isFragment) - { - v7_encode_bp_adu_length(enc, &v->fragmentOffset); - v7_encode_bp_adu_length(enc, &v->totalADUlength); - } - - /* Attach the CRC if requested. */ - if (v->crctype != bp_crctype_none) + while (field_id < bp_pri_field_done && !enc->error) { - v7_encode_crc(enc); + switch (field_id) + { + case bp_pri_field_version: + v7_encode_small_int(enc, v->version); + if (v->version != 7) + { + /* don't know how to encode the rest if not v7 */ + enc->error = true; + } + break; + case bp_pri_field_flags: + v7_encode_bp_bundle_processing_control_flags(enc, &v->controlFlags); + break; + case bp_pri_field_crctype: + v7_encode_bp_crctype(enc, &v->crctype); + break; + case bp_pri_field_destid: + v7_encode_bp_endpointid_buffer(enc, &v->destinationEID); + break; + case bp_pri_field_sourceid: + v7_encode_bp_endpointid_buffer(enc, &v->sourceEID); + break; + case bp_pri_field_reportid: + v7_encode_bp_endpointid_buffer(enc, &v->reportEID); + break; + case bp_pri_field_timestamp: + v7_encode_bp_creation_timestamp(enc, &v->creationTimeStamp); + break; + case bp_pri_field_lifetime: + v7_encode_bp_lifetime(enc, &v->lifetime); + break; + case bp_pri_field_fragmentoffset: + /* depends on whether the flag is set */ + if (v->controlFlags.isFragment) + { + v7_encode_bp_adu_length(enc, &v->fragmentOffset); + } + break; + case bp_pri_field_totallength: + /* depends on whether the flag is set */ + if (v->controlFlags.isFragment) + { + v7_encode_bp_adu_length(enc, &v->totalADUlength); + } + break; + case bp_pri_field_crcvalue: + /* Attach the CRC if requested. */ + if (v->crctype != bp_crctype_none) + { + v7_encode_crc(enc); + } + break; + default: + break; + } + ++field_id; } } @@ -173,41 +221,75 @@ void v7_decode_bp_adu_length(v7_decode_state_t *dec, bp_adu_length_t *v) void v7_decode_bp_primary_block_impl(v7_decode_state_t *dec, void *arg) { - bp_primary_block_t *v = arg; + bp_primary_block_t *v = arg; + bp_pri_field_t field_id = bp_pri_field_undef; - v->version = (uint8_t)v7_decode_small_int(dec); - if (v->version != 7) - { - /* don't know how to decode the rest if not v7 */ - dec->error = true; - return; - } - - /* the other 7 fixed fields defined by BPv7 */ - v7_decode_bp_bundle_processing_control_flags(dec, &v->controlFlags); - v7_decode_bp_crctype(dec, &v->crctype); - v7_decode_bp_endpointid_buffer(dec, &v->destinationEID); - v7_decode_bp_endpointid_buffer(dec, &v->sourceEID); - v7_decode_bp_endpointid_buffer(dec, &v->reportEID); - v7_decode_bp_creation_timestamp(dec, &v->creationTimeStamp); - v7_decode_bp_lifetime(dec, &v->lifetime); - - /* next fields depend on whether the flag is set */ - if (v->controlFlags.isFragment) - { - v7_decode_bp_adu_length(dec, &v->fragmentOffset); - v7_decode_bp_adu_length(dec, &v->totalADUlength); - } - else - { - v->fragmentOffset = 0; - v->totalADUlength = 0; - } - - /* Attach the CRC if requested. */ - if (v->crctype != bp_crctype_none) + while (field_id < bp_pri_field_done && !dec->error && !cbor_value_at_end(dec->cbor)) { - v7_decode_crc(dec, &v->crcval); + switch (field_id) + { + case bp_pri_field_version: + v->version = (uint8_t)v7_decode_small_int(dec); + if (v->version != 7) + { + /* don't know how to decode the rest if not v7 */ + dec->error = true; + } + break; + case bp_pri_field_flags: + v7_decode_bp_bundle_processing_control_flags(dec, &v->controlFlags); + break; + case bp_pri_field_crctype: + v7_decode_bp_crctype(dec, &v->crctype); + break; + case bp_pri_field_destid: + v7_decode_bp_endpointid_buffer(dec, &v->destinationEID); + break; + case bp_pri_field_sourceid: + v7_decode_bp_endpointid_buffer(dec, &v->sourceEID); + break; + case bp_pri_field_reportid: + v7_decode_bp_endpointid_buffer(dec, &v->reportEID); + break; + case bp_pri_field_timestamp: + v7_decode_bp_creation_timestamp(dec, &v->creationTimeStamp); + break; + case bp_pri_field_lifetime: + v7_decode_bp_lifetime(dec, &v->lifetime); + break; + case bp_pri_field_fragmentoffset: + /* depends on whether the flag is set */ + if (v->controlFlags.isFragment) + { + v7_decode_bp_adu_length(dec, &v->fragmentOffset); + } + else + { + v->fragmentOffset = 0; + } + break; + case bp_pri_field_totallength: + /* depends on whether the flag is set */ + if (v->controlFlags.isFragment) + { + v7_decode_bp_adu_length(dec, &v->totalADUlength); + } + else + { + v->totalADUlength = 0; + } + break; + case bp_pri_field_crcvalue: + /* decode the CRC if it has one. */ + if (v->crctype != bp_crctype_none) + { + v7_decode_crc(dec, &v->crcval); + } + break; + default: + break; + } + ++field_id; } }