From 6b6be4a4344daffcab9e74dd25485727b117074f Mon Sep 17 00:00:00 2001 From: Steve Karg Date: Wed, 18 Dec 2024 15:29:27 -0600 Subject: [PATCH] Added check for zero length buffer size in primitive decoders that returns zero to enable simpler complex value optional element decoding. (#876) --- Makefile | 1 + src/bacnet/bacdcode.c | 244 ++++++++++++++++------- src/bacnet/bacdcode.h | 6 + src/bacnet/bacdest.c | 328 +++++++++++++++++++++---------- src/bacnet/bacdest.h | 15 ++ src/bacnet/bacdevobjpropref.c | 305 +++++++++++++++++++++------- src/bacnet/bacdevobjpropref.h | 39 +++- src/bacnet/timestamp.c | 8 +- test/bacnet/bacdcode/src/main.c | 41 ++-- test/bacnet/bacdest/src/main.c | 4 +- test/bacnet/timestamp/src/main.c | 2 +- 11 files changed, 723 insertions(+), 270 deletions(-) diff --git a/Makefile b/Makefile index 158cbfae..9e384923 100644 --- a/Makefile +++ b/Makefile @@ -409,6 +409,7 @@ CPPCHECK_OPTIONS += --suppress=redundantAssignment CPPCHECK_OPTIONS += --suppress=duplicateCondition CPPCHECK_OPTIONS += --suppress=funcArgNamesDifferent CPPCHECK_OPTIONS += --suppress=unusedStructMember +CPPCHECK_OPTIONS += --suppress=uselessAssignmentPtrArg CPPCHECK_OPTIONS += --addon=cert.py CPPCHECK_OPTIONS += --suppress=cert-MSC30-c CPPCHECK_OPTIONS += --suppress=cert-STR05-C diff --git a/src/bacnet/bacdcode.c b/src/bacnet/bacdcode.c index f0ba3853..ea508043 100644 --- a/src/bacnet/bacdcode.c +++ b/src/bacnet/bacdcode.c @@ -1246,7 +1246,7 @@ int bacnet_boolean_application_encode( * @param apdu_size - number of bytes in the buffer * @param boolean_value - decoded Boolean Value, if decoded * - * @return number of bytes decoded, zero if wrong tag number, + * @return number of bytes decoded, zero if tag mismatch, * or #BACNET_STATUS_ERROR (-1) if malformed */ int bacnet_boolean_application_decode( @@ -1256,9 +1256,12 @@ int bacnet_boolean_application_decode( int len = 0; BACNET_TAG tag = { 0 }; + if (apdu_size == 0) { + return 0; + } len = bacnet_tag_decode(apdu, apdu_size, &tag); - if ((len > 0) && tag.application) { - if (tag.number == BACNET_APPLICATION_TAG_BOOLEAN) { + if (len > 0) { + if (tag.application && (tag.number == BACNET_APPLICATION_TAG_BOOLEAN)) { apdu_len = len; if (boolean_value) { *boolean_value = decode_boolean(tag.len_value_type); @@ -1291,7 +1294,7 @@ int bacnet_boolean_application_decode( * @param tag_value - context tag number expected * @param boolean_value - decoded Boolean Value, if decoded * - * @return number of bytes decoded, zero if wrong tag number, + * @return number of bytes decoded, zero if tag mismatch, * or #BACNET_STATUS_ERROR (-1) if malformed */ int bacnet_boolean_context_decode( @@ -1304,9 +1307,12 @@ int bacnet_boolean_context_decode( int len = 0; BACNET_TAG tag = { 0 }; + if (apdu_size == 0) { + return 0; + } len = bacnet_tag_decode(apdu, apdu_size, &tag); - if ((len > 0) && tag.context) { - if (tag.number == tag_value) { + if (len > 0) { + if (tag.context && (tag.number == tag_value)) { apdu_len = len; if (apdu_len < apdu_size) { if (boolean_value) { @@ -1521,7 +1527,7 @@ int bacnet_bitstring_application_encode( * @param apdu_size - number of bytes in the buffer * @param value - decoded value, if decoded * - * @return number of bytes decoded, zero if wrong tag number, + * @return number of bytes decoded, zero if tag mismatch, * or #BACNET_STATUS_ERROR (-1) if malformed */ int bacnet_bitstring_application_decode( @@ -1531,9 +1537,13 @@ int bacnet_bitstring_application_decode( int len = 0; BACNET_TAG tag = { 0 }; + if (apdu_size == 0) { + return 0; + } len = bacnet_tag_decode(apdu, apdu_size, &tag); - if ((len > 0) && tag.application) { - if (tag.number == BACNET_APPLICATION_TAG_BIT_STRING) { + if (len > 0) { + if (tag.application && + (tag.number == BACNET_APPLICATION_TAG_BIT_STRING)) { apdu_len = len; len = bacnet_bitstring_decode( &apdu[apdu_len], apdu_size - apdu_len, tag.len_value_type, @@ -1561,7 +1571,7 @@ int bacnet_bitstring_application_decode( * @param tag_value - context tag number expected * @param value - decoded value, if decoded * - * @return number of bytes decoded, or zero if tag number mismatch, or + * @return number of bytes decoded, or zero if tag mismatch, or * #BACNET_STATUS_ERROR (-1) if malformed */ int bacnet_bitstring_context_decode( @@ -1574,9 +1584,12 @@ int bacnet_bitstring_context_decode( int len = 0; BACNET_TAG tag = { 0 }; + if (apdu_size == 0) { + return 0; + } len = bacnet_tag_decode(apdu, apdu_size, &tag); - if ((len > 0) && tag.context) { - if (tag.number == tag_value) { + if (len > 0) { + if (tag.context && (tag.number == tag_value)) { apdu_len = len; len = bacnet_bitstring_decode( &apdu[apdu_len], apdu_size - apdu_len, tag.len_value_type, @@ -1851,7 +1864,7 @@ int bacnet_object_id_application_encode( * @param object_type - decoded object type, if decoded * @param object_instance - decoded object instance, if decoded * - * @return number of bytes decoded, zero if wrong tag number, + * @return number of bytes decoded, zero if tag mismatch, * or #BACNET_STATUS_ERROR (-1) if malformed */ int bacnet_object_id_application_decode( @@ -1864,9 +1877,13 @@ int bacnet_object_id_application_decode( int len = 0; BACNET_TAG tag = { 0 }; + if (apdu_size == 0) { + return 0; + } len = bacnet_tag_decode(apdu, apdu_size, &tag); - if ((len > 0) && tag.application) { - if (tag.number == BACNET_APPLICATION_TAG_OBJECT_ID) { + if (len > 0) { + if (tag.application && + (tag.number == BACNET_APPLICATION_TAG_OBJECT_ID)) { apdu_len = len; len = bacnet_object_id_decode( &apdu[apdu_len], apdu_size - apdu_len, tag.len_value_type, @@ -1895,7 +1912,7 @@ int bacnet_object_id_application_decode( * @param object_type - decoded object type, if decoded * @param object_instance - decoded object instance, if decoded * - * @return number of bytes decoded, zero if wrong tag number, + * @return number of bytes decoded, zero if tag mismatch, * or #BACNET_STATUS_ERROR (-1) if malformed */ int bacnet_object_id_context_decode( @@ -1909,9 +1926,12 @@ int bacnet_object_id_context_decode( int len = 0; BACNET_TAG tag = { 0 }; + if (apdu_size == 0) { + return 0; + } len = bacnet_tag_decode(apdu, apdu_size, &tag); - if ((len > 0) && tag.context) { - if (tag.number == tag_value) { + if (len > 0) { + if (tag.context && (tag.number == tag_value)) { apdu_len = len; len = bacnet_object_id_decode( &apdu[apdu_len], apdu_size - apdu_len, tag.len_value_type, @@ -1929,6 +1949,27 @@ int bacnet_object_id_context_decode( return apdu_len; } +/** + * @brief Compare two object identifiers for equality. + * @param value1 - first object identifier + * @param value2 - second object identifier + * @return true if the object identifiers are the same, false otherwise + */ +bool bacnet_object_id_same( + BACNET_OBJECT_TYPE object_type1, + uint32_t instance1, + BACNET_OBJECT_TYPE object_type2, + uint32_t instance2) +{ + bool status = false; + + if ((object_type1 == object_type2) && (instance1 == instance2)) { + status = true; + } + + return status; +} + /** * @brief Decode the BACnet Object Identifier Value when context encoded * as defined in clause 20.2.14 Encoding of an Object Identifier Value @@ -2258,7 +2299,7 @@ int bacnet_octet_string_application_encode( * @param apdu_size - number of bytes in the buffer * @param value - decoded value, if decoded, or NULL for length * - * @return number of bytes decoded, zero if wrong tag number, + * @return number of bytes decoded, zero if tag mismatch, * or #BACNET_STATUS_ERROR (-1) if malformed */ int bacnet_octet_string_application_decode( @@ -2268,9 +2309,13 @@ int bacnet_octet_string_application_decode( int len = 0; BACNET_TAG tag = { 0 }; + if (apdu_size == 0) { + return 0; + } len = bacnet_tag_decode(apdu, apdu_size, &tag); - if ((len > 0) && tag.application) { - if (tag.number == BACNET_APPLICATION_TAG_OCTET_STRING) { + if (len > 0) { + if (tag.application && + (tag.number == BACNET_APPLICATION_TAG_OCTET_STRING)) { apdu_len = len; len = bacnet_octet_string_decode( &apdu[len], apdu_size - apdu_len, tag.len_value_type, value); @@ -2297,7 +2342,7 @@ int bacnet_octet_string_application_decode( * @param tag_value - context tag number expected * @param value - the value decoded, or NULL for length * - * @return number of bytes decoded, or zero if tag number mismatch, or + * @return number of bytes decoded, or zero if tag mismatch, or * #BACNET_STATUS_ERROR (-1) if malformed */ int bacnet_octet_string_context_decode( @@ -2310,9 +2355,12 @@ int bacnet_octet_string_context_decode( int len = 0; BACNET_TAG tag = { 0 }; + if (apdu_size == 0) { + return 0; + } len = bacnet_tag_decode(apdu, apdu_size, &tag); - if ((len > 0) && tag.context) { - if (tag.number == tag_value) { + if (len > 0) { + if (tag.context && (tag.number == tag_value)) { apdu_len = len; len = bacnet_octet_string_decode( &apdu[apdu_len], apdu_size - apdu_len, tag.len_value_type, @@ -2553,7 +2601,7 @@ int bacnet_character_string_application_encode( * @param apdu_size - number of bytes in the buffer * @param value - decoded value, if decoded * - * @return number of bytes decoded, zero if wrong tag number, + * @return number of bytes decoded, zero if tag mismatch, * or #BACNET_STATUS_ERROR (-1) if malformed */ int bacnet_character_string_application_decode( @@ -2563,9 +2611,13 @@ int bacnet_character_string_application_decode( int len = 0; BACNET_TAG tag = { 0 }; + if (apdu_size == 0) { + return 0; + } len = bacnet_tag_decode(apdu, apdu_size, &tag); - if ((len > 0) && tag.application) { - if (tag.number == BACNET_APPLICATION_TAG_CHARACTER_STRING) { + if (len > 0) { + if (tag.application && + (tag.number == BACNET_APPLICATION_TAG_CHARACTER_STRING)) { apdu_len = len; len = bacnet_character_string_decode( &apdu[len], apdu_size - apdu_len, tag.len_value_type, value); @@ -2592,7 +2644,7 @@ int bacnet_character_string_application_decode( * @param tag_value - context tag number expected * @param value - the value decoded, if decoded * - * @return number of bytes decoded, or zero if tag number mismatch, or + * @return number of bytes decoded, or zero if tag mismatch, or * #BACNET_STATUS_ERROR (-1) if malformed */ int bacnet_character_string_context_decode( @@ -2605,9 +2657,12 @@ int bacnet_character_string_context_decode( int len = 0; BACNET_TAG tag = { 0 }; + if (apdu_size == 0) { + return 0; + } len = bacnet_tag_decode(apdu, apdu_size, &tag); - if ((len > 0) && tag.context) { - if (tag.number == tag_value) { + if (len > 0) { + if (tag.context && (tag.number == tag_value)) { apdu_len = len; len = bacnet_character_string_decode( &apdu[apdu_len], apdu_size - apdu_len, tag.len_value_type, @@ -2758,7 +2813,7 @@ int bacnet_unsigned_decode( * @param tag_value - context tag number expected * @param value - the value decoded, if decoded * - * @return number of bytes decoded, zero if wrong tag number, + * @return number of bytes decoded, zero if tag mismatch, * or #BACNET_STATUS_ERROR (-1) if malformed */ int bacnet_unsigned_context_decode( @@ -2771,9 +2826,12 @@ int bacnet_unsigned_context_decode( int len = 0; BACNET_TAG tag = { 0 }; + if (apdu_size == 0) { + return 0; + } len = bacnet_tag_decode(apdu, apdu_size, &tag); - if ((len > 0) && tag.context) { - if (tag.number == tag_value) { + if (len > 0) { + if (tag.context && (tag.number == tag_value)) { apdu_len = len; len = bacnet_unsigned_decode( &apdu[apdu_len], apdu_size - apdu_len, tag.len_value_type, @@ -2828,7 +2886,7 @@ int bacnet_unsigned_application_encode( * @param apdu_size - number of bytes in the buffer * @param value - decoded value, if decoded * - * @return number of bytes decoded, zero if wrong tag number, + * @return number of bytes decoded, zero if tag mismatch, * or #BACNET_STATUS_ERROR (-1) if malformed */ int bacnet_unsigned_application_decode( @@ -2838,9 +2896,13 @@ int bacnet_unsigned_application_decode( int len = 0; BACNET_TAG tag = { 0 }; + if (apdu_size == 0) { + return 0; + } len = bacnet_tag_decode(apdu, apdu_size, &tag); - if ((len > 0) && tag.application) { - if (tag.number == BACNET_APPLICATION_TAG_UNSIGNED_INT) { + if (len > 0) { + if (tag.application && + (tag.number == BACNET_APPLICATION_TAG_UNSIGNED_INT)) { apdu_len = len; len = bacnet_unsigned_decode( &apdu[apdu_len], apdu_size - apdu_len, tag.len_value_type, @@ -3092,7 +3154,7 @@ int bacnet_enumerated_application_encode( * @param apdu_size - number of bytes in the buffer * @param value - decoded value, if decoded * - * @return number of bytes decoded, zero if wrong tag number, + * @return number of bytes decoded, zero if tag mismatch, * or #BACNET_STATUS_ERROR (-1) if malformed */ int bacnet_enumerated_application_decode( @@ -3103,9 +3165,13 @@ int bacnet_enumerated_application_decode( BACNET_UNSIGNED_INTEGER unsigned_value = 0; BACNET_TAG tag = { 0 }; + if (apdu_size == 0) { + return 0; + } len = bacnet_tag_decode(apdu, apdu_size, &tag); - if ((len > 0) && tag.application) { - if (tag.number == BACNET_APPLICATION_TAG_ENUMERATED) { + if (len > 0) { + if (tag.application && + (tag.number == BACNET_APPLICATION_TAG_ENUMERATED)) { apdu_len = len; /* note: enumerated is encoded as UNSIGNED INT */ len = bacnet_unsigned_decode( @@ -3141,7 +3207,7 @@ int bacnet_enumerated_application_decode( * @param tag_value - context tag number expected * @param value - the enumerated value decoded * - * @return number of bytes decoded, or zero if tag number mismatch, or + * @return number of bytes decoded, or zero if tag mismatch, or * #BACNET_STATUS_ERROR (-1) if malformed */ int bacnet_enumerated_context_decode( @@ -3151,9 +3217,12 @@ int bacnet_enumerated_context_decode( int len = 0; BACNET_TAG tag = { 0 }; + if (apdu_size == 0) { + return 0; + } len = bacnet_tag_decode(apdu, apdu_size, &tag); - if ((len > 0) && tag.context) { - if (tag.number == tag_value) { + if (len > 0) { + if (tag.context && (tag.number == tag_value)) { apdu_len = len; len = bacnet_enumerated_decode( &apdu[apdu_len], apdu_size - apdu_len, tag.len_value_type, @@ -3318,7 +3387,7 @@ int bacnet_signed_decode( * @param tag_value - context tag number expected * @param value - the signed value decoded * - * @return number of bytes decoded, zero if wrong tag number, + * @return number of bytes decoded, zero if tag mismatch, * or error (-1) if malformed */ int bacnet_signed_context_decode( @@ -3328,9 +3397,12 @@ int bacnet_signed_context_decode( int len = 0; BACNET_TAG tag = { 0 }; + if (apdu_size == 0) { + return 0; + } len = bacnet_tag_decode(apdu, apdu_size, &tag); - if ((len > 0) && tag.context) { - if (tag.number == tag_value) { + if (len > 0) { + if (tag.context && (tag.number == tag_value)) { apdu_len = len; len = bacnet_signed_decode( &apdu[apdu_len], apdu_size - apdu_len, tag.len_value_type, @@ -3384,7 +3456,7 @@ int bacnet_signed_application_encode( * @param apdu_size - number of bytes in the buffer * @param value - decoded value, if decoded * - * @return number of bytes decoded, zero if wrong tag number, + * @return number of bytes decoded, zero if tag mismatch, * or #BACNET_STATUS_ERROR (-1) if malformed */ int bacnet_signed_application_decode( @@ -3394,9 +3466,13 @@ int bacnet_signed_application_decode( int len = 0; BACNET_TAG tag = { 0 }; + if (apdu_size == 0) { + return 0; + } len = bacnet_tag_decode(apdu, apdu_size, &tag); - if ((len > 0) && tag.application) { - if (tag.number == BACNET_APPLICATION_TAG_SIGNED_INT) { + if (len > 0) { + if (tag.application && + (tag.number == BACNET_APPLICATION_TAG_SIGNED_INT)) { apdu_len = len; len = bacnet_signed_decode( &apdu[apdu_len], apdu_size - apdu_len, tag.len_value_type, @@ -3629,7 +3705,7 @@ int bacnet_real_decode( * @param tag_value - context tag number expected * @param value - the value decoded, if decoded * - * @return number of bytes decoded, zero if wrong tag number, + * @return number of bytes decoded, zero if tag mismatch, * or error (-1) if malformed */ int bacnet_real_context_decode( @@ -3639,9 +3715,12 @@ int bacnet_real_context_decode( int len = 0; BACNET_TAG tag = { 0 }; + if (apdu_size == 0) { + return 0; + } len = bacnet_tag_decode(apdu, apdu_size, &tag); - if ((len > 0) && tag.context) { - if (tag.number == tag_value) { + if (len > 0) { + if (tag.context && (tag.number == tag_value)) { apdu_len = len; len = bacnet_real_decode( &apdu[apdu_len], apdu_size - apdu_len, tag.len_value_type, @@ -3695,7 +3774,7 @@ int bacnet_real_application_encode( * @param apdu_size - number of bytes in the buffer * @param value - decoded value, if decoded * - * @return number of bytes decoded, zero if wrong tag number, + * @return number of bytes decoded, zero if tag mismatch, * or #BACNET_STATUS_ERROR (-1) if malformed */ int bacnet_real_application_decode( @@ -3705,9 +3784,12 @@ int bacnet_real_application_decode( int len = 0; BACNET_TAG tag = { 0 }; + if (apdu_size == 0) { + return 0; + } len = bacnet_tag_decode(apdu, apdu_size, &tag); - if ((len > 0) && tag.application) { - if (tag.number == BACNET_APPLICATION_TAG_REAL) { + if (len > 0) { + if (tag.application && (tag.number == BACNET_APPLICATION_TAG_REAL)) { apdu_len = len; len = bacnet_real_decode( &apdu[apdu_len], apdu_size - apdu_len, tag.len_value_type, @@ -3840,7 +3922,7 @@ int bacnet_double_decode( * @param tag_value - context tag number expected * @param value - the value decoded * - * @return number of bytes decoded, zero if wrong tag number, + * @return number of bytes decoded, zero if tag mismatch, * or error (-1) if malformed */ int bacnet_double_context_decode( @@ -3850,9 +3932,12 @@ int bacnet_double_context_decode( int len = 0; BACNET_TAG tag = { 0 }; + if (apdu_size == 0) { + return 0; + } len = bacnet_tag_decode(apdu, apdu_size, &tag); - if ((len > 0) && tag.context) { - if (tag.number == tag_value) { + if (len > 0) { + if (tag.context && (tag.number == tag_value)) { apdu_len = len; len = bacnet_double_decode( &apdu[apdu_len], apdu_size - apdu_len, tag.len_value_type, @@ -3906,7 +3991,7 @@ int bacnet_double_application_encode( * @param apdu_size - number of bytes in the buffer * @param value - decoded value, if decoded * - * @return number of bytes decoded, zero if wrong tag number, + * @return number of bytes decoded, zero if tag mismatch, * or #BACNET_STATUS_ERROR (-1) if malformed */ int bacnet_double_application_decode( @@ -3916,9 +4001,12 @@ int bacnet_double_application_decode( int len = 0; BACNET_TAG tag = { 0 }; + if (apdu_size == 0) { + return 0; + } len = bacnet_tag_decode(apdu, apdu_size, &tag); - if ((len > 0) && tag.application) { - if (tag.number == BACNET_APPLICATION_TAG_DOUBLE) { + if (len > 0) { + if (tag.application && (tag.number == BACNET_APPLICATION_TAG_DOUBLE)) { apdu_len = len; len = bacnet_double_decode( &apdu[apdu_len], apdu_size - apdu_len, tag.len_value_type, @@ -4083,7 +4171,7 @@ int bacnet_time_decode( * @param tag_value - context tag number expected * @param value - the value decoded, if decoded * - * @return number of bytes decoded, zero if wrong tag number, + * @return number of bytes decoded, zero if tag mismatch, * or error (-1) if malformed */ int bacnet_time_context_decode( @@ -4096,9 +4184,12 @@ int bacnet_time_context_decode( int len = 0; BACNET_TAG tag = { 0 }; + if (apdu_size == 0) { + return 0; + } len = bacnet_tag_decode(apdu, apdu_size, &tag); - if ((len > 0) && tag.context) { - if (tag.number == tag_value) { + if (len > 0) { + if (tag.context && (tag.number == tag_value)) { apdu_len = len; len = bacnet_time_decode( &apdu[apdu_len], apdu_size - apdu_len, tag.len_value_type, @@ -4152,7 +4243,7 @@ int bacnet_time_application_encode( * @param apdu_size - number of bytes in the buffer * @param value - decoded value, if decoded * - * @return number of bytes decoded, zero if wrong tag number, + * @return number of bytes decoded, zero if tag mismatch, * or #BACNET_STATUS_ERROR (-1) if malformed */ int bacnet_time_application_decode( @@ -4162,9 +4253,12 @@ int bacnet_time_application_decode( int len = 0; BACNET_TAG tag = { 0 }; + if (apdu_size == 0) { + return 0; + } len = bacnet_tag_decode(apdu, apdu_size, &tag); - if ((len > 0) && tag.application) { - if (tag.number == BACNET_APPLICATION_TAG_TIME) { + if (len > 0) { + if (tag.application && (tag.number == BACNET_APPLICATION_TAG_TIME)) { apdu_len = len; len = bacnet_time_decode( &apdu[apdu_len], apdu_size - apdu_len, tag.len_value_type, @@ -4464,7 +4558,7 @@ int bacnet_date_decode( * @param tag_value - context tag number expected * @param value - the value decoded, if decoded * - * @return number of bytes decoded, zero if wrong tag number, + * @return number of bytes decoded, zero if tag mismatch, * or error (-1) if malformed */ int bacnet_date_context_decode( @@ -4477,9 +4571,12 @@ int bacnet_date_context_decode( int len = 0; BACNET_TAG tag = { 0 }; + if (apdu_size == 0) { + return 0; + } len = bacnet_tag_decode(apdu, apdu_size, &tag); - if ((len > 0) && tag.context) { - if (tag.number == tag_value) { + if (len > 0) { + if (tag.context && (tag.number == tag_value)) { apdu_len = len; len = bacnet_date_decode( &apdu[apdu_len], apdu_size - apdu_len, tag.len_value_type, @@ -4533,7 +4630,7 @@ int bacnet_date_application_encode( * @param apdu_size - number of bytes in the buffer * @param value - decoded value, if decoded * - * @return number of bytes decoded, zero if wrong tag number, + * @return number of bytes decoded, zero if tag mismatch, * or #BACNET_STATUS_ERROR (-1) if malformed */ int bacnet_date_application_decode( @@ -4543,9 +4640,12 @@ int bacnet_date_application_decode( int len = 0; BACNET_TAG tag = { 0 }; + if (apdu_size == 0) { + return 0; + } len = bacnet_tag_decode(apdu, apdu_size, &tag); - if ((len > 0) && tag.application) { - if (tag.number == BACNET_APPLICATION_TAG_DATE) { + if (len > 0) { + if (tag.application && (tag.number == BACNET_APPLICATION_TAG_DATE)) { apdu_len = len; len = bacnet_date_decode( &apdu[len], apdu_size - apdu_len, tag.len_value_type, value); diff --git a/src/bacnet/bacdcode.h b/src/bacnet/bacdcode.h index 87077405..afc215b0 100644 --- a/src/bacnet/bacdcode.h +++ b/src/bacnet/bacdcode.h @@ -340,6 +340,12 @@ int bacnet_object_id_context_decode( uint8_t tag_value, BACNET_OBJECT_TYPE *object_type, uint32_t *instance); +BACNET_STACK_EXPORT +bool bacnet_object_id_same( + BACNET_OBJECT_TYPE object_type1, + uint32_t instance1, + BACNET_OBJECT_TYPE object_type2, + uint32_t instance2); BACNET_STACK_EXPORT int encode_octet_string(uint8_t *apdu, const BACNET_OCTET_STRING *octet_string); diff --git a/src/bacnet/bacdest.c b/src/bacnet/bacdest.c index b8666137..d76bb7c1 100644 --- a/src/bacnet/bacdest.c +++ b/src/bacnet/bacdest.c @@ -248,33 +248,10 @@ int bacnet_destination_encode( if (apdu) { apdu += len; } - if (destination->Recipient.tag == BACNET_RECIPIENT_TAG_DEVICE) { - len = encode_context_object_id( - apdu, 0, OBJECT_DEVICE, - destination->Recipient.type.device.instance); - apdu_len += len; - if (apdu) { - apdu += len; - } - } else if (destination->Recipient.tag == BACNET_RECIPIENT_TAG_ADDRESS) { - /* opening tag 1 */ - len = encode_opening_tag(apdu, 1); - apdu_len += len; - if (apdu) { - apdu += len; - } - len = encode_bacnet_address( - apdu, &destination->Recipient.type.address); - apdu_len += len; - if (apdu) { - apdu += len; - } - /* closing tag 1 */ - len = encode_closing_tag(apdu, 1); - apdu_len += len; - if (apdu) { - apdu += len; - } + len = bacnet_recipient_encode(apdu, &destination->Recipient); + apdu_len += len; + if (apdu) { + apdu += len; } /* Process Identifier - Unsigned32 */ len = encode_application_unsigned(apdu, destination->ProcessIdentifier); @@ -350,112 +327,253 @@ int bacnet_destination_decode( const uint8_t *apdu, int apdu_size, BACNET_DESTINATION *destination) { int len = 0, apdu_len = 0; - BACNET_APPLICATION_DATA_VALUE value = { 0 }; + BACNET_BIT_STRING bitstring = { 0 }; + BACNET_TIME btime = { 0 }; + BACNET_RECIPIENT recipient = { 0 }; + BACNET_UNSIGNED_INTEGER unsigned_value = 0; + bool boolean_value = false; if (!apdu) { return BACNET_STATUS_REJECT; } - if (!destination) { - return BACNET_STATUS_REJECT; - } /* Decode Valid Days */ - len = bacapp_decode_application_data(apdu, apdu_size, &value); - if ((len == 0) || (len == BACNET_STATUS_ERROR) || - (value.tag != BACNET_APPLICATION_TAG_BIT_STRING)) { + len = bacnet_bitstring_application_decode( + &apdu[apdu_len], apdu_size - apdu_len, &bitstring); + if (len <= 0) { return BACNET_STATUS_REJECT; } - bitstring_copy(&destination->ValidDays, &value.type.Bit_String); + if (destination) { + bitstring_copy(&destination->ValidDays, &bitstring); + } apdu_len += len; - apdu += len; /* Decode From Time */ - len = bacapp_decode_application_data(apdu, apdu_size, &value); - if ((len == 0) || (len == BACNET_STATUS_ERROR) || - (value.tag != BACNET_APPLICATION_TAG_TIME)) { + len = bacnet_time_application_decode( + &apdu[apdu_len], apdu_size - apdu_len, &btime); + if (len <= 0) { return BACNET_STATUS_REJECT; } - /* store value */ - datetime_copy_time(&destination->FromTime, &value.type.Time); + if (destination) { + datetime_copy_time(&destination->FromTime, &btime); + } apdu_len += len; - apdu += len; /* Decode To Time */ - len = bacapp_decode_application_data(apdu, apdu_size, &value); - if ((len == 0) || (len == BACNET_STATUS_ERROR) || - (value.tag != BACNET_APPLICATION_TAG_TIME)) { + len = bacnet_time_application_decode( + &apdu[apdu_len], apdu_size - apdu_len, &btime); + if (len <= 0) { return BACNET_STATUS_REJECT; } - /* store value */ - datetime_copy_time(&destination->ToTime, &value.type.Time); + if (destination) { + datetime_copy_time(&destination->ToTime, &btime); + } apdu_len += len; - apdu += len; - if (decode_is_context_tag(apdu, BACNET_RECIPIENT_TAG_DEVICE)) { - /* device [0] BACnetObjectIdentifier */ - destination->Recipient.tag = BACNET_RECIPIENT_TAG_DEVICE; - len = decode_context_object_id( - apdu, BACNET_RECIPIENT_TAG_DEVICE, - &destination->Recipient.type.device.type, - &destination->Recipient.type.device.instance); - if (len == BACNET_STATUS_ERROR) { - return BACNET_STATUS_REJECT; - } - if (destination->Recipient.type.device.type != OBJECT_DEVICE) { - return BACNET_STATUS_REJECT; - } + /* Recipient */ + len = bacnet_recipient_decode( + &apdu[apdu_len], apdu_size - apdu_len, &recipient); + if (len < 0) { + return BACNET_STATUS_REJECT; + } + if (destination) { + bacnet_recipient_copy(&destination->Recipient, &recipient); + } + apdu_len += len; + /* Process Identifier */ + len = bacnet_unsigned_application_decode( + &apdu[apdu_len], apdu_size - apdu_len, &unsigned_value); + if (len <= 0) { + return BACNET_STATUS_REJECT; + } + if (destination) { + destination->ProcessIdentifier = unsigned_value; + } + apdu_len += len; + /* Issue Confirmed Notifications */ + len = bacnet_boolean_application_decode( + &apdu[apdu_len], apdu_size - apdu_len, &boolean_value); + if (len <= 0) { + return BACNET_STATUS_REJECT; + } + if (destination) { + destination->ConfirmedNotify = boolean_value; + } + apdu_len += len; + /* Transitions */ + len = bacnet_bitstring_application_decode( + &apdu[apdu_len], apdu_size - apdu_len, &bitstring); + if (len <= 0) { + return BACNET_STATUS_REJECT; + } + if (destination) { + bitstring_copy(&destination->Transitions, &bitstring); + } + apdu_len += len; + + return apdu_len; +} + +/** + * @brief Encode the BACnetRecipient complex data + * + * BACnetRecipient ::= CHOICE { + * device [0] BACnetObjectIdentifier, + * address [1] BACnetAddress + * } + * + * @param apdu Pointer to the buffer for encoding. + * @param recipient Pointer to the property data to be encoded. + * + * @return bytes encoded or zero on error. + */ +int bacnet_recipient_encode(uint8_t *apdu, const BACNET_RECIPIENT *recipient) +{ + int apdu_len = 0, len = 0; + + if (recipient->tag == BACNET_RECIPIENT_TAG_DEVICE) { + len = encode_context_object_id( + apdu, 0, OBJECT_DEVICE, recipient->type.device.instance); apdu_len += len; - apdu += len; - } else if (decode_is_opening_tag_number( - apdu, BACNET_RECIPIENT_TAG_ADDRESS)) { - /* address [1] BACnetAddress */ - destination->Recipient.tag = BACNET_RECIPIENT_TAG_ADDRESS; - /* opening tag [1] is len 1 */ - len = 1; + } else if (recipient->tag == BACNET_RECIPIENT_TAG_ADDRESS) { + /* opening tag 1 */ + len = encode_opening_tag(apdu, 1); apdu_len += len; - apdu += len; - len = decode_bacnet_address(apdu, &destination->Recipient.type.address); - if ((len == 0) || (len == BACNET_STATUS_ERROR)) { - return BACNET_STATUS_REJECT; - } - apdu_len += len; - apdu += len; - /* closing tag [1] */ - if (decode_is_closing_tag_number(apdu, BACNET_RECIPIENT_TAG_ADDRESS)) { - /* closing tag [1] is len 1 */ - len = 1; - apdu_len += len; + if (apdu) { apdu += len; + } + len = encode_bacnet_address(apdu, &recipient->type.address); + apdu_len += len; + if (apdu) { + apdu += len; + } + /* closing tag 1 */ + len = encode_closing_tag(apdu, 1); + apdu_len += len; + } + + return apdu_len; +} + +/** + * @brief Encode a BACnetRecipient complex data type + * @param apdu - the APDU buffer + * @param tag_number - context tag number + * @param recipient Pointer to the property data to be encoded. + * @return length of the APDU buffer, or 0 if not able to encode + */ +int bacnet_recipient_context_encode( + uint8_t *apdu, uint8_t tag_number, const BACNET_RECIPIENT *recipient) +{ + int len = 0; + int apdu_len = 0; + + if (recipient) { + len = encode_opening_tag(apdu, tag_number); + apdu_len += len; + if (apdu) { + apdu += len; + } + len = bacnet_recipient_encode(apdu, recipient); + apdu_len += len; + if (apdu) { + apdu += len; + } + len = encode_closing_tag(apdu, tag_number); + apdu_len += len; + } + + return apdu_len; +} + +/** + * @brief Decode the BACnetRecipient complex data + * + * BACnetRecipient ::= CHOICE { + * device [0] BACnetObjectIdentifier, + * address [1] BACnetAddress + * } + * + * @param apdu Pointer to the buffer for decoding. + * @param apdu_size Count of valid bytes in the buffer. + * @param recipient Pointer to the property data to be decoded, or NULL for + * decoding to determine the length. + * + * @return bytes encoded or #BACNET_STATUS_REJECT on error. + */ +int bacnet_recipient_decode( + const uint8_t *apdu, int apdu_size, BACNET_RECIPIENT *recipient) +{ + int len = 0, apdu_len = 0; + BACNET_OBJECT_TYPE object_type = OBJECT_DEVICE; + uint32_t instance = 0; + BACNET_ADDRESS address; + + if (!apdu) { + return BACNET_STATUS_REJECT; + } + /* device [0] BACnetObjectIdentifier */ + len = bacnet_object_id_context_decode( + &apdu[apdu_len], apdu_size - apdu_len, BACNET_RECIPIENT_TAG_DEVICE, + &object_type, &instance); + if (len > 0) { + if (object_type != OBJECT_DEVICE) { + return BACNET_STATUS_REJECT; + } + if (recipient) { + recipient->tag = BACNET_RECIPIENT_TAG_DEVICE; + recipient->type.device.type = object_type; + recipient->type.device.instance = instance; + } + apdu_len += len; + } else { + len = bacnet_address_context_decode( + &apdu[apdu_len], apdu_size - apdu_len, BACNET_RECIPIENT_TAG_ADDRESS, + &address); + if (len > 0) { + if (recipient) { + recipient->tag = BACNET_RECIPIENT_TAG_ADDRESS; + bacnet_address_copy(&recipient->type.address, &address); + } + apdu_len += len; } else { return BACNET_STATUS_REJECT; } - } else { - return BACNET_STATUS_REJECT; } - /* Process Identifier */ - len = bacapp_decode_application_data(apdu, apdu_size, &value); - if ((len == 0) || (len == BACNET_STATUS_ERROR) || - (value.tag != BACNET_APPLICATION_TAG_UNSIGNED_INT)) { - return BACNET_STATUS_REJECT; + + return apdu_len; +} + +/** + * @brief Decode a time stamp and check for opening and closing tags. + * @param apdu Pointer to the APDU buffer. + * @param apdu_size - the APDU buffer length + * @param tag_number The tag number that shall + * hold the time stamp. + * @param value Pointer to the variable that shall + * take the time stamp values. + * @return number of bytes decoded, zero if tag mismatch, + * or BACNET_STATUS_ERROR if an error occurs + */ +int bacnet_recipient_context_decode( + const uint8_t *apdu, + uint32_t apdu_size, + uint8_t tag_number, + BACNET_RECIPIENT *value) +{ + int len = 0; + int apdu_len = 0; + + if (!bacnet_is_opening_tag_number( + &apdu[apdu_len], apdu_size - apdu_len, tag_number, &len)) { + return 0; } - /* store value */ - destination->ProcessIdentifier = value.type.Unsigned_Int; apdu_len += len; - apdu += len; - /* Issue Confirmed Notifications */ - len = bacapp_decode_application_data(apdu, apdu_size, &value); - if ((len == 0) || (len == BACNET_STATUS_ERROR) || - (value.tag != BACNET_APPLICATION_TAG_BOOLEAN)) { - return BACNET_STATUS_REJECT; + len = bacnet_recipient_decode(&apdu[apdu_len], apdu_size - apdu_len, value); + if (len < 0) { + return BACNET_STATUS_ERROR; } - /* store value */ - destination->ConfirmedNotify = value.type.Boolean; apdu_len += len; - apdu += len; - /* Transitions */ - len = bacapp_decode_application_data(apdu, apdu_size, &value); - if ((len == 0) || (len == BACNET_STATUS_ERROR) || - (value.tag != BACNET_APPLICATION_TAG_BIT_STRING)) { - return BACNET_STATUS_REJECT; + if (!bacnet_is_closing_tag_number( + &apdu[apdu_len], apdu_size - apdu_len, tag_number, &len)) { + return BACNET_STATUS_ERROR; } - /* store value */ - bitstring_copy(&destination->Transitions, &value.type.Bit_String); apdu_len += len; return apdu_len; diff --git a/src/bacnet/bacdest.h b/src/bacnet/bacdest.h index 25e12d8e..fbe6b225 100644 --- a/src/bacnet/bacdest.h +++ b/src/bacnet/bacdest.h @@ -91,6 +91,21 @@ bool bacnet_recipient_device_wildcard(const BACNET_RECIPIENT *recipient); BACNET_STACK_EXPORT bool bacnet_recipient_device_valid(const BACNET_RECIPIENT *recipient); +BACNET_STACK_EXPORT +int bacnet_recipient_encode(uint8_t *apdu, const BACNET_RECIPIENT *recipient); +BACNET_STACK_EXPORT +int bacnet_recipient_context_encode( + uint8_t *apdu, uint8_t tag_number, const BACNET_RECIPIENT *recipient); +BACNET_STACK_EXPORT +int bacnet_recipient_decode( + const uint8_t *apdu, int apdu_size, BACNET_RECIPIENT *recipient); +BACNET_STACK_EXPORT +int bacnet_recipient_context_decode( + const uint8_t *apdu, + uint32_t apdu_size, + uint8_t tag_number, + BACNET_RECIPIENT *value); + BACNET_STACK_EXPORT int bacnet_destination_to_ascii( const BACNET_DESTINATION *bacdest, char *buf, size_t buf_size); diff --git a/src/bacnet/bacdevobjpropref.c b/src/bacnet/bacdevobjpropref.c index f155cdfc..fcf04b58 100644 --- a/src/bacnet/bacdevobjpropref.c +++ b/src/bacnet/bacdevobjpropref.c @@ -132,7 +132,8 @@ int bacapp_encode_device_obj_property_ref( * @param apdu_size Size of the buffer containing the encoded value * @param value Pointer to the structure which contains the decoded value * - * @return number of bytes decoded or BACNET_STATUS_ERROR on failure. + * @return number of bytes decoded, zero if tag mismatch, + * or #BACNET_STATUS_ERROR (-1) if malformed */ int bacnet_device_object_property_reference_decode( const uint8_t *apdu, @@ -141,7 +142,6 @@ int bacnet_device_object_property_reference_decode( { int apdu_len = 0; int len = 0; - uint32_t len_value_type = 0; BACNET_UNSIGNED_INTEGER array_index = 0; BACNET_OBJECT_TYPE object_type = 0; uint32_t object_instance = 0; @@ -161,7 +161,7 @@ int bacnet_device_object_property_reference_decode( value->objectIdentifier.type = object_type; } } else { - return BACNET_STATUS_ERROR; + return len; } /* property-identifier [1] BACnetPropertyIdentifier */ len = bacnet_enumerated_context_decode( @@ -175,20 +175,15 @@ int bacnet_device_object_property_reference_decode( return BACNET_STATUS_ERROR; } /* property-array-index [2] Unsigned OPTIONAL */ - if (bacnet_is_context_tag_number( - &apdu[apdu_len], apdu_size - apdu_len, 2, &len, &len_value_type)) { + len = bacnet_unsigned_context_decode( + &apdu[apdu_len], apdu_size - apdu_len, 2, &array_index); + if (len > 0) { apdu_len += len; - len = bacnet_unsigned_decode( - &apdu[apdu_len], apdu_size - apdu_len, len_value_type, - &array_index); - if (len > 0) { - apdu_len += len; - if (value) { - value->arrayIndex = array_index; - } - } else { - return BACNET_STATUS_ERROR; + if (value) { + value->arrayIndex = array_index; } + } else if (len < 0) { + return BACNET_STATUS_ERROR; } else { /* OPTIONAL - skip apdu_len increment */ if (value) { @@ -196,21 +191,17 @@ int bacnet_device_object_property_reference_decode( } } /* device-identifier [3] BACnetObjectIdentifier OPTIONAL */ - if (bacnet_is_context_tag_number( - &apdu[apdu_len], apdu_size - apdu_len, 3, &len, &len_value_type)) { + len = bacnet_object_id_context_decode( + &apdu[apdu_len], apdu_size - apdu_len, 3, &object_type, + &object_instance); + if (len > 0) { apdu_len += len; - len = bacnet_object_id_decode( - &apdu[apdu_len], apdu_size - apdu_len, len_value_type, &object_type, - &object_instance); - if (len > 0) { - apdu_len += len; - if (value) { - value->deviceIdentifier.type = object_type; - value->deviceIdentifier.instance = object_instance; - } - } else { - return BACNET_STATUS_ERROR; + if (value) { + value->deviceIdentifier.type = object_type; + value->deviceIdentifier.instance = object_instance; } + } else if (len < 0) { + return BACNET_STATUS_ERROR; } else { /* OPTIONAL - skip apdu_len increment */ if (value) { @@ -231,7 +222,8 @@ int bacnet_device_object_property_reference_decode( * @param tag_number Tag number * @param value Pointer to the structure which contains the decoded value * - * @return number of bytes decoded or BACNET_STATUS_ERROR on failure. + * @return number of bytes decoded, zero if tag mismatch, + * or #BACNET_STATUS_ERROR (-1) if malformed */ int bacnet_device_object_property_reference_context_decode( const uint8_t *apdu, @@ -261,8 +253,6 @@ int bacnet_device_object_property_reference_context_decode( } else { return BACNET_STATUS_ERROR; } - } else { - return BACNET_STATUS_ERROR; } return apdu_len; @@ -450,7 +440,6 @@ int bacnet_device_object_reference_decode( { int len; int apdu_len = 0; - uint32_t len_value_type = 0; BACNET_OBJECT_TYPE object_type = 0; uint32_t object_instance = 0; @@ -458,21 +447,17 @@ int bacnet_device_object_reference_decode( return BACNET_STATUS_ERROR; } /* device-identifier [0] BACnetObjectIdentifier OPTIONAL */ - if (bacnet_is_context_tag_number( - &apdu[apdu_len], apdu_size - apdu_len, 0, &len, &len_value_type)) { + len = bacnet_object_id_context_decode( + &apdu[apdu_len], apdu_size - apdu_len, 0, &object_type, + &object_instance); + if (len > 0) { apdu_len += len; - len = bacnet_object_id_decode( - &apdu[apdu_len], apdu_size - apdu_len, len_value_type, &object_type, - &object_instance); - if (len > 0) { - apdu_len += len; - if (value) { - value->deviceIdentifier.instance = object_instance; - value->deviceIdentifier.type = object_type; - } - } else { - return BACNET_STATUS_ERROR; + if (value) { + value->deviceIdentifier.instance = object_instance; + value->deviceIdentifier.type = object_type; } + } else if (len < 0) { + return BACNET_STATUS_ERROR; } else { /* OPTIONAL - skip apdu_len increment */ value->deviceIdentifier.type = BACNET_NO_DEV_TYPE; @@ -504,7 +489,8 @@ int bacnet_device_object_reference_decode( * @param tag_number Tag number * @param value Pointer to the structure containing the decoded value * - * @return number of bytes decoded or BACNET_STATUS_ERROR on failure. + * @return number of bytes decoded, zero if wrong tag number, + * or #BACNET_STATUS_ERROR (-1) if malformed */ int bacnet_device_object_reference_context_decode( const uint8_t *apdu, @@ -534,8 +520,6 @@ int bacnet_device_object_reference_context_decode( } else { return BACNET_STATUS_ERROR; } - } else { - return BACNET_STATUS_ERROR; } return apdu_len; @@ -704,7 +688,8 @@ int bacapp_encode_context_obj_property_ref( * @param apdu Pointer to the buffer containing the encoded value * @param apdu_size Size of the buffer containing the encoded value * @param reference - BACnetObjectPropertyReference to decode into - * @return number of bytes decoded or BACNET_STATUS_ERROR on failure. + * @return number of bytes decoded, zero if tag mismatch, + * or BACNET_STATUS_ERROR on failure. */ int bacapp_decode_obj_property_ref( const uint8_t *apdu, @@ -727,7 +712,7 @@ int bacapp_decode_obj_property_ref( if (len > 0) { apdu_len += len; } else { - return BACNET_STATUS_ERROR; + return len; } /* property-identifier [1] BACnetPropertyIdentifier */ len = bacnet_enumerated_context_decode( @@ -735,7 +720,7 @@ int bacapp_decode_obj_property_ref( if (len > 0) { apdu_len += len; } else { - return BACNET_STATUS_ERROR; + return len; } if (reference) { reference->object_identifier.type = object_identifier.type; @@ -744,21 +729,18 @@ int bacapp_decode_obj_property_ref( (BACNET_PROPERTY_ID)property_identifier; } /* property-array-index [2] Unsigned OPTIONAL */ - if (bacnet_is_opening_tag_number( - &apdu[apdu_len], apdu_size - apdu_len, 2, NULL)) { - len = bacnet_unsigned_context_decode( - &apdu[apdu_len], apdu_size - apdu_len, 2, &unsigned_value); - if (len > 0) { - apdu_len += len; - if (unsigned_value > UINT32_MAX) { - return BACNET_STATUS_ERROR; - } - if (reference) { - reference->property_array_index = unsigned_value; - } - } else { + len = bacnet_unsigned_context_decode( + &apdu[apdu_len], apdu_size - apdu_len, 2, &unsigned_value); + if (len > 0) { + apdu_len += len; + if (unsigned_value > UINT32_MAX) { return BACNET_STATUS_ERROR; } + if (reference) { + reference->property_array_index = unsigned_value; + } + } else if (len < 0) { + return BACNET_STATUS_ERROR; } else { /* OPTIONAL - skip apdu_len increment */ if (reference) { @@ -778,7 +760,8 @@ int bacapp_decode_obj_property_ref( * @param tag_number Tag number * @param value Pointer to the structure that shall be decoded into. * - * @return number of bytes decoded or BACNET_STATUS_ERROR on failure. + * @return number of bytes decoded, zero if wrong tag number, + * or #BACNET_STATUS_ERROR (-1) if malformed */ int bacapp_decode_context_obj_property_ref( const uint8_t *apdu, @@ -794,7 +777,7 @@ int bacapp_decode_context_obj_property_ref( } if (!bacnet_is_opening_tag_number( &apdu[apdu_len], apdu_size - apdu_len, tag_number, &len)) { - return BACNET_STATUS_ERROR; + return 0; } apdu_len += len; len = bacapp_decode_obj_property_ref( @@ -838,3 +821,193 @@ bool bacnet_object_property_reference_same( return status; } + +/** + * @brief Encode a BACnetPropertyReference into a buffer + * + * BACnetPropertyReference ::= SEQUENCE { + * propertyIdentifier [0] BACnetPropertyIdentifier, + * propertyArrayIndex [1] Unsigned OPTIONAL + * -- used only with array datatype + * -- if omitted with an array the entire array is referenced + * } + * + * @param apdu - the APDU buffer, or NULL for length + * @param reference - BACnetPropertyReference + * @return length of the APDU buffer + */ +int bacnet_property_reference_encode( + uint8_t *apdu, const struct BACnetPropertyReference *reference) +{ + int len = 0; + int apdu_len = 0; + + if (!reference) { + return 0; + } + len = encode_context_enumerated(apdu, 0, reference->property_identifier); + apdu_len += len; + if (apdu) { + apdu += len; + } + if (reference->property_array_index != BACNET_ARRAY_ALL) { + len = encode_context_unsigned(apdu, 1, reference->property_array_index); + apdu_len += len; + } + + return apdu_len; +} + +/** + * @brief Encode a BACnetPropertyReference into a buffer + * BACnetPropertyReference ::= SEQUENCE { + * propertyIdentifier [0] BACnetPropertyIdentifier, + * propertyArrayIndex [1] Unsigned OPTIONAL + * -- used only with array datatype + * -- if omitted with an array the entire array is referenced + * } + * + * @param apdu - the APDU buffer, or NULL for length + * @param tag_number - context tag number to be encoded + * @param reference - BACnetPropertyReference + * @return length of the APDU buffer + */ +int bacnet_property_reference_context_encode( + uint8_t *apdu, + uint8_t tag_number, + const struct BACnetPropertyReference *reference) +{ + int len = 0; + int apdu_len = 0; + + len = encode_opening_tag(apdu, tag_number); + apdu_len += len; + if (apdu) { + apdu += len; + } + + len = bacnet_property_reference_encode(apdu, reference); + apdu_len += len; + if (apdu) { + apdu += len; + } + len = encode_closing_tag(apdu, tag_number); + apdu_len += len; + + return apdu_len; +} + +/** + * @brief Compare the complex data of value1 and value2 + * @param value1 - value 1 structure + * @param value2 - value 2 structure + * @return true if the values are the same + */ +bool bacnet_property_reference_same( + const struct BACnetPropertyReference *value1, + const struct BACnetPropertyReference *value2) +{ + bool status = false; + + if (value1 && value2) { + if ((value1->property_identifier == value2->property_identifier) && + (value1->property_array_index == value2->property_array_index)) { + status = true; + } + } + + return status; +} + +/** + * @brief Decode a BACnetPropertyReference from a buffer + * @param apdu - the APDU buffer + * @param apdu_size - the size of the APDU buffer + * @param reference - BACnetPropertyReference to decode into + * @return number of bytes decoded or BACNET_STATUS_ERROR on failure. + */ +int bacnet_property_reference_decode( + const uint8_t *apdu, + uint32_t apdu_size, + struct BACnetPropertyReference *value) +{ + int apdu_len = 0; + int len = 0; + uint32_t property_identifier = 0; + BACNET_UNSIGNED_INTEGER unsigned_value; + + if (!apdu) { + return BACNET_STATUS_ERROR; + } + /* propertyIdentifier [0] BACnetPropertyIdentifier */ + len = bacnet_enumerated_context_decode( + &apdu[apdu_len], apdu_size - apdu_len, 0, &property_identifier); + if (len > 0) { + apdu_len += len; + if (value) { + value->property_identifier = property_identifier; + } + } else { + return len; + } + /* propertyArrayIndex [1] Unsigned OPTIONAL */ + len = bacnet_unsigned_context_decode( + &apdu[apdu_len], apdu_size - apdu_len, 1, &unsigned_value); + if (len > 0) { + apdu_len += len; + if (value) { + value->property_array_index = unsigned_value; + } + } else { + /* OPTIONAL - skip apdu_len increment */ + if (value) { + value->property_array_index = BACNET_ARRAY_ALL; + } + } + + return apdu_len; +} + +/** + * @brief Decode the context property reference. Check for + * an opening tag and a closing tag as well. + * @param apdu - the APDU buffer + * @param apdu_size - the size of the APDU buffer + * @param tag_number - the tag number + * @param value - BACnetPropertyReference to decode into + * @return number of bytes decoded, zero if wrong tag number, + * or #BACNET_STATUS_ERROR (-1) if malformed + */ +int bacnet_property_reference_context_decode( + const uint8_t *apdu, + uint32_t apdu_size, + uint8_t tag_number, + struct BACnetPropertyReference *value) +{ + int len = 0; + int apdu_len = 0; + + if (!apdu) { + return BACNET_STATUS_ERROR; + } + if (!bacnet_is_opening_tag_number( + &apdu[apdu_len], apdu_size - apdu_len, tag_number, &len)) { + return 0; + } + apdu_len += len; + len = bacnet_property_reference_decode( + &apdu[apdu_len], apdu_size - apdu_len, value); + if (len > 0) { + apdu_len += len; + if (bacnet_is_closing_tag_number( + &apdu[apdu_len], apdu_size - apdu_len, tag_number, &len)) { + apdu_len += len; + } else { + return BACNET_STATUS_ERROR; + } + } else { + return BACNET_STATUS_ERROR; + } + + return apdu_len; +} diff --git a/src/bacnet/bacdevobjpropref.h b/src/bacnet/bacdevobjpropref.h index 5dfe4d44..cff92ba3 100644 --- a/src/bacnet/bacdevobjpropref.h +++ b/src/bacnet/bacdevobjpropref.h @@ -43,7 +43,7 @@ typedef struct BACnetDeviceObjectReference { * -- if omitted with an array the entire array is referenced * } */ -typedef struct BACnet_Object_Property_Reference { +typedef struct BACnetObjectPropertyReference { /* note: use type = OBJECT_NONE for unused reference */ BACNET_OBJECT_ID object_identifier; BACNET_PROPERTY_ID property_identifier; @@ -51,6 +51,19 @@ typedef struct BACnet_Object_Property_Reference { BACNET_ARRAY_INDEX property_array_index; } BACNET_OBJECT_PROPERTY_REFERENCE; +/** + * BACnetPropertyReference ::= SEQUENCE { + * propertyIdentifier [0] BACnetPropertyIdentifier, + * propertyArrayIndex [1] Unsigned OPTIONAL + * -- used only with array datatype + * -- if omitted with an array the entire array is referenced + * } + */ +struct BACnetPropertyReference { + BACNET_PROPERTY_ID property_identifier; + BACNET_ARRAY_INDEX property_array_index; +}; + #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ @@ -161,6 +174,30 @@ bool bacnet_object_property_reference_same( const BACNET_OBJECT_PROPERTY_REFERENCE *value1, const BACNET_OBJECT_PROPERTY_REFERENCE *value2); +BACNET_STACK_EXPORT +int bacnet_property_reference_encode( + uint8_t *apdu, const struct BACnetPropertyReference *reference); +BACNET_STACK_EXPORT +int bacnet_property_reference_context_encode( + uint8_t *apdu, + uint8_t tag_number, + const struct BACnetPropertyReference *reference); +BACNET_STACK_EXPORT +bool bacnet_property_reference_same( + const struct BACnetPropertyReference *value1, + const struct BACnetPropertyReference *value2); +BACNET_STACK_EXPORT +int bacnet_property_reference_decode( + const uint8_t *apdu, + uint32_t apdu_size, + struct BACnetPropertyReference *value); +BACNET_STACK_EXPORT +int bacnet_property_reference_context_decode( + const uint8_t *apdu, + uint32_t apdu_size, + uint8_t tag_number, + struct BACnetPropertyReference *value); + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/src/bacnet/timestamp.c b/src/bacnet/timestamp.c index 5c1985ad..1424762d 100644 --- a/src/bacnet/timestamp.c +++ b/src/bacnet/timestamp.c @@ -305,7 +305,8 @@ int bacapp_decode_timestamp(const uint8_t *apdu, BACNET_TIMESTAMP *value) * hold the time stamp. * @param value Pointer to the variable that shall * take the time stamp values. - * @return number of bytes decoded, or BACNET_STATUS_ERROR if an error occurs + * @return number of bytes decoded, zero if tag mismatch, + * or #BACNET_STATUS_ERROR (-1) if malformed */ int bacnet_timestamp_context_decode( const uint8_t *apdu, @@ -316,9 +317,12 @@ int bacnet_timestamp_context_decode( int len = 0; int apdu_len = 0; + if (!apdu) { + return BACNET_STATUS_ERROR; + } if (!bacnet_is_opening_tag_number( &apdu[apdu_len], apdu_size - apdu_len, tag_number, &len)) { - return BACNET_STATUS_ERROR; + return 0; } apdu_len += len; len = bacnet_timestamp_decode(&apdu[apdu_len], apdu_size - apdu_len, value); diff --git a/test/bacnet/bacdcode/src/main.c b/test/bacnet/bacdcode/src/main.c index bbd434f2..d73071b3 100644 --- a/test/bacnet/bacdcode/src/main.c +++ b/test/bacnet/bacdcode/src/main.c @@ -428,7 +428,7 @@ static void testBACDCodeReal(void) while (apdu_len) { apdu_len--; len = bacnet_real_application_decode(apdu, apdu_len, NULL); - zassert_equal(len, BACNET_STATUS_ERROR, NULL); + zassert_true(len <= 0, NULL); } apdu_len = bacnet_real_application_encode(apdu, sizeof(apdu), value); null_len = bacnet_real_application_encode(NULL, sizeof(apdu), value); @@ -497,7 +497,7 @@ static void testBACDCodeDouble(void) while (apdu_len) { apdu_len--; len = bacnet_double_application_decode(apdu, apdu_len, NULL); - zassert_equal(len, BACNET_STATUS_ERROR, NULL); + zassert_true(len <= 0, NULL); } apdu_len = bacnet_double_application_encode(apdu, sizeof(apdu), value); null_len = bacnet_double_application_encode(NULL, sizeof(apdu), value); @@ -558,7 +558,7 @@ static void testBACnetDateDecodes(void) zassert_equal(value.year, test_value.year, NULL); while (--test_len) { len = bacnet_date_application_decode(apdu, test_len, &test_value); - zassert_equal(len, BACNET_STATUS_ERROR, NULL); + zassert_true(len <= 0, NULL); } while (--apdu_len) { len = bacnet_date_application_encode(apdu, apdu_len, &value); @@ -684,7 +684,7 @@ static void test_bacnet_unsigned_value_codec(BACNET_UNSIGNED_INTEGER value) while (apdu_len) { apdu_len--; test_len = bacnet_unsigned_application_decode(apdu, apdu_len, NULL); - zassert_equal(test_len, BACNET_STATUS_ERROR, NULL); + zassert_true(test_len <= 0, NULL); } apdu_len = bacnet_unsigned_application_encode(apdu, sizeof(apdu), value); null_len = bacnet_unsigned_application_encode(NULL, sizeof(apdu), value); @@ -818,7 +818,7 @@ static void testBACDCodeSignedValue(int32_t value) while (len) { len--; test_len = bacnet_signed_application_decode(apdu, len, NULL); - zassert_equal(test_len, BACNET_STATUS_ERROR, NULL); + zassert_true(test_len <= 0, NULL); } apdu_len = bacnet_signed_application_encode(apdu, sizeof(apdu), value); null_len = bacnet_signed_application_encode(NULL, sizeof(apdu), value); @@ -975,7 +975,7 @@ static void testBACDCodeOctetString(void) zassert_true(octetstring_value_same(&value, &test_value), NULL); while (--test_len) { len = bacnet_octet_string_application_decode(apdu, test_len, NULL); - zassert_equal(len, BACNET_STATUS_ERROR, NULL); + zassert_true(len <= 0, NULL); } while (--apdu_len) { len = bacnet_octet_string_application_encode(apdu, apdu_len, &value); @@ -1063,7 +1063,7 @@ static void testBACDCodeCharacterString(void) zassert_true(characterstring_same(&value, &test_value), NULL); while (--test_len) { len = bacnet_character_string_application_decode(apdu, test_len, NULL); - zassert_equal(len, BACNET_STATUS_ERROR, NULL); + zassert_true(len <= 0, NULL); } while (--apdu_len) { len = @@ -1149,7 +1149,7 @@ static void testBACDCodeObject(void) while (--test_len) { len = bacnet_object_id_application_decode( apdu, test_len, &decoded_type, &decoded_instance); - zassert_equal(len, BACNET_STATUS_ERROR, NULL); + zassert_true(len <= 0, NULL); } while (--apdu_len) { len = @@ -1266,7 +1266,7 @@ static void testBACDCodeBitString(void) zassert_true(bitstring_same(&value, &test_value), NULL); while (--test_len) { len = bacnet_bitstring_application_decode(apdu, test_len, NULL); - zassert_equal(len, BACNET_STATUS_ERROR, NULL); + zassert_true(len <= 0, NULL); } while (--apdu_len) { len = bacnet_bitstring_application_encode(apdu, apdu_len, &value); @@ -1305,7 +1305,7 @@ test_unsigned_context_codec(BACNET_UNSIGNED_INTEGER value, uint8_t context_tag) while (len) { len--; test_len = bacnet_unsigned_context_decode(apdu, len, context_tag, NULL); - zassert_equal(test_len, BACNET_STATUS_ERROR, NULL); + zassert_true(test_len <= 0, NULL); } } @@ -1358,7 +1358,7 @@ static void test_signed_context_codec(int32_t value, uint8_t context_tag) while (len) { len--; test_len = bacnet_signed_context_decode(apdu, len, context_tag, NULL); - zassert_equal(test_len, BACNET_STATUS_ERROR, NULL); + zassert_true(test_len <= 0, NULL); } } @@ -1418,7 +1418,7 @@ static void test_enumerated_context_codec(uint32_t value, uint8_t context_tag) len--; test_len = bacnet_enumerated_context_decode(apdu, len, context_tag, NULL); - zassert_equal(test_len, BACNET_STATUS_ERROR, NULL); + zassert_true(test_len <= 0, NULL); } } @@ -1519,7 +1519,7 @@ static void testFloatContextDecodes(void) inLen--; outLen = bacnet_real_context_decode(apdu, inLen, large_context_tag, &out); - zassert_equal(outLen, BACNET_STATUS_ERROR, NULL); + zassert_true(outLen <= 0, NULL); } } @@ -1574,7 +1574,7 @@ static void testDoubleContextDecodes(void) inLen--; outLen = bacnet_double_context_decode(apdu, inLen, large_context_tag, &out); - zassert_equal(outLen, BACNET_STATUS_ERROR, NULL); + zassert_true(outLen <= 0, NULL); } } @@ -1621,7 +1621,7 @@ static void testObjectIDContextDecodes(void) inLen--; outLen = bacnet_object_id_context_decode( apdu, inLen, large_context_tag, &out_type, &out_id); - zassert_equal(outLen, BACNET_STATUS_ERROR, NULL); + zassert_true(outLen <= 0, NULL); } } @@ -1697,7 +1697,7 @@ static void testBitStringContextDecodes(void) while (inLen) { inLen--; outLen = bacnet_bitstring_context_decode(apdu, inLen, 10, &out); - zassert_equal(outLen, BACNET_STATUS_ERROR, NULL); + zassert_true(outLen <= 0, NULL); } inLen = encode_context_bitstring(apdu, large_context_tag, &in); @@ -1713,8 +1713,7 @@ static void testBitStringContextDecodes(void) inLen--; outLen = bacnet_bitstring_context_decode( apdu, inLen, large_context_tag, &out); - zassert_equal( - outLen, BACNET_STATUS_ERROR, "inLen=%d outLen=%d", inLen, outLen); + zassert_true(outLen <= 0, "inLen=%d outLen=%d", inLen, outLen); } } @@ -1760,7 +1759,7 @@ static void testOctetStringContextDecodes(void) inLen--; outLen2 = bacnet_octet_string_context_decode( apdu, inLen, large_context_tag, &out); - zassert_equal(outLen2, BACNET_STATUS_ERROR, NULL); + zassert_true(outLen2 <= 0, NULL); } } @@ -1811,7 +1810,7 @@ static void testTimeContextDecodes(void) inLen--; outLen2 = bacnet_time_context_decode(apdu, inLen, large_context_tag, &out); - zassert_equal(outLen2, BACNET_STATUS_ERROR, NULL); + zassert_true(outLen2 <= 0, NULL); } } @@ -1863,7 +1862,7 @@ static void testDateContextDecodes(void) inLen--; outLen2 = bacnet_date_context_decode(apdu, inLen, large_context_tag, &out); - zassert_equal(outLen2, BACNET_STATUS_ERROR, NULL); + zassert_true(outLen2 <= 0, NULL); } } diff --git a/test/bacnet/bacdest/src/main.c b/test/bacnet/bacdest/src/main.c index c9728573..d4f651a6 100644 --- a/test/bacnet/bacdest/src/main.c +++ b/test/bacnet/bacdest/src/main.c @@ -106,14 +106,14 @@ static void testBACnetDestination(void) zassert_equal(apdu_len, null_len, NULL); test_len = bacnet_destination_decode(apdu, apdu_len, &test_destination); zassert_equal(test_len, apdu_len, NULL); + test_len = bacnet_destination_decode(apdu, apdu_len, NULL); + zassert_equal(test_len, apdu_len, NULL); /* decoding, some negative tests */ test_len = bacnet_destination_decode(NULL, apdu_len, &test_destination); zassert_equal(test_len, BACNET_STATUS_REJECT, NULL); test_len = bacnet_destination_decode(apdu, 0, &test_destination); zassert_equal(test_len, BACNET_STATUS_REJECT, NULL); - test_len = bacnet_destination_decode(apdu, apdu_len, NULL); - zassert_equal(test_len, BACNET_STATUS_REJECT, NULL); } /** * @} diff --git a/test/bacnet/timestamp/src/main.c b/test/bacnet/timestamp/src/main.c index 2dc7a44b..e62e2a9d 100644 --- a/test/bacnet/timestamp/src/main.c +++ b/test/bacnet/timestamp/src/main.c @@ -137,7 +137,7 @@ static void testTimestampTimeDate(void) len--; test_len = bacnet_timestamp_context_decode( buffer, len, tag_number, &testTimestampOut); - zassert_equal(test_len, BACNET_STATUS_ERROR, NULL); + zassert_true(test_len <= 0, "len=%d test_len=%d", len, test_len); } /* test for valid values */ zassert_equal(testTimestampIn.tag, testTimestampOut.tag, NULL);