Fixed BVLC Write Broadcast Distribution Table for protocol revision 17 and later. (#1005)
* Fixed BVLC Write Broadcast Distribution Table for protocol revision 17 and later. * Added check for Network Port object bbmd-accept-fd-registrations property in BBMD handler. * Added bvlc_foreign_device_table_decode() function and unit test. * Added BDT and FTD write property to network port for IPv4
This commit is contained in:
+216
-30
@@ -356,6 +356,37 @@ bool bvlc_broadcast_distribution_table_entry_append(
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Append an entry to the Broadcast-Distribution-Table
|
||||
* @param bdt_list - first entry in list of BDT entries
|
||||
* @param bdt_entry - entry to insert into to list of BDT entries
|
||||
* @param bdt_index - 0..N where N is count-1
|
||||
* @return true if the Broadcast-Distribution-Table entry was inserted
|
||||
*/
|
||||
bool bvlc_broadcast_distribution_table_entry_insert(
|
||||
BACNET_IP_BROADCAST_DISTRIBUTION_TABLE_ENTRY *bdt_list,
|
||||
const BACNET_IP_BROADCAST_DISTRIBUTION_TABLE_ENTRY *bdt_entry,
|
||||
uint16_t bdt_index)
|
||||
{
|
||||
BACNET_IP_BROADCAST_DISTRIBUTION_TABLE_ENTRY *bdt_node = NULL;
|
||||
uint16_t count = 0;
|
||||
bool status = false;
|
||||
|
||||
bdt_node = bdt_list;
|
||||
while (bdt_node) {
|
||||
if (count == bdt_index) {
|
||||
status = true;
|
||||
bvlc_broadcast_distribution_table_entry_copy(bdt_node, bdt_entry);
|
||||
bdt_node->valid = true;
|
||||
break;
|
||||
}
|
||||
bdt_node = bdt_node->next;
|
||||
count++;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set an entry to the Broadcast-Distribution-Table
|
||||
* @param bdt_entry - first element in list of BDT entries
|
||||
@@ -831,17 +862,15 @@ int bvlc_encode_write_broadcast_distribution_table(
|
||||
* @param pdu_len - length of the buffer that needs decoding
|
||||
* @param bdt_list - BDT Entry list
|
||||
*
|
||||
* @return number of bytes decoded
|
||||
* @return number of bytes decoded, or 0 for none or error
|
||||
*/
|
||||
int bvlc_decode_write_broadcast_distribution_table(
|
||||
const uint8_t *pdu,
|
||||
uint16_t pdu_len,
|
||||
uint16_t pdu_size,
|
||||
BACNET_IP_BROADCAST_DISTRIBUTION_TABLE_ENTRY *bdt_list)
|
||||
{
|
||||
int bytes_consumed = 0;
|
||||
int len = 0;
|
||||
uint16_t offset = 0;
|
||||
uint16_t pdu_bytes = 0;
|
||||
uint16_t pdu_len = 0;
|
||||
uint16_t bdt_entry_count = 0;
|
||||
BACNET_IP_BROADCAST_DISTRIBUTION_TABLE_ENTRY *bdt_entry = NULL;
|
||||
uint16_t list_len = 0;
|
||||
@@ -850,26 +879,40 @@ int bvlc_decode_write_broadcast_distribution_table(
|
||||
bdt_entry_count = bvlc_broadcast_distribution_table_count(bdt_list);
|
||||
list_len = bdt_entry_count * BACNET_IP_BDT_ENTRY_SIZE;
|
||||
/* will the entries fit */
|
||||
if (pdu && (pdu_len <= list_len)) {
|
||||
if (pdu && (pdu_size <= list_len)) {
|
||||
/* check payload for valid entries */
|
||||
while (pdu_len < pdu_size) {
|
||||
len = bvlc_decode_broadcast_distribution_table_entry(
|
||||
&pdu[pdu_len], pdu_size - pdu_len, NULL);
|
||||
if (len > 0) {
|
||||
pdu_len += len;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
pdu_len = 0;
|
||||
bdt_entry = bdt_list;
|
||||
while (bdt_entry) {
|
||||
pdu_bytes = pdu_len - offset;
|
||||
if (pdu_bytes >= BACNET_IP_BDT_ENTRY_SIZE) {
|
||||
if (pdu_len < pdu_size) {
|
||||
/* decode valid entries */
|
||||
len = bvlc_decode_broadcast_distribution_table_entry(
|
||||
&pdu[offset], pdu_bytes, bdt_entry);
|
||||
&pdu[pdu_len], pdu_size - pdu_len, bdt_entry);
|
||||
if (len > 0) {
|
||||
pdu_len += len;
|
||||
bdt_entry->valid = true;
|
||||
} else {
|
||||
/* set the available entries as invalid */
|
||||
bdt_entry->valid = false;
|
||||
}
|
||||
offset += len;
|
||||
} else {
|
||||
/* set the available entries as invalid */
|
||||
bdt_entry->valid = false;
|
||||
}
|
||||
bdt_entry = bdt_entry->next;
|
||||
}
|
||||
bytes_consumed = (int)offset;
|
||||
}
|
||||
|
||||
return bytes_consumed;
|
||||
return pdu_len;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1274,6 +1317,92 @@ int bvlc_foreign_device_table_encode(
|
||||
return len;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Decode the Foreign_Device-Table for Network Port object
|
||||
* @param apdu - the APDU buffer
|
||||
* @param apdu_size - the APDU buffer length
|
||||
* @param fdt_head - head of a FDT linked list
|
||||
* @return length of the APDU buffer decoded, or ERROR, REJECT, or ABORT
|
||||
*/
|
||||
int bvlc_foreign_device_table_decode(
|
||||
const uint8_t *apdu,
|
||||
uint16_t apdu_size,
|
||||
BACNET_ERROR_CODE *error_code,
|
||||
BACNET_IP_FOREIGN_DEVICE_TABLE_ENTRY *fdt_head)
|
||||
{
|
||||
int len = 0, apdu_len = 0;
|
||||
BACNET_IP_FOREIGN_DEVICE_TABLE_ENTRY *fdt_entry = NULL;
|
||||
BACNET_UNSIGNED_INTEGER unsigned_value = 0;
|
||||
BACNET_OCTET_STRING octet_string = { 0 };
|
||||
|
||||
/* default reject code */
|
||||
if (error_code) {
|
||||
*error_code = ERROR_CODE_REJECT_MISSING_REQUIRED_PARAMETER;
|
||||
}
|
||||
/* check for value pointers */
|
||||
if ((apdu_size == 0) || (!apdu)) {
|
||||
return BACNET_STATUS_REJECT;
|
||||
}
|
||||
fdt_entry = fdt_head;
|
||||
while (fdt_entry) {
|
||||
/* bacnetip-address [0] OCTET STRING */
|
||||
len = bacnet_octet_string_context_decode(
|
||||
&apdu[apdu_len], apdu_size - apdu_len, 0, &octet_string);
|
||||
if (len <= 0) {
|
||||
if (error_code) {
|
||||
*error_code = ERROR_CODE_REJECT_INVALID_TAG;
|
||||
}
|
||||
return BACNET_STATUS_REJECT;
|
||||
}
|
||||
bvlc_decode_address(
|
||||
octetstring_value(&octet_string), octetstring_length(&octet_string),
|
||||
&fdt_entry->dest_address);
|
||||
apdu_len += len;
|
||||
/* time-to-live [1] Unsigned16 */
|
||||
len = bacnet_unsigned_context_decode(
|
||||
&apdu[apdu_len], apdu_size - apdu_len, 1, &unsigned_value);
|
||||
if (len <= 0) {
|
||||
if (error_code) {
|
||||
*error_code = ERROR_CODE_REJECT_INVALID_TAG;
|
||||
}
|
||||
return BACNET_STATUS_REJECT;
|
||||
}
|
||||
apdu_len += len;
|
||||
if (unsigned_value <= UINT16_MAX) {
|
||||
fdt_entry->ttl_seconds = unsigned_value;
|
||||
} else {
|
||||
if (error_code) {
|
||||
*error_code = ERROR_CODE_REJECT_PARAMETER_OUT_OF_RANGE;
|
||||
}
|
||||
return BACNET_STATUS_REJECT;
|
||||
}
|
||||
/* remaining-time-to-live [2] Unsigned16 */
|
||||
len = bacnet_unsigned_context_decode(
|
||||
&apdu[apdu_len], apdu_size - apdu_len, 2, &unsigned_value);
|
||||
if (len <= 0) {
|
||||
if (error_code) {
|
||||
*error_code = ERROR_CODE_REJECT_INVALID_TAG;
|
||||
}
|
||||
return BACNET_STATUS_REJECT;
|
||||
}
|
||||
apdu_len += len;
|
||||
if (unsigned_value <= UINT16_MAX) {
|
||||
fdt_entry->ttl_seconds_remaining = unsigned_value;
|
||||
} else {
|
||||
if (error_code) {
|
||||
*error_code = ERROR_CODE_REJECT_PARAMETER_OUT_OF_RANGE;
|
||||
}
|
||||
return BACNET_STATUS_REJECT;
|
||||
}
|
||||
/* mark as valid */
|
||||
fdt_entry->valid = true;
|
||||
/* next entry */
|
||||
fdt_entry = fdt_entry->next;
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief J.2.7 Read-Foreign-Device-Table: encode
|
||||
*
|
||||
@@ -1461,6 +1590,53 @@ bool bvlc_foreign_device_table_entry_add(
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Append an entry to the Foreign-Device-Table
|
||||
* @param bdt_list - first entry in list of FDT entries
|
||||
* @param bdt_entry - entry to insert into to list of FDT entries
|
||||
* @param bdt_index - 0..N where N is count-1
|
||||
* @return true if the entry was inserted
|
||||
*/
|
||||
bool bvlc_foreign_device_table_entry_insert(
|
||||
BACNET_IP_FOREIGN_DEVICE_TABLE_ENTRY *fdt_list,
|
||||
const BACNET_IP_FOREIGN_DEVICE_TABLE_ENTRY *fdt_entry,
|
||||
uint16_t array_index)
|
||||
{
|
||||
BACNET_IP_FOREIGN_DEVICE_TABLE_ENTRY *fdt_node = NULL;
|
||||
uint16_t count = 0;
|
||||
bool status = false;
|
||||
|
||||
fdt_node = fdt_list;
|
||||
while (fdt_node) {
|
||||
if (count == array_index) {
|
||||
status = bvlc_foreign_device_table_entry_copy(fdt_node, fdt_entry);
|
||||
fdt_node->valid = true;
|
||||
break;
|
||||
}
|
||||
fdt_node = fdt_node->next;
|
||||
count++;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Clear all Write-Broadcast-Distribution-Table entries
|
||||
* @param bdt_list - first element in array BDT entries
|
||||
*/
|
||||
void bvlc_foreign_device_table_valid_clear(
|
||||
BACNET_IP_FOREIGN_DEVICE_TABLE_ENTRY *fdt_list)
|
||||
{
|
||||
BACNET_IP_FOREIGN_DEVICE_TABLE_ENTRY *fdt_entry;
|
||||
|
||||
/* clear the valid entries */
|
||||
fdt_entry = fdt_list;
|
||||
while (fdt_entry) {
|
||||
fdt_entry->valid = false;
|
||||
fdt_entry = fdt_entry->next;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Count the number of valid Foreign-Device-Table entries
|
||||
* @param fdt_list - first element in list of FDT entries
|
||||
@@ -2143,6 +2319,7 @@ bool bvlc_address_mask(
|
||||
dst->address[i] = src->address[i] | ~mask->address[i];
|
||||
}
|
||||
dst->port = src->port;
|
||||
status = true;
|
||||
}
|
||||
|
||||
return status;
|
||||
@@ -2569,37 +2746,46 @@ int bvlc_encode_broadcast_distribution_table_entry(
|
||||
* IP subnet served by the BBMD
|
||||
*
|
||||
* @param pdu - buffer from which to decode the message
|
||||
* @param pdu_len - length of the buffer that needs decoding
|
||||
* @param bdt_entry - BDT Entry
|
||||
* @param pdu_size - length of the buffer that needs decoding
|
||||
* @param bdt_entry - BDT Entry, or NULL for length only
|
||||
*
|
||||
* @return number of bytes decoded
|
||||
* @return number of bytes decoded, or 0 if error
|
||||
*/
|
||||
int bvlc_decode_broadcast_distribution_table_entry(
|
||||
const uint8_t *pdu,
|
||||
uint16_t pdu_len,
|
||||
uint16_t pdu_size,
|
||||
BACNET_IP_BROADCAST_DISTRIBUTION_TABLE_ENTRY *bdt_entry)
|
||||
{
|
||||
int bytes_consumed = 0;
|
||||
int pdu_len = 0;
|
||||
int len = 0;
|
||||
int offset = 0;
|
||||
BACNET_IP_ADDRESS dest_address;
|
||||
BACNET_IP_BROADCAST_DISTRIBUTION_MASK broadcast_mask;
|
||||
|
||||
if (pdu && (pdu_len >= BACNET_IP_BDT_ENTRY_SIZE)) {
|
||||
if (bdt_entry) {
|
||||
len = bvlc_decode_address(
|
||||
&pdu[offset], pdu_len - offset, &bdt_entry->dest_address);
|
||||
if (len > 0) {
|
||||
offset += len;
|
||||
len = bvlc_decode_broadcast_distribution_mask(
|
||||
&pdu[offset], pdu_len - offset, &bdt_entry->broadcast_mask);
|
||||
if (pdu) {
|
||||
len = bvlc_decode_address(
|
||||
&pdu[pdu_len], pdu_size - pdu_len, &dest_address);
|
||||
if (len > 0) {
|
||||
pdu_len += len;
|
||||
if (bdt_entry) {
|
||||
bvlc_address_copy(&bdt_entry->dest_address, &dest_address);
|
||||
}
|
||||
if (len > 0) {
|
||||
offset += len;
|
||||
bytes_consumed = offset;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
len = bvlc_decode_broadcast_distribution_mask(
|
||||
&pdu[pdu_len], pdu_size - pdu_len, &broadcast_mask);
|
||||
if (len > 0) {
|
||||
pdu_len += len;
|
||||
if (bdt_entry) {
|
||||
bvlc_broadcast_distribution_mask_copy(
|
||||
&bdt_entry->broadcast_mask, &broadcast_mask);
|
||||
}
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return bytes_consumed;
|
||||
return pdu_len;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -272,6 +272,12 @@ bool bvlc_broadcast_distribution_table_entry_append(
|
||||
BACNET_IP_BROADCAST_DISTRIBUTION_TABLE_ENTRY *bdt_list,
|
||||
const BACNET_IP_BROADCAST_DISTRIBUTION_TABLE_ENTRY *bdt_entry);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
bool bvlc_broadcast_distribution_table_entry_insert(
|
||||
BACNET_IP_BROADCAST_DISTRIBUTION_TABLE_ENTRY *bdt_list,
|
||||
const BACNET_IP_BROADCAST_DISTRIBUTION_TABLE_ENTRY *bdt_entry,
|
||||
uint16_t array_index);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
bool bvlc_broadcast_distribution_table_entry_set(
|
||||
BACNET_IP_BROADCAST_DISTRIBUTION_TABLE_ENTRY *bdt_entry,
|
||||
@@ -380,6 +386,9 @@ void bvlc_foreign_device_table_maintenance_timer(
|
||||
BACNET_IP_FOREIGN_DEVICE_TABLE_ENTRY *fdt_list, uint16_t seconds);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
void bvlc_foreign_device_table_valid_clear(
|
||||
BACNET_IP_FOREIGN_DEVICE_TABLE_ENTRY *fdt_list);
|
||||
BACNET_STACK_EXPORT
|
||||
uint16_t bvlc_foreign_device_table_valid_count(
|
||||
BACNET_IP_FOREIGN_DEVICE_TABLE_ENTRY *fdt_list);
|
||||
|
||||
@@ -412,6 +421,12 @@ bool bvlc_foreign_device_table_entry_add(
|
||||
const BACNET_IP_ADDRESS *ip_address,
|
||||
uint16_t ttl_seconds);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
bool bvlc_foreign_device_table_entry_insert(
|
||||
BACNET_IP_FOREIGN_DEVICE_TABLE_ENTRY *fdt_list,
|
||||
const BACNET_IP_FOREIGN_DEVICE_TABLE_ENTRY *fdt_entry,
|
||||
uint16_t array_index);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
int bvlc_encode_foreign_device_table_entry(
|
||||
uint8_t *pdu,
|
||||
@@ -435,6 +450,11 @@ int bvlc_foreign_device_table_encode(
|
||||
uint8_t *apdu,
|
||||
uint16_t apdu_size,
|
||||
const BACNET_IP_FOREIGN_DEVICE_TABLE_ENTRY *fdt_head);
|
||||
int bvlc_foreign_device_table_decode(
|
||||
const uint8_t *apdu,
|
||||
uint16_t apdu_len,
|
||||
BACNET_ERROR_CODE *error_code,
|
||||
BACNET_IP_FOREIGN_DEVICE_TABLE_ENTRY *fdt_head);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
int bvlc_encode_read_foreign_device_table(uint8_t *pdu, uint16_t pdu_size);
|
||||
|
||||
@@ -321,6 +321,38 @@ static int bbmd6_register_as_foreign_device(void)
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param instance
|
||||
*/
|
||||
static void bip_network_port_activate_changes(uint32_t instance)
|
||||
{
|
||||
#if defined(BACDL_BIP)
|
||||
bvlc_bbmd_accept_fd_registrations_set(
|
||||
Network_Port_BBMD_Accept_FD_Registrations(instance));
|
||||
#else
|
||||
/* if we are not using BIP, then we don't have any changes to discard */
|
||||
(void)instance;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param instance
|
||||
*/
|
||||
static void bip_network_port_discard_changes(uint32_t instance)
|
||||
{
|
||||
#if defined(BACDL_BIP)
|
||||
Network_Port_BBMD_Accept_FD_Registrations_Set(
|
||||
instance, bvlc_bbmd_accept_fd_registrations());
|
||||
#else
|
||||
/* if we are not using BIP, then we don't have any changes to discard */
|
||||
(void)instance;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Datalink network port object settings
|
||||
*/
|
||||
@@ -401,6 +433,8 @@ static void dlenv_network_port_bip_init(uint32_t instance)
|
||||
instance, addr0, addr1, addr2, addr3);
|
||||
Network_Port_Remote_BBMD_BIP_Port_Set(instance, BBMD_Address.port);
|
||||
Network_Port_Remote_BBMD_BIP_Lifetime_Set(instance, BBMD_TTL_Seconds);
|
||||
Network_Port_BBMD_Accept_FD_Registrations_Set(
|
||||
instance, bvlc_bbmd_accept_fd_registrations());
|
||||
#endif
|
||||
/* common NP data */
|
||||
Network_Port_Reliability_Set(instance, RELIABILITY_NO_FAULT_DETECTED);
|
||||
@@ -411,6 +445,10 @@ static void dlenv_network_port_bip_init(uint32_t instance)
|
||||
/* last thing - clear pending changes - we don't want to set these
|
||||
since they are already set */
|
||||
Network_Port_Changes_Pending_Set(instance, false);
|
||||
Network_Port_Changes_Pending_Activate_Callback_Set(
|
||||
instance, bip_network_port_activate_changes);
|
||||
Network_Port_Changes_Pending_Discard_Callback_Set(
|
||||
instance, bip_network_port_discard_changes);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user