Fixed GetEvent initialization of linked list (#1026)

* Fixed GetEvent usage of linked list by initializing next in all the examples and unit test.

* Secured GetEventInformation encoders by accepting NULL for APDU for determining the size, and exploit the NULL APDU for size checking during encoding. Secured the GetEventInformation decoders and removed the use of deprecated decoder API.
This commit is contained in:
Steve Karg
2025-06-20 13:34:39 -05:00
committed by GitHub
parent b0a97c6f75
commit 14f033ceda
7 changed files with 498 additions and 300 deletions
+4
View File
@@ -16,6 +16,8 @@ The git repositories are hosted at the following sites:
### Security
* Secured GetEventInformation-Request and -ACK decoder and encoder. (#1026)
### Added
* Added more writable properties to Analog, Binary, and Multistate Output
@@ -48,6 +50,8 @@ The git repositories are hosted at the following sites:
### Fixed
* Fixed GetEvent usage of linked list by initializing next in all
the examples and unit test. (#1026)
* Fixed usage of Keylist_Data_Add() return value in Calendar,
CharacterString Value, Load Control, and BACnet/SC Network Port
objects. (#1016)
+2 -6
View File
@@ -111,14 +111,10 @@ static void My_Get_Event_Ack_Handler(
BACNET_CONFIRMED_SERVICE_ACK_DATA *service_data)
{
int len = 0;
int i;
BACNET_GET_EVENT_INFORMATION_DATA data[MAX_OBJ_IDS_IN_GE_ACK];
BACNET_GET_EVENT_INFORMATION_DATA data[MAX_OBJ_IDS_IN_GE_ACK] = { 0 };
(void)src;
for (i = 0; i < MAX_OBJ_IDS_IN_GE_ACK - 1; i++) {
data[i].next = &data[i + 1];
}
getevent_information_link_array(&data[0], ARRAY_SIZE(data));
printf(
"Recieved Ack. Saved invoke ID was %i, service returned %i\n",
Request_Invoke_ID, service_data->invoke_id);
+1 -1
View File
@@ -96,7 +96,7 @@ void handler_get_event_information(
BACNET_ADDRESS my_address;
BACNET_OBJECT_ID object_id;
unsigned i = 0, j = 0; /* counter */
BACNET_GET_EVENT_INFORMATION_DATA getevent_data;
BACNET_GET_EVENT_INFORMATION_DATA getevent_data = { 0 };
int valid_event = 0;
/* initialize type of 'Last Received Object Identifier' using max value */
+5 -7
View File
@@ -42,20 +42,18 @@ void get_event_ack_handler(
BACNET_ADDRESS *src,
BACNET_CONFIRMED_SERVICE_ACK_DATA *service_data)
{
uint8_t i = 0;
uint16_t apdu_len = 0;
bool more_events = false;
/* initialize array big enough to accommodate
multiple get event data in APDU */
BACNET_GET_EVENT_INFORMATION_DATA get_event_data[MAX_NUMBER_OF_EVENTS];
BACNET_GET_EVENT_INFORMATION_DATA get_event_data[MAX_NUMBER_OF_EVENTS] = {
0
};
(void)src;
(void)service_data;
for (i = 1; i < MAX_NUMBER_OF_EVENTS; i++) {
/* Create linked list */
get_event_data[i - 1].next = &get_event_data[i];
}
getevent_information_link_array(
&get_event_data[0], ARRAY_SIZE(get_event_data));
apdu_len = getevent_ack_decode_service_request(
&service_request[0], service_len, &get_event_data[0], &more_events);
+415 -234
View File
@@ -14,6 +14,11 @@
/**
* @brief Encode APDU for GetEvent-Request service
*
* GetEventInformation-Request ::= SEQUENCE {
* last-received-object-identifier [0] BACnetObjectIdentifier OPTIONAL
* }
*
* @param apdu Pointer to a buffer, or NULL for length
* @param lastReceivedObjectIdentifier Object identifier
* @return Bytes encoded.
@@ -92,249 +97,425 @@ int getevent_encode_apdu(
/** Decode the service request only
*
* @param apdu APDU buffer to encode to.
* @param apdu_len Valid bytes in the buffer.
* @param apdu_size Valid bytes in the buffer.
* @param lastReceivedObjectIdentifier Object identifier
*
* @return Bytes encoded.
* @return number of bytes decoded, zero if tag mismatch,
* or #BACNET_STATUS_ERROR (-1) if malformed
*/
int getevent_decode_service_request(
const uint8_t *apdu,
unsigned apdu_len,
unsigned apdu_size,
BACNET_OBJECT_ID *lastReceivedObjectIdentifier)
{
unsigned len = 0;
int len = 0;
BACNET_OBJECT_TYPE *object_type = NULL;
uint32_t *object_instance = NULL;
/* check for value pointers */
if (apdu_len && lastReceivedObjectIdentifier) {
/* Tag 0: Object ID - optional */
if (!decode_is_context_tag(&apdu[len++], 0)) {
return -1;
}
if (len < apdu_len) {
len += decode_object_id(
&apdu[len], &lastReceivedObjectIdentifier->type,
&lastReceivedObjectIdentifier->instance);
}
}
return (int)len;
}
int getevent_ack_encode_apdu_init(
uint8_t *apdu, size_t max_apdu, uint8_t invoke_id)
{
int apdu_len = 0; /* total length of the apdu, return value */
if (apdu && (max_apdu >= 4)) {
apdu[0] = PDU_TYPE_COMPLEX_ACK; /* complex ACK service */
apdu[1] = invoke_id; /* original invoke id from request */
apdu[2] = SERVICE_CONFIRMED_GET_EVENT_INFORMATION;
apdu_len = 3;
/* service ack follows */
/* Tag 0: listOfEventSummaries */
apdu_len += encode_opening_tag(&apdu[apdu_len], 0);
}
return apdu_len;
}
int getevent_ack_encode_apdu_data(
uint8_t *apdu,
size_t max_apdu,
BACNET_GET_EVENT_INFORMATION_DATA *get_event_data)
{
int apdu_len = 0; /* total length of the apdu, return value */
BACNET_GET_EVENT_INFORMATION_DATA *event_data;
unsigned i = 0; /* counter */
(void)max_apdu;
if (apdu) {
event_data = get_event_data;
while (event_data) {
/* Tag 0: objectIdentifier */
apdu_len += encode_context_object_id(
&apdu[apdu_len], 0, event_data->objectIdentifier.type,
event_data->objectIdentifier.instance);
/* Tag 1: eventState */
apdu_len += encode_context_enumerated(
&apdu[apdu_len], 1, event_data->eventState);
/* Tag 2: acknowledgedTransitions */
apdu_len += encode_context_bitstring(
&apdu[apdu_len], 2, &event_data->acknowledgedTransitions);
/* Tag 3: eventTimeStamps */
apdu_len += encode_opening_tag(&apdu[apdu_len], 3);
for (i = 0; i < 3; i++) {
apdu_len += bacapp_encode_timestamp(
&apdu[apdu_len], &event_data->eventTimeStamps[i]);
}
apdu_len += encode_closing_tag(&apdu[apdu_len], 3);
/* Tag 4: notifyType */
apdu_len += encode_context_enumerated(
&apdu[apdu_len], 4, event_data->notifyType);
/* Tag 5: eventEnable */
apdu_len += encode_context_bitstring(
&apdu[apdu_len], 5, &event_data->eventEnable);
/* Tag 6: eventPriorities */
apdu_len += encode_opening_tag(&apdu[apdu_len], 6);
for (i = 0; i < 3; i++) {
apdu_len += encode_application_unsigned(
&apdu[apdu_len], event_data->eventPriorities[i]);
}
apdu_len += encode_closing_tag(&apdu[apdu_len], 6);
event_data = event_data->next;
}
}
return apdu_len;
}
int getevent_ack_encode_apdu_end(
uint8_t *apdu, size_t max_apdu, bool moreEvents)
{
int apdu_len = 0; /* total length of the apdu, return value */
(void)max_apdu;
if (apdu) {
apdu_len += encode_closing_tag(&apdu[apdu_len], 0);
apdu_len += encode_context_boolean(&apdu[apdu_len], 1, moreEvents);
}
return apdu_len;
}
int getevent_ack_decode_service_request(
const uint8_t *apdu,
int apdu_len, /* total length of the apdu */
BACNET_GET_EVENT_INFORMATION_DATA *get_event_data,
bool *moreEvents)
{
uint8_t tag_number = 0;
uint32_t len_value = 0;
int len = 0; /* total length of decodes */
uint32_t enum_value = 0; /* for decoding */
BACNET_UNSIGNED_INTEGER unsigned_value = 0;
BACNET_GET_EVENT_INFORMATION_DATA *event_data;
unsigned i = 0; /* counter */
/* FIXME: check apdu_len against the len during decode */
event_data = get_event_data;
if (apdu && apdu_len && event_data && moreEvents) {
if (!decode_is_opening_tag_number(&apdu[len], 0)) {
return -1;
}
len++;
while (event_data) {
/* Tag 0: objectIdentifier */
if (decode_is_context_tag(&apdu[len], 0)) {
len += decode_tag_number_and_value(
&apdu[len], &tag_number, &len_value);
len += decode_object_id(
&apdu[len], &event_data->objectIdentifier.type,
&event_data->objectIdentifier.instance);
} else {
return -1;
}
/* Tag 1: eventState */
if (decode_is_context_tag(&apdu[len], 1)) {
len += decode_tag_number_and_value(
&apdu[len], &tag_number, &len_value);
len += decode_enumerated(&apdu[len], len_value, &enum_value);
if (enum_value < EVENT_STATE_MAX) {
event_data->eventState = (BACNET_EVENT_STATE)enum_value;
} else {
return -1;
}
} else {
return -1;
}
/* Tag 2: acknowledgedTransitions */
if (decode_is_context_tag(&apdu[len], 2)) {
len += decode_tag_number_and_value(
&apdu[len], &tag_number, &len_value);
len += decode_bitstring(
&apdu[len], len_value,
&event_data->acknowledgedTransitions);
} else {
return -1;
}
/* Tag 3: eventTimeStamps */
if (decode_is_opening_tag_number(&apdu[len], 3)) {
len += decode_tag_number_and_value(
&apdu[len], &tag_number, &len_value);
for (i = 0; i < 3; i++) {
len += bacapp_decode_timestamp(
&apdu[len], &event_data->eventTimeStamps[i]);
}
} else {
return -1;
}
if (decode_is_closing_tag_number(&apdu[len], 3)) {
len += decode_tag_number_and_value(
&apdu[len], &tag_number, &len_value);
} else {
return -1;
}
/* Tag 4: notifyType */
if (decode_is_context_tag(&apdu[len], 4)) {
len += decode_tag_number_and_value(
&apdu[len], &tag_number, &len_value);
len += decode_enumerated(&apdu[len], len_value, &enum_value);
if (enum_value < NOTIFY_MAX) {
event_data->notifyType = (BACNET_NOTIFY_TYPE)enum_value;
} else {
return -1;
}
} else {
return -1;
}
/* Tag 5: eventEnable */
if (decode_is_context_tag(&apdu[len], 5)) {
len += decode_tag_number_and_value(
&apdu[len], &tag_number, &len_value);
len += decode_bitstring(
&apdu[len], len_value, &event_data->eventEnable);
} else {
return -1;
}
/* Tag 6: eventPriorities */
if (decode_is_opening_tag_number(&apdu[len], 6)) {
len += decode_tag_number_and_value(
&apdu[len], &tag_number, &len_value);
for (i = 0; i < 3; i++) {
len += decode_tag_number_and_value(
&apdu[len], &tag_number, &len_value);
len +=
decode_unsigned(&apdu[len], len_value, &unsigned_value);
event_data->eventPriorities[i] = (uint32_t)unsigned_value;
}
} else {
return -1;
}
if (decode_is_closing_tag_number(&apdu[len], 6)) {
len += decode_tag_number_and_value(
&apdu[len], &tag_number, &len_value);
} else {
return -1;
}
if (decode_is_closing_tag_number(&apdu[len], 0)) {
len += decode_tag_number_and_value(
&apdu[len], &tag_number, &len_value);
event_data->next = NULL;
}
event_data = event_data->next;
}
if (decode_is_context_tag(&apdu[len], 1)) {
len += decode_tag_number_and_value(
&apdu[len], &tag_number, &len_value);
if (len_value == 1) {
*moreEvents = decode_context_boolean(&apdu[len++]);
} else {
*moreEvents = false;
}
} else {
return -1;
}
if (lastReceivedObjectIdentifier) {
object_type = &lastReceivedObjectIdentifier->type;
object_instance = &lastReceivedObjectIdentifier->instance;
}
len = bacnet_object_id_context_decode(
apdu, apdu_size, 0, object_type, object_instance);
return len;
}
/**
* @brief Encode the GetEventInformation-ACK service
* @param apdu Pointer to the buffer for encoding into
* @param max_apdu Maximum number of bytes available in the buffer
* @param invoke_id Invoke ID
* @return number of bytes encoded, or zero if unable to encode or too large
*/
int getevent_ack_encode_apdu_init(
uint8_t *apdu, size_t max_apdu, uint8_t invoke_id)
{
int len = 0; /* length of each encoding */
int apdu_len = 0; /* total length of the apdu, return value */
if (apdu && (max_apdu >= 3)) {
apdu[0] = PDU_TYPE_COMPLEX_ACK; /* complex ACK service */
apdu[1] = invoke_id; /* original invoke id from request */
apdu[2] = SERVICE_CONFIRMED_GET_EVENT_INFORMATION;
}
len = 3; /* length of the header */
apdu_len += len;
if (apdu) {
apdu += len;
}
/* service ack follows */
/* Tag 0: listOfEventSummaries */
len = encode_opening_tag(apdu, 0);
apdu_len += len;
return apdu_len;
}
/**
* @brief Encode one or more GetEventInformation-ACK service data
*
* GetEventInformation-ACK ::= SEQUENCE {
* list-of-event-summaries [0] SEQUENCE OF SEQUENCE {
* object-identifier[0] BACnetObjectIdentifier,
* event-state[1] BACnetEventState,
* acknowledged-transitions[2] BACnetEventTransitionBits,
* event-timestamps[3] SEQUENCE SIZE (3) OF BACnetTimeStamp,
* notify-type[4] BACnetNotifyType,
* event-enable[5] BACnetEventTransitionBits,
* event-priorities[6] SEQUENCE SIZE (3) OF Unsigned
* },
* more-events [1] Boolean
* }
*
* @param apdu Pointer to the buffer for encoding into
* @param head Pointer to the head of service data used for encoding values
* @return number of bytes encoded
*/
int getevent_information_ack_encode(
uint8_t *apdu, BACNET_GET_EVENT_INFORMATION_DATA *head)
{
int len = 0, apdu_len = 0;
BACNET_GET_EVENT_INFORMATION_DATA *data;
unsigned i = 0; /* counter */
data = head;
while (data) {
/* Tag 0: objectIdentifier */
len = encode_context_object_id(
apdu, 0, data->objectIdentifier.type,
data->objectIdentifier.instance);
apdu_len += len;
if (apdu) {
apdu += len;
}
/* Tag 1: eventState */
len = encode_context_enumerated(apdu, 1, data->eventState);
apdu_len += len;
if (apdu) {
apdu += len;
}
/* Tag 2: acknowledgedTransitions */
len = encode_context_bitstring(apdu, 2, &data->acknowledgedTransitions);
apdu_len += len;
if (apdu) {
apdu += len;
}
/* Tag 3: eventTimeStamps */
len = encode_opening_tag(apdu, 3);
apdu_len += len;
if (apdu) {
apdu += len;
}
for (i = 0; i < 3; i++) {
len = bacapp_encode_timestamp(apdu, &data->eventTimeStamps[i]);
apdu_len += len;
if (apdu) {
apdu += len;
}
}
len = encode_closing_tag(apdu, 3);
apdu_len += len;
if (apdu) {
apdu += len;
}
/* Tag 4: notifyType */
len = encode_context_enumerated(apdu, 4, data->notifyType);
apdu_len += len;
if (apdu) {
apdu += len;
}
/* Tag 5: eventEnable */
len = encode_context_bitstring(apdu, 5, &data->eventEnable);
apdu_len += len;
if (apdu) {
apdu += len;
}
/* Tag 6: eventPriorities */
len = encode_opening_tag(apdu, 6);
apdu_len += len;
if (apdu) {
apdu += len;
}
for (i = 0; i < 3; i++) {
len = encode_application_unsigned(apdu, data->eventPriorities[i]);
apdu_len += len;
if (apdu) {
apdu += len;
}
}
len = encode_closing_tag(apdu, 6);
apdu_len += len;
if (apdu) {
apdu += len;
}
data = data->next;
}
return apdu_len;
}
/**
* @brief Encode the GetEventInformation-ACK service data
* @param apdu Pointer to the buffer for encoding into
* @param apdu_size Maximum number of bytes available in the buffer
* @param get_event_data Pointer to the service data used for encoding values
* @return number of bytes encoded, or zero if unable to encode or too large
*/
int getevent_ack_encode_apdu_data(
uint8_t *apdu, size_t apdu_size, BACNET_GET_EVENT_INFORMATION_DATA *data)
{
size_t apdu_len = 0; /* total length of the apdu, return value */
apdu_len = getevent_information_ack_encode(NULL, data);
if (apdu_len > apdu_size) {
apdu_len = 0;
} else {
apdu_len = getevent_information_ack_encode(apdu, data);
}
return apdu_len;
}
/**
* @brief Encode the end of the GetEventInformation-ACK service
* @param apdu Pointer to the buffer for encoding into, or NULL for length
* @param moreEvents More events flag
* @return number of bytes encoded
*/
int getevent_information_ack_end_encode(uint8_t *apdu, bool moreEvents)
{
int len = 0, apdu_len = 0;
len = encode_closing_tag(apdu, 0);
apdu_len += len;
if (apdu) {
apdu += len;
}
len = encode_context_boolean(apdu, 1, moreEvents);
apdu_len += len;
return apdu_len;
}
/**
* @brief Encode the end of the GetEventInformation-ACK service
* @param apdu Pointer to the buffer for encoding into
* @param max_apdu Maximum number of bytes available in the buffer
* @param moreEvents More events flag
* @return number of bytes encoded, or zero if unable to encode or too large
*/
int getevent_ack_encode_apdu_end(
uint8_t *apdu, size_t apdu_size, bool moreEvents)
{
size_t apdu_len = 0; /* total length of the apdu, return value */
apdu_len = getevent_information_ack_end_encode(NULL, moreEvents);
if (apdu_len > apdu_size) {
apdu_len = 0;
} else {
apdu_len = getevent_information_ack_end_encode(apdu, moreEvents);
}
return apdu_len;
}
/**
* @brief Decode the GetEventInformation-ACK service
* @param apdu Pointer to the buffer for decoding from
* @param apdu_size Total length of the APDU
* @param invoke_id Invoke ID
* @param get_event_data Pointer to one or more service data used for
* decoding values
* @param moreEvents More events flag
* @return number of bytes decoded, or BACNET_STATUS_ERROR on error
*/
int getevent_ack_decode_service_request(
const uint8_t *apdu,
int apdu_size,
BACNET_GET_EVENT_INFORMATION_DATA *get_event_data,
bool *moreEvents)
{
int len = 0, apdu_len = 0;
uint32_t enum_value = 0; /* for decoding */
BACNET_UNSIGNED_INTEGER unsigned_value = 0;
BACNET_OBJECT_TYPE *object_type;
uint32_t *object_instance;
BACNET_BIT_STRING *bitstring_value;
BACNET_TIMESTAMP *timestamp_value;
BACNET_GET_EVENT_INFORMATION_DATA *data;
unsigned i = 0; /* counter */
if (!apdu) {
return BACNET_STATUS_ERROR;
}
if (apdu_size == 0) {
return BACNET_STATUS_ERROR;
}
if (!bacnet_is_opening_tag_number(apdu, apdu_size - apdu_len, 0, &len)) {
return BACNET_STATUS_ERROR;
}
apdu_len += len;
data = get_event_data;
while (apdu_len < apdu_size) {
if (data) {
object_type = &data->objectIdentifier.type;
object_instance = &data->objectIdentifier.instance;
} else {
object_type = NULL;
object_instance = NULL;
}
/* Tag 0: objectIdentifier */
len = bacnet_object_id_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 0, object_type,
object_instance);
if (len <= 0) {
return BACNET_STATUS_ERROR;
}
apdu_len += len;
/* Tag 1: eventState */
len = bacnet_enumerated_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 1, &enum_value);
if (len > 0) {
if (data) {
if (enum_value < EVENT_STATE_MAX) {
data->eventState = (BACNET_EVENT_STATE)enum_value;
} else {
return BACNET_STATUS_ERROR;
}
}
} else {
return BACNET_STATUS_ERROR;
}
apdu_len += len;
/* Tag 2: acknowledgedTransitions */
if (data) {
bitstring_value = &data->acknowledgedTransitions;
} else {
bitstring_value = NULL;
}
len = bacnet_bitstring_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 2, bitstring_value);
if (len <= 0) {
return BACNET_STATUS_ERROR;
}
apdu_len += len;
/* Tag 3: eventTimeStamps */
if (!bacnet_is_opening_tag_number(
&apdu[apdu_len], apdu_size - apdu_len, 3, &len)) {
return BACNET_STATUS_ERROR;
}
apdu_len += len;
for (i = 0; i < 3; i++) {
if (data) {
timestamp_value = &data->eventTimeStamps[i];
} else {
timestamp_value = NULL;
}
len = bacnet_timestamp_decode(
&apdu[apdu_len], apdu_size - apdu_len, timestamp_value);
if (len <= 0) {
return BACNET_STATUS_ERROR;
}
apdu_len += len;
}
if (!bacnet_is_closing_tag_number(
&apdu[apdu_len], apdu_size - apdu_len, 3, &len)) {
return BACNET_STATUS_ERROR;
}
apdu_len += len;
/* Tag 4: notifyType */
len = bacnet_enumerated_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 4, &enum_value);
if (len > 0) {
if (enum_value < NOTIFY_MAX) {
if (data) {
data->notifyType = (BACNET_NOTIFY_TYPE)enum_value;
}
} else {
return BACNET_STATUS_ERROR;
}
} else {
return BACNET_STATUS_ERROR;
}
apdu_len += len;
/* Tag 5: eventEnable */
if (data) {
bitstring_value = &data->eventEnable;
} else {
bitstring_value = NULL;
}
len = bacnet_bitstring_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 5, bitstring_value);
if (len <= 0) {
return BACNET_STATUS_ERROR;
}
apdu_len += len;
/* Tag 6: eventPriorities */
if (!bacnet_is_opening_tag_number(
&apdu[apdu_len], apdu_size - apdu_len, 6, &len)) {
return BACNET_STATUS_ERROR;
}
apdu_len += len;
for (i = 0; i < 3; i++) {
len = bacnet_unsigned_application_decode(
&apdu[apdu_len], apdu_size - apdu_len, &unsigned_value);
if (len > 0) {
if (unsigned_value <= UINT32_MAX) {
if (data) {
data->eventPriorities[i] = (uint32_t)unsigned_value;
}
} else {
return BACNET_STATUS_ERROR;
}
} else {
return BACNET_STATUS_ERROR;
}
apdu_len += len;
}
if (!bacnet_is_closing_tag_number(
&apdu[apdu_len], apdu_size - apdu_len, 6, &len)) {
return BACNET_STATUS_ERROR;
}
apdu_len += len;
if (bacnet_is_closing_tag_number(
&apdu[apdu_len], apdu_size - apdu_len, 0, &len)) {
if (data) {
data->next = NULL; /* mark end of the list */
}
apdu_len += len;
break;
}
if (data) {
data = data->next;
}
}
/* Tag 1: moreEvents */
len = bacnet_boolean_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 1, moreEvents);
if (len <= 0) {
return BACNET_STATUS_ERROR; /* malformed */
}
apdu_len += len;
return apdu_len;
}
/**
* @brief Convert an array of GetEventInformation-Request to linked list
* @param array pointer to element zero of the array
* @param size number of elements in the array
*/
void getevent_information_link_array(
BACNET_GET_EVENT_INFORMATION_DATA *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;
}
}
+16 -5
View File
@@ -55,29 +55,40 @@ size_t getevent_service_request_encode(
BACNET_STACK_EXPORT
int getevent_decode_service_request(
const uint8_t *apdu, unsigned apdu_len, BACNET_OBJECT_ID *object_id);
const uint8_t *apdu, unsigned apdu_size, BACNET_OBJECT_ID *object_id);
BACNET_STACK_EXPORT
int getevent_ack_encode_apdu_init(
uint8_t *apdu, size_t max_apdu, uint8_t invoke_id);
uint8_t *apdu, size_t apdu_size, uint8_t invoke_id);
BACNET_STACK_EXPORT
int getevent_information_ack_encode(
uint8_t *apdu, BACNET_GET_EVENT_INFORMATION_DATA *head);
BACNET_STACK_EXPORT
int getevent_ack_encode_apdu_data(
uint8_t *apdu,
size_t max_apdu,
size_t apdu_size,
BACNET_GET_EVENT_INFORMATION_DATA *get_event_data);
BACNET_STACK_EXPORT
int getevent_information_ack_end_encode(uint8_t *apdu, bool moreEvents);
BACNET_STACK_EXPORT
int getevent_ack_encode_apdu_end(
uint8_t *apdu, size_t max_apdu, bool moreEvents);
uint8_t *apdu, size_t apdu_size, bool moreEvents);
BACNET_STACK_EXPORT
int getevent_ack_decode_service_request(
const uint8_t *apdu,
int apdu_len, /* total length of the apdu */
int apdu_size,
BACNET_GET_EVENT_INFORMATION_DATA *get_event_data,
bool *moreEvents);
BACNET_STACK_EXPORT
void getevent_information_link_array(
BACNET_GET_EVENT_INFORMATION_DATA *array, size_t size);
#ifdef __cplusplus
}
#endif /* __cplusplus */
+55 -47
View File
@@ -64,27 +64,25 @@ static int getevent_ack_decode_apdu(
BACNET_GET_EVENT_INFORMATION_DATA *get_event_data,
bool *moreEvents)
{
int len = 0;
int offset = 0;
if (!apdu) {
return -1;
return BACNET_STATUS_ERROR;
}
if (apdu_len < 3) {
return BACNET_STATUS_ERROR; /* too short */
}
/* optional checking - most likely was already done prior to this call */
if (apdu[0] != PDU_TYPE_COMPLEX_ACK) {
return -1;
return BACNET_STATUS_ERROR;
}
if (invoke_id) {
*invoke_id = apdu[1];
}
*invoke_id = apdu[1];
if (apdu[2] != SERVICE_CONFIRMED_GET_EVENT_INFORMATION) {
return -1;
}
offset = 3;
if (apdu_len > offset) {
len = getevent_ack_decode_service_request(
&apdu[offset], apdu_len - offset, get_event_data, moreEvents);
return BACNET_STATUS_ERROR;
}
return len;
return getevent_ack_decode_service_request(
&apdu[3], apdu_len - 3, get_event_data, moreEvents);
}
#if defined(CONFIG_ZTEST_NEW_API)
@@ -94,46 +92,48 @@ static void testGetEventInformationAck(void)
#endif
{
uint8_t apdu[480] = { 0 };
int len = 0;
int apdu_len = 0;
int len = 0, apdu_len = 0, null_len = 0;
uint8_t invoke_id = 1;
uint8_t test_invoke_id = 0;
BACNET_GET_EVENT_INFORMATION_DATA event_data;
BACNET_GET_EVENT_INFORMATION_DATA test_event_data;
BACNET_GET_EVENT_INFORMATION_DATA event_data[1] = { 0 };
BACNET_GET_EVENT_INFORMATION_DATA test_event_data[1] = { 0 };
bool moreEvents = false;
bool test_moreEvents = false;
unsigned i = 0;
event_data.objectIdentifier.type = OBJECT_BINARY_INPUT;
event_data.objectIdentifier.instance = 1;
event_data.eventState = EVENT_STATE_NORMAL;
bitstring_init(&event_data.acknowledgedTransitions);
bitstring_set_bit(
&event_data.acknowledgedTransitions, TRANSITION_TO_OFFNORMAL, false);
bitstring_set_bit(
&event_data.acknowledgedTransitions, TRANSITION_TO_FAULT, false);
bitstring_set_bit(
&event_data.acknowledgedTransitions, TRANSITION_TO_NORMAL, false);
for (i = 0; i < 3; i++) {
event_data.eventTimeStamps[i].tag = TIME_STAMP_SEQUENCE;
event_data.eventTimeStamps[i].value.sequenceNum = 0;
}
event_data.notifyType = NOTIFY_ALARM;
bitstring_init(&event_data.eventEnable);
bitstring_set_bit(&event_data.eventEnable, TRANSITION_TO_OFFNORMAL, true);
bitstring_set_bit(&event_data.eventEnable, TRANSITION_TO_FAULT, true);
bitstring_set_bit(&event_data.eventEnable, TRANSITION_TO_NORMAL, true);
for (i = 0; i < 3; i++) {
event_data.eventPriorities[i] = 1;
}
event_data.next = NULL;
getevent_information_link_array(
&test_event_data[0], ARRAY_SIZE(test_event_data));
getevent_information_link_array(&event_data[0], ARRAY_SIZE(event_data));
event_data[0].objectIdentifier.type = OBJECT_BINARY_INPUT;
event_data[0].objectIdentifier.instance = 1;
event_data[0].eventState = EVENT_STATE_NORMAL;
bitstring_init(&event_data[0].acknowledgedTransitions);
bitstring_set_bit(
&event_data[0].acknowledgedTransitions, TRANSITION_TO_OFFNORMAL, false);
bitstring_set_bit(
&event_data[0].acknowledgedTransitions, TRANSITION_TO_FAULT, false);
bitstring_set_bit(
&event_data[0].acknowledgedTransitions, TRANSITION_TO_NORMAL, false);
for (i = 0; i < 3; i++) {
event_data[0].eventTimeStamps[i].tag = TIME_STAMP_SEQUENCE;
event_data[0].eventTimeStamps[i].value.sequenceNum = 0;
}
event_data[0].notifyType = NOTIFY_ALARM;
bitstring_init(&event_data[0].eventEnable);
bitstring_set_bit(
&event_data[0].eventEnable, TRANSITION_TO_OFFNORMAL, true);
bitstring_set_bit(&event_data[0].eventEnable, TRANSITION_TO_FAULT, true);
bitstring_set_bit(&event_data[0].eventEnable, TRANSITION_TO_NORMAL, true);
for (i = 0; i < 3; i++) {
event_data[0].eventPriorities[i] = 1;
}
len = getevent_ack_encode_apdu_init(&apdu[0], sizeof(apdu), invoke_id);
zassert_not_equal(len, 0, NULL);
zassert_not_equal(len, -1, NULL);
apdu_len = len;
len = getevent_ack_encode_apdu_data(
&apdu[apdu_len], sizeof(apdu) - apdu_len, &event_data);
&apdu[apdu_len], sizeof(apdu) - apdu_len, &event_data[0]);
zassert_not_equal(len, 0, NULL);
zassert_not_equal(len, -1, NULL);
apdu_len += len;
@@ -142,20 +142,28 @@ static void testGetEventInformationAck(void)
zassert_not_equal(len, 0, NULL);
zassert_not_equal(len, -1, NULL);
apdu_len += len;
null_len = getevent_ack_decode_apdu(&apdu[0], apdu_len, NULL, NULL, NULL);
len = getevent_ack_decode_apdu(
&apdu[0], apdu_len, /* total length of the apdu */
&test_invoke_id, &test_event_data, &test_moreEvents);
&test_invoke_id, &test_event_data[0], &test_moreEvents);
zassert_equal(null_len, len, "null_len=%d len=%d", null_len, len);
zassert_not_equal(len, -1, NULL);
zassert_equal(test_invoke_id, invoke_id, NULL);
zassert_equal(
event_data.objectIdentifier.type, test_event_data.objectIdentifier.type,
NULL);
event_data[0].objectIdentifier.type,
test_event_data[0].objectIdentifier.type, NULL);
zassert_equal(
event_data.objectIdentifier.instance,
test_event_data.objectIdentifier.instance, NULL);
event_data[0].objectIdentifier.instance,
test_event_data[0].objectIdentifier.instance, NULL);
zassert_equal(event_data.eventState, test_event_data.eventState, NULL);
zassert_equal(
event_data[0].eventState, test_event_data[0].eventState, NULL);
while (apdu_len) {
apdu_len--;
len = getevent_ack_decode_apdu(&apdu[0], apdu_len, NULL, NULL, NULL);
zassert_equal(len, BACNET_STATUS_ERROR, NULL);
}
}
#if defined(CONFIG_ZTEST_NEW_API)