Refactor/mstp zero config state machine (#676)

* Changed MS/TP master node self destination checks to be located in receive FSM

* Changed MSTP zero configuration: modified comments for state transition names; modified next station increment; refactored the UUID rand() to not be required by common zero config implementation; added more unit tests.

* Added another context to MS/TP user data to allow additional user data
This commit is contained in:
Steve Karg
2024-06-26 07:43:25 -05:00
committed by GitHub
parent 9e0751f8c9
commit ddb2b43125
16 changed files with 313 additions and 126 deletions
+73 -1
View File
@@ -81,6 +81,7 @@ static uint32_t Database_Revision;
static BACNET_REINITIALIZED_STATE Reinitialize_State = BACNET_REINIT_IDLE;
static const char *Reinit_Password = "stm32f4xx";
static const char *BACnet_Version = BACNET_VERSION_TEXT;
static uint8_t Device_UUID[16];
/* These three arrays are used by the ReadPropertyMultiple handler */
static const int Device_Properties_Required[] = { PROP_OBJECT_IDENTIFIER,
@@ -94,7 +95,8 @@ static const int Device_Properties_Required[] = { PROP_OBJECT_IDENTIFIER,
PROP_DATABASE_REVISION, -1 };
static const int Device_Properties_Optional[] = { PROP_DESCRIPTION,
PROP_LOCATION, PROP_MAX_MASTER, PROP_MAX_INFO_FRAMES, -1 };
PROP_LOCATION, PROP_MAX_MASTER, PROP_MAX_INFO_FRAMES, PROP_DEVICE_UUID,
-1 };
static const int Device_Properties_Proprietary[] = { -1 };
@@ -398,6 +400,71 @@ void Device_Inc_Database_Revision(void)
Database_Revision++;
}
/**
* @brief Initialize a UUID for storing the unique identifier of this device
* @note A Universally Unique IDentifier (UUID) - also called a
* Global Unique IDentifier (GUID) - is a 128-bit value, see RFC 4122.
*
* 4.4. Algorithms for Creating a UUID from Truly Random or
* Pseudo-Random Numbers
*
* The version 4 UUID is meant for generating UUIDs from truly-random or
* pseudo-random numbers.
*
* The algorithm is as follows:
*
* o Set the two most significant bits (bits 6 and 7) of the
* clock_seq_hi_and_reserved to zero and one, respectively.
*
* o Set the four most significant bits (bits 12 through 15) of the
* time_hi_and_version field to the 4-bit version number from
* Section 4.1.3.
*
* o Set all the other bits to randomly (or pseudo-randomly) chosen
* values.
*/
void Device_UUID_Init(void)
{
unsigned i = 0;
/* 1. Generate 16 random bytes = 128 bits */
for (i = 0; i < sizeof(Device_UUID); i++) {
Device_UUID[i] = rand() % 255;
}
/* 2. Adjust certain bits according to RFC 4122 section 4.4.
This just means do the following
(a) set the high nibble of the 7th byte equal to 4 and
(b) set the two most significant bits of the 9th byte to 10'B,
so the high nibble will be one of {8,9,A,B}.
From http://www.cryptosys.net/pki/Uuid.c.html */
Device_UUID[6] = 0x40 | (Device_UUID[6] & 0x0f);
Device_UUID[8] = 0x80 | (Device_UUID[8] & 0x3f);
}
/**
* @brief Set the UUID for this device
* @param new_uuid [in] The new UUID to set
* @param length [in] The length of the new UUID
*/
void Device_UUID_Set(uint8_t *new_uuid, size_t length)
{
if (new_uuid && (length == sizeof(Device_UUID))) {
memcpy(Device_UUID, new_uuid, sizeof(Device_UUID));
}
}
/**
* @brief Get the UUID for this device
* @param uuid [out] The UUID of this device
* @param length [in] The length of the UUID
*/
void Device_UUID_Get(uint8_t *uuid, size_t length)
{
if (uuid && (length == sizeof(Device_UUID))) {
memcpy(uuid, Device_UUID, sizeof(Device_UUID));
}
}
/** Get the total count of objects supported by this Device Object.
* @note Since many network clients depend on the object list
* for discovery, it must be consistent!
@@ -586,6 +653,7 @@ int Device_Read_Property_Local(BACNET_READ_PROPERTY_DATA *rpdata)
int apdu_len = 0; /* return value */
BACNET_BIT_STRING bit_string = { 0 };
BACNET_CHARACTER_STRING char_string = { 0 };
BACNET_OCTET_STRING octet_string = { 0 };
uint32_t i = 0;
uint32_t count = 0;
uint8_t *apdu = NULL;
@@ -713,6 +781,10 @@ int Device_Read_Property_Local(BACNET_READ_PROPERTY_DATA *rpdata)
apdu_len =
encode_application_unsigned(&apdu[0], dlmstp_max_master());
break;
case PROP_DEVICE_UUID:
octetstring_init(&octet_string, Device_UUID, sizeof(Device_UUID));
apdu_len = encode_application_octet_string(&apdu[0], &octet_string);
break;
default:
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY;