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:
@@ -50,6 +50,8 @@ static bool BVLC_NAT_Handling = false;
|
||||
static BACNET_IP_ADDRESS Remote_BBMD;
|
||||
/** if we are a foreign device, store the Time-To-Live Seconds here */
|
||||
static uint16_t Remote_BBMD_TTL_Seconds;
|
||||
/** Dynamic enable or disable of accepting FD registrations */
|
||||
static bool BBMD_Accept_FD_Registrations = 1;
|
||||
#if BBMD_ENABLED || BBMD_CLIENT_ENABLED
|
||||
/* local buffer & length for sending */
|
||||
static uint8_t BVLC_Buffer[BIP_MPDU_MAX];
|
||||
@@ -873,6 +875,22 @@ int bvlc_bbmd_enabled_handler(
|
||||
}
|
||||
break;
|
||||
case BVLC_WRITE_BROADCAST_DISTRIBUTION_TABLE:
|
||||
/* J.2.2.1 Write-Broadcast-Distribution-Table: Format
|
||||
...
|
||||
Prior to the introduction of the Network Port object
|
||||
in Protocol_Revision 17, this message was the interoperable
|
||||
means of updating BDTs. That function is now performed
|
||||
by writes to the Network Port object
|
||||
...
|
||||
J.4.4.2 Use of the BVLL Write-Broadcast-Distribution-Table Message
|
||||
Upon receipt of a BVLL Write-Broadcast-Distribution-Table message,
|
||||
B/IP devices shall always return a BVLC-Result message to the
|
||||
originating device with a result code of X'0010' indicating that
|
||||
the Write-Broadcast-Distribution BVLL message is not supported.*/
|
||||
#if (BACNET_PROTOCOL_REVISION >= 17)
|
||||
result_code = BVLC_RESULT_WRITE_BROADCAST_DISTRIBUTION_TABLE_NAK;
|
||||
send_result = true;
|
||||
#else
|
||||
debug_print_bip("Received Write-BDT", addr);
|
||||
function_len = bvlc_decode_write_broadcast_distribution_table(
|
||||
pdu, pdu_len, &BBMD_Table[0]);
|
||||
@@ -886,6 +904,7 @@ int bvlc_bbmd_enabled_handler(
|
||||
BVLC_RESULT_WRITE_BROADCAST_DISTRIBUTION_TABLE_NAK;
|
||||
send_result = true;
|
||||
}
|
||||
#endif
|
||||
/* not an NPDU */
|
||||
offset = 0;
|
||||
break;
|
||||
@@ -971,6 +990,13 @@ int bvlc_bbmd_enabled_handler(
|
||||
without the receipt of another BVLL Register-Foreign-Device
|
||||
message from the same foreign device, the FDT entry for this
|
||||
device shall be cleared. */
|
||||
#if (BACNET_PROTOCOL_REVISION >= 17)
|
||||
if (!BBMD_Accept_FD_Registrations) {
|
||||
result_code = BVLC_RESULT_REGISTER_FOREIGN_DEVICE_NAK;
|
||||
send_result = true;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
function_len =
|
||||
bvlc_decode_register_foreign_device(pdu, pdu_len, &ttl_seconds);
|
||||
if (function_len) {
|
||||
@@ -1203,6 +1229,25 @@ int bvlc_broadcast_handler(
|
||||
return offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the status of the BBMD_Accept_FD_Registrations flag.
|
||||
* @return true if BBMD_Accept_FD_Registrations is enabled, false otherwise.
|
||||
*/
|
||||
bool bvlc_bbmd_accept_fd_registrations(void)
|
||||
{
|
||||
return BBMD_Accept_FD_Registrations;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the status of the BBMD_Accept_FD_Registrations flag.
|
||||
* @param flag - true to enable accepting foreign device registrations,
|
||||
* false to disable.
|
||||
*/
|
||||
void bvlc_bbmd_accept_fd_registrations_set(bool flag)
|
||||
{
|
||||
BBMD_Accept_FD_Registrations = flag;
|
||||
}
|
||||
|
||||
#if BBMD_CLIENT_ENABLED
|
||||
/** Register as a foreign device with the indicated BBMD.
|
||||
* @param bbmd_addr - IPv4 address of BBMD with which to register
|
||||
|
||||
@@ -98,6 +98,11 @@ void bvlc_remote_bbmd_address(BACNET_IP_ADDRESS *address);
|
||||
BACNET_STACK_EXPORT
|
||||
uint16_t bvlc_remote_bbmd_lifetime(void);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
bool bvlc_bbmd_accept_fd_registrations(void);
|
||||
BACNET_STACK_EXPORT
|
||||
void bvlc_bbmd_accept_fd_registrations_set(bool flag);
|
||||
|
||||
/* Local interface to manage BBMD.
|
||||
* The interface user needs to handle mutual exclusion if needed i.e.
|
||||
* BACnet packet is not being handled when the BBMD table is modified.
|
||||
|
||||
@@ -1869,6 +1869,110 @@ static int BBMD_Broadcast_Distribution_Table_Encode(
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the BACnetLIST capacity
|
||||
* @param object_instance [in] BACnet network port object instance number
|
||||
* @return capacity of the BACnetList (number of possible entries) or
|
||||
* zero on error
|
||||
*/
|
||||
static size_t
|
||||
BBMD_Broadcast_Distribution_Table_Capacity(uint32_t object_instance)
|
||||
{
|
||||
BACNET_IP_BROADCAST_DISTRIBUTION_TABLE_ENTRY *bdt_list;
|
||||
size_t capacity = 0;
|
||||
unsigned index = 0;
|
||||
|
||||
index = Network_Port_Instance_To_Index(object_instance);
|
||||
if (index < BACNET_NETWORK_PORTS_MAX) {
|
||||
if (Object_List[index].Network_Type == PORT_TYPE_BIP) {
|
||||
bdt_list = Object_List[index].Network.IPv4.BBMD_BD_Table;
|
||||
capacity = bvlc_broadcast_distribution_table_count(bdt_list);
|
||||
}
|
||||
}
|
||||
|
||||
return capacity;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Decode a BACnetLIST property element to determine the element length
|
||||
* @param object_instance [in] BACnet network port object instance number
|
||||
* @param apdu [in] Buffer in which the APDU contents are extracted
|
||||
* @param apdu_size [in] The size of the APDU buffer
|
||||
* @return The length of the decoded apdu, or BACNET_STATUS_ERROR on error
|
||||
*/
|
||||
static int BBMD_Broadcast_Distribution_Table_Element_Length(
|
||||
uint32_t object_instance, uint8_t *apdu, size_t apdu_size)
|
||||
{
|
||||
int len = 0;
|
||||
unsigned index = 0;
|
||||
|
||||
index = Network_Port_Instance_To_Index(object_instance);
|
||||
if (index < BACNET_NETWORK_PORTS_MAX) {
|
||||
if (Object_List[index].Network_Type == PORT_TYPE_BIP) {
|
||||
len = bvlc_decode_broadcast_distribution_table_entry(
|
||||
apdu, apdu_size, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Write a value to a BACnetLIST property element value
|
||||
* using a BACnetARRAY write utility function
|
||||
* @param object_instance [in] BACnet network port object instance number
|
||||
* @param array_index [in] array index to write:
|
||||
* 0=array size, 1 to N for individual array members
|
||||
* @param application_data [in] encoded element value
|
||||
* @param application_data_len [in] The size of the encoded element value
|
||||
* @return BACNET_ERROR_CODE value
|
||||
*/
|
||||
static BACNET_ERROR_CODE BBMD_Broadcast_Distribution_Table_Element_Write(
|
||||
uint32_t object_instance,
|
||||
BACNET_ARRAY_INDEX array_index,
|
||||
uint8_t *application_data,
|
||||
size_t application_data_len)
|
||||
{
|
||||
BACNET_ERROR_CODE error_code = ERROR_CODE_UNKNOWN_OBJECT;
|
||||
BACNET_IP_BROADCAST_DISTRIBUTION_TABLE_ENTRY bdt_entry = { 0 };
|
||||
BACNET_IP_BROADCAST_DISTRIBUTION_TABLE_ENTRY *bdt_list;
|
||||
uint16_t capacity = 0;
|
||||
int len;
|
||||
bool status = false;
|
||||
unsigned index = 0;
|
||||
|
||||
index = Network_Port_Instance_To_Index(object_instance);
|
||||
if (index < BACNET_NETWORK_PORTS_MAX) {
|
||||
if (Object_List[index].Network_Type == PORT_TYPE_BIP) {
|
||||
bdt_list = Object_List[index].Network.IPv4.BBMD_BD_Table;
|
||||
capacity = bvlc_broadcast_distribution_table_count(bdt_list);
|
||||
if (array_index == 0) {
|
||||
error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
|
||||
} else if (array_index <= capacity) {
|
||||
len = bvlc_decode_broadcast_distribution_table_entry(
|
||||
application_data, application_data_len, &bdt_entry);
|
||||
if (len > 0) {
|
||||
status = bvlc_broadcast_distribution_table_entry_insert(
|
||||
bdt_list, &bdt_entry, array_index);
|
||||
if (status) {
|
||||
error_code = ERROR_CODE_SUCCESS;
|
||||
} else {
|
||||
error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
}
|
||||
} else {
|
||||
error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
} else {
|
||||
error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
|
||||
}
|
||||
} else {
|
||||
error_code = ERROR_CODE_ABORT_OTHER;
|
||||
}
|
||||
}
|
||||
|
||||
return error_code;
|
||||
}
|
||||
|
||||
/**
|
||||
* For a given object instance-number, sets the BBMD-BD-Table head
|
||||
* property value
|
||||
@@ -1980,6 +2084,108 @@ static int BBMD_Foreign_Device_Table_Encode(
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the BACnetLIST capacity
|
||||
* @param object_instance [in] BACnet network port object instance number
|
||||
* @return capacity of the BACnetList (number of possible entries) or
|
||||
* zero on error
|
||||
*/
|
||||
static size_t BBMD_Foreign_Device_Table_Capacity(uint32_t object_instance)
|
||||
{
|
||||
BACNET_IP_FOREIGN_DEVICE_TABLE_ENTRY *fdt_list;
|
||||
size_t capacity = 0;
|
||||
unsigned index = 0;
|
||||
|
||||
index = Network_Port_Instance_To_Index(object_instance);
|
||||
if (index < BACNET_NETWORK_PORTS_MAX) {
|
||||
if (Object_List[index].Network_Type == PORT_TYPE_BIP) {
|
||||
fdt_list = Object_List[index].Network.IPv4.BBMD_FD_Table;
|
||||
capacity = bvlc_foreign_device_table_count(fdt_list);
|
||||
}
|
||||
}
|
||||
|
||||
return capacity;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Decode a BACnetLIST property element to determine the element length
|
||||
* @param object_instance [in] BACnet network port object instance number
|
||||
* @param apdu [in] Buffer in which the APDU contents are extracted
|
||||
* @param apdu_size [in] The size of the APDU buffer
|
||||
* @return The length of the decoded apdu, or BACNET_STATUS_ERROR on error
|
||||
*/
|
||||
static int BBMD_Foreign_Device_Table_Element_Length(
|
||||
uint32_t object_instance, uint8_t *apdu, size_t apdu_size)
|
||||
{
|
||||
int len = 0;
|
||||
unsigned index = 0;
|
||||
|
||||
index = Network_Port_Instance_To_Index(object_instance);
|
||||
if (index < BACNET_NETWORK_PORTS_MAX) {
|
||||
if (Object_List[index].Network_Type == PORT_TYPE_BIP) {
|
||||
len = bvlc_decode_foreign_device_table_entry(apdu, apdu_size, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Write a value to a BACnetLIST property element value
|
||||
* using a BACnetARRAY write utility function
|
||||
* @param object_instance [in] BACnet network port object instance number
|
||||
* @param array_index [in] array index to write:
|
||||
* 0=array size, 1 to N for individual array members
|
||||
* @param application_data [in] encoded element value
|
||||
* @param application_data_len [in] The size of the encoded element value
|
||||
* @return BACNET_ERROR_CODE value
|
||||
*/
|
||||
static BACNET_ERROR_CODE BBMD_Foreign_Device_Table_Element_Write(
|
||||
uint32_t object_instance,
|
||||
BACNET_ARRAY_INDEX array_index,
|
||||
uint8_t *application_data,
|
||||
size_t application_data_len)
|
||||
{
|
||||
BACNET_ERROR_CODE error_code = ERROR_CODE_UNKNOWN_OBJECT;
|
||||
BACNET_IP_FOREIGN_DEVICE_TABLE_ENTRY fdt_entry = { 0 };
|
||||
BACNET_IP_FOREIGN_DEVICE_TABLE_ENTRY *fdt_list;
|
||||
uint16_t capacity = 0;
|
||||
int len;
|
||||
bool status = false;
|
||||
unsigned index = 0;
|
||||
|
||||
index = Network_Port_Instance_To_Index(object_instance);
|
||||
if (index < BACNET_NETWORK_PORTS_MAX) {
|
||||
if (Object_List[index].Network_Type == PORT_TYPE_BIP) {
|
||||
fdt_list = Object_List[index].Network.IPv4.BBMD_FD_Table;
|
||||
capacity = bvlc_foreign_device_table_count(fdt_list);
|
||||
if (array_index == 0) {
|
||||
error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
|
||||
} else if (array_index <= capacity) {
|
||||
len = bvlc_decode_foreign_device_table_entry(
|
||||
application_data, application_data_len, &fdt_entry);
|
||||
if (len > 0) {
|
||||
status = bvlc_foreign_device_table_entry_insert(
|
||||
fdt_list, &fdt_entry, array_index - 1);
|
||||
if (status) {
|
||||
error_code = ERROR_CODE_SUCCESS;
|
||||
} else {
|
||||
error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
}
|
||||
} else {
|
||||
error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
} else {
|
||||
error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
|
||||
}
|
||||
} else {
|
||||
error_code = ERROR_CODE_ABORT_OTHER;
|
||||
}
|
||||
}
|
||||
|
||||
return error_code;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief For a given object instance-number, gets the HostNPort
|
||||
* @note depends on Network_Type being set for this object
|
||||
@@ -4100,6 +4306,7 @@ bool Network_Port_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data)
|
||||
{
|
||||
bool status = false; /* return value */
|
||||
int len = 0;
|
||||
uint32_t capacity;
|
||||
BACNET_APPLICATION_DATA_VALUE value = { 0 };
|
||||
|
||||
if (!Network_Port_Valid_Instance(wp_data->object_instance)) {
|
||||
@@ -4181,6 +4388,44 @@ bool Network_Port_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data)
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
}
|
||||
break;
|
||||
case PROP_BBMD_ACCEPT_FD_REGISTRATIONS:
|
||||
status = write_property_type_valid(
|
||||
wp_data, &value, BACNET_APPLICATION_TAG_BOOLEAN);
|
||||
if (status) {
|
||||
status = Network_Port_BBMD_Accept_FD_Registrations_Set(
|
||||
wp_data->object_instance, value.type.Boolean);
|
||||
if (!status) {
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case PROP_BBMD_BROADCAST_DISTRIBUTION_TABLE:
|
||||
/* BACnetLIST */
|
||||
capacity = BBMD_Broadcast_Distribution_Table_Capacity(
|
||||
wp_data->object_instance);
|
||||
wp_data->error_code = bacnet_array_write(
|
||||
wp_data->object_instance, wp_data->array_index,
|
||||
BBMD_Broadcast_Distribution_Table_Element_Length,
|
||||
BBMD_Broadcast_Distribution_Table_Element_Write, capacity,
|
||||
wp_data->application_data, wp_data->application_data_len);
|
||||
if (wp_data->error_code == ERROR_CODE_SUCCESS) {
|
||||
status = true;
|
||||
}
|
||||
break;
|
||||
case PROP_BBMD_FOREIGN_DEVICE_TABLE:
|
||||
/* BACnetLIST */
|
||||
capacity =
|
||||
BBMD_Foreign_Device_Table_Capacity(wp_data->object_instance);
|
||||
wp_data->error_code = bacnet_array_write(
|
||||
wp_data->object_instance, wp_data->array_index,
|
||||
BBMD_Foreign_Device_Table_Element_Length,
|
||||
BBMD_Foreign_Device_Table_Element_Write, capacity,
|
||||
wp_data->application_data, wp_data->application_data_len);
|
||||
if (wp_data->error_code == ERROR_CODE_SUCCESS) {
|
||||
status = true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (Property_List_Member(
|
||||
wp_data->object_instance, wp_data->object_property)) {
|
||||
|
||||
Reference in New Issue
Block a user