Secure ReadProperty decoding and BACnetActionCommand (#702)
* Refactored and secured BACnetActionCommand codec into bacaction.c module for command object and added to bacapp module encode/decode with define for enabling and pseudo application tag for internal use. * Simplified bacapp_data_len() and moved into bacdcode module as bacnet_enclosed_data_len() function. * Secured ReadProperty-REQUEST and -ACK decoding. * Removed deprecated Keylist_Key() functions from usage. * Removed pseudo application datatypes from bacapp_data_decode() which only uses primitive application tag encoded values. * Defined INT_MAX when it is not already defined by compiler or libc. * Deprecated bacapp_decode_application_data_len() and bacapp_decode_context_data_len() as they are no longer used in any code in the library. * Added BACnetScale to bacapp module. Improved complex property value decoding. Refactored bacapp_decode_known_property() function. * Refactored and improved the bacapp_snprintf() function for printing EPICS. * Fixed Lighting Output WriteProperty to handle known property decoding.
This commit is contained in:
+119
-72
@@ -16,44 +16,15 @@
|
||||
#include <bacnet/bactext.h>
|
||||
|
||||
static const BACNET_APPLICATION_TAG tag_list[] = {
|
||||
BACNET_APPLICATION_TAG_NULL,
|
||||
#if defined(BACAPP_BOOLEAN)
|
||||
BACNET_APPLICATION_TAG_BOOLEAN,
|
||||
#endif
|
||||
#if defined(BACAPP_UNSIGNED)
|
||||
BACNET_APPLICATION_TAG_UNSIGNED_INT,
|
||||
#endif
|
||||
#if defined(BACAPP_SIGNED)
|
||||
BACNET_APPLICATION_TAG_SIGNED_INT,
|
||||
#endif
|
||||
#if defined(BACAPP_REAL)
|
||||
BACNET_APPLICATION_TAG_REAL,
|
||||
#endif
|
||||
#if defined(BACAPP_DOUBLE)
|
||||
BACNET_APPLICATION_TAG_DOUBLE,
|
||||
#endif
|
||||
#if defined(BACAPP_OCTET_STRING)
|
||||
/* primitive tags */
|
||||
BACNET_APPLICATION_TAG_NULL, BACNET_APPLICATION_TAG_BOOLEAN,
|
||||
BACNET_APPLICATION_TAG_UNSIGNED_INT, BACNET_APPLICATION_TAG_SIGNED_INT,
|
||||
BACNET_APPLICATION_TAG_REAL, BACNET_APPLICATION_TAG_DOUBLE,
|
||||
BACNET_APPLICATION_TAG_OCTET_STRING,
|
||||
#endif
|
||||
#if defined(BACAPP_CHARACTER_STRING)
|
||||
BACNET_APPLICATION_TAG_CHARACTER_STRING,
|
||||
#endif
|
||||
#if defined(BACAPP_BIT_STRING)
|
||||
BACNET_APPLICATION_TAG_BIT_STRING,
|
||||
#endif
|
||||
#if defined(BACAPP_ENUMERATED)
|
||||
BACNET_APPLICATION_TAG_ENUMERATED,
|
||||
#endif
|
||||
#if defined(BACAPP_DATE)
|
||||
BACNET_APPLICATION_TAG_DATE,
|
||||
#endif
|
||||
#if defined(BACAPP_TIME)
|
||||
BACNET_APPLICATION_TAG_TIME,
|
||||
#endif
|
||||
#if defined(BACAPP_OBJECT_ID)
|
||||
BACNET_APPLICATION_TAG_OBJECT_ID,
|
||||
#endif
|
||||
#if defined(BACAPP_TYPES_EXTRA)
|
||||
BACNET_APPLICATION_TAG_CHARACTER_STRING, BACNET_APPLICATION_TAG_BIT_STRING,
|
||||
BACNET_APPLICATION_TAG_ENUMERATED, BACNET_APPLICATION_TAG_DATE,
|
||||
BACNET_APPLICATION_TAG_TIME, BACNET_APPLICATION_TAG_OBJECT_ID,
|
||||
/* non-primitive tags */
|
||||
BACNET_APPLICATION_TAG_EMPTYLIST,
|
||||
/* BACnetWeeknday */
|
||||
/* BACNET_APPLICATION_TAG_WEEKNDAY, --> not implemented! */
|
||||
@@ -96,8 +67,11 @@ static const BACNET_APPLICATION_TAG tag_list[] = {
|
||||
/* BACnetBDTEntry */
|
||||
BACNET_APPLICATION_TAG_BDT_ENTRY,
|
||||
/* BACnetFDTEntry */
|
||||
BACNET_APPLICATION_TAG_FDT_ENTRY
|
||||
#endif
|
||||
BACNET_APPLICATION_TAG_FDT_ENTRY,
|
||||
/* BACnetActionCommand */
|
||||
BACNET_APPLICATION_TAG_ACTION_COMMAND,
|
||||
/* BACnetScale */
|
||||
BACNET_APPLICATION_TAG_SCALE
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -138,7 +112,7 @@ static void test_bacapp_decode_data_len(void)
|
||||
zassert_equal(
|
||||
bacapp_decode_data_len(apdu, UINT8_MAX, sizeof(apdu)), 0, NULL);
|
||||
|
||||
expected_value = (int)(~0U >> 1); /* INT_MAX is not universally defined */
|
||||
expected_value = INT_MAX;
|
||||
zassert_equal(
|
||||
bacapp_decode_data_len(
|
||||
apdu, BACNET_APPLICATION_TAG_UNSIGNED_INT, UINT32_MAX),
|
||||
@@ -250,7 +224,7 @@ static void test_bacapp_copy(void)
|
||||
zassert_equal(dest_value.tag, src_value.tag, NULL);
|
||||
zassert_equal(dest_value.next, src_value.next, NULL);
|
||||
|
||||
for (i = 0; i < sizeof(tag_list) / sizeof(tag_list[0]); ++i) {
|
||||
for (i = 0; i < ARRAY_SIZE(tag_list); ++i) {
|
||||
BACNET_APPLICATION_TAG tag = tag_list[i];
|
||||
bool result;
|
||||
bool expected_result = true;
|
||||
@@ -739,8 +713,7 @@ static void testBACnetApplicationDataLength(void)
|
||||
len = encode_closing_tag(&apdu[apdu_len], 3);
|
||||
apdu_len += len;
|
||||
/* verify the length of the data inside the opening/closing tags */
|
||||
len = bacapp_data_len(
|
||||
&apdu[0], apdu_len, PROP_LIST_OF_OBJECT_PROPERTY_REFERENCES);
|
||||
len = bacnet_enclosed_data_length(&apdu[0], apdu_len);
|
||||
zassert_equal(test_len, len, NULL);
|
||||
|
||||
/* 2. application tagged data, one element */
|
||||
@@ -754,7 +727,7 @@ static void testBACnetApplicationDataLength(void)
|
||||
len = encode_closing_tag(&apdu[apdu_len], 3);
|
||||
apdu_len += len;
|
||||
/* verify the length of the data inside the opening/closing tags */
|
||||
len = bacapp_data_len(&apdu[0], apdu_len, PROP_OBJECT_IDENTIFIER);
|
||||
len = bacnet_enclosed_data_length(&apdu[0], apdu_len);
|
||||
zassert_equal(test_len, len, NULL);
|
||||
|
||||
/* 3. application tagged data, multiple elements */
|
||||
@@ -813,7 +786,7 @@ static void testBACnetApplicationDataLength(void)
|
||||
len = encode_closing_tag(&apdu[apdu_len], 3);
|
||||
apdu_len += len;
|
||||
/* verify the length of the data inside the opening/closing tags */
|
||||
len = bacapp_data_len(&apdu[0], apdu_len, PROP_PRIORITY_ARRAY);
|
||||
len = bacnet_enclosed_data_length(&apdu[0], apdu_len);
|
||||
zassert_equal(test_len, len, NULL);
|
||||
|
||||
/* 4. complex datatype - one element */
|
||||
@@ -844,7 +817,7 @@ static void testBACnetApplicationDataLength(void)
|
||||
len = encode_closing_tag(&apdu[apdu_len], 3);
|
||||
apdu_len += len;
|
||||
/* verify the length of the data inside the opening/closing tags */
|
||||
len = bacapp_data_len(&apdu[0], apdu_len, PROP_START_TIME);
|
||||
len = bacnet_enclosed_data_length(&apdu[0], apdu_len);
|
||||
zassert_equal(test_len, len, NULL);
|
||||
|
||||
/* 5. complex datatype - multiple elements */
|
||||
@@ -860,7 +833,7 @@ static void testBACnetApplicationDataLength(void)
|
||||
len = encode_closing_tag(&apdu[apdu_len], 3);
|
||||
apdu_len += len;
|
||||
/* verify the length of the data inside the opening/closing tags */
|
||||
len = bacapp_data_len(&apdu[0], apdu_len, PROP_REQUESTED_SHED_LEVEL);
|
||||
len = bacnet_enclosed_data_length(&apdu[0], apdu_len);
|
||||
zassert_equal(test_len, len, NULL);
|
||||
|
||||
/* 7. context opening & closing tag */
|
||||
@@ -877,7 +850,7 @@ static void testBACnetApplicationDataLength(void)
|
||||
len = encode_closing_tag(&apdu[apdu_len], 3);
|
||||
apdu_len += len;
|
||||
/* verify the length of the data inside the opening/closing tags */
|
||||
len = bacapp_data_len(&apdu[0], apdu_len, PROP_WEEKLY_SCHEDULE);
|
||||
len = bacnet_enclosed_data_length(&apdu[0], apdu_len);
|
||||
zassert_equal(test_len, len, NULL);
|
||||
}
|
||||
|
||||
@@ -891,16 +864,20 @@ verifyBACnetApplicationDataValue(BACNET_APPLICATION_DATA_VALUE *value)
|
||||
int apdu_len = 0;
|
||||
int null_len = 0;
|
||||
int test_len = 0;
|
||||
int len = 0;
|
||||
bool status = false;
|
||||
BACNET_APPLICATION_DATA_VALUE test_value = { 0 };
|
||||
|
||||
/* 1. test that encode length matches NULL */
|
||||
apdu_len = bacapp_encode_application_data(&apdu[0], value);
|
||||
zassert_true(apdu_len > 0, NULL);
|
||||
null_len = bacapp_encode_application_data(NULL, value);
|
||||
zassert_equal(apdu_len, null_len, NULL);
|
||||
/* 2. test that value decoded from buffer matches incoming value */
|
||||
test_len = bacapp_decode_application_data(&apdu[0], apdu_len, &test_value);
|
||||
zassert_true(test_len != BACNET_STATUS_ERROR, NULL);
|
||||
status = bacapp_same_value(value, &test_value);
|
||||
/* 3. test that decoded buffer matches encoded buffer */
|
||||
while (apdu_len) {
|
||||
apdu_len--;
|
||||
test_len =
|
||||
@@ -916,6 +893,20 @@ verifyBACnetApplicationDataValue(BACNET_APPLICATION_DATA_VALUE *value)
|
||||
apdu_len, test_len, null_len);
|
||||
}
|
||||
}
|
||||
/* 4. test bacnet_enclosed_data_length() matches APDU buffer length */
|
||||
apdu_len = 0;
|
||||
test_len = 0;
|
||||
len = encode_opening_tag(&apdu[0], 3);
|
||||
apdu_len += len;
|
||||
len = bacapp_encode_application_data(&apdu[apdu_len], value);
|
||||
test_len += len;
|
||||
apdu_len += len;
|
||||
len = encode_closing_tag(&apdu[apdu_len], 3);
|
||||
apdu_len += len;
|
||||
/* verify the length of the data inside the opening/closing tags */
|
||||
len = bacnet_enclosed_data_length(&apdu[0], apdu_len);
|
||||
zassert_equal(test_len, len, NULL);
|
||||
zassert_equal(null_len, len, NULL);
|
||||
|
||||
return status;
|
||||
}
|
||||
@@ -924,32 +915,50 @@ verifyBACnetApplicationDataValue(BACNET_APPLICATION_DATA_VALUE *value)
|
||||
* @brief Test
|
||||
*/
|
||||
static void verifyBACnetComplexDataValue(
|
||||
BACNET_APPLICATION_DATA_VALUE *value,
|
||||
BACNET_APPLICATION_DATA_VALUE *value,
|
||||
BACNET_OBJECT_TYPE object_type,
|
||||
BACNET_PROPERTY_ID prop)
|
||||
{
|
||||
uint8_t apdu[480] = { 0 };
|
||||
int apdu_len = 0;
|
||||
int null_len = 0;
|
||||
int test_len = 0;
|
||||
int len = 0;
|
||||
BACNET_APPLICATION_DATA_VALUE test_value = { 0 };
|
||||
bool status = false;
|
||||
|
||||
/* 1. test that encode length matches NULL */
|
||||
apdu_len = bacapp_encode_application_data(&apdu[0], value);
|
||||
zassert_true(apdu_len > 0, NULL);
|
||||
null_len = bacapp_encode_application_data(NULL, value);
|
||||
zassert_equal(apdu_len, null_len, "encoded length=%d", apdu_len);
|
||||
apdu_len =
|
||||
bacapp_decode_known_property(&apdu[0], apdu_len, &test_value,
|
||||
object_type, prop);
|
||||
zassert_true(apdu_len != BACNET_STATUS_ERROR, "decoded length=%d", apdu_len);
|
||||
/* 2. test that value decoded from buffer matches incoming value */
|
||||
apdu_len = bacapp_decode_known_property(
|
||||
&apdu[0], apdu_len, &test_value, object_type, prop);
|
||||
zassert_true(
|
||||
apdu_len != BACNET_STATUS_ERROR, "decoded length=%d", apdu_len);
|
||||
zassert_true(apdu_len > 0, "decoded length=%d", apdu_len);
|
||||
|
||||
status = bacapp_same_value(value, &test_value);
|
||||
if (!status) {
|
||||
null_len = 0;
|
||||
null_len = 0;
|
||||
}
|
||||
zassert_true(status, "bacapp: same-value of tag=%s[%u]\n",
|
||||
bactext_application_tag_name(value->tag), value->tag);
|
||||
zassert_true(
|
||||
status, "bacapp: same-value of tag=%s[%u]\n",
|
||||
bactext_application_tag_name(value->tag), value->tag);
|
||||
/* 3. test bacnet_enclosed_data_length() matches APDU buffer length */
|
||||
apdu_len = 0;
|
||||
test_len = 0;
|
||||
len = encode_opening_tag(&apdu[0], 3);
|
||||
apdu_len += len;
|
||||
len = bacapp_encode_application_data(&apdu[apdu_len], value);
|
||||
test_len += len;
|
||||
apdu_len += len;
|
||||
len = encode_closing_tag(&apdu[apdu_len], 3);
|
||||
apdu_len += len;
|
||||
/* verify the length of the data inside the opening/closing tags */
|
||||
len = bacnet_enclosed_data_length(&apdu[0], apdu_len);
|
||||
zassert_equal(test_len, len, NULL);
|
||||
zassert_equal(null_len, len, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1205,17 +1214,17 @@ static void testBACnetApplicationData(void)
|
||||
status = bacapp_parse_application_data(
|
||||
BACNET_APPLICATION_TAG_HOST_N_PORT, "192.168.1.1:47808", &value);
|
||||
zassert_true(status, NULL);
|
||||
verifyBACnetComplexDataValue(&value, OBJECT_NETWORK_PORT,
|
||||
PROP_FD_BBMD_ADDRESS);
|
||||
verifyBACnetComplexDataValue(&value, OBJECT_NETWORK_PORT,
|
||||
PROP_BACNET_IP_GLOBAL_ADDRESS);
|
||||
verifyBACnetComplexDataValue(
|
||||
&value, OBJECT_NETWORK_PORT, PROP_FD_BBMD_ADDRESS);
|
||||
verifyBACnetComplexDataValue(
|
||||
&value, OBJECT_NETWORK_PORT, PROP_BACNET_IP_GLOBAL_ADDRESS);
|
||||
|
||||
status = bacapp_parse_application_data(
|
||||
BACNET_APPLICATION_TAG_BDT_ENTRY, "192.168.1.1:47808,255.255.255.255",
|
||||
BACNET_APPLICATION_TAG_BDT_ENTRY, "192.168.1.1:47808,255.255.255.255",
|
||||
&value);
|
||||
zassert_true(status, NULL);
|
||||
verifyBACnetComplexDataValue(&value, OBJECT_NETWORK_PORT,
|
||||
PROP_BBMD_BROADCAST_DISTRIBUTION_TABLE);
|
||||
verifyBACnetComplexDataValue(
|
||||
&value, OBJECT_NETWORK_PORT, PROP_BBMD_BROADCAST_DISTRIBUTION_TABLE);
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -1224,30 +1233,68 @@ static void testBACnetApplicationData(void)
|
||||
* @brief Test
|
||||
*/
|
||||
#if defined(CONFIG_ZTEST_NEW_API)
|
||||
ZTEST(bacapp_tests, test_bacapp_context_data)
|
||||
ZTEST(bacapp_tests, test_bacapp_data)
|
||||
#else
|
||||
static void test_bacapp_context_data(void)
|
||||
static void test_bacapp_data(void)
|
||||
#endif
|
||||
{
|
||||
const uint8_t context_tag_number = 1;
|
||||
uint8_t apdu[480] = { 0 };
|
||||
BACNET_APPLICATION_DATA_VALUE value = { 0 };
|
||||
int apdu_len, null_len;
|
||||
int apdu_len, null_len, test_len, len;
|
||||
unsigned i = 0;
|
||||
|
||||
for (i = 0; i < sizeof(tag_list) / sizeof(tag_list[0]); i++) {
|
||||
for (i = 0; i < ARRAY_SIZE(tag_list); i++) {
|
||||
/* 1. test encoding matches for NULL and APDU buffer */
|
||||
BACNET_APPLICATION_TAG tag = tag_list[i];
|
||||
value.tag = tag;
|
||||
null_len =
|
||||
bacapp_encode_context_data_value(NULL, context_tag_number, &value);
|
||||
bacapp_encode_application_data(NULL, &value);
|
||||
apdu_len =
|
||||
bacapp_encode_context_data_value(apdu, context_tag_number, &value);
|
||||
bacapp_encode_application_data(apdu, &value);
|
||||
if (apdu_len != null_len) {
|
||||
printf(
|
||||
"bacapp: NULL len=%d != APDU len=%d for tag=%s", null_len,
|
||||
apdu_len, bactext_application_tag_name(tag));
|
||||
}
|
||||
zassert_equal(apdu_len, null_len, NULL);
|
||||
/* 2. test bacnet_enclosed_data_length() matches APDU buffer or NULL */
|
||||
apdu_len = 0;
|
||||
test_len = 0;
|
||||
len = encode_opening_tag(apdu, 3);
|
||||
apdu_len += len;
|
||||
len = bacapp_encode_application_data(
|
||||
&apdu[apdu_len], &value);
|
||||
test_len += len;
|
||||
apdu_len += len;
|
||||
len = encode_closing_tag(&apdu[apdu_len], 3);
|
||||
apdu_len += len;
|
||||
/* verify the length of the data inside the opening/closing tags */
|
||||
len = bacnet_enclosed_data_length(apdu, apdu_len);
|
||||
zassert_equal(test_len, len, NULL);
|
||||
zassert_equal(null_len, len, NULL);
|
||||
/* 3. application tagged */
|
||||
null_len = bacapp_encode_application_data(NULL, &value);
|
||||
apdu_len = bacapp_encode_application_data(apdu, &value);
|
||||
if (apdu_len != null_len) {
|
||||
printf(
|
||||
"bacapp: NULL len=%d != APDU len=%d for tag=%s", null_len,
|
||||
apdu_len, bactext_application_tag_name(tag));
|
||||
}
|
||||
zassert_equal(apdu_len, null_len, NULL);
|
||||
/* 4. test bacnet_enclosed_data_length() matches APDU buffer or NULL */
|
||||
apdu_len = 0;
|
||||
test_len = 0;
|
||||
len = encode_opening_tag(apdu, 3);
|
||||
apdu_len += len;
|
||||
len = bacapp_encode_application_data(&apdu[apdu_len], &value);
|
||||
test_len += len;
|
||||
apdu_len += len;
|
||||
len = encode_closing_tag(&apdu[apdu_len], 3);
|
||||
apdu_len += len;
|
||||
/* verify the length of the data inside the opening/closing tags */
|
||||
len = bacnet_enclosed_data_length(apdu, apdu_len);
|
||||
zassert_equal(test_len, len, NULL);
|
||||
zassert_equal(null_len, len, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1301,7 +1348,7 @@ void test_main(void)
|
||||
ztest_unit_test(testBACnetApplicationData),
|
||||
ztest_unit_test(testBACnetApplicationDataLength),
|
||||
ztest_unit_test(testBACnetApplicationData_Safe),
|
||||
ztest_unit_test(test_bacapp_context_data),
|
||||
ztest_unit_test(test_bacapp_data),
|
||||
ztest_unit_test(test_bacapp_sprintf_data));
|
||||
|
||||
ztest_run_test_suite(bacapp_tests);
|
||||
|
||||
Reference in New Issue
Block a user