Files
bacnet_stack/src/bacnet/datalink/bsc/bvlc-sc.h
T
Steve Karg d4cbec91e2 Enabled style and CERT-C addon for CPPCHECK (#869)
* Enabled style and CERT-C addon for CPPCHECK with some suppressions and fixed the defects found..
2024-12-10 07:56:24 -06:00

426 lines
12 KiB
C

/**
* @file
* @brief API for encoding/decoding of BACnet/SC BVLC messages
* @author Kirill Neznamov <kirill.neznamov@dsr-corporation.com>
* @date May 2022
* @copyright SPDX-License-Identifier: MIT
*/
#ifndef BACNET_DATALINK_BSC_BVLC_SC_H
#define BACNET_DATALINK_BSC_BVLC_SC_H
#include <stdbool.h>
#include <stdint.h>
#include <stddef.h>
#include <string.h>
#include <limits.h>
/* BACnet Stack defines - first */
#include "bacnet/bacdef.h"
/* BACnet Stack API */
#include "bacnet/npdu.h"
#ifndef BVLC_SC_NPDU_SIZE_CONF
#define BVLC_SC_NPDU_SIZE 1440
#else
#define BVLC_SC_NPDU_SIZE BVLC_SC_NPDU_SIZE_CONF
#endif
#define BVLC_SC_NPDU_MAX_SIZE \
61327 /* Table 6-1. NPDU Lengths of BACnet Data Link Layers */
#define BVLC_SC_VMAC_SIZE 6
#define BVLC_SC_UUID_SIZE 16
#define BSC_PRE (2 * BVLC_SC_VMAC_SIZE)
#if !defined(USER_DEFINED_BVLC_SC_HEADER_OPTION_MAX)
#define BVLC_SC_HEADER_OPTION_MAX \
4 /* though BACNet standard does not limit number of option headers \
the implementation defines max value */
#else
#define BVLC_SC_HEADER_OPTION_MAX USER_DEFINED_BVLC_SC_HEADER_OPTION_MAX
#endif
#if BVLC_SC_NPDU_SIZE > BVLC_SC_NPDU_MAX_SIZE
#error \
"Maximum NPDU Length on BACNet/SC Data Link must be <= BVLC_SC_NPDU_MAX_SIZE"
#endif
/*
* BACnet/SC BVLC Messages (functions) (AB.2 BACnet/SC Virtual Link Layer
* Messages)
*/
typedef enum BVLC_SC_Message_Type {
BVLC_SC_RESULT = 0x00,
BVLC_SC_ENCAPSULATED_NPDU = 0x01,
BVLC_SC_ADDRESS_RESOLUTION = 0x02,
BVLC_SC_ADDRESS_RESOLUTION_ACK = 0x03,
BVLC_SC_ADVERTISIMENT = 0x04,
BVLC_SC_ADVERTISIMENT_SOLICITATION = 0x05,
BVLC_SC_CONNECT_REQUEST = 0x06,
BVLC_SC_CONNECT_ACCEPT = 0x07,
BVLC_SC_DISCONNECT_REQUEST = 0x08,
BVLC_SC_DISCONNECT_ACK = 0x09,
BVLC_SC_HEARTBEAT_REQUEST = 0x0a,
BVLC_SC_HEARTBEAT_ACK = 0x0b,
BVLC_SC_PROPRIETARY_MESSAGE = 0x0c
} BVLC_SC_MESSAGE_TYPE;
/*
* AB.2.2 Control Flags
*/
#define BVLC_SC_CONTROL_DATA_OPTIONS (1 << 0)
#define BVLC_SC_CONTROL_DEST_OPTIONS (1 << 1)
#define BVLC_SC_CONTROL_DEST_VADDR (1 << 2)
#define BVLC_SC_CONTROL_ORIG_VADDR (1 << 3)
/*
* AB.2.3 Header Options
*/
#define BVLC_SC_HEADER_DATA (1 << 5)
#define BVLC_SC_HEADER_MUST_UNDERSTAND (1 << 6)
#define BVLC_SC_HEADER_MORE (1 << 7)
#define BVLC_SC_HEADER_OPTION_TYPE_MASK (0x1F)
/**
* BACnet SC VMAC Address
*
* B.1.5.2 VMAC Addressing of Nodes
* For the BVLC message exchange, BACnet/SC nodes are identified by their
* 6-octet virtual MAC address as defined in Clause H.7.3.
* For broadcast BVLC messages that need to reach all nodes of the BACnet/SC
* network, the destination VMAC address shall be the non-EUI-48 value
* X'FFFFFFFFFFFF', referred to as the Local Broadcast VMAC address.
* The reserved EUI-48 value X'000000000000' is not used by this data link
* and therefore can be used internally to indicate that a VMAC is unknown
* or uninitialized.
* @{
*/
typedef struct BACnet_SC_VMAC_Address {
uint8_t address[BVLC_SC_VMAC_SIZE];
} BACNET_SC_VMAC_ADDRESS;
/** @} */
/**
* BACnet SC UUID
* AB.1.5.3 Device UUID
* Every BACnet device that supports one or more BACnet/SC network ports shall
* have a Universally Unique ID (UUID) as defined in RFC 4122. This UUID
* identifies the device regardless of its current VMAC address or device
* instance number and is referred to as the device UUID.
* This device UUID shall be generated before first deployment of the device in
* an installation, shall be persistently stored across device restarts, and
* shall not change over the entire lifetime of a device.
* If a device is replaced in an installation, the new device is not required
* to reuse the UUID of the replaced device. For BACnet/SC, it is assumed
* that existing connections to the device being replaced are all terminated
* before the new device comes into operation.
* @{
*/
typedef struct BACnet_SC_Uuid {
uint8_t uuid[BVLC_SC_UUID_SIZE];
} BACNET_SC_UUID;
/** @} */
/*
* AB.2.3.1 Secure Path Header Option
*/
typedef enum BVLC_SC_Option_Type {
BVLC_SC_OPTION_TYPE_SECURE_PATH = 1,
BVLC_SC_OPTION_TYPE_PROPRIETARY = 31
} BVLC_SC_OPTION_TYPE;
typedef enum BVLC_SC_Direct_Connection_Support {
BVLC_SC_DIRECT_CONNECTION_ACCEPT_UNSUPPORTED = 0,
BVLC_SC_DIRECT_CONNECTION_ACCEPT_SUPPORTED = 1,
BVLC_SC_DIRECT_CONNECTION_SUPPORT_MAX = 1
} BVLC_SC_DIRECT_CONNECTION_SUPPORT;
typedef struct BVLC_SC_Decoded_Hdr {
uint8_t bvlc_function;
uint16_t message_id;
BACNET_SC_VMAC_ADDRESS *origin;
BACNET_SC_VMAC_ADDRESS *dest;
uint8_t *dest_options; /* pointer to packed dest options list in message */
size_t dest_options_len;
size_t dest_options_num; /* number of filled items in dest_options */
uint8_t *data_options; /* pointer to packed data options list in message */
size_t data_options_len;
size_t data_options_num; /* number of filled items in data_options */
uint8_t *payload; /* packed payload, points to data in message */
size_t payload_len;
} BVLC_SC_DECODED_HDR;
typedef struct BVLC_SC_Decoded_Result {
uint8_t bvlc_function;
uint8_t result;
uint8_t error_header_marker;
uint16_t error_class;
uint16_t error_code;
uint8_t *utf8_details_string; /* NOTE!: this is utf 8 string without
trailing zero */
size_t utf8_details_string_len;
} BVLC_SC_DECODED_RESULT;
typedef struct BVLC_SC_Decoded_Address_Resolution_Ack {
uint8_t *utf8_websocket_uri_string; /* NOTE!: this is utf 8 string without
trailing zero */
size_t utf8_websocket_uri_string_len;
} BVLC_SC_DECODED_ADDRESS_RESOLUTION_ACK;
typedef struct BVLC_SC_Decoded_Ecapsulated_NPDU {
uint8_t *npdu;
size_t npdu_len;
} BVLC_SC_DECODED_ENCAPSULATED_NPDU;
typedef struct BVLC_SC_Decoded_Advertisiment {
BACNET_SC_HUB_CONNECTOR_STATE hub_status;
BVLC_SC_DIRECT_CONNECTION_SUPPORT support;
uint16_t max_bvlc_len;
uint16_t max_npdu_len;
} BVLC_SC_DECODED_ADVERTISIMENT;
typedef struct BVLC_SC_Decoded_Connect_Request {
BACNET_SC_VMAC_ADDRESS *vmac;
BACNET_SC_UUID *uuid;
uint16_t max_bvlc_len;
uint16_t max_npdu_len;
} BVLC_SC_DECODED_CONNECT_REQUEST;
typedef struct BVLC_SC_Decoded_Connect_Accept {
BACNET_SC_VMAC_ADDRESS *vmac;
BACNET_SC_UUID *uuid;
uint16_t max_bvlc_len;
uint16_t max_npdu_len;
} BVLC_SC_DECODED_CONNECT_ACCEPT;
typedef struct BVLC_SC_Decoded_Proprietary {
uint16_t vendor_id;
uint8_t function;
uint8_t *data;
size_t data_len;
} BVLC_SC_DECODED_PROPRIETARY;
typedef union BVLC_SC_Decoded_Data {
BVLC_SC_DECODED_RESULT result;
BVLC_SC_DECODED_ENCAPSULATED_NPDU encapsulated_npdu;
BVLC_SC_DECODED_ADDRESS_RESOLUTION_ACK address_resolution_ack;
BVLC_SC_DECODED_ADVERTISIMENT advertisiment;
BVLC_SC_DECODED_CONNECT_REQUEST connect_request;
BVLC_SC_DECODED_CONNECT_ACCEPT connect_accept;
BVLC_SC_DECODED_PROPRIETARY proprietary;
} BVLC_SC_DECODED_DATA;
typedef struct BVLC_SC_Decoded_Hdr_Proprietary_Option {
uint16_t vendor_id;
uint8_t option_type;
uint8_t *data;
size_t data_len;
} BVLC_SC_DECODED_HDR_PROPRIETARY_OPTION;
typedef union BVLC_SC_Decoded_Specific_Option_Data {
BVLC_SC_DECODED_HDR_PROPRIETARY_OPTION proprietary;
} BVLC_SC_DECODED_SPECIFIC_OPTION_DATA;
typedef struct BVLC_SC_Decoded_Hdr_Option {
uint8_t packed_header_marker;
BVLC_SC_OPTION_TYPE type;
bool must_understand;
BVLC_SC_DECODED_SPECIFIC_OPTION_DATA specific;
} BVLC_SC_DECODED_HDR_OPTION;
typedef struct BVLC_SC_Decoded_Message {
BVLC_SC_DECODED_HDR hdr;
BVLC_SC_DECODED_HDR_OPTION data_options[BVLC_SC_HEADER_OPTION_MAX];
BVLC_SC_DECODED_HDR_OPTION dest_options[BVLC_SC_HEADER_OPTION_MAX];
BVLC_SC_DECODED_DATA payload;
} BVLC_SC_DECODED_MESSAGE;
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
BACNET_STACK_EXPORT
size_t bvlc_sc_add_option_to_destination_options(
uint8_t *out_pdu,
size_t out_pdu_size,
uint8_t *pdu,
size_t pdu_size,
uint8_t *sc_option,
size_t sc_option_len);
BACNET_STACK_EXPORT
size_t bvlc_sc_add_option_to_data_options(
uint8_t *out_pdu,
size_t out_pdu_size,
uint8_t *pdu,
size_t pdu_size,
uint8_t *sc_option,
size_t sc_option_len);
BACNET_STACK_EXPORT
size_t bvlc_sc_encode_proprietary_option(
uint8_t *pdu,
size_t pdu_size,
bool must_understand,
uint16_t vendor_id,
uint8_t proprietary_option_type,
uint8_t *proprietary_data,
size_t proprietary_data_len);
BACNET_STACK_EXPORT
size_t bvlc_sc_encode_secure_path_option(
uint8_t *pdu, size_t pdu_size, bool must_understand);
BACNET_STACK_EXPORT
size_t bvlc_sc_encode_result(
uint8_t *pdu,
size_t pdu_len,
uint16_t message_id,
BACNET_SC_VMAC_ADDRESS *origin,
BACNET_SC_VMAC_ADDRESS *dest,
uint8_t bvlc_function,
uint8_t result_code,
uint8_t *error_header_marker,
uint16_t *error_class,
uint16_t *error_code,
const uint8_t *utf8_details_string);
BACNET_STACK_EXPORT
size_t bvlc_sc_encode_encapsulated_npdu(
uint8_t *pdu,
size_t pdu_len,
uint16_t message_id,
BACNET_SC_VMAC_ADDRESS *origin,
BACNET_SC_VMAC_ADDRESS *dest,
uint8_t *npdu,
size_t npdu_size);
BACNET_STACK_EXPORT
size_t bvlc_sc_encode_address_resolution(
uint8_t *pdu,
size_t pdu_len,
uint16_t message_id,
BACNET_SC_VMAC_ADDRESS *origin,
BACNET_SC_VMAC_ADDRESS *dest);
BACNET_STACK_EXPORT
size_t bvlc_sc_encode_address_resolution_ack(
uint8_t *pdu,
size_t pdu_len,
uint16_t message_id,
BACNET_SC_VMAC_ADDRESS *origin,
BACNET_SC_VMAC_ADDRESS *dest,
uint8_t *web_socket_uris,
size_t web_socket_uris_len);
BACNET_STACK_EXPORT
size_t bvlc_sc_encode_advertisiment(
uint8_t *pdu,
size_t pdu_len,
uint16_t message_id,
BACNET_SC_VMAC_ADDRESS *origin,
BACNET_SC_VMAC_ADDRESS *dest,
BACNET_SC_HUB_CONNECTOR_STATE hub_status,
BVLC_SC_DIRECT_CONNECTION_SUPPORT support,
uint16_t max_bvlc_len,
uint16_t max_npdu_size);
BACNET_STACK_EXPORT
size_t bvlc_sc_encode_advertisiment_solicitation(
uint8_t *pdu,
size_t pdu_len,
uint16_t message_id,
BACNET_SC_VMAC_ADDRESS *origin,
BACNET_SC_VMAC_ADDRESS *dest);
BACNET_STACK_EXPORT
size_t bvlc_sc_encode_connect_request(
uint8_t *pdu,
size_t pdu_len,
uint16_t message_id,
BACNET_SC_VMAC_ADDRESS *local_vmac,
BACNET_SC_UUID *local_uuid,
uint16_t max_bvlc_len,
uint16_t max_npdu_size);
BACNET_STACK_EXPORT
size_t bvlc_sc_encode_connect_accept(
uint8_t *pdu,
size_t pdu_len,
uint16_t message_id,
BACNET_SC_VMAC_ADDRESS *local_vmac,
BACNET_SC_UUID *local_uuid,
uint16_t max_bvlc_len,
uint16_t max_npdu_len);
BACNET_STACK_EXPORT
size_t bvlc_sc_encode_disconnect_request(
uint8_t *pdu, size_t pdu_len, uint16_t message_id);
BACNET_STACK_EXPORT
size_t bvlc_sc_encode_disconnect_ack(
uint8_t *pdu, size_t pdu_len, uint16_t message_id);
BACNET_STACK_EXPORT
size_t bvlc_sc_encode_heartbeat_request(
uint8_t *out_buf, size_t out_buf_len, uint16_t message_id);
BACNET_STACK_EXPORT
size_t bvlc_sc_encode_heartbeat_ack(
uint8_t *out_buf, size_t out_buf_len, uint16_t message_id);
BACNET_STACK_EXPORT
size_t bvlc_sc_encode_proprietary_message(
uint8_t *pdu,
size_t pdu_len,
uint16_t message_id,
BACNET_SC_VMAC_ADDRESS *origin,
BACNET_SC_VMAC_ADDRESS *dest,
uint16_t vendor_id,
uint8_t proprietary_function,
uint8_t *proprietary_data,
size_t proprietary_data_len);
BACNET_STACK_EXPORT
bool bvlc_sc_decode_message(
uint8_t *buf,
size_t buf_len,
BVLC_SC_DECODED_MESSAGE *message,
BACNET_ERROR_CODE *error,
BACNET_ERROR_CLASS *class,
const char **err_desc);
BACNET_STACK_EXPORT
void bvlc_sc_remove_dest_set_orig(
uint8_t *pdu, size_t pdu_len, BACNET_SC_VMAC_ADDRESS *orig);
BACNET_STACK_EXPORT
size_t
bvlc_sc_set_orig(uint8_t **ppdu, size_t pdu_len, BACNET_SC_VMAC_ADDRESS *orig);
BACNET_STACK_EXPORT
bool bvlc_sc_is_vmac_broadcast(BACNET_SC_VMAC_ADDRESS *vmac);
BACNET_STACK_EXPORT
bool bvlc_sc_need_send_bvlc_result(BVLC_SC_DECODED_MESSAGE *dm);
BACNET_STACK_EXPORT
bool bvlc_sc_pdu_has_dest_broadcast(uint8_t *pdu, size_t pdu_len);
BACNET_STACK_EXPORT
bool bvlc_sc_pdu_has_no_dest(uint8_t *pdu, size_t pdu_len);
BACNET_STACK_EXPORT
bool bvlc_sc_pdu_get_dest(
uint8_t *pdu, size_t pdu_len, BACNET_SC_VMAC_ADDRESS *vmac);
BACNET_STACK_EXPORT
size_t bvlc_sc_remove_orig_and_dest(uint8_t **ppdu, size_t pdu_len);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif