Secured I-Am request encoding and decoding, and updated the example apps and handlers to use secure version of I-Am decoder. (#1080)

This commit is contained in:
Steve Karg
2025-08-19 21:31:50 -05:00
committed by GitHub
parent 743c5845b3
commit 25c2aaa20d
9 changed files with 285 additions and 106 deletions
+3 -3
View File
@@ -156,9 +156,9 @@ static void My_I_Am_Bind(
bool found = false;
bool bind = false;
(void)service_len;
len = iam_decode_service_request(
service_request, &device_id, &max_apdu, &segmentation, &vendor_id);
len = bacnet_iam_request_decode(
service_request, service_len, &device_id, &max_apdu, &segmentation,
&vendor_id);
if (len > 0) {
found = address_bind_request(device_id, NULL, NULL);
if (!found) {
+6 -6
View File
@@ -33,9 +33,9 @@ void handler_i_am_add(
int segmentation = 0;
uint16_t vendor_id = 0;
(void)service_len;
len = iam_decode_service_request(
service_request, &device_id, &max_apdu, &segmentation, &vendor_id);
len = bacnet_iam_request_decode(
service_request, service_len, &device_id, &max_apdu, &segmentation,
&vendor_id);
#if PRINT_ENABLED
fprintf(stderr, "Received I-Am Request");
#endif
@@ -73,9 +73,9 @@ void handler_i_am_bind(
int segmentation = 0;
uint16_t vendor_id = 0;
(void)service_len;
len = iam_decode_service_request(
service_request, &device_id, &max_apdu, &segmentation, &vendor_id);
len = bacnet_iam_request_decode(
service_request, service_len, &device_id, &max_apdu, &segmentation,
&vendor_id);
if (len > 0) {
/* only add address if requested to bind */
address_add_binding(device_id, max_apdu, src);
+159 -76
View File
@@ -14,6 +14,75 @@
#include "bacnet/bacdcode.h"
#include "bacnet/iam.h"
/**
* @brief Encode the I-Am Request.
* @param apdu Transmit buffer
* @param device_id Device Id
* @param max_apdu Transmit buffer size.
* @param segmentation True, if segmentation shall be featured.
* @param vendor_id Vendor Id
* @return Total length of the apdu, zero otherwise.
*/
int bacnet_iam_request_encode(
uint8_t *apdu,
uint32_t device_id,
unsigned max_apdu,
int segmentation,
uint16_t vendor_id)
{
int len; /* length of each encoding */
int apdu_len = 0; /* total length of the apdu, return value */
len = encode_application_object_id(apdu, OBJECT_DEVICE, device_id);
apdu_len += len;
if (apdu) {
apdu += len;
}
len = encode_application_unsigned(apdu, max_apdu);
apdu_len += len;
if (apdu) {
apdu += len;
}
len = encode_application_enumerated(apdu, (uint32_t)segmentation);
apdu_len += len;
if (apdu) {
apdu += len;
}
len = encode_application_unsigned(apdu, vendor_id);
apdu_len += len;
return apdu_len;
}
/**
* @brief Encode the WriteGroup service 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 bacnet_iam_service_request_encode(
uint8_t *apdu,
size_t apdu_size,
uint32_t device_id,
unsigned max_apdu,
int segmentation,
uint16_t vendor_id)
{
size_t apdu_len = 0; /* total length of the apdu, return value */
apdu_len = bacnet_iam_request_encode(
NULL, device_id, max_apdu, segmentation, vendor_id);
if (apdu_len > apdu_size) {
apdu_len = 0;
} else {
apdu_len = bacnet_iam_request_encode(
apdu, device_id, max_apdu, segmentation, vendor_id);
}
return apdu_len;
}
/**
* @brief Encode the I-Am service.
*
@@ -38,17 +107,94 @@ int iam_encode_apdu(
if (apdu) {
apdu[0] = PDU_TYPE_UNCONFIRMED_SERVICE_REQUEST;
apdu[1] = SERVICE_UNCONFIRMED_I_AM; /* service choice */
apdu_len = 2;
len = encode_application_object_id(
&apdu[apdu_len], OBJECT_DEVICE, device_id);
apdu_len += len;
len = encode_application_unsigned(&apdu[apdu_len], max_apdu);
apdu_len += len;
len = encode_application_enumerated(
&apdu[apdu_len], (uint32_t)segmentation);
apdu_len += len;
len = encode_application_unsigned(&apdu[apdu_len], vendor_id);
apdu_len += len;
}
len = 2;
apdu_len += len;
if (apdu) {
apdu += len;
}
len = bacnet_iam_request_encode(
apdu, device_id, max_apdu, segmentation, vendor_id);
apdu_len += len;
return apdu_len;
}
/**
* @brief Decode the I-Am-Request.
* @ingroup BIBB-DM-DOB
* @param apdu [in] Buffer containing the APDU
* @param apdu_size [in] The length of the APDU
* @param pDevice_id Pointer to the variable that shall take the device Id.
* @param pMax_apdu Pointer to a variable that shall take the decoded length.
* @param pSegmentation Pointer to a variable taking if segmentation is used.
* @param pVendor_id Pointer to a variable taking the vendor id.
* @return The number of bytes decoded , or #BACNET_STATUS_ERROR on error
*/
int bacnet_iam_request_decode(
const uint8_t *apdu,
unsigned apdu_size,
uint32_t *pDevice_id,
unsigned *pMax_apdu,
int *pSegmentation,
uint16_t *pVendor_id)
{
int len = 0;
int apdu_len = 0; /* total length of the apdu, return value */
/* should be a Device Object */
BACNET_OBJECT_TYPE object_type = OBJECT_NONE;
uint32_t object_instance = 0;
uint32_t enum_value = 0;
BACNET_UNSIGNED_INTEGER unsigned_value = 0;
/* OBJECT ID - object id */
len = bacnet_object_id_application_decode(
&apdu[apdu_len], apdu_size - apdu_len, &object_type, &object_instance);
if (len <= 0) {
return BACNET_STATUS_ERROR;
}
apdu_len += len;
if (object_type != OBJECT_DEVICE) {
return BACNET_STATUS_ERROR;
}
if (pDevice_id) {
*pDevice_id = object_instance;
}
/* MAX APDU - unsigned */
len = bacnet_unsigned_application_decode(
&apdu[apdu_len], apdu_size - apdu_len, &unsigned_value);
if (len <= 0) {
return BACNET_STATUS_ERROR;
}
apdu_len += len;
if (pMax_apdu) {
*pMax_apdu = (unsigned)unsigned_value;
}
/* Segmentation - enumerated */
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 (enum_value >= MAX_BACNET_SEGMENTATION) {
return BACNET_STATUS_ERROR;
}
if (pSegmentation) {
*pSegmentation = (int)enum_value;
}
/* Vendor ID - unsigned16 */
len = bacnet_unsigned_application_decode(
&apdu[apdu_len], apdu_size - apdu_len, &unsigned_value);
if (len <= 0) {
return BACNET_STATUS_ERROR;
}
apdu_len += len;
if (unsigned_value > 0xFFFF) {
return BACNET_STATUS_ERROR;
}
if (pVendor_id) {
*pVendor_id = (uint16_t)unsigned_value;
}
return apdu_len;
@@ -72,69 +218,6 @@ int iam_decode_service_request(
int *pSegmentation,
uint16_t *pVendor_id)
{
int len = 0;
int apdu_len = 0; /* total length of the apdu, return value */
/* should be a Device Object */
BACNET_OBJECT_TYPE object_type = OBJECT_NONE;
uint32_t object_instance = 0;
uint8_t tag_number = 0;
uint32_t len_value = 0;
uint32_t enum_value = 0;
BACNET_UNSIGNED_INTEGER unsigned_value = 0;
/* OBJECT ID - object id */
len = decode_tag_number_and_value(&apdu[apdu_len], &tag_number, &len_value);
apdu_len += len;
if (tag_number != BACNET_APPLICATION_TAG_OBJECT_ID) {
return -1;
}
len = decode_object_id(&apdu[apdu_len], &object_type, &object_instance);
apdu_len += len;
if (object_type != OBJECT_DEVICE) {
return -1;
}
if (pDevice_id) {
*pDevice_id = object_instance;
}
/* MAX APDU - unsigned */
len = decode_tag_number_and_value(&apdu[apdu_len], &tag_number, &len_value);
apdu_len += len;
if (tag_number != BACNET_APPLICATION_TAG_UNSIGNED_INT) {
return -1;
}
len = decode_unsigned(&apdu[apdu_len], len_value, &unsigned_value);
apdu_len += len;
if (pMax_apdu) {
*pMax_apdu = (unsigned)unsigned_value;
}
/* Segmentation - enumerated */
len = decode_tag_number_and_value(&apdu[apdu_len], &tag_number, &len_value);
apdu_len += len;
if (tag_number != BACNET_APPLICATION_TAG_ENUMERATED) {
return -1;
}
len = decode_enumerated(&apdu[apdu_len], len_value, &enum_value);
apdu_len += len;
if (enum_value >= MAX_BACNET_SEGMENTATION) {
return -1;
}
if (pSegmentation) {
*pSegmentation = (int)enum_value;
}
/* Vendor ID - unsigned16 */
len = decode_tag_number_and_value(&apdu[apdu_len], &tag_number, &len_value);
apdu_len += len;
if (tag_number != BACNET_APPLICATION_TAG_UNSIGNED_INT) {
return -1;
}
len = decode_unsigned(&apdu[apdu_len], len_value, &unsigned_value);
apdu_len += len;
if (unsigned_value > 0xFFFF) {
return -1;
}
if (pVendor_id) {
*pVendor_id = (uint16_t)unsigned_value;
}
return apdu_len;
return bacnet_iam_request_decode(
apdu, MAX_APDU, pDevice_id, pMax_apdu, pSegmentation, pVendor_id);
}
+26
View File
@@ -36,6 +36,32 @@ int iam_decode_service_request(
int *pSegmentation,
uint16_t *pVendor_id);
BACNET_STACK_EXPORT
int bacnet_iam_request_decode(
const uint8_t *apdu,
unsigned apdu_size,
uint32_t *pDevice_id,
unsigned *pMax_apdu,
int *pSegmentation,
uint16_t *pVendor_id);
BACNET_STACK_EXPORT
int bacnet_iam_request_encode(
uint8_t *apdu,
uint32_t device_id,
unsigned max_apdu,
int segmentation,
uint16_t vendor_id);
BACNET_STACK_EXPORT
size_t bacnet_iam_service_request_encode(
uint8_t *apdu,
size_t apdu_size,
uint32_t device_id,
unsigned max_apdu,
int segmentation,
uint16_t vendor_id);
#ifdef __cplusplus
}
#endif /* __cplusplus */