diff --git a/src/bacnet/basic/bbmd/h_bbmd.c b/src/bacnet/basic/bbmd/h_bbmd.c index d79a041e..e53be901 100644 --- a/src/bacnet/basic/bbmd/h_bbmd.c +++ b/src/bacnet/basic/bbmd/h_bbmd.c @@ -37,6 +37,7 @@ #include /* for the standard bool type. */ #include /* for memcpy */ #include "bacnet/bacdcode.h" +#include "bacnet/npdu.h" #include "bacnet/datalink/bip.h" #include "bacnet/datalink/bvlc.h" #include "bacnet/basic/sys/debug.h" @@ -663,6 +664,7 @@ int bvlc_bbmd_disabled_handler(BACNET_IP_ADDRESS *addr, int function_len = 0; uint8_t *pdu = NULL; uint16_t pdu_len = 0; + uint8_t *npdu = NULL; uint16_t npdu_len = 0; bool send_result = false; uint16_t offset = 0; @@ -765,8 +767,20 @@ int bvlc_bbmd_disabled_handler(BACNET_IP_ADDRESS *addr, if (function_len) { bvlc_ip_address_to_bacnet_local(src, addr); offset = header_len + function_len - npdu_len; - debug_print_npdu( - "Original-Broadcast-NPDU", offset, npdu_len); + /* BTL test: verifies that the IUT will quietly discard any + Confirmed-Request-PDU, whose destination address is a + multicast or broadcast address, received from the + network layer. */ + npdu = &mtu[offset]; + if (npdu_confirmed_service(npdu, npdu_len)) { + offset = 0; + debug_print_string( + "Original-Broadcast-NPDU: " + "Confirmed Service! Discard!"); + } else { + debug_print_npdu( + "Original-Broadcast-NPDU", offset, npdu_len); + } } else { debug_print_string( "Original-Broadcast-NPDU: Unable to decode!"); @@ -1075,9 +1089,21 @@ int bvlc_bbmd_enabled_handler(BACNET_IP_ADDRESS *addr, shall be sent directly to each foreign device currently in the BBMD's FDT also using the BVLL Forwarded-NPDU message. */ npdu = &mtu[offset]; - bbmd_fdt_forward_npdu(addr, npdu, npdu_len, true); - bbmd_bdt_forward_npdu(addr, npdu, npdu_len, true); - debug_print_npdu("Original-Broadcast-NPDU", offset, npdu_len); + /* BTL test: verifies that the IUT will quietly discard any + Confirmed-Request-PDU, whose destination address is a + multicast or broadcast address, received from the + network layer. */ + if (npdu_confirmed_service(npdu, npdu_len)) { + offset = 0; + debug_print_string( + "Original-Broadcast-NPDU: " + "Confirmed Service! Discard!"); + } else { + bbmd_fdt_forward_npdu(addr, npdu, npdu_len, true); + bbmd_bdt_forward_npdu(addr, npdu, npdu_len, true); + debug_print_npdu("Original-Broadcast-NPDU", + offset, npdu_len); + } } else { debug_print_string( "Original-Broadcast-NPDU: Unable to decode!"); diff --git a/src/bacnet/basic/bbmd6/h_bbmd6.c b/src/bacnet/basic/bbmd6/h_bbmd6.c index 89a5fb4d..d5786387 100644 --- a/src/bacnet/basic/bbmd6/h_bbmd6.c +++ b/src/bacnet/basic/bbmd6/h_bbmd6.c @@ -615,6 +615,7 @@ int bvlc6_bbmd_disabled_handler(BACNET_IP6_ADDRESS *addr, int function_len = 0; uint8_t *pdu = NULL; uint16_t pdu_len = 0; + uint8_t *npdu = NULL; uint16_t npdu_len = 0; bool send_result = false; uint16_t offset = 0; @@ -696,6 +697,18 @@ int bvlc6_bbmd_disabled_handler(BACNET_IP6_ADDRESS *addr, bbmd6_add_vmac(vmac_src, addr); bvlc6_vmac_address_set(src, vmac_src); offset = header_len + (function_len - npdu_len); + /* BTL test: verifies that the IUT will quietly + discard any Confirmed-Request-PDU, whose + destination address is a multicast or + broadcast address, received from the + network layer. */ + npdu = &mtu[offset]; + if (npdu_confirmed_service(npdu, npdu_len)) { + offset = 0; + debug_printf( + "BIP6: Original-Broadcast-NPDU: " + "Confirmed Service! Discard!"); + } } else { debug_printf("BIP6: Original-Broadcast-NPDU: Unable to " "decode!\n"); @@ -853,18 +866,30 @@ int bvlc6_bbmd_enabled_handler(BACNET_IP6_ADDRESS *addr, if (function_len) { offset = header_len + (function_len - npdu_len); npdu = &mtu[offset]; - /* Upon receipt of a BVLL Original-Broadcast-NPDU - message from the local multicast domain, a BBMD - shall construct a BVLL Forwarded-NPDU message and - unicast it to each entry in its BDT. In addition, - the constructed BVLL Forwarded-NPDU message shall - be unicast to each foreign device currently in - the BBMD's FDT */ - BVLC6_Buffer_Len = bvlc6_encode_forwarded_npdu( - &BVLC6_Buffer[0], sizeof(BVLC6_Buffer), vmac_src, addr, - npdu, npdu_len); - bbmd6_send_pdu_bdt(&BVLC6_Buffer[0], BVLC6_Buffer_Len); - bbmd6_send_pdu_fdt(&BVLC6_Buffer[0], BVLC6_Buffer_Len); + /* BTL test: verifies that the IUT will quietly + discard any Confirmed-Request-PDU, whose + destination address is a multicast or + broadcast address, received from the + network layer. */ + if (npdu_confirmed_service(npdu, npdu_len)) { + offset = 0; + debug_printf( + "BIP6: Original-Broadcast-NPDU: " + "Confirmed Service! Discard!"); + } else { + /* Upon receipt of a BVLL Original-Broadcast-NPDU + message from the local multicast domain, a BBMD + shall construct a BVLL Forwarded-NPDU message and + unicast it to each entry in its BDT. In addition, + the constructed BVLL Forwarded-NPDU message shall + be unicast to each foreign device currently in + the BBMD's FDT */ + BVLC6_Buffer_Len = bvlc6_encode_forwarded_npdu( + &BVLC6_Buffer[0], sizeof(BVLC6_Buffer), vmac_src, + addr, npdu, npdu_len); + bbmd6_send_pdu_bdt(&BVLC6_Buffer[0], BVLC6_Buffer_Len); + bbmd6_send_pdu_fdt(&BVLC6_Buffer[0], BVLC6_Buffer_Len); + } if (!bbmd6_address_match_self(addr)) { /* The Virtual MAC address table shall be updated using the respective parameter values of the diff --git a/src/bacnet/datalink/datalink.h b/src/bacnet/datalink/datalink.h index ceae524a..a99a49bc 100644 --- a/src/bacnet/datalink/datalink.h +++ b/src/bacnet/datalink/datalink.h @@ -84,6 +84,7 @@ void routed_get_my_address( #elif defined(BACDL_BIP6) #include "bacnet/datalink/bip6.h" #include "bacnet/datalink/bvlc6.h" +#include "bacnet/basic/bbmd6/h_bbmd6.h" #define datalink_init bip6_init #define datalink_send_pdu bip6_send_pdu #define datalink_receive bip6_receive diff --git a/src/bacnet/npdu.c b/src/bacnet/npdu.c index e97bda2e..c9549bea 100644 --- a/src/bacnet/npdu.c +++ b/src/bacnet/npdu.c @@ -501,6 +501,38 @@ int bacnet_npdu_decode(uint8_t *npdu, return len; } +/** + * @brief Helper for datalink detecting an application confirmed service + * @param pdu [in] Buffer containing the NPDU and APDU of the received packet. + * @param pdu_len [in] The size of the received message in the pdu[] buffer. + * @return true if the PDU is a confirmed APDU + */ +bool npdu_confirmed_service( + uint8_t *pdu, + uint16_t pdu_len) +{ + bool status = false; + int apdu_offset = 0; + BACNET_NPDU_DATA npdu_data = { 0 }; + + if (pdu_len > 0) { + if (pdu[0] == BACNET_PROTOCOL_VERSION) { + /* only handle the version that we know how to handle */ + apdu_offset = + bacnet_npdu_decode(&pdu[0], pdu_len, NULL, NULL, &npdu_data); + if ((!npdu_data.network_layer_message) && (apdu_offset > 0) && + (apdu_offset < pdu_len)) { + if ((pdu[apdu_offset] & 0xF0) == + PDU_TYPE_CONFIRMED_SERVICE_REQUEST) { + status = true; + } + } + } + } + + return status; +} + #ifdef BAC_TEST #include #include diff --git a/src/bacnet/npdu.h b/src/bacnet/npdu.h index 010802c2..f7dec868 100644 --- a/src/bacnet/npdu.h +++ b/src/bacnet/npdu.h @@ -103,6 +103,11 @@ extern "C" { BACNET_ADDRESS * src, BACNET_NPDU_DATA * npdu_data); + BACNET_STACK_EXPORT + bool npdu_confirmed_service( + uint8_t *pdu, + uint16_t pdu_len); + #ifdef __cplusplus } #endif /* __cplusplus */