From 9780f526409fec7206572f412b7af963e105bc3d Mon Sep 17 00:00:00 2001 From: Steve Karg Date: Wed, 29 Nov 2023 15:44:58 -0600 Subject: [PATCH] Fix bacdevobjpropref module decode buffer overflow reads (#541) Co-authored-by: Steve Karg --- src/bacnet/bacapp.c | 10 +- src/bacnet/bacdcode.c | 2 +- src/bacnet/bacdevobjpropref.c | 623 +++++++++++++++--------- src/bacnet/bacdevobjpropref.h | 170 ++++--- src/bacnet/basic/object/trendlog.c | 11 +- src/bacnet/event.c | 13 +- test/bacnet/bacdevobjpropref/src/main.c | 264 +++++----- 7 files changed, 645 insertions(+), 448 deletions(-) diff --git a/src/bacnet/bacapp.c b/src/bacnet/bacapp.c index 64635b9b..75ede30f 100644 --- a/src/bacnet/bacapp.c +++ b/src/bacnet/bacapp.c @@ -337,8 +337,9 @@ int bacapp_decode_data(uint8_t *apdu, break; case BACNET_APPLICATION_TAG_DEVICE_OBJECT_PROPERTY_REFERENCE: /* BACnetDeviceObjectPropertyReference */ - len = bacapp_decode_device_obj_property_ref( - apdu, &value->type.Device_Object_Property_Reference); + len = bacnet_device_object_property_reference_decode( + apdu, len_value_type, + &value->type.Device_Object_Property_Reference); break; case BACNET_APPLICATION_TAG_DEVICE_OBJECT_REFERENCE: /* BACnetDeviceObjectReference */ @@ -1264,8 +1265,9 @@ int bacapp_decode_known_property(uint8_t *apdu, case PROP_LOG_DEVICE_OBJECT_PROPERTY: case PROP_LIST_OF_OBJECT_PROPERTY_REFERENCES: /* Properties using BACnetDeviceObjectPropertyReference */ - len = bacapp_decode_device_obj_property_ref( - apdu, &value->type.Device_Object_Property_Reference); + len = bacnet_device_object_property_reference_decode( + apdu, max_apdu_len, + &value->type.Device_Object_Property_Reference); break; case PROP_MANIPULATED_VARIABLE_REFERENCE: diff --git a/src/bacnet/bacdcode.c b/src/bacnet/bacdcode.c index 6681dc28..faf880bd 100644 --- a/src/bacnet/bacdcode.c +++ b/src/bacnet/bacdcode.c @@ -849,7 +849,7 @@ bool decode_is_opening_tag_number(uint8_t *apdu, uint8_t tag_number) * @param tag_length Pointer to a variable, or NULL. * Returns the length of the tag in bytes if not NULL. * - * @return true if the tag number matches is an opening tag. + * @return true if the tag number matches and is an opening tag. */ bool bacnet_is_opening_tag_number( uint8_t *apdu, uint32_t apdu_size, uint8_t tag_number, int *tag_length) diff --git a/src/bacnet/bacdevobjpropref.c b/src/bacnet/bacdevobjpropref.c index f3c3467a..ac615478 100644 --- a/src/bacnet/bacdevobjpropref.c +++ b/src/bacnet/bacdevobjpropref.c @@ -47,10 +47,9 @@ * Add an opening tag, encode the property and finally * add a closing tag as well. * - * @param apdu Pointer to the buffer to encode to. - * @param tag_number Tag number. - * @param value Pointer to the object property reference, - * used for encoding. + * @param apdu Pointer to the encode buffer, or NULL for length + * @param tag_number Tag number. + * @param value Pointer to the object property reference, used for encoding. * * @return Bytes encoded or 0 on failure. */ @@ -62,13 +61,17 @@ int bacapp_encode_context_device_obj_property_ref(uint8_t *apdu, int apdu_len = 0; if (value) { - len = encode_opening_tag(&apdu[apdu_len], tag_number); + len = encode_opening_tag(apdu, tag_number); apdu_len += len; - - len = bacapp_encode_device_obj_property_ref(&apdu[apdu_len], value); + if (apdu) { + apdu += len; + } + len = bacapp_encode_device_obj_property_ref(apdu, value); apdu_len += len; - - len = encode_closing_tag(&apdu[apdu_len], tag_number); + if (apdu) { + apdu += len; + } + len = encode_closing_tag(apdu, tag_number); apdu_len += len; } @@ -88,7 +91,7 @@ int bacapp_encode_context_device_obj_property_ref(uint8_t *apdu, * device-identifier [3] BACnetObjectIdentifier OPTIONAL * } * - * @param apdu Pointer to the buffer to encode to. + * @param apdu Pointer to the encode buffer, or NULL for length * @param value Pointer to the object property reference, * used for encoding. * @@ -104,15 +107,14 @@ int bacapp_encode_device_obj_property_ref( return apdu_len; } /* object-identifier [0] BACnetObjectIdentifier */ - len = encode_context_object_id(apdu, 0, - value->objectIdentifier.type, value->objectIdentifier.instance); + len = encode_context_object_id(apdu, 0, value->objectIdentifier.type, + value->objectIdentifier.instance); apdu_len += len; if (apdu) { apdu += len; } /* property-identifier [1] BACnetPropertyIdentifier */ - len = encode_context_enumerated( - apdu, 1, value->propertyIdentifier); + len = encode_context_enumerated(apdu, 1, value->propertyIdentifier); apdu_len += len; if (apdu) { apdu += len; @@ -131,14 +133,159 @@ int bacapp_encode_device_obj_property_ref( * (set type to BACNET_NO_DEV_TYPE or something other than OBJECT_DEVICE to * omit */ if (value->deviceIdentifier.type == OBJECT_DEVICE) { - len = encode_context_object_id(apdu, 3, - value->deviceIdentifier.type, value->deviceIdentifier.instance); + len = encode_context_object_id(apdu, 3, value->deviceIdentifier.type, + value->deviceIdentifier.instance); apdu_len += len; } return apdu_len; } +/** + * Decode a property reference of a device object. + * + * BACnetDeviceObjectPropertyReference ::= SEQUENCE { + * object-identifier [0] BACnetObjectIdentifier, + * property-identifier [1] BACnetPropertyIdentifier, + * property-array-index [2] Unsigned OPTIONAL, + * -- used only with array datatype + * -- if omitted with an array then + * -- the entire array is referenced + * device-identifier [3] BACnetObjectIdentifier OPTIONAL + * } + * + * @param apdu Pointer to the buffer containing the encoded value + * @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. + */ +int bacnet_device_object_property_reference_decode(uint8_t *apdu, + uint32_t apdu_size, + BACNET_DEVICE_OBJECT_PROPERTY_REFERENCE *value) +{ + int apdu_len = 0; + int len = 0; + BACNET_UNSIGNED_INTEGER array_index = 0; + BACNET_OBJECT_TYPE object_type = 0; + uint32_t object_instance = 0; + uint32_t property_identifier = 0; + + if (!apdu) { + return BACNET_STATUS_ERROR; + } + /* object-identifier [0] BACnetObjectIdentifier */ + len = bacnet_object_id_context_decode(&apdu[apdu_len], apdu_size - apdu_len, + 0, &object_type, &object_instance); + if (len > 0) { + apdu_len += len; + if (value) { + value->objectIdentifier.instance = object_instance; + value->objectIdentifier.type = object_type; + } + } else { + return BACNET_STATUS_ERROR; + } + /* property-identifier [1] BACnetPropertyIdentifier */ + len = bacnet_enumerated_context_decode( + &apdu[apdu_len], apdu_size - apdu_len, 1, &property_identifier); + if (len > 0) { + apdu_len += len; + if (value) { + value->propertyIdentifier = property_identifier; + } + } else { + return BACNET_STATUS_ERROR; + } + /* property-array-index [2] Unsigned OPTIONAL */ + if (bacnet_is_context_tag_number( + &apdu[apdu_len], apdu_size - apdu_len, 2, NULL)) { + len = bacnet_unsigned_context_decode( + &apdu[apdu_len], apdu_size - apdu_len, 2, &array_index); + if (len > 0) { + apdu_len += len; + if (value) { + value->arrayIndex = array_index; + } + } else { + return BACNET_STATUS_ERROR; + } + } else { + /* OPTIONAL - skip apdu_len increment */ + if (value) { + value->arrayIndex = BACNET_ARRAY_ALL; + } + } + /* device-identifier [3] BACnetObjectIdentifier OPTIONAL */ + if (bacnet_is_context_tag_number( + &apdu[apdu_len], apdu_size - apdu_len, 3, NULL)) { + len = bacnet_object_id_context_decode(&apdu[apdu_len], + apdu_size - apdu_len, 3, &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; + } + } else { + /* OPTIONAL - skip apdu_len increment */ + if (value) { + value->deviceIdentifier.type = BACNET_NO_DEV_TYPE; + value->deviceIdentifier.instance = BACNET_NO_DEV_ID; + } + } + + return apdu_len; +} + +/** + * Decode the opening tag and the property reference of + * an device object and check for the closing tag as well. + * + * @param apdu Pointer to the buffer containing the encoded value + * @param apdu_size Size of the buffer containing the encoded value + * @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. + */ +int bacnet_device_object_property_reference_context_decode(uint8_t *apdu, + uint32_t apdu_size, + uint8_t tag_number, + BACNET_DEVICE_OBJECT_PROPERTY_REFERENCE *value) +{ + int apdu_len = 0; + int len = 0; + + if (!apdu) { + return BACNET_STATUS_ERROR; + } + if (bacnet_is_opening_tag_number( + &apdu[apdu_len], apdu_size - apdu_len, tag_number, &len)) { + apdu_len += len; + len = bacnet_device_object_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; + } + } else { + return BACNET_STATUS_ERROR; + } + + return apdu_len; +} + /** * Decode a property reference of a device object. * @@ -157,55 +304,13 @@ int bacapp_encode_device_obj_property_ref( * used to decode the data into. * * @return Bytes decoded or BACNET_STATUS_ERROR on failure. + * @deprecated Use bacnet_device_object_property_reference_decode() instead */ int bacapp_decode_device_obj_property_ref( uint8_t *apdu, BACNET_DEVICE_OBJECT_PROPERTY_REFERENCE *value) { - int len; - int apdu_len = 0; - uint32_t enumValue = 0; - - /* object-identifier [0] BACnetObjectIdentifier */ - len = decode_context_object_id(&apdu[apdu_len], 0, - &value->objectIdentifier.type, &value->objectIdentifier.instance); - if (len == BACNET_STATUS_ERROR) { - return BACNET_STATUS_ERROR; - } - apdu_len += len; - /* property-identifier [1] BACnetPropertyIdentifier */ - len = decode_context_enumerated(&apdu[apdu_len], 1, &enumValue); - if (len == BACNET_STATUS_ERROR) { - return BACNET_STATUS_ERROR; - } - value->propertyIdentifier = (BACNET_PROPERTY_ID)enumValue; - apdu_len += len; - /* property-array-index [2] Unsigned OPTIONAL */ - if (decode_is_context_tag(&apdu[apdu_len], 2) && - !decode_is_closing_tag(&apdu[apdu_len])) { - len = decode_context_unsigned(&apdu[apdu_len], 2, &value->arrayIndex); - if (len == BACNET_STATUS_ERROR) { - return BACNET_STATUS_ERROR; - } - apdu_len += len; - } else { - value->arrayIndex = BACNET_ARRAY_ALL; - } - /* device-identifier [3] BACnetObjectIdentifier OPTIONAL */ - if (decode_is_context_tag(&apdu[apdu_len], 3) && - !decode_is_closing_tag(&apdu[apdu_len])) { - if (-1 == - (len = decode_context_object_id(&apdu[apdu_len], 3, - &value->deviceIdentifier.type, - &value->deviceIdentifier.instance))) { - return -1; - } - apdu_len += len; - } else { - value->deviceIdentifier.type = BACNET_NO_DEV_TYPE; - value->deviceIdentifier.instance = BACNET_NO_DEV_ID; - } - - return apdu_len; + return bacnet_device_object_property_reference_decode( + apdu, MAX_APDU, value); } /** @@ -218,32 +323,15 @@ int bacapp_decode_device_obj_property_ref( * used to decode the data into. * * @return Bytes decoded or BACNET_STATUS_ERROR on failure. + * @deprecated Use bacnet_device_object_property_reference_context_decode() + * instead */ int bacapp_decode_context_device_obj_property_ref(uint8_t *apdu, uint8_t tag_number, BACNET_DEVICE_OBJECT_PROPERTY_REFERENCE *value) { - int len = 0; - int section_length; - - if (decode_is_opening_tag_number(&apdu[len], tag_number)) { - len++; - section_length = - bacapp_decode_device_obj_property_ref(&apdu[len], value); - if (section_length == BACNET_STATUS_ERROR) { - len = BACNET_STATUS_ERROR; - } else { - len += section_length; - if (decode_is_closing_tag_number(&apdu[len], tag_number)) { - len++; - } else { - len = BACNET_STATUS_ERROR; - } - } - } else { - len = BACNET_STATUS_ERROR; - } - return len; + return bacnet_device_object_property_reference_context_decode( + apdu, MAX_APDU, tag_number, value); } /** @@ -251,14 +339,13 @@ int bacapp_decode_context_device_obj_property_ref(uint8_t *apdu, * and finally for the closing tag as well. * * BACnetDeviceObjectReference ::= SEQUENCE { - * device-identifier [0] BACnetObjectIdentifier OPTIONAL, - * object-identifier [1] BACnetObjectIdentifier + * device-identifier [0] BACnetObjectIdentifier OPTIONAL, + * object-identifier [1] BACnetObjectIdentifier * } * - * @param apdu Pointer to the buffer used for encoding. - * @param tag_number Tag number - * @param value Pointer to the device object reference, - * used to encode. + * @param apdu Pointer to the encode buffer, or NULL for length + * @param tag_number Tag number + * @param value Pointer to the device object reference, used to encode. * * @return Bytes encoded or 0 on failure. */ @@ -269,13 +356,17 @@ int bacapp_encode_context_device_obj_ref( int apdu_len = 0; if (value) { - len = encode_opening_tag(&apdu[apdu_len], tag_number); + len = encode_opening_tag(apdu, tag_number); apdu_len += len; - - len = bacapp_encode_device_obj_ref(&apdu[apdu_len], value); + if (apdu) { + apdu += len; + } + len = bacapp_encode_device_obj_ref(apdu, value); apdu_len += len; - - len = encode_closing_tag(&apdu[apdu_len], tag_number); + if (apdu) { + apdu += len; + } + len = encode_closing_tag(apdu, tag_number); apdu_len += len; } @@ -286,13 +377,12 @@ int bacapp_encode_context_device_obj_ref( * Encode the device object reference. * * BACnetDeviceObjectReference ::= SEQUENCE { - * device-identifier [0] BACnetObjectIdentifier OPTIONAL, - * object-identifier [1] BACnetObjectIdentifier + * device-identifier [0] BACnetObjectIdentifier OPTIONAL, + * object-identifier [1] BACnetObjectIdentifier * } * - * @param apdu Pointer to the buffer used for encoding. - * @param value Pointer to the device object reference, - * used to encode. + * @param apdu Pointer to the encode buffer, or NULL for length + * @param value Pointer to the device object reference, used to encode. * * @return Bytes encoded or 0 on failure. */ @@ -302,19 +392,129 @@ int bacapp_encode_device_obj_ref( int len; int apdu_len = 0; - /* device-identifier [0] BACnetObjectIdentifier OPTIONAL */ - /* Device id is optional so see if needed - * (set type to BACNET_NO_DEV_TYPE or something other than OBJECT_DEVICE to - * omit */ - if (value->deviceIdentifier.type == OBJECT_DEVICE) { - len = encode_context_object_id(&apdu[apdu_len], 0, - value->deviceIdentifier.type, value->deviceIdentifier.instance); + if (value) { + /* device-identifier [0] BACnetObjectIdentifier OPTIONAL */ + /* Device id is optional so determine if needed and + set type to BACNET_NO_DEV_TYPE or something other + than OBJECT_DEVICE to omit */ + if (value->deviceIdentifier.type == OBJECT_DEVICE) { + len = encode_context_object_id(apdu, 0, + value->deviceIdentifier.type, value->deviceIdentifier.instance); + apdu_len += len; + if (apdu) { + apdu += len; + } + } + /* object-identifier [1] BACnetObjectIdentifier */ + len = encode_context_object_id(apdu, 1, value->objectIdentifier.type, + value->objectIdentifier.instance); apdu_len += len; } + + return apdu_len; +} + +/** + * Decode the device object reference. + * + * BACnetDeviceObjectReference ::= SEQUENCE { + * device-identifier [0] BACnetObjectIdentifier OPTIONAL, + * object-identifier [1] BACnetObjectIdentifier + * } + * + * @param apdu Pointer to the buffer containing the encoded value + * @param apdu_size Size of the buffer containing the encoded value + * @param value Pointer to the structure containing the decoded value + * + * @return number of bytes decoded or BACNET_STATUS_ERROR on failure. + */ +int bacnet_device_object_reference_decode( + uint8_t *apdu, uint32_t apdu_size, BACNET_DEVICE_OBJECT_REFERENCE *value) +{ + int len; + int apdu_len = 0; + BACNET_OBJECT_TYPE object_type = 0; + uint32_t object_instance = 0; + + if (!apdu) { + return BACNET_STATUS_ERROR; + } + /* device-identifier [0] BACnetObjectIdentifier OPTIONAL */ + if (bacnet_is_context_tag_number( + &apdu[apdu_len], apdu_size - apdu_len, 0, NULL)) { + len = bacnet_object_id_context_decode(&apdu[apdu_len], + apdu_size - apdu_len, 0, &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; + } + } else { + /* OPTIONAL - skip apdu_len increment */ + value->deviceIdentifier.type = BACNET_NO_DEV_TYPE; + value->deviceIdentifier.instance = BACNET_NO_DEV_ID; + } /* object-identifier [1] BACnetObjectIdentifier */ - len = encode_context_object_id(&apdu[apdu_len], 1, - value->objectIdentifier.type, value->objectIdentifier.instance); - apdu_len += len; + len = bacnet_object_id_context_decode(&apdu[apdu_len], apdu_size - apdu_len, + 1, &object_type, &object_instance); + if (len > 0) { + apdu_len += len; + if (value) { + value->objectIdentifier.instance = object_instance; + value->objectIdentifier.type = object_type; + } + } else { + return BACNET_STATUS_ERROR; + } + + return apdu_len; +} + +/** + * Decode the context device object reference. Check for + * an opening tag and a closing tag as well. + * + * @param apdu Pointer to the buffer containing the encoded value + * @param apdu_size Size of the buffer containing the encoded value + * @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. + */ +int bacnet_device_object_reference_context_decode(uint8_t *apdu, + uint32_t apdu_size, + uint8_t tag_number, + BACNET_DEVICE_OBJECT_REFERENCE *value) +{ + int apdu_len = 0; + int len = 0; + + if (!apdu) { + return BACNET_STATUS_ERROR; + } + if (bacnet_is_opening_tag_number( + &apdu[apdu_len], apdu_size - apdu_len, tag_number, &len)) { + apdu_len += len; + len = bacnet_device_object_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; + } + } else { + return BACNET_STATUS_ERROR; + } return apdu_len; } @@ -332,35 +532,12 @@ int bacapp_encode_device_obj_ref( * that shall be decoded. * * @return Bytes decoded or BACNET_STATUS_ERROR on failure. + * @deprecated Use bacnet_device_object_reference_decode() instead. */ int bacapp_decode_device_obj_ref( uint8_t *apdu, BACNET_DEVICE_OBJECT_REFERENCE *value) { - int len; - int apdu_len = 0; - - /* device-identifier [0] BACnetObjectIdentifier OPTIONAL */ - if (decode_is_context_tag(&apdu[apdu_len], 0) && - !decode_is_closing_tag(&apdu[apdu_len])) { - len = decode_context_object_id(&apdu[apdu_len], 0, - &value->deviceIdentifier.type, &value->deviceIdentifier.instance); - if (len == BACNET_STATUS_ERROR) { - return BACNET_STATUS_ERROR; - } - apdu_len += len; - } else { - value->deviceIdentifier.type = BACNET_NO_DEV_TYPE; - value->deviceIdentifier.instance = BACNET_NO_DEV_ID; - } - /* object-identifier [1] BACnetObjectIdentifier */ - len = decode_context_object_id(&apdu[apdu_len], 1, - &value->objectIdentifier.type, &value->objectIdentifier.instance); - if (len == BACNET_STATUS_ERROR) { - return BACNET_STATUS_ERROR; - } - apdu_len += len; - - return apdu_len; + return bacnet_device_object_reference_decode(apdu, MAX_APDU, value); } /** @@ -373,30 +550,13 @@ int bacapp_decode_device_obj_ref( * that shall be decoded. * * @return Bytes decoded or BACNET_STATUS_ERROR on failure. + * @deprecated Use bacnet_device_object_reference_context_decode() instead. */ int bacapp_decode_context_device_obj_ref( uint8_t *apdu, uint8_t tag_number, BACNET_DEVICE_OBJECT_REFERENCE *value) { - int len = 0; - int section_length; - - if (decode_is_opening_tag_number(&apdu[len], tag_number)) { - len++; - section_length = bacapp_decode_device_obj_ref(&apdu[len], value); - if (section_length == BACNET_STATUS_ERROR) { - len = BACNET_STATUS_ERROR; - } else { - len += section_length; - if (decode_is_closing_tag_number(&apdu[len], tag_number)) { - len++; - } else { - len = BACNET_STATUS_ERROR; - } - } - } else { - len = BACNET_STATUS_ERROR; - } - return len; + return bacnet_device_object_reference_context_decode( + apdu, MAX_APDU, tag_number, value); } /** @@ -418,7 +578,6 @@ int bacapp_encode_obj_property_ref( uint8_t *apdu, BACNET_OBJECT_PROPERTY_REFERENCE *reference) { int len = 0; - uint8_t *apdu_offset = NULL; int apdu_len = 0; if (!reference) { @@ -427,25 +586,19 @@ int bacapp_encode_obj_property_ref( if (reference->object_identifier.type == OBJECT_NONE) { return 0; } - if (apdu) { - apdu_offset = apdu; - } - len = encode_context_object_id(apdu_offset, 0, - reference->object_identifier.type, + len = encode_context_object_id(apdu, 0, reference->object_identifier.type, reference->object_identifier.instance); apdu_len += len; if (apdu) { - apdu_offset = &apdu[apdu_len]; + apdu += len; } - len = encode_context_enumerated( - apdu_offset, 1, reference->property_identifier); + len = encode_context_enumerated(apdu, 1, reference->property_identifier); apdu_len += len; if (apdu) { - apdu_offset = &apdu[apdu_len]; + apdu += len; } if (reference->property_array_index != BACNET_ARRAY_ALL) { - len = encode_context_unsigned( - apdu_offset, 2, reference->property_array_index); + len = encode_context_unsigned(apdu, 2, reference->property_array_index); apdu_len += len; } @@ -465,25 +618,21 @@ int bacapp_encode_context_obj_property_ref(uint8_t *apdu, { int len = 0; int apdu_len = 0; - uint8_t *apdu_offset = NULL; if (reference && (reference->object_identifier.type == OBJECT_NONE)) { return 0; } - if (apdu) { - apdu_offset = apdu; - } - len = encode_opening_tag(apdu_offset, tag_number); + len = encode_opening_tag(apdu, tag_number); apdu_len += len; if (apdu) { - apdu_offset = &apdu[apdu_len]; + apdu += len; } - len = bacapp_encode_obj_property_ref(apdu_offset, reference); + len = bacapp_encode_obj_property_ref(apdu, reference); apdu_len += len; if (apdu) { - apdu_offset = &apdu[apdu_len]; + apdu += len; } - len = encode_closing_tag(apdu_offset, tag_number); + len = encode_closing_tag(apdu, tag_number); apdu_len += len; return apdu_len; @@ -500,13 +649,13 @@ int bacapp_encode_context_obj_property_ref(uint8_t *apdu, * -- if omitted with an array the entire array is referenced * } * - * @param apdu - the APDU buffer - * @param apdu_len_max - the APDU buffer length + * @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 length of the APDU buffer decoded, or 0 if failed to decode + * @return number of bytes decoded or BACNET_STATUS_ERROR on failure. */ int bacapp_decode_obj_property_ref(uint8_t *apdu, - uint16_t apdu_len_max, + uint16_t apdu_size, BACNET_OBJECT_PROPERTY_REFERENCE *reference) { int apdu_len = 0; @@ -515,48 +664,51 @@ int bacapp_decode_obj_property_ref(uint8_t *apdu, uint32_t property_identifier; BACNET_UNSIGNED_INTEGER unsigned_value; - if (apdu && (apdu_len_max > 0)) { - /* object-identifier [0] BACnetObjectIdentifier */ - len = bacnet_object_id_context_decode(&apdu[apdu_len], - apdu_len_max - apdu_len, 0, &object_identifier.type, - &object_identifier.instance); + if (!apdu) { + return BACNET_STATUS_ERROR; + } + /* object-identifier [0] BACnetObjectIdentifier */ + len = bacnet_object_id_context_decode(&apdu[apdu_len], apdu_size - apdu_len, + 0, &object_identifier.type, &object_identifier.instance); + if (len > 0) { + apdu_len += len; + } else if (len <= 0) { + return BACNET_STATUS_ERROR; + } + /* property-identifier [1] BACnetPropertyIdentifier */ + len = bacnet_enumerated_context_decode( + &apdu[apdu_len], apdu_size - apdu_len, 1, &property_identifier); + if (len > 0) { + apdu_len += len; + } else if (len <= 0) { + return BACNET_STATUS_ERROR; + } + if (reference) { + reference->object_identifier.type = object_identifier.type; + reference->object_identifier.instance = object_identifier.instance; + reference->property_identifier = + (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; - } else if (len <= 0) { - return 0; - } - /* property-identifier [1] BACnetPropertyIdentifier */ - len = bacnet_enumerated_context_decode( - &apdu[apdu_len], apdu_len_max - apdu_len, 1, &property_identifier); - if (len > 0) { - apdu_len += len; - } else if (len <= 0) { - return 0; - } - if (reference) { - reference->object_identifier.type = object_identifier.type; - reference->object_identifier.instance = object_identifier.instance; - reference->property_identifier = - (BACNET_PROPERTY_ID)property_identifier; - reference->property_array_index = BACNET_ARRAY_ALL; - } - /* property-array-index [2] Unsigned OPTIONAL */ - if (apdu_len_max > apdu_len) { - if (decode_is_context_tag(&apdu[apdu_len], 2)) { - len = bacnet_unsigned_context_decode(&apdu[apdu_len], - apdu_len_max - apdu_len, 2, &unsigned_value); - if (len > 0) { - apdu_len += len; - if (unsigned_value > UINT32_MAX) { - return 0; - } - if (reference) { - reference->property_array_index = unsigned_value; - } - } else if (len <= 0) { - return 0; - } + if (unsigned_value > UINT32_MAX) { + return BACNET_STATUS_ERROR; } + if (reference) { + reference->property_array_index = unsigned_value; + } + } else { + return BACNET_STATUS_ERROR; + } + } else { + /* OPTIONAL - skip apdu_len increment */ + if (reference) { + reference->property_array_index = BACNET_ARRAY_ALL; } } @@ -567,42 +719,39 @@ int bacapp_decode_obj_property_ref(uint8_t *apdu, * Decode the context object property reference. Check for * an opening tag and a closing tag as well. * - * @param apdu Pointer to the buffer containing the data to decode. - * @param apdu_len_max - the APDU buffer length + * @param apdu Pointer to the buffer containing the encoded value + * @param apdu_size Size of the buffer containing the encoded value * @param tag_number Tag number - * @param value Pointer to the context device object reference, - * that shall be decoded. + * @param value Pointer to the structure that shall be decoded into. * - * @return Bytes decoded or BACNET_STATUS_ERROR on failure. + * @return number of bytes decoded or BACNET_STATUS_ERROR on failure. */ int bacapp_decode_context_obj_property_ref(uint8_t *apdu, - uint16_t apdu_len_max, + uint16_t apdu_size, uint8_t tag_number, BACNET_OBJECT_PROPERTY_REFERENCE *value) { int len = 0; int apdu_len = 0; - if (apdu_len_max == 0) { + if (!apdu) { return BACNET_STATUS_ERROR; } - if (decode_is_opening_tag_number(&apdu[apdu_len], tag_number)) { - apdu_len++; - } else { + if (!bacnet_is_opening_tag_number( + &apdu[apdu_len], apdu_size - apdu_len, tag_number, &len)) { return BACNET_STATUS_ERROR; } + apdu_len += len; len = bacapp_decode_obj_property_ref( - &apdu[apdu_len], apdu_len_max - apdu_len, value); - if (len == 0) { - return BACNET_STATUS_ERROR; - } else { + &apdu[apdu_len], apdu_size - apdu_len, value); + if (len > 0) { apdu_len += len; - } - if ((apdu_len_max - apdu_len) == 0) { - return BACNET_STATUS_ERROR; - } - if (decode_is_closing_tag_number(&apdu[apdu_len], tag_number)) { - apdu_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; } diff --git a/src/bacnet/bacdevobjpropref.h b/src/bacnet/bacdevobjpropref.h index b570a85a..1ad5bc92 100644 --- a/src/bacnet/bacdevobjpropref.h +++ b/src/bacnet/bacdevobjpropref.h @@ -1,27 +1,27 @@ /************************************************************************** -* -* Copyright (C) 2008 John Minack -* Copyright (C) 2022 Steve Karg -* -* Permission is hereby granted, free of charge, to any person obtaining -* a copy of this software and associated documentation files (the -* "Software"), to deal in the Software without restriction, including -* without limitation the rights to use, copy, modify, merge, publish, -* distribute, sublicense, and/or sell copies of the Software, and to -* permit persons to whom the Software is furnished to do so, subject to -* the following conditions: -* -* The above copyright notice and this permission notice shall be included -* in all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*********************************************************************/ + * + * Copyright (C) 2008 John Minack + * Copyright (C) 2022 Steve Karg + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + *********************************************************************/ #ifndef _BAC_DEV_PROP_REF_H_ #define _BAC_DEV_PROP_REF_H_ @@ -32,6 +32,7 @@ #include "bacnet/bacdef.h" #include "bacnet/bacint.h" #include "bacnet/bacenum.h" +#include "bacnet/basic/sys/platform.h" typedef struct BACnetDeviceObjectPropertyReference { /* number type first to avoid enum cast warning on = { 0 } */ @@ -46,7 +47,7 @@ typedef struct BACnetDeviceObjectPropertyReference { * to an object inside this Device. */ typedef struct BACnetDeviceObjectReference { - BACNET_OBJECT_ID deviceIdentifier; /**< Optional, for external device. */ + BACNET_OBJECT_ID deviceIdentifier; /**< Optional, for external device. */ BACNET_OBJECT_ID objectIdentifier; } BACNET_DEVICE_OBJECT_REFERENCE; @@ -71,73 +72,82 @@ typedef struct BACnet_Object_Property_Reference { extern "C" { #endif /* __cplusplus */ - BACNET_STACK_EXPORT - int bacapp_encode_device_obj_property_ref( - uint8_t * apdu, - BACNET_DEVICE_OBJECT_PROPERTY_REFERENCE * value); +BACNET_STACK_EXPORT +int bacapp_encode_device_obj_property_ref( + uint8_t *apdu, BACNET_DEVICE_OBJECT_PROPERTY_REFERENCE *value); - BACNET_STACK_EXPORT - int bacapp_encode_context_device_obj_property_ref( - uint8_t * apdu, - uint8_t tag_number, - BACNET_DEVICE_OBJECT_PROPERTY_REFERENCE * value); +BACNET_STACK_EXPORT +int bacapp_encode_context_device_obj_property_ref(uint8_t *apdu, + uint8_t tag_number, + BACNET_DEVICE_OBJECT_PROPERTY_REFERENCE *value); - BACNET_STACK_EXPORT - int bacapp_decode_device_obj_property_ref( - uint8_t * apdu, - BACNET_DEVICE_OBJECT_PROPERTY_REFERENCE * value); +BACNET_STACK_DEPRECATED( + "Use bacnet_device_object_property_reference_decode() instead") +BACNET_STACK_EXPORT +int bacapp_decode_device_obj_property_ref( + uint8_t *apdu, BACNET_DEVICE_OBJECT_PROPERTY_REFERENCE *value); - BACNET_STACK_EXPORT - int bacapp_decode_context_device_obj_property_ref( - uint8_t * apdu, - uint8_t tag_number, - BACNET_DEVICE_OBJECT_PROPERTY_REFERENCE * value); +BACNET_STACK_DEPRECATED( + "Use bacnet_device_object_property_reference_context_decode() instead") +BACNET_STACK_EXPORT +int bacapp_decode_context_device_obj_property_ref(uint8_t *apdu, + uint8_t tag_number, + BACNET_DEVICE_OBJECT_PROPERTY_REFERENCE *value); - BACNET_STACK_EXPORT - int bacapp_encode_device_obj_ref( - uint8_t * apdu, - BACNET_DEVICE_OBJECT_REFERENCE * value); +BACNET_STACK_EXPORT +int bacapp_encode_device_obj_ref( + uint8_t *apdu, BACNET_DEVICE_OBJECT_REFERENCE *value); - BACNET_STACK_EXPORT - int bacapp_encode_context_device_obj_ref( - uint8_t * apdu, - uint8_t tag_number, - BACNET_DEVICE_OBJECT_REFERENCE * value); +BACNET_STACK_EXPORT +int bacapp_encode_context_device_obj_ref( + uint8_t *apdu, uint8_t tag_number, BACNET_DEVICE_OBJECT_REFERENCE *value); - BACNET_STACK_EXPORT - int bacapp_decode_device_obj_ref( - uint8_t * apdu, - BACNET_DEVICE_OBJECT_REFERENCE * value); +BACNET_STACK_EXPORT +int bacapp_decode_device_obj_ref( + uint8_t *apdu, BACNET_DEVICE_OBJECT_REFERENCE *value); - BACNET_STACK_EXPORT - int bacapp_decode_context_device_obj_ref( - uint8_t * apdu, - uint8_t tag_number, - BACNET_DEVICE_OBJECT_REFERENCE * value); +BACNET_STACK_EXPORT +int bacapp_decode_context_device_obj_ref( + uint8_t *apdu, uint8_t tag_number, BACNET_DEVICE_OBJECT_REFERENCE *value); - BACNET_STACK_EXPORT - int bacapp_encode_obj_property_ref( - uint8_t * apdu, - BACNET_OBJECT_PROPERTY_REFERENCE * value); +BACNET_STACK_EXPORT +int bacapp_encode_obj_property_ref( + uint8_t *apdu, BACNET_OBJECT_PROPERTY_REFERENCE *value); - BACNET_STACK_EXPORT - int bacapp_encode_context_obj_property_ref( - uint8_t * apdu, - uint8_t tag_number, - BACNET_OBJECT_PROPERTY_REFERENCE * value); +BACNET_STACK_EXPORT +int bacapp_encode_context_obj_property_ref( + uint8_t *apdu, uint8_t tag_number, BACNET_OBJECT_PROPERTY_REFERENCE *value); - BACNET_STACK_EXPORT - int bacapp_decode_obj_property_ref( - uint8_t * apdu, - uint16_t apdu_len_max, - BACNET_OBJECT_PROPERTY_REFERENCE * value); +BACNET_STACK_EXPORT +int bacapp_decode_obj_property_ref(uint8_t *apdu, + uint16_t apdu_len_max, + BACNET_OBJECT_PROPERTY_REFERENCE *value); + +BACNET_STACK_EXPORT +int bacapp_decode_context_obj_property_ref(uint8_t *apdu, + uint16_t apdu_len_max, + uint8_t tag_number, + BACNET_OBJECT_PROPERTY_REFERENCE *value); + +BACNET_STACK_EXPORT +int bacnet_device_object_property_reference_decode(uint8_t *apdu, + uint32_t apdu_size, + BACNET_DEVICE_OBJECT_PROPERTY_REFERENCE *value); +BACNET_STACK_EXPORT +int bacnet_device_object_property_reference_context_decode(uint8_t *apdu, + uint32_t apdu_size, + uint8_t tag_number, + BACNET_DEVICE_OBJECT_PROPERTY_REFERENCE *value); + +BACNET_STACK_EXPORT +int bacnet_device_object_reference_decode( + uint8_t *apdu, uint32_t apdu_size, BACNET_DEVICE_OBJECT_REFERENCE *value); +BACNET_STACK_EXPORT +int bacnet_device_object_reference_context_decode(uint8_t *apdu, + uint32_t apdu_size, + uint8_t tag_number, + BACNET_DEVICE_OBJECT_REFERENCE *value); - BACNET_STACK_EXPORT - int bacapp_decode_context_obj_property_ref( - uint8_t * apdu, - uint16_t apdu_len_max, - uint8_t tag_number, - BACNET_OBJECT_PROPERTY_REFERENCE * value); #ifdef __cplusplus } diff --git a/src/bacnet/basic/object/trendlog.c b/src/bacnet/basic/object/trendlog.c index 652620bc..b8da5b19 100644 --- a/src/bacnet/basic/object/trendlog.c +++ b/src/bacnet/basic/object/trendlog.c @@ -680,17 +680,14 @@ bool Trend_Log_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data) break; case PROP_LOG_DEVICE_OBJECT_PROPERTY: - len = bacapp_decode_device_obj_property_ref( - wp_data->application_data, &TempSource); - if ((len < 0) || - (len > wp_data->application_data_len)) /* Hmm, that didn't go */ - /* as planned... */ - { + len = bacnet_device_object_property_reference_decode( + wp_data->application_data,wp_data->application_data_len, + &TempSource); + if (len <= 0) { wp_data->error_class = ERROR_CLASS_PROPERTY; wp_data->error_code = ERROR_CODE_OTHER; break; } - /* We only support references to objects in ourself for now */ if ((TempSource.deviceIdentifier.type == OBJECT_DEVICE) && (TempSource.deviceIdentifier.instance != diff --git a/src/bacnet/event.c b/src/bacnet/event.c index ae4ea3af..5d34159b 100644 --- a/src/bacnet/event.c +++ b/src/bacnet/event.c @@ -1024,13 +1024,12 @@ int event_notify_decode_service_request( case EVENT_BUFFER_READY: /* Tag 0 - bufferProperty */ - if (-1 == - (section_length = - bacapp_decode_context_device_obj_property_ref( - &apdu[len], 0, - &data->notificationParams - .bufferReady - .bufferProperty))) { + section_length = + bacnet_device_object_property_reference_context_decode( + &apdu[len], apdu_len - len, 0, + &data->notificationParams.bufferReady + .bufferProperty); + if (section_length <= 0) { return -1; } len += section_length; diff --git a/test/bacnet/bacdevobjpropref/src/main.c b/test/bacnet/bacdevobjpropref/src/main.c index 17cbda8d..4de3d773 100644 --- a/test/bacnet/bacdevobjpropref/src/main.c +++ b/test/bacnet/bacdevobjpropref/src/main.c @@ -1,13 +1,15 @@ -/* - * Copyright (c) 2020 Legrand North America, LLC. +/** + * @file + * @brief Unit test for BACnetObjectPropertyReference and + * BACnetDeviceObjectReference and BACnetDeviceObjectPropertyReference encode + * and decode API + * @author Steve Karg + * @date November 2023 + * @section LICENSE * * SPDX-License-Identifier: MIT */ -/* @file - * @brief test BACnet integer encode/decode APIs - */ - #include #include #include @@ -20,42 +22,63 @@ /** * @brief Test */ -static void testDevObjPropRef( - BACNET_DEVICE_OBJECT_PROPERTY_REFERENCE *inData) +static void testDevObjPropRef(BACNET_DEVICE_OBJECT_PROPERTY_REFERENCE *data) { - BACNET_DEVICE_OBJECT_PROPERTY_REFERENCE outData; - uint8_t buffer[MAX_APDU] = { 0 }; - int inLen = 0; - int outLen = 0; + BACNET_DEVICE_OBJECT_PROPERTY_REFERENCE test_data; + uint8_t apdu[MAX_APDU] = { 0 }; + int len = 0; + int test_len = 0; + int null_len = 0; /* encode */ - inLen = bacapp_encode_device_obj_property_ref(buffer, inData); - /* add a closing tag at the end of the buffer to verify proper handling + null_len = bacapp_encode_device_obj_property_ref(NULL, data); + len = bacapp_encode_device_obj_property_ref(apdu, data); + zassert_equal(null_len, len, "null_len=%d len=%d", null_len, len); + /* add a closing tag at the end of the apdu to verify proper handling when that is encountered in real packets */ - encode_closing_tag(&buffer[inLen], 3); + encode_closing_tag(&apdu[len], 3); /* decode */ - outLen = bacapp_decode_device_obj_property_ref(buffer, &outData); - zassert_equal(outLen, inLen, NULL); + null_len = bacnet_device_object_property_reference_decode(apdu, len, NULL); + test_len = + bacnet_device_object_property_reference_decode(apdu, len, &test_data); + zassert_equal(null_len, len, "null_len=%d len=%d", null_len, len); + zassert_equal(test_len, len, "test_len=%d len=%d", test_len, len); + zassert_equal(data->objectIdentifier.instance, + test_data.objectIdentifier.instance, NULL); zassert_equal( - inData->objectIdentifier.instance, outData.objectIdentifier.instance, NULL); - zassert_equal( - inData->objectIdentifier.type, outData.objectIdentifier.type, NULL); - zassert_equal(inData->propertyIdentifier, outData.propertyIdentifier, NULL); - if (inData->arrayIndex != BACNET_ARRAY_ALL) { - zassert_equal(inData->arrayIndex, outData.arrayIndex, NULL); + data->objectIdentifier.type, test_data.objectIdentifier.type, NULL); + zassert_equal(data->propertyIdentifier, test_data.propertyIdentifier, NULL); + if (data->arrayIndex != BACNET_ARRAY_ALL) { + zassert_equal(data->arrayIndex, test_data.arrayIndex, NULL); } else { - zassert_equal(outData.arrayIndex, BACNET_ARRAY_ALL, NULL); + zassert_equal(test_data.arrayIndex, BACNET_ARRAY_ALL, NULL); } - if (inData->deviceIdentifier.type == OBJECT_DEVICE) { + if (data->deviceIdentifier.type == OBJECT_DEVICE) { + zassert_equal(data->deviceIdentifier.instance, + test_data.deviceIdentifier.instance, NULL); zassert_equal( - inData->deviceIdentifier.instance, - outData.deviceIdentifier.instance, NULL); - zassert_equal( - inData->deviceIdentifier.type, outData.deviceIdentifier.type, NULL); + data->deviceIdentifier.type, test_data.deviceIdentifier.type, NULL); } else { - zassert_equal(outData.deviceIdentifier.instance, BACNET_NO_DEV_ID, NULL); - zassert_equal(outData.deviceIdentifier.type, BACNET_NO_DEV_TYPE, NULL); + zassert_equal( + test_data.deviceIdentifier.instance, BACNET_NO_DEV_ID, NULL); + zassert_equal( + test_data.deviceIdentifier.type, BACNET_NO_DEV_TYPE, NULL); } + while (--len) { + test_len = bacnet_device_object_property_reference_decode( + apdu, len, &test_data); + if ((len > 0) && (test_data.arrayIndex == BACNET_ARRAY_ALL)) { + /* special case when optional portion is exactly missing */ + } else if ((len > 0) && + (test_data.deviceIdentifier.type == BACNET_NO_DEV_TYPE)) { + /* special case when optional portion is exactly missing */ + } else { + zassert_true(test_len <= 0, "test_len=%d len=%d", test_len, len); + } + } + test_len = bacnet_device_object_property_reference_decode( + NULL, sizeof(apdu), &test_data); + zassert_true(test_len <= 0, "test_len=%d len=%d", test_len, len); } #if defined(CONFIG_ZTEST_NEW_API) @@ -64,40 +87,40 @@ ZTEST(bacdevobjpropref_tests, testDevIdPropRef) static void testDevIdPropRef(void) #endif { - BACNET_DEVICE_OBJECT_PROPERTY_REFERENCE inData; + BACNET_DEVICE_OBJECT_PROPERTY_REFERENCE data; /* everything encoded */ - inData.objectIdentifier.instance = 0x1234; - inData.objectIdentifier.type = 15; - inData.propertyIdentifier = 25; - inData.arrayIndex = 0x5678; - inData.deviceIdentifier.instance = 0x4343; - inData.deviceIdentifier.type = OBJECT_DEVICE; - testDevObjPropRef(&inData); + data.objectIdentifier.instance = 0x1234; + data.objectIdentifier.type = 15; + data.propertyIdentifier = 25; + data.arrayIndex = 0x5678; + data.deviceIdentifier.instance = 0x4343; + data.deviceIdentifier.type = OBJECT_DEVICE; + testDevObjPropRef(&data); /* optional array */ - inData.objectIdentifier.instance = 0x1234; - inData.objectIdentifier.type = 15; - inData.propertyIdentifier = 25; - inData.arrayIndex = BACNET_ARRAY_ALL; - inData.deviceIdentifier.instance = 0x4343; - inData.deviceIdentifier.type = OBJECT_DEVICE; - testDevObjPropRef(&inData); + data.objectIdentifier.instance = 0x1234; + data.objectIdentifier.type = 15; + data.propertyIdentifier = 25; + data.arrayIndex = BACNET_ARRAY_ALL; + data.deviceIdentifier.instance = 0x4343; + data.deviceIdentifier.type = OBJECT_DEVICE; + testDevObjPropRef(&data); /* optional device ID */ - inData.objectIdentifier.instance = 0x1234; - inData.objectIdentifier.type = 15; - inData.propertyIdentifier = 25; - inData.arrayIndex = 1; - inData.deviceIdentifier.instance = 0; - inData.deviceIdentifier.type = BACNET_NO_DEV_TYPE; - testDevObjPropRef(&inData); + data.objectIdentifier.instance = 0x1234; + data.objectIdentifier.type = 15; + data.propertyIdentifier = 25; + data.arrayIndex = 1; + data.deviceIdentifier.instance = 0; + data.deviceIdentifier.type = BACNET_NO_DEV_TYPE; + testDevObjPropRef(&data); /* optional array + optional device ID */ - inData.objectIdentifier.instance = 0x1234; - inData.objectIdentifier.type = 15; - inData.propertyIdentifier = 25; - inData.arrayIndex = BACNET_ARRAY_ALL; - inData.deviceIdentifier.instance = 0; - inData.deviceIdentifier.type = BACNET_NO_DEV_TYPE; - testDevObjPropRef(&inData); + data.objectIdentifier.instance = 0x1234; + data.objectIdentifier.type = 15; + data.propertyIdentifier = 25; + data.arrayIndex = BACNET_ARRAY_ALL; + data.deviceIdentifier.instance = 0; + data.deviceIdentifier.type = BACNET_NO_DEV_TYPE; + testDevObjPropRef(&data); } #if defined(CONFIG_ZTEST_NEW_API) @@ -106,21 +129,33 @@ ZTEST(bacdevobjpropref_tests, testDevIdRef) static void testDevIdRef(void) #endif { - BACNET_DEVICE_OBJECT_REFERENCE inData; - BACNET_DEVICE_OBJECT_REFERENCE outData; - uint8_t buffer[MAX_APDU]; - int inLen; - int outLen; + BACNET_DEVICE_OBJECT_REFERENCE data; + BACNET_DEVICE_OBJECT_REFERENCE test_data; + uint8_t apdu[MAX_APDU]; + int len; + int test_len; + int null_len; - inData.deviceIdentifier.instance = 0x4343; - inData.deviceIdentifier.type = OBJECT_DEVICE; - inLen = bacapp_encode_device_obj_ref(buffer, &inData); - outLen = bacapp_decode_device_obj_ref(buffer, &outData); - zassert_equal(outLen, inLen, NULL); + data.deviceIdentifier.instance = 0x4343; + data.deviceIdentifier.type = OBJECT_DEVICE; + null_len = bacapp_encode_device_obj_ref(NULL, &data); + len = bacapp_encode_device_obj_ref(apdu, &data); + zassert_equal(null_len, len, NULL); + test_len = bacnet_device_object_reference_decode(apdu, len, &test_data); + zassert_equal(test_len, len, NULL); + null_len = bacnet_device_object_reference_decode(apdu, len, NULL); + zassert_equal(test_len, null_len, NULL); + zassert_equal(data.deviceIdentifier.instance, + test_data.deviceIdentifier.instance, NULL); zassert_equal( - inData.deviceIdentifier.instance, outData.deviceIdentifier.instance, NULL); - zassert_equal( - inData.deviceIdentifier.type, outData.deviceIdentifier.type, NULL); + data.deviceIdentifier.type, test_data.deviceIdentifier.type, NULL); + while (--len) { + test_len = bacnet_device_object_reference_decode(apdu, len, &test_data); + zassert_true(test_len <= 0, NULL); + } + test_len = + bacnet_device_object_reference_decode(NULL, sizeof(apdu), &test_data); + zassert_true(test_len <= 0, NULL); } #if defined(CONFIG_ZTEST_NEW_API) @@ -129,66 +164,71 @@ ZTEST(bacdevobjpropref_tests, testObjPropRef) static void testObjPropRef(void) #endif { - BACNET_OBJECT_PROPERTY_REFERENCE inData; - BACNET_OBJECT_PROPERTY_REFERENCE outData; + BACNET_OBJECT_PROPERTY_REFERENCE data; + BACNET_OBJECT_PROPERTY_REFERENCE test_data; uint8_t apdu[MAX_APDU]; uint8_t tag_number = 1; - int inLen; - int outLen; + int len; + int test_len; + int null_len; - inData.object_identifier.instance = 12345; - inData.object_identifier.type = OBJECT_ANALOG_VALUE; - inData.property_identifier = PROP_PRESENT_VALUE; - inData.property_array_index = BACNET_ARRAY_ALL; - inLen = bacapp_encode_obj_property_ref(apdu, &inData); - outLen = bacapp_decode_obj_property_ref(apdu, inLen, &outData); - zassert_equal(outLen, inLen, NULL); + data.object_identifier.instance = 12345; + data.object_identifier.type = OBJECT_ANALOG_VALUE; + data.property_identifier = PROP_PRESENT_VALUE; + data.property_array_index = BACNET_ARRAY_ALL; + null_len = bacapp_encode_obj_property_ref(NULL, &data); + len = bacapp_encode_obj_property_ref(apdu, &data); + zassert_equal(null_len, len, NULL); + test_len = bacapp_decode_obj_property_ref(apdu, len, &test_data); + zassert_equal(test_len, len, NULL); zassert_equal( - inData.object_identifier.type, - outData.object_identifier.type, NULL); + data.object_identifier.type, test_data.object_identifier.type, NULL); + zassert_equal(data.object_identifier.instance, + test_data.object_identifier.instance, NULL); zassert_equal( - inData.object_identifier.instance, - outData.object_identifier.instance, NULL); + data.property_identifier, test_data.property_identifier, NULL); zassert_equal( - inData.property_identifier, - outData.property_identifier, NULL); - zassert_equal( - inData.property_array_index, - outData.property_array_index, NULL); + data.property_array_index, test_data.property_array_index, NULL); + while (--len) { + test_len = bacapp_decode_obj_property_ref(apdu, len, &test_data); + zassert_true(test_len <= 0, NULL); + } /* context */ - inLen = bacapp_encode_context_obj_property_ref(apdu, tag_number, &inData); - outLen = bacapp_decode_context_obj_property_ref(apdu, inLen, tag_number, - &outData); - zassert_equal(outLen, inLen, NULL); + null_len = bacapp_encode_context_obj_property_ref(NULL, tag_number, &data); + len = bacapp_encode_context_obj_property_ref(apdu, tag_number, &data); + zassert_equal(null_len, len, NULL); + test_len = bacapp_decode_context_obj_property_ref( + apdu, len, tag_number, &test_data); + zassert_equal(test_len, len, "len=%d test_len=%d", len, test_len); zassert_equal( - inData.object_identifier.type, - outData.object_identifier.type, NULL); + data.object_identifier.type, test_data.object_identifier.type, NULL); + zassert_equal(data.object_identifier.instance, + test_data.object_identifier.instance, NULL); zassert_equal( - inData.object_identifier.instance, - outData.object_identifier.instance, NULL); + data.property_identifier, test_data.property_identifier, NULL); zassert_equal( - inData.property_identifier, - outData.property_identifier, NULL); - zassert_equal( - inData.property_array_index, - outData.property_array_index, NULL); + data.property_array_index, test_data.property_array_index, NULL); + while (--len) { + test_len = bacapp_decode_context_obj_property_ref( + apdu, len, tag_number, &test_data); + zassert_true(test_len <= 0, "test_len=%d len=%d", test_len, len); + } + null_len = bacapp_decode_context_obj_property_ref( + NULL, sizeof(apdu), tag_number, &test_data); + zassert_true(test_len <= 0, "test_len=%d len=%d", test_len, len); } /** * @} */ - #if defined(CONFIG_ZTEST_NEW_API) ZTEST_SUITE(bacdevobjpropref_tests, NULL, NULL, NULL, NULL, NULL); #else void test_main(void) { - ztest_test_suite(bacdevobjpropref_tests, - ztest_unit_test(testDevIdPropRef), - ztest_unit_test(testDevIdRef), - ztest_unit_test(testObjPropRef) - ); + ztest_test_suite(bacdevobjpropref_tests, ztest_unit_test(testDevIdPropRef), + ztest_unit_test(testDevIdRef), ztest_unit_test(testObjPropRef)); ztest_run_test_suite(bacdevobjpropref_tests); }