Bugfix/bacapp deprecation fixes (#578)

* Secured bacapp_decode_application_data_safe(), bacapp_decode_application_data_len(), bacapp_decode_context_data(), bacapp_decode_known_property() for timestamp, bacapp_decode_context_data_len(), and bacapp_data_len() functions.

* Fixed Command, Credential Data Input, and Schedule objects unit test
This commit is contained in:
Steve Karg
2024-02-27 14:03:14 -06:00
committed by GitHub
parent 33c7df249a
commit dfef5208d1
21 changed files with 698 additions and 548 deletions
+230 -210
View File
@@ -251,14 +251,19 @@ int bacapp_encode_application_data(
/**
* @brief Decode the data and store it into value.
* @param apdu Receive buffer
* @param apdu_size Size of the receive buffer
* @param tag_data_type Data type of the given tag
* @param len_value_type Count of bytes of given tag
* @param value Pointer to the application value structure,
* used to store the decoded value to.
*
* @return Number of octets consumed.
* @return Number of octets consumed (could be zero).
* Parameter value->tag set to MAX_BACNET_APPLICATION_TAG when
* the number of octets consumed is zero and there is an error
* in the decoding, or BACNET_STATUS_ERROR/ABORT/REJECT if malformed.
*/
int bacapp_decode_data(uint8_t *apdu,
int bacapp_data_decode(uint8_t *apdu,
uint32_t apdu_size,
uint8_t tag_data_type,
uint32_t len_value_type,
BACNET_APPLICATION_DATA_VALUE *value)
@@ -279,162 +284,158 @@ int bacapp_decode_data(uint8_t *apdu,
#endif
#if defined(BACAPP_UNSIGNED)
case BACNET_APPLICATION_TAG_UNSIGNED_INT:
len = decode_unsigned(
apdu, len_value_type, &value->type.Unsigned_Int);
len = bacnet_unsigned_decode(
apdu, apdu_size, len_value_type, &value->type.Unsigned_Int);
break;
#endif
#if defined(BACAPP_SIGNED)
case BACNET_APPLICATION_TAG_SIGNED_INT:
len = decode_signed(
apdu, len_value_type, &value->type.Signed_Int);
len = bacnet_signed_decode(
apdu, apdu_size, len_value_type, &value->type.Signed_Int);
break;
#endif
#if defined(BACAPP_REAL)
case BACNET_APPLICATION_TAG_REAL:
len =
decode_real_safe(apdu, len_value_type, &(value->type.Real));
len = bacnet_real_decode(
apdu, apdu_size, len_value_type, &(value->type.Real));
break;
#endif
#if defined(BACAPP_DOUBLE)
case BACNET_APPLICATION_TAG_DOUBLE:
len = decode_double_safe(
apdu, len_value_type, &(value->type.Double));
len = bacnet_double_decode(
apdu, apdu_size, len_value_type, &(value->type.Double));
break;
#endif
#if defined(BACAPP_OCTET_STRING)
case BACNET_APPLICATION_TAG_OCTET_STRING:
len = decode_octet_string(
apdu, len_value_type, &value->type.Octet_String);
len = bacnet_octet_string_decode(
apdu, apdu_size, len_value_type, &value->type.Octet_String);
break;
#endif
#if defined(BACAPP_CHARACTER_STRING)
case BACNET_APPLICATION_TAG_CHARACTER_STRING:
len = decode_character_string(
apdu, len_value_type, &value->type.Character_String);
len = bacnet_character_string_decode(apdu, apdu_size,
len_value_type, &value->type.Character_String);
break;
#endif
#if defined(BACAPP_BIT_STRING)
case BACNET_APPLICATION_TAG_BIT_STRING:
len = decode_bitstring(
apdu, len_value_type, &value->type.Bit_String);
len = bacnet_bitstring_decode(
apdu, apdu_size, len_value_type, &value->type.Bit_String);
break;
#endif
#if defined(BACAPP_ENUMERATED)
case BACNET_APPLICATION_TAG_ENUMERATED:
len = decode_enumerated(
apdu, len_value_type, &value->type.Enumerated);
len = bacnet_enumerated_decode(
apdu, apdu_size, len_value_type, &value->type.Enumerated);
break;
#endif
#if defined(BACAPP_DATE)
case BACNET_APPLICATION_TAG_DATE:
len = decode_date_safe(apdu, len_value_type, &value->type.Date);
len = bacnet_date_decode(
apdu, apdu_size, len_value_type, &value->type.Date);
break;
#endif
#if defined(BACAPP_TIME)
case BACNET_APPLICATION_TAG_TIME:
len = decode_bacnet_time_safe(
apdu, len_value_type, &value->type.Time);
len = bacnet_time_decode(
apdu, apdu_size, len_value_type, &value->type.Time);
break;
#endif
#if defined(BACAPP_OBJECT_ID)
case BACNET_APPLICATION_TAG_OBJECT_ID: {
BACNET_OBJECT_TYPE object_type = OBJECT_NONE;
uint32_t instance = 0;
len = decode_object_id_safe(
apdu, len_value_type, &object_type, &instance);
value->type.Object_Id.type = object_type;
value->type.Object_Id.instance = instance;
len = bacnet_object_id_decode(apdu, apdu_size, len_value_type,
&value->type.Object_Id.type,
&value->type.Object_Id.instance);
} break;
#endif
#if defined(BACAPP_TIMESTAMP)
case BACNET_APPLICATION_TAG_TIMESTAMP:
len = bacnet_timestamp_decode(
apdu, len_value_type, &value->type.Time_Stamp);
apdu, apdu_size, &value->type.Time_Stamp);
break;
#endif
#if defined(BACAPP_DATETIME)
case BACNET_APPLICATION_TAG_DATETIME:
len = bacnet_datetime_decode(
apdu, len_value_type, &value->type.Date_Time);
apdu, apdu_size, &value->type.Date_Time);
break;
#endif
#if defined(BACAPP_DATERANGE)
case BACNET_APPLICATION_TAG_DATERANGE:
len = bacnet_daterange_decode(
apdu, len_value_type, &value->type.Date_Range);
apdu, apdu_size, &value->type.Date_Range);
break;
#endif
#if defined(BACAPP_LIGHTING_COMMAND)
case BACNET_APPLICATION_TAG_LIGHTING_COMMAND:
len = lighting_command_decode(
apdu, len_value_type, &value->type.Lighting_Command);
apdu, apdu_size, &value->type.Lighting_Command);
break;
#endif
#if defined(BACAPP_XY_COLOR)
case BACNET_APPLICATION_TAG_XY_COLOR:
/* BACnetxyColor */
len = xy_color_decode(
apdu, len_value_type, &value->type.XY_Color);
len = xy_color_decode(apdu, apdu_size, &value->type.XY_Color);
break;
#endif
#if defined(BACAPP_COLOR_COMMAND)
case BACNET_APPLICATION_TAG_COLOR_COMMAND:
/* BACnetColorCommand */
len = color_command_decode(
apdu, len_value_type, NULL, &value->type.Color_Command);
apdu, apdu_size, NULL, &value->type.Color_Command);
break;
#endif
#if defined(BACAPP_WEEKLY_SCHEDULE)
case BACNET_APPLICATION_TAG_WEEKLY_SCHEDULE:
len = bacnet_weeklyschedule_decode(
apdu, (int)len_value_type, &value->type.Weekly_Schedule);
apdu, apdu_size, &value->type.Weekly_Schedule);
break;
#endif
#if defined(BACAPP_CALENDAR_ENTRY)
case BACNET_APPLICATION_TAG_CALENDAR_ENTRY:
len = bacnet_calendar_entry_decode(
apdu, len_value_type, &value->type.Calendar_Entry);
apdu, apdu_size, &value->type.Calendar_Entry);
break;
#endif
#if defined(BACAPP_SPECIAL_EVENT)
case BACNET_APPLICATION_TAG_SPECIAL_EVENT:
len = bacnet_special_event_decode(
apdu, (int)len_value_type, &value->type.Special_Event);
apdu, apdu_size, &value->type.Special_Event);
break;
#endif
#if defined(BACAPP_HOST_N_PORT)
case BACNET_APPLICATION_TAG_HOST_N_PORT:
len = host_n_port_decode(
apdu, len_value_type, NULL, &value->type.Host_Address);
apdu, apdu_size, NULL, &value->type.Host_Address);
break;
#endif
#if defined(BACAPP_DEVICE_OBJECT_PROPERTY_REFERENCE)
case BACNET_APPLICATION_TAG_DEVICE_OBJECT_PROPERTY_REFERENCE:
/* BACnetDeviceObjectPropertyReference */
len = bacnet_device_object_property_reference_decode(apdu,
len_value_type,
&value->type.Device_Object_Property_Reference);
apdu_size, &value->type.Device_Object_Property_Reference);
break;
#endif
#if defined(BACAPP_DEVICE_OBJECT_REFERENCE)
case BACNET_APPLICATION_TAG_DEVICE_OBJECT_REFERENCE:
/* BACnetDeviceObjectReference */
len = bacapp_decode_device_obj_ref(
apdu, &value->type.Device_Object_Reference);
len = bacnet_device_object_reference_decode(
apdu, apdu_size, &value->type.Device_Object_Reference);
break;
#endif
#if defined(BACAPP_OBJECT_PROPERTY_REFERENCE)
case BACNET_APPLICATION_TAG_OBJECT_PROPERTY_REFERENCE:
/* BACnetObjectPropertyReference */
len = bacapp_decode_obj_property_ref(apdu, len_value_type,
&value->type.Object_Property_Reference);
len = bacapp_decode_obj_property_ref(
apdu, apdu_size, &value->type.Object_Property_Reference);
break;
#endif
#if defined(BACAPP_DESTINATION)
case BACNET_APPLICATION_TAG_DESTINATION:
/* BACnetDestination */
len = bacnet_destination_decode(
apdu, len_value_type, &value->type.Destination);
apdu, apdu_size, &value->type.Destination);
break;
#endif
default:
@@ -450,9 +451,30 @@ int bacapp_decode_data(uint8_t *apdu,
value->tag = MAX_BACNET_APPLICATION_TAG;
}
}
return len;
}
/**
* @brief Decode the data and store it into value.
* @param apdu Receive buffer
* @param tag_data_type Data type of the given tag
* @param len_value_type Count of bytes of given tag
* @param value Pointer to the application value structure,
* used to store the decoded value to.
*
* @return Number of octets consumed
* @deprecated Use bacapp_data_decode() instead.
*/
int bacapp_decode_data(uint8_t *apdu,
uint8_t tag_data_type,
uint32_t len_value_type,
BACNET_APPLICATION_DATA_VALUE *value)
{
return bacapp_data_decode(
apdu, MAX_APDU, tag_data_type, len_value_type, value);
}
/**
* @brief Decode the BACnet Application Data
*
@@ -460,46 +482,37 @@ int bacapp_decode_data(uint8_t *apdu,
* @param apdu_len_max - number of bytes in the buffer
* @param value - decoded value, if decoded
*
* @return the number of apdu bytes consumed, or #BACNET_STATUS_ERROR
* @return the number of apdu bytes consumed, 0 on bad args, or
* BACNET_STATUS_ERROR
*/
int bacapp_decode_application_data(
uint8_t *apdu, uint32_t apdu_size, BACNET_APPLICATION_DATA_VALUE *value)
{
int len = 0;
int tag_len = 0;
int decode_len = 0;
uint8_t tag_number = 0;
uint32_t len_value_type = 0;
int apdu_len = 0;
BACNET_TAG tag = { 0 };
if (apdu && value && apdu_size && !IS_CONTEXT_SPECIFIC(*apdu)) {
if (!value) {
return 0;
}
len = bacnet_tag_decode(apdu, apdu_size, &tag);
if ((len > 0) && tag.application) {
value->context_specific = false;
tag_len = bacnet_tag_number_and_value_decode(
&apdu[0], apdu_size, &tag_number, &len_value_type);
if (tag_len > 0) {
len += tag_len;
value->tag = tag_number;
if ((unsigned)len <= apdu_size) {
decode_len =
bacapp_decode_data_len(NULL, tag_number, len_value_type);
if ((unsigned)decode_len <= (apdu_size - len)) {
decode_len = bacapp_decode_data(
&apdu[len], tag_number, len_value_type, value);
if (value->tag != MAX_BACNET_APPLICATION_TAG) {
len += decode_len;
} else {
len = BACNET_STATUS_ERROR;
}
} else {
len = BACNET_STATUS_ERROR;
}
} else {
len = BACNET_STATUS_ERROR;
}
value->tag = tag.number;
apdu_len += len;
len = bacapp_data_decode(&apdu[apdu_len], apdu_size - apdu_len,
tag.number, tag.len_value_type, value);
if ((len >= 0) && (value->tag != MAX_BACNET_APPLICATION_TAG)) {
apdu_len += len;
} else {
apdu_len = BACNET_STATUS_ERROR;
}
value->next = NULL;
} else if (apdu && (apdu_size > 0)) {
apdu_len = BACNET_STATUS_ERROR;
}
return len;
return apdu_len;
}
/*
@@ -527,8 +540,7 @@ bool bacapp_decode_application_data_safe(uint8_t *new_apdu,
static uint32_t apdu_len = 0;
int len = 0;
int tag_len = 0;
uint8_t tag_number = 0;
uint32_t len_value_type = 0;
BACNET_TAG tag = { 0 };
bool ret = false;
@@ -537,27 +549,28 @@ bool bacapp_decode_application_data_safe(uint8_t *new_apdu,
apdu_len_remaining = new_apdu_len;
apdu_len = 0;
}
if (value && apdu_len_remaining > 0 &&
!IS_CONTEXT_SPECIFIC(apdu[apdu_len])) {
value->context_specific = false;
tag_len = bacnet_tag_number_and_value_decode(
&apdu[apdu_len], apdu_len_remaining, &tag_number, &len_value_type);
if (!value) {
return ret;
}
tag_len = bacnet_tag_decode(&apdu[apdu_len], apdu_len_remaining, &tag);
if ((tag_len > 0) && tag.application) {
/* If tag_len is zero, then the tag information is truncated */
if (tag_len) {
apdu_len += tag_len;
apdu_len_remaining -= tag_len;
/* The tag is boolean then len_value_type is interpreted as value,
not length, so don't bother checking with apdu_len_remaining */
if (tag_number == BACNET_APPLICATION_TAG_BOOLEAN ||
len_value_type <= apdu_len_remaining) {
value->tag = tag_number;
len = bacapp_decode_data(
&apdu[apdu_len], tag_number, len_value_type, value);
value->context_specific = false;
apdu_len += tag_len;
apdu_len_remaining -= tag_len;
/* The tag is boolean then len_value_type is interpreted as value,
not length, so don't bother checking with apdu_len_remaining */
if (tag.number == BACNET_APPLICATION_TAG_BOOLEAN ||
(tag.len_value_type <= apdu_len_remaining)) {
value->tag = tag.number;
len = bacapp_data_decode(&apdu[apdu_len], apdu_len_remaining,
tag.number, tag.len_value_type, value);
if (value->tag != MAX_BACNET_APPLICATION_TAG) {
apdu_len += len;
apdu_len_remaining -= len;
ret = true;
} else {
ret = false;
}
}
value->next = NULL;
@@ -610,29 +623,23 @@ int bacapp_decode_data_len(
/**
* @brief Determine the BACnet Application Data number of APDU bytes consumed
* @param apdu - buffer of data to be decoded
* @param apdu_len_max - number of bytes in the buffer
* @param apdu_size - number of bytes in the buffer
* @return number of bytes decoded, or zero if errors occur
*/
int bacapp_decode_application_data_len(uint8_t *apdu, unsigned apdu_len_max)
int bacapp_decode_application_data_len(uint8_t *apdu, unsigned apdu_size)
{
int apdu_len = 0;
int len = 0;
int tag_len = 0;
int decode_len = 0;
uint8_t tag_number = 0;
uint32_t len_value_type = 0;
BACNET_TAG tag = { 0 };
if (apdu && !IS_CONTEXT_SPECIFIC(*apdu)) {
tag_len = bacnet_tag_number_and_value_decode(
&apdu[0], apdu_len_max, &tag_number, &len_value_type);
if (tag_len > 0) {
len += tag_len;
decode_len =
bacapp_decode_data_len(NULL, tag_number, len_value_type);
len += decode_len;
}
len = bacnet_tag_decode(apdu, apdu_size, &tag);
if ((len > 0) && (tag.application)) {
apdu_len += len;
len = bacapp_decode_data_len(NULL, tag.number, tag.len_value_type);
apdu_len += len;
}
return len;
return apdu_len;
}
int bacapp_encode_context_data_value(uint8_t *apdu,
@@ -834,7 +841,7 @@ BACNET_APPLICATION_TAG bacapp_context_tag_type(
date [0] Date,
date-range [1] BACnetDateRange,
weekNDay [2] BACnetWeekNDay
}
}
*/
switch (tag_number) {
case 0: /* single calendar date */
@@ -857,7 +864,7 @@ BACNET_APPLICATION_TAG bacapp_context_tag_type(
percent [0] Unsigned,
level [1] Unsigned,
amount [2] REAL
}
}
*/
switch (tag_number) {
case 0:
@@ -909,9 +916,9 @@ BACNET_APPLICATION_TAG bacapp_context_tag_type(
case PROP_LIST_OF_GROUP_MEMBERS:
/* ReadAccessSpecification ::= SEQUENCE {
object-identifier [0] BACnetObjectIdentifier,
list-of-property-references [1] SEQUENCE OF
list-of-property-references [1] SEQUENCE OF
BACnetPropertyReference
}
}
*/
switch (tag_number) {
case 0:
@@ -986,17 +993,17 @@ BACNET_APPLICATION_TAG bacapp_context_tag_type(
monitored-property-reference [1] BACnetObjectPropertyReference,
issue-confirmed-notifications [2] BOOLEAN,
time-remaining [3] Unsigned,
cov-increment [4] REAL OPTIONAL
cov-increment [4] REAL OPTIONAL
-- used only with monitored
-- properties with a numeric datatype
}
*/
switch (tag_number) {
case 0:
case 0:
/* BACnetRecipientProcess ::= SEQUENCE {
recipient [0] BACnetRecipient,
process-identifier [1] Unsigned32
}
}
*/
break;
case 1: /* BACnetObjectPropertyReference */
@@ -1147,43 +1154,54 @@ int bacapp_encode_context_data(uint8_t *apdu,
return apdu_len;
}
/**
* @brief Decode context encoded data
*
* @param apdu - buffer of data to be decoded
* @param apdu_size - number of bytes in the buffer
* @param value - stores the decoded property value
* @param property - context property identifier
* @return number of bytes decoded, or #BACNET_STATUS_ERROR
*/
int bacapp_decode_context_data(uint8_t *apdu,
unsigned max_apdu_len,
unsigned apdu_size,
BACNET_APPLICATION_DATA_VALUE *value,
BACNET_PROPERTY_ID property)
{
int apdu_len = 0, len = 0;
int tag_len = 0;
uint8_t tag_number = 0;
uint32_t len_value_type = 0;
BACNET_TAG tag = { 0 };
if (apdu && value && IS_CONTEXT_SPECIFIC(*apdu)) {
value->context_specific = true;
value->next = NULL;
tag_len =
decode_tag_number_and_value(&apdu[0], &tag_number, &len_value_type);
apdu_len = tag_len;
/* Empty construct : (closing tag) => returns NULL value */
if (tag_len && ((unsigned)tag_len <= max_apdu_len) &&
!decode_is_closing_tag_number(&apdu[0], tag_number)) {
value->context_tag = tag_number;
value->tag = bacapp_context_tag_type(property, tag_number);
if (!value) {
return apdu_len;
}
len = bacnet_tag_decode(&apdu[0], apdu_size, &tag);
if (len > 0) {
if (tag.closing) {
/* Empty construct : (closing tag) */
/* Don't advance over that closing tag. */
apdu_len = 0;
} else if (tag.context) {
apdu_len += len;
value->context_specific = true;
value->next = NULL;
value->context_tag = tag.number;
value->tag = bacapp_context_tag_type(property, tag.number);
if (value->tag != MAX_BACNET_APPLICATION_TAG) {
len = bacapp_decode_data(
&apdu[apdu_len], value->tag, len_value_type, value);
apdu_len += len;
} else if (len_value_type) {
len = bacapp_data_decode(&apdu[apdu_len], apdu_size - apdu_len,
value->tag, tag.len_value_type, value);
if ((len >= 0) && (value->tag != MAX_BACNET_APPLICATION_TAG)) {
apdu_len += len;
} else {
apdu_len = BACNET_STATUS_ERROR;
}
} else if (tag.len_value_type) {
/* Unknown value : non null size (elementary type) */
apdu_len += len_value_type;
apdu_len += tag.len_value_type;
/* SHOULD NOT HAPPEN, EXCEPTED WHEN READING UNKNOWN CONTEXTUAL
* PROPERTY */
} else {
apdu_len = BACNET_STATUS_ERROR;
}
} else if (tag_len == 1) {
/* and is a Closing tag */
/* Don't advance over that closing tag. */
apdu_len = 0;
}
}
@@ -1195,62 +1213,68 @@ int bacapp_decode_context_data(uint8_t *apdu,
* @brief Context or Application tagged property value decoding
*
* @param apdu - buffer of data to be decoded
* @param max_apdu_len - number of bytes in the buffer
* @param apdu_size - number of bytes in the buffer
* @param value - stores the decoded property value
* @param property - context property identifier
* @return number of bytes decoded, or ERROR if errors occur
* @return number of bytes decoded, or #BACNET_STATUS_ERROR
*/
int bacapp_decode_generic_property(uint8_t *apdu,
int max_apdu_len,
int apdu_size,
BACNET_APPLICATION_DATA_VALUE *value,
BACNET_PROPERTY_ID prop)
{
int len = 0;
if (IS_CONTEXT_SPECIFIC(*apdu)) {
len = bacapp_decode_context_data(apdu, max_apdu_len, value, prop);
} else {
len = bacapp_decode_application_data(apdu, max_apdu_len, value);
int apdu_len = BACNET_STATUS_ERROR;
if (apdu && (apdu_size > 0)) {
if (IS_CONTEXT_SPECIFIC(*apdu)) {
apdu_len = bacapp_decode_context_data(apdu, apdu_size, value, prop);
} else {
apdu_len = bacapp_decode_application_data(apdu, apdu_size, value);
}
}
return len;
return apdu_len;
}
#endif
#if defined(BACAPP_COMPLEX_TYPES)
/* decode one value of a priority array */
/**
* @brief Decode BACnetPriorityValue complex data
*
* @param apdu - buffer of data to be decoded
* @param apdu_size - number of bytes in the buffer
* @param value - stores the decoded property value
* @param property - context property identifier
* @return number of bytes decoded, or #BACNET_STATUS_ERROR
*/
static int decode_priority_value(uint8_t *apdu,
unsigned max_apdu_len,
unsigned apdu_size,
BACNET_APPLICATION_DATA_VALUE *value,
BACNET_PROPERTY_ID prop)
BACNET_PROPERTY_ID property)
{
int val_len = 0;
uint32_t len_value_type = 0;
int apdu_len = 0;
int len = 0;
bool is_opening_tag;
uint8_t tag_number;
if (decode_is_context_tag(apdu, 0) && !decode_is_closing_tag(apdu)) {
if (bacnet_is_opening_tag_number(apdu, apdu_size, 0, &len)) {
/* Contextual Abstract-syntax & type */
val_len =
decode_tag_number_and_value(apdu, &tag_number, &len_value_type);
is_opening_tag = decode_is_opening_tag(apdu);
len += val_len;
val_len = bacapp_decode_generic_property(
&apdu[len], max_apdu_len - len, value, prop);
if (val_len < 0) {
apdu_len += len;
len = bacapp_decode_generic_property(
&apdu[apdu_len], apdu_size - apdu_len, value, property);
if (len < 0) {
return BACNET_STATUS_ERROR;
}
len += val_len;
if (is_opening_tag) {
if (!decode_is_closing_tag_number(apdu, 0)) {
return BACNET_STATUS_ERROR;
}
len++;
apdu_len += len;
if (!bacnet_is_closing_tag_number(
&apdu[apdu_len], apdu_size - apdu_len, 0, &len)) {
return BACNET_STATUS_ERROR;
}
apdu_len += len;
} else {
len = bacapp_decode_generic_property(apdu, max_apdu_len, value, prop);
apdu_len =
bacapp_decode_generic_property(apdu, apdu_size, value, property);
}
return len;
return apdu_len;
}
#endif
@@ -1492,7 +1516,8 @@ int bacapp_decode_known_property(uint8_t *apdu,
case PROP_ACCESS_EVENT_TIME:
#ifdef BACAPP_TIMESTAMP
/* Properties using BACnetTimeStamp */
len = bacapp_decode_timestamp(apdu, &value->type.Time_Stamp);
len = bacnet_timestamp_decode(
apdu, max_apdu_len, &value->type.Time_Stamp);
#endif
break;
@@ -1619,23 +1644,19 @@ int bacapp_decode_context_data_len(
uint8_t *apdu, unsigned apdu_len_max, BACNET_PROPERTY_ID property)
{
int apdu_len = 0, len = 0;
int tag_len = 0;
uint8_t tag_number = 0;
uint32_t len_value_type = 0;
uint8_t tag = 0;
BACNET_TAG tag = { 0 };
uint8_t application_tag = 0;
if (apdu && IS_CONTEXT_SPECIFIC(*apdu)) {
tag_len = bacnet_tag_number_and_value_decode(
&apdu[0], apdu_len_max, &tag_number, &len_value_type);
if (tag_len) {
apdu_len = tag_len;
tag = bacapp_context_tag_type(property, tag_number);
if (tag != MAX_BACNET_APPLICATION_TAG) {
len = bacapp_decode_data_len(NULL, tag, len_value_type);
apdu_len += len;
} else {
apdu_len += len_value_type;
}
len = bacnet_tag_decode(&apdu[0], apdu_len_max, &tag);
if ((len > 0) && tag.context) {
apdu_len = len;
application_tag = bacapp_context_tag_type(property, tag.number);
if (application_tag != MAX_BACNET_APPLICATION_TAG) {
len = bacapp_decode_data_len(
NULL, application_tag, tag.len_value_type);
apdu_len += len;
} else {
apdu_len += tag.len_value_type;
}
}
@@ -1758,69 +1779,68 @@ bool bacapp_copy(BACNET_APPLICATION_DATA_VALUE *dest_value,
* Include a value property identifier for context specific data
* such as the value received in a WriteProperty request.
*
* @param Pointer to the APDU buffer
* @param apdu_len_max Bytes valid in the buffer
* @param apdu Pointer to the APDU buffer
* @param apdu_size Bytes valid in the buffer
* @param property ID of the property to get the length for.
*
* @return Length in bytes 0..N, or BACNET_STATUS_ERROR.
*/
int bacapp_data_len(
uint8_t *apdu, unsigned apdu_len_max, BACNET_PROPERTY_ID property)
uint8_t *apdu, unsigned apdu_size, BACNET_PROPERTY_ID property)
{
int len = 0;
int total_len = 0;
int apdu_len = 0;
uint8_t tag_number = 0;
BACNET_TAG tag = { 0 };
uint8_t opening_tag_number = 0;
uint8_t opening_tag_number_counter = 0;
uint32_t value = 0;
bool total_len_enable = false;
if (!apdu) {
return BACNET_STATUS_ERROR;
}
if (apdu_len_max <= apdu_len) {
if (apdu_size <= apdu_len) {
/* error: exceeding our buffer limit */
return BACNET_STATUS_ERROR;
}
if (!bacnet_is_opening_tag(apdu, apdu_len_max)) {
if (!bacnet_is_opening_tag(apdu, apdu_size)) {
/* error: opening tag is missing */
return BACNET_STATUS_ERROR;
}
do {
if (bacnet_is_opening_tag(apdu, apdu_len_max)) {
len = bacnet_tag_number_and_value_decode(
apdu, apdu_len_max - apdu_len, &tag_number, &value);
len = bacnet_tag_decode(apdu, apdu_size - apdu_len, &tag);
if (len == 0) {
return BACNET_STATUS_ERROR;
}
if (tag.opening) {
if (opening_tag_number_counter == 0) {
opening_tag_number = tag_number;
opening_tag_number = tag.number;
opening_tag_number_counter = 1;
total_len_enable = false;
} else if (tag_number == opening_tag_number) {
} else if (tag.number == opening_tag_number) {
total_len_enable = true;
opening_tag_number_counter++;
} else {
total_len_enable = true;
}
} else if (bacnet_is_closing_tag(apdu, apdu_len_max)) {
len = bacnet_tag_number_and_value_decode(
apdu, apdu_len_max - apdu_len, &tag_number, &value);
if (tag_number == opening_tag_number) {
} else if (tag.closing) {
if (tag.number == opening_tag_number) {
if (opening_tag_number_counter > 0) {
opening_tag_number_counter--;
}
}
total_len_enable = true;
} else if (bacnet_is_context_specific(apdu, apdu_len_max)) {
} else if (tag.context) {
#if defined(BACAPP_COMPLEX_TYPES)
/* context-specific tagged data */
len = bacapp_decode_context_data_len(
apdu, apdu_len_max - apdu_len, property);
apdu, apdu_size - apdu_len, property);
total_len_enable = true;
#endif
} else {
/* application tagged data */
len = bacapp_decode_application_data_len(
apdu, apdu_len_max - apdu_len);
len =
bacapp_decode_application_data_len(apdu, apdu_size - apdu_len);
total_len_enable = true;
}
if (opening_tag_number_counter > 0) {
@@ -1833,7 +1853,7 @@ int bacapp_data_len(
return BACNET_STATUS_ERROR;
}
apdu_len += len;
if (apdu_len_max <= apdu_len) {
if (apdu_size <= apdu_len) {
/* error: exceeding our buffer limit */
return BACNET_STATUS_ERROR;
}
+9 -1
View File
@@ -206,10 +206,18 @@ extern "C" {
uint8_t * apdu,
BACNET_APPLICATION_DATA_VALUE * value);
BACNET_STACK_EXPORT
int bacapp_data_decode(
uint8_t * apdu,
uint32_t apdu_size,
uint8_t tag_data_type,
uint32_t len_value_type,
BACNET_APPLICATION_DATA_VALUE * value);
BACNET_STACK_DEPRECATED("Use bacapp_data_decode() instead")
BACNET_STACK_EXPORT
int bacapp_decode_data(
uint8_t * apdu,
uint8_t tag_data_type,
uint32_t apdu_size,
uint32_t len_value_type,
BACNET_APPLICATION_DATA_VALUE * value);
BACNET_STACK_EXPORT
+36 -13
View File
@@ -379,6 +379,34 @@ void Command_Property_Lists(
return;
}
/**
* @brief Determine if the object property is a member of this object instance
* @param object_instance - object-instance number of the object
* @param object_property - object-property to be checked
* @return true if the property is a member of this object instance
*/
static bool Property_List_Member(
uint32_t object_instance, int object_property)
{
bool found = false;
const int *pRequired = NULL;
const int *pOptional = NULL;
const int *pProprietary = NULL;
(void)object_instance;
Command_Property_Lists(
&pRequired, &pOptional, &pProprietary);
found = property_list_member(pRequired, object_property);
if (!found) {
found = property_list_member(pOptional, object_property);
}
if (!found) {
found = property_list_member(pProprietary, object_property);
}
return found;
}
/**
* Initializes the Command object data
*/
@@ -797,21 +825,16 @@ bool Command_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data)
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
status = false;
}
break;
case PROP_OBJECT_IDENTIFIER:
case PROP_OBJECT_NAME:
case PROP_OBJECT_TYPE:
case PROP_IN_PROCESS:
case PROP_ALL_WRITES_SUCCESSFUL:
case PROP_ACTION:
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
break;
default:
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
if (Property_List_Member(
wp_data->object_instance, wp_data->object_property)) {
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
} else {
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
}
break;
}
+35 -19
View File
@@ -223,6 +223,33 @@ void Network_Port_Property_Lists(
Object_List[0].Instance_Number, pRequired, pOptional, pProprietary);
}
/**
* @brief Determine if the object property is a member of this object instance
* @param object_instance - object-instance number of the object
* @param object_property - object-property to be checked
* @return true if the property is a member of this object instance
*/
static bool Property_List_Member(
uint32_t object_instance, int object_property)
{
bool found = false;
const int *pRequired = NULL;
const int *pOptional = NULL;
const int *pProprietary = NULL;
Network_Port_Property_List(object_instance,
&pRequired, &pOptional, &pProprietary);
found = property_list_member(pRequired, object_property);
if (!found) {
found = property_list_member(pOptional, object_property);
}
if (!found) {
found = property_list_member(pProprietary, object_property);
}
return found;
}
/**
* For a given object instance-number, loads the object-name into
* a characterstring. Note that the object name must be unique
@@ -2523,26 +2550,15 @@ bool Network_Port_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data)
}
}
break;
case PROP_OBJECT_IDENTIFIER:
case PROP_OBJECT_NAME:
case PROP_OBJECT_TYPE:
case PROP_STATUS_FLAGS:
case PROP_RELIABILITY:
case PROP_OUT_OF_SERVICE:
case PROP_NETWORK_TYPE:
case PROP_PROTOCOL_LEVEL:
case PROP_NETWORK_NUMBER:
case PROP_NETWORK_NUMBER_QUALITY:
case PROP_MAC_ADDRESS:
case PROP_LINK_SPEED:
case PROP_CHANGES_PENDING:
case PROP_APDU_LENGTH:
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
break;
default:
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
if (Property_List_Member(
wp_data->object_instance, wp_data->object_property)) {
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
} else {
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
}
break;
}