Added Who-Is-Router process for Notification Class recipient unknown router addresses. (#1243)
* Added Who-Is-Router-To-Network process in basic Notification Class when recipient address is missing the router MAC address. * Added buffer_length parameter to octet string buffer decode functions * Fixed BACnet address handling for I-Am-Router address updating the recipient list address for the next hop router. * Changed VMAC encoding and decoding to use octet string buffer API to reduce stack RAM.
This commit is contained in:
+80
-30
@@ -15,7 +15,6 @@
|
||||
/* BACnet Stack API */
|
||||
#include "bacnet/bacdcode.h"
|
||||
#include "bacnet/bacint.h"
|
||||
#include "bacnet/bacstr.h"
|
||||
#include "bacnet/bactext.h"
|
||||
#include "bacnet/bacaddr.h"
|
||||
|
||||
@@ -203,6 +202,33 @@ bool bacnet_address_init(
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the #BACNET_ADDRESS of the next-hop router to the MAC of the dest
|
||||
* @param dest - #BACNET_ADDRESS to be configured
|
||||
* @param router - #BACNET_ADDRESS MAC to be copied from
|
||||
*/
|
||||
void bacnet_address_router_set(
|
||||
BACNET_ADDRESS *dest, const BACNET_ADDRESS *router)
|
||||
{
|
||||
uint8_t i = 0;
|
||||
uint8_t mac_len = 0;
|
||||
|
||||
if (dest && router) {
|
||||
mac_len = router->mac_len;
|
||||
if (mac_len > MAX_MAC_LEN) {
|
||||
mac_len = MAX_MAC_LEN;
|
||||
}
|
||||
dest->mac_len = mac_len;
|
||||
for (i = 0; i < MAX_MAC_LEN; i++) {
|
||||
if (i < mac_len) {
|
||||
dest->mac[i] = router->mac[i];
|
||||
} else {
|
||||
dest->mac[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compare two #BACNET_MAC_ADDRESS values
|
||||
* @param dest - #BACNET_MAC_ADDRESS to be compared
|
||||
@@ -385,7 +411,8 @@ int bacnet_address_decode(
|
||||
int apdu_len = 0;
|
||||
uint8_t i = 0;
|
||||
BACNET_UNSIGNED_INTEGER snet = 0;
|
||||
BACNET_OCTET_STRING mac_addr = { 0 };
|
||||
uint32_t mac_addr_len = 0;
|
||||
uint8_t mac_addr[MAX_MAC_LEN] = { 0 };
|
||||
|
||||
if (!apdu) {
|
||||
return BACNET_STATUS_ERROR;
|
||||
@@ -406,33 +433,47 @@ int bacnet_address_decode(
|
||||
}
|
||||
apdu_len += len;
|
||||
/* mac address as an octet-string */
|
||||
len = bacnet_octet_string_application_decode(
|
||||
&apdu[apdu_len], apdu_size - apdu_len, &mac_addr);
|
||||
len = bacnet_octet_string_buffer_application_decode(
|
||||
&apdu[apdu_len], apdu_size - apdu_len, &mac_addr[0], sizeof(mac_addr),
|
||||
&mac_addr_len);
|
||||
if (len <= 0) {
|
||||
return BACNET_STATUS_ERROR;
|
||||
}
|
||||
if (mac_addr_len > MAX_MAC_LEN) {
|
||||
return BACNET_STATUS_ERROR;
|
||||
}
|
||||
if (snet) {
|
||||
if (value) {
|
||||
if (mac_addr.length > sizeof(value->adr)) {
|
||||
if (mac_addr_len > sizeof(value->adr)) {
|
||||
return BACNET_STATUS_ERROR;
|
||||
}
|
||||
/* bounds checking - passed! */
|
||||
value->len = mac_addr.length;
|
||||
value->len = (uint8_t)mac_addr_len;
|
||||
/* copy address */
|
||||
for (i = 0; i < value->len; i++) {
|
||||
value->adr[i] = mac_addr.value[i];
|
||||
value->adr[i] = mac_addr[i];
|
||||
}
|
||||
/* zero the router address */
|
||||
value->mac_len = 0;
|
||||
for (i = 0; i < MAX_MAC_LEN; i++) {
|
||||
value->mac[i] = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (value) {
|
||||
if (mac_addr.length > sizeof(value->mac)) {
|
||||
if (mac_addr_len > sizeof(value->mac)) {
|
||||
return BACNET_STATUS_ERROR;
|
||||
}
|
||||
/* bounds checking - passed! */
|
||||
value->mac_len = mac_addr.length;
|
||||
value->mac_len = (uint8_t)mac_addr_len;
|
||||
/* copy address */
|
||||
for (i = 0; i < value->mac_len; i++) {
|
||||
value->mac[i] = mac_addr.value[i];
|
||||
value->mac[i] = mac_addr[i];
|
||||
}
|
||||
/* zero the device behind a router address */
|
||||
value->len = 0;
|
||||
for (i = 0; i < MAX_MAC_LEN; i++) {
|
||||
value->adr[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -581,24 +622,21 @@ int decode_context_bacnet_address(
|
||||
int bacnet_vmac_entry_data_encode(uint8_t *apdu, const BACNET_VMAC_ENTRY *value)
|
||||
{
|
||||
int apdu_len = 0, len;
|
||||
BACNET_OCTET_STRING address = { 0 };
|
||||
|
||||
if (!value) {
|
||||
return 0;
|
||||
}
|
||||
/* virtual-mac-address [0] OctetString */
|
||||
octetstring_init(
|
||||
&address, value->virtual_mac_address.adr,
|
||||
len = encode_context_octet_string_buffer(
|
||||
apdu, 0, value->virtual_mac_address.adr,
|
||||
value->virtual_mac_address.len);
|
||||
len = encode_context_octet_string(apdu, 0, &address);
|
||||
apdu_len += len;
|
||||
if (apdu) {
|
||||
apdu += len;
|
||||
}
|
||||
/* native-mac-address */
|
||||
octetstring_init(
|
||||
&address, value->native_mac_address, value->native_mac_address_len);
|
||||
len = encode_context_octet_string(apdu, 1, &address);
|
||||
len = encode_context_octet_string_buffer(
|
||||
apdu, 1, value->native_mac_address, value->native_mac_address_len);
|
||||
apdu_len += len;
|
||||
|
||||
return apdu_len;
|
||||
@@ -647,44 +685,56 @@ int bacnet_vmac_entry_decode(
|
||||
int len = 0;
|
||||
int apdu_len = 0;
|
||||
size_t i = 0;
|
||||
BACNET_OCTET_STRING mac_addr = { 0 };
|
||||
BACNET_VMAC_ENTRY entry = { 0 };
|
||||
uint32_t mac_addr_len = 0;
|
||||
|
||||
if (!apdu) {
|
||||
return BACNET_STATUS_ERROR;
|
||||
}
|
||||
/* virtual-mac-address [0] OctetString */
|
||||
len = bacnet_octet_string_context_decode(
|
||||
&apdu[apdu_len], apdu_size - apdu_len, 0, &mac_addr);
|
||||
len = bacnet_octet_string_buffer_context_decode(
|
||||
&apdu[apdu_len], apdu_size - apdu_len, 0, entry.virtual_mac_address.adr,
|
||||
sizeof(entry.virtual_mac_address.adr), &mac_addr_len);
|
||||
if (len <= 0) {
|
||||
return BACNET_STATUS_ERROR;
|
||||
}
|
||||
if (value) {
|
||||
if (mac_addr.length > sizeof(value->virtual_mac_address.adr)) {
|
||||
if (mac_addr_len > sizeof(value->virtual_mac_address.adr)) {
|
||||
return BACNET_STATUS_ERROR;
|
||||
}
|
||||
/* bounds checking - passed! */
|
||||
value->virtual_mac_address.len = mac_addr.length;
|
||||
value->virtual_mac_address.len = mac_addr_len;
|
||||
/* copy address */
|
||||
for (i = 0; i < mac_addr.length; i++) {
|
||||
value->virtual_mac_address.adr[i] = mac_addr.value[i];
|
||||
for (i = 0; i < sizeof(value->virtual_mac_address.adr); i++) {
|
||||
if (i < mac_addr_len) {
|
||||
value->virtual_mac_address.adr[i] =
|
||||
entry.virtual_mac_address.adr[i];
|
||||
} else {
|
||||
value->virtual_mac_address.adr[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
apdu_len += len;
|
||||
/* native-mac-address [1] OctetString */
|
||||
len = bacnet_octet_string_context_decode(
|
||||
&apdu[apdu_len], apdu_size - apdu_len, 1, &mac_addr);
|
||||
len = bacnet_octet_string_buffer_context_decode(
|
||||
&apdu[apdu_len], apdu_size - apdu_len, 1, entry.native_mac_address,
|
||||
sizeof(entry.native_mac_address), &mac_addr_len);
|
||||
if (len <= 0) {
|
||||
return BACNET_STATUS_ERROR;
|
||||
}
|
||||
if (value) {
|
||||
if (mac_addr.length > sizeof(value->native_mac_address)) {
|
||||
if (mac_addr_len > sizeof(value->native_mac_address)) {
|
||||
return BACNET_STATUS_ERROR;
|
||||
}
|
||||
/* bounds checking - passed! */
|
||||
value->native_mac_address_len = mac_addr.length;
|
||||
value->native_mac_address_len = mac_addr_len;
|
||||
/* copy address */
|
||||
for (i = 0; i < mac_addr.length; i++) {
|
||||
value->native_mac_address[i] = mac_addr.value[i];
|
||||
for (i = 0; i < sizeof(value->native_mac_address); i++) {
|
||||
if (i < mac_addr_len) {
|
||||
value->native_mac_address[i] = entry.native_mac_address[i];
|
||||
} else {
|
||||
value->native_mac_address[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
apdu_len += len;
|
||||
|
||||
@@ -58,6 +58,9 @@ bool bacnet_address_init(
|
||||
const BACNET_MAC_ADDRESS *mac,
|
||||
uint16_t dnet,
|
||||
const BACNET_MAC_ADDRESS *adr);
|
||||
BACNET_STACK_EXPORT
|
||||
void bacnet_address_router_set(
|
||||
BACNET_ADDRESS *dest, const BACNET_ADDRESS *router);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
bool bacnet_address_mac_same(
|
||||
|
||||
+12
-2
@@ -2438,6 +2438,7 @@ int bacnet_octet_string_buffer_decode(
|
||||
* or NULL for length only.
|
||||
* @param buffer_size - number of bytes in the buffer where the
|
||||
* decoded value is stored
|
||||
* @param buffer_length - number of bytes decoded into the buffer
|
||||
*
|
||||
* @return number of bytes decoded, zero if tag mismatch,
|
||||
* or #BACNET_STATUS_ERROR (-1) if malformed
|
||||
@@ -2446,7 +2447,8 @@ int bacnet_octet_string_buffer_application_decode(
|
||||
const uint8_t *apdu,
|
||||
uint32_t apdu_size,
|
||||
uint8_t *buffer,
|
||||
size_t buffer_size)
|
||||
size_t buffer_size,
|
||||
uint32_t *buffer_length)
|
||||
{
|
||||
int apdu_len = BACNET_STATUS_ERROR;
|
||||
int len = 0;
|
||||
@@ -2464,6 +2466,9 @@ int bacnet_octet_string_buffer_application_decode(
|
||||
&apdu[len], apdu_size - apdu_len, tag.len_value_type, buffer,
|
||||
buffer_size);
|
||||
if (len >= 0) {
|
||||
if (buffer_length) {
|
||||
*buffer_length = tag.len_value_type;
|
||||
}
|
||||
apdu_len += len;
|
||||
} else {
|
||||
apdu_len = BACNET_STATUS_ERROR;
|
||||
@@ -2488,6 +2493,7 @@ int bacnet_octet_string_buffer_application_decode(
|
||||
* or NULL for length only.
|
||||
* @param buffer_size - number of bytes in the buffer where the
|
||||
* decoded value is stored
|
||||
* @param buffer_length - number of bytes decoded into the buffer
|
||||
*
|
||||
* @return number of bytes decoded, or zero if tag mismatch, or
|
||||
* #BACNET_STATUS_ERROR (-1) if malformed
|
||||
@@ -2497,7 +2503,8 @@ int bacnet_octet_string_buffer_context_decode(
|
||||
uint32_t apdu_size,
|
||||
uint8_t tag_value,
|
||||
uint8_t *buffer,
|
||||
size_t buffer_size)
|
||||
size_t buffer_size,
|
||||
uint32_t *buffer_length)
|
||||
{
|
||||
int apdu_len = BACNET_STATUS_ERROR;
|
||||
int len = 0;
|
||||
@@ -2514,6 +2521,9 @@ int bacnet_octet_string_buffer_context_decode(
|
||||
&apdu[apdu_len], apdu_size - apdu_len, tag.len_value_type,
|
||||
buffer, buffer_size);
|
||||
if (len >= 0) {
|
||||
if (buffer_length) {
|
||||
*buffer_length = tag.len_value_type;
|
||||
}
|
||||
apdu_len += len;
|
||||
} else {
|
||||
apdu_len = BACNET_STATUS_ERROR;
|
||||
|
||||
@@ -433,14 +433,16 @@ int bacnet_octet_string_buffer_application_decode(
|
||||
const uint8_t *apdu,
|
||||
uint32_t apdu_size,
|
||||
uint8_t *buffer,
|
||||
size_t buffer_size);
|
||||
size_t buffer_size,
|
||||
uint32_t *buffer_length);
|
||||
BACNET_STACK_EXPORT
|
||||
int bacnet_octet_string_buffer_context_decode(
|
||||
const uint8_t *apdu,
|
||||
uint32_t apdu_size,
|
||||
uint8_t tag_value,
|
||||
uint8_t *buffer,
|
||||
size_t buffer_size);
|
||||
size_t buffer_size,
|
||||
uint32_t *buffer_length);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
int encode_octet_string(uint8_t *apdu, const BACNET_OCTET_STRING *octet_string);
|
||||
|
||||
@@ -125,6 +125,28 @@ void bacnet_recipient_address_set(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Inspect the BACnetRecipient data structure for valid router address
|
||||
* @param recipient - BACnetRecipient structure
|
||||
* @return true if BACnetRecipient is a valid address
|
||||
*/
|
||||
bool bacnet_recipient_address_router_unknown(const BACNET_RECIPIENT *recipient)
|
||||
{
|
||||
bool status = false;
|
||||
|
||||
if (recipient) {
|
||||
if ((recipient->tag == BACNET_RECIPIENT_TAG_ADDRESS) &&
|
||||
(recipient->type.address.net != 0) &&
|
||||
(recipient->type.address.net != BACNET_BROADCAST_NETWORK) &&
|
||||
(recipient->type.address.len != 0) &&
|
||||
(recipient->type.address.mac_len == 0)) {
|
||||
status = true;
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Copy the BACnetRecipient complex data from src to dest
|
||||
* @param src - BACnetRecipient 1 structure
|
||||
|
||||
@@ -98,6 +98,8 @@ void bacnet_recipient_copy(BACNET_RECIPIENT *dest, const BACNET_RECIPIENT *src);
|
||||
BACNET_STACK_EXPORT
|
||||
bool bacnet_recipient_same(
|
||||
const BACNET_RECIPIENT *r1, const BACNET_RECIPIENT *r2);
|
||||
BACNET_STACK_EXPORT
|
||||
bool bacnet_recipient_address_router_unknown(const BACNET_RECIPIENT *recipient);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
void bacnet_recipient_device_wildcard_set(BACNET_RECIPIENT *recipient);
|
||||
|
||||
@@ -90,6 +90,33 @@ void Notification_Class_Writable_Property_List(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Handle I-Am router to network for out of network recipients
|
||||
* @param src - source address of the router
|
||||
* @param network - network number of the router
|
||||
*/
|
||||
static void Notification_Class_I_Am_Router_To_Network_Handler(
|
||||
BACNET_ADDRESS *src, uint16_t network)
|
||||
{
|
||||
NOTIFICATION_CLASS_INFO *notification;
|
||||
BACNET_DESTINATION *destination;
|
||||
BACNET_RECIPIENT *recipient;
|
||||
unsigned i, j;
|
||||
|
||||
for (i = 0; i < MAX_NOTIFICATION_CLASSES; i++) {
|
||||
notification = &NC_Info[i];
|
||||
for (j = 0; j < NC_MAX_RECIPIENTS; j++) {
|
||||
destination = ¬ification->Recipient_List[j];
|
||||
recipient = &destination->Recipient;
|
||||
/* update recipient addresses for this network */
|
||||
if ((recipient->tag == BACNET_RECIPIENT_TAG_ADDRESS) &&
|
||||
(recipient->type.address.net == network)) {
|
||||
bacnet_address_router_set(&recipient->type.address, src);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Notification_Class_Init(void)
|
||||
{
|
||||
uint8_t NotifyIdx = 0;
|
||||
@@ -111,6 +138,8 @@ void Notification_Class_Init(void)
|
||||
bacnet_destination_default_init(destination);
|
||||
}
|
||||
}
|
||||
npdu_set_i_am_router_to_network_handler(
|
||||
Notification_Class_I_Am_Router_To_Network_Handler);
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -727,12 +756,11 @@ void Notification_Class_common_reporting_function(
|
||||
"Notification Class[%u]: send notification to ADDR\n",
|
||||
event_data->notificationClass);
|
||||
/* send notification to the address indicated */
|
||||
bacnet_address_copy(&dest, &pBacDest->Recipient.type.address);
|
||||
if (pBacDest->ConfirmedNotify == true) {
|
||||
if (address_get_device_id(&dest, &device_id)) {
|
||||
Send_CEvent_Notify(device_id, event_data);
|
||||
}
|
||||
Send_CEvent_Notify_Address(
|
||||
Event_Buffer, sizeof(Event_Buffer), event_data, &dest);
|
||||
} else {
|
||||
dest = pBacDest->Recipient.type.address;
|
||||
Send_UEvent_Notify(Event_Buffer, event_data, &dest);
|
||||
}
|
||||
}
|
||||
@@ -764,6 +792,9 @@ void Notification_Class_find_recipient(void)
|
||||
address of device is unknown. */
|
||||
Send_WhoIs(device_id, device_id);
|
||||
}
|
||||
} else if (bacnet_recipient_address_router_unknown(recipient)) {
|
||||
Send_Who_Is_Router_To_Network(
|
||||
NULL, recipient->type.address.net);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -683,6 +683,7 @@ int bvlc_broadcast_distribution_table_decode(
|
||||
int len = 0, apdu_len = 0;
|
||||
BACNET_IP_BROADCAST_DISTRIBUTION_TABLE_ENTRY *bdt_entry = NULL;
|
||||
BACNET_HOST_N_PORT_MINIMAL host_n_port = { 0 };
|
||||
uint32_t address_length = 0;
|
||||
|
||||
/* default reject code */
|
||||
if (error_code) {
|
||||
@@ -700,7 +701,6 @@ int bvlc_broadcast_distribution_table_decode(
|
||||
apdu_len += len;
|
||||
bdt_entry->dest_address.port = host_n_port.port;
|
||||
if (host_n_port.tag == BACNET_HOST_ADDRESS_TAG_IP_ADDRESS) {
|
||||
bdt_entry->valid = true;
|
||||
bdt_entry->dest_address.address[0] =
|
||||
host_n_port.host.ip_address.address[0];
|
||||
bdt_entry->dest_address.address[1] =
|
||||
@@ -719,8 +719,13 @@ int bvlc_broadcast_distribution_table_decode(
|
||||
len = bacnet_octet_string_buffer_context_decode(
|
||||
&apdu[apdu_len], apdu_size - apdu_len, 1,
|
||||
bdt_entry->broadcast_mask.address,
|
||||
sizeof(bdt_entry->broadcast_mask.address));
|
||||
sizeof(bdt_entry->broadcast_mask.address), &address_length);
|
||||
if (len > 0) {
|
||||
if (address_length == sizeof(bdt_entry->broadcast_mask.address)) {
|
||||
bdt_entry->valid = true;
|
||||
} else {
|
||||
bdt_entry->valid = false;
|
||||
}
|
||||
apdu_len += len;
|
||||
} else {
|
||||
if (error_code) {
|
||||
|
||||
Reference in New Issue
Block a user