Bugfix/service request refactor size check (#553)

* refactor service requests from service header

* add APDU size checking and length feature

* add unit tests to check for length when passing NULL buffer

---------

Co-authored-by: Steve Karg <skarg@users.sourceforge.net>
This commit is contained in:
Steve Karg
2024-01-05 08:59:45 -06:00
committed by GitHub
parent 5ca14e5320
commit bb081d28da
39 changed files with 2614 additions and 1514 deletions
+82 -21
View File
@@ -38,37 +38,98 @@
/** @file lso.c BACnet Life Safety Operation encode/decode */
/**
* @brief Encode APDU for LifeSafetyOperation-Request
* @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.
*/
int life_safety_operation_encode(uint8_t *apdu, BACNET_LSO_DATA *data)
{
int len = 0; /* length of each encoding */
int apdu_len = 0; /* total length of the apdu, return value */
if (!data) {
return 0;
}
/* tag 0 - requestingProcessId */
len = encode_context_unsigned(apdu, 0, data->processId);
apdu_len += len;
if (apdu) {
apdu += len;
}
/* tag 1 - requestingSource */
len = encode_context_character_string(
apdu, 1, &data->requestingSrc);
apdu_len += len;
if (apdu) {
apdu += len;
}
/* Operation */
len = encode_context_enumerated(apdu, 2, data->operation);
apdu_len += len;
if (apdu) {
apdu += len;
}
/* Object ID */
if (data->use_target) {
len = encode_context_object_id(apdu, 3,
data->targetObject.type, data->targetObject.instance);
apdu_len += len;
}
return apdu_len;
}
/**
* @brief Encode APDU for LifeSafetyOperation-Request
* @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.
*/
int lso_encode_apdu(uint8_t *apdu, uint8_t invoke_id, BACNET_LSO_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_CONFIRMED_SERVICE_REQUEST;
apdu[1] = encode_max_segs_max_apdu(0, MAX_APDU);
apdu[2] = invoke_id;
apdu[3] = SERVICE_CONFIRMED_LIFE_SAFETY_OPERATION;
apdu_len = 4;
/* tag 0 - requestingProcessId */
len = encode_context_unsigned(&apdu[apdu_len], 0, data->processId);
}
len = 4;
apdu_len += len;
if (apdu) {
apdu += len;
}
len = life_safety_operation_encode(apdu, data);
if (len > 0) {
apdu_len += len;
/* tag 1 - requestingSource */
len = encode_context_character_string(
&apdu[apdu_len], 1, &data->requestingSrc);
apdu_len += len;
/*
Operation
*/
len = encode_context_enumerated(&apdu[apdu_len], 2, data->operation);
apdu_len += len;
/*
Object ID
*/
if (data->use_target) {
len = encode_context_object_id(&apdu[apdu_len], 3,
data->targetObject.type, data->targetObject.instance);
apdu_len += len;
}
} else {
apdu_len = len;
}
return apdu_len;
}
/**
* @brief Encode the LifeSafetyOperation-Request
* @param apdu Pointer to the buffer for encoding into
* @param apdu_size number of bytes available in the buffer
* @param data Pointer to the service data used for encoding values
* @return number of bytes encoded, or zero if unable to encode or too large
*/
size_t life_safety_operation_request_encode(
uint8_t *apdu, size_t apdu_size, BACNET_LSO_DATA *data)
{
size_t apdu_len = 0;
apdu_len = life_safety_operation_encode(NULL, data);
if (apdu_len > apdu_size) {
apdu_len = 0;
} else {
apdu_len = life_safety_operation_encode(apdu, data);
}
return apdu_len;