Feature/bacnet secure connect hub (#818)
* Added BACnet Secure Connect datalink. * Added BACnet/SC hub application --------- Co-authored-by: Kirill Neznamov <kirill.neznamov@dsr-corporation.com> Co-authored-by: Mikhail Antropov <michail.antropov@dsr-corporation.com> Co-authored-by: Ondřej Hruška <ondra@ondrovo.com> Co-authored-by: Patrick Grimm <patrick@lunatiki.de>
This commit is contained in:
@@ -26,6 +26,14 @@
|
||||
#if (BACNET_PROTOCOL_REVISION >= 17)
|
||||
#include "bacnet/basic/object/netport.h"
|
||||
#endif
|
||||
#if defined(BACDL_BSC)
|
||||
#include "bacnet/basic/object/bacfile.h"
|
||||
#include "bacnet/basic/object/sc_netport.h"
|
||||
#include "bacnet/datalink/bsc/bvlc-sc.h"
|
||||
#include "bacnet/datalink/bsc/bsc-util.h"
|
||||
#include "bacnet/datalink/bsc/bsc-datalink.h"
|
||||
#include "bacnet/datalink/bsc/bsc-event.h"
|
||||
#endif
|
||||
|
||||
/** @file dlenv.c Initialize the DataLink configuration. */
|
||||
/* timer used to renew Foreign Device Registration */
|
||||
@@ -459,6 +467,179 @@ void dlenv_network_port_init(void)
|
||||
since they are already set */
|
||||
Network_Port_Changes_Pending_Set(instance, false);
|
||||
}
|
||||
#elif defined(BACDL_BSC)
|
||||
/**
|
||||
* @brief Datalink network port object settings
|
||||
* @param primary_hub_uri
|
||||
* @param failover_hub_uri
|
||||
* @param filename_ca_1_cert
|
||||
* @param filename_ca_2_cert
|
||||
* @param filename_cert
|
||||
* @param filename_key
|
||||
* @param direct_connect_port
|
||||
* @param hub_function_port
|
||||
* @param direct_connect_initiate
|
||||
* @param direct_connect_accept_urls
|
||||
*/
|
||||
static void bacnet_secure_connect_network_port_init(
|
||||
char *primary_hub_uri,
|
||||
char *failover_hub_uri,
|
||||
char *filename_ca_1_cert,
|
||||
char *filename_ca_2_cert,
|
||||
char *filename_cert,
|
||||
char *filename_key,
|
||||
char *direct_binding,
|
||||
char *hub_binding,
|
||||
char *direct_connect_initiate,
|
||||
char *direct_connect_accept_urls)
|
||||
{
|
||||
const uint32_t instance = 1;
|
||||
BACNET_SC_UUID uuid = { 0 };
|
||||
BACNET_SC_VMAC_ADDRESS vmac = { 0 };
|
||||
long seed;
|
||||
char c;
|
||||
|
||||
seed = (long)&instance;
|
||||
srand((int)seed);
|
||||
Network_Port_Object_Instance_Number_Set(0, instance);
|
||||
Network_Port_Name_Set(instance, "BACnet/BSC Port");
|
||||
Network_Port_Type_Set(instance, PORT_TYPE_BSC);
|
||||
|
||||
bsc_generate_random_uuid(&uuid);
|
||||
Network_Port_SC_Local_UUID_Set(instance, (BACNET_UUID *)&uuid);
|
||||
bsc_generate_random_vmac(&vmac);
|
||||
Network_Port_MAC_Address_Set(instance, vmac.address, sizeof(vmac));
|
||||
|
||||
/* common NP data */
|
||||
Network_Port_Reliability_Set(instance, RELIABILITY_NO_FAULT_DETECTED);
|
||||
Network_Port_Out_Of_Service_Set(instance, false);
|
||||
Network_Port_Quality_Set(instance, PORT_QUALITY_UNKNOWN);
|
||||
Network_Port_APDU_Length_Set(instance, MAX_APDU);
|
||||
Network_Port_Network_Number_Set(instance, 0);
|
||||
|
||||
/* SC parameters */
|
||||
Network_Port_Max_BVLC_Length_Accepted_Set(instance, SC_NETPORT_BVLC_MAX);
|
||||
Network_Port_Max_NPDU_Length_Accepted_Set(instance, SC_NETPORT_NPDU_MAX);
|
||||
Network_Port_SC_Connect_Wait_Timeout_Set(
|
||||
instance, SC_NETPORT_CONNECT_TIMEOUT);
|
||||
Network_Port_SC_Heartbeat_Timeout_Set(
|
||||
instance, SC_NETPORT_HEARTBEAT_TIMEOUT);
|
||||
Network_Port_SC_Disconnect_Wait_Timeout_Set(
|
||||
instance, SC_NETPORT_DISCONNECT_TIMEOUT);
|
||||
Network_Port_SC_Maximum_Reconnect_Time_Set(
|
||||
instance, SC_NETPORT_RECONNECT_TIME);
|
||||
|
||||
if (filename_ca_1_cert == NULL) {
|
||||
fprintf(stderr, "BACNET_SC_ISSUER_1_CERTIFICATE_FILE must be set\n");
|
||||
return;
|
||||
}
|
||||
bacfile_create(BSC_ISSUER_CERTIFICATE_FILE_1_INSTANCE);
|
||||
bacfile_pathname_set(
|
||||
BSC_ISSUER_CERTIFICATE_FILE_1_INSTANCE, filename_ca_1_cert);
|
||||
Network_Port_Issuer_Certificate_File_Set(
|
||||
instance, 0, BSC_ISSUER_CERTIFICATE_FILE_1_INSTANCE);
|
||||
|
||||
if (filename_ca_2_cert) {
|
||||
bacfile_create(BSC_ISSUER_CERTIFICATE_FILE_2_INSTANCE);
|
||||
bacfile_pathname_set(
|
||||
BSC_ISSUER_CERTIFICATE_FILE_2_INSTANCE, filename_ca_2_cert);
|
||||
Network_Port_Issuer_Certificate_File_Set(
|
||||
instance, 1, BSC_ISSUER_CERTIFICATE_FILE_2_INSTANCE);
|
||||
}
|
||||
|
||||
if (filename_cert == NULL) {
|
||||
fprintf(stderr, "BACNET_SC_OPERATIONAL_CERTIFICATE_FILE must be set\n");
|
||||
return;
|
||||
}
|
||||
bacfile_create(BSC_OPERATIONAL_CERTIFICATE_FILE_INSTANCE);
|
||||
bacfile_pathname_set(
|
||||
BSC_OPERATIONAL_CERTIFICATE_FILE_INSTANCE, filename_cert);
|
||||
Network_Port_Operational_Certificate_File_Set(
|
||||
instance, BSC_OPERATIONAL_CERTIFICATE_FILE_INSTANCE);
|
||||
|
||||
if (filename_key == NULL) {
|
||||
fprintf(
|
||||
stderr,
|
||||
"BACNET_SC_OPERATIONAL_CERTIFICATE_PRIVATE_KEY_FILE must be set\n");
|
||||
return;
|
||||
}
|
||||
bacfile_create(BSC_CERTIFICATE_SIGNING_REQUEST_FILE_INSTANCE);
|
||||
bacfile_pathname_set(
|
||||
BSC_CERTIFICATE_SIGNING_REQUEST_FILE_INSTANCE, filename_key);
|
||||
Network_Port_Certificate_Key_File_Set(
|
||||
instance, BSC_CERTIFICATE_SIGNING_REQUEST_FILE_INSTANCE);
|
||||
|
||||
if ((primary_hub_uri == NULL) && (failover_hub_uri == NULL) &&
|
||||
(direct_binding == NULL) && (hub_binding == NULL)) {
|
||||
fprintf(
|
||||
stderr,
|
||||
"At least must be set:\n"
|
||||
"BACNET_SC_HUB_FUNCTION_BINDING for HUB or\n"
|
||||
"BACNET_SC_PRIMARY_HUB_URI and BACNET_SC_FAILOVER_HUB_URI for node "
|
||||
"or\n"
|
||||
"BACNET_SC_DIRECT_CONNECT_BINDING for direct connect.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
Network_Port_SC_Primary_Hub_URI_Set(instance, primary_hub_uri);
|
||||
Network_Port_SC_Failover_Hub_URI_Set(instance, failover_hub_uri);
|
||||
|
||||
Network_Port_SC_Direct_Connect_Binding_Set(instance, direct_binding);
|
||||
Network_Port_SC_Direct_Connect_Accept_Enable_Set(
|
||||
instance, direct_binding != NULL);
|
||||
|
||||
c = direct_connect_initiate ? direct_connect_initiate[0] : '0';
|
||||
if ((c != '0') && (c != 'n') && (c != 'N')) {
|
||||
Network_Port_SC_Direct_Connect_Initiate_Enable_Set(instance, true);
|
||||
} else {
|
||||
Network_Port_SC_Direct_Connect_Initiate_Enable_Set(instance, false);
|
||||
}
|
||||
|
||||
Network_Port_SC_Direct_Connect_Accept_URIs_Set(
|
||||
instance, direct_connect_accept_urls);
|
||||
|
||||
/* HUB parameters */
|
||||
Network_Port_SC_Hub_Function_Binding_Set(instance, hub_binding);
|
||||
Network_Port_SC_Hub_Function_Enable_Set(instance, hub_binding != NULL);
|
||||
|
||||
/* last thing - clear pending changes - we don't want to set these
|
||||
since they are already set */
|
||||
Network_Port_Changes_Pending_Set(instance, false);
|
||||
}
|
||||
|
||||
static bool dlenv_hub_connection_status_check(void)
|
||||
{
|
||||
uint32_t instance = Network_Port_Index_To_Instance(0);
|
||||
BACNET_SC_HUB_CONNECTION_STATUS *status;
|
||||
|
||||
status = Network_Port_SC_Primary_Hub_Connection_Status(instance);
|
||||
if (status && status->State == BACNET_SC_CONNECTION_STATE_CONNECTED) {
|
||||
return true;
|
||||
}
|
||||
|
||||
status = Network_Port_SC_Failover_Hub_Connection_Status(instance);
|
||||
if (status && status->State == BACNET_SC_CONNECTION_STATE_CONNECTED) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Datalink network port object settings for BACnet/SC
|
||||
*/
|
||||
void dlenv_network_port_init(void)
|
||||
{
|
||||
/* if a user has configured BACnet/SC port with primary hub URI, */
|
||||
/* wait for a establishin of a connection to BACnet/SC hub at first */
|
||||
/* to reduce possibility of packet losses. */
|
||||
if (Network_Port_SC_Primary_Hub_URI_char(1)) {
|
||||
while (!dlenv_hub_connection_status_check()) {
|
||||
bsc_wait(1);
|
||||
bsc_maintenance_timer(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
/**
|
||||
* Datalink network port object settings
|
||||
@@ -548,6 +729,24 @@ void dlenv_maintenance_timer(uint16_t elapsed_seconds)
|
||||
* - BACNET_BIP6_PORT - UDP/IP port number (0..65534) used for BACnet/IPv6
|
||||
* communications. Default is 47808 (0xBAC0).
|
||||
* - BACNET_BIP6_BROADCAST - FF05::BAC0 or FF02::BAC0 or ...
|
||||
* - BACDL_BSC: (BACnet Secure Connect)
|
||||
* - BACNET_SC_PRIMARY_HUB_URI
|
||||
* - BACNET_SC_FAILOVER_HUB_URI
|
||||
* - BACNET_SC_ISSUER_1_CERTIFICATE_FILE
|
||||
* - BACNET_SC_ISSUER_2_CERTIFICATE_FILE
|
||||
* - BACNET_SC_OPERATIONAL_CERTIFICATE_FILE
|
||||
* - BACNET_SC_OPERATIONAL_CERTIFICATE_PRIVATE_KEY_FILE
|
||||
* - BACNET_SC_DIRECT_CONNECT_BINDING - pair: interface name (optional) and
|
||||
* TCP/IP port number (0..65534), like "50000" (port only) or
|
||||
* "eth0:50000"(both)
|
||||
* - BACNET_SC_HUB_FUNCTION_BINDING - pair: interface name (optional) and
|
||||
* TCP/IP port number (0..65534), like "50000" (port only) or
|
||||
* "eth0:50000"(both)
|
||||
* - BACNET_SC_DIRECT_CONNECT_INITIATE - if true equal "1", "y", "Y",
|
||||
* otherwise false
|
||||
* - BACNET_SC_DIRECT_CONNECT_ACCEPT_URLS - list of direct connect accept URLs
|
||||
* separated by a space character, e.g.
|
||||
* "wss://192.0.0.1:40000 wss://192.0.0.2:6666"
|
||||
*/
|
||||
void dlenv_init(void)
|
||||
{
|
||||
@@ -574,6 +773,8 @@ void dlenv_init(void)
|
||||
datalink_set("ethernet");
|
||||
#elif defined(BACDL_ARCNET)
|
||||
datalink_set("arcnet");
|
||||
#elif defined(BACDL_BSC)
|
||||
datalink_set("bsc");
|
||||
#else
|
||||
datalink_set("none");
|
||||
#endif
|
||||
@@ -665,6 +866,35 @@ void dlenv_init(void)
|
||||
} else {
|
||||
dlmstp_set_mac_address(127);
|
||||
}
|
||||
#elif defined(BACDL_BSC)
|
||||
char *primary_hub_uri;
|
||||
char *failover_hub_uri;
|
||||
char *filename_ca_1_cert;
|
||||
char *filename_ca_2_cert;
|
||||
char *filename_cert;
|
||||
char *filename_key;
|
||||
char *direct_binding;
|
||||
char *hub_binding;
|
||||
char *direct_connect_initiate;
|
||||
char *direct_connect_accept_urls;
|
||||
|
||||
primary_hub_uri = getenv("BACNET_SC_PRIMARY_HUB_URI");
|
||||
failover_hub_uri = getenv("BACNET_SC_FAILOVER_HUB_URI");
|
||||
filename_ca_1_cert = getenv("BACNET_SC_ISSUER_1_CERTIFICATE_FILE");
|
||||
filename_ca_2_cert = getenv("BACNET_SC_ISSUER_2_CERTIFICATE_FILE");
|
||||
filename_cert = getenv("BACNET_SC_OPERATIONAL_CERTIFICATE_FILE");
|
||||
filename_key = getenv("BACNET_SC_OPERATIONAL_CERTIFICATE_PRIVATE_KEY_FILE");
|
||||
direct_binding = getenv("BACNET_SC_DIRECT_CONNECT_BINDING");
|
||||
hub_binding = getenv("BACNET_SC_HUB_FUNCTION_BINDING");
|
||||
direct_connect_initiate = getenv("BACNET_SC_DIRECT_CONNECT_INITIATE");
|
||||
direct_connect_accept_urls = getenv("BACNET_SC_DIRECT_CONNECT_ACCEPT_URLS");
|
||||
bacnet_secure_connect_network_port_init(
|
||||
primary_hub_uri, failover_hub_uri, filename_ca_1_cert,
|
||||
filename_ca_2_cert, filename_cert, filename_key, direct_binding,
|
||||
hub_binding, direct_connect_initiate, direct_connect_accept_urls);
|
||||
if (!bsc_cert_files_check()) {
|
||||
exit(1);
|
||||
}
|
||||
#endif
|
||||
pEnv = getenv("BACNET_APDU_TIMEOUT");
|
||||
if (pEnv) {
|
||||
|
||||
Reference in New Issue
Block a user