Secure BACnet decoders and service requests (#1244)

* Secured BACnetAssignedAccessRights decoder.

* Secured BACnetPropertyState decoder.

* Secured BACnetCredentialAuthenticationFactor decoder.

* Secured BACnetEventState change-of-state [1] SEQUENCE decoder.

* Secured I-Have-Request service decoder.

* Secured Add/Remove ListElement service request decoder.

* Secured ConfirmedPrivateTransfer-Request and UnconfirmedPrivateTransfer-Request decoders.

* Secured ReadPropertyMultiple-Request and -Ack decoders.

* Secured TimeSynchronization-Request decoder.

* Secured WritePropertyMultiple service decoders

* Secured Trend Log object TL_fetch_property() function.

* Secured ReadProperty-Ack decider,

* Refactor BACnet time sync recipient handling by moving timesync linked list structure into bacdest where the recipient encoder and decoder already existed.

* Secured decoding of BACnetPropertyState.

* Secured decoding in the LifeSafetyOperation-Request service.

* Secured BACnetAuthenticationFactor decoding in the Credential Data Input object.

* Fixed WriteProperty decoder to avoid read buffer overrun.  Improved WriteProperty error reporting by adding specific reject codes during decoding similar to WritePropertyMultiple. Deduplicated the WriteProperty handling of abort, reject and error codes.

* Added BACNET_STACK_DEPRECATED_DISABLE guards around all of the deprecated decoding functions to ensure they are not used except intentionally for legacy code bases.

* Changed version to 1.5.0.rc5 for security fix tracking in branch.
This commit is contained in:
Steve Karg
2026-02-26 10:48:25 -06:00
committed by GitHub
parent cf4f62f7e0
commit a70ce07507
44 changed files with 1841 additions and 1164 deletions
+2
View File
@@ -167,6 +167,7 @@ int bacnet_access_rule_decode(
return apdu_len;
}
#if defined(BACNET_STACK_DEPRECATED_DISABLE)
/**
* @brief Decode the BACnetAccessRule
* @param apdu Pointer to the buffer for decoding.
@@ -178,6 +179,7 @@ int bacapp_decode_access_rule(const uint8_t *apdu, BACNET_ACCESS_RULE *data)
{
return bacnet_access_rule_decode(apdu, MAX_APDU, data);
}
#endif
/**
* @brief Parse a string into a BACnetAccessRule value
+85 -37
View File
@@ -9,6 +9,18 @@
#include "bacnet/assigned_access_rights.h"
#include "bacnet/bacdcode.h"
/**
* @brief Encode a BACnetAssignedAccessRights structure into an APDU buffer.
*
* BACnetAssignedAccessRights ::= SEQUENCE {
* assigned-access-rights [0]BACnetDeviceObjectReference,
* enable [1] Boolean
* }
*
* @param apdu [in] The APDU buffer, or NULL for length
* @param aar [in] The BACnetAssignedAccessRights structure to encode
* @return number of bytes encoded, or negative on error
*/
int bacapp_encode_assigned_access_rights(
uint8_t *apdu, const BACNET_ASSIGNED_ACCESS_RIGHTS *aar)
{
@@ -33,6 +45,16 @@ int bacapp_encode_assigned_access_rights(
return apdu_len;
}
/**
* @brief Encode a BACnetAssignedAccessRights structure into an APDU buffer,
* with context tag.
*
* @param apdu [in] The APDU buffer, or NULL for length
* @param tag [in] The context tag number to use for the opening and closing
* tags
* @param aar [in] The BACnetAssignedAccessRights structure to encode
* @return number of bytes encoded, or negative on error
*/
int bacapp_encode_context_assigned_access_rights(
uint8_t *apdu, uint8_t tag, const BACNET_ASSIGNED_ACCESS_RIGHTS *aar)
{
@@ -51,60 +73,86 @@ int bacapp_encode_context_assigned_access_rights(
return apdu_len;
}
/**
* @brief Decode a BACnetAssignedAccessRights structure from an APDU buffer.
*
* @param apdu [in] The APDU buffer to decode
* @param apdu_size [in] The size of the APDU buffer
* @param aar [out] The BACnetAssignedAccessRights structure to fill with
* decoded values
* @return number of bytes decoded, or negative on error
*/
int bacapp_decode_assigned_access_rights(
const uint8_t *apdu, BACNET_ASSIGNED_ACCESS_RIGHTS *aar)
const uint8_t *apdu, size_t apdu_size, BACNET_ASSIGNED_ACCESS_RIGHTS *data)
{
int len;
int apdu_len = 0;
int len = 0, apdu_len = 0;
bool enable = false;
BACNET_DEVICE_OBJECT_REFERENCE *reference = NULL;
if (decode_is_context_tag(&apdu[apdu_len], 0)) {
len = bacapp_decode_context_device_obj_ref(
&apdu[apdu_len], 0, &aar->assigned_access_rights);
if (len < 0) {
return -1;
} else {
apdu_len += len;
}
} else {
return -1;
if (data) {
reference = &data->assigned_access_rights;
}
if (decode_is_context_tag(&apdu[apdu_len], 1)) {
len = decode_context_boolean2(&apdu[apdu_len], 1, &aar->enable);
if (len < 0) {
return -1;
} else {
apdu_len += len;
}
len = bacnet_device_object_reference_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 0, reference);
if (len <= 0) {
return BACNET_STATUS_ERROR;
} else {
return -1;
apdu_len += len;
/* reference already decoded in place */
}
len = bacnet_boolean_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 1, &enable);
if (len <= 0) {
return BACNET_STATUS_ERROR;
} else {
apdu_len += len;
if (data) {
data->enable = enable;
}
}
return apdu_len;
}
/**
* @brief Decode a BACnetAssignedAccessRights structure from an APDU buffer,
* with context tag.
*
* @param apdu [in] The APDU buffer to decode
* @param apdu_size [in] The size of the APDU buffer
* @param tag [in] The context tag number to use for the opening and closing
* tags
* @param aar [out] The BACnetAssignedAccessRights structure to fill with
* decoded values
* @return number of bytes decoded, or negative on error
*/
int bacapp_decode_context_assigned_access_rights(
const uint8_t *apdu, uint8_t tag, BACNET_ASSIGNED_ACCESS_RIGHTS *aar)
const uint8_t *apdu,
size_t apdu_size,
uint8_t tag,
BACNET_ASSIGNED_ACCESS_RIGHTS *data)
{
int len = 0;
int section_length;
int len = 0, apdu_len = 0;
if (decode_is_opening_tag_number(&apdu[len], tag)) {
len++;
section_length = bacapp_decode_assigned_access_rights(&apdu[len], aar);
if (section_length == -1) {
len = -1;
if (bacnet_is_opening_tag_number(
&apdu[apdu_len], apdu_size - apdu_len, tag, &len)) {
apdu_len += len;
len = bacapp_decode_assigned_access_rights(
&apdu[apdu_len], apdu_size - apdu_len, data);
if (len < 0) {
apdu_len = len;
} else {
len += section_length;
if (decode_is_closing_tag_number(&apdu[len], tag)) {
len++;
apdu_len += len;
if (bacnet_is_closing_tag_number(
&apdu[apdu_len], apdu_size - apdu_len, tag, &len)) {
apdu_len += len;
} else {
len = -1;
apdu_len = BACNET_STATUS_ERROR;
}
}
} else {
len = -1;
apdu_len = BACNET_STATUS_ERROR;
}
return len;
return apdu_len;
}
+5 -2
View File
@@ -33,10 +33,13 @@ int bacapp_encode_context_assigned_access_rights(
uint8_t *apdu, uint8_t tag, const BACNET_ASSIGNED_ACCESS_RIGHTS *aar);
BACNET_STACK_EXPORT
int bacapp_decode_assigned_access_rights(
const uint8_t *apdu, BACNET_ASSIGNED_ACCESS_RIGHTS *aar);
const uint8_t *apdu, size_t apdu_size, BACNET_ASSIGNED_ACCESS_RIGHTS *aar);
BACNET_STACK_EXPORT
int bacapp_decode_context_assigned_access_rights(
const uint8_t *apdu, uint8_t tag, BACNET_ASSIGNED_ACCESS_RIGHTS *aar);
const uint8_t *apdu,
size_t apdu_size,
uint8_t tag,
BACNET_ASSIGNED_ACCESS_RIGHTS *aar);
#ifdef __cplusplus
}
+4
View File
@@ -131,6 +131,7 @@ int bacnet_authentication_factor_decode(
return apdu_len;
}
#if defined(BACNET_STACK_DEPRECATED_DISABLE)
/**
* @brief Decode the BACnetAuthenticationFactor complex data
* @param apdu Pointer to the buffer for decoding.
@@ -143,6 +144,7 @@ int bacapp_decode_authentication_factor(
{
return bacnet_authentication_factor_decode(apdu, MAX_APDU, af);
}
#endif
/**
* @brief Decode the context tagged BACnetAuthenticationFactor complex data
@@ -186,6 +188,7 @@ int bacnet_authentication_factor_context_decode(
return apdu_len;
}
#if defined(BACNET_STACK_DEPRECATED_DISABLE)
/**
* @brief Decode the context tagged BACnetAuthenticationFactor complex data
* @param apdu Pointer to the buffer for decoding.
@@ -201,3 +204,4 @@ int bacapp_decode_context_authentication_factor(
{
return bacnet_authentication_factor_context_decode(apdu, MAX_APDU, tag, af);
}
#endif
@@ -146,6 +146,7 @@ int bacnet_authentication_factor_format_decode(
return apdu_len;
}
#if defined(BACNET_STACK_DEPRECATED_DISABLE)
/**
* @brief Decode a BACnetAuthenticationFactorFormat property value
* @param apdu Pointer to the buffer for decoding.
@@ -160,6 +161,7 @@ int bacapp_decode_authentication_factor_format(
{
return bacnet_authentication_factor_format_decode(apdu, MAX_APDU, data);
}
#endif
/**
* @brief Decode a context tagged BACnetAuthenticationFactorFormat property
@@ -201,6 +203,7 @@ int bacnet_authentication_factor_format_context_decode(
return apdu_len;
}
#if defined(BACNET_STACK_DEPRECATED_DISABLE)
/**
* @brief Decode a context tagged BACnetAuthenticationFactorFormat property
* value
@@ -219,3 +222,4 @@ int bacapp_decode_context_authentication_factor_format(
return bacnet_authentication_factor_format_context_decode(
apdu, MAX_APDU, tag, data);
}
#endif
+4
View File
@@ -556,6 +556,7 @@ int encode_bacnet_address(uint8_t *apdu, const BACNET_ADDRESS *destination)
return apdu_len;
}
#if defined(BACNET_STACK_DEPRECATED_DISABLE)
/**
* @brief Decode a BACnetAddress and returns the number of apdu bytes consumed.
* @param apdu Receive buffer
@@ -567,6 +568,7 @@ int decode_bacnet_address(const uint8_t *apdu, BACNET_ADDRESS *value)
{
return bacnet_address_decode(apdu, MAX_APDU, value);
}
#endif
/**
* @brief Encode a context encoded BACnetAddress
@@ -592,6 +594,7 @@ int encode_context_bacnet_address(
return len;
}
#if defined(BACNET_STACK_DEPRECATED_DISABLE)
/*
* @brief Decodes a context tagged BACnetAddress value from APDU buffer
* @param apdu - the APDU buffer
@@ -605,6 +608,7 @@ int decode_context_bacnet_address(
{
return bacnet_address_context_decode(apdu, MAX_APDU, tag_number, value);
}
#endif
/**
* @brief Encode a BACnetVMACEntry value
+8
View File
@@ -564,6 +564,7 @@ int bacapp_data_decode(
return len;
}
#if defined(BACNET_STACK_DEPRECATED_DISABLE)
/**
* @brief Decode the data and store it into value.
* @param apdu Receive buffer
@@ -584,6 +585,7 @@ int bacapp_decode_data(
return bacapp_data_decode(
apdu, MAX_APDU, tag_data_type, len_value_type, value);
}
#endif
/**
* @brief Decode the BACnet Application Data
@@ -694,6 +696,7 @@ bool bacapp_decode_application_data_safe(
return ret;
}
#if defined(BACNET_STACK_DEPRECATED_DISABLE)
/**
* @brief Decode the data to determine the data length
* @param apdu Pointer to the received data.
@@ -708,7 +711,9 @@ int bacapp_decode_data_len(
(void)apdu;
return bacnet_application_data_length(tag_number, len_value_type);
}
#endif
#if defined(BACNET_STACK_DEPRECATED_DISABLE)
/**
* @brief Determine the BACnet Application Data number of APDU bytes consumed
* @param apdu - buffer of data to be decoded
@@ -735,6 +740,7 @@ int bacapp_decode_application_data_len(const uint8_t *apdu, unsigned apdu_size)
return len;
}
#endif
/**
* @brief Encode a BACnet Context tagged data,
@@ -853,6 +859,7 @@ int bacapp_encode_context_data_value(
return apdu_len;
}
#if defined(BACNET_STACK_DEPRECATED_DISABLE)
/**
* @brief Lookup an application tag for specific context tagged data
* @param property - object property identifier
@@ -875,6 +882,7 @@ bacapp_context_tag_type(BACNET_PROPERTY_ID property, uint8_t tag_number)
return (BACNET_APPLICATION_TAG)tag;
}
#endif
/**
* @brief Encode a BACnet Context tagged data
+69 -1
View File
@@ -361,6 +361,7 @@ int encode_closing_tag(uint8_t *apdu, uint8_t tag_number)
return len;
}
#if defined(BACNET_STACK_DEPRECATED_DISABLE)
/**
* Decode a BACnet tag and returns the number of bytes consumed.
*
@@ -390,6 +391,7 @@ int decode_tag_number(const uint8_t *apdu, uint8_t *tag_number)
return len;
}
#endif
/**
* @brief Decode the BACnet Tag Number
@@ -577,6 +579,7 @@ int bacnet_tag_decode(const uint8_t *apdu, uint32_t apdu_size, BACNET_TAG *tag)
return len;
}
#if defined(BACNET_STACK_DEPRECATED_DISABLE)
/**
* @brief Returns if at the given pointer a
* opening tag has been found.
@@ -588,6 +591,7 @@ bool decode_is_opening_tag(const uint8_t *apdu)
{
return (bool)((apdu[0] & 0x07) == 6);
}
#endif
/**
* @brief Returns true if an opening tag has been found.
@@ -610,6 +614,7 @@ bool bacnet_is_opening_tag(const uint8_t *apdu, uint32_t apdu_size)
return tag;
}
#if defined(BACNET_STACK_DEPRECATED_DISABLE)
/**
* @brief Returns if at the given pointer a
* closing tag has been found.
@@ -621,6 +626,7 @@ bool decode_is_closing_tag(const uint8_t *apdu)
{
return (bool)((apdu[0] & 0x07) == 7);
}
#endif
/**
* @brief Returns true if a closing tag has been found.
@@ -664,6 +670,7 @@ bool bacnet_is_context_specific(const uint8_t *apdu, uint32_t apdu_size)
return tag;
}
#if defined(BACNET_STACK_DEPRECATED_DISABLE)
/**
* @brief Decodes the tag number and the value,
* that the APDU pointer is addressing.
@@ -725,7 +732,9 @@ int decode_tag_number_and_value(
return len;
}
#endif
#if defined(BACNET_STACK_DEPRECATED_DISABLE)
/**
* @brief Decode the BACnet Tag Number and Value
* as defined in clause 20.2.1.3.2 Constructed Data
@@ -759,6 +768,7 @@ int bacnet_tag_number_and_value_decode(
return len;
}
#endif
/**
* @brief Determine the data length from the application tag number
@@ -889,6 +899,7 @@ int bacnet_enclosed_data_length(const uint8_t *apdu, size_t apdu_size)
return total_len;
}
#if defined(BACNET_STACK_DEPRECATED_DISABLE)
/**
* @brief Returns true if the tag is context specific
* and matches, as defined in clause 20.2.1.3.2 Constructed
@@ -908,7 +919,9 @@ bool decode_is_context_tag(const uint8_t *apdu, uint8_t tag_number)
return (bool)(IS_CONTEXT_SPECIFIC(*apdu) && (my_tag_number == tag_number));
}
#endif
#if defined(BACNET_STACK_DEPRECATED_DISABLE)
/**
* @brief Returns true if the tag is context specific
* and matches, as defined in clause 20.2.1.3.2 Constructed
@@ -931,6 +944,7 @@ bool decode_is_context_tag_with_length(
return (bool)(IS_CONTEXT_SPECIFIC(*apdu) && (my_tag_number == tag_number));
}
#endif
/**
* @brief Returns true if the tag is context specific
@@ -974,6 +988,7 @@ bool bacnet_is_context_tag_number(
return match;
}
#if defined(BACNET_STACK_DEPRECATED_DISABLE)
/**
* @brief Returns true if the tag does match and it
* is an opening tag as well.
@@ -993,6 +1008,7 @@ bool decode_is_opening_tag_number(const uint8_t *apdu, uint8_t tag_number)
return (bool)(IS_OPENING_TAG(apdu[0]) && (my_tag_number == tag_number));
}
#endif
/**
* @brief Returns true if the tag number matches is an opening tag.
@@ -1033,6 +1049,7 @@ bool bacnet_is_opening_tag_number(
return match;
}
#if defined(BACNET_STACK_DEPRECATED_DISABLE)
/**
* @brief Returns true if the tag does match and it
* is an closing tag as well.
@@ -1051,6 +1068,7 @@ bool decode_is_closing_tag_number(const uint8_t *apdu, uint8_t tag_number)
decode_tag_number(apdu, &my_tag_number);
return (bool)(IS_CLOSING_TAG(apdu[0]) && (my_tag_number == tag_number));
}
#endif
/**
* @brief Returns true if the tag number matches is an closing tag.
@@ -1141,11 +1159,12 @@ int encode_context_boolean(
return len;
}
#if defined(BACNET_STACK_DEPRECATED_DISABLE)
/**
* @brief Decode an boolean value.
* @param apdu Pointer to the encode buffer.
* @return true/false
* @deprecated Use bacnet_boolean_context_decode() instead
* @deprecated Use bacnet_boolean_context_value_decode() instead
*/
bool decode_context_boolean(const uint8_t *apdu)
{
@@ -1157,7 +1176,9 @@ bool decode_context_boolean(const uint8_t *apdu)
return boolean_value;
}
#endif
#if defined(BACNET_STACK_DEPRECATED_DISABLE)
/**
* @brief Decode an boolean value in the context of a tag.
*
@@ -1187,6 +1208,7 @@ int decode_context_boolean2(
return len;
}
#endif
/**
* @brief Check the length value and return the boolean meaning.
@@ -1526,6 +1548,7 @@ uint8_t bacnet_byte_reverse_bits(uint8_t in_byte)
return out_byte;
}
#if defined(BACNET_STACK_DEPRECATED_DISABLE)
/**
* @brief Decode a bit string value.
* (From clause 20.2.10 Encoding of a Bit String Value.)
@@ -1570,6 +1593,7 @@ int decode_bitstring(
return len;
}
#endif
/**
* @brief Decodes from bytes into a BACnet bit string value.
@@ -1735,6 +1759,7 @@ int bacnet_bitstring_context_decode(
return apdu_len;
}
#if defined(BACNET_STACK_DEPRECATED_DISABLE)
/**
* @brief Decode a bit string value in the given context.
* (From clause 20.2.10 Encoding of a Bit String Value.)
@@ -1764,6 +1789,7 @@ int decode_context_bitstring(
return len;
}
#endif
/**
* @brief Encode the BACnet Bit String Value
@@ -2131,6 +2157,7 @@ bool bacnet_object_id_same(
return status;
}
#if defined(BACNET_STACK_DEPRECATED_DISABLE)
/**
* @brief Decode the BACnet Object Identifier Value when context encoded
* as defined in clause 20.2.14 Encoding of an Object Identifier Value
@@ -2161,6 +2188,7 @@ int decode_context_object_id(
return len;
}
#endif
/**
* @brief Encode the BACnet Object Identifier Value
@@ -2654,6 +2682,7 @@ int bacnet_octet_string_decode(
return len;
}
#if defined(BACNET_STACK_DEPRECATED_DISABLE)
/**
* @brief Decode the BACnet Octet String Value
* from clause 20.2.8 Encoding of an Octet String Value
@@ -2673,7 +2702,9 @@ int decode_octet_string(
return bacnet_octet_string_decode(apdu, apdu_len_max, len_value, value);
}
#endif
#if defined(BACNET_STACK_DEPRECATED_DISABLE)
/**
* @brief Decodes from bytes into a BACnet Octet String context encoding
* from clause 20.2.8 Encoding of an Octet String Value
@@ -2712,6 +2743,7 @@ int decode_context_octet_string(
return len;
}
#endif
/**
* @brief Encode an application tagged BACnet Octet String Value
@@ -2829,6 +2861,7 @@ int bacnet_octet_string_context_decode(
}
#endif
#if defined(BACNET_STACK_DEPRECATED_DISABLE)
/**
* @brief Encode the BACnet Character String Value
* from 20.2.9 Encoding of a Character String Value
@@ -2867,6 +2900,7 @@ uint32_t encode_bacnet_character_string_safe(
return apdu_len;
}
#endif
/**
* @brief Encode the BACnet Character String Value
@@ -3000,6 +3034,7 @@ int bacnet_character_string_decode(
return len;
}
#if defined(BACNET_STACK_DEPRECATED_DISABLE)
/**
* @brief Decodes from bytes into a BACnet Character String value
* from clause 20.2.9 Encoding of a Character String Value
@@ -3019,6 +3054,7 @@ int decode_character_string(
return bacnet_character_string_decode(apdu, apdu_size, len_value, value);
}
#endif
/**
* @brief Encode an application tagged BACnet Character String value
@@ -3135,6 +3171,7 @@ int bacnet_character_string_context_decode(
return apdu_len;
}
#if defined(BACNET_STACK_DEPRECATED_DISABLE)
/**
* @brief Decodes from bytes into a BACnet Character String value
* from clause 20.2.9 Encoding of a Character String Value
@@ -3162,6 +3199,7 @@ int decode_context_character_string(
return len;
}
#endif
/**
* @brief Encode the BACnet Character String Value
@@ -3737,6 +3775,7 @@ int bacnet_unsigned_application_decode(
return apdu_len;
}
#if defined(BACNET_STACK_DEPRECATED_DISABLE)
/**
* @brief Decodes from bytes into a BACnet Unsigned value
* from clause 20.2.4 Encoding of an Unsigned Integer Value
@@ -3760,7 +3799,9 @@ int decode_unsigned(
return bacnet_unsigned_decode(apdu, apdu_size, len_value, value);
}
#endif
#if defined(BACNET_STACK_DEPRECATED_DISABLE)
/**
* @brief Decodes from bytes into a BACnet Unsigned value
* from clause 20.2.4 Encoding of an Unsigned Integer Value
@@ -3791,6 +3832,7 @@ int decode_context_unsigned(
return len;
}
#endif
/**
* @brief Encode the BACnet Unsigned value
@@ -4061,6 +4103,7 @@ int bacnet_enumerated_context_decode(
return apdu_len;
}
#if defined(BACNET_STACK_DEPRECATED_DISABLE)
/**
* @brief Decodes from bytes into a BACnet Enumerated value
* from clause 20.2.11 Encoding of an Enumerated Value
@@ -4087,6 +4130,7 @@ int decode_context_enumerated(
return len;
}
#endif
/**
* @brief Encode the BACnet Enumerated Value
@@ -4315,6 +4359,7 @@ int bacnet_signed_application_decode(
return apdu_len;
}
#if defined(BACNET_STACK_DEPRECATED_DISABLE)
/**
* @brief Decodes from bytes into a BACnet Signed Integer
* from clause 20.2.5 Encoding of an Signed Integer Value
@@ -4334,7 +4379,9 @@ int decode_signed(const uint8_t *apdu, uint32_t len_value, int32_t *value)
return bacnet_signed_decode(apdu, apdu_size, len_value, value);
}
#endif
#if defined(BACNET_STACK_DEPRECATED_DISABLE)
/**
* @brief Decodes from bytes into a BACnet Signed Integer
* from clause 20.2.5 Encoding of an Signed Integer Value
@@ -4361,6 +4408,7 @@ int decode_context_signed(
return len;
}
#endif
/**
* @brief Decodes from bytes into a BACnet Signed Integer
@@ -4640,6 +4688,7 @@ int bacnet_real_application_decode(
return apdu_len;
}
#if defined(BACNET_STACK_DEPRECATED_DISABLE)
/**
* @brief Decode a context tagged single precision floating value.
* From clause 20.2.6 Encoding of a Real Number Value
@@ -4668,6 +4717,7 @@ int decode_context_real(
return len;
}
#endif
#if BACNET_USE_DOUBLE
/**
@@ -4874,6 +4924,7 @@ int bacnet_double_application_decode(
* if wrong tag number or malformed
* @deprecated use bacnet_double_context_decode() instead
*/
#if defined(BACNET_STACK_DEPRECATED_DISABLE)
int decode_context_double(
const uint8_t *apdu, uint8_t tag_number, double *double_value)
{
@@ -4889,6 +4940,7 @@ int decode_context_double(
return len;
}
#endif
#endif
/**
* @brief Encode a Time Value
@@ -5117,6 +5169,7 @@ int bacnet_time_application_decode(
return apdu_len;
}
#if defined(BACNET_STACK_DEPRECATED_DISABLE)
/**
* @brief Decodes from bytes into a BACnet Time Value
* from clause 20.2.13 Encoding of a Time Value
@@ -5135,7 +5188,9 @@ int decode_bacnet_time(const uint8_t *apdu, BACNET_TIME *value)
return bacnet_time_decode(apdu, apdu_size, len_value, value);
}
#endif
#if defined(BACNET_STACK_DEPRECATED_DISABLE)
/**
* @brief Decodes from bytes into a BACnet Time Value
* from clause 20.2.13 Encoding of a Time Value
@@ -5162,7 +5217,9 @@ int decode_bacnet_time_safe(
return decode_bacnet_time(apdu, btime);
}
}
#endif
#if defined(BACNET_STACK_DEPRECATED_DISABLE)
/**
* @brief Decodes from bytes into a BACnet Time Value application encoded
* from clause 20.2.13 Encoding of a Time Value
@@ -5190,7 +5247,9 @@ int decode_application_time(const uint8_t *apdu, BACNET_TIME *btime)
return len;
}
#endif
#if defined(BACNET_STACK_DEPRECATED_DISABLE)
/**
* @brief Decodes from bytes into a BACnet Time Value context encoded
* from clause 20.2.13 Encoding of a Time Value
@@ -5216,6 +5275,7 @@ int decode_context_bacnet_time(
return len;
}
#endif
/**
* @brief Encode a Date value
@@ -5309,6 +5369,7 @@ int encode_context_date(
return apdu_len;
}
#if defined(BACNET_STACK_DEPRECATED_DISABLE)
/**
* @brief Decodes from bytes into a BACnet Date Value
* From clause 20.2.12 Encoding of a Date Value
@@ -5329,7 +5390,9 @@ int decode_date(const uint8_t *apdu, BACNET_DATE *bdate)
return 4;
}
#endif
#if defined(BACNET_STACK_DEPRECATED_DISABLE)
/**
* @brief Decodes from bytes into a BACnet Date Value
* From clause 20.2.12 Encoding of a Date Value
@@ -5355,6 +5418,7 @@ int decode_date_safe(
return decode_date(apdu, bdate);
}
}
#endif
/**
* @brief Decodes from bytes into a BACnet Date Value
@@ -5504,6 +5568,7 @@ int bacnet_date_application_decode(
return apdu_len;
}
#if defined(BACNET_STACK_DEPRECATED_DISABLE)
/**
* @brief Decodes from bytes into a BACnet Date Value application encoded
* From clause 20.2.12 Encoding of a Date Value
@@ -5528,7 +5593,9 @@ int decode_application_date(const uint8_t *apdu, BACNET_DATE *value)
return len;
}
#endif
#if defined(BACNET_STACK_DEPRECATED_DISABLE)
/**
* @brief Decodes from bytes into a BACnet Date Value context encoded
* From clause 20.2.12 Encoding of a Date Value
@@ -5556,6 +5623,7 @@ int decode_context_date(
return len;
}
#endif
/**
* @brief Encode a context tagged BACnetTimerStateChangeValue
+1 -1
View File
@@ -211,7 +211,7 @@ bool decode_boolean(uint32_t len_value);
BACNET_STACK_EXPORT
int encode_context_boolean(
uint8_t *apdu, uint8_t tag_number, bool boolean_value);
BACNET_STACK_DEPRECATED("Use bacnet_boolean_context_decode() instead")
BACNET_STACK_DEPRECATED("Use bacnet_boolean_context_value_decode() instead")
BACNET_STACK_EXPORT
bool decode_context_boolean(const uint8_t *apdu);
BACNET_STACK_EXPORT
+47
View File
@@ -558,6 +558,53 @@ int bacnet_recipient_encode(uint8_t *apdu, const BACNET_RECIPIENT *recipient)
return apdu_len;
}
/**
* @brief Encode a list of BACnetRecipient complex data types
* @param apdu Pointer to the buffer for encoding.
* @param list_head Pointer to the head of the linked list of BACnetRecipient
* @return bytes encoded or zero if nothing is encoded
*/
int bacnet_recipient_list_encode(
uint8_t *apdu, BACNET_RECIPIENT_LIST *list_head)
{
int apdu_len = 0, len = 0;
BACNET_RECIPIENT_LIST *list_entry;
if (!list_head) {
/* encoded nothing */
return 0;
}
/* how big? */
list_entry = list_head;
while (list_entry != NULL) {
len = bacnet_recipient_encode(apdu, &list_entry->recipient);
apdu_len += len;
if (apdu) {
apdu += len;
}
list_entry = list_entry->next;
}
return apdu_len;
}
/**
* @brief Convert an array of BACnetRecipient to linked list
* @param array pointer to element zero of the array
* @param size number of elements in the array
*/
void bacnet_recipient_list_link_array(BACNET_RECIPIENT_LIST *array, size_t size)
{
size_t i = 0;
for (i = 0; i < size; i++) {
if (i > 0) {
array[i - 1].next = &array[i];
}
array[i].next = NULL;
}
}
/**
* @brief Encode a BACnetRecipient complex data type
* @param apdu - the APDU buffer
+13
View File
@@ -36,6 +36,13 @@ typedef struct BACnet_Recipient {
} type;
} BACNET_RECIPIENT;
struct BACnet_Recipient_List;
typedef struct BACnet_Recipient_List {
BACNET_RECIPIENT recipient;
/* simple linked list */
struct BACnet_Recipient_List *next;
} BACNET_RECIPIENT_LIST;
typedef struct BACnet_Destination {
/**
* BACnetDestination ::= SEQUENCE {
@@ -111,6 +118,12 @@ bool bacnet_recipient_device_valid(const BACNET_RECIPIENT *recipient);
BACNET_STACK_EXPORT
int bacnet_recipient_encode(uint8_t *apdu, const BACNET_RECIPIENT *recipient);
BACNET_STACK_EXPORT
int bacnet_recipient_list_encode(
uint8_t *apdu, BACNET_RECIPIENT_LIST *list_head);
BACNET_STACK_EXPORT
void bacnet_recipient_list_link_array(
BACNET_RECIPIENT_LIST *array, size_t size);
BACNET_STACK_EXPORT
int bacnet_recipient_context_encode(
uint8_t *apdu, uint8_t tag_number, const BACNET_RECIPIENT *recipient);
BACNET_STACK_EXPORT
+8
View File
@@ -311,6 +311,7 @@ bool bacnet_device_object_property_reference_copy(
return status;
}
#if defined(BACNET_STACK_DEPRECATED_DISABLE)
/**
* Decode a property reference of a device object.
*
@@ -337,7 +338,9 @@ int bacapp_decode_device_obj_property_ref(
return bacnet_device_object_property_reference_decode(
apdu, MAX_APDU, value);
}
#endif
#if defined(BACNET_STACK_DEPRECATED_DISABLE)
/**
* Decode the opening tag and the property reference of
* an device object and check for the closing tag as well.
@@ -359,6 +362,7 @@ int bacapp_decode_context_device_obj_property_ref(
return bacnet_device_object_property_reference_context_decode(
apdu, MAX_APDU, tag_number, value);
}
#endif
/**
* Encode the opening tag and the device object reference
@@ -599,6 +603,7 @@ bool bacnet_device_object_reference_copy(
return status;
}
#if defined(BACNET_STACK_DEPRECATED_DISABLE)
/**
* Decode the device object reference.
*
@@ -619,7 +624,9 @@ int bacapp_decode_device_obj_ref(
{
return bacnet_device_object_reference_decode(apdu, MAX_APDU, value);
}
#endif
#if defined(BACNET_STACK_DEPRECATED_DISABLE)
/**
* Decode the context device object reference. Check for
* an opening tag and a closing tag as well.
@@ -640,6 +647,7 @@ int bacapp_decode_context_device_obj_ref(
return bacnet_device_object_reference_context_decode(
apdu, MAX_APDU, tag_number, value);
}
#endif
/**
* @brief Encode a BACnetObjectPropertyReference
+92 -20
View File
@@ -49,6 +49,7 @@ int bacapp_property_state_decode(
BACNET_TAG tag = { 0 };
uint32_t enum_value = 0;
int32_t integer_value = 0;
bool boolean_value = false;
int apdu_len = 0;
int len = 0;
@@ -68,8 +69,13 @@ int bacapp_property_state_decode(
return BACNET_STATUS_ERROR;
}
if (value) {
value->state.booleanValue = decode_context_boolean(&apdu[apdu_len]);
apdu_len++;
len = bacnet_boolean_context_value_decode(
&apdu[apdu_len], apdu_size - apdu_len, &boolean_value);
if (len <= 0) {
return BACNET_STATUS_ERROR;
}
value->state.booleanValue = boolean_value;
apdu_len += len;
}
} else if (tag.number == PROP_STATE_INTEGER_VALUE) {
len = bacnet_signed_decode(
@@ -300,37 +306,103 @@ int bacapp_property_state_decode(
return apdu_len;
}
/**
* @brief Decodes BACnetPropertyState from bytes into a data structure, with
* opening and closing tags
* @param apdu - buffer of data to be decoded
* @param apdu_size - number of bytes in the buffer
* @param tag_number - expected tag number for the opening and closing tags
* @param value - decoded value, if decoded
* @return number of bytes decoded, or #BACNET_STATUS_ERROR (-1) if malformed
*/
int bacapp_property_state_context_decode(
const uint8_t *apdu,
uint32_t apdu_size,
uint8_t tag_number,
BACNET_PROPERTY_STATE *value)
{
int len = 0, apdu_len = 0;
if (bacnet_is_opening_tag_number(
&apdu[apdu_len], apdu_size - apdu_len, tag_number, &len)) {
apdu_len += len;
} else {
return BACNET_STATUS_ERROR;
}
len = bacapp_property_state_decode(
&apdu[apdu_len], apdu_size - apdu_len, value);
if (len > 0) {
apdu_len += len;
} else {
return BACNET_STATUS_ERROR;
}
if (bacnet_is_closing_tag_number(
&apdu[apdu_len], apdu_size - apdu_len, tag_number, &len)) {
apdu_len += len;
} else {
return BACNET_STATUS_ERROR;
}
return apdu_len;
}
#if defined(BACNET_STACK_DEPRECATED_DISABLE)
/**
* @brief Decodes BACnetPropertyState from bytes into a data structure, with
* opening and closing tags
* @param apdu - buffer of data to be decoded
* @param value - decoded value, if decoded
* @return number of bytes decoded, or #BACNET_STATUS_ERROR (-1) if malformed
* @deprecated This function is deprecated.
* Use bacapp_property_state_decode() instead.
*/
int bacapp_decode_property_state(
const uint8_t *apdu, BACNET_PROPERTY_STATE *value)
{
return bacapp_property_state_decode(apdu, MAX_APDU, value);
}
#endif
#if defined(BACNET_STACK_DEPRECATED_DISABLE)
/**
* @brief Decodes BACnetPropertyState from bytes into a data structure, with
* opening and closing tags
* @param apdu - buffer of data to be decoded
* @param tag_number - expected tag number for the opening and closing tags
* @param value - decoded value, if decoded
* @return number of bytes decoded, or #BACNET_STATUS_ERROR (-1) if malformed
* @deprecated This function is deprecated.
* Use bacapp_property_state_context_decode() instead.
*/
int bacapp_decode_context_property_state(
const uint8_t *apdu, uint8_t tag_number, BACNET_PROPERTY_STATE *value)
{
int len = 0;
int section_length;
int len = 0, apdu_len = 0;
int apdu_size = MAX_APDU;
if (decode_is_opening_tag_number(&apdu[len], tag_number)) {
len++;
section_length = bacapp_decode_property_state(&apdu[len], value);
if (section_length == -1) {
len = -1;
} else {
len += section_length;
if (decode_is_closing_tag_number(&apdu[len], tag_number)) {
len++;
} else {
len = -1;
}
}
if (bacnet_is_opening_tag_number(
&apdu[apdu_len], apdu_size - apdu_len, tag_number, &len)) {
apdu_len += len;
} else {
len = -1;
return BACNET_STATUS_ERROR;
}
return len;
len = bacapp_property_state_decode(
&apdu[apdu_len], apdu_size - apdu_len, value);
if (len > 0) {
apdu_len += len;
} else {
return BACNET_STATUS_ERROR;
}
if (bacnet_is_closing_tag_number(
&apdu[apdu_len], apdu_size - apdu_len, tag_number, &len)) {
apdu_len += len;
} else {
return BACNET_STATUS_ERROR;
}
return apdu_len;
}
#endif
/**
* @brief Encode the BACnetPropertyState
+9
View File
@@ -91,10 +91,19 @@ BACNET_STACK_EXPORT
int bacapp_property_state_decode(
const uint8_t *apdu, uint32_t apdu_size, BACNET_PROPERTY_STATE *value);
BACNET_STACK_EXPORT
int bacapp_property_state_context_decode(
const uint8_t *apdu,
uint32_t apdu_size,
uint8_t tag_number,
BACNET_PROPERTY_STATE *value);
BACNET_STACK_DEPRECATED("Use bacapp_property_state_decode() instead")
BACNET_STACK_EXPORT
int bacapp_decode_property_state(
const uint8_t *apdu, BACNET_PROPERTY_STATE *value);
BACNET_STACK_DEPRECATED("Use bacapp_property_state_context_decode() instead")
BACNET_STACK_EXPORT
int bacapp_decode_context_property_state(
const uint8_t *apdu, uint8_t tag_number, BACNET_PROPERTY_STATE *value);
+61 -16
View File
@@ -88,6 +88,9 @@ void Credential_Data_Input_Writable_Property_List(
}
}
/**
* @brief Initialize the Credential Data Input object data structures.
*/
void Credential_Data_Input_Init(void)
{
unsigned i;
@@ -112,9 +115,11 @@ void Credential_Data_Input_Init(void)
return;
}
/* we simply have 0-n object instances. Yours might be */
/* more complex, and then you need validate that the */
/* given instance exists */
/**
* @brief Check if the given object instance is valid.
* @param object_instance - object-instance number of the object
* @return true if the instance is valid, false otherwise
*/
bool Credential_Data_Input_Valid_Instance(uint32_t object_instance)
{
if (object_instance < MAX_CREDENTIAL_DATA_INPUTS) {
@@ -124,24 +129,32 @@ bool Credential_Data_Input_Valid_Instance(uint32_t object_instance)
return false;
}
/* we simply have 0-n object instances. Yours might be */
/* more complex, and then count how many you have */
/**
* @brief Get the total count of Credential Data Input objects.
* @return The count of Credential Data Input objects.
*/
unsigned Credential_Data_Input_Count(void)
{
return MAX_CREDENTIAL_DATA_INPUTS;
}
/* we simply have 0-n object instances. Yours might be */
/* more complex, and then you need to return the instance */
/* that correlates to the correct index */
/**
* @brief Convert an object instance number to an index in the object array.
* @param object_instance - object-instance number of the object
* @return The index corresponding to the given object instance, or
* MAX_CREDENTIAL_DATA_INPUTS if the instance is invalid.
*/
uint32_t Credential_Data_Input_Index_To_Instance(unsigned index)
{
return index;
}
/* we simply have 0-n object instances. Yours might be */
/* more complex, and then you need to return the index */
/* that correlates to the correct instance number */
/**
* @brief Convert an object instance number to an index in the object array.
* @param object_instance - object-instance number of the object
* @return The index corresponding to the given object instance, or
* MAX_CREDENTIAL_DATA_INPUTS if the instance is invalid.
*/
unsigned Credential_Data_Input_Instance_To_Index(uint32_t object_instance)
{
unsigned index = MAX_CREDENTIAL_DATA_INPUTS;
@@ -153,7 +166,13 @@ unsigned Credential_Data_Input_Instance_To_Index(uint32_t object_instance)
return index;
}
/* note: the object name must be unique within this device */
/**
* @brief Get the object name for a given Credential Data Input object instance.
* @param object_instance - object-instance number of the object
* @param object_name - pointer to a BACNET_CHARACTER_STRING to receive the
* object name
* @return true if the object name was successfully retrieved, false otherwise
*/
bool Credential_Data_Input_Object_Name(
uint32_t object_instance, BACNET_CHARACTER_STRING *object_name)
{
@@ -170,6 +189,11 @@ bool Credential_Data_Input_Object_Name(
return status;
}
/**
* @brief Check if the Credential Data Input object instance is out of service.
* @param object_instance - object-instance number of the object
* @return true if the object instance is out of service, false otherwise
*/
bool Credential_Data_Input_Out_Of_Service(uint32_t instance)
{
unsigned index = 0;
@@ -183,6 +207,13 @@ bool Credential_Data_Input_Out_Of_Service(uint32_t instance)
return oos_flag;
}
/**
* @brief Set the out of service flag for a given Credential Data Input object
* instance.
* @param instance - object-instance number of the object
* @param oos_flag - true to set the object instance as out of service, false to
* set it as in service
*/
void Credential_Data_Input_Out_Of_Service_Set(uint32_t instance, bool oos_flag)
{
unsigned index = 0;
@@ -193,7 +224,14 @@ void Credential_Data_Input_Out_Of_Service_Set(uint32_t instance, bool oos_flag)
}
}
/* return apdu len, or BACNET_STATUS_ERROR on error */
/**
* @brief Read a property value for a given Credential Data Input object
* instance.
* @param rpdata - pointer to a BACNET_READ_PROPERTY_DATA structure containing
* the read request data
* @return The number of bytes encoded in the response, or BACNET_STATUS_ERROR
* on error.
*/
int Credential_Data_Input_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata)
{
int len = 0;
@@ -299,7 +337,13 @@ int Credential_Data_Input_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata)
return apdu_len;
}
/* returns true if successful */
/**
* @brief Write a property value for a given Credential Data Input object
* instance.
* @param wp_data - pointer to a BACNET_WRITE_PROPERTY_DATA structure containing
* the write request data
* @return true if the property was successfully written, false otherwise
*/
bool Credential_Data_Input_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data)
{
bool status = false; /* return value */
@@ -324,8 +368,9 @@ bool Credential_Data_Input_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data)
if (Credential_Data_Input_Out_Of_Service(
wp_data->object_instance)) {
BACNET_AUTHENTICATION_FACTOR tmp;
len = bacapp_decode_authentication_factor(
wp_data->application_data, &tmp);
len = bacnet_authentication_factor_decode(
wp_data->application_data, wp_data->application_data_len,
&tmp);
if (len > 0) {
memcpy(
&cdi_descr[object_index].present_value, &tmp,
+36 -20
View File
@@ -1640,10 +1640,9 @@ static void TL_fetch_property(int iLog)
uint8_t ucCount;
TL_LOG_INFO *CurrentLog;
TL_DATA_REC TempRec;
uint8_t tag_number = 0;
uint32_t len_value_type = 0;
BACNET_BIT_STRING TempBits;
BACNET_UNSIGNED_INTEGER unsigned_value = 0;
BACNET_TAG tag = { 0 };
CurrentLog = &LogInfo[iLog];
@@ -1662,40 +1661,46 @@ static void TL_fetch_property(int iLog)
TempRec.ucRecType = TL_TYPE_ERROR;
} else {
/* Decode data returned and see if we can fit it into the log */
iLen =
decode_tag_number_and_value(ValueBuf, &tag_number, &len_value_type);
switch (tag_number) {
iLen = bacnet_tag_decode(ValueBuf, sizeof(ValueBuf), &tag);
}
if ((iLen > 0) && (tag.application)) {
switch (tag.number) {
case BACNET_APPLICATION_TAG_NULL:
TempRec.ucRecType = TL_TYPE_NULL;
break;
case BACNET_APPLICATION_TAG_BOOLEAN:
TempRec.ucRecType = TL_TYPE_BOOL;
TempRec.Datum.ucBoolean = decode_boolean(len_value_type);
TempRec.Datum.ucBoolean = decode_boolean(tag.len_value_type);
break;
case BACNET_APPLICATION_TAG_UNSIGNED_INT:
TempRec.ucRecType = TL_TYPE_UNSIGN;
decode_unsigned(
&ValueBuf[iLen], len_value_type, &unsigned_value);
bacnet_unsigned_decode(
&ValueBuf[iLen], sizeof(ValueBuf) - iLen,
tag.len_value_type, &unsigned_value);
TempRec.Datum.ulUValue = unsigned_value;
break;
case BACNET_APPLICATION_TAG_SIGNED_INT:
TempRec.ucRecType = TL_TYPE_SIGN;
decode_signed(
&ValueBuf[iLen], len_value_type, &TempRec.Datum.lSValue);
bacnet_signed_decode(
&ValueBuf[iLen], sizeof(ValueBuf) - iLen,
tag.len_value_type, &TempRec.Datum.lSValue);
break;
case BACNET_APPLICATION_TAG_REAL:
TempRec.ucRecType = TL_TYPE_REAL;
decode_real_safe(
&ValueBuf[iLen], len_value_type, &TempRec.Datum.fReal);
bacnet_real_decode(
&ValueBuf[iLen], sizeof(ValueBuf) - iLen,
tag.len_value_type, &TempRec.Datum.fReal);
break;
case BACNET_APPLICATION_TAG_BIT_STRING:
TempRec.ucRecType = TL_TYPE_BITS;
decode_bitstring(&ValueBuf[iLen], len_value_type, &TempBits);
bacnet_bitstring_decode(
&ValueBuf[iLen], sizeof(ValueBuf) - iLen,
tag.len_value_type, &TempBits);
/* We truncate any bitstrings at 32 bits to conserve space */
if (bitstring_bits_used(&TempBits) < 32) {
/* Store the bytes used and the bits free
@@ -1722,8 +1727,9 @@ static void TL_fetch_property(int iLog)
case BACNET_APPLICATION_TAG_ENUMERATED:
TempRec.ucRecType = TL_TYPE_ENUM;
decode_enumerated(
&ValueBuf[iLen], len_value_type, &TempRec.Datum.ulEnum);
bacnet_enumerated_decode(
&ValueBuf[iLen], sizeof(ValueBuf) - iLen,
tag.len_value_type, &TempRec.Datum.ulEnum);
break;
default:
@@ -1734,12 +1740,22 @@ static void TL_fetch_property(int iLog)
break;
}
/* Finally insert the status flags into the record */
iLen = decode_tag_number_and_value(
StatusBuf, &tag_number, &len_value_type);
decode_bitstring(&StatusBuf[iLen], len_value_type, &TempBits);
TempRec.ucStatus = 128 | bitstring_octet(&TempBits, 0);
iLen = bacnet_bitstring_application_decode(
StatusBuf, sizeof(StatusBuf), &TempBits);
if (iLen > 0) {
TempRec.ucStatus = 128 | bitstring_octet(&TempBits, 0);
} else {
/* If we couldn't decode the status flags, just set the bit to
* say they are not present */
TempRec.ucStatus = 0;
}
} else {
/* We couldn't decode the value, so we will just log an error with
* the error code for the value read attempt */
TempRec.Datum.Error.usClass = ERROR_CLASS_SERVICES;
TempRec.Datum.Error.usCode = ERROR_CODE_OTHER;
TempRec.ucRecType = TL_TYPE_ERROR;
}
Logs[iLog][CurrentLog->iIndex++] = TempRec;
if (CurrentLog->iIndex >= TL_MAX_ENTRIES) {
CurrentLog->iIndex = 0;
+4 -5
View File
@@ -153,7 +153,7 @@ int rp_ack_fully_decode_service_request(
BACNET_PROPERTY_REFERENCE *rp1_property; /* single property */
BACNET_APPLICATION_DATA_VALUE *value, *old_value;
uint8_t *vdata;
int vlen, len;
int vlen, len, tag_len;
decoded_len = rp_ack_decode_service_request(apdu, apdu_len, &rp1data);
if (decoded_len > 0) {
@@ -204,10 +204,9 @@ int rp_ack_fully_decode_service_request(
vlen -= len;
vdata += len;
/* If unexpected closing tag here: */
if (vlen && decode_is_closing_tag_number(vdata, 3)) {
decoded_len++;
vlen--;
vdata++;
if (vlen &&
bacnet_is_closing_tag_number(vdata, vlen, 3, &tag_len)) {
decoded_len += tag_len;
break;
} else {
if (len == 0) {
+5 -3
View File
@@ -219,6 +219,7 @@ void handler_read_property_multiple(
BACNET_RPM_DATA rpmdata;
int apdu_len = 0;
int npdu_len = 0;
int tag_len = 0;
int error = 0;
if (service_data) {
@@ -451,11 +452,12 @@ void handler_read_property_multiple(
}
}
if (decode_is_closing_tag_number(
&service_request[decode_len], 1)) {
if (bacnet_is_closing_tag_number(
&service_request[decode_len],
service_len - decode_len, 1, &tag_len)) {
/* Reached end of property list so cap the result list
*/
decode_len++;
decode_len += tag_len;
len = rpm_ack_encode_apdu_object_end(&Temp_Buf[0]);
copy_len = memcopy(
&Handler_Transmit_Buffer[npdu_len], &Temp_Buf[0],
+49 -36
View File
@@ -45,8 +45,8 @@ int rpm_ack_decode_service_request(
uint32_t error_value = 0; /* decoded error value */
int len = 0; /* number of bytes returned from decoding */
uint8_t tag_number = 0; /* decoded tag number */
uint32_t len_value = 0; /* decoded length value */
int data_len = 0; /* data blob length */
int tag_len = 0; /* length of the tag portion of the data */
BACNET_READ_ACCESS_DATA *rpm_object;
BACNET_READ_ACCESS_DATA *old_rpm_object;
BACNET_PROPERTY_REFERENCE *rpm_property;
@@ -95,23 +95,25 @@ int rpm_ack_decode_service_request(
decoded_len += len;
apdu_len -= len;
apdu += len;
if (apdu_len && decode_is_opening_tag_number(apdu, 4)) {
if (apdu_len &&
bacnet_is_opening_tag_number(apdu, apdu_len, 4, &tag_len)) {
data_len = bacnet_enclosed_data_length(apdu, apdu_len);
/* propertyValue */
decoded_len++;
apdu_len--;
apdu++;
decoded_len += tag_len;
apdu_len -= tag_len;
apdu += tag_len;
value = calloc(1, sizeof(BACNET_APPLICATION_DATA_VALUE));
rpm_property->value = value;
if (apdu_len && decode_is_closing_tag_number(apdu, 4)) {
if (apdu_len &&
bacnet_is_closing_tag_number(apdu, apdu_len, 4, &tag_len)) {
/* Special case for an empty array or list */
if (value) {
bacapp_value_list_init(value, 1);
value->tag = BACNET_APPLICATION_TAG_EMPTYLIST;
}
decoded_len++;
apdu_len--;
apdu++;
decoded_len += tag_len;
apdu_len -= tag_len;
apdu += tag_len;
} else {
/* one or more (array or list) elements to decode */
while (value && (apdu_len > 0)) {
@@ -142,10 +144,12 @@ int rpm_ack_decode_service_request(
decoded_len += len;
apdu_len -= len;
apdu += len;
if (apdu_len && decode_is_closing_tag_number(apdu, 4)) {
decoded_len++;
apdu_len--;
apdu++;
if (apdu_len &&
bacnet_is_closing_tag_number(
apdu, apdu_len, 4, &tag_len)) {
decoded_len += tag_len;
apdu_len -= tag_len;
apdu += tag_len;
break;
} else if (len > 0) {
old_value = value;
@@ -164,39 +168,48 @@ int rpm_ack_decode_service_request(
}
}
}
} else if (apdu_len && decode_is_opening_tag_number(apdu, 5)) {
} else if (
apdu_len &&
bacnet_is_opening_tag_number(apdu, apdu_len, 5, &tag_len)) {
/* propertyAccessError */
decoded_len++;
apdu_len--;
apdu++;
decoded_len += tag_len;
apdu_len -= tag_len;
apdu += tag_len;
/* decode the class and code sequence */
len =
decode_tag_number_and_value(apdu, &tag_number, &len_value);
len = bacnet_enumerated_application_decode(
apdu, apdu_len, &error_value);
if (len <= 0) {
PERROR("RPM Ack: unable to decode error class!\n");
return BACNET_STATUS_ERROR;
}
decoded_len += len;
apdu_len -= len;
apdu += len;
/* FIXME: we could validate that the tag is enumerated... */
len = decode_enumerated(apdu, len_value, &error_value);
rpm_property->error.error_class =
(BACNET_ERROR_CLASS)error_value;
len = bacnet_enumerated_application_decode(
apdu, apdu_len, &error_value);
if (len <= 0) {
PERROR("RPM Ack: unable to decode error code!\n");
return BACNET_STATUS_ERROR;
}
decoded_len += len;
apdu_len -= len;
apdu += len;
len =
decode_tag_number_and_value(apdu, &tag_number, &len_value);
decoded_len += len;
apdu_len -= len;
apdu += len;
/* FIXME: we could validate that the tag is enumerated... */
len = decode_enumerated(apdu, len_value, &error_value);
rpm_property->error.error_code = (BACNET_ERROR_CODE)error_value;
decoded_len += len;
apdu_len -= len;
apdu += len;
if (apdu_len && decode_is_closing_tag_number(apdu, 5)) {
decoded_len++;
apdu_len--;
apdu++;
if (apdu_len) {
if (bacnet_is_closing_tag_number(
apdu, apdu_len, 5, &tag_len)) {
decoded_len += tag_len;
apdu_len -= tag_len;
apdu += tag_len;
} else {
PERROR(
"RPM Ack: expected closing tag for error code, got "
"%d\n",
tag_number);
return BACNET_STATUS_ERROR;
}
}
}
old_rpm_property = rpm_property;
@@ -204,7 +217,7 @@ int rpm_ack_decode_service_request(
old_rpm_property->next = rpm_property;
}
len = rpm_decode_object_end(apdu, apdu_len);
if (len) {
if (len > 0) {
decoded_len += len;
apdu_len -= len;
apdu += len;
+11 -9
View File
@@ -13,6 +13,7 @@
/* BACnet Stack API */
#include "bacnet/datetime.h"
#include "bacnet/bacdcode.h"
#include "bacnet/bacdest.h"
#include "bacnet/timesync.h"
#include "bacnet/bacaddr.h"
#include "bacnet/npdu.h"
@@ -146,9 +147,10 @@ static void handler_timesync_send(BACNET_DATE_TIME *current_date_time)
unsigned index = 0;
for (index = 0; index < MAX_TIME_SYNC_RECIPIENTS; index++) {
if (Time_Sync_Recipients[index].tag == 1) {
if (Time_Sync_Recipients[index].recipient.tag ==
BACNET_RECIPIENT_TAG_ADDRESS) {
Send_TimeSync_Remote(
&Time_Sync_Recipients[index].type.address,
&Time_Sync_Recipients[index].recipient.type.address,
&current_date_time->date, &current_date_time->time);
}
}
@@ -221,8 +223,10 @@ bool handler_timesync_recipient_address_set(
bool status = false;
if (address && (index < MAX_TIME_SYNC_RECIPIENTS)) {
Time_Sync_Recipients[index].tag = 1;
bacnet_address_copy(&Time_Sync_Recipients[index].type.address, address);
Time_Sync_Recipients[index].recipient.tag =
BACNET_RECIPIENT_TAG_ADDRESS;
bacnet_address_copy(
&Time_Sync_Recipients[index].recipient.type.address, address);
status = true;
}
@@ -256,12 +260,10 @@ void handler_timesync_init(void)
unsigned i = 0;
/* connect linked list */
for (; i < (MAX_TIME_SYNC_RECIPIENTS - 1); i++) {
Time_Sync_Recipients[i].next = &Time_Sync_Recipients[i + 1];
Time_Sync_Recipients[i + 1].next = NULL;
}
bacnet_recipient_list_link_array(
Time_Sync_Recipients, MAX_TIME_SYNC_RECIPIENTS);
for (i = 0; i < MAX_TIME_SYNC_RECIPIENTS; i++) {
Time_Sync_Recipients[i].tag = 0xFF;
Time_Sync_Recipients[i].recipient.tag = BACNET_RECIPIENT_TAG_MAX;
}
}
#endif
+55 -62
View File
@@ -88,9 +88,8 @@ void handler_write_property(
BACNET_ADDRESS *src,
BACNET_CONFIRMED_SERVICE_DATA *service_data)
{
BACNET_WRITE_PROPERTY_DATA wp_data;
BACNET_WRITE_PROPERTY_DATA wp_data = { 0 };
int len = 0;
bool bcontinue = true;
bool success = false;
int pdu_len = 0;
BACNET_NPDU_DATA npdu_data;
@@ -104,75 +103,69 @@ void handler_write_property(
&Handler_Transmit_Buffer[0], src, &my_address, &npdu_data);
debug_print("WP: Received Request!\n");
if (service_len == 0) {
len = reject_encode_apdu(
&Handler_Transmit_Buffer[pdu_len], service_data->invoke_id,
REJECT_REASON_MISSING_REQUIRED_PARAMETER);
wp_data.error_code = ERROR_CODE_REJECT_MISSING_REQUIRED_PARAMETER;
len = BACNET_STATUS_REJECT;
debug_print("WP: Missing Required Parameter. Sending Reject!\n");
bcontinue = false;
} else if (service_data->segmented_message) {
len = abort_encode_apdu(
&Handler_Transmit_Buffer[pdu_len], service_data->invoke_id,
ABORT_REASON_SEGMENTATION_NOT_SUPPORTED, true);
wp_data.error_code = ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
len = BACNET_STATUS_ABORT;
debug_print("WP: Segmented message. Sending Abort!\n");
bcontinue = false;
}
if (bcontinue) {
} else {
/* decode the service request only */
wp_data.error_class = ERROR_CLASS_PROPERTY;
wp_data.error_code = ERROR_CODE_SUCCESS;
len = wp_decode_service_request(service_request, service_len, &wp_data);
if (len > 0) {
debug_fprintf(
stderr,
"WP: type=%lu instance=%lu property=%lu priority=%lu "
"index=%ld\n",
(unsigned long)wp_data.object_type,
(unsigned long)wp_data.object_instance,
(unsigned long)wp_data.object_property,
(unsigned long)wp_data.priority, (long)wp_data.array_index);
}
if (len > 0) {
debug_fprintf(
stderr,
"WP: type=%lu instance=%lu property=%lu priority=%lu "
"index=%ld\n",
(unsigned long)wp_data.object_type,
(unsigned long)wp_data.object_instance,
(unsigned long)wp_data.object_property,
(unsigned long)wp_data.priority, (long)wp_data.array_index);
} else {
debug_print("WP: Unable to decode Request!\n");
}
if (len > 0) {
success = handler_write_property_relinquish_bypass(&wp_data);
if (success) {
/* this object property is not commandable,
and therefore, not able to be relinquished,
so it "shall not be changed, and
the write shall be considered successful." */
} else {
debug_print("WP: Unable to decode Request!\n");
if (write_property_bacnet_array_valid(&wp_data)) {
success = Device_Write_Property(&wp_data);
}
}
/* bad decoding or something we didn't understand - send an abort */
if (len <= 0) {
if (success) {
len = encode_simple_ack(
&Handler_Transmit_Buffer[pdu_len], service_data->invoke_id,
SERVICE_CONFIRMED_WRITE_PROPERTY);
debug_print("WP: Sending Simple Ack!\n");
} else {
len = BACNET_STATUS_ERROR;
}
}
if (len < 0) {
if (abort_valid_error_code(wp_data.error_code)) {
len = abort_encode_apdu(
&Handler_Transmit_Buffer[pdu_len], service_data->invoke_id,
ABORT_REASON_OTHER, true);
debug_print("WP: Bad Encoding. Sending Abort!\n");
bcontinue = false;
}
if (bcontinue) {
success = handler_write_property_relinquish_bypass(&wp_data);
if (success) {
/* this object property is not commandable,
and therefore, not able to be relinquished,
so it "shall not be changed, and
the write shall be considered successful." */
} else {
if (write_property_bacnet_array_valid(&wp_data)) {
success = Device_Write_Property(&wp_data);
}
}
if (success) {
len = encode_simple_ack(
&Handler_Transmit_Buffer[pdu_len], service_data->invoke_id,
SERVICE_CONFIRMED_WRITE_PROPERTY);
debug_print("WP: Sending Simple Ack!\n");
} else if (abort_valid_error_code(wp_data.error_code)) {
len = abort_encode_apdu(
&Handler_Transmit_Buffer[pdu_len], service_data->invoke_id,
abort_convert_error_code(wp_data.error_code), true);
debug_print("WP: Sending Abort!\n");
} else if (reject_valid_error_code(wp_data.error_code)) {
len = reject_encode_apdu(
&Handler_Transmit_Buffer[pdu_len], service_data->invoke_id,
reject_convert_error_code(wp_data.error_code));
debug_print("WP: Sending Reject!\n");
} else {
len = bacerror_encode_apdu(
&Handler_Transmit_Buffer[pdu_len], service_data->invoke_id,
SERVICE_CONFIRMED_WRITE_PROPERTY, wp_data.error_class,
wp_data.error_code);
debug_print("WP: Sending Error!\n");
}
abort_convert_error_code(wp_data.error_code), true);
debug_print("WP: Sending Abort!\n");
} else if (reject_valid_error_code(wp_data.error_code)) {
len = reject_encode_apdu(
&Handler_Transmit_Buffer[pdu_len], service_data->invoke_id,
reject_convert_error_code(wp_data.error_code));
debug_print("WP: Sending Reject!\n");
} else {
len = bacerror_encode_apdu(
&Handler_Transmit_Buffer[pdu_len], service_data->invoke_id,
SERVICE_CONFIRMED_WRITE_PROPERTY, wp_data.error_class,
wp_data.error_code);
debug_print("WP: Sending Error!\n");
}
}
/* Send PDU */
+15 -11
View File
@@ -45,6 +45,7 @@ static int write_property_multiple_decode(
{
int len = 0;
int offset = 0;
int tag_len = 0;
uint8_t tag_number = 0;
/* decode service request */
@@ -54,7 +55,9 @@ static int write_property_multiple_decode(
if (len > 0) {
offset += len;
/* Opening tag 1 - List of Properties */
if (decode_is_opening_tag_number(&apdu[offset++], 1)) {
if (bacnet_is_opening_tag_number(
&apdu[offset], apdu_len - offset, 1, &tag_len)) {
offset += tag_len;
do {
/* decode a 'Property Identifier':
(3) an optional 'Property Array Index'
@@ -85,9 +88,10 @@ static int write_property_multiple_decode(
return len;
}
/* Closing tag 1 - List of Properties */
if (decode_is_closing_tag_number(&apdu[offset], 1)) {
if (bacnet_is_closing_tag_number(
&apdu[offset], apdu_len - offset, 1, &len)) {
tag_number = 1;
offset++;
offset += len;
} else {
/* it was not tag 1, decode next Property Identifier */
tag_number = 0;
@@ -101,7 +105,7 @@ static int write_property_multiple_decode(
}
} while (offset < apdu_len);
return len;
return offset;
}
/** Handler for a WriteProperty Service request.
@@ -166,21 +170,21 @@ void handler_write_property_multiple(
debug_print("WPM: Sending Ack!\n");
} else {
/* handle any errors */
if (len == BACNET_STATUS_ABORT) {
if (abort_valid_error_code(wp_data.error_code)) {
apdu_len = abort_encode_apdu(
&Handler_Transmit_Buffer[npdu_len], service_data->invoke_id,
abort_convert_error_code(wp_data.error_code), true);
debug_print("WPM: Sending Abort!\n");
} else if (len == BACNET_STATUS_ERROR) {
apdu_len = wpm_error_ack_encode_apdu(
&Handler_Transmit_Buffer[npdu_len], service_data->invoke_id,
&wp_data);
debug_print("WPM: Sending Error!\n");
} else if (len == BACNET_STATUS_REJECT) {
} else if (reject_valid_error_code(wp_data.error_code)) {
apdu_len = reject_encode_apdu(
&Handler_Transmit_Buffer[npdu_len], service_data->invoke_id,
reject_convert_error_code(wp_data.error_code));
debug_print("WPM: Sending Reject!\n");
} else {
apdu_len = wpm_error_ack_encode_apdu(
&Handler_Transmit_Buffer[npdu_len], service_data->invoke_id,
&wp_data);
debug_print("WPM: Sending Error!\n");
}
}
pdu_len = npdu_len + apdu_len;
+88 -42
View File
@@ -10,6 +10,20 @@
#include "bacnet/credential_authentication_factor.h"
#include "bacnet/bacdcode.h"
/**
* @brief Encode a BACnetCredentialAuthenticationFactor structure into an APDU
* buffer.
*
* BACnetCredentialAuthenticationFactor ::= SEQUENCE {
* disable[0] BACnetAccessAuthenticationFactorDisable,
* authentication-factor[1] BACnetAuthenticationFactor
* }
*
* @param apdu [in] The APDU buffer, or NULL for length
* @param factor [in] The BACnetCredentialAuthenticationFactor structure to
* encode
* @return number of bytes encoded, or negative on error
*/
int bacapp_encode_credential_authentication_factor(
uint8_t *apdu, const BACNET_CREDENTIAL_AUTHENTICATION_FACTOR *factor)
{
@@ -34,6 +48,16 @@ int bacapp_encode_credential_authentication_factor(
return apdu_len;
}
/**
* @brief Encode a BACnetCredentialAuthenticationFactor structure into an APDU
* buffer, with context tag.
*
* @param apdu [in] The APDU buffer, or NULL for length
* @param tag [in] The context tag number
* @param factor [in] The BACnetCredentialAuthenticationFactor structure to
* encode
* @return number of bytes encoded, or negative on error
*/
int bacapp_encode_context_credential_authentication_factor(
uint8_t *apdu,
uint8_t tag,
@@ -55,68 +79,90 @@ int bacapp_encode_context_credential_authentication_factor(
return apdu_len;
}
/**
* @brief Decode a BACnetCredentialAuthenticationFactor structure from an APDU
* buffer.
*
* BACnetCredentialAuthenticationFactor ::= SEQUENCE {
* disable[0] BACnetAccessAuthenticationFactorDisable,
* authentication-factor[1] BACnetAuthenticationFactor
* }
*
* @param apdu [in] The APDU buffer
* @param apdu_size [in] The size of the APDU buffer
* @param factor [out] The BACnetCredentialAuthenticationFactor structure to
* decode
* @return number of bytes decoded, or negative on error
*/
int bacapp_decode_credential_authentication_factor(
const uint8_t *apdu, BACNET_CREDENTIAL_AUTHENTICATION_FACTOR *factor)
const uint8_t *apdu,
size_t apdu_size,
BACNET_CREDENTIAL_AUTHENTICATION_FACTOR *factor)
{
int len;
int apdu_len = 0;
uint32_t disable = factor->disable;
if (decode_is_context_tag(&apdu[apdu_len], 0)) {
len = decode_context_enumerated(&apdu[apdu_len], 0, &disable);
if (len < 0) {
return -1;
} else if (disable < UINT16_MAX) {
apdu_len += len;
factor->disable =
(BACNET_ACCESS_AUTHENTICATION_FACTOR_DISABLE)disable;
} else {
return -1;
}
/* disable[0] BACnetAccessAuthenticationFactorDisable */
len = bacnet_enumerated_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 0, &disable);
if (len <= 0) {
return BACNET_STATUS_ERROR;
} else if (disable < UINT16_MAX) {
apdu_len += len;
factor->disable = (BACNET_ACCESS_AUTHENTICATION_FACTOR_DISABLE)disable;
} else {
return -1;
return BACNET_STATUS_ERROR;
}
if (decode_is_context_tag(&apdu[apdu_len], 1)) {
len = bacapp_decode_context_authentication_factor(
&apdu[apdu_len], 1, &factor->authentication_factor);
if (len < 0) {
return -1;
} else {
apdu_len += len;
}
len = bacnet_authentication_factor_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 1,
&factor->authentication_factor);
if (len <= 0) {
return BACNET_STATUS_ERROR;
} else {
return -1;
apdu_len += len;
}
return apdu_len;
}
/**
* @brief Decode a BACnetCredentialAuthenticationFactor structure from an APDU
* buffer, with context tag.
* @param apdu [in] The APDU buffer
* @param apdu_size [in] The size of the APDU buffer
* @param tag [in] The context tag number
* @param factor [out] The BACnetCredentialAuthenticationFactor structure to
* decode
* @return number of bytes decoded, or negative on error
*/
int bacapp_decode_context_credential_authentication_factor(
const uint8_t *apdu,
size_t apdu_size,
uint8_t tag,
BACNET_CREDENTIAL_AUTHENTICATION_FACTOR *factor)
{
int len = 0;
int section_length;
int len = 0, apdu_len = 0;
if (decode_is_opening_tag_number(&apdu[len], tag)) {
len++;
section_length =
bacapp_decode_credential_authentication_factor(&apdu[len], factor);
if (section_length == -1) {
len = -1;
} else {
len += section_length;
if (decode_is_closing_tag_number(&apdu[len], tag)) {
len++;
} else {
len = -1;
}
}
if (bacnet_is_opening_tag_number(
&apdu[apdu_len], apdu_size - apdu_len, tag, &len)) {
apdu_len += len;
} else {
len = -1;
return BACNET_STATUS_ERROR;
}
return len;
len = bacapp_decode_credential_authentication_factor(
&apdu[apdu_len], apdu_size - apdu_len, factor);
if (len > 0) {
apdu_len += len;
} else {
return BACNET_STATUS_ERROR;
}
if (bacnet_is_closing_tag_number(
&apdu[apdu_len], apdu_size - apdu_len, tag, &len)) {
apdu_len += len;
} else {
return BACNET_STATUS_ERROR;
}
return apdu_len;
}
@@ -36,10 +36,13 @@ int bacapp_encode_context_credential_authentication_factor(
const BACNET_CREDENTIAL_AUTHENTICATION_FACTOR *factor);
BACNET_STACK_EXPORT
int bacapp_decode_credential_authentication_factor(
const uint8_t *apdu, BACNET_CREDENTIAL_AUTHENTICATION_FACTOR *factor);
const uint8_t *apdu,
size_t apdu_size,
BACNET_CREDENTIAL_AUTHENTICATION_FACTOR *factor);
BACNET_STACK_EXPORT
int bacapp_decode_context_credential_authentication_factor(
const uint8_t *apdu,
size_t apdu_size,
uint8_t tag,
BACNET_CREDENTIAL_AUTHENTICATION_FACTOR *factor);
+2
View File
@@ -1288,6 +1288,7 @@ int bacnet_datetime_context_decode(
return apdu_len;
}
#if defined(BACNET_STACK_DEPRECATED_DISABLE)
/**
* @brief Decodes a context tagged BACnetDateTime value from APDU buffer
* @param apdu - the APDU buffer
@@ -1301,6 +1302,7 @@ int bacapp_decode_context_datetime(
{
return bacnet_datetime_context_decode(apdu, MAX_APDU, tag_number, value);
}
#endif
/**
* @brief Compare BACnetDateRange complex data types
+3 -2
View File
@@ -1898,8 +1898,9 @@ int event_notify_decode_service_request(
} else {
property_state = NULL;
}
len = bacapp_decode_context_property_state(
&apdu[apdu_len], 0, property_state);
len = bacapp_property_state_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 0,
property_state);
if (len > 0) {
apdu_len += len;
} else {
-1
View File
@@ -69,7 +69,6 @@ size_t getevent_service_request_encode(
* @param lastReceivedObjectIdentifier Object identifier
*
* @return Bytes encoded.
* @deprecated Use getevent_apdu_encode() instead
*/
int getevent_encode_apdu(
uint8_t *apdu, uint8_t invoke_id, const BACNET_OBJECT_ID *data)
-1
View File
@@ -42,7 +42,6 @@ BACNET_STACK_EXPORT
int getevent_apdu_encode(
uint8_t *apdu, const BACNET_OBJECT_ID *lastReceivedObjectIdentifier);
BACNET_STACK_DEPRECATED("Use getevent_apdu_encode() instead")
BACNET_STACK_EXPORT
int getevent_encode_apdu(
uint8_t *apdu,
+75 -53
View File
@@ -25,21 +25,32 @@ int ihave_encode_apdu(uint8_t *apdu, const BACNET_I_HAVE_DATA *data)
int len = 0; /* length of each encoding */
int apdu_len = 0; /* total length of the apdu, return value */
if (apdu && data) {
if (apdu) {
apdu[0] = PDU_TYPE_UNCONFIRMED_SERVICE_REQUEST;
apdu[1] = SERVICE_UNCONFIRMED_I_HAVE;
apdu_len = 2;
}
len = 2;
apdu_len += len;
if (apdu) {
apdu += len;
}
if (data) {
/* deviceIdentifier */
len = encode_application_object_id(
&apdu[apdu_len], data->device_id.type, data->device_id.instance);
apdu, data->device_id.type, data->device_id.instance);
apdu_len += len;
if (apdu) {
apdu += len;
}
/* objectIdentifier */
len = encode_application_object_id(
&apdu[apdu_len], data->object_id.type, data->object_id.instance);
apdu, data->object_id.type, data->object_id.instance);
apdu_len += len;
if (apdu) {
apdu += len;
}
/* objectName */
len = encode_application_character_string(
&apdu[apdu_len], &data->object_name);
len = encode_application_character_string(apdu, &data->object_name);
apdu_len += len;
}
@@ -51,85 +62,96 @@ int ihave_encode_apdu(uint8_t *apdu, const BACNET_I_HAVE_DATA *data)
/**
* Decode the I Have request only
*
* I-Have-Request ::= SEQUENCE {
* device-identifierBACnetObjectIdentifier,
* object-identifierBACnetObjectIdentifier,
* object-nameCharacterString
* }
*
* @param apdu Pointer to the APDU buffer
* @param apdu_len Valid bytes in the buffer
* @param apdu_size Number of valid bytes in the buffer
* @param data Pointer to the I Have data structure.
*
* @return Bytes decoded.
*/
int ihave_decode_service_request(
const uint8_t *apdu, unsigned apdu_len, BACNET_I_HAVE_DATA *data)
const uint8_t *apdu, unsigned apdu_size, BACNET_I_HAVE_DATA *data)
{
int len = 0;
uint8_t tag_number = 0;
uint32_t len_value = 0;
int len = 0, apdu_len = 0;
BACNET_OBJECT_TYPE decoded_type = OBJECT_NONE; /* for decoding */
uint32_t decoded_instance = 0; /* for decoding */
BACNET_CHARACTER_STRING *decoded_string = NULL; /* for decoding */
if ((apdu_len >= 2) && data) {
/* deviceIdentifier */
len += decode_tag_number_and_value(&apdu[len], &tag_number, &len_value);
if (tag_number == BACNET_APPLICATION_TAG_OBJECT_ID) {
len += decode_object_id(
&apdu[len], &decoded_type, &data->device_id.instance);
data->device_id.type = decoded_type;
} else {
return -1;
}
/* objectIdentifier */
if ((unsigned)len >= apdu_len) {
return -1;
}
len += decode_tag_number_and_value(&apdu[len], &tag_number, &len_value);
if (tag_number == BACNET_APPLICATION_TAG_OBJECT_ID) {
len += decode_object_id(
&apdu[len], &decoded_type, &data->object_id.instance);
data->object_id.type = decoded_type;
} else {
return -1;
}
/* objectName */
if ((unsigned)len >= apdu_len) {
return -1;
}
len += decode_tag_number_and_value(&apdu[len], &tag_number, &len_value);
if (tag_number == BACNET_APPLICATION_TAG_CHARACTER_STRING) {
len += decode_character_string(
&apdu[len], len_value, &data->object_name);
} else {
return -1;
}
} else {
if (!apdu || (apdu_size < 2)) {
return -1;
}
/* deviceIdentifier */
len = bacnet_object_id_application_decode(
&apdu[apdu_len], apdu_size - apdu_len, &decoded_type,
&decoded_instance);
if (len <= 0) {
return BACNET_STATUS_ERROR;
} else {
if (data) {
data->device_id.type = decoded_type;
data->device_id.instance = decoded_instance;
}
}
apdu_len += len;
/* objectIdentifier */
len = bacnet_object_id_application_decode(
&apdu[apdu_len], apdu_size - apdu_len, &decoded_type,
&decoded_instance);
if (len <= 0) {
return BACNET_STATUS_ERROR;
} else {
if (data) {
data->object_id.type = decoded_type;
data->object_id.instance = decoded_instance;
}
}
apdu_len += len;
/* objectName */
if (data) {
decoded_string = &data->object_name;
}
len = bacnet_character_string_application_decode(
&apdu[apdu_len], apdu_size - apdu_len, decoded_string);
if (len <= 0) {
return BACNET_STATUS_ERROR;
} else {
/* nothing else to do, the string is already decoded in place */
}
apdu_len += len;
return len;
return apdu_len;
}
/**
* Decode the I Have
*
* @param apdu Pointer to the APDU buffer
* @param apdu_len Valid bytes in the buffer
* @param apdu_size Number of valid bytes in the buffer
* @param data Pointer to the I Have data structure.
*
* @return Bytes decoded.
*/
int ihave_decode_apdu(
const uint8_t *apdu, unsigned apdu_len, BACNET_I_HAVE_DATA *data)
const uint8_t *apdu, unsigned apdu_size, BACNET_I_HAVE_DATA *data)
{
int len = 0;
if ((!apdu) || (apdu_len < 2)) {
return -1;
if ((!apdu) || (apdu_size < 2)) {
return BACNET_STATUS_ERROR;
}
/* optional checking - most likely was already done prior to this call */
if (apdu[0] != PDU_TYPE_UNCONFIRMED_SERVICE_REQUEST) {
return -1;
return BACNET_STATUS_ERROR;
}
if (apdu[1] != SERVICE_UNCONFIRMED_I_HAVE) {
return -1;
return BACNET_STATUS_ERROR;
}
len = ihave_decode_service_request(&apdu[2], apdu_len - 2, data);
len = ihave_decode_service_request(&apdu[2], apdu_size - 2, data);
return len;
}
+46 -72
View File
@@ -107,17 +107,15 @@ size_t list_element_service_request_encode(
/**
* @brief Decode the Add/Remove ListElement service request only
* @param apdu Pointer to the buffer for decoding.
* @param apdu_len Count of valid bytes in the buffer.
* @param apdu_size Count of valid bytes in the buffer.
* @param list_element Pointer to the property decoded data to be stored
*
* @return Bytes decoded or BACNET_STATUS_REJECT on error.
*/
int list_element_decode_service_request(
uint8_t *apdu, unsigned apdu_len, BACNET_LIST_ELEMENT_DATA *list_element)
uint8_t *apdu, unsigned apdu_size, BACNET_LIST_ELEMENT_DATA *list_element)
{
unsigned len = 0, application_data_len = 0;
uint8_t tag_number = 0;
uint32_t len_value_type = 0;
int len = 0, application_data_len = 0, apdu_len = 0;
BACNET_OBJECT_TYPE object_type = OBJECT_NONE;
uint32_t object_instance = 0;
uint32_t property = 0;
@@ -125,7 +123,7 @@ int list_element_decode_service_request(
/* Must have at least 2 tags, an object id and a property identifier
* of at least 1 byte in length to have any chance of parsing */
if (apdu_len < 7) {
if (apdu_size < 7) {
if (list_element) {
list_element->error_code =
ERROR_CODE_REJECT_MISSING_REQUIRED_PARAMETER;
@@ -134,107 +132,87 @@ int list_element_decode_service_request(
}
/* Tag 0: Object ID */
if (!decode_is_context_tag(&apdu[len++], 0)) {
len = bacnet_object_id_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 0, &object_type,
&object_instance);
if (len <= 0) {
if (list_element) {
list_element->error_code = ERROR_CODE_REJECT_INVALID_TAG;
}
return BACNET_STATUS_REJECT;
}
len += decode_object_id(&apdu[len], &object_type, &object_instance);
apdu_len += len;
if (list_element) {
list_element->object_type = object_type;
list_element->object_instance = object_instance;
}
/* Tag 1: Property ID */
len +=
decode_tag_number_and_value(&apdu[len], &tag_number, &len_value_type);
if (tag_number != 1) {
len = bacnet_enumerated_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 1, &property);
if (len <= 0) {
if (list_element) {
list_element->error_code = ERROR_CODE_REJECT_INVALID_TAG;
}
return BACNET_STATUS_REJECT;
}
if (len >= apdu_len) {
if (list_element) {
list_element->error_code =
ERROR_CODE_REJECT_MISSING_REQUIRED_PARAMETER;
}
return BACNET_STATUS_REJECT;
}
len += decode_enumerated(&apdu[len], len_value_type, &property);
if (list_element) {
list_element->object_property = (BACNET_PROPERTY_ID)property;
}
if (len >= apdu_len) {
if (list_element) {
list_element->error_code =
ERROR_CODE_REJECT_MISSING_REQUIRED_PARAMETER;
}
return BACNET_STATUS_REJECT;
}
apdu_len += len;
/* Tag 2: Optional Array Index */
if (decode_is_opening_tag_number(&apdu[len], 3)) {
/* this is tag 3, therefore, optional tag 2 is not present */
len = bacnet_unsigned_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 2, &unsigned_value);
if (len > 0) {
if (list_element) {
list_element->array_index = (BACNET_ARRAY_INDEX)unsigned_value;
}
apdu_len += len;
} else if (len == 0) {
/* optional, so not an error if not present */
if (list_element) {
list_element->array_index = BACNET_ARRAY_ALL;
}
} else {
len += decode_tag_number_and_value(
&apdu[len], &tag_number, &len_value_type);
if ((tag_number == 2) && (len < apdu_len)) {
len += decode_unsigned(&apdu[len], len_value_type, &unsigned_value);
if (list_element) {
list_element->array_index = (BACNET_ARRAY_INDEX)unsigned_value;
}
}
}
if (len >= apdu_len) {
if (list_element) {
list_element->error_code =
ERROR_CODE_REJECT_MISSING_REQUIRED_PARAMETER;
list_element->error_code = ERROR_CODE_REJECT_INVALID_TAG;
}
return BACNET_STATUS_REJECT;
}
/* Tag 3: opening context tag */
if (decode_is_opening_tag_number(&apdu[len], 3)) {
/* an opening tag number of 3 is not extended so only one octet */
len++;
/* don't decode the application tag number or its data here */
if (list_element) {
list_element->application_data = &apdu[len];
}
application_data_len = apdu_len - len - 1 /*closing tag */;
if (list_element) {
/* Just to ensure we do not create a wrapped over value here. */
if (len < apdu_len) {
list_element->application_data_len = application_data_len;
} else {
list_element->application_data_len = 0;
if (bacnet_is_opening_tag_number(
&apdu[apdu_len], apdu_size - apdu_len, 3, &len)) {
application_data_len =
bacnet_enclosed_data_length(&apdu[apdu_len], apdu_size - apdu_len);
if (application_data_len < 0) {
if (list_element) {
list_element->error_code = ERROR_CODE_REJECT_INVALID_TAG;
}
return BACNET_STATUS_REJECT;
}
len += application_data_len;
/* add the tag length */
apdu_len += len;
/* postpone the application data */
if (list_element) {
list_element->application_data = &apdu[apdu_len];
list_element->application_data_len = application_data_len;
}
apdu_len += application_data_len;
} else {
if (list_element) {
list_element->error_code = ERROR_CODE_REJECT_INVALID_TAG;
}
return BACNET_STATUS_REJECT;
}
if (len >= apdu_len) {
if (list_element) {
list_element->error_code = ERROR_CODE_REJECT_INVALID_TAG;
}
return BACNET_STATUS_REJECT;
}
if (decode_is_closing_tag_number(&apdu[len], 3)) {
/* a closing tag number of 3 is not extended so only one octet */
len++;
if (bacnet_is_closing_tag_number(
&apdu[apdu_len], apdu_size - apdu_len, 3, &len)) {
apdu_len += len;
} else {
if (list_element) {
list_element->error_code = ERROR_CODE_REJECT_INVALID_TAG;
}
return BACNET_STATUS_REJECT;
}
if (len < apdu_len) {
if (apdu_len < apdu_size) {
/* If something left over now, we have an invalid request */
if (list_element) {
list_element->error_code = ERROR_CODE_REJECT_TOO_MANY_ARGUMENTS;
@@ -242,7 +220,7 @@ int list_element_decode_service_request(
return BACNET_STATUS_REJECT;
}
return (int)len;
return (int)apdu_len;
}
/**
@@ -330,9 +308,7 @@ int list_element_error_ack_decode(
return 0;
}
/* Opening Context tag 0 - Error */
if (decode_is_opening_tag_number(apdu, 0)) {
/* opening tag 0 is 1 byte */
len = 1;
if (bacnet_is_opening_tag_number(apdu, apdu_size, 0, &len)) {
apdu_len += len;
apdu += len;
} else {
@@ -357,9 +333,7 @@ int list_element_error_ack_decode(
return 0;
}
/* Closing Context tag 0 - Error */
if (decode_is_closing_tag_number(apdu, 0)) {
/* closing tag 0 is 1 byte */
len = 1;
if (bacnet_is_closing_tag_number(apdu, apdu_size - apdu_len, 0, &len)) {
apdu_len += len;
apdu += len;
} else {
+76 -37
View File
@@ -13,6 +13,14 @@
/**
* @brief Encode APDU for LifeSafetyOperation-Request
*
* LifeSafetyOperation-Request ::= SEQUENCE {
* requesting-process-identifier[0] Unsigned32,
* requesting-source[1] CharacterString,
* request[2] BACnetLifeSafetyOperation,
* object-identifier[3] BACnetObjectIdentifier OPTIONAL
* }
*
* @param apdu Pointer to the buffer, or NULL for length
* @param data Pointer to the data to encode.
* @return number of bytes encoded, or zero on error.
@@ -108,55 +116,86 @@ size_t life_safety_operation_request_encode(
return apdu_len;
}
/**
* @brief Decode the LifeSafetyOperation-Request
*
* * LifeSafetyOperation-Request ::= SEQUENCE {
* requesting-process-identifier[0] Unsigned32,
* requesting-source[1] CharacterString,
* request[2] BACnetLifeSafetyOperation,
* object-identifier[3] BACnetObjectIdentifier OPTIONAL
* }
* @param apdu Pointer to the buffer to decode from
* @param apdu_size number of bytes available in the buffer
* @param data Pointer to the data to decode into.
* @return number of bytes decoded, or BACNET_STATUS_ERROR on error.
*/
int lso_decode_service_request(
const uint8_t *apdu, unsigned apdu_len, BACNET_LSO_DATA *data)
const uint8_t *apdu, unsigned apdu_size, BACNET_LSO_DATA *data)
{
int len = 0; /* return value */
int section_length = 0; /* length returned from decoding */
int len = 0; /* length returned from decoding */
int apdu_len = 0; /* return value */
uint32_t operation = 0; /* handles decoded value */
BACNET_UNSIGNED_INTEGER unsigned_value = 0;
BACNET_UNSIGNED_INTEGER unsigned_value = 0; /* for decoding*/
BACNET_CHARACTER_STRING *decoded_string = NULL; /* for decoding */
BACNET_OBJECT_TYPE object_type = 0;
uint32_t instance = 0;
/* check for value pointers */
if (apdu_len && data) {
/* Tag 0: Object ID */
section_length =
decode_context_unsigned(&apdu[len], 0, &unsigned_value);
if (section_length == BACNET_STATUS_ERROR) {
return BACNET_STATUS_ERROR;
}
if (!apdu && !apdu_size) {
return 0;
}
/* requesting-process-identifier[0] Unsigned32 */
len = bacnet_unsigned_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 0, &unsigned_value);
if (len <= 0) {
return BACNET_STATUS_ERROR;
}
if (data) {
data->processId = (uint32_t)unsigned_value;
len += section_length;
section_length = decode_context_character_string(
&apdu[len], 1, &data->requestingSrc);
if (section_length == BACNET_STATUS_ERROR) {
return BACNET_STATUS_ERROR;
}
len += section_length;
section_length = decode_context_enumerated(&apdu[len], 2, &operation);
if (section_length == BACNET_STATUS_ERROR) {
return BACNET_STATUS_ERROR;
}
}
apdu_len += len;
if (data) {
decoded_string = &data->requestingSrc;
}
/* requesting-source[1] CharacterString */
len = bacnet_character_string_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 1, decoded_string);
if (len <= 0) {
return BACNET_STATUS_ERROR;
}
apdu_len += len;
/* request[2] BACnetLifeSafetyOperation */
len = bacnet_enumerated_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 2, &operation);
if (len <= 0) {
return BACNET_STATUS_ERROR;
}
if (operation > LIFE_SAFETY_OP_PROPRIETARY_MAX) {
return BACNET_STATUS_ERROR;
}
if (data) {
data->operation = (BACNET_LIFE_SAFETY_OPERATION)operation;
len += section_length;
/*
** This is an optional parameter, so don't fail if it doesn't exist
*/
if (decode_is_context_tag(&apdu[len], 3)) {
section_length = decode_context_object_id(
&apdu[len], 3, &data->targetObject.type,
&data->targetObject.instance);
if (section_length == BACNET_STATUS_ERROR) {
return BACNET_STATUS_ERROR;
}
}
apdu_len += len;
/* object-identifier[3] BACnetObjectIdentifier OPTIONAL */
len = bacnet_object_id_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 3, &object_type, &instance);
if (len > 0) {
if (data) {
data->targetObject.type = object_type;
data->targetObject.instance = instance;
data->use_target = true;
len += section_length;
} else {
}
apdu_len += len;
} else {
if (data) {
data->use_target = false;
data->targetObject.type = OBJECT_NONE;
data->targetObject.instance = 0;
}
return len;
}
return 0;
return apdu_len;
}
+362 -177
View File
@@ -12,47 +12,99 @@
#include "bacnet/bacdcode.h"
#include "bacnet/ptransfer.h"
/* encode service */
static int pt_encode_apdu(
uint8_t *apdu,
uint16_t max_apdu,
const BACNET_PRIVATE_TRANSFER_DATA *private_data)
/**
* @brief Encode the service parameters for both confirmed and
* unconfirmed private transfer
*
* ConfirmedPrivateTransfer-Request ::= SEQUENCE {
* vendorID [0] Unsigned,
* serviceNumber [1] Unsigned,
* serviceParameters [2] ABSTRACT-SYNTAX.&Type OPTIONAL
* }
* UnconfirmedPrivateTransfer-Request ::= SEQUENCE {
* vendorID [0] Unsigned,
* serviceNumber [1] Unsigned,
* serviceParameters [2] ABSTRACT-SYNTAX.&Type OPTIONAL
* }
*
* @param apdu [in] The APDU buffer for encoding, or NULL for length
* @param apdu_size [in] The maximum APDU size for encoding
* @param private_data [in] The BACNET_PRIVATE_TRANSFER_DATA structure to encode
* @return number of bytes encoded, or negative on error
*/
int private_transfer_request_encode(
uint8_t *apdu, const BACNET_PRIVATE_TRANSFER_DATA *data)
{
int len = 0; /* length of each encoding */
int apdu_len = 0; /* total length of the apdu, return value */
/*
Unconfirmed/ConfirmedPrivateTransfer-Request ::= SEQUENCE {
vendorID [0] Unsigned,
serviceNumber [1] Unsigned,
serviceParameters [2] ABSTRACT-SYNTAX.&Type OPTIONAL
}
*/
/* unused parameter */
(void)max_apdu;
len = encode_context_unsigned(apdu, 0, data->vendorID);
apdu_len += len;
if (apdu) {
len =
encode_context_unsigned(&apdu[apdu_len], 0, private_data->vendorID);
apdu_len += len;
len = encode_context_unsigned(
&apdu[apdu_len], 1, private_data->serviceNumber);
apdu_len += len;
len = encode_opening_tag(&apdu[apdu_len], 2);
apdu_len += len;
for (len = 0; len < private_data->serviceParametersLen; len++) {
apdu[apdu_len] = private_data->serviceParameters[len];
apdu_len++;
apdu += len;
}
len = encode_context_unsigned(apdu, 1, data->serviceNumber);
apdu_len += len;
if (apdu) {
apdu += len;
}
len = encode_opening_tag(apdu, 2);
apdu_len += len;
if (apdu) {
apdu += len;
}
for (len = 0; len < data->serviceParametersLen; len++) {
if (apdu) {
*apdu = data->serviceParameters[len];
apdu++;
}
len = encode_closing_tag(&apdu[apdu_len], 2);
apdu_len += len;
apdu_len++;
}
len = encode_closing_tag(apdu, 2);
apdu_len += len;
return apdu_len;
}
/**
* @brief Encode the service parameters for both confirmed and
* unconfirmed private transfer, with APDU length checking
* @param apdu [in] The APDU buffer for encoding, or NULL for length
* @param apdu_size [in] The maximum APDU size for encoding
* @param private_data [in] The BACNET_PRIVATE_TRANSFER_DATA structure to encode
* @return number of bytes encoded, or zero on error
*/
int private_transfer_request_service_encode(
uint8_t *apdu, uint16_t apdu_size, const BACNET_PRIVATE_TRANSFER_DATA *data)
{
size_t apdu_len = 0; /* total length of the apdu, return value */
apdu_len = private_transfer_request_encode(NULL, data);
if (apdu_len > apdu_size) {
apdu_len = 0;
} else {
apdu_len = private_transfer_request_encode(apdu, data);
}
return apdu_len;
}
/**
* @brief Encode a ConfirmedPrivateTransfer-Error APDU
* ConfirmedPrivateTransfer-Error ::= SEQUENCE {
* errorType [0] Error,
* vendorID [1] Unsigned,
* serviceNumber [2] Unsigned,
* errorParameters [3] ABSTRACT-SYNTAX.&Type OPTIONAL
* }
* @param apdu [in] The APDU buffer for encoding, or NULL for length
* @param apdu_size [in] The maximum APDU size for encoding
* @param invoke_id [in] The invoke ID for the error response
* @param data [in] The BACNET_PRIVATE_TRANSFER_DATA structure to encode
* @return number of bytes encoded, or zero on error
*/
int ptransfer_encode_apdu(
uint8_t *apdu,
uint8_t invoke_id,
const BACNET_PRIVATE_TRANSFER_DATA *private_data)
uint8_t *apdu, uint8_t invoke_id, const BACNET_PRIVATE_TRANSFER_DATA *data)
{
int apdu_len = 0; /* total length of the apdu, return value */
int len = 0;
@@ -62,17 +114,20 @@ int ptransfer_encode_apdu(
apdu[1] = encode_max_segs_max_apdu(0, MAX_APDU);
apdu[2] = invoke_id;
apdu[3] = SERVICE_CONFIRMED_PRIVATE_TRANSFER;
apdu_len = 4;
len = pt_encode_apdu(
&apdu[apdu_len], (uint16_t)(MAX_APDU - apdu_len), private_data);
apdu_len += len;
}
len = 4;
apdu_len += len;
if (apdu) {
apdu += len;
}
len = private_transfer_request_encode(apdu, data);
apdu_len += len;
return apdu_len;
}
int uptransfer_encode_apdu(
uint8_t *apdu, const BACNET_PRIVATE_TRANSFER_DATA *private_data)
uint8_t *apdu, const BACNET_PRIVATE_TRANSFER_DATA *data)
{
int apdu_len = 0; /* total length of the apdu, return value */
int len = 0;
@@ -80,65 +135,197 @@ int uptransfer_encode_apdu(
if (apdu) {
apdu[0] = PDU_TYPE_UNCONFIRMED_SERVICE_REQUEST;
apdu[1] = SERVICE_UNCONFIRMED_PRIVATE_TRANSFER;
apdu_len = 2;
len = pt_encode_apdu(
&apdu[apdu_len], (uint16_t)(MAX_APDU - apdu_len), private_data);
}
len = 2;
apdu_len += len;
if (apdu) {
apdu += len;
}
len = private_transfer_request_encode(apdu, data);
apdu_len += len;
return apdu_len;
}
/**
* @brief Decode the service parameters for both confirmed and
* unconfirmed private transfer
* ConfirmedPrivateTransfer-Request ::= SEQUENCE {
* vendorID [0] Unsigned,
* serviceNumber [1] Unsigned,
* serviceParameters [2] ABSTRACT-SYNTAX.&Type OPTIONAL
* }
* UnconfirmedPrivateTransfer-Request ::= SEQUENCE {
* vendorID [0] Unsigned,
* serviceNumber [1] Unsigned,
* serviceParameters [2] ABSTRACT-SYNTAX.&Type OPTIONAL
* }
* @param apdu [in] The APDU buffer for decoding
* @param apdu_size [in] The length of the APDU buffer for decoding
* @param private_data [out] The BACNET_PRIVATE_TRANSFER_DATA structure to
* decode into
* @return number of bytes decoded, or negative on error
*/
int ptransfer_decode_service_request(
uint8_t *apdu, unsigned apdu_size, BACNET_PRIVATE_TRANSFER_DATA *data)
{
int apdu_len = 0, len = 0, application_len = 0;
BACNET_UNSIGNED_INTEGER unsigned_value = 0;
/* check for value pointers */
if (!(apdu && apdu_size)) {
return BACNET_STATUS_ERROR;
}
/* Tag 0: vendorID */
len = bacnet_unsigned_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 0, &unsigned_value);
if (len <= 0) {
return BACNET_STATUS_ERROR;
}
apdu_len += len;
if (data) {
if (unsigned_value > UINT16_MAX) {
data->vendorID = UINT16_MAX;
} else {
data->vendorID = (uint16_t)unsigned_value;
}
}
/* Tag 1: serviceNumber */
len = bacnet_unsigned_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 1, &unsigned_value);
if (len <= 0) {
return BACNET_STATUS_ERROR;
}
apdu_len += len;
if (data) {
if (unsigned_value > UINT32_MAX) {
data->serviceNumber = UINT32_MAX;
} else {
data->serviceNumber = (uint32_t)unsigned_value;
}
}
/* Tag 2: serviceParameters */
if (bacnet_is_opening_tag_number(
&apdu[apdu_len], apdu_size - apdu_len, 2, &len)) {
application_len =
bacnet_enclosed_data_length(&apdu[apdu_len], apdu_size - apdu_len);
if (application_len < 0) {
return BACNET_STATUS_ERROR;
}
/* add the tag length */
apdu_len += len;
/* postpone decoding the serviceParameters */
if (data) {
data->serviceParameters = &apdu[apdu_len];
data->serviceParametersLen = application_len;
}
apdu_len += application_len;
if (bacnet_is_closing_tag_number(
&apdu[apdu_len], apdu_size - apdu_len, 2, &len)) {
apdu_len += len;
} else {
return BACNET_STATUS_ERROR;
}
} else {
return BACNET_STATUS_ERROR;
}
return apdu_len;
}
/* decode the service request only */
int ptransfer_decode_service_request(
/**
* @brief Encode an Error acknowledge for a Private Transfer service.
* ConfirmedPrivateTransfer-Error ::= SEQUENCE {
* errorType [0] Error,
* vendorID [1] Unsigned,
* serviceNumber [2] Unsigned,
* errorParameters [3] ABSTRACT-SYNTAX.&Type OPTIONAL
* }
* @param apdu [in] The APDU buffer for encoding, or NULL for length
* @param error_class [in] The BACNET_ERROR_CLASS to encode
* @param error_code [in] The BACNET_ERROR_CODE to encode
* @param private_data [in] The BACNET_PRIVATE_TRANSFER_DATA structure to encode
* @return number of bytes encoded, or zero on error
*/
int ptransfer_error_encode_service(
uint8_t *apdu,
unsigned apdu_len,
BACNET_PRIVATE_TRANSFER_DATA *private_data)
BACNET_ERROR_CLASS error_class,
BACNET_ERROR_CODE error_code,
const BACNET_PRIVATE_TRANSFER_DATA *private_data)
{
int len = 0; /* return value */
int decode_len = 0; /* return value */
BACNET_UNSIGNED_INTEGER unsigned_value = 0;
int apdu_len = 0; /* total length of the apdu, return value */
int len = 0; /* length of the part of the encoding */
/* check for value pointers */
if (apdu_len && private_data) {
/* Tag 0: vendorID */
decode_len = decode_context_unsigned(&apdu[len], 0, &unsigned_value);
if (decode_len < 0) {
return -1;
}
len = decode_len;
private_data->vendorID = (uint16_t)unsigned_value;
/* Tag 1: serviceNumber */
decode_len = decode_context_unsigned(&apdu[len], 1, &unsigned_value);
if (decode_len < 0) {
return -1;
}
len += decode_len;
private_data->serviceNumber = unsigned_value;
/* Tag 2: serviceParameters */
if (decode_is_opening_tag_number(&apdu[len], 2)) {
/* a tag number of 2 is not extended so only one octet */
len++;
/* don't decode the serviceParameters here */
private_data->serviceParameters = &apdu[len];
private_data->serviceParametersLen =
(int)apdu_len - len - 1 /*closing tag */;
/* len includes the data and the closing tag */
len = (int)apdu_len;
} else {
return -1;
}
len = encode_opening_tag(apdu, 0);
apdu_len += len;
if (apdu) {
apdu += len;
}
len = encode_application_enumerated(apdu, error_class);
apdu_len += len;
if (apdu) {
apdu += len;
}
len = encode_application_enumerated(apdu, error_code);
apdu_len += len;
if (apdu) {
apdu += len;
}
len = encode_closing_tag(apdu, 0);
apdu_len += len;
if (apdu) {
apdu += len;
}
len = encode_context_unsigned(apdu, 1, private_data->vendorID);
apdu_len += len;
if (apdu) {
apdu += len;
}
len = encode_context_unsigned(apdu, 2, private_data->serviceNumber);
apdu_len += len;
if (apdu) {
apdu += len;
}
len = encode_opening_tag(apdu, 3);
apdu_len += len;
if (apdu) {
apdu += len;
}
for (len = 0; len < private_data->serviceParametersLen; len++) {
if (apdu) {
*apdu = private_data->serviceParameters[len];
apdu++;
}
apdu_len++;
}
len = encode_closing_tag(apdu, 3);
apdu_len += len;
return len;
return apdu_len;
}
/**
* @brief Encode an Error acknowledge for a Private Transfer service.
* ConfirmedPrivateTransfer-Error ::= SEQUENCE {
* errorType [0] Error,
* vendorID [1] Unsigned,
* serviceNumber [2] Unsigned,
* errorParameters [3] ABSTRACT-SYNTAX.&Type OPTIONAL
* }
* @param apdu [in] The APDU buffer for encoding, or NULL for length
* @param apdu_size [in] The maximum APDU size for encoding
* @param invoke_id [in] The invoke ID for the error response
* @param error_class [in] The BACNET_ERROR_CLASS to encode
* @param error_code [in] The BACNET_ERROR_CODE to encode
* @param private_data [in] The BACNET_PRIVATE_TRANSFER_DATA structure to encode
* @return number of bytes encoded, or zero on error
*/
int ptransfer_error_encode_apdu(
uint8_t *apdu,
uint8_t invoke_id,
BACNET_ERROR_CLASS error_class,
BACNET_ERROR_CODE error_code,
const BACNET_PRIVATE_TRANSFER_DATA *private_data)
const BACNET_PRIVATE_TRANSFER_DATA *data)
{
int apdu_len = 0; /* total length of the apdu, return value */
int len = 0; /* length of the part of the encoding */
@@ -147,126 +334,124 @@ int ptransfer_error_encode_apdu(
apdu[0] = PDU_TYPE_ERROR;
apdu[1] = invoke_id;
apdu[2] = SERVICE_CONFIRMED_PRIVATE_TRANSFER;
apdu_len = 3;
/* service parameters */
/*
ConfirmedPrivateTransfer-Error ::= SEQUENCE {
errorType [0] Error,
vendorID [1] Unsigned,
serviceNumber [2] Unsigned,
errorParameters [3] ABSTRACT-SYNTAX.&Type OPTIONAL
}
*/
len = encode_opening_tag(&apdu[apdu_len], 0);
apdu_len += len;
len = encode_application_enumerated(&apdu[apdu_len], error_class);
apdu_len += len;
len = encode_application_enumerated(&apdu[apdu_len], error_code);
apdu_len += len;
len = encode_closing_tag(&apdu[apdu_len], 0);
apdu_len += len;
len =
encode_context_unsigned(&apdu[apdu_len], 1, private_data->vendorID);
apdu_len += len;
len = encode_context_unsigned(
&apdu[apdu_len], 2, private_data->serviceNumber);
apdu_len += len;
len = encode_opening_tag(&apdu[apdu_len], 3);
apdu_len += len;
for (len = 0; len < private_data->serviceParametersLen; len++) {
apdu[apdu_len] = private_data->serviceParameters[len];
apdu_len++;
}
len = encode_closing_tag(&apdu[apdu_len], 3);
apdu_len += len;
}
len = 3;
apdu_len += len;
if (apdu) {
apdu += len;
}
/* service parameters */
len = ptransfer_error_encode_service(apdu, error_class, error_code, data);
apdu_len += len;
return apdu_len;
}
/* decode the service request only */
/**
* @brief Decode an Error acknowledge for a Private Transfer service.
* @param apdu [in] The APDU buffer for decoding.
* @param apdu_size [in] The length of the APDU buffer.
* @param error_class [out] The decoded error class.
* @param error_code [out] The decoded error code.
* @param private_data [out] The decoded private transfer data.
* @return number of bytes decoded, or negative on error.
*/
int ptransfer_error_decode_service_request(
uint8_t *apdu,
unsigned apdu_len,
unsigned apdu_size,
BACNET_ERROR_CLASS *error_class,
BACNET_ERROR_CODE *error_code,
BACNET_PRIVATE_TRANSFER_DATA *private_data)
{
int len = 0; /* return value */
int decode_len = 0; /* return value */
uint8_t tag_number = 0;
uint32_t len_value_type = 0;
int apdu_len = 0, len = 0;
int application_len = 0;
uint32_t enum_value = 0;
BACNET_UNSIGNED_INTEGER unsigned_value = 0;
/* check for value pointers */
if (apdu_len && private_data) {
/* Tag 0: Error */
if (decode_is_opening_tag_number(&apdu[len], 0)) {
/* a tag number of 0 is not extended so only one octet */
len++;
/* error class */
decode_len = decode_tag_number_and_value(
&apdu[len], &tag_number, &len_value_type);
len += decode_len;
if (tag_number != BACNET_APPLICATION_TAG_ENUMERATED) {
return 0;
}
decode_len =
decode_enumerated(&apdu[len], len_value_type, &enum_value);
len += decode_len;
if (error_class) {
*error_class = (BACNET_ERROR_CLASS)enum_value;
}
/* error code */
decode_len = decode_tag_number_and_value(
&apdu[len], &tag_number, &len_value_type);
len += decode_len;
if (tag_number != BACNET_APPLICATION_TAG_ENUMERATED) {
return 0;
}
decode_len =
decode_enumerated(&apdu[len], len_value_type, &enum_value);
len += decode_len;
if (error_code) {
*error_code = (BACNET_ERROR_CODE)enum_value;
}
if (decode_is_closing_tag_number(&apdu[len], 0)) {
/* a tag number of 0 is not extended so only one octet */
len++;
} else {
return 0;
}
}
/* Tag 1: vendorID */
decode_len = decode_context_unsigned(&apdu[len], 1, &unsigned_value);
if (decode_len < 0) {
return -1;
}
len += decode_len;
/* check for value pointer and minimum size */
if (!(apdu && apdu_size)) {
return BACNET_STATUS_ERROR;
}
/* Tag 0: Error */
if (bacnet_is_opening_tag_number(
&apdu[apdu_len], apdu_size - apdu_len, 0, &len)) {
apdu_len += len;
} else {
return BACNET_STATUS_ERROR;
}
/* error class */
len = bacnet_enumerated_application_decode(
&apdu[apdu_len], apdu_size - apdu_len, &enum_value);
if (len <= 0) {
return BACNET_STATUS_ERROR;
}
apdu_len += len;
if (error_class) {
*error_class = (BACNET_ERROR_CLASS)enum_value;
}
/* error code */
len = bacnet_enumerated_application_decode(
&apdu[apdu_len], apdu_size - apdu_len, &enum_value);
if (len <= 0) {
return BACNET_STATUS_ERROR;
}
apdu_len += len;
if (error_code) {
*error_code = (BACNET_ERROR_CODE)enum_value;
}
if (bacnet_is_closing_tag_number(
&apdu[apdu_len], apdu_size - apdu_len, 0, &len)) {
apdu_len += len;
} else {
return BACNET_STATUS_ERROR;
}
/* Tag 1: vendorID */
len = bacnet_unsigned_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 1, &unsigned_value);
if (len <= 0) {
return BACNET_STATUS_ERROR;
}
apdu_len += len;
if (private_data) {
private_data->vendorID = (uint16_t)unsigned_value;
/* Tag 2: serviceNumber */
decode_len = decode_context_unsigned(&apdu[len], 2, &unsigned_value);
if (decode_len < 0) {
return -1;
}
len += decode_len;
}
/* Tag 2: serviceNumber */
len = bacnet_unsigned_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 2, &unsigned_value);
if (len <= 0) {
return BACNET_STATUS_ERROR;
}
apdu_len += len;
if (private_data) {
private_data->serviceNumber = (uint32_t)unsigned_value;
/* Tag 3: serviceParameters */
if (decode_is_opening_tag_number(&apdu[len], 3)) {
/* a tag number of 2 is not extended so only one octet */
len++;
/* don't decode the serviceParameters here */
private_data->serviceParameters = &apdu[len];
private_data->serviceParametersLen =
(int)apdu_len - len - 1 /*closing tag */;
} else {
return -1;
}
/* Tag 3: serviceParameters */
if (bacnet_is_opening_tag_number(
&apdu[apdu_len], apdu_size - apdu_len, 3, &len)) {
application_len =
bacnet_enclosed_data_length(&apdu[apdu_len], apdu_size - apdu_len);
if (application_len < 0) {
return BACNET_STATUS_ERROR;
}
/* we could check for a closing tag of 3 */
/* update the tag length */
apdu_len += len;
/* postpone serviceParameters decoding */
if (private_data) {
private_data->serviceParameters = &apdu[apdu_len];
private_data->serviceParametersLen = application_len;
}
apdu_len += application_len;
if (bacnet_is_closing_tag_number(
&apdu[apdu_len], apdu_size - apdu_len, 3, &len)) {
apdu_len += len;
} else {
return BACNET_STATUS_ERROR;
}
} else {
return BACNET_STATUS_ERROR;
}
return len;
return apdu_len;
}
int ptransfer_ack_encode_apdu(
+62 -61
View File
@@ -260,50 +260,60 @@ int rpm_encode_apdu(
* @return number of decoded bytes, or negative on failure.
*/
int rpm_decode_object_id(
const uint8_t *apdu, unsigned apdu_len, BACNET_RPM_DATA *rpmdata)
const uint8_t *apdu, unsigned apdu_size, BACNET_RPM_DATA *rpmdata)
{
int len = 0;
int len = 0, apdu_len = 0;
uint32_t instance = 0;
BACNET_OBJECT_TYPE type = OBJECT_NONE; /* for decoding */
/* check for value pointers */
if (apdu && apdu_len && rpmdata) {
if (apdu_len < 5) { /* Must be at least 2 tags and an object id */
rpmdata->error_code = ERROR_CODE_REJECT_MISSING_REQUIRED_PARAMETER;
if (apdu && apdu_size) {
if (apdu_size < 6) { /* Must be at least 2 tags and an object id */
if (rpmdata) {
rpmdata->error_code =
ERROR_CODE_REJECT_MISSING_REQUIRED_PARAMETER;
}
return BACNET_STATUS_REJECT;
}
/* Tag 0: Object ID */
if (!decode_is_context_tag(&apdu[len++], 0)) {
rpmdata->error_code = ERROR_CODE_REJECT_INVALID_TAG;
len = bacnet_object_id_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 0, &type, &instance);
if (len <= 0) {
if (rpmdata) {
rpmdata->error_code = ERROR_CODE_REJECT_INVALID_TAG;
}
return BACNET_STATUS_REJECT;
}
len += decode_object_id(&apdu[len], &type, &rpmdata->object_instance);
rpmdata->object_type = type;
if (rpmdata) {
rpmdata->object_type = type;
rpmdata->object_instance = instance;
}
apdu_len += len;
/* Tag 1: sequence of ReadAccessSpecification */
if (!decode_is_opening_tag_number(&apdu[len], 1)) {
rpmdata->error_code = ERROR_CODE_REJECT_INVALID_TAG;
if (!bacnet_is_opening_tag_number(
&apdu[apdu_len], apdu_size - apdu_len, 1, &len)) {
if (rpmdata) {
rpmdata->error_code = ERROR_CODE_REJECT_INVALID_TAG;
}
return BACNET_STATUS_REJECT;
}
len++; /* opening tag is only one octet */
apdu_len += len;
}
return len;
return apdu_len;
}
/**
* @brief Decode the end portion of the service request only.
* @param apdu application data unit buffer for decoding
* @param apdu_len [in] Count of valid bytes in the buffer.
* @param apdu_size [in] Count of valid bytes in the buffer.
* @return number of decoded bytes, or negative on failure.
*/
int rpm_decode_object_end(const uint8_t *apdu, unsigned apdu_len)
int rpm_decode_object_end(const uint8_t *apdu, unsigned apdu_size)
{
int len = 0; /* total length of the apdu, return value */
if (apdu && apdu_len) {
if (decode_is_closing_tag_number(apdu, 1) == true) {
len = 1;
}
}
(void)bacnet_is_closing_tag_number(apdu, apdu_size, 1, &len);
return len;
}
@@ -319,63 +329,54 @@ int rpm_decode_object_end(const uint8_t *apdu, unsigned apdu_len)
* }
*
* @param apdu application data unit buffer for decoding
* @param apdu_len Count of received bytes.
* @param apdu_size Count of received bytes.
* @param rpmdata Pointer to the data structure to be filled.
* @return number of decoded bytes, or negative on failure.
*/
int rpm_decode_object_property(
const uint8_t *apdu, unsigned apdu_len, BACNET_RPM_DATA *rpmdata)
const uint8_t *apdu, unsigned apdu_size, BACNET_RPM_DATA *rpmdata)
{
int len = 0;
int option_len = 0;
uint8_t tag_number = 0;
uint32_t len_value_type = 0;
int len = 0, apdu_len = 0;
uint32_t property = 0; /* for decoding */
BACNET_UNSIGNED_INTEGER unsigned_value = 0; /* for decoding */
/* check for valid pointers */
if (apdu && apdu_len && rpmdata) {
/* Tag 0: propertyIdentifier */
if (!IS_CONTEXT_SPECIFIC(apdu[len])) {
rpmdata->error_code = ERROR_CODE_REJECT_INVALID_TAG;
/* check for valid pointer and minimum size */
if (apdu && apdu_size) {
/* propertyIdentifier [0] BACnetPropertyIdentifier */
len = bacnet_enumerated_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 0, &property);
if (len <= 0) {
if (rpmdata) {
rpmdata->error_code = ERROR_CODE_REJECT_INVALID_TAG;
}
return BACNET_STATUS_REJECT;
}
len += decode_tag_number_and_value(
&apdu[len], &tag_number, &len_value_type);
if (tag_number != 0) {
rpmdata->error_code = ERROR_CODE_REJECT_INVALID_TAG;
return BACNET_STATUS_REJECT;
if (rpmdata) {
rpmdata->object_property = (BACNET_PROPERTY_ID)property;
}
/* Should be at least the unsigned value + 1 tag left */
if ((len + len_value_type) >= apdu_len) {
rpmdata->error_code = ERROR_CODE_REJECT_MISSING_REQUIRED_PARAMETER;
return BACNET_STATUS_REJECT;
}
len += decode_enumerated(&apdu[len], len_value_type, &property);
rpmdata->object_property = (BACNET_PROPERTY_ID)property;
/* Assume most probable outcome */
rpmdata->array_index = BACNET_ARRAY_ALL;
/* Tag 1: Optional propertyArrayIndex */
if (IS_CONTEXT_SPECIFIC(apdu[len]) && !IS_CLOSING_TAG(apdu[len])) {
option_len = decode_tag_number_and_value(
&apdu[len], &tag_number, &len_value_type);
if (tag_number == 1) {
len += option_len;
/* Should be at least the unsigned array index + 1 tag left */
if ((len + len_value_type) >= apdu_len) {
rpmdata->error_code =
ERROR_CODE_REJECT_MISSING_REQUIRED_PARAMETER;
return BACNET_STATUS_REJECT;
}
len += decode_unsigned(
&apdu[len], len_value_type, &unsigned_value);
apdu_len += len;
len = bacnet_unsigned_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 1, &unsigned_value);
if (len > 0) {
/* propertyArrayIndex [1] Unsigned OPTIONAL */
apdu_len += len;
if (rpmdata) {
rpmdata->array_index = unsigned_value;
}
} else if (len == 0) {
/* optional - assume ALL array elements */
if (rpmdata) {
rpmdata->array_index = BACNET_ARRAY_ALL;
}
} else {
if (rpmdata) {
rpmdata->error_code = ERROR_CODE_REJECT_INVALID_TAG;
}
return BACNET_STATUS_REJECT;
}
}
return len;
return apdu_len;
}
/**
+4
View File
@@ -282,6 +282,7 @@ int bacnet_timestamp_decode(
return apdu_len;
}
#if defined(BACNET_STACK_DEPRECATED_DISABLE)
/**
* @brief Decode a time stamp from the given buffer.
* @param apdu Pointer to the APDU buffer.
@@ -294,6 +295,7 @@ int bacapp_decode_timestamp(const uint8_t *apdu, BACNET_TIMESTAMP *value)
{
return bacnet_timestamp_decode(apdu, MAX_APDU, value);
}
#endif
/**
* @brief Decode a time stamp and check for opening and closing tags.
@@ -337,6 +339,7 @@ int bacnet_timestamp_context_decode(
return apdu_len;
}
#if defined(BACNET_STACK_DEPRECATED_DISABLE)
/**
* @brief Decode a time stamp and check for opening and closing tags.
* @param apdu Pointer to the APDU buffer.
@@ -360,6 +363,7 @@ int bacapp_decode_context_timestamp(
return len;
}
#endif
/**
* @brief Parse an ascii string for the timestamp
+85 -171
View File
@@ -15,6 +15,41 @@
#include "bacnet/timesync.h"
#if BACNET_SVC_TS_A
/**
* @brief Encode the time synchronisation service.
*
* TimeSynchronization-Request ::= SEQUENCE {
* time BACnetDateTime
* }
*
* @param apdu [in] Buffer in which the APDU contents are written
* @param service [in] Time service that shall be encoded, like
* SERVICE_UNCONFIRMED_UTC_TIME_SYNCHRONIZATION.
* @param my_date [in] Pointer to the date structure used to encode.
* @param my_time [in] Pointer to the time structure used to encode.
*
* @return Count of encoded bytes.
*/
int timesync_encode_apdu_service_parameters(
uint8_t *apdu, const BACNET_DATE *my_date, const BACNET_TIME *my_time)
{
int len = 0; /* length of each encoding */
int apdu_len = 0; /* total length of the apdu, return value */
if (my_date && my_time) {
/* encode the date and time */
len = encode_application_date(apdu, my_date);
apdu_len += len;
if (apdu) {
apdu += len;
}
len = encode_application_time(apdu, my_time);
apdu_len += len;
}
return apdu_len;
}
/** Encode the time synchronisation service.
*
* @param apdu [in] Buffer in which the APDU contents are written
@@ -34,15 +69,17 @@ int timesync_encode_apdu_service(
int len = 0; /* length of each encoding */
int apdu_len = 0; /* total length of the apdu, return value */
if (apdu && my_date && my_time) {
if (apdu) {
apdu[0] = PDU_TYPE_UNCONFIRMED_SERVICE_REQUEST;
apdu[1] = service;
apdu_len = 2;
len = encode_application_date(&apdu[apdu_len], my_date);
apdu_len += len;
len = encode_application_time(&apdu[apdu_len], my_time);
apdu_len += len;
}
len = 2;
apdu_len += len;
if (apdu) {
apdu += len;
}
len = timesync_encode_apdu_service_parameters(apdu, my_date, my_time);
apdu_len += len;
return apdu_len;
}
@@ -81,7 +118,7 @@ int timesync_encode_apdu(
/** Decode the service request only.
*
* @param apdu [in] Buffer in which the APDU contents are read
* @param apdu_len [in] length of the APDU buffer.
* @param apdu_size [in] length of the APDU buffer.
* @param my_date [in] Pointer to the date structure filled in.
* @param my_time [in] Pointer to the time structure filled in.
*
@@ -89,40 +126,29 @@ int timesync_encode_apdu(
*/
int timesync_decode_service_request(
const uint8_t *apdu,
unsigned apdu_len,
unsigned apdu_size,
BACNET_DATE *my_date,
BACNET_TIME *my_time)
{
int len = 0;
uint8_t tag_number = 0;
uint32_t len_value = 0;
int len = 0, apdu_len = 0;
if (apdu_len && my_date && my_time) {
/* date */
len += decode_tag_number_and_value(&apdu[len], &tag_number, &len_value);
if (tag_number == BACNET_APPLICATION_TAG_DATE) {
if ((unsigned)(len + 4) <= apdu_len) {
len += decode_date(&apdu[len], my_date);
} else {
return -1;
}
} else {
return -1;
}
/* time */
len += decode_tag_number_and_value(&apdu[len], &tag_number, &len_value);
if (tag_number == BACNET_APPLICATION_TAG_TIME) {
if ((unsigned)(len + 4) <= apdu_len) {
len += decode_bacnet_time(&apdu[len], my_time);
} else {
return -1;
}
} else {
return -1;
}
if (!(apdu && apdu_size)) {
return BACNET_STATUS_ERROR;
}
len = bacnet_date_application_decode(
&apdu[apdu_len], apdu_size - apdu_len, my_date);
if (len <= 0) {
return BACNET_STATUS_ERROR;
}
apdu_len += len;
len = bacnet_time_application_decode(
&apdu[apdu_len], apdu_size - apdu_len, my_time);
if (len <= 0) {
return BACNET_STATUS_ERROR;
}
apdu_len += len;
return len;
return apdu_len;
}
/** Handle a request to encode the list of timesync recipients.
@@ -143,78 +169,23 @@ int timesync_decode_service_request(
* }
*
* @param apdu [out] Buffer in which the APDU contents are built.
* @param max_apdu [in] Max length of the APDU buffer.
* @param apdu_size [in] Max length of the APDU buffer.
* @param recipient [in] BACNET_RECIPIENT_LIST type linked list of recipients.
*
* @return How many bytes were encoded in the buffer, or
* BACNET_STATUS_ABORT if the response would not fit within the buffer.
*/
int timesync_encode_timesync_recipients(
uint8_t *apdu, unsigned max_apdu, BACNET_RECIPIENT_LIST *recipient)
uint8_t *apdu, unsigned apdu_size, BACNET_RECIPIENT_LIST *list_head)
{
int len = 0;
int apdu_len = 0;
BACNET_OCTET_STRING octet_string;
BACNET_RECIPIENT_LIST *pRecipient;
if ((!apdu) || (max_apdu < 1) || (!recipient)) {
return (0);
}
pRecipient = recipient;
while (pRecipient != NULL) {
if (pRecipient->tag == 0) {
if (max_apdu >= (1 + 4)) {
/* CHOICE - device [0] BACnetObjectIdentifier */
if (pRecipient->type.device.type == OBJECT_DEVICE) {
len = encode_context_object_id(
&apdu[apdu_len], 0, pRecipient->type.device.type,
pRecipient->type.device.instance);
apdu_len += len;
}
} else {
return BACNET_STATUS_ABORT;
}
} else if (pRecipient->tag == 1) {
if (pRecipient->type.address.net) {
len = (int)(1 + 3 + 2 + pRecipient->type.address.len + 1);
} else {
len = (int)(1 + 3 + 2 + pRecipient->type.address.mac_len + 1);
}
if (max_apdu >= (unsigned)len) {
/* CHOICE - address [1] BACnetAddress - opening */
len = encode_opening_tag(&apdu[apdu_len], 1);
apdu_len += len;
/* network-number Unsigned16, */
/* -- A value of 0 indicates the local network */
len = encode_application_unsigned(
&apdu[apdu_len], pRecipient->type.address.net);
apdu_len += len;
/* mac-address OCTET STRING */
/* -- A string of length 0 indicates a broadcast */
if (pRecipient->type.address.net == BACNET_BROADCAST_NETWORK) {
octetstring_init(&octet_string, NULL, 0);
} else if (pRecipient->type.address.net) {
octetstring_init(
&octet_string, &pRecipient->type.address.adr[0],
pRecipient->type.address.len);
} else {
octetstring_init(
&octet_string, &pRecipient->type.address.mac[0],
pRecipient->type.address.mac_len);
}
len = encode_application_octet_string(
&apdu[apdu_len], &octet_string);
apdu_len += len;
/* CHOICE - address [1] BACnetAddress - closing */
len = encode_closing_tag(&apdu[apdu_len], 1);
apdu_len += len;
} else {
/* not a valid tag - don't encode this one */
}
}
pRecipient = pRecipient->next;
apdu_len = bacnet_recipient_list_encode(NULL, list_head);
if (apdu_len > apdu_size) {
/* response would not fit within the buffer */
return BACNET_STATUS_ABORT;
}
apdu_len = bacnet_recipient_list_encode(apdu, list_head);
return apdu_len;
}
@@ -244,89 +215,32 @@ int timesync_encode_timesync_recipients(
* BACNET_STATUS_ABORT if there was a problem decoding the buffer
*/
int timesync_decode_timesync_recipients(
const uint8_t *apdu, unsigned max_apdu, BACNET_RECIPIENT_LIST *recipient)
const uint8_t *apdu, unsigned apdu_size, BACNET_RECIPIENT_LIST *list_head)
{
int len = 0;
int apdu_len = 0;
int tag_len = 0;
uint8_t tag_number = 0;
uint32_t len_value_type = 0;
BACNET_UNSIGNED_INTEGER unsigned_value = 0;
BACNET_OCTET_STRING octet_string;
BACNET_RECIPIENT_LIST *pRecipient;
BACNET_RECIPIENT_LIST *list;
BACNET_RECIPIENT *recipient;
if ((!apdu) || (max_apdu < 1) || (!recipient)) {
if ((!apdu) || (apdu_size == 0)) {
return BACNET_STATUS_ABORT;
}
pRecipient = recipient;
while (pRecipient != NULL) {
/* device [0] BACnetObjectIdentifier */
if (decode_is_context_tag(&apdu[apdu_len], 0)) {
pRecipient->tag = 0;
if ((unsigned)(apdu_len + 4) > max_apdu) {
return BACNET_STATUS_ABORT;
}
len = decode_context_object_id(
&apdu[apdu_len], 0, &pRecipient->type.device.type,
&pRecipient->type.device.instance);
if (len < 0) {
return BACNET_STATUS_ABORT;
}
apdu_len += len;
} else if (decode_is_opening_tag_number(&apdu[apdu_len], 1)) {
apdu_len += 1;
pRecipient->tag = 1;
/* network-number Unsigned16 */
tag_len = decode_tag_number_and_value(
&apdu[apdu_len], &tag_number, &len_value_type);
apdu_len += tag_len;
if ((unsigned)apdu_len > max_apdu) {
return BACNET_STATUS_ABORT;
}
if (tag_number != BACNET_APPLICATION_TAG_UNSIGNED_INT) {
return BACNET_STATUS_ABORT;
}
len = decode_unsigned(
&apdu[apdu_len], len_value_type, &unsigned_value);
pRecipient->type.address.net = (uint16_t)unsigned_value;
apdu_len += len;
if ((unsigned)apdu_len > max_apdu) {
return BACNET_STATUS_ABORT;
}
/* mac-address OCTET STRING */
tag_len = decode_tag_number_and_value(
&apdu[apdu_len], &tag_number, &len_value_type);
apdu_len += tag_len;
if (tag_number != BACNET_APPLICATION_TAG_OCTET_STRING) {
return BACNET_STATUS_ABORT;
}
len = bacnet_octet_string_decode(
&apdu[apdu_len], max_apdu - apdu_len, len_value_type,
&octet_string);
if (len < 0) {
return BACNET_STATUS_ERROR;
}
apdu_len += len;
if (octetstring_length(&octet_string) == 0) {
/* -- A string of length 0 indicates a broadcast */
} else if (pRecipient->type.address.net) {
pRecipient->type.address.len = octetstring_copy_value(
&pRecipient->type.address.adr[0],
sizeof(pRecipient->type.address.adr), &octet_string);
} else {
pRecipient->type.address.mac_len = octetstring_copy_value(
&pRecipient->type.address.mac[0],
sizeof(pRecipient->type.address.mac), &octet_string);
}
if (!decode_is_closing_tag_number(&apdu[apdu_len], 1)) {
return BACNET_STATUS_ABORT;
}
apdu_len += 1;
list = list_head;
while (apdu_len < apdu_size) {
if (list) {
recipient = &list->recipient;
} else {
recipient = NULL;
}
len = bacnet_recipient_decode(
&apdu[apdu_len], apdu_size - apdu_len, recipient);
if (len <= 0) {
return BACNET_STATUS_ABORT;
}
pRecipient = pRecipient->next;
apdu_len += len;
if (list) {
list = list->next;
}
}
return apdu_len;
+4 -17
View File
@@ -13,23 +13,7 @@
#include <stdbool.h>
/* BACnet Stack defines - first */
#include "bacnet/bacdef.h"
struct BACnet_Recipient_List;
typedef struct BACnet_Recipient_List {
/*
BACnetRecipient ::= CHOICE {
device [0] BACnetObjectIdentifier,
address [1] BACnetAddress
}
*/
uint8_t tag;
union {
BACNET_OBJECT_ID device;
BACNET_ADDRESS address;
} type;
/* simple linked list */
struct BACnet_Recipient_List *next;
} BACNET_RECIPIENT_LIST;
#include "bacnet/bacdest.h"
#ifdef __cplusplus
extern "C" {
@@ -37,6 +21,9 @@ extern "C" {
/* encode service */
BACNET_STACK_EXPORT
int timesync_encode_apdu_service_parameters(
uint8_t *apdu, const BACNET_DATE *my_date, const BACNET_TIME *my_time);
BACNET_STACK_EXPORT
int timesync_utc_encode_apdu(
uint8_t *apdu, const BACNET_DATE *my_date, const BACNET_TIME *my_time);
BACNET_STACK_EXPORT
+1 -1
View File
@@ -15,7 +15,7 @@
#define BACNET_VERSION(x, y, z) (((x) << 16) + ((y) << 8) + (z))
#endif
#define BACNET_VERSION_TEXT "1.5.0.rc4"
#define BACNET_VERSION_TEXT "1.5.0.rc5"
#define BACNET_VERSION_CODE BACNET_VERSION(1, 5, 0)
#define BACNET_VERSION_MAJOR ((BACNET_VERSION_CODE >> 16) & 0xFF)
#define BACNET_VERSION_MINOR ((BACNET_VERSION_CODE >> 8) & 0xFF)
+46 -8
View File
@@ -198,21 +198,30 @@ int wp_decode_service_request(
/* check for value pointers */
if (!apdu) {
if (wpdata) {
wpdata->error_code = ERROR_CODE_REJECT_MISSING_REQUIRED_PARAMETER;
}
return BACNET_STATUS_ERROR;
}
if (wpdata) {
wpdata->error_code = ERROR_CODE_OTHER;
wpdata->array_index = BACNET_ARRAY_ALL;
wpdata->priority = BACNET_MAX_PRIORITY;
wpdata->application_data_len = 0;
}
/* object-identifier [0] BACnetObjectIdentifier */
len = bacnet_object_id_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 0, &type, &instance);
if (len > 0) {
if (instance > BACNET_MAX_INSTANCE) {
return BACNET_STATUS_ERROR;
}
apdu_len += len;
if (wpdata) {
wpdata->object_type = type;
wpdata->object_instance = instance;
}
} else {
if (wpdata) {
wpdata->error_code = ERROR_CODE_REJECT_MISSING_REQUIRED_PARAMETER;
}
return BACNET_STATUS_ERROR;
}
/* property-identifier [1] BACnetPropertyIdentifier */
@@ -224,6 +233,9 @@ int wp_decode_service_request(
wpdata->object_property = (BACNET_PROPERTY_ID)property;
}
} else {
if (wpdata) {
wpdata->error_code = ERROR_CODE_REJECT_MISSING_REQUIRED_PARAMETER;
}
return BACNET_STATUS_ERROR;
}
/* property-array-index [2] Unsigned OPTIONAL */
@@ -235,7 +247,7 @@ int wp_decode_service_request(
wpdata->array_index = unsigned_value;
}
} else {
/* wrong tag - skip apdu_len increment and go to next field */
/* wrong tag, OPTIONAL, skip apdu_len increment and go to next field */
if (wpdata) {
wpdata->array_index = BACNET_ARRAY_ALL;
}
@@ -243,20 +255,35 @@ int wp_decode_service_request(
/* property-value [3] ABSTRACT-SYNTAX.&Type */
if (!bacnet_is_opening_tag_number(
&apdu[apdu_len], apdu_size - apdu_len, 3, &len)) {
if (wpdata) {
wpdata->error_code = ERROR_CODE_REJECT_INVALID_TAG;
}
return BACNET_STATUS_ERROR;
}
/* determine the length of the data blob */
imax = bacnet_enclosed_data_length(&apdu[apdu_len], apdu_size - apdu_len);
if (imax == BACNET_STATUS_ERROR) {
if (imax < 0) {
if (wpdata) {
wpdata->error_code = ERROR_CODE_REJECT_INVALID_TAG;
}
return BACNET_STATUS_ERROR;
}
/* count the opening tag number length */
apdu_len += len;
/* copy the data from the APDU */
if (imax > MAX_APDU) {
/* not enough size in application_data to store the data chunk */
if (imax > (apdu_size - apdu_len)) {
/* not enough bytes in APDU to avoid buffer overrun */
if (wpdata) {
wpdata->error_code = ERROR_CODE_REJECT_BUFFER_OVERFLOW;
}
return BACNET_STATUS_ERROR;
} else if (wpdata) {
}
if (wpdata) {
if (imax > sizeof(wpdata->application_data)) {
/* not enough bytes in application_data to store the data chunk */
wpdata->error_code = ERROR_CODE_REJECT_BUFFER_OVERFLOW;
return BACNET_STATUS_ERROR;
}
for (i = 0; i < imax; i++) {
wpdata->application_data[i] = apdu[apdu_len + i];
}
@@ -266,6 +293,9 @@ int wp_decode_service_request(
apdu_len += imax;
if (!bacnet_is_closing_tag_number(
&apdu[apdu_len], apdu_size - apdu_len, 3, &len)) {
if (wpdata) {
wpdata->error_code = ERROR_CODE_REJECT_INVALID_TAG;
}
return BACNET_STATUS_ERROR;
}
/* count the closing tag number length */
@@ -286,9 +316,17 @@ int wp_decode_service_request(
wpdata->priority = (uint8_t)unsigned_value;
}
} else {
if (wpdata) {
wpdata->error_code =
ERROR_CODE_REJECT_PARAMETER_OUT_OF_RANGE;
}
return BACNET_STATUS_ERROR;
}
} else {
if (wpdata) {
wpdata->error_code =
ERROR_CODE_REJECT_MISSING_REQUIRED_PARAMETER;
}
return BACNET_STATUS_ERROR;
}
}
+237 -190
View File
@@ -38,43 +38,41 @@
* @return Count of decoded bytes.
*/
int wpm_decode_object_id(
const uint8_t *apdu, uint16_t apdu_len, BACNET_WRITE_PROPERTY_DATA *wp_data)
const uint8_t *apdu,
uint16_t apdu_size,
BACNET_WRITE_PROPERTY_DATA *wp_data)
{
uint8_t tag_number = 0;
uint32_t len_value = 0;
uint32_t object_instance = 0;
BACNET_OBJECT_TYPE object_type = OBJECT_NONE;
uint16_t len = 0;
int len = 0, apdu_len = 0;
if (apdu && (apdu_len > 5)) {
/* check for valid pointer and minimum size */
if (apdu && (apdu_size > 5)) {
/* Context tag 0 - Object ID */
len += decode_tag_number_and_value(&apdu[len], &tag_number, &len_value);
if ((tag_number == 0) && (apdu_len > len)) {
apdu_len -= len;
if (apdu_len >= 4) {
len += decode_object_id(
&apdu[len], &object_type, &object_instance);
if (wp_data) {
wp_data->object_type = object_type;
wp_data->object_instance = object_instance;
}
apdu_len -= len;
} else {
if (wp_data) {
wp_data->error_code =
ERROR_CODE_REJECT_MISSING_REQUIRED_PARAMETER;
}
return BACNET_STATUS_REJECT;
}
} else {
len = bacnet_object_id_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 0, &object_type,
&object_instance);
if (len < 0) {
if (wp_data) {
wp_data->error_code = ERROR_CODE_REJECT_INVALID_TAG;
}
return BACNET_STATUS_REJECT;
} else if (len == 0) {
if (wp_data) {
wp_data->error_code =
ERROR_CODE_REJECT_MISSING_REQUIRED_PARAMETER;
}
return BACNET_STATUS_REJECT;
}
apdu_len += len;
if (wp_data) {
wp_data->object_type = object_type;
wp_data->object_instance = object_instance;
}
/* just test for the next tag - no need to decode it here */
/* Context tag 1: sequence of BACnetPropertyValue */
if (apdu_len && !decode_is_opening_tag_number(&apdu[len], 1)) {
if (!bacnet_is_opening_tag_number(
&apdu[len], apdu_size - apdu_len, 1, NULL)) {
if (wp_data) {
wp_data->error_code = ERROR_CODE_REJECT_INVALID_TAG;
}
@@ -91,6 +89,17 @@ int wpm_decode_object_id(
}
/** Decoding for an object property.
*
* BACnetPropertyValue ::= SEQUENCE {
* property-identifier[0] BACnetPropertyIdentifier,
* property-array-index[1] Unsigned OPTIONAL,
* -- used only with array datatypes
* -- if omitted with an array the entire array is referenced
* property-value[2] ABSTRACT-SYNTAX.&Type,
* -- any datatype appropriate for the specified property
* priority[3] Unsigned (1..16) OPTIONAL
* -- used only when property is commandable
* }
*
* @param apdu [in] The contents of the APDU buffer.
* @param apdu_len [in] The length of the APDU buffer.
@@ -99,93 +108,126 @@ int wpm_decode_object_id(
* @return Bytes decoded
*/
int wpm_decode_object_property(
const uint8_t *apdu, uint16_t apdu_len, BACNET_WRITE_PROPERTY_DATA *wp_data)
const uint8_t *apdu,
uint16_t apdu_size,
BACNET_WRITE_PROPERTY_DATA *wp_data)
{
uint8_t tag_number = 0;
uint32_t len_value = 0;
uint32_t enum_value = 0;
BACNET_UNSIGNED_INTEGER unsigned_value = 0;
int len = 0, i = 0, imax = 0;
int len = 0, apdu_len = 0, i = 0, imax = 0;
if ((apdu) && (apdu_len) && (wp_data)) {
wp_data->array_index = BACNET_ARRAY_ALL;
wp_data->priority = BACNET_MAX_PRIORITY;
wp_data->application_data_len = 0;
/* tag 0 - Property Identifier */
len += decode_tag_number_and_value(&apdu[len], &tag_number, &len_value);
if (tag_number == 0) {
len += decode_enumerated(&apdu[len], len_value, &enum_value);
wp_data->object_property = enum_value;
} else {
wp_data->error_code = ERROR_CODE_REJECT_INVALID_TAG;
return BACNET_STATUS_REJECT;
}
/* tag 1 - Property Array Index - optional */
len += decode_tag_number_and_value(&apdu[len], &tag_number, &len_value);
if (tag_number == 1) {
len += decode_unsigned(&apdu[len], len_value, &unsigned_value);
wp_data->array_index = (uint32_t)unsigned_value;
len += decode_tag_number_and_value(
&apdu[len], &tag_number, &len_value);
}
/* tag 2 - Property Value */
if ((tag_number == 2) && (decode_is_opening_tag(&apdu[len - 1]))) {
len--;
imax = bacnet_enclosed_data_length(&apdu[len], apdu_len - len);
len++;
if (imax != BACNET_STATUS_ERROR) {
/* copy application data, check max length */
if (imax > (apdu_len - len)) {
imax = (apdu_len - len);
}
for (i = 0; i < imax; i++) {
wp_data->application_data[i] = apdu[len + i];
}
wp_data->application_data_len = imax;
len += imax;
if (len < apdu_len) {
len += decode_tag_number_and_value(
&apdu[len], &tag_number, &len_value);
/* closing tag 2 */
if ((tag_number != 2) &&
(decode_is_closing_tag(&apdu[len - 1]))) {
wp_data->error_code = ERROR_CODE_REJECT_INVALID_TAG;
return BACNET_STATUS_REJECT;
}
} else {
wp_data->error_code = ERROR_CODE_REJECT_INVALID_TAG;
return BACNET_STATUS_REJECT;
}
} else {
wp_data->error_code = ERROR_CODE_REJECT_INVALID_TAG;
return BACNET_STATUS_REJECT;
}
} else {
wp_data->error_code = ERROR_CODE_REJECT_INVALID_TAG;
return BACNET_STATUS_REJECT;
}
/* tag 3 - Priority - optional */
if (len < apdu_len) {
len += decode_tag_number_and_value(
&apdu[len], &tag_number, &len_value);
if (tag_number == 3) {
len += decode_unsigned(&apdu[len], len_value, &unsigned_value);
wp_data->priority = (uint8_t)unsigned_value;
} else {
len--;
}
}
} else {
if (!apdu || (apdu_size == 0)) {
if (wp_data) {
wp_data->error_code = ERROR_CODE_REJECT_MISSING_REQUIRED_PARAMETER;
}
return BACNET_STATUS_REJECT;
}
if (wp_data) {
wp_data->error_code = ERROR_CODE_OTHER;
wp_data->array_index = BACNET_ARRAY_ALL;
wp_data->priority = BACNET_MAX_PRIORITY;
wp_data->application_data_len = 0;
}
/* property-identifier[0] BACnetPropertyIdentifier */
len = bacnet_enumerated_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 0, &enum_value);
if (len <= 0) {
if (wp_data) {
wp_data->error_code = ERROR_CODE_REJECT_INVALID_TAG;
}
return BACNET_STATUS_REJECT;
}
apdu_len += len;
if (wp_data) {
wp_data->object_property = enum_value;
}
len = bacnet_unsigned_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 1, &unsigned_value);
if (len > 0) {
/* property-array-index [1] Unsigned OPTIONAL */
apdu_len += len;
if (wp_data) {
wp_data->array_index = unsigned_value;
}
} else if (len == 0) {
/* optional - assume ALL array elements */
if (wp_data) {
wp_data->array_index = BACNET_ARRAY_ALL;
}
} else {
if (wp_data) {
wp_data->error_code = ERROR_CODE_REJECT_INVALID_TAG;
}
return BACNET_STATUS_REJECT;
}
/* property-value[2] ABSTRACT-SYNTAX.&Type */
if (!bacnet_is_opening_tag_number(
&apdu[apdu_len], apdu_size - apdu_len, 2, &len)) {
if (wp_data) {
wp_data->error_code = ERROR_CODE_REJECT_INVALID_TAG;
}
return BACNET_STATUS_REJECT;
}
/* note: evaluate with the tag as the first octet */
imax = bacnet_enclosed_data_length(&apdu[apdu_len], apdu_size - apdu_len);
if (imax == BACNET_STATUS_ERROR) {
if (wp_data) {
wp_data->error_code = ERROR_CODE_REJECT_INVALID_TAG;
}
return BACNET_STATUS_REJECT;
}
/* add the tag length */
apdu_len += len;
if (imax > (apdu_size - apdu_len)) {
/* bigger than the buffer we are reading from */
if (wp_data) {
wp_data->error_code = ERROR_CODE_REJECT_BUFFER_OVERFLOW;
}
return BACNET_STATUS_REJECT;
}
if (wp_data) {
if (imax > sizeof(wp_data->application_data)) {
/* bigger than the buffer we are writing to */
wp_data->error_code = ERROR_CODE_REJECT_BUFFER_OVERFLOW;
return BACNET_STATUS_REJECT;
}
for (i = 0; i < imax; i++) {
wp_data->application_data[i] = apdu[apdu_len + i];
}
wp_data->application_data_len = imax;
}
/* add the application data length */
apdu_len += imax;
if (bacnet_is_closing_tag_number(
&apdu[apdu_len], apdu_size - apdu_len, 2, &len)) {
apdu_len += len;
} else {
if (wp_data) {
wp_data->error_code = ERROR_CODE_REJECT_INVALID_TAG;
}
return BACNET_STATUS_REJECT;
}
/* priority[3] Unsigned (1..16) OPTIONAL */
len = bacnet_unsigned_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 3, &unsigned_value);
if (len > 0) {
apdu_len += len;
if (wp_data) {
wp_data->priority = unsigned_value;
}
} else if (len == 0) {
/* OPTIONAL - no priority */
if (wp_data) {
wp_data->priority = BACNET_NO_PRIORITY;
}
} else {
if (wp_data) {
wp_data->error_code = ERROR_CODE_REJECT_INVALID_TAG;
}
return BACNET_STATUS_REJECT;
}
return len;
return apdu_len;
}
/**
@@ -442,39 +484,92 @@ int wpm_ack_encode_apdu_init(uint8_t *apdu, uint8_t invoke_id)
/** Encode an Error acknowledge in the APDU.
*
* @param apdu [in] The APDU buffer.
* @param apdu [in] The APDU buffer, or NULL for length
* @param wp_data [in] Data of the invoked property.
*
* @return number of bytes encoded.
*/
int wpm_error_ack_service_encode(
uint8_t *apdu, const BACNET_WRITE_PROPERTY_DATA *wp_data)
{
int len = 0, apdu_len = 0;
len = encode_opening_tag(apdu, 0);
apdu_len += len;
if (apdu) {
apdu += len;
}
len = encode_application_enumerated(apdu, wp_data->error_class);
apdu_len += len;
if (apdu) {
apdu += len;
}
len = encode_application_enumerated(apdu, wp_data->error_code);
apdu_len += len;
if (apdu) {
apdu += len;
}
len = encode_closing_tag(apdu, 0);
apdu_len += len;
if (apdu) {
apdu += len;
}
len = encode_opening_tag(apdu, 1);
apdu_len += len;
if (apdu) {
apdu += len;
}
len = encode_context_object_id(
apdu, 0, wp_data->object_type, wp_data->object_instance);
apdu_len += len;
if (apdu) {
apdu += len;
}
len = encode_context_enumerated(apdu, 1, wp_data->object_property);
apdu_len += len;
if (apdu) {
apdu += len;
}
if (wp_data->array_index != BACNET_ARRAY_ALL) {
len = encode_context_unsigned(apdu, 2, wp_data->array_index);
apdu_len += len;
if (apdu) {
apdu += len;
}
}
len = encode_closing_tag(apdu, 1);
apdu_len += len;
return apdu_len;
}
/** Encode an Error acknowledge in the APDU.
*
* @param apdu [in] The APDU buffer, or NULL for length
* @param invoke_id [in] Invoked service ID.
* @param wp_data [in] Data of the invoked property.
*
* @return Bytes encoded.
* @return number of bytes encoded.
*/
int wpm_error_ack_encode_apdu(
uint8_t *apdu, uint8_t invoke_id, const BACNET_WRITE_PROPERTY_DATA *wp_data)
{
int len = 0;
int len = 0, apdu_len = 0;
if (apdu) {
apdu[len++] = PDU_TYPE_ERROR;
apdu[len++] = invoke_id;
apdu[len++] = SERVICE_CONFIRMED_WRITE_PROP_MULTIPLE;
len += encode_opening_tag(&apdu[len], 0);
len += encode_application_enumerated(&apdu[len], wp_data->error_class);
len += encode_application_enumerated(&apdu[len], wp_data->error_code);
len += encode_closing_tag(&apdu[len], 0);
len += encode_opening_tag(&apdu[len], 1);
len += encode_context_object_id(
&apdu[len], 0, wp_data->object_type, wp_data->object_instance);
len +=
encode_context_enumerated(&apdu[len], 1, wp_data->object_property);
if (wp_data->array_index != BACNET_ARRAY_ALL) {
len += encode_context_unsigned(&apdu[len], 2, wp_data->array_index);
}
len += encode_closing_tag(&apdu[len], 1);
apdu[0] = PDU_TYPE_ERROR;
apdu[1] = invoke_id;
apdu[2] = SERVICE_CONFIRMED_WRITE_PROP_MULTIPLE;
}
return len;
len = 3;
apdu_len += len;
if (apdu) {
apdu += len;
}
len = wpm_error_ack_service_encode(apdu, wp_data);
apdu_len += len;
return apdu_len;
}
#if !BACNET_SVC_SERVER
@@ -498,91 +593,54 @@ int wpm_error_ack_decode_apdu(
BACNET_WRITE_PROPERTY_DATA *wp_data)
{
int len = 0, apdu_len = 0;
const uint8_t *apdu_offset = NULL;
BACNET_ERROR_CLASS error_class = ERROR_CLASS_SERVICES;
BACNET_ERROR_CODE error_code = ERROR_CODE_SUCCESS;
BACNET_OBJECT_PROPERTY_REFERENCE value;
if (apdu) {
apdu_offset = apdu;
if (!apdu || (apdu_size == 0)) {
if (wp_data) {
wp_data->error_class = ERROR_CLASS_SERVICES;
wp_data->error_code = ERROR_CODE_REJECT_MISSING_REQUIRED_PARAMETER;
}
return 0;
}
if (wp_data) {
wp_data->error_class = ERROR_CLASS_SERVICES;
wp_data->error_code = ERROR_CODE_REJECT_PARAMETER_OUT_OF_RANGE;
}
/* Context tag 0 - Error */
if (apdu_size == 0) {
return 0;
}
if (decode_is_opening_tag_number(apdu_offset, 0)) {
len = 1;
if (bacnet_is_opening_tag_number(
&apdu[apdu_len], apdu_size - apdu_len, 0, &len)) {
apdu_len += len;
if (apdu) {
apdu_offset = &apdu[apdu_len];
if (apdu_size > len) {
apdu_size -= len;
} else {
return 0;
}
}
} else {
return 0;
}
len = bacerror_decode_error_class_and_code(
apdu_offset, apdu_size, &error_class, &error_code);
&apdu[apdu_len], apdu_size - apdu_len, &error_class, &error_code);
if (len > 0) {
if (wp_data) {
wp_data->error_class = error_class;
wp_data->error_code = error_code;
}
apdu_len += len;
if (apdu) {
apdu_offset = &apdu[apdu_len];
if (apdu_size > len) {
apdu_size -= len;
} else {
return 0;
}
}
} else {
return 0;
}
if (apdu_size == 0) {
return 0;
}
if (decode_is_closing_tag_number(apdu_offset, 0)) {
len = 1;
if (bacnet_is_closing_tag_number(
&apdu[apdu_len], apdu_size - apdu_len, 0, &len)) {
apdu_len += len;
if (apdu) {
apdu_offset = &apdu[apdu_len];
if (apdu_size > len) {
apdu_size -= len;
} else {
return 0;
}
}
} else {
return 0;
}
/* Context tag 1 - BACnetObjectPropertyReference */
if (apdu_size == 0) {
return 0;
}
if (decode_is_opening_tag_number(apdu_offset, 1)) {
len = 1;
if (bacnet_is_opening_tag_number(
&apdu[apdu_len], apdu_size - apdu_len, 1, &len)) {
apdu_len += len;
if (apdu) {
apdu_offset = &apdu[apdu_len];
if (apdu_size > len) {
apdu_size -= len;
} else {
return 0;
}
}
} else {
return 0;
}
len = bacapp_decode_obj_property_ref(apdu_offset, apdu_size, &value);
len = bacapp_decode_obj_property_ref(
&apdu[apdu_len], apdu_size - apdu_len, &value);
if (len > 0) {
if (wp_data) {
wp_data->object_instance = value.object_identifier.instance;
@@ -591,22 +649,11 @@ int wpm_error_ack_decode_apdu(
wp_data->array_index = value.property_array_index;
}
apdu_len += len;
if (apdu) {
apdu_offset = &apdu[apdu_len];
if (apdu_size > len) {
apdu_size -= len;
} else {
return 0;
}
}
} else {
return 0;
}
if (apdu_size == 0) {
return 0;
}
if (decode_is_closing_tag_number(apdu_offset, 1)) {
len = 1;
if (bacnet_is_closing_tag_number(
&apdu[apdu_len], apdu_size - apdu_len, 1, &len)) {
apdu_len += len;
} else {
return 0;
+3
View File
@@ -70,6 +70,9 @@ int wpm_encode_apdu(
BACNET_STACK_EXPORT
int wpm_ack_encode_apdu_init(uint8_t *apdu, uint8_t invoke_id);
BACNET_STACK_EXPORT
int wpm_error_ack_service_encode(
uint8_t *apdu, const BACNET_WRITE_PROPERTY_DATA *wp_data);
BACNET_STACK_EXPORT
int wpm_error_ack_encode_apdu(
uint8_t *apdu,