Files
bacnet_stack/src/bacnet/datalink/bvlc6.c
T
Steve Karg eff691aedd Bugfix/codeql initial fixes (#195)
* Fix to BVLC6 bounds checking

* Convert MSTP capture to use datetime library

* Convert timesync app to use datetime and mstimer library

* fix workflow per warning

* fix BSD mstimer init function name

Co-authored-by: Steve Karg <skarg@users.sourceforge.net>
2021-09-17 09:21:26 -05:00

2279 lines
71 KiB
C

/*####COPYRIGHTBEGIN####
-------------------------------------------
Copyright (C) 2015 Steve Karg
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
The Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA.
As a special exception, if other files instantiate templates or
use macros or inline functions from this file, or you compile
this file and link it with other works to produce a work based
on this file, this file does not by itself cause the resulting
work to be covered by the GNU General Public License. However
the source code for this file must still be made available in
accordance with section (3) of the GNU General Public License.
This exception does not invalidate any other reasons why a work
based on this file might be covered by the GNU General Public
License.
-------------------------------------------
####COPYRIGHTEND####*/
#include <stdint.h> /* for standard integer types uint8_t etc. */
#include <stdbool.h> /* for the standard bool type. */
#include "bacnet/bacenum.h"
#include "bacnet/bacdcode.h"
#include "bacnet/bacint.h"
#include "bacnet/datalink/bvlc6.h"
/** Encode the BVLC header
*
* @param pdu - buffer to store the encoding
* @param pdu_size - size of the buffer to store encoding
* @param message_type - BVLL Messages
* @param length - number of bytes for this message type
*
* @return number of bytes encoded
*/
int bvlc6_encode_header(
uint8_t *pdu, uint16_t pdu_size, uint8_t message_type, uint16_t length)
{
int bytes_encoded = 0;
if (pdu && (pdu_size >= 2)) {
pdu[0] = BVLL_TYPE_BACNET_IP6;
pdu[1] = message_type;
/* The 2-octet BVLC Length field is the length, in octets,
of the entire BVLL message, including the two octets of the
length field itself, most significant octet first. */
encode_unsigned16(&pdu[2], length);
bytes_encoded = 4;
}
return bytes_encoded;
}
/** Decode the BVLC Result message
*
* @param pdu - buffer from which to decode the message
* @param pdu_len - length of the buffer that needs decoding
* @param message_type - BVLL Messages
* @param length - number of bytes for this message type
*
* @return number of bytes decoded
*/
int bvlc6_decode_header(
uint8_t *pdu, uint16_t pdu_len, uint8_t *message_type, uint16_t *length)
{
int bytes_consumed = 0;
if (pdu && (pdu_len >= 4)) {
if (pdu[0] == BVLL_TYPE_BACNET_IP6) {
if (message_type) {
*message_type = pdu[1];
}
if (length) {
decode_unsigned16(&pdu[2], length);
}
bytes_consumed = 4;
}
}
return bytes_consumed;
}
/** Encode the BVLC Result message
*
* This message provides a mechanism to acknowledge the result
* of those BVLL service requests that require an acknowledgment,
* whether successful (ACK) or unsuccessful (NAK).
*
* @param pdu - buffer to store the encoding
* @param pdu_size - size of the buffer to store encoding
* @param result_code - BVLC result code
*
* @return number of bytes encoded
*
* BVLC Type: 1-octet X'82' BVLL for BACnet/IPv6
* BVLC Function: 1-octet X'00' BVLC-Result
* BVLC Length: 2-octets X'0009' Length of the BVLL message
* Source-Virtual-Address 3-octets
* Result Code: 2-octets X'0000' Successful completion
* X'0030' Address-Resolution NAK
* X'0060' Virtual-Address-Resolution NAK
* X'0090' Register-Foreign-Device NAK
* X'00A0' Delete-Foreign-Device-Table-Entry
* NAK X'00C0' Distribute-Broadcast-To-Network NAK
*/
int bvlc6_encode_result(
uint8_t *pdu, uint16_t pdu_size, uint32_t vmac, uint16_t result_code)
{
int bytes_encoded = 0;
const uint16_t length = 9;
if (pdu && (pdu_size >= 9) && (vmac <= 0xFFFFFF)) {
bytes_encoded =
bvlc6_encode_header(pdu, pdu_size, BVLC6_RESULT, length);
if (bytes_encoded == 4) {
encode_unsigned24(&pdu[4], vmac);
encode_unsigned16(&pdu[7], result_code);
bytes_encoded = (int)length;
}
}
return bytes_encoded;
}
/** Decode the BVLC Result message
*
* @param pdu - buffer from which to decode the message
* @param pdu_len - length of the buffer that needs decoding
* @param vmac - Virtual MAC address
* @param result_code - BVLC result code
*
* @return number of bytes decoded
*/
int bvlc6_decode_result(
uint8_t *pdu, uint16_t pdu_len, uint32_t *vmac, uint16_t *result_code)
{
int bytes_consumed = 0;
if (pdu && (pdu_len >= 5)) {
if (vmac) {
decode_unsigned24(&pdu[0], vmac);
}
if (result_code) {
decode_unsigned16(&pdu[3], result_code);
}
bytes_consumed = 5;
}
return bytes_consumed;
}
/** Encode the BVLC Original-Unicast-NPDU message
*
* This message is used to send directed NPDUs to another B/IPv6 node
* or router.
*
* @param pdu - buffer to store the encoding
* @param pdu_size - size of the buffer to store encoding
* @param vmac_src - Source-Virtual-Address
* @param vmac_dst - Destination-Virtual-Address
* @param npdu - BACnet NPDU buffer
* @param npdu_len - size of the BACnet NPDU buffer
*
* @return number of bytes encoded
*
* BVLC Type: 1-octet X'82' BVLL for BACnet/IPv6
* BVLC Function: 1-octet X'01' Original-Unicast-NPDU
* BVLC Length: 2-octets L Length of the BVLL message
* Source-Virtual-Address: 3-octets
* Destination-Virtual-Address: 3-octets
* BACnet NPDU: Variable length
*/
int bvlc6_encode_original_unicast(uint8_t *pdu,
uint16_t pdu_size,
uint32_t vmac_src,
uint32_t vmac_dst,
uint8_t *npdu,
uint16_t npdu_len)
{
int bytes_encoded = 0;
uint16_t length = 10;
uint16_t i = 0;
length += npdu_len;
if (pdu && (pdu_size >= length) && (vmac_src <= 0xFFFFFF) &&
(vmac_dst <= 0xFFFFFF)) {
bytes_encoded = bvlc6_encode_header(
pdu, pdu_size, BVLC6_ORIGINAL_UNICAST_NPDU, length);
if (bytes_encoded == 4) {
encode_unsigned24(&pdu[4], vmac_src);
encode_unsigned24(&pdu[7], vmac_dst);
if (npdu && length) {
for (i = 0; i < npdu_len; i++) {
pdu[10 + i] = npdu[i];
}
}
bytes_encoded = (int)length;
}
}
return bytes_encoded;
}
/** Decode the BVLC Original-Unicast-NPDU message
*
* @param pdu - buffer from which to decode the message
* @param pdu_len - length of the buffer that needs decoding
* @param vmac_src - Source-Virtual-Address
* @param vmac_dst - Destination-Virtual-Address
* @param npdu - BACnet NPDU buffer
* @param npdu_size - size of the buffer for the decoded BACnet NPDU
* @param npdu_len - decoded length of the BACnet NPDU buffer
*
* @return number of bytes decoded
*/
int bvlc6_decode_original_unicast(uint8_t *pdu,
uint16_t pdu_len,
uint32_t *vmac_src,
uint32_t *vmac_dst,
uint8_t *npdu,
uint16_t npdu_size,
uint16_t *npdu_len)
{
int bytes_consumed = 0;
uint16_t length = 0;
uint16_t i = 0;
if (pdu && (pdu_len >= 6)) {
if (vmac_src) {
decode_unsigned24(&pdu[0], vmac_src);
}
if (vmac_dst) {
decode_unsigned24(&pdu[3], vmac_dst);
}
length = pdu_len - 6;
if (npdu && length && (length <= npdu_size)) {
for (i = 0; i < length; i++) {
npdu[i] = pdu[6 + i];
}
}
if (npdu_len) {
*npdu_len = length;
}
bytes_consumed = (int)pdu_len;
}
return bytes_consumed;
}
/** Encode the BVLC Original-Broadcast-NPDU message
*
* This message is used by B/IPv6 nodes which are not
* foreign devices to broadcast NPDUs on a B/IPv6 network.
*
* @param pdu - buffer to store the encoding
* @param pdu_size - size of the buffer to store encoding
* @param vmac - Source-Virtual-Address
* @param npdu - BACnet NPDU buffer
* @param npdu_len - size of the BACnet NPDU buffer
*
* @return number of bytes encoded
*
* BVLC Type: 1-octet X'82' BVLL for BACnet/IPv6
* BVLC Function: 1-octet X'02' Original-Broadcast-NPDU
* BVLC Length: 2-octets L Length of the BVLL message
* Source-Virtual-Address: 3-octets
* BACnet NPDU: Variable length
*/
int bvlc6_encode_original_broadcast(uint8_t *pdu,
uint16_t pdu_size,
uint32_t vmac,
uint8_t *npdu,
uint16_t npdu_len)
{
int bytes_encoded = 0;
uint16_t length = 7;
uint16_t i = 0;
length += npdu_len;
if (pdu && (pdu_size >= length) && (vmac <= 0xFFFFFF)) {
bytes_encoded = bvlc6_encode_header(
pdu, pdu_size, BVLC6_ORIGINAL_BROADCAST_NPDU, length);
if (bytes_encoded == 4) {
encode_unsigned24(&pdu[4], vmac);
if (npdu && npdu_len) {
for (i = 0; i < npdu_len; i++) {
pdu[7 + i] = npdu[i];
}
}
bytes_encoded = (int)length;
}
}
return bytes_encoded;
}
/** Decode the BVLC Original-Broadcast-NPDU message
*
* @param pdu - buffer from which to decode the message
* @param pdu_len - length of the buffer that needs decoding
* @param vmac - decoded Source-Virtual-Address
* @param npdu - buffer to copy the decoded BACnet NDPU
* @param npdu_size - size of the buffer for the decoded BACnet NPDU
* @param npdu_len - decoded length of the BACnet NPDU
*
* @return number of bytes decoded
*/
int bvlc6_decode_original_broadcast(uint8_t *pdu,
uint16_t pdu_len,
uint32_t *vmac,
uint8_t *npdu,
uint16_t npdu_size,
uint16_t *npdu_len)
{
int bytes_consumed = 0;
uint16_t length = 0;
uint16_t i = 0;
if (pdu && (pdu_len >= 3)) {
if (vmac) {
decode_unsigned24(&pdu[0], vmac);
}
length = pdu_len - 3;
if (npdu && length && (length <= npdu_size)) {
for (i = 0; i < length; i++) {
npdu[i] = pdu[3 + i];
}
}
if (npdu_len) {
*npdu_len = length;
}
bytes_consumed = (int)pdu_len;
}
return bytes_consumed;
}
/** Encode the BVLC Address-Resolution message
*
* This message is unicast by B/IPv6 BBMDs to determine
* the B/IPv6 address of a known virtual address belonging to
* a different multicast domain.
*
* @param pdu - buffer to store the encoding
* @param pdu_size - size of the buffer to store encoding
* @param vmac_src - Source-Virtual-Address
* @param vmac_target - Target-Virtual-Address
*
* @return number of bytes encoded
*
* BVLC Type: 1-octet X'82' BVLL for BACnet/IPv6
* BVLC Function: 1-octet X'03' Address-Resolution
* BVLC Length: 2-octets X'000A' Length of the BVLL message
* Source-Virtual-Address: 3-octets
* Target-Virtual-Address: 3-octets
*/
int bvlc6_encode_address_resolution(
uint8_t *pdu, uint16_t pdu_size, uint32_t vmac_src, uint32_t vmac_target)
{
int bytes_encoded = 0;
uint16_t length = 10;
if (pdu && (pdu_size >= length) && (vmac_src <= 0xFFFFFF) &&
(vmac_target <= 0xFFFFFF)) {
bytes_encoded = bvlc6_encode_header(
pdu, pdu_size, BVLC6_ADDRESS_RESOLUTION, length);
if (bytes_encoded == 4) {
encode_unsigned24(&pdu[4], vmac_src);
encode_unsigned24(&pdu[7], vmac_target);
bytes_encoded = (int)length;
}
}
return bytes_encoded;
}
/** Decode the BVLC Address-Resolution message
*
* @param pdu - buffer from which to decode the message
* @param pdu_len - length of the buffer that needs decoding
* @param vmac_src - Source-Virtual-Address
* @param vmac_target - Target-Virtual-Address
*
* @return number of bytes decoded
*/
int bvlc6_decode_address_resolution(
uint8_t *pdu, uint16_t pdu_len, uint32_t *vmac_src, uint32_t *vmac_target)
{
int bytes_consumed = 0;
if (pdu && (pdu_len >= 6)) {
if (vmac_src) {
decode_unsigned24(&pdu[0], vmac_src);
}
if (vmac_target) {
decode_unsigned24(&pdu[3], vmac_target);
}
bytes_consumed = 6;
}
return bytes_consumed;
}
/** Encode the BVLC Address
*
* Data link layer addressing between B/IPv6 nodes consists of a 128-bit
* IPv6 address followed by a two-octet UDP port number (both of which
* shall be transmitted with the most significant octet first). This
* address shall be referred to as a B/IPv6 address.
*
* @param pdu - buffer to store the encoding
* @param pdu_size - size of the buffer to store encoding
* @param bip6_address - B/IPv6 address
*
* @return number of bytes encoded
*/
int bvlc6_encode_address(
uint8_t *pdu, uint16_t pdu_size, BACNET_IP6_ADDRESS *bip6_address)
{
int bytes_encoded = 0;
uint16_t length = BIP6_ADDRESS_MAX;
unsigned i = 0;
if (pdu && (pdu_size >= length) && bip6_address) {
for (i = 0; i < IP6_ADDRESS_MAX; i++) {
pdu[i] = bip6_address->address[i];
}
encode_unsigned16(&pdu[IP6_ADDRESS_MAX], bip6_address->port);
bytes_encoded = (int)length;
}
return bytes_encoded;
}
/** Decode the BVLC Address-Resolution message
*
* @param pdu - buffer from which to decode the message
* @param pdu_len - length of the buffer that needs decoding
* @param bip6_address - B/IPv6 address
*
* @return number of bytes decoded
*/
int bvlc6_decode_address(
uint8_t *pdu, uint16_t pdu_len, BACNET_IP6_ADDRESS *bip6_address)
{
int bytes_consumed = 0;
uint16_t length = BIP6_ADDRESS_MAX;
unsigned i = 0;
if (pdu && (pdu_len >= length) && bip6_address) {
for (i = 0; i < IP6_ADDRESS_MAX; i++) {
bip6_address->address[i] = pdu[i];
}
decode_unsigned16(&pdu[IP6_ADDRESS_MAX], &bip6_address->port);
bytes_consumed = (int)length;
}
return bytes_consumed;
}
/** Copy the BVLC Address
*
* Data link layer addressing between B/IPv6 nodes consists of a 128-bit
* IPv6 address followed by a two-octet UDP port number (both of which
* shall be transmitted with the most significant octet first). This
* address shall be referred to as a B/IPv6 address.
*
* @param dst - B/IPv6 address that will be filled with src
* @param src - B/IPv6 address that will be copied into dst
*
* @return true if the address was copied
*/
bool bvlc6_address_copy(BACNET_IP6_ADDRESS *dst, BACNET_IP6_ADDRESS *src)
{
bool status = false;
unsigned int i = 0;
if (src && dst) {
for (i = 0; i < IP6_ADDRESS_MAX; i++) {
dst->address[i] = src->address[i];
}
dst->port = src->port;
status = true;
}
return status;
}
/** Compare the BVLC Address
*
* Data link layer addressing between B/IPv6 nodes consists of a 128-bit
* IPv6 address followed by a two-octet UDP port number (both of which
* shall be transmitted with the most significant octet first). This
* address shall be referred to as a B/IPv6 address.
*
* @param dst - B/IPv6 address that will be compared to src
* @param src - B/IPv6 address that will be compared to dst
*
* @return true if the addresses are different
*/
bool bvlc6_address_different(BACNET_IP6_ADDRESS *dst, BACNET_IP6_ADDRESS *src)
{
bool status = false;
unsigned int i = 0;
if (src && dst) {
for (i = 0; i < IP6_ADDRESS_MAX; i++) {
if (dst->address[i] != src->address[i]) {
status = true;
}
}
if (dst->port != src->port) {
status = true;
}
}
return status;
}
/** Set a BVLC Address from 16-bit group chunks
*
* Data link layer addressing between B/IPv6 nodes consists of a 128-bit
* IPv6 address followed by a two-octet UDP port number (both of which
* shall be transmitted with the most significant octet first). This
* address shall be referred to as a B/IPv6 address.
*
* @param addr - B/IPv6 address that be set
* @param addr0 - B/IPv6 address 16-bit
* @param addr1 - B/IPv6 address bytes
* @param addr2 - B/IPv6 address bytes
* @param addr3 - B/IPv6 address bytes
* @param addr4 - B/IPv6 address bytes
* @param addr5 - B/IPv6 address bytes
* @param addr6 - B/IPv6 address bytes
* @param addr7 - B/IPv6 address bytes
*
* @return true if the address is set
*/
bool bvlc6_address_set(BACNET_IP6_ADDRESS *addr,
uint16_t addr0,
uint16_t addr1,
uint16_t addr2,
uint16_t addr3,
uint16_t addr4,
uint16_t addr5,
uint16_t addr6,
uint16_t addr7)
{
bool status = false;
if (addr) {
encode_unsigned16(&addr->address[0], addr0);
encode_unsigned16(&addr->address[2], addr1);
encode_unsigned16(&addr->address[4], addr2);
encode_unsigned16(&addr->address[6], addr3);
encode_unsigned16(&addr->address[8], addr4);
encode_unsigned16(&addr->address[10], addr5);
encode_unsigned16(&addr->address[12], addr6);
encode_unsigned16(&addr->address[14], addr7);
status = true;
}
return status;
}
/** Get a BVLC Address into 16-bit group chunks
*
* Data link layer addressing between B/IPv6 nodes consists of a 128-bit
* IPv6 address followed by a two-octet UDP port number (both of which
* shall be transmitted with the most significant octet first). This
* address shall be referred to as a B/IPv6 address.
*
* @param addr - B/IPv6 address that be set
* @param addr0 - B/IPv6 address 16-bit
* @param addr1 - B/IPv6 address bytes
* @param addr2 - B/IPv6 address bytes
* @param addr3 - B/IPv6 address bytes
* @param addr4 - B/IPv6 address bytes
* @param addr5 - B/IPv6 address bytes
* @param addr6 - B/IPv6 address bytes
* @param addr7 - B/IPv6 address bytes
*
* @return true if the address is set
*/
bool bvlc6_address_get(BACNET_IP6_ADDRESS *addr,
uint16_t *addr0,
uint16_t *addr1,
uint16_t *addr2,
uint16_t *addr3,
uint16_t *addr4,
uint16_t *addr5,
uint16_t *addr6,
uint16_t *addr7)
{
bool status = false;
if (addr) {
if (addr0) {
decode_unsigned16(&addr->address[0], addr0);
}
if (addr1) {
decode_unsigned16(&addr->address[2], addr1);
}
if (addr2) {
decode_unsigned16(&addr->address[4], addr2);
}
if (addr3) {
decode_unsigned16(&addr->address[6], addr3);
}
if (addr4) {
decode_unsigned16(&addr->address[8], addr4);
}
if (addr5) {
decode_unsigned16(&addr->address[10], addr5);
}
if (addr6) {
decode_unsigned16(&addr->address[12], addr6);
}
if (addr7) {
decode_unsigned16(&addr->address[14], addr7);
}
status = true;
}
return status;
}
/** Convert IPv6 Address from ASCII
*
* IPv6 addresses are represented as eight groups, separated by colons,
* of four hexadecimal digits.
*
* For convenience, an IPv6 address may be abbreviated to shorter notations
* by application of the following rules.
* - One or more leading zeros from any groups of hexadecimal digits
* are removed; this is usually done to either all or none of the
* leading zeros. For example, the group 0042 is converted to 42.
* - Consecutive sections of zeros are replaced with a double colon (::).
* The double colon may only be used once in an address, as multiple
* use would render the address indeterminate. RFC 5952 requires that
* a double colon not be used to denote an omitted single section of
* zeros.
*
* Adapted from the uIP TCP/IP stack and the Contiki operating system.
* Thank you, Adam Dunkel, and the Swedish Institute of Computer Science.
*
* @param addr - B/IPv6 address that is set
* @param addrstr - B/IPv6 address in 16-bit ASCII hex compressed format
*
* @return true if a valid address was set
*/
bool bvlc6_address_from_ascii(BACNET_IP6_ADDRESS *addr, const char *addrstr)
{
uint16_t value = 0;
int tmp, zero = -1;
unsigned int len = 0;
unsigned int i = 0;
char c = 0;
if (!addrstr) {
return false;
}
if (!addrstr) {
return false;
}
if (*addrstr == '[') {
addrstr++;
}
for (len = 0; len < IP6_ADDRESS_MAX - 1; addrstr++) {
c = *addrstr;
if (c == ':' || c == '\0' || c == ']' || c == '/') {
addr->address[len] = (value >> 8) & 0xff;
addr->address[len + 1] = value & 0xff;
len += 2;
value = 0;
if (c == '\0' || c == ']' || c == '/') {
break;
}
if (*(addrstr + 1) == ':') {
/* Zero compression */
if (zero < 0) {
zero = len;
}
addrstr++;
}
} else {
if (c >= '0' && c <= '9') {
tmp = c - '0';
} else if (c >= 'a' && c <= 'f') {
tmp = c - 'a' + 10;
} else if (c >= 'A' && c <= 'F') {
tmp = c - 'A' + 10;
} else {
/* illegal char! */
return false;
}
value = (value << 4) + (tmp & 0xf);
}
}
if (c != '\0' && c != ']' && c != '/') {
/* expected termination. too long! */
return false;
}
if (len < IP6_ADDRESS_MAX) {
uint8_t addr_end[IP6_ADDRESS_MAX];
if (zero < 0) {
/* too short address! */
return false;
}
/* move end address values from zero position to end position */
for (i = 0; i < len - zero; i++) {
addr_end[i] = addr->address[zero + i];
}
for (i = 0; i < len - zero; i++) {
addr->address[zero + IP6_ADDRESS_MAX - len + i] = addr_end[i];
}
/* fill in middle zero values */
for (i = 0; i < (IP6_ADDRESS_MAX - len); i++) {
addr->address[zero + i] = 0;
}
}
/* note: should we look for []:BAC0 UDP port number? */
return true;
}
/** Set a BACnet VMAC Address from a Device ID
*
* @param addr - BACnet address that be set
* @param device_id - 22-bit device ID
*
* @return true if the address is set
*/
bool bvlc6_vmac_address_set(BACNET_ADDRESS *addr, uint32_t device_id)
{
bool status = false;
if (addr) {
encode_unsigned24(&addr->mac[0], device_id);
addr->mac_len = 3;
addr->net = 0;
addr->len = 0;
status = true;
}
return status;
}
/** Get a BACnet VMAC Address from a Device ID
*
* @param addr - BACnet address that be set
* @param device_id - 22-bit device ID
*
* @return true if the address is set
*/
bool bvlc6_vmac_address_get(BACNET_ADDRESS *addr, uint32_t *device_id)
{
bool status = false;
if (addr && device_id) {
if (addr->mac_len == 3) {
decode_unsigned24(&addr->mac[0], device_id);
status = true;
}
}
return status;
}
/** Encode the BVLC Forwarded-Address-Resolution message
*
* This message is unicast by B/IPv6 BBMDs to determine
* the B/IPv6 address of a known virtual address belonging to
* a different multicast domain.
*
* @param pdu - buffer to store the encoding
* @param pdu_size - size of the buffer to store encoding
* @param vmac_src - Source-Virtual-Address
* @param vmac_target - Target-Virtual-Address
* @param bip6_address - Original-Source-B/IPv6-Address
*
* @return number of bytes encoded
*
* BVLC Type: 1-octet X'82' BVLL for BACnet/IPv6
* BVLC Function: 1-octet X'04' Forwarded-Address-Resolution
* BVLC Length: 2-octets X'001C' Length of this message
* Original-Source-Virtual-Address: 3-octets
* Target-Virtual-Address: 3-octets
* Original-Source-B/IPv6-Address 18-octets
*/
int bvlc6_encode_forwarded_address_resolution(uint8_t *pdu,
uint16_t pdu_size,
uint32_t vmac_src,
uint32_t vmac_target,
BACNET_IP6_ADDRESS *bip6_address)
{
int bytes_encoded = 0;
uint16_t length = 0x001C;
uint16_t offset = 0;
if (pdu && (pdu_size >= length) && (vmac_src <= 0xFFFFFF) &&
(vmac_target <= 0xFFFFFF) && bip6_address) {
bytes_encoded = bvlc6_encode_header(
pdu, pdu_size, BVLC6_FORWARDED_ADDRESS_RESOLUTION, length);
if (bytes_encoded == 4) {
offset = 4;
encode_unsigned24(&pdu[offset], vmac_src);
offset += 3;
encode_unsigned24(&pdu[offset], vmac_target);
offset += 3;
bvlc6_encode_address(&pdu[offset], pdu_size - offset, bip6_address);
bytes_encoded = (int)length;
}
}
return bytes_encoded;
}
/** Decode the BVLC Forwarded-Address-Resolution message
*
* @param pdu - buffer from which to decode the message
* @param pdu_len - length of the buffer that needs decoding
* @param vmac_src - Source-Virtual-Address
* @param vmac_target - Target-Virtual-Address
* @param bip6_address - Original-Source-B/IPv6-Address
*
* @return number of bytes decoded
*/
int bvlc6_decode_forwarded_address_resolution(uint8_t *pdu,
uint16_t pdu_len,
uint32_t *vmac_src,
uint32_t *vmac_target,
BACNET_IP6_ADDRESS *bip6_address)
{
int bytes_consumed = 0;
const uint16_t length = 3 + 3 + BIP6_ADDRESS_MAX;
uint16_t offset = 0;
if (pdu && (pdu_len >= length)) {
if (vmac_src) {
decode_unsigned24(&pdu[offset], vmac_src);
}
offset += 3;
if (vmac_target) {
decode_unsigned24(&pdu[offset], vmac_target);
}
offset += 3;
if (bip6_address) {
bvlc6_decode_address(&pdu[offset], pdu_len - offset, bip6_address);
}
bytes_consumed = (int)length;
}
return bytes_consumed;
}
/** Encode generic BVLC Address-Ack message
*
* @param pdu - buffer to store the encoding
* @param pdu_size - size of the buffer to store encoding
* @param vmac_src - Source-Virtual-Address
* @param vmac_dst - Destination-Virtual-Address
*
* @return number of bytes encoded
*/
static int bvlc6_encode_address_ack(uint8_t message_type,
uint8_t *pdu,
uint16_t pdu_size,
uint32_t vmac_src,
uint32_t vmac_dst)
{
int bytes_encoded = 0;
const uint16_t length = 10;
uint16_t offset = 0;
if (pdu && (pdu_size >= length) && (vmac_src <= 0xFFFFFF) &&
(vmac_dst <= 0xFFFFFF)) {
bytes_encoded =
bvlc6_encode_header(pdu, pdu_size, message_type, length);
if (bytes_encoded == 4) {
offset = 4;
encode_unsigned24(&pdu[offset], vmac_src);
offset += 3;
encode_unsigned24(&pdu[offset], vmac_dst);
bytes_encoded = (int)length;
}
}
return bytes_encoded;
}
/** Encode the BVLC Address-Resolution-Ack message
*
* This message is the reply to either the Address-Resolution or
* the Forwarded-Address-Resolution messages.
*
* @param pdu - buffer to store the encoding
* @param pdu_size - size of the buffer to store encoding
* @param vmac_src - Source-Virtual-Address
* @param vmac_dst - Destination-Virtual-Address
*
* @return number of bytes encoded
*
* BVLC Type: 1-octet X'82' BVLL for BACnet/IPv6
* BVLC Function: 1-octet X'05' Address-Resolution-Ack
* BVLC Length: 2-octets X'000A' Length of the BVLL message
* Source-Virtual-Address: 3-octets
* Destination-Virtual-Address: 3-octets
*/
int bvlc6_encode_address_resolution_ack(
uint8_t *pdu, uint16_t pdu_size, uint32_t vmac_src, uint32_t vmac_dst)
{
return bvlc6_encode_address_ack(
BVLC6_ADDRESS_RESOLUTION_ACK, pdu, pdu_size, vmac_src, vmac_dst);
}
/** Decode the BVLC Address-Resolution-Ack message
*
* @param pdu - buffer from which to decode the message
* @param pdu_len - length of the buffer that needs decoding
* @param vmac_src - Source-Virtual-Address
* @param vmac_dst - Destination-Virtual-Address
*
* @return number of bytes decoded
*/
int bvlc6_decode_address_resolution_ack(
uint8_t *pdu, uint16_t pdu_len, uint32_t *vmac_src, uint32_t *vmac_dst)
{
int bytes_consumed = 0;
const uint16_t length = 6;
uint16_t offset = 0;
if (pdu && (pdu_len >= length)) {
if (vmac_src) {
decode_unsigned24(&pdu[offset], vmac_src);
}
offset += 3;
if (vmac_dst) {
decode_unsigned24(&pdu[offset], vmac_dst);
}
bytes_consumed = (int)length;
}
return bytes_consumed;
}
/** Encode the BVLC Virtual-Address-Resolution message
*
* This message is unicast by B/IPv6 nodes to determine the
* virtual address of a device with a known B/IPv6 address.
*
* @param pdu - buffer to store the encoding
* @param pdu_size - size of the buffer to store encoding
* @param vmac_src - Source-Virtual-Address
*
* @return number of bytes encoded
*
* BVLC Type: 1-octet X'82' BVLL for BACnet/IPv6
* BVLC Function: 1-octet X'06' Virtual-Address-Resolution
* BVLC Length: 2-octets X'0007' Length of the BVLL message
* Source-Virtual-Address: 3-octets
*/
int bvlc6_encode_virtual_address_resolution(
uint8_t *pdu, uint16_t pdu_size, uint32_t vmac_src)
{
int bytes_encoded = 0;
const uint16_t length = 7;
if (pdu && (pdu_size >= length) && (vmac_src <= 0xFFFFFF)) {
bytes_encoded = bvlc6_encode_header(
pdu, pdu_size, BVLC6_VIRTUAL_ADDRESS_RESOLUTION, length);
if (bytes_encoded == 4) {
encode_unsigned24(&pdu[4], vmac_src);
bytes_encoded = (int)length;
}
}
return bytes_encoded;
}
/** Decode the BVLC Virtual-Address-Resolution message
*
* @param pdu - buffer from which to decode the message
* @param pdu_len - length of the buffer that needs decoding
* @param vmac_src - Source-Virtual-Address
*
* @return number of bytes decoded
*/
int bvlc6_decode_virtual_address_resolution(
uint8_t *pdu, uint16_t pdu_len, uint32_t *vmac_src)
{
int bytes_consumed = 0;
if (pdu && (pdu_len >= 3)) {
if (vmac_src) {
decode_unsigned24(&pdu[0], vmac_src);
}
bytes_consumed = 3;
}
return bytes_consumed;
}
/** Encode the BVLC Virtual-Address-Resolution-Ack message
*
* This message is the reply to the Virtual-Address-Resolution message
*
* @param pdu - buffer to store the encoding
* @param pdu_size - size of the buffer to store encoding
* @param vmac_src - Source-Virtual-Address
* @param vmac_dst - Destination-Virtual-Address
*
* @return number of bytes encoded
*
* BVLC Type: 1-octet X'82' BVLL for BACnet/IPv6
* BVLC Function: 1-octet X'07' Address-Resolution-Ack
* BVLC Length: 2-octets X'000A' Length of the BVLL message
* Source-Virtual-Address: 3-octets
* Destination-Virtual-Address: 3-octets
*/
int bvlc6_encode_virtual_address_resolution_ack(
uint8_t *pdu, uint16_t pdu_size, uint32_t vmac_src, uint32_t vmac_dst)
{
return bvlc6_encode_address_ack(BVLC6_VIRTUAL_ADDRESS_RESOLUTION_ACK, pdu,
pdu_size, vmac_src, vmac_dst);
}
/** Decode the BVLC Virtual-Address-Resolution-Ack message
*
* @param pdu - buffer from which to decode the message
* @param pdu_len - length of the buffer that needs decoding
* @param vmac_src - Source-Virtual-Address
* @param vmac_dst - Destination-Virtual-Address
*
* @return number of bytes decoded
*/
int bvlc6_decode_virtual_address_resolution_ack(
uint8_t *pdu, uint16_t pdu_len, uint32_t *vmac_src, uint32_t *vmac_dst)
{
return bvlc6_decode_address_resolution_ack(
pdu, pdu_len, vmac_src, vmac_dst);
}
/** Encode the BVLC Forwarded-NPDU message
*
* This BVLL message is used in multicast messages from a BBMD
* as well as in messages forwarded to registered foreign
* devices. It contains the source address of the original
* node as well as the original BACnet NPDU.
*
* @param pdu - buffer to store the encoding
* @param pdu_size - size of the buffer to store encoding
* @param vmac_src - Original-Source-Virtual-Address
* @param bip6_address - Original-Source-B/IPv6-Address
* @param npdu - BACnet NPDU from Originating Device buffer
* @param npdu_len - size of the BACnet NPDU buffer
*
* @return number of bytes encoded
*
* BVLC Type: 1-octet X'82' BVLL for BACnet/IPv6
* BVLC Function: 1-octet X'08' Forwarded-NPDU
* BVLC Length: 2-octets L Length of the BVLL message
* Original-Source-Virtual-Address: 3-octets
* Original-Source-B-IPv6-Address: 18-octets
* BACnet NPDU from Originating Device: N-octets (N=L-25)
*/
int bvlc6_encode_forwarded_npdu(uint8_t *pdu,
uint16_t pdu_size,
uint32_t vmac_src,
BACNET_IP6_ADDRESS *bip6_address,
uint8_t *npdu,
uint16_t npdu_len)
{
int bytes_encoded = 0;
uint16_t length = 1 + 1 + 2 + 3 + BIP6_ADDRESS_MAX;
uint16_t i = 0;
uint16_t offset = 0;
length += npdu_len;
if (pdu && (pdu_size >= length) && (vmac_src <= 0xFFFFFF)) {
bytes_encoded =
bvlc6_encode_header(pdu, pdu_size, BVLC6_FORWARDED_NPDU, length);
if (bytes_encoded == 4) {
offset = 4;
encode_unsigned24(&pdu[offset], vmac_src);
offset += 3;
bvlc6_encode_address(&pdu[offset], pdu_size - offset, bip6_address);
offset += BIP6_ADDRESS_MAX;
if (npdu && length) {
for (i = 0; i < npdu_len; i++) {
pdu[offset + i] = npdu[i];
}
}
bytes_encoded = (int)length;
}
}
return bytes_encoded;
}
/** Decode the BVLC Forwarded-NPDU message
*
* @param pdu - buffer from which to decode the message
* @param pdu_len - length of the buffer that needs decoding
* @param vmac_src - Original-Source-Virtual-Address
* @param bip6_address - Original-Source-B/IPv6-Address
* @param npdu - BACnet NPDU buffer
* @param npdu_size - size of the buffer for the decoded BACnet NPDU
* @param npdu_len - decoded length of the BACnet NPDU buffer
*
* @return number of bytes decoded
*/
int bvlc6_decode_forwarded_npdu(uint8_t *pdu,
uint16_t pdu_len,
uint32_t *vmac_src,
BACNET_IP6_ADDRESS *bip6_address,
uint8_t *npdu,
uint16_t npdu_size,
uint16_t *npdu_len)
{
int bytes_consumed = 0;
uint16_t length = 0;
uint16_t i = 0;
const uint16_t address_len = 3 + BIP6_ADDRESS_MAX;
uint16_t offset = 0;
if (pdu && (pdu_len >= address_len)) {
if (vmac_src) {
decode_unsigned24(&pdu[offset], vmac_src);
}
offset += 3;
if (bip6_address) {
bvlc6_decode_address(&pdu[offset], pdu_len - offset, bip6_address);
}
offset += BIP6_ADDRESS_MAX;
length = pdu_len - offset;
if (npdu && length && (length <= npdu_size)) {
for (i = 0; i < length; i++) {
npdu[i] = pdu[offset + i];
}
}
if (npdu_len) {
*npdu_len = length;
}
bytes_consumed = (int)pdu_len;
}
return bytes_consumed;
}
/** Encode the BVLC Register-Foreign-Device message
*
* This message allows a foreign device, as defined in X.4.5.1,
* to register with a BBMD for the purpose of receiving
* broadcast messages.
*
* @param pdu - buffer to store the encoding
* @param pdu_size - size of the buffer to store encoding
* @param vmac_src - Source-Virtual-Address
* @param ttl_seconds - Time-to-Live T, in seconds
*
* @return number of bytes encoded
*
* BVLC Type: 1-octet X'82' BVLL for BACnet/IPv6
* BVLC Function: 1-octet X'09' Register-Foreign-Device
* BVLC Length: 2-octets X'0009' Length of the BVLL message
* Source-Virtual-Address: 3-octets
* Time-to-Live: 2-octets T Time-to-Live T, in seconds
*/
int bvlc6_encode_register_foreign_device(
uint8_t *pdu, uint16_t pdu_size, uint32_t vmac_src, uint16_t ttl_seconds)
{
int bytes_encoded = 0;
const uint16_t length = 9;
uint16_t offset = 0;
if (pdu && (pdu_size >= length) && (vmac_src <= 0xFFFFFF)) {
bytes_encoded = bvlc6_encode_header(
pdu, pdu_size, BVLC6_REGISTER_FOREIGN_DEVICE, length);
if (bytes_encoded == 4) {
offset = 4;
encode_unsigned24(&pdu[offset], vmac_src);
offset += 3;
encode_unsigned16(&pdu[offset], ttl_seconds);
bytes_encoded = (int)length;
}
}
return bytes_encoded;
}
/** Decode the BVLC Register-Foreign-Device message
*
* @param pdu - buffer from which to decode the message
* @param pdu_len - length of the buffer that needs decoding
* @param vmac_src - Source-Virtual-Address
* @param ttl_seconds - Time-to-Live T, in seconds
*
* @return number of bytes decoded
*/
int bvlc6_decode_register_foreign_device(
uint8_t *pdu, uint16_t pdu_len, uint32_t *vmac_src, uint16_t *ttl_seconds)
{
int bytes_consumed = 0;
const uint16_t length = 5;
uint16_t offset = 0;
if (pdu && (pdu_len >= length)) {
if (vmac_src) {
decode_unsigned24(&pdu[offset], vmac_src);
}
offset += 3;
if (ttl_seconds) {
decode_unsigned16(&pdu[offset], ttl_seconds);
}
bytes_consumed = (int)length;
}
return bytes_consumed;
}
/** Encode the BVLC Delete-Foreign-Device message
*
* This message allows a foreign device, as defined in X.4.5.1,
* to register with a BBMD for the purpose of receiving
* broadcast messages.
*
* @param pdu - buffer to store the encoding
* @param pdu_size - size of the buffer to store encoding
* @param vmac_src - Source-Virtual-Address
* @param fdt_entry - FDT Entry
*
* @return number of bytes encoded
*
* BVLC Type: 1-octet X'82' BVLL for BACnet/IPv6
* BVLC Function: 1-octet X'0A' Delete-Foreign-Device
* BVLC Length: 2-octets X'0019' Length of the BVLL message
* Source-Virtual-Address: 3-octets
* FDT Entry: 18-octets The FDT entry is the B/IPv6 address
* of the foreign device to be deleted.
*/
int bvlc6_encode_delete_foreign_device(uint8_t *pdu,
uint16_t pdu_size,
uint32_t vmac_src,
BACNET_IP6_ADDRESS *bip6_address)
{
int bytes_encoded = 0;
const uint16_t length = 0x0019;
uint16_t offset = 0;
if (pdu && (pdu_size >= length) && (vmac_src <= 0xFFFFFF)) {
bytes_encoded = bvlc6_encode_header(
pdu, pdu_size, BVLC6_DELETE_FOREIGN_DEVICE, length);
if (bytes_encoded == 4) {
offset = 4;
encode_unsigned24(&pdu[offset], vmac_src);
offset += 3;
if (bip6_address) {
bvlc6_encode_address(
&pdu[offset], pdu_size - offset, bip6_address);
bytes_encoded = (int)length;
}
}
}
return bytes_encoded;
}
/** Decode the BVLC Delete-Foreign-Device message
*
* @param pdu - buffer from which to decode the message
* @param pdu_len - length of the buffer that needs decoding
* @param vmac_src - Source-Virtual-Address
* @param fdt_entry - The FDT entry is the B/IPv6 address of the
* foreign device to be deleted.
*
* @return number of bytes decoded
*/
int bvlc6_decode_delete_foreign_device(uint8_t *pdu,
uint16_t pdu_len,
uint32_t *vmac_src,
BACNET_IP6_ADDRESS *bip6_address)
{
int bytes_consumed = 0;
/* BVLL length less the header length */
const uint16_t length = 0x0019 - (1 + 1 + 2);
uint16_t offset = 0;
if (pdu && (pdu_len >= length)) {
if (vmac_src) {
decode_unsigned24(&pdu[offset], vmac_src);
bytes_consumed = 3;
}
offset += 3;
if (bip6_address) {
bvlc6_decode_address(&pdu[offset], pdu_len - offset, bip6_address);
}
bytes_consumed = (int)length;
}
return bytes_consumed;
}
/** Encode the BVLC Secure-BVLL message
*
* This message is used to secure BVLL messages that do not contain NPDUs.
* Its use is described in Clause 24.
*
* @param pdu - buffer to store the encoding
* @param pdu_size - size of the buffer to store encoding
* @param sbuf - Security Wrapper buffer
* @param sbuf_len - size of the Security Wrapper buffer
*
* @return number of bytes encoded
*
* BVLC Type: 1-octet X'82' BVLL for BACnet/IPv6
* BVLC Function: 1-octet X'0B' Secure-BVLL
* BVLC Length: 2-octets L Length of the BVLL message
* Security Wrapper: Variable length
*/
int bvlc6_encode_secure_bvll(
uint8_t *pdu, uint16_t pdu_size, uint8_t *sbuf, uint16_t sbuf_len)
{
int bytes_encoded = 0;
uint16_t length = 4;
uint16_t i = 0;
length += sbuf_len;
if (pdu && (pdu_size >= length)) {
bytes_encoded =
bvlc6_encode_header(pdu, pdu_size, BVLC6_SECURE_BVLL, length);
if (bytes_encoded == 4) {
if (sbuf && sbuf_len) {
for (i = 0; i < sbuf_len; i++) {
pdu[4 + i] = sbuf[i];
}
}
bytes_encoded = (int)length;
}
}
return bytes_encoded;
}
/** Decode the BVLC Secure-BVLL message
*
* @param pdu - buffer from which to decode the message
* @param pdu_len - length of the buffer that needs decoding
* @param sbuf - Security Wrapper buffer
* @param sbuf_size - size of the Security Wrapper buffer
* @param sbuf_len - number of bytes decoded into the Security Wrapper buffer
*
* @return number of bytes decoded
*/
int bvlc6_decode_secure_bvll(uint8_t *pdu,
uint16_t pdu_len,
uint8_t *sbuf,
uint16_t sbuf_size,
uint16_t *sbuf_len)
{
int bytes_consumed = 0;
uint16_t i = 0;
if (pdu && sbuf) {
if (sbuf_len) {
*sbuf_len = pdu_len;
}
if (pdu_len) {
for (i = 0; i < pdu_len; i++) {
sbuf[i] = pdu[i];
}
}
bytes_consumed = (int)pdu_len;
}
return bytes_consumed;
}
/** Encode the BVLC Distribute-Broadcast-To-Network message
*
* This message provides a mechanism whereby a foreign device
* shall cause a BBMD to distribute a Forwarded-NPDU
* BVLC to the local multicast domain, to all BBMDs configured
* in the BBMDs BDT, and to all foreign devices in the
* BBMDs FDT.
*
* @param pdu - buffer to store the encoding
* @param pdu_size - size of the buffer to store encoding
* @param vmac - Original-Source-Virtual-Address
* @param npdu - BACnet NPDU from Originating Device buffer
* @param npdu_len - size of the BACnet NPDU buffer
*
* @return number of bytes encoded
*
* BVLC Type: 1-octet X'82' BVLL for BACnet/IPv6
* BVLC Function: 1-octet X'0C' Original-Unicast-NPDU
* BVLC Length: 2-octets L Length of the BVLL message
* Original-Source-Virtual-Address: 3-octets
* BACnet NPDU from Originating Device: Variable length
*/
int bvlc6_encode_distribute_broadcast_to_network(uint8_t *pdu,
uint16_t pdu_size,
uint32_t vmac,
uint8_t *npdu,
uint16_t npdu_len)
{
int bytes_encoded = 0;
uint16_t length = 1 + 1 + 2 + 3;
uint16_t i = 0;
length += npdu_len;
if (pdu && (pdu_size >= length) && (vmac <= 0xFFFFFF)) {
bytes_encoded = bvlc6_encode_header(
pdu, pdu_size, BVLC6_DISTRIBUTE_BROADCAST_TO_NETWORK, length);
if (bytes_encoded == 4) {
encode_unsigned24(&pdu[4], vmac);
if (npdu && (npdu_len > 0)) {
for (i = 0; i < npdu_len; i++) {
pdu[7 + i] = npdu[i];
}
}
bytes_encoded = (int)length;
}
}
return bytes_encoded;
}
/** Decode the BVLC Original-Broadcast-NPDU message
*
* @param pdu - buffer from which to decode the message
* @param pdu_len - length of the buffer that needs decoding
* @param vmac - decoded Original-Source-Virtual-Address
* @param npdu - buffer to copy the decoded BACnet NDPU
* @param npdu_size - size of the buffer for the decoded BACnet NPDU
* @param npdu_len - decoded length of the BACnet NPDU
*
* @return number of bytes decoded
*/
int bvlc6_decode_distribute_broadcast_to_network(uint8_t *pdu,
uint16_t pdu_len,
uint32_t *vmac,
uint8_t *npdu,
uint16_t npdu_size,
uint16_t *npdu_len)
{
int bytes_consumed = 0;
uint16_t length = 0;
uint16_t i = 0;
if (pdu && (pdu_len >= 3)) {
if (vmac) {
decode_unsigned24(&pdu[0], vmac);
}
length = pdu_len - 3;
if (npdu && length && (length <= npdu_size)) {
for (i = 0; i < length; i++) {
npdu[i] = pdu[3 + i];
}
}
if (npdu_len) {
*npdu_len = length;
}
bytes_consumed = (int)pdu_len;
}
return bytes_consumed;
}
#ifdef BAC_TEST
#include <assert.h>
#include <string.h>
#include "ctest.h"
static void test_BVLC6_Address(Test *pTest,
BACNET_IP6_ADDRESS *bip6_address_1,
BACNET_IP6_ADDRESS *bip6_address_2)
{
unsigned i = 0;
if (bip6_address_1 && bip6_address_2) {
ct_test(pTest, bip6_address_1->port == bip6_address_2->port);
for (i = 0; i < IP6_ADDRESS_MAX; i++) {
ct_test(pTest,
bip6_address_1->address[i] == bip6_address_2->address[i]);
}
}
return;
}
static int test_BVLC6_Header(Test *pTest,
uint8_t *pdu,
uint16_t pdu_len,
uint8_t *message_type,
uint16_t *length)
{
int bytes_consumed = 0;
int len = 0;
if (pdu && message_type && length) {
len = bvlc6_decode_header(pdu, pdu_len, message_type, length);
ct_test(pTest, len == 4);
bytes_consumed = len;
}
return bytes_consumed;
}
static void test_BVLC6_Result_Code(
Test *pTest, uint32_t vmac, uint16_t result_code)
{
uint8_t pdu[50] = { 0 };
uint32_t test_vmac = 0;
uint16_t test_result_code = 0;
uint8_t message_type = 0;
uint16_t length = 0;
int len = 0, test_len = 0;
len = bvlc6_encode_result(pdu, sizeof(pdu), vmac, result_code);
ct_test(pTest, len == 9);
test_len = test_BVLC6_Header(pTest, pdu, len, &message_type, &length);
ct_test(pTest, test_len == 4);
ct_test(pTest, message_type == BVLC6_RESULT);
ct_test(pTest, length == 9);
test_len +=
bvlc6_decode_result(&pdu[4], length - 4, &test_vmac, &test_result_code);
ct_test(pTest, len == test_len);
ct_test(pTest, vmac == test_vmac);
ct_test(pTest, result_code == test_result_code);
len = bvlc6_encode_result(pdu, sizeof(pdu), 0xffffff + 1, result_code);
ct_test(pTest, len == 0);
}
static void test_BVLC6_Result(Test *pTest)
{
uint32_t vmac = 0;
uint16_t result_code[6] = { BVLC6_RESULT_SUCCESSFUL_COMPLETION,
BVLC6_RESULT_ADDRESS_RESOLUTION_NAK,
BVLC6_RESULT_VIRTUAL_ADDRESS_RESOLUTION_NAK,
BVLC6_RESULT_REGISTER_FOREIGN_DEVICE_NAK,
BVLC6_RESULT_DELETE_FOREIGN_DEVICE_NAK,
BVLC6_RESULT_DISTRIBUTE_BROADCAST_TO_NETWORK_NAK };
unsigned int i = 0;
vmac = 4194303;
for (i = 0; i < 6; i++) {
test_BVLC6_Result_Code(pTest, vmac, result_code[i]);
}
}
static void test_BVLC6_Original_Unicast_NPDU_Message(Test *pTest,
uint8_t *npdu,
uint16_t npdu_len,
uint32_t vmac_src,
uint32_t vmac_dst)
{
uint8_t test_npdu[50] = { 0 };
uint8_t pdu[60] = { 0 };
uint32_t test_vmac_src = 0;
uint32_t test_vmac_dst = 0;
uint16_t test_npdu_len = 0;
uint8_t message_type = 0;
uint16_t length = 0;
int len = 0, msg_len = 0, test_len = 0;
uint16_t i = 0;
len = bvlc6_encode_original_unicast(
pdu, sizeof(pdu), vmac_src, vmac_dst, npdu, npdu_len);
msg_len = 10 + npdu_len;
ct_test(pTest, len == msg_len);
test_len = test_BVLC6_Header(pTest, pdu, len, &message_type, &length);
ct_test(pTest, test_len == 4);
ct_test(pTest, message_type == BVLC6_ORIGINAL_UNICAST_NPDU);
ct_test(pTest, length == msg_len);
test_len +=
bvlc6_decode_original_unicast(&pdu[4], length - 4, &test_vmac_src,
&test_vmac_dst, test_npdu, sizeof(test_npdu), &test_npdu_len);
ct_test(pTest, len == test_len);
ct_test(pTest, msg_len == test_len);
ct_test(pTest, vmac_src == test_vmac_src);
ct_test(pTest, vmac_dst == test_vmac_dst);
ct_test(pTest, npdu_len == test_npdu_len);
for (i = 0; i < npdu_len; i++) {
ct_test(pTest, npdu[i] == test_npdu[i]);
}
}
static void test_BVLC6_Original_Unicast_NPDU(Test *pTest)
{
uint8_t npdu[50] = { 0 };
uint32_t vmac_src = 0;
uint32_t vmac_dst = 0;
uint16_t npdu_len = 0;
uint16_t i = 0;
test_BVLC6_Original_Unicast_NPDU_Message(
pTest, npdu, npdu_len, vmac_src, vmac_dst);
/* now with some NPDU data */
for (i = 0; i < sizeof(npdu); i++) {
npdu[i] = i;
}
npdu_len = sizeof(npdu);
vmac_src = 4194303;
vmac_dst = 4194302;
test_BVLC6_Original_Unicast_NPDU_Message(
pTest, npdu, npdu_len, vmac_src, vmac_dst);
}
static void test_BVLC6_Original_Broadcast_NPDU_Message(
Test *pTest, uint8_t *npdu, uint16_t npdu_len, uint32_t vmac)
{
uint8_t test_npdu[50] = { 0 };
uint8_t pdu[60] = { 0 };
uint32_t test_vmac = 0;
uint16_t test_npdu_len = 0;
uint8_t message_type = 0;
uint16_t length = 0;
int len = 0, msg_len = 0, test_len = 0;
uint16_t i = 0;
len =
bvlc6_encode_original_broadcast(pdu, sizeof(pdu), vmac, npdu, npdu_len);
msg_len = 7 + npdu_len;
ct_test(pTest, len == msg_len);
test_len = test_BVLC6_Header(pTest, pdu, len, &message_type, &length);
ct_test(pTest, test_len == 4);
ct_test(pTest, message_type == BVLC6_ORIGINAL_BROADCAST_NPDU);
ct_test(pTest, length == msg_len);
test_len += bvlc6_decode_original_broadcast(&pdu[4], length - 4, &test_vmac,
test_npdu, sizeof(test_npdu), &test_npdu_len);
ct_test(pTest, len == test_len);
ct_test(pTest, msg_len == test_len);
ct_test(pTest, vmac == test_vmac);
ct_test(pTest, npdu_len == test_npdu_len);
for (i = 0; i < npdu_len; i++) {
ct_test(pTest, npdu[i] == test_npdu[i]);
}
}
static void test_BVLC6_Original_Broadcast_NPDU(Test *pTest)
{
uint8_t npdu[50] = { 0 };
uint32_t vmac = 0;
uint16_t npdu_len = 0;
uint16_t i = 0;
test_BVLC6_Original_Broadcast_NPDU_Message(pTest, npdu, npdu_len, vmac);
/* now with some NPDU data */
for (i = 0; i < sizeof(npdu); i++) {
npdu[i] = i;
}
npdu_len = sizeof(npdu);
vmac = 4194303;
test_BVLC6_Original_Broadcast_NPDU_Message(pTest, npdu, npdu_len, vmac);
}
static void test_BVLC6_Address_Resolution_Message(
Test *pTest, uint32_t vmac_src, uint32_t vmac_target)
{
uint8_t pdu[60] = { 0 };
uint32_t test_vmac_src = 0;
uint32_t test_vmac_target = 0;
uint8_t message_type = 0;
uint16_t length = 0;
int len = 0, test_len = 0;
const int msg_len = 10;
len = bvlc6_encode_address_resolution(
pdu, sizeof(pdu), vmac_src, vmac_target);
ct_test(pTest, len == msg_len);
test_len = test_BVLC6_Header(pTest, pdu, len, &message_type, &length);
ct_test(pTest, test_len == 4);
ct_test(pTest, message_type == BVLC6_ADDRESS_RESOLUTION);
ct_test(pTest, length == msg_len);
test_len += bvlc6_decode_address_resolution(
&pdu[4], length - 4, &test_vmac_src, &test_vmac_target);
ct_test(pTest, len == test_len);
ct_test(pTest, msg_len == test_len);
ct_test(pTest, vmac_src == test_vmac_src);
ct_test(pTest, vmac_target == test_vmac_target);
}
static void test_BVLC6_Address_Resolution(Test *pTest)
{
uint32_t vmac_src = 0;
uint32_t vmac_target = 0;
test_BVLC6_Address_Resolution_Message(pTest, vmac_src, vmac_target);
vmac_src = 4194303;
vmac_target = 4194302;
test_BVLC6_Address_Resolution_Message(pTest, vmac_src, vmac_target);
}
static void test_BVLC6_Forwarded_Address_Resolution_Message(Test *pTest,
uint32_t vmac_src,
uint32_t vmac_dst,
BACNET_IP6_ADDRESS *bip6_address)
{
BACNET_IP6_ADDRESS test_bip6_address = { { 0 } };
uint8_t pdu[60] = { 0 };
uint32_t test_vmac_src = 0;
uint32_t test_vmac_dst = 0;
uint8_t message_type = 0;
uint16_t length = 0;
int len = 0, test_len = 0;
const int msg_len = 4 + 3 + 3 + BIP6_ADDRESS_MAX;
len = bvlc6_encode_forwarded_address_resolution(
pdu, sizeof(pdu), vmac_src, vmac_dst, bip6_address);
ct_test(pTest, len == msg_len);
test_len = test_BVLC6_Header(pTest, pdu, len, &message_type, &length);
ct_test(pTest, test_len == 4);
ct_test(pTest, message_type == BVLC6_FORWARDED_ADDRESS_RESOLUTION);
ct_test(pTest, length == msg_len);
test_len += bvlc6_decode_forwarded_address_resolution(&pdu[4], length - 4,
&test_vmac_src, &test_vmac_dst, &test_bip6_address);
ct_test(pTest, len == test_len);
ct_test(pTest, msg_len == test_len);
ct_test(pTest, vmac_src == test_vmac_src);
ct_test(pTest, vmac_dst == test_vmac_dst);
test_BVLC6_Address(pTest, bip6_address, &test_bip6_address);
}
static void test_BVLC6_Forwarded_Address_Resolution(Test *pTest)
{
BACNET_IP6_ADDRESS bip6_address = { { 0 } };
uint32_t vmac_src = 0;
uint32_t vmac_target = 0;
uint16_t i = 0;
test_BVLC6_Forwarded_Address_Resolution_Message(
pTest, vmac_src, vmac_target, &bip6_address);
/* now with some address data */
for (i = 0; i < sizeof(bip6_address.address); i++) {
bip6_address.address[i] = i;
}
bip6_address.port = 47808;
vmac_src = 4194303;
vmac_target = 4194302;
test_BVLC6_Forwarded_Address_Resolution_Message(
pTest, vmac_src, vmac_target, &bip6_address);
}
static void test_BVLC6_Address_Resolution_Ack_Message(
Test *pTest, uint32_t vmac_src, uint32_t vmac_dst)
{
uint8_t pdu[60] = { 0 };
uint32_t test_vmac_src = 0;
uint32_t test_vmac_dst = 0;
uint8_t message_type = 0;
uint16_t length = 0;
int len = 0, test_len = 0;
const int msg_len = 10;
len = bvlc6_encode_address_resolution_ack(
pdu, sizeof(pdu), vmac_src, vmac_dst);
ct_test(pTest, len == msg_len);
test_len = test_BVLC6_Header(pTest, pdu, len, &message_type, &length);
ct_test(pTest, test_len == 4);
ct_test(pTest, message_type == BVLC6_ADDRESS_RESOLUTION_ACK);
ct_test(pTest, length == msg_len);
test_len += bvlc6_decode_address_resolution_ack(
&pdu[4], length - 4, &test_vmac_src, &test_vmac_dst);
ct_test(pTest, len == test_len);
ct_test(pTest, msg_len == test_len);
ct_test(pTest, vmac_src == test_vmac_src);
ct_test(pTest, vmac_dst == test_vmac_dst);
}
static void test_BVLC6_Address_Resolution_Ack(Test *pTest)
{
uint32_t vmac_src = 0;
uint32_t vmac_dst = 0;
test_BVLC6_Address_Resolution_Ack_Message(pTest, vmac_src, vmac_dst);
vmac_src = 4194303;
vmac_dst = 4194302;
test_BVLC6_Address_Resolution_Ack_Message(pTest, vmac_src, vmac_dst);
}
static void test_BVLC6_Virtual_Address_Resolution_Message(
Test *pTest, uint32_t vmac_src)
{
uint8_t pdu[60] = { 0 };
uint32_t test_vmac_src = 0;
uint8_t message_type = 0;
uint16_t length = 0;
int len = 0, test_len = 0;
const int msg_len = 7;
len = bvlc6_encode_virtual_address_resolution(pdu, sizeof(pdu), vmac_src);
ct_test(pTest, len == msg_len);
test_len = test_BVLC6_Header(pTest, pdu, len, &message_type, &length);
ct_test(pTest, test_len == 4);
ct_test(pTest, message_type == BVLC6_VIRTUAL_ADDRESS_RESOLUTION);
ct_test(pTest, length == msg_len);
test_len += bvlc6_decode_virtual_address_resolution(
&pdu[4], length - 4, &test_vmac_src);
ct_test(pTest, len == test_len);
ct_test(pTest, msg_len == test_len);
ct_test(pTest, vmac_src == test_vmac_src);
}
static void test_BVLC6_Virtual_Address_Resolution(Test *pTest)
{
uint32_t vmac_src = 0;
test_BVLC6_Virtual_Address_Resolution_Message(pTest, vmac_src);
vmac_src = 0x1234;
test_BVLC6_Virtual_Address_Resolution_Message(pTest, vmac_src);
}
static void test_BVLC6_Virtual_Address_Resolution_Ack_Message(
Test *pTest, uint32_t vmac_src, uint32_t vmac_dst)
{
uint8_t pdu[60] = { 0 };
uint32_t test_vmac_src = 0;
uint32_t test_vmac_dst = 0;
uint8_t message_type = 0;
uint16_t length = 0;
int len = 0, test_len = 0;
const int msg_len = 10;
len = bvlc6_encode_virtual_address_resolution_ack(
pdu, sizeof(pdu), vmac_src, vmac_dst);
ct_test(pTest, len == msg_len);
test_len = test_BVLC6_Header(pTest, pdu, len, &message_type, &length);
ct_test(pTest, test_len == 4);
ct_test(pTest, message_type == BVLC6_VIRTUAL_ADDRESS_RESOLUTION_ACK);
ct_test(pTest, length == msg_len);
test_len += bvlc6_decode_virtual_address_resolution_ack(
&pdu[4], length - 4, &test_vmac_src, &test_vmac_dst);
ct_test(pTest, len == test_len);
ct_test(pTest, msg_len == test_len);
ct_test(pTest, vmac_src == test_vmac_src);
ct_test(pTest, vmac_dst == test_vmac_dst);
}
static void test_BVLC6_Virtual_Address_Resolution_Ack(Test *pTest)
{
uint32_t vmac_src = 0;
uint32_t vmac_dst = 0;
test_BVLC6_Virtual_Address_Resolution_Ack_Message(
pTest, vmac_src, vmac_dst);
vmac_src = 4194303;
vmac_dst = 4194302;
test_BVLC6_Virtual_Address_Resolution_Ack_Message(
pTest, vmac_src, vmac_dst);
}
static void test_BVLC6_Forwarded_NPDU_Message(Test *pTest,
uint8_t *npdu,
uint16_t npdu_len,
uint32_t vmac_src,
BACNET_IP6_ADDRESS *bip6_address)
{
uint8_t test_npdu[50] = { 0 };
uint8_t pdu[75] = { 0 };
uint32_t test_vmac_src = 0;
BACNET_IP6_ADDRESS test_bip6_address = { { 0 } };
uint16_t test_npdu_len = 0;
uint8_t message_type = 0;
uint16_t length = 0;
int len = 0, msg_len = 0, test_len = 0;
uint16_t i = 0;
len = bvlc6_encode_forwarded_npdu(
pdu, sizeof(pdu), vmac_src, bip6_address, npdu, npdu_len);
msg_len = 1 + 1 + 2 + 3 + BIP6_ADDRESS_MAX + npdu_len;
ct_test(pTest, len == msg_len);
test_len = test_BVLC6_Header(pTest, pdu, len, &message_type, &length);
ct_test(pTest, test_len == 4);
ct_test(pTest, message_type == BVLC6_FORWARDED_NPDU);
ct_test(pTest, length == msg_len);
test_len += bvlc6_decode_forwarded_npdu(&pdu[4], length - 4, &test_vmac_src,
&test_bip6_address, test_npdu, sizeof(test_npdu), &test_npdu_len);
ct_test(pTest, len == test_len);
ct_test(pTest, msg_len == test_len);
ct_test(pTest, vmac_src == test_vmac_src);
test_BVLC6_Address(pTest, bip6_address, &test_bip6_address);
ct_test(pTest, npdu_len == test_npdu_len);
for (i = 0; i < npdu_len; i++) {
ct_test(pTest, npdu[i] == test_npdu[i]);
}
}
static void test_BVLC6_Forwarded_NPDU(Test *pTest)
{
uint8_t npdu[50] = { 0 };
uint32_t vmac_src = 0;
BACNET_IP6_ADDRESS bip6_address = { { 0 } };
uint16_t npdu_len = 0;
uint16_t i = 0;
test_BVLC6_Forwarded_NPDU_Message(
pTest, npdu, npdu_len, vmac_src, &bip6_address);
for (i = 0; i < sizeof(bip6_address.address); i++) {
bip6_address.address[i] = i;
}
bip6_address.port = 47808;
/* now with some NPDU data */
for (i = 0; i < sizeof(npdu); i++) {
npdu[i] = i;
}
npdu_len = sizeof(npdu);
vmac_src = 4194303;
test_BVLC6_Forwarded_NPDU_Message(
pTest, npdu, npdu_len, vmac_src, &bip6_address);
}
static void test_BVLC6_Register_Foreign_Device_Message(
Test *pTest, uint32_t vmac_src, uint16_t ttl_seconds)
{
uint8_t pdu[60] = { 0 };
uint32_t test_vmac_src = 0;
uint16_t test_ttl_seconds = 0;
uint8_t message_type = 0;
uint16_t length = 0;
int len = 0, test_len = 0;
const int msg_len = 9;
len = bvlc6_encode_register_foreign_device(
pdu, sizeof(pdu), vmac_src, ttl_seconds);
ct_test(pTest, len == msg_len);
test_len = test_BVLC6_Header(pTest, pdu, len, &message_type, &length);
ct_test(pTest, test_len == 4);
ct_test(pTest, message_type == BVLC6_REGISTER_FOREIGN_DEVICE);
ct_test(pTest, length == msg_len);
test_len += bvlc6_decode_register_foreign_device(
&pdu[4], length - 4, &test_vmac_src, &test_ttl_seconds);
ct_test(pTest, len == test_len);
ct_test(pTest, msg_len == test_len);
ct_test(pTest, vmac_src == test_vmac_src);
ct_test(pTest, ttl_seconds == test_ttl_seconds);
}
static void test_BVLC6_Register_Foreign_Device(Test *pTest)
{
uint32_t vmac_src = 0;
uint16_t ttl_seconds = 0;
test_BVLC6_Register_Foreign_Device_Message(pTest, vmac_src, ttl_seconds);
vmac_src = 4194303;
ttl_seconds = 600;
test_BVLC6_Register_Foreign_Device_Message(pTest, vmac_src, ttl_seconds);
}
static void test_BVLC6_Delete_Foreign_Device_Message(Test *pTest,
uint32_t vmac_src,
BACNET_IP6_FOREIGN_DEVICE_TABLE_ENTRY *fdt_entry)
{
uint8_t pdu[64] = { 0 };
uint32_t test_vmac_src = 0;
BACNET_IP6_FOREIGN_DEVICE_TABLE_ENTRY test_fdt_entry = { 0 };
uint8_t message_type = 0;
uint16_t length = 0;
int len = 0, test_len = 0;
const int msg_len = 0x0019;
len = bvlc6_encode_delete_foreign_device(
pdu, sizeof(pdu), vmac_src, &fdt_entry->bip6_address);
ct_test(pTest, len == msg_len);
test_len = test_BVLC6_Header(pTest, pdu, len, &message_type, &length);
ct_test(pTest, test_len == 4);
ct_test(pTest, message_type == BVLC6_DELETE_FOREIGN_DEVICE);
ct_test(pTest, length == msg_len);
test_len += bvlc6_decode_delete_foreign_device(
&pdu[4], length - 4, &test_vmac_src, &test_fdt_entry.bip6_address);
ct_test(pTest, len == test_len);
ct_test(pTest, msg_len == test_len);
ct_test(pTest, vmac_src == test_vmac_src);
test_BVLC6_Address(
pTest, &fdt_entry->bip6_address, &test_fdt_entry.bip6_address);
}
static void test_BVLC6_Delete_Foreign_Device(Test *pTest)
{
uint32_t vmac_src = 0;
BACNET_IP6_FOREIGN_DEVICE_TABLE_ENTRY fdt_entry = { 0 };
unsigned int i = 0;
/* test with zeros */
test_BVLC6_Delete_Foreign_Device_Message(pTest, vmac_src, &fdt_entry);
/* test with valid values */
vmac_src = 4194303;
for (i = 0; i < sizeof(fdt_entry.bip6_address.address); i++) {
fdt_entry.bip6_address.address[i] = i;
}
fdt_entry.bip6_address.port = 47808;
fdt_entry.ttl_seconds = 600;
fdt_entry.ttl_seconds_remaining = 42;
fdt_entry.next = NULL;
test_BVLC6_Delete_Foreign_Device_Message(pTest, vmac_src, &fdt_entry);
}
static void test_BVLC6_Secure_BVLL_Message(
Test *pTest, uint8_t *sbuf, uint16_t sbuf_len)
{
uint8_t test_sbuf[50] = { 0 };
uint8_t pdu[60] = { 0 };
uint16_t test_sbuf_len = 0;
uint8_t message_type = 0;
uint16_t length = 0;
int len = 0, msg_len = 0, test_len = 0;
uint16_t i = 0;
len = bvlc6_encode_secure_bvll(pdu, sizeof(pdu), sbuf, sbuf_len);
msg_len = 1 + 1 + 2 + sbuf_len;
ct_test(pTest, len == msg_len);
test_len = test_BVLC6_Header(pTest, pdu, len, &message_type, &length);
ct_test(pTest, test_len == 4);
ct_test(pTest, message_type == BVLC6_SECURE_BVLL);
ct_test(pTest, length == msg_len);
test_len += bvlc6_decode_secure_bvll(
&pdu[4], length - 4, test_sbuf, sizeof(test_sbuf), &test_sbuf_len);
ct_test(pTest, len == test_len);
ct_test(pTest, msg_len == test_len);
ct_test(pTest, sbuf_len == test_sbuf_len);
for (i = 0; i < sbuf_len; i++) {
ct_test(pTest, sbuf[i] == test_sbuf[i]);
}
}
static void test_BVLC6_Secure_BVLL(Test *pTest)
{
uint8_t sbuf[50] = { 0 };
uint16_t sbuf_len = 0;
uint16_t i = 0;
test_BVLC6_Secure_BVLL_Message(pTest, sbuf, sbuf_len);
/* now with some NPDU data */
for (i = 0; i < sizeof(sbuf); i++) {
sbuf[i] = i;
}
sbuf_len = sizeof(sbuf);
test_BVLC6_Secure_BVLL_Message(pTest, sbuf, sbuf_len);
}
static void test_BVLC6_Distribute_Broadcast_To_Network_Message(
Test *pTest, uint8_t *npdu, uint16_t npdu_len, uint32_t vmac)
{
uint8_t test_npdu[50] = { 0 };
uint8_t pdu[60] = { 0 };
uint32_t test_vmac = 0;
uint16_t test_npdu_len = 0;
uint8_t message_type = 0;
uint16_t length = 0;
int len = 0, msg_len = 0, test_len = 0;
uint16_t i = 0;
len = bvlc6_encode_distribute_broadcast_to_network(
pdu, sizeof(pdu), vmac, npdu, npdu_len);
msg_len = 7 + npdu_len;
ct_test(pTest, len == msg_len);
test_len = test_BVLC6_Header(pTest, pdu, len, &message_type, &length);
ct_test(pTest, test_len == 4);
ct_test(pTest, message_type == BVLC6_DISTRIBUTE_BROADCAST_TO_NETWORK);
ct_test(pTest, length == msg_len);
test_len += bvlc6_decode_distribute_broadcast_to_network(&pdu[4],
length - 4, &test_vmac, test_npdu, sizeof(test_npdu), &test_npdu_len);
ct_test(pTest, len == test_len);
ct_test(pTest, msg_len == test_len);
ct_test(pTest, vmac == test_vmac);
ct_test(pTest, npdu_len == test_npdu_len);
for (i = 0; i < npdu_len; i++) {
ct_test(pTest, npdu[i] == test_npdu[i]);
}
}
static void test_BVLC6_Distribute_Broadcast_To_Network(Test *pTest)
{
uint8_t npdu[50] = { 0 };
uint32_t vmac = 0;
uint16_t npdu_len = 0;
uint16_t i = 0;
test_BVLC6_Distribute_Broadcast_To_Network_Message(
pTest, npdu, npdu_len, vmac);
/* now with some NPDU data */
for (i = 0; i < sizeof(npdu); i++) {
npdu[i] = i;
}
npdu_len = sizeof(npdu);
vmac = 4194303;
test_BVLC6_Distribute_Broadcast_To_Network_Message(
pTest, npdu, npdu_len, vmac);
}
static void test_BVLC6_Address_Copy(Test *pTest)
{
unsigned int i = 0;
BACNET_IP6_ADDRESS src = { { 0 } };
BACNET_IP6_ADDRESS dst = { { 0 } };
bool status = false;
/* test with zeros */
status = bvlc6_address_copy(&dst, &src);
ct_test(pTest, status);
status = bvlc6_address_different(&dst, &src);
ct_test(pTest, !status);
/* test with valid values */
for (i = 0; i < sizeof(src.address); i++) {
src.address[i] = 1 + i;
}
src.port = 47808;
status = bvlc6_address_copy(&dst, &src);
ct_test(pTest, status);
status = bvlc6_address_different(&dst, &src);
ct_test(pTest, !status);
/* test for different port */
dst.port = 47809;
status = bvlc6_address_different(&dst, &src);
ct_test(pTest, status);
/* test for different address */
dst.port = src.port;
for (i = 0; i < sizeof(src.address); i++) {
dst.address[i] = 0;
status = bvlc6_address_different(&dst, &src);
ct_test(pTest, status);
dst.address[i] = 1 + i;
}
}
static void test_BVLC6_Address_Get_Set(Test *pTest)
{
uint16_t i = 0;
BACNET_IP6_ADDRESS src = { { 0 } };
BACNET_IP6_ADDRESS dst = { { 0 } };
uint16_t group = 1;
uint16_t test_group = 0;
uint16_t hextet[8] = { 0 };
bool status = false;
for (i = 0; i < 16; i++) {
status = bvlc6_address_set(&src, group, 0, 0, 0, 0, 0, 0, 0);
ct_test(pTest, status);
status = bvlc6_address_get(
&src, &test_group, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
ct_test(pTest, status);
ct_test(pTest, group == test_group);
group = group << 1;
}
/* test the ASCII hex to address */
/* test too short */
status = bvlc6_address_from_ascii(&src, "[1234:5678]");
ct_test(pTest, status == false);
status = bvlc6_address_from_ascii(
&src, "[1234:5678:9ABC:DEF0:1234:5678:9ABC:DEF0]");
ct_test(pTest, status);
status = bvlc6_address_set(
&dst, 0x1234, 0x5678, 0x9ABC, 0xDEF0, 0x1234, 0x5678, 0x9ABC, 0xDEF0);
ct_test(pTest, status);
status = bvlc6_address_different(&dst, &src);
ct_test(pTest, status == false);
/* test zero compression */
status = bvlc6_address_from_ascii(&src, "[1234:5678:9ABC::5678:9ABC:DEF0]");
ct_test(pTest, status);
status = bvlc6_address_set(
&dst, 0x1234, 0x5678, 0x9ABC, 0x0000, 0x0000, 0x5678, 0x9ABC, 0xDEF0);
ct_test(pTest, status);
status = bvlc6_address_different(&dst, &src);
if (status) {
status = bvlc6_address_get(&src, &hextet[0], &hextet[1], &hextet[2],
&hextet[3], &hextet[4], &hextet[5], &hextet[6], &hextet[7]);
printf("src:[%X:%X:%X:%X:%X:%X:%X:%X]\n", hextet[0], hextet[1],
hextet[2], hextet[3], hextet[4], hextet[5], hextet[6], hextet[7]);
status = bvlc6_address_get(&dst, &hextet[0], &hextet[1], &hextet[2],
&hextet[3], &hextet[4], &hextet[5], &hextet[6], &hextet[7]);
printf("dst:[%X:%X:%X:%X:%X:%X:%X:%X]\n", hextet[0], hextet[1],
hextet[2], hextet[3], hextet[4], hextet[5], hextet[6], hextet[7]);
}
ct_test(pTest, status == false);
/* test some compressed 16-bit zero fields */
status =
bvlc6_address_from_ascii(&src, "[234:678:ABC:EF0:1234:5678:9ABC:DEF0]");
ct_test(pTest, status);
status = bvlc6_address_set(
&dst, 0x0234, 0x0678, 0x0ABC, 0x0EF0, 0x1234, 0x5678, 0x9ABC, 0xDEF0);
ct_test(pTest, status);
status = bvlc6_address_different(&dst, &src);
ct_test(pTest, status == false);
}
static void test_BVLC6_VMAC_Address_Get_Set(Test *pTest)
{
uint16_t i = 0;
BACNET_ADDRESS addr;
uint32_t device_id = 1;
uint32_t test_device_id = 0;
bool status = false;
for (i = 0; i < 24; i++) {
status = bvlc6_vmac_address_set(&addr, device_id);
ct_test(pTest, status);
ct_test(pTest, addr.mac_len == 3);
ct_test(pTest, addr.net == 0);
ct_test(pTest, addr.len == 0);
status = bvlc6_vmac_address_get(&addr, &test_device_id);
ct_test(pTest, status);
ct_test(pTest, device_id == test_device_id);
device_id = device_id << 1;
}
}
void test_BVLC6(Test *pTest)
{
bool rc;
/* individual tests */
rc = ct_addTestFunction(pTest, test_BVLC6_Result);
assert(rc);
rc = ct_addTestFunction(pTest, test_BVLC6_Original_Unicast_NPDU);
assert(rc);
rc = ct_addTestFunction(pTest, test_BVLC6_Original_Broadcast_NPDU);
assert(rc);
rc = ct_addTestFunction(pTest, test_BVLC6_Address_Resolution);
assert(rc);
rc = ct_addTestFunction(pTest, test_BVLC6_Forwarded_Address_Resolution);
assert(rc);
rc = ct_addTestFunction(pTest, test_BVLC6_Address_Resolution_Ack);
assert(rc);
rc = ct_addTestFunction(pTest, test_BVLC6_Virtual_Address_Resolution);
assert(rc);
rc = ct_addTestFunction(pTest, test_BVLC6_Virtual_Address_Resolution_Ack);
assert(rc);
rc = ct_addTestFunction(pTest, test_BVLC6_Forwarded_NPDU);
assert(rc);
rc = ct_addTestFunction(pTest, test_BVLC6_Register_Foreign_Device);
assert(rc);
rc = ct_addTestFunction(pTest, test_BVLC6_Delete_Foreign_Device);
assert(rc);
rc = ct_addTestFunction(pTest, test_BVLC6_Secure_BVLL);
assert(rc);
rc = ct_addTestFunction(pTest, test_BVLC6_Distribute_Broadcast_To_Network);
assert(rc);
rc = ct_addTestFunction(pTest, test_BVLC6_Address_Copy);
assert(rc);
rc = ct_addTestFunction(pTest, test_BVLC6_Address_Get_Set);
assert(rc);
rc = ct_addTestFunction(pTest, test_BVLC6_VMAC_Address_Get_Set);
assert(rc);
}
#ifdef TEST_BVLC6
int main(void)
{
Test *pTest;
pTest = ct_create("BACnet Virtual Link Control IP/v6", NULL);
test_BVLC6(pTest);
/* configure output */
ct_setStream(pTest, stdout);
ct_run(pTest);
(void)ct_report(pTest);
ct_destroy(pTest);
return 0;
}
#endif /* TEST_BBMD */
#endif /* BAC_TEST */