From 25d14c7c15a4411963bc123a955f02f2fce37dd6 Mon Sep 17 00:00:00 2001 From: Steve Karg Date: Fri, 14 Nov 2025 15:41:17 -0600 Subject: [PATCH] Fixed BACnet/SC secure connect VMAC, UUID, and initialization sequence (#1142) * Refactored the BACnet/SC datalink initialization order by moving certificate file checks and hub connection registration to occur after datalink initialization * Replaced stdlib rand() with platform-specific cryptographically secure random functions (RtlGenRandom for Windows, getrandom for Linux, arc4random_buf for BSD) to generate UUID and VMAC addresses, preventing duplicates that broke connections * Enabled conditional debug output in BACnet/SC components when BUILD=debug is specified --- CHANGELOG.md | 6 + Makefile | 8 +- apps/Makefile | 14 +- apps/sc-hub/README.md | 10 +- ports/bsd/bsc-event.c | 28 +- ports/bsd/websocket-cli.c | 4 +- ports/bsd/websocket-srv.c | 4 +- ports/linux/bsc-event.c | 29 +- ports/linux/websocket-cli.c | 4 +- ports/linux/websocket-srv.c | 4 +- ports/posix/bacfile-posix.c | 13 + ports/win32/bsc-event.c | 27 +- ports/win32/websocket-cli.c | 4 +- ports/win32/websocket-srv.c | 4 +- src/bacnet/basic/object/bacfile.c | 7 +- src/bacnet/basic/object/sc_netport.h | 19 ++ src/bacnet/config.h | 19 -- src/bacnet/datalink/bsc/bsc-datalink.c | 18 +- src/bacnet/datalink/bsc/bsc-datalink.h | 2 +- src/bacnet/datalink/bsc/bsc-event.h | 14 + src/bacnet/datalink/bsc/bsc-hub-connector.c | 4 +- src/bacnet/datalink/bsc/bsc-hub-function.c | 117 ++++---- src/bacnet/datalink/bsc/bsc-node-switch.c | 4 +- src/bacnet/datalink/bsc/bsc-node.c | 4 +- src/bacnet/datalink/bsc/bsc-socket.c | 242 +++++++++-------- src/bacnet/datalink/bsc/bsc-util.c | 254 ++++++++++++++---- src/bacnet/datalink/bsc/bsc-util.h | 10 +- src/bacnet/datalink/dlenv.c | 133 ++++++--- .../basic/object/netport/CMakeLists.txt | 1 + test/bacnet/datalink/bsc-datalink/src/main.c | 4 +- 30 files changed, 672 insertions(+), 339 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 942fd6fb..c7137013 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -148,6 +148,12 @@ The git repositories are hosted at the following sites: ### Fixed +* Fixed the sequence of BACnet/SC datalink initialization that was + broken during datalink environment changes and POSIX file refactoring. + Refactored the UUID and VMAC random functions into port specific + since stdlib rand() is not random and caused duplicate UUID and VMAC + preventing BACnet/SC from forming any stable connections. + Enabled debug in BACnet/SC datalink when BUILD=debug used.(#1142) * Fixed WPM workaround for BTL Specified Test 9.23.2.X5 by reverting.(#1140) * Fixed the API integration for the additional datatypes now supported in the Channel object by adding CHANNEL_VALUE_ALL to enable and test. (#1135) diff --git a/Makefile b/Makefile index 0072a020..442c5728 100644 --- a/Makefile +++ b/Makefile @@ -62,7 +62,7 @@ ethernet: # see .github/workflows/gcc.yml .PHONY: bsc bsc: - $(MAKE) BACDL=bsc -s -C apps all + $(MAKE) LEGACY=true BACDL=bsc -s -C apps all .PHONY: apps apps: @@ -226,7 +226,11 @@ server-mini: .PHONY: sc-hub sc-hub: - $(MAKE) BACDL=bsc -s -C apps $@ + $(MAKE) LEGACY=true BACDL=bsc -s -C apps $@ + +.PHONY: sc-hub-debug +sc-hub-debug: + $(MAKE) LEGACY=true BACDL=bsc BUILD=debug -s -C apps sc-hub .PHONY: mstpcap mstpcap: diff --git a/apps/Makefile b/apps/Makefile index af85bfa0..bfe60035 100644 --- a/apps/Makefile +++ b/apps/Makefile @@ -43,8 +43,7 @@ ifeq (${BACDL},bip6) BACDL_DEFINE=-DBACDL_BIP6=1 endif ifeq (${BACDL},bsc) -BACDL_DEFINE=-DBACDL_BSC=1 -BACNET_DEFINE=-DBACFILE=1 +BACDL_DEFINE=-DBACDL_BSC=1 -DBACFILE=1 endif ifeq (${BACDL},zigbee) BACDL_DEFINE=-DBACDL_ZIGBEE=1 @@ -206,6 +205,17 @@ DEBUGGING = -g -DDEBUG_ENABLED=1 ifeq (${BACDL},bip) BACNET_DEFINES += -DBIP_DEBUG endif +ifeq (${BACDL},bsc) +CFLAGS += -DDEBUG_BSC_DATALINK=1 +CFLAGS += -DDEBUG_BSC_EVENT=0 +CFLAGS += -DDEBUG_BSC_HUB_CONNECTOR=0 +CFLAGS += -DDEBUG_BSC_HUB_FUNCTION=0 +CFLAGS += -DDEBUG_BSC_NODE_SWITCH=0 +CFLAGS += -DDEBUG_BSC_NODE=0 +CFLAGS += -DDEBUG_BSC_SOCKET=0 +CFLAGS += -DDEBUG_WEBSOCKET_CLIENT=0 +CFLAGS += -DDEBUG_WEBSOCKET_SERVER=0 +endif endif ifeq (${LEGACY},true) diff --git a/apps/sc-hub/README.md b/apps/sc-hub/README.md index e365d9c2..c81c1cad 100644 --- a/apps/sc-hub/README.md +++ b/apps/sc-hub/README.md @@ -2,23 +2,23 @@ Test BACnet/SC using the following steps: - * Build apps for bsc datalink: + * Build all the apps and the hub for the BACnet/SC datalink: - make bsc + make clean bsc sc-hub - * Run hub app: + * Run the BACnet/SC hub application: cd bin ./bsc-server.sh ./bacschub 1 Hubster - * Run server app: + * Run BACnet/SC server application: cd bin ./bsc-client.sh ./bacserv 123 Francine - * Run any client: + * Run any BACnet/SC client: cd bin ./bsc-client.sh diff --git a/ports/bsd/bsc-event.c b/ports/bsd/bsc-event.c index b39b9114..cc34dfdf 100644 --- a/ports/bsd/bsc-event.c +++ b/ports/bsd/bsc-event.c @@ -1,6 +1,6 @@ /** * @file - * @brief Implementation of mutex abstraction used in BACNet secure connect. + * @brief Implementation of port specific API used in BACNet secure connect. * @author Kirill Neznamov * @date August 2022 * @copyright SPDX-License-Identifier: GPL-2.0-or-later WITH GCC-exception-2.0 @@ -14,10 +14,8 @@ #include "bacnet/basic/sys/debug.h" #include "bacnet/datalink/bsc/bsc-event.h" -#define DEBUG_BSC_EVENT 0 - #undef DEBUG_PRINTF -#if DEBUG_BSC_EVENT == 1 +#if DEBUG_BSC_EVENT #define DEBUG_PRINTF printf #else #undef DEBUG_ENABLED @@ -179,3 +177,25 @@ void bsc_wait_ms(int mseconds) { usleep(mseconds * 1000); } + +void bsc_generate_random_vmac(BACNET_SC_VMAC_ADDRESS *p) +{ + arc4random_buf(p->address, BVLC_SC_VMAC_SIZE); + + /* According H.7.3 EUI-48 and Random-48 VMAC Address: + The Random-48 VMAC is a 6-octet VMAC address in which the least + significant 4 bits (Bit 3 to Bit 0) in the first octet shall be + B'0010' (X'2'), and all other 44 bits are randomly selected to be + 0 or 1. */ + p->address[0] = (p->address[0] & 0xF0) | 0x02; + + debug_printf_hex( + 0, p->address, BVLC_SC_VMAC_SIZE, "bsc_generate_random_vmac:"); +} + +void bsc_generate_random_uuid(BACNET_SC_UUID *p) +{ + arc4random_buf(p->uuid, BVLC_SC_UUID_SIZE); + debug_printf_hex( + 0, p->uuid, BVLC_SC_UUID_SIZE, "bsc_generate_random_uuid:"); +} diff --git a/ports/bsd/websocket-cli.c b/ports/bsd/websocket-cli.c index 12750cb4..213c97f1 100644 --- a/ports/bsd/websocket-cli.c +++ b/ports/bsd/websocket-cli.c @@ -14,10 +14,8 @@ #include "bacnet/basic/sys/debug.h" #include "websocket-global.h" -#define DEBUG_WEBSOCKET_CLIENT 0 - #undef DEBUG_PRINTF -#if DEBUG_WEBSOCKET_CLIENT == 1 +#if DEBUG_WEBSOCKET_CLIENT #define DEBUG_PRINTF debug_printf #else #undef DEBUG_ENABLED diff --git a/ports/bsd/websocket-srv.c b/ports/bsd/websocket-srv.c index bbb81a00..0eea5482 100644 --- a/ports/bsd/websocket-srv.c +++ b/ports/bsd/websocket-srv.c @@ -15,10 +15,8 @@ #include "websocket-global.h" #include -#define DEBUG_WEBSOCKET_SERVER 0 - #undef DEBUG_PRINTF -#if DEBUG_WEBSOCKET_SERVER == 1 +#if DEBUG_WEBSOCKET_SERVER #define DEBUG_PRINTF debug_printf #else #undef DEBUG_ENABLED diff --git a/ports/linux/bsc-event.c b/ports/linux/bsc-event.c index 8f69f064..ecb37618 100644 --- a/ports/linux/bsc-event.c +++ b/ports/linux/bsc-event.c @@ -1,6 +1,6 @@ /** * @file - * @brief Implementation of mutex abstraction used in BACNet secure connect. + * @brief Implementation of port specific API used in BACNet secure connect. * @author Kirill Neznamov * @date August 2022 * @copyright SPDX-License-Identifier: GPL-2.0-or-later WITH GCC-exception-2.0 @@ -11,13 +11,12 @@ #include #include #include +#include #include "bacnet/basic/sys/debug.h" #include "bacnet/datalink/bsc/bsc-event.h" -#define DEBUG_BSC_EVENT 0 - #undef DEBUG_PRINTF -#if DEBUG_BSC_EVENT == 1 +#if DEBUG_BSC_EVENT #define DEBUG_PRINTF printf #else #undef DEBUG_ENABLED @@ -179,3 +178,25 @@ void bsc_wait_ms(int mseconds) { usleep(mseconds * 1000); } + +void bsc_generate_random_vmac(BACNET_SC_VMAC_ADDRESS *p) +{ + getrandom(p->address, BVLC_SC_VMAC_SIZE, 0); + + /* According H.7.3 EUI-48 and Random-48 VMAC Address: + The Random-48 VMAC is a 6-octet VMAC address in which the least + significant 4 bits (Bit 3 to Bit 0) in the first octet shall be + B'0010' (X'2'), and all other 44 bits are randomly selected to be + 0 or 1. */ + p->address[0] = (p->address[0] & 0xF0) | 0x02; + + debug_printf_hex( + 0, p->address, BVLC_SC_VMAC_SIZE, "bsc_generate_random_vmac:"); +} + +void bsc_generate_random_uuid(BACNET_SC_UUID *p) +{ + getrandom(p->uuid, BVLC_SC_UUID_SIZE, 0); + debug_printf_hex( + 0, p->uuid, BVLC_SC_UUID_SIZE, "bsc_generate_random_uuid:"); +} diff --git a/ports/linux/websocket-cli.c b/ports/linux/websocket-cli.c index 30f4d655..66896849 100644 --- a/ports/linux/websocket-cli.c +++ b/ports/linux/websocket-cli.c @@ -15,10 +15,8 @@ #include "bacnet/basic/sys/debug.h" #include "websocket-global.h" -#define DEBUG_WEBSOCKET_CLIENT 0 - #undef DEBUG_PRINTF -#if DEBUG_WEBSOCKET_CLIENT == 1 +#if DEBUG_WEBSOCKET_CLIENT #define DEBUG_PRINTF debug_printf #else #undef DEBUG_ENABLED diff --git a/ports/linux/websocket-srv.c b/ports/linux/websocket-srv.c index 330972c5..9744ae2a 100644 --- a/ports/linux/websocket-srv.c +++ b/ports/linux/websocket-srv.c @@ -16,10 +16,8 @@ #include "websocket-global.h" #include -#define DEBUG_WEBSOCKET_SERVER 0 - #undef DEBUG_PRINTF -#if DEBUG_WEBSOCKET_SERVER == 1 +#if DEBUG_WEBSOCKET_SERVER #define DEBUG_PRINTF debug_printf #else #undef DEBUG_ENABLED diff --git a/ports/posix/bacfile-posix.c b/ports/posix/bacfile-posix.c index ce91d4a3..1dcc3425 100644 --- a/ports/posix/bacfile-posix.c +++ b/ports/posix/bacfile-posix.c @@ -13,6 +13,7 @@ #include /* BACnet Stack defines - first */ #include "bacnet/bacdef.h" +#include "bacnet/basic/sys/debug.h" #include "bacnet/basic/object/bacfile.h" #ifndef FILE_RECORD_SIZE @@ -57,6 +58,8 @@ size_t bacfile_posix_file_size(const char *pathname) file_size = (size_t)file_position; } fclose(pFile); + } else { + debug_printf_stderr("Failed to open %s for reading!\n", pathname); } } @@ -103,6 +106,8 @@ size_t bacfile_posix_read_stream_data( (void)fseek(pFile, fileStartPosition, SEEK_SET); len = fread(fileData, 1, fileDataLen, pFile); fclose(pFile); + } else { + debug_printf_stderr("Failed to open %s for reading!\n", pathname); } } @@ -145,6 +150,8 @@ size_t bacfile_posix_write_stream_data( } bytes_written = fwrite(fileData, fileDataLen, 1, pFile); fclose(pFile); + } else { + debug_printf_stderr("Failed to open %s for writing!\n", pathname); } } @@ -204,6 +211,8 @@ bool bacfile_posix_write_record_data( status = true; } fclose(pFile); + } else { + debug_printf_stderr("Failed to open %s for writing!\n", pathname); } } @@ -250,6 +259,8 @@ bool bacfile_posix_read_record_data( status = true; } fclose(pFile); + } else { + debug_printf_stderr("Failed to open %s for reading!\n", pathname); } } @@ -268,5 +279,7 @@ void bacfile_posix_init(void) bacfile_read_record_data_callback_set(bacfile_posix_read_record_data); bacfile_file_size_callback_set(bacfile_posix_file_size); bacfile_file_size_set_callback_set(bacfile_posix_file_size_set); +#elif defined(BACDL_BSC) +#error BACFILE is not defined for BACnet/SC! #endif } diff --git a/ports/win32/bsc-event.c b/ports/win32/bsc-event.c index 6ae9d5d0..1a63f40c 100644 --- a/ports/win32/bsc-event.c +++ b/ports/win32/bsc-event.c @@ -1,11 +1,12 @@ /** * @file - * @brief Implementation of mutex abstraction used in BACNet secure connect. + * @brief Implementation of port specific API used in BACNet secure connect. * @author Kirill Neznamov * @date August 2022 * @copyright SPDX-License-Identifier: GPL-2.0-or-later WITH GCC-exception-2.0 */ #include +#include #include #include #include @@ -13,10 +14,8 @@ #include "bacnet/basic/sys/debug.h" #include "bacnet/datalink/bsc/bsc-event.h" -#define DEBUG_BSC_EVENT 0 - #undef DEBUG_PRINTF -#if DEBUG_BSC_EVENT == 1 +#if DEBUG_BSC_EVENT #define DEBUG_PRINTF printf #else #undef DEBUG_ENABLED @@ -144,3 +143,23 @@ void bsc_wait_ms(int mseconds) { Sleep(mseconds); } + +void bsc_generate_random_vmac(BACNET_SC_VMAC_ADDRESS *p) +{ + // Use RtlGenRandom (SystemFunction036) for cryptographically secure random + // bytes + RtlGenRandom(p->address, BVLC_SC_VMAC_SIZE); + + /* According H.7.3 EUI-48 and Random-48 VMAC Address */ + p->address[0] = (p->address[0] & 0xF0) | 0x02; + + debug_printf_hex( + 0, p->address, BVLC_SC_VMAC_SIZE, "bsc_generate_random_vmac:"); +} + +void bsc_generate_random_uuid(BACNET_SC_UUID *p) +{ + RtlGenRandom(p->uuid, BVLC_SC_UUID_SIZE); + debug_printf_hex( + 0, p->uuid, BVLC_SC_UUID_SIZE, "bsc_generate_random_uuid:"); +} diff --git a/ports/win32/websocket-cli.c b/ports/win32/websocket-cli.c index 6075478f..086ecbcf 100644 --- a/ports/win32/websocket-cli.c +++ b/ports/win32/websocket-cli.c @@ -13,10 +13,8 @@ #include "bacnet/basic/sys/debug.h" #include "websocket-global.h" -#define DEBUG_WEBSOCKET_CLIENT 0 - #undef DEBUG_PRINTF -#if DEBUG_WEBSOCKET_CLIENT == 1 +#if DEBUG_WEBSOCKET_CLIENT #define DEBUG_PRINTF debug_printf #else #undef DEBUG_ENABLED diff --git a/ports/win32/websocket-srv.c b/ports/win32/websocket-srv.c index 0c274159..ad8131fc 100644 --- a/ports/win32/websocket-srv.c +++ b/ports/win32/websocket-srv.c @@ -13,10 +13,8 @@ #include "bacnet/basic/sys/debug.h" #include "websocket-global.h" -#define DEBUG_WEBSOCKET_SERVER 0 - #undef DEBUG_PRINTF -#if DEBUG_WEBSOCKET_SERVER == 1 +#if DEBUG_WEBSOCKET_SERVER #define DEBUG_PRINTF debug_printf #else #undef DEBUG_ENABLED diff --git a/src/bacnet/basic/object/bacfile.c b/src/bacnet/basic/object/bacfile.c index 3629ee68..9dcd2fe2 100644 --- a/src/bacnet/basic/object/bacfile.c +++ b/src/bacnet/basic/object/bacfile.c @@ -558,15 +558,12 @@ uint32_t bacfile_write( BACNET_UNSIGNED_INTEGER bacfile_file_size(uint32_t object_instance) { const char *pathname = NULL; - long file_position = 0; BACNET_UNSIGNED_INTEGER file_size = 0; pathname = bacfile_pathname(object_instance); if (pathname) { - file_position = bacfile_file_size_callback(pathname); - if (file_position >= 0) { - file_size = (BACNET_UNSIGNED_INTEGER)file_position; - } + file_size = + (BACNET_UNSIGNED_INTEGER)bacfile_file_size_callback(pathname); } return file_size; diff --git a/src/bacnet/basic/object/sc_netport.h b/src/bacnet/basic/object/sc_netport.h index fdeb1781..8aced890 100644 --- a/src/bacnet/basic/object/sc_netport.h +++ b/src/bacnet/basic/object/sc_netport.h @@ -19,6 +19,25 @@ #include "bacnet/datalink/bsc/bsc-conf.h" #include "bacnet/datalink/bsc/bvlc-sc.h" +#ifndef SC_NETPORT_BVLC_MAX +#define SC_NETPORT_BVLC_MAX 1500 +#endif +#ifndef SC_NETPORT_NPDU_MAX +#define SC_NETPORT_NPDU_MAX 1500 +#endif +#ifndef SC_NETPORT_CONNECT_TIMEOUT +#define SC_NETPORT_CONNECT_TIMEOUT 5 +#endif +#ifndef SC_NETPORT_HEARTBEAT_TIMEOUT +#define SC_NETPORT_HEARTBEAT_TIMEOUT 60 +#endif +#ifndef SC_NETPORT_DISCONNECT_TIMEOUT +#define SC_NETPORT_DISCONNECT_TIMEOUT 150 +#endif +#ifndef SC_NETPORT_RECONNECT_TIME +#define SC_NETPORT_RECONNECT_TIME 2 +#endif + /* BACnet file instance numbers */ #ifndef BSC_ISSUER_CERTIFICATE_FILE_1_INSTANCE #define BSC_ISSUER_CERTIFICATE_FILE_1_INSTANCE \ diff --git a/src/bacnet/config.h b/src/bacnet/config.h index b429cc85..69c72538 100644 --- a/src/bacnet/config.h +++ b/src/bacnet/config.h @@ -164,25 +164,6 @@ #endif #endif -#ifndef SC_NETPORT_BVLC_MAX -#define SC_NETPORT_BVLC_MAX 1500 -#endif -#ifndef SC_NETPORT_NPDU_MAX -#define SC_NETPORT_NPDU_MAX 1500 -#endif -#ifndef SC_NETPORT_CONNECT_TIMEOUT -#define SC_NETPORT_CONNECT_TIMEOUT 5 -#endif -#ifndef SC_NETPORT_HEARTBEAT_TIMEOUT -#define SC_NETPORT_HEARTBEAT_TIMEOUT 60 -#endif -#ifndef SC_NETPORT_DISCONNECT_TIMEOUT -#define SC_NETPORT_DISCONNECT_TIMEOUT 150 -#endif -#ifndef SC_NETPORT_RECONNECT_TIME -#define SC_NETPORT_RECONNECT_TIME 2 -#endif - /* for confirmed messages, this is the number of transactions */ /* that we hold in a queue waiting for timeout. */ /* Configure to zero if you don't want any confirmed messages */ diff --git a/src/bacnet/datalink/bsc/bsc-datalink.c b/src/bacnet/datalink/bsc/bsc-datalink.c index e1c2ff64..e0ffd591 100644 --- a/src/bacnet/datalink/bsc/bsc-datalink.c +++ b/src/bacnet/datalink/bsc/bsc-datalink.c @@ -23,9 +23,8 @@ #include "bacnet/basic/object/bacfile.h" #define PRINTF debug_printf_stderr -#define DEBUG_BSC_DATALINK 0 #undef DEBUG_PRINTF -#if DEBUG_BSC_DATALINK == 1 +#if DEBUG_BSC_DATALINK #define DEBUG_PRINTF debug_printf #else #define DEBUG_PRINTF debug_printf_disabled @@ -94,7 +93,7 @@ static void bsc_node_event( FIFO_Add(&bsc_fifo, pdu, pdu16_len); bsc_event_signal(bsc_data_event); } -#if DEBUG_ENABLED == 1 +#if DEBUG_ENABLED else { PRINTF("pdu of size %d\n is dropped\n", pdu_len); } @@ -260,7 +259,6 @@ int bsc_send_pdu( PRINTF("bsc_send_pdu() <<< ret = -1, incorrect dest mac address\n"); return len; } - len = (int)bvlc_sc_encode_encapsulated_npdu( buf, sizeof(buf), bsc_get_next_message_id(), NULL, &dest_vmac, pdu, pdu_len); @@ -270,6 +268,9 @@ int bsc_send_pdu( if (ret != BSC_SC_SUCCESS) { len = -1; + PRINTF( + "bsc_send_pdu(): bsc_node_send() returned %s\n", + bsc_return_code_to_string(ret)); } } @@ -313,8 +314,6 @@ uint16_t bsc_receive( const char *err_desc = NULL; static uint8_t buf[BVLC_SC_NPDU_SIZE_CONF]; - DEBUG_PRINTF("bsc_receive() >>>\n"); - bws_dispatch_lock(); if (bsc_datalink_state == BSC_DATALINK_STATE_STARTED) { @@ -355,7 +354,7 @@ uint16_t bsc_receive( pdu_len = (uint16_t)dm.payload.encapsulated_npdu.npdu_len; } -#if DEBUG_ENABLED == 1 +#if DEBUG_ENABLED else { PRINTF( "bsc_receive() pdu of size %d is dropped " @@ -369,9 +368,8 @@ uint16_t bsc_receive( DEBUG_PRINTF("bsc_receive() pdu_len = %d\n", pdu_len); } } - bws_dispatch_unlock(); - DEBUG_PRINTF("bsc_receive() <<< ret = %d\n", pdu_len); + return pdu_len; } @@ -608,7 +606,7 @@ static void bsc_update_failed_requests(void) Network_Port_SC_Failed_Connection_Requests_Delete_All(instance); for (i = 0; i < cnt; i++) { if (r[i].Peer_Address.host[0] != 0) { -#if DEBUG_ENABLED == 1 +#if DEBUG_ENABLED DEBUG_PRINTF( "failed request record %d, host %s, vmac %s, uuid " "%s, error %d, details = %s\n", diff --git a/src/bacnet/datalink/bsc/bsc-datalink.h b/src/bacnet/datalink/bsc/bsc-datalink.h index 3fef7fe2..f0a06038 100644 --- a/src/bacnet/datalink/bsc/bsc-datalink.h +++ b/src/bacnet/datalink/bsc/bsc-datalink.h @@ -56,7 +56,7 @@ void bsc_cleanup(void); */ BACNET_STACK_EXPORT -bool bsc_cert_files_check(void); +bool bsc_cert_files_check(uint32_t netport_instance); /** * @brief Blocking thread-safe bsc_send_pdu() function diff --git a/src/bacnet/datalink/bsc/bsc-event.h b/src/bacnet/datalink/bsc/bsc-event.h index 3e1bdcaf..3abb7f1f 100644 --- a/src/bacnet/datalink/bsc/bsc-event.h +++ b/src/bacnet/datalink/bsc/bsc-event.h @@ -9,6 +9,8 @@ #define BACNET_DATALINK_BSC_EVENT_H /* BACnet Stack defines - first */ #include "bacnet/bacdef.h" +/* BACnet Stack Datalink API */ +#include "bacnet/datalink/bsc/bvlc-sc.h" struct BSC_Event; typedef struct BSC_Event BSC_EVENT; @@ -98,4 +100,16 @@ bool bsc_event_timedwait(BSC_EVENT *ev, unsigned int ms_timeout); void bsc_event_signal(BSC_EVENT *ev); +/** + * @brief Generate random BACnet Secure Connect VMAC address + * @param p - pointer to the VMAC address + */ +void bsc_generate_random_vmac(BACNET_SC_VMAC_ADDRESS *p); + +/** + * @brief Generate random BACnet Secure Connect UUID + * @param p - pointer to the UUID + */ +void bsc_generate_random_uuid(BACNET_SC_UUID *p); + #endif diff --git a/src/bacnet/datalink/bsc/bsc-hub-connector.c b/src/bacnet/datalink/bsc/bsc-hub-connector.c index 1952df8b..342d6b45 100644 --- a/src/bacnet/datalink/bsc/bsc-hub-connector.c +++ b/src/bacnet/datalink/bsc/bsc-hub-connector.c @@ -16,10 +16,8 @@ #include "bacnet/basic/object/sc_netport.h" #include "bacnet/bactext.h" -#define DEBUG_BSC_HUB_CONNECTOR 0 - #undef DEBUG_PRINTF -#if DEBUG_BSC_HUB_CONNECTOR == 1 +#if DEBUG_BSC_HUB_CONNECTOR #define DEBUG_PRINTF debug_printf #else #undef DEBUG_ENABLED diff --git a/src/bacnet/datalink/bsc/bsc-hub-function.c b/src/bacnet/datalink/bsc/bsc-hub-function.c index c307f02e..9f17c302 100644 --- a/src/bacnet/datalink/bsc/bsc-hub-function.c +++ b/src/bacnet/datalink/bsc/bsc-hub-function.c @@ -14,15 +14,19 @@ #include "bacnet/bacdef.h" #include "bacnet/npdu.h" #include "bacnet/bacenum.h" - -#define DEBUG_BSC_HUB_FUNCTION 0 - +#include "bacnet/bactext.h" #undef DEBUG_PRINTF -#if DEBUG_BSC_HUB_FUNCTION == 1 +#if DEBUG_BSC_HUB_FUNCTION #define DEBUG_PRINTF debug_printf +#if (DEBUG_BSC_HUB_FUNCTION == 2) +#define DEBUG_PRINTF_VERBOSE debug_printf +#else +#define DEBUG_PRINTF_VERBOSE debug_printf_disabled +#endif #else #undef DEBUG_ENABLED #define DEBUG_PRINTF debug_printf_disabled +#define DEBUG_PRINTF_VERBOSE debug_printf_disabled #endif static BSC_SOCKET *hub_function_find_connection_for_vmac( @@ -152,14 +156,14 @@ hub_function_find_connection_for_uuid(BACNET_SC_UUID *uuid, void *user_arg) bws_dispatch_lock(); f = (BSC_HUB_FUNCTION *)user_arg; for (i = 0; i < sizeof(f->sock) / sizeof(BSC_SOCKET); i++) { - DEBUG_PRINTF( + DEBUG_PRINTF_VERBOSE( "hubf = %p, sock %p, state = %d, uuid = %s\n", f, &f->sock[i], f->sock[i].state, bsc_uuid_to_string(&f->sock[i].uuid)); if (f->sock[i].state != BSC_SOCK_STATE_IDLE && !memcmp( &uuid->uuid[0], &f->sock[i].uuid.uuid[0], sizeof(uuid->uuid))) { bws_dispatch_unlock(); - DEBUG_PRINTF("found socket\n"); + DEBUG_PRINTF_VERBOSE("found socket\n"); return &f->sock[i]; } } @@ -282,14 +286,17 @@ static void hub_function_socket_event( BSC_HUB_FUNCTION *f; size_t len; - DEBUG_PRINTF( + DEBUG_PRINTF_VERBOSE( "hub_function_socket_event() >>> c = %p, ev = %d, reason = " - "%d, desc = %p, pdu = %p, pdu_len = %d, decoded_pdu = %p\n", - c, ev, reason, reason_desc, pdu, pdu_len, decoded_pdu); + "%s, desc = %p, pdu = %p, pdu_len = %d, decoded_pdu = %p\n", + c, ev, bactext_error_code_name(reason), reason_desc, pdu, pdu_len, + decoded_pdu); bws_dispatch_lock(); f = (BSC_HUB_FUNCTION *)c->ctx->user_arg; if (ev == BSC_SOCKET_EVENT_RECEIVED) { + DEBUG_PRINTF( + "BSC-HUB: socket event %s\n", bsc_socket_event_to_string(ev)); /* double check that received message does not contain */ /* originating virtual address and contains dest vaddr */ /* although such kind of check is already in bsc-socket.c */ @@ -299,52 +306,56 @@ static void hub_function_socket_event( p_pdu = bsc_socket_get_global_buf(); len = pdu_len; memcpy(p_pdu, pdu, len); - for (i = 0; i < sizeof(f->sock) / sizeof(BSC_SOCKET); i++) { - if (&f->sock[i] != c && - f->sock[i].state == BSC_SOCK_STATE_CONNECTED) { + if ((&f->sock[i] != c) && + (f->sock[i].state == BSC_SOCK_STATE_CONNECTED)) { /* change origin address if presented or add origin */ /* address into pdu by extending of it's header */ len = (uint16_t)bvlc_sc_set_orig( &p_pdu, len, &c->vmac); ret = bsc_send(&f->sock[i], p_pdu, len); - (void)ret; -#if DEBUG_ENABLED == 1 - if (ret != BSC_SC_SUCCESS) { + if (ret == BSC_SC_SUCCESS) { DEBUG_PRINTF( + "BSC-HUB: " + "sent pdu of %d bytes\n", + len); + } else { + DEBUG_PRINTF( + "BSC-HUB: " "sending of reconstructed pdu failed, " - "err = %d\n", - ret); + "err = %s\n", + bsc_return_code_to_string(ret)); } -#endif } } + } else { + DEBUG_PRINTF( + "BSC-HUB: received pdu with len = %d is dropped\n", + pdu_len); } -#if DEBUG_ENABLED == 1 - else { - DEBUG_PRINTF("pdu with len = %d is dropped\n", pdu_len); - } -#endif } else { dst = hub_function_find_connection_for_vmac( decoded_pdu->hdr.dest, (void *)f); if (!dst) { DEBUG_PRINTF( - "can not find socket, hub dropped pdu of size " + "BSC-HUB: cannot find socket. Hub dropped pdu of size " "%d for dest vmac %s\n", pdu_len, bsc_vmac_to_string(decoded_pdu->hdr.dest)); } else { bvlc_sc_remove_dest_set_orig(pdu, pdu_len, &c->vmac); ret = bsc_send(dst, pdu, pdu_len); - (void)ret; -#if DEBUG_ENABLED == 1 - if (ret != BSC_SC_SUCCESS) { + if (ret == BSC_SC_SUCCESS) { DEBUG_PRINTF( - "sending of pdu of %d bytes failed, err = %d\n", - pdu_len, ret); + "BSC-HUB: " + "sent pdu of %d bytes\n", + pdu_len); + } else { + DEBUG_PRINTF( + "BSC-HUB: sending of pdu of %d bytes failed." + " err = %s\n", + pdu_len, bsc_return_code_to_string(ret)); } -#endif } } } @@ -355,11 +366,17 @@ static void hub_function_socket_event( BSC_HUBF_EVENT_ERROR_DUPLICATED_VMAC, (BSC_HUB_FUNCTION_HANDLE)f, f->user_arg); } + if (reason != ERROR_CODE_SUCCESS) { + DEBUG_PRINTF( + "BSC-HUB: event=%s reason=%s \"%s\"\n", + bsc_socket_event_to_string(ev), bactext_error_code_name(reason), + reason_desc); + } } else if (ev == BSC_SOCKET_EVENT_CONNECTED) { hub_function_update_status(f, c, ev, reason, reason_desc); } bws_dispatch_unlock(); - DEBUG_PRINTF("hub_function_socket_event() <<<\n"); + DEBUG_PRINTF_VERBOSE("hub_function_socket_event() <<<\n"); } /** @@ -430,31 +447,30 @@ BSC_SC_RET bsc_hub_function_start( BSC_SC_RET ret; BSC_HUB_FUNCTION *f; - DEBUG_PRINTF("bsc_hub_function_start() >>>\n"); + DEBUG_PRINTF_VERBOSE("bsc_hub_function_start() >>>\n"); if (!ca_cert_chain || !ca_cert_chain_size || !cert_chain || !cert_chain_size || !key || !key_size || !local_uuid || !local_vmac || !max_local_npdu_len || !max_local_bvlc_len || !connect_timeout_s || !heartbeat_timeout_s || !disconnect_timeout_s || !event_func || !h) { - DEBUG_PRINTF("bsc_hub_function_start() <<< ret = BSC_SC_BAD_PARAM\n"); - return BSC_SC_BAD_PARAM; + ret = BSC_SC_BAD_PARAM; + DEBUG_PRINTF( + "BSC-HUB: start failed. err=%s\n", bsc_return_code_to_string(ret)); + return ret; } - *h = NULL; - bws_dispatch_lock(); f = hub_function_alloc(); if (!f) { bws_dispatch_unlock(); + ret = BSC_SC_NO_RESOURCES; DEBUG_PRINTF( - "bsc_hub_function_start() <<< ret = BSC_SC_NO_RESOURCES\n"); - return BSC_SC_NO_RESOURCES; + "BSC-HUB: alloc failed. err=%s\n", bsc_return_code_to_string(ret)); + return ret; } - f->user_arg = user_arg; f->event_func = event_func; - bsc_init_ctx_cfg( BSC_SOCKET_CTX_ACCEPTOR, &f->cfg, BSC_WEBSOCKET_HUB_PROTOCOL, port, iface, ca_cert_chain, ca_cert_chain_size, cert_chain, cert_chain_size, @@ -470,10 +486,13 @@ BSC_SC_RET bsc_hub_function_start( f->state = BSC_HUB_FUNCTION_STATE_STARTING; *h = (BSC_HUB_FUNCTION_HANDLE)f; } else { + DEBUG_PRINTF( + "BSC-HUB: context initialization failed. err=%s\n", + bsc_return_code_to_string(ret)); hub_function_free(f); } bws_dispatch_unlock(); - DEBUG_PRINTF("bsc_hub_function_start() << ret = %d\n", ret); + DEBUG_PRINTF_VERBOSE("bsc_hub_function_start() << ret = %d\n", ret); return ret; } @@ -484,7 +503,7 @@ BSC_SC_RET bsc_hub_function_start( void bsc_hub_function_stop(BSC_HUB_FUNCTION_HANDLE h) { BSC_HUB_FUNCTION *f = (BSC_HUB_FUNCTION *)h; - DEBUG_PRINTF("bsc_hub_function_stop() >>> h = %p\n", h); + DEBUG_PRINTF_VERBOSE("bsc_hub_function_stop() >>> h = %p\n", h); bws_dispatch_lock(); if (f && f->state != BSC_HUB_FUNCTION_STATE_IDLE && f->state != BSC_HUB_FUNCTION_STATE_STOPPING) { @@ -492,7 +511,7 @@ void bsc_hub_function_stop(BSC_HUB_FUNCTION_HANDLE h) bsc_deinit_ctx(&f->ctx); } bws_dispatch_unlock(); - DEBUG_PRINTF("bsc_hub_function_stop() <<<\n"); + DEBUG_PRINTF_VERBOSE("bsc_hub_function_stop() <<<\n"); } /** @@ -505,13 +524,15 @@ bool bsc_hub_function_stopped(BSC_HUB_FUNCTION_HANDLE h) BSC_HUB_FUNCTION *f = (BSC_HUB_FUNCTION *)h; bool ret = false; - DEBUG_PRINTF("bsc_hub_function_stopped() >>> h = %p\n", h); + DEBUG_PRINTF_VERBOSE("bsc_hub_function_stopped() >>> h = %p\n", h); bws_dispatch_lock(); if (f && f->state == BSC_HUB_FUNCTION_STATE_IDLE) { ret = true; } bws_dispatch_unlock(); - DEBUG_PRINTF("bsc_hub_function_stopped() <<< ret = %d\n", ret); + DEBUG_PRINTF_VERBOSE( + "bsc_hub_function_stopped() <<< ret = %s\n", ret ? "true" : "false"); + return ret; } @@ -525,12 +546,14 @@ bool bsc_hub_function_started(BSC_HUB_FUNCTION_HANDLE h) BSC_HUB_FUNCTION *f = (BSC_HUB_FUNCTION *)h; bool ret = false; - DEBUG_PRINTF("bsc_hub_function_started() >>> h = %p\n", h); + DEBUG_PRINTF_VERBOSE("bsc_hub_function_started() >>> h = %p\n", h); bws_dispatch_lock(); if (f && f->state == BSC_HUB_FUNCTION_STATE_STARTED) { ret = true; } bws_dispatch_unlock(); - DEBUG_PRINTF("bsc_hub_function_started() <<< ret = %d\n", ret); + DEBUG_PRINTF_VERBOSE( + "bsc_hub_function_started() <<< ret = %s\n", ret ? "true" : "false"); + return ret; } diff --git a/src/bacnet/datalink/bsc/bsc-node-switch.c b/src/bacnet/datalink/bsc/bsc-node-switch.c index 61e06828..4c4f13bd 100644 --- a/src/bacnet/datalink/bsc/bsc-node-switch.c +++ b/src/bacnet/datalink/bsc/bsc-node-switch.c @@ -16,10 +16,8 @@ #include "bacnet/npdu.h" #include "bacnet/bacenum.h" -#define DEBUG_BSC_NODE_SWITCH 0 - #undef DEBUG_PRINTF -#if DEBUG_BSC_NODE_SWITCH == 1 +#if DEBUG_BSC_NODE_SWITCH #define DEBUG_PRINTF debug_printf #else #undef DEBUG_ENABLED diff --git a/src/bacnet/datalink/bsc/bsc-node.c b/src/bacnet/datalink/bsc/bsc-node.c index 0a46360c..c898f2a5 100644 --- a/src/bacnet/datalink/bsc/bsc-node.c +++ b/src/bacnet/datalink/bsc/bsc-node.c @@ -19,10 +19,8 @@ #include "bacnet/npdu.h" #include "bacnet/bacenum.h" -#define DEBUG_BSC_NODE 0 - #undef DEBUG_PRINTF -#if DEBUG_BSC_NODE == 1 +#if DEBUG_BSC_NODE #define DEBUG_PRINTF debug_printf #else #undef DEBUG_ENABLED diff --git a/src/bacnet/datalink/bsc/bsc-socket.c b/src/bacnet/datalink/bsc/bsc-socket.c index d3da68bd..33223f52 100644 --- a/src/bacnet/datalink/bsc/bsc-socket.c +++ b/src/bacnet/datalink/bsc/bsc-socket.c @@ -9,20 +9,25 @@ #include #include #include +#include "bacnet/bactext.h" #include "bacnet/datalink/bsc/bvlc-sc.h" #include "bacnet/datalink/bsc/bsc-socket.h" #include "bacnet/datalink/bsc/bsc-util.h" #include "bacnet/basic/sys/mstimer.h" #include "bacnet/basic/sys/debug.h" -#define DEBUG_BSC_SOCKET 0 - #undef DEBUG_PRINTF -#if DEBUG_BSC_SOCKET == 1 +#if DEBUG_BSC_SOCKET #define DEBUG_PRINTF debug_printf +#if (DEBUG_BSC_SOCKET == 2) +#define DEBUG_PRINTF_VERBOSE debug_printf +#else +#define DEBUG_PRINTF_VERBOSE debug_printf_disabled +#endif #else #undef DEBUG_ENABLED #define DEBUG_PRINTF debug_printf_disabled +#define DEBUG_PRINTF_VERBOSE debug_printf_disabled #endif static const char *s_error_no_origin = @@ -135,7 +140,7 @@ void bsc_init_ctx_cfg( unsigned int heartbeat_timeout_s, unsigned int disconnect_timeout_s) { - DEBUG_PRINTF("bsc_init_ctx_cfg() >>> cfg = %p\n"); + DEBUG_PRINTF_VERBOSE("bsc_init_ctx_cfg() >>> cfg = %p\n"); if (cfg) { cfg->proto = proto; cfg->port = port; @@ -155,7 +160,7 @@ void bsc_init_ctx_cfg( cfg->heartbeat_timeout_s = heartbeat_timeout_s; cfg->disconnect_timeout_s = disconnect_timeout_s; } - DEBUG_PRINTF("bsc_init_ctx_cfg() <<<\n"); + DEBUG_PRINTF_VERBOSE("bsc_init_ctx_cfg() <<<\n"); } /** @@ -200,11 +205,12 @@ static BSC_SOCKET *bsc_find_free_socket(BSC_SOCKET_CTX *ctx) static void bsc_srv_process_error(BSC_SOCKET *c, BACNET_ERROR_CODE reason) { DEBUG_PRINTF( - "bsc_srv_process_error() >>> c = %p, reason = %d\n", c, reason); + "bsc_srv_process_error() >>> c = %p, reason = %s\n", c, + bactext_error_code_name(reason)); c->state = BSC_SOCK_STATE_ERROR; c->reason = reason; bws_srv_disconnect(c->ctx->sh, c->wh); - DEBUG_PRINTF("bsc_srv_process_error() <<<\n"); + DEBUG_PRINTF_VERBOSE("bsc_srv_process_error() <<<\n"); } /** @@ -214,11 +220,13 @@ static void bsc_srv_process_error(BSC_SOCKET *c, BACNET_ERROR_CODE reason) */ static void bsc_cli_process_error(BSC_SOCKET *c, BACNET_ERROR_CODE reason) { - DEBUG_PRINTF("bsc_cli_process_error) >>> c = %p, reason = %d\n", c, reason); + DEBUG_PRINTF( + "bsc_cli_process_error() >>> c = %p, reason = %s\n", c, + bactext_error_code_name(reason)); c->state = BSC_SOCK_STATE_ERROR; c->reason = reason; bws_cli_disconnect(c->wh); - DEBUG_PRINTF("bsc_cli_process_error) <<<\n"); + DEBUG_PRINTF_VERBOSE("bsc_cli_process_error() <<<\n"); } /** @@ -283,7 +291,8 @@ static bool bsc_prepare_error_extended( #endif message_id = bsc_get_next_message_id(); - DEBUG_PRINTF(" message_id = %d\n", message_id); + DEBUG_PRINTF( + " message_id = %04x\n", message_id); len = bvlc_sc_encode_result( TX_BUF_PTR(c), TX_BUF_BYTES_AVAIL(c), message_id, origin, dest, @@ -295,7 +304,7 @@ static bool bsc_prepare_error_extended( "bsc_prepare_error_extended() <<< ret = true, pdu_len = %d\n", len); return true; } - DEBUG_PRINTF("bsc_prepare_error_extended() <<< ret = false\n"); + DEBUG_PRINTF_VERBOSE("bsc_prepare_error_extended() <<< ret = false\n"); return false; } @@ -349,6 +358,9 @@ static bool bsc_prepare_protocol_error( BACNET_ERROR_CODE error_code, const char *utf8_details_string) { + DEBUG_PRINTF( + "Socket %p Error: %s %s\n", c, bactext_error_class_name(error_class), + bactext_error_code_name(error_code)); return bsc_prepare_protocol_error_extended( c, dm, origin, dest, NULL, error_class, error_code, utf8_details_string); @@ -389,14 +401,14 @@ static void bsc_process_socket_disconnecting( size_t buflen, bool *need_disconnect) { - DEBUG_PRINTF("bsc_process_socket_disconnecting() >>> c = %p\n", c); + DEBUG_PRINTF_VERBOSE("bsc_process_socket_disconnecting() >>> c = %p\n", c); if (dm->hdr.bvlc_function == BVLC_SC_DISCONNECT_ACK) { #if DEBUG_BSC_SOCKET == 1 if (dm->hdr.message_id != c->expected_disconnect_message_id) { DEBUG_PRINTF( "bsc_process_socket_disconnecting() got disconnect ack with " - "unexpected message id %d for socket %p\n", + "unexpected message id %04x for socket %p\n", dm->hdr.message_id, c); } else { DEBUG_PRINTF( @@ -429,7 +441,7 @@ static void bsc_process_socket_disconnecting( c->ctx->funcs->socket_event( c, BSC_SOCKET_EVENT_RECEIVED, 0, NULL, buf, buflen, dm); } - DEBUG_PRINTF("bsc_process_socket_disconnecting() <<<\n"); + DEBUG_PRINTF_VERBOSE("bsc_process_socket_disconnecting() <<<\n"); } /** @@ -452,29 +464,27 @@ static void bsc_process_socket_connected_state( uint16_t message_id; size_t len; - DEBUG_PRINTF( + DEBUG_PRINTF_VERBOSE( "bsc_process_socket_connected_state() >>> c = %p, dm = %p, buf = %p, " "buflen = %d\n", c, dm, buf, buflen); if (dm->hdr.bvlc_function == BVLC_SC_HEARTBEAT_ACK) { -#if DEBUG_ENABLED == 1 if (dm->hdr.message_id != c->expected_heartbeat_message_id) { - DEBUG_PRINTF( + DEBUG_PRINTF_VERBOSE( "bsc_process_socket_connected_state() got heartbeat ack with " - "unexpected message id %d for socket %p\n", + "unexpected message id %04x for socket %p\n", dm->hdr.message_id, c); } else { - DEBUG_PRINTF( + DEBUG_PRINTF_VERBOSE( "bsc_process_socket_connected_state() got heartbeat ack for " "socket %p\n", c); } -#endif } else if (dm->hdr.bvlc_function == BVLC_SC_HEARTBEAT_REQUEST) { DEBUG_PRINTF( "bsc_process_socket_connected_state() got heartbeat " - "request with message_id %d\n", + "request with message id %04x\n", dm->hdr.message_id); message_id = dm->hdr.message_id; len = bvlc_sc_encode_heartbeat_ack( @@ -482,20 +492,17 @@ static void bsc_process_socket_connected_state( if (len) { TX_BUF_UPDATE(c, len); *need_send = true; - } -#if DEBUG_BSC_SOCKET == 1 - else { + } else { DEBUG_PRINTF( "bsc_process_socket_connected_state() no resources to " "answer on heartbeat request " "socket %p\n", c); } -#endif } else if (dm->hdr.bvlc_function == BVLC_SC_DISCONNECT_REQUEST) { DEBUG_PRINTF( "bsc_process_socket_connected_state() got disconnect " - "request with message_id %d\n", + "request with message id %04x\n", dm->hdr.message_id); message_id = dm->hdr.message_id; len = bvlc_sc_encode_disconnect_ack( @@ -518,7 +525,7 @@ static void bsc_process_socket_connected_state( /* and hope that remote peer clears itself up. */ DEBUG_PRINTF( "bsc_process_socket_connected_state() got unexpected " - "disconnect ack with message_id %d\n", + "disconnect ack with message id %04x\n", dm->hdr.message_id); c->state = BSC_SOCK_STATE_DISCONNECTING; *need_disconnect = true; @@ -545,7 +552,7 @@ static void bsc_process_socket_connected_state( c, BSC_SOCKET_EVENT_RECEIVED, 0, NULL, buf, buflen, dm); } - DEBUG_PRINTF("bsc_process_socket_connected_state() <<<\n"); + DEBUG_PRINTF_VERBOSE("bsc_process_socket_connected_state() <<<\n"); } /** @@ -572,7 +579,7 @@ static void bsc_process_socket_state( bool valid = true; size_t len; - DEBUG_PRINTF( + DEBUG_PRINTF_VERBOSE( "bsc_process_socket_state() >>> ctx = %p, c = %p, state = %d, " "rx_buf = %p, rx_buf_size = %d\n", c->ctx, c, c->state, rx_buf, rx_buf_size); @@ -592,18 +599,17 @@ static void bsc_process_socket_state( *need_send = bsc_prepare_protocol_error( c, dm, dm->hdr.origin, dm->hdr.dest, error_class, error_code, err_desc); - } -#if DEBUG_BSC_SOCKET == 1 - else { + } else { DEBUG_PRINTF( "bsc_process_socket_state() decoding failed, message " "is silently dropped cause it's length < 4 bytes\n"); } -#endif } else { - DEBUG_PRINTF( - "c->dm.hdr.bvlc_function == %d, message_id = %d\n", - dm->hdr.bvlc_function, dm->hdr.message_id); + DEBUG_PRINTF_VERBOSE( + "bsc_process_socket_state() " + "bvlc_function %s, message id %04x\n", + bsc_bvlc_message_type_to_string(dm->hdr.bvlc_function), + dm->hdr.message_id); if (dm->hdr.bvlc_function == BVLC_SC_ENCAPSULATED_NPDU || dm->hdr.bvlc_function == BVLC_SC_ADVERTISIMENT || dm->hdr.bvlc_function == BVLC_SC_ADDRESS_RESOLUTION_ACK || @@ -612,14 +618,12 @@ static void bsc_process_socket_state( dm->hdr.bvlc_function == BVLC_SC_RESULT) { if (c->ctx->cfg->type == BSC_SOCKET_CTX_INITIATOR && c->ctx->cfg->proto == BSC_WEBSOCKET_HUB_PROTOCOL) { - /* this is a case when socket is a hub connector receiving - */ - /* from hub */ + /* this is a case when socket is a hub connector + receiving from hub */ if (dm->hdr.origin == NULL && dm->hdr.bvlc_function != BVLC_SC_RESULT) { error_class = ERROR_CLASS_COMMUNICATION; error_code = ERROR_CODE_HEADER_ENCODING_ERROR; - *need_send = bsc_prepare_protocol_error( c, dm, NULL, &c->vmac, error_class, error_code, s_error_no_origin); @@ -637,8 +641,8 @@ static void bsc_process_socket_state( } else if ( c->ctx->cfg->type == BSC_SOCKET_CTX_ACCEPTOR && c->ctx->cfg->proto == BSC_WEBSOCKET_HUB_PROTOCOL) { - /* this is a case when socket is hub function receiving */ - /* from node */ + /* this is a case when socket is hub function + receiving from node */ if (dm->hdr.dest == NULL) { error_class = ERROR_CLASS_COMMUNICATION; error_code = ERROR_CODE_HEADER_ENCODING_ERROR; @@ -656,7 +660,6 @@ static void bsc_process_socket_state( } } } - /* every valid message restarts heartbeat timeout */ /* and only valid messages are processed */ if (valid) { @@ -680,38 +683,39 @@ static void bsc_process_socket_state( } expired = mstimer_expired(&c->t); - DEBUG_PRINTF("bsc_process_socket_state() expired = %d\n", expired); - + DEBUG_PRINTF_VERBOSE( + "BSC-Socket: connection mstimer_expired() = %d\n", expired); if (c->state == BSC_SOCK_STATE_AWAITING_ACCEPT && expired) { c->state = BSC_SOCK_STATE_ERROR; c->reason = ERROR_CODE_TIMEOUT; *need_disconnect = true; + DEBUG_PRINTF("BSC-Socket: connection timeout AWAITING_ACCEPT.\n"); } else if (c->state == BSC_SOCK_STATE_AWAITING_REQUEST && expired) { c->state = BSC_SOCK_STATE_ERROR; c->reason = ERROR_CODE_TIMEOUT; *need_disconnect = true; + DEBUG_PRINTF("BSC-Socket: connection timeout AWAITING_REQUEST.\n"); } else if (c->state == BSC_SOCK_STATE_DISCONNECTING && expired) { c->state = BSC_SOCK_STATE_ERROR; c->reason = ERROR_CODE_TIMEOUT; *need_disconnect = true; + DEBUG_PRINTF("BSC-Socket: connection timeout DISCONNECTING.\n"); } else if (c->state == BSC_SOCK_STATE_CONNECTED) { expired = mstimer_expired(&c->heartbeat); - DEBUG_PRINTF( - "bsc_process_socket_state() heartbeat timeout expired = %d\n", - expired); + DEBUG_PRINTF_VERBOSE( + "BSC-Socket: heartbeat mstimer_expired() = %d\n", expired); if (expired) { - DEBUG_PRINTF( - "bsc_process_socket_state() heartbeat timeout elapsed " + DEBUG_PRINTF_VERBOSE( + "BSC-Socket: heartbeat timeout elapsed " "for socket %p\n", c); if (c->ctx->cfg->type == BSC_SOCKET_CTX_INITIATOR) { DEBUG_PRINTF( - "bsc_process_socket_state() going to send heartbeat " - "request on connection %p\n", + "BSC-Socket: sending heartbeat request on connection %p\n", c); c->expected_heartbeat_message_id = bsc_get_next_message_id(); - DEBUG_PRINTF( - "bsc_process_socket_state() heartbeat message_id %04x\n", + DEBUG_PRINTF_VERBOSE( + "BSC-Socket: heartbeat message id %04x\n", c->expected_heartbeat_message_id); len = bvlc_sc_encode_heartbeat_request( @@ -725,14 +729,14 @@ static void bsc_process_socket_state( *need_send = true; } else { DEBUG_PRINTF( - "bsc_process_socket_state() sending of " + "BSC-Socket: sending of " "heartbeat request failed on connection %p\n", c); } } else if (c->ctx->cfg->type == BSC_SOCKET_CTX_ACCEPTOR) { DEBUG_PRINTF( - "bsc_process_socket_state() zombie socket %p is " - "disconnecting...\n", + "BSC-Socket: zombie socket %p is " + "disconnecting by timeout.\n", c); c->state = BSC_SOCK_STATE_ERROR; c->reason = ERROR_CODE_TIMEOUT; @@ -740,7 +744,7 @@ static void bsc_process_socket_state( } } } - DEBUG_PRINTF("bsc_process_socket_state() <<<\n"); + DEBUG_PRINTF_VERBOSE("bsc_process_socket_state() <<<\n"); } /** @@ -785,24 +789,24 @@ static void bsc_runloop_socket( */ void bsc_socket_maintenance_timer(uint16_t seconds) { - int i, j; - (void)seconds; - DEBUG_PRINTF("bsc_socket_maintenance_timer() >>>\n"); + int i, j, count = 0; + DEBUG_PRINTF_VERBOSE( + "bsc_socket_maintenance_timer(%us) >>>\n", (unsigned)seconds); bws_dispatch_lock(); - for (i = 0; i < BSC_SOCKET_CTX_NUM; i++) { if (bsc_socket_ctx[i] != NULL) { if (bsc_socket_ctx[i]->state == BSC_CTX_STATE_INITIALIZED) { for (j = 0; j < bsc_socket_ctx[i]->sock_num; j++) { + count++; bsc_runloop_socket( &bsc_socket_ctx[i]->sock[j], NULL, NULL, 0); } } } } - bws_dispatch_unlock(); - DEBUG_PRINTF("bsc_socket_maintenance_timer() <<<\n"); + DEBUG_PRINTF_VERBOSE( + "bsc_socket_maintenance_timer() <<< %d sockets processed\n", count); } /** @@ -824,7 +828,7 @@ static void bsc_process_srv_awaiting_request( uint16_t uclass; const char *err_desc = NULL; - DEBUG_PRINTF( + DEBUG_PRINTF_VERBOSE( "bsc_process_srv_awaiting_request() >>> c = %p, dm = %p, buf = %p, " "bufsize = %d\n", c, dm, buf, bufsize); @@ -858,8 +862,8 @@ static void bsc_process_srv_awaiting_request( bsc_vmac_to_string(dm->payload.connect_request.vmac)); DEBUG_PRINTF( "bsc_process_srv_awaiting_request() existing = %p, " - "existing->state = %d, c = %p\n", - existing, existing->state, c); + "existing->state = %s, c = %p\n", + existing, bsc_socket_state_to_string(existing->state), c); bsc_copy_vmac(&c->vmac, dm->payload.connect_request.vmac); bsc_copy_uuid(&c->uuid, dm->payload.connect_request.uuid); c->max_npdu_len = dm->payload.connect_request.max_npdu_len; @@ -879,7 +883,9 @@ static void bsc_process_srv_awaiting_request( ERROR_CODE_ABORT_OUT_OF_RESOURCES, NULL); } bsc_srv_process_error(c, ERROR_CODE_ABORT_OUT_OF_RESOURCES); - DEBUG_PRINTF("bsc_process_srv_awaiting_request() <<<\n"); + DEBUG_PRINTF( + "bsc_process_srv_awaiting_request() connect_accept " + "encoding failed, err = ABORT_OUT_OF_RESOURCES\n"); return; } else { TX_BUF_UPDATE(c, len); @@ -901,25 +907,28 @@ static void bsc_process_srv_awaiting_request( TX_BUF_UPDATE(existing, len); DEBUG_PRINTF( "bsc_process_srv_awaiting_request() request to " - "send disconnect request to socket %d(%p)\n", - existing->wh, existing); + "send disconnect request with message id %04x " + " to existing socket %d(%p)\n", + existing->expected_disconnect_message_id, existing->wh, + existing); bws_srv_send(existing->ctx->sh, existing->wh); } else { DEBUG_PRINTF( - "bsc_process_srv_awaiting_request() sending of disconnect " - "request failed, err = BSC_SC_NO_RESOURCES\n"); + "bsc_process_srv_awaiting_request() sending of " + "disconnect request to existing socket (%p) failed. " + "err = BSC_SC_NO_RESOURCES\n", + c); } - DEBUG_PRINTF( + DEBUG_PRINTF_VERBOSE( "bsc_process_srv_awaiting_request() set socket %p to " "connected state\n", c); - mstimer_set( &c->heartbeat, 2 * c->ctx->cfg->heartbeat_timeout_s * 1000); c->state = BSC_SOCK_STATE_CONNECTED; c->ctx->funcs->socket_event( c, BSC_SOCKET_EVENT_CONNECTED, 0, NULL, NULL, 0, NULL); - DEBUG_PRINTF("bsc_process_srv_awaiting_request() <<<\n"); + DEBUG_PRINTF_VERBOSE("bsc_process_srv_awaiting_request() <<<\n"); return; } @@ -959,7 +968,7 @@ static void bsc_process_srv_awaiting_request( "message failed, err = BSC_SC_NO_RESOURCES\n"); bsc_srv_process_error(c, ERROR_CODE_NODE_DUPLICATE_VMAC); } - DEBUG_PRINTF("bsc_process_srv_awaiting_request() <<<\n"); + DEBUG_PRINTF_VERBOSE("bsc_process_srv_awaiting_request() <<<\n"); return; } @@ -1011,7 +1020,7 @@ static void bsc_process_srv_awaiting_request( "message failed, err = BSC_SC_NO_RESOURCES\n"); bsc_srv_process_error(c, ERROR_CODE_NODE_DUPLICATE_VMAC); } - DEBUG_PRINTF("bsc_process_srv_awaiting_request() <<<\n"); + DEBUG_PRINTF_VERBOSE("bsc_process_srv_awaiting_request() <<<\n"); return; } DEBUG_PRINTF( @@ -1058,7 +1067,7 @@ static void bsc_process_srv_awaiting_request( dm->hdr.bvlc_function); } #endif - DEBUG_PRINTF("bsc_process_srv_awaiting_request() <<<\n"); + DEBUG_PRINTF_VERBOSE("bsc_process_srv_awaiting_request() <<<\n"); } /** @@ -1092,7 +1101,7 @@ static void bsc_dispatch_srv_func( (void)sh; bws_dispatch_lock(); - DEBUG_PRINTF( + DEBUG_PRINTF_VERBOSE( "bsc_dispatch_srv_func() >>> sh = %p, h = %d, ev = %d, " "reason = %d, desc = %p, buf " "= %p, bufsize = %ld, ctx = %p\n", @@ -1131,7 +1140,7 @@ static void bsc_dispatch_srv_func( bws_dispatch_unlock(); return; } - DEBUG_PRINTF( + DEBUG_PRINTF_VERBOSE( "bsc_dispatch_srv_func() socket %p, state = %d\n", c, c->state); } @@ -1163,25 +1172,22 @@ static void bsc_dispatch_srv_func( mstimer_set(&c->t, c->ctx->cfg->connect_timeout_s * 1000); } } else if (ev == BSC_WEBSOCKET_RECEIVED) { - DEBUG_PRINTF("bsc_dispatch_srv_func() processing " - "BSC_WEBSOCKET_RECEIVED event\n"); DEBUG_PRINTF( - "bsc_dispatch_srv_func() socket %p, state = %d\n", c, c->state); + "bsc_dispatch_srv_func() BSC_WEBSOCKET_RECEIVED event " + "socket %p, state = %s\n", + c, bsc_socket_state_to_string(c->state)); if (c->state == BSC_SOCK_STATE_AWAITING_REQUEST) { bsc_process_srv_awaiting_request(c, &bsc_dm, buf, bufsize); } else if ( c->state == BSC_SOCK_STATE_DISCONNECTING || c->state == BSC_SOCK_STATE_CONNECTED) { bsc_runloop_socket(c, &bsc_dm, buf, bufsize); - } -#if DEBUG_BSC_SOCKET == 1 - else { + } else { DEBUG_PRINTF( "bsc_dispatch_srv_func() data was dropped for socket " - "%p, state %d, data_size %d\n", - c, c->state, bufsize); + "%p, state %s, data_size %d\n", + c, bsc_socket_state_to_string(c->state), bufsize); } -#endif } else if (ev == BSC_WEBSOCKET_SENDABLE) { p = c->tx_buf; @@ -1191,9 +1197,9 @@ static void bsc_dispatch_srv_func( c->ctx->sh, c->wh, &p[sizeof(len) + BSC_CONF_TX_PRE], len); if (wret != BSC_WEBSOCKET_SUCCESS) { DEBUG_PRINTF( - "bsc_dispatch_srv_func() send data failed, start " - "disconnect operation on socket %p\n", - c); + "bsc_dispatch_srv_func() send data failed. " + "Error=%s, start disconnect operation on socket %p\n", + bsc_websocket_return_to_string(wret), c); bsc_srv_process_error( c, c->state != BSC_SOCK_STATE_ERROR_FLUSH_TX @@ -1215,7 +1221,7 @@ static void bsc_dispatch_srv_func( } bsc_socket_maintenance_timer(0); - DEBUG_PRINTF("bsc_dispatch_srv_func() <<<\n"); + DEBUG_PRINTF_VERBOSE("bsc_dispatch_srv_func() <<<\n"); bws_dispatch_unlock(); } @@ -1233,7 +1239,7 @@ static void bsc_process_cli_awaiting_accept( uint16_t error_code; const char *err_desc = NULL; - DEBUG_PRINTF( + DEBUG_PRINTF_VERBOSE( "bsc_process_cli_awaiting_accept() >>> c = %p, dm = %p, buf = " "%p, bufsize = %d\n", c, dm, buf, bufsize); @@ -1329,7 +1335,7 @@ static void bsc_process_cli_awaiting_accept( dm->hdr.bvlc_function); } #endif - DEBUG_PRINTF("bsc_process_cli_awaiting_accept() <<<\n"); + DEBUG_PRINTF_VERBOSE("bsc_process_cli_awaiting_accept() <<<\n"); } /** @@ -1363,14 +1369,12 @@ static void bsc_dispatch_cli_func( bws_dispatch_lock(); - DEBUG_PRINTF( + DEBUG_PRINTF_VERBOSE( "bsc_dispatch_cli_func() >>> h = %d, ev = %d, reason = %d, " "reason_desc = %p, buf = %p, " "bufsize = %ld, ctx = %p\n", h, ev, ws_reason, ws_reason_desc, buf, bufsize, ctx); - c = bsc_find_conn_by_websocket(ctx, h); - if (!c) { DEBUG_PRINTF( "bsc_dispatch_cli_func() <<< warning, can not find " @@ -1379,11 +1383,13 @@ static void bsc_dispatch_cli_func( bws_dispatch_unlock(); return; } - - DEBUG_PRINTF("bsc_dispatch_cli_func() ev = %d, state = %d\n", ev, c->state); - + DEBUG_PRINTF_VERBOSE( + "bsc_dispatch_cli_func() ev = %d, state = %d\n", ev, c->state); if (ev == BSC_WEBSOCKET_DISCONNECTED) { - DEBUG_PRINTF("bsc_dispatch_cli_func() ctx->state = %d\n", ctx->state); + DEBUG_PRINTF( + "bsc_dispatch_cli_func() websocket %s ctx->state = %s\n", + bsc_websocket_event_to_string(ev), + bsc_context_state_to_string(ctx->state)); if (ctx->state == BSC_CTX_STATE_DEINITIALIZING) { bsc_set_socket_idle(c); bsc_clear_vmac_and_uuid(c); @@ -1412,6 +1418,10 @@ static void bsc_dispatch_cli_func( bsc_clear_vmac_and_uuid(c); } } else if (ev == BSC_WEBSOCKET_CONNECTED) { + DEBUG_PRINTF( + "bsc_dispatch_cli_func() websocket %s c->state = %s\n", + bsc_websocket_event_to_string(ev), + bsc_socket_state_to_string(c->state)); if (c->state == BSC_SOCK_STATE_AWAITING_WEBSOCKET) { DEBUG_PRINTF( "bsc_dispatch_cli_func() conn %p, websocket %d, state " @@ -1494,7 +1504,7 @@ static void bsc_dispatch_cli_func( } bsc_socket_maintenance_timer(0); - DEBUG_PRINTF("bsc_dispatch_cli_func() <<<\n"); + DEBUG_PRINTF_VERBOSE("bsc_dispatch_cli_func() <<<\n"); bws_dispatch_unlock(); } @@ -1579,7 +1589,7 @@ BSC_SC_RET bsc_init_ctx( } bws_dispatch_unlock(); - DEBUG_PRINTF("bsc_init_ctx() <<< ret = %d \n", sc_ret); + DEBUG_PRINTF_VERBOSE("bsc_init_ctx() <<< ret = %d \n", sc_ret); return sc_ret; } @@ -1627,7 +1637,7 @@ void bsc_deinit_ctx(BSC_SOCKET_CTX *ctx) } bws_dispatch_unlock(); - DEBUG_PRINTF("bsc_deinit_ctx() <<<\n"); + DEBUG_PRINTF_VERBOSE("bsc_deinit_ctx() <<<\n"); } /** @@ -1642,8 +1652,8 @@ BSC_SC_RET bsc_connect(BSC_SOCKET_CTX *ctx, BSC_SOCKET *c, char *url) BSC_SC_RET ret = BSC_SC_INVALID_OPERATION; BSC_WEBSOCKET_RET wret; - DEBUG_PRINTF("bsc_connect() >>> ctx = %p, c = %p, url = %s\n", ctx, c, url); - + DEBUG_PRINTF_VERBOSE( + "bsc_connect() >>> ctx = %p, c = %p, url = %s\n", ctx, c, url); if (!ctx || !c || !url) { ret = BSC_SC_BAD_PARAM; } else { @@ -1654,25 +1664,25 @@ BSC_SC_RET bsc_connect(BSC_SOCKET_CTX *ctx, BSC_SOCKET *c, char *url) c->ctx = ctx; c->state = BSC_SOCK_STATE_AWAITING_WEBSOCKET; c->tx_buf_size = 0; - wret = bws_cli_connect( ctx->cfg->proto, url, ctx->cfg->ca_cert_chain, ctx->cfg->ca_cert_chain_size, ctx->cfg->cert_chain, ctx->cfg->cert_chain_size, ctx->cfg->priv_key, ctx->cfg->priv_key_size, ctx->cfg->connect_timeout_s, bsc_dispatch_cli_func, ctx, &c->wh); - ret = bsc_map_websocket_retcode(wret); if (wret != BSC_WEBSOCKET_SUCCESS) { + DEBUG_PRINTF( + "bsc_connect() failed. %s\n", + bsc_websocket_return_to_string(wret)); bsc_set_socket_idle(c); bsc_clear_vmac_and_uuid(c); } } - bws_dispatch_unlock(); } - DEBUG_PRINTF("bsc_connect() <<< ret = %d\n", ret); + DEBUG_PRINTF_VERBOSE("bsc_connect() <<< ret = %d\n", ret); return ret; } @@ -1685,9 +1695,7 @@ void bsc_disconnect(BSC_SOCKET *c) size_t len; DEBUG_PRINTF("bsc_disconnect() >>> c = %p\n", c); - bws_dispatch_lock(); - if (c->ctx->state == BSC_CTX_STATE_INITIALIZED) { if (c->state == BSC_SOCK_STATE_CONNECTED) { c->expected_disconnect_message_id = bsc_get_next_message_id(); @@ -1723,10 +1731,8 @@ void bsc_disconnect(BSC_SOCKET *c) } } } - bws_dispatch_unlock(); - - DEBUG_PRINTF("bsc_disconnect() <<<\n"); + DEBUG_PRINTF_VERBOSE("bsc_disconnect() <<<\n"); } /** @@ -1768,7 +1774,7 @@ BSC_SC_RET bsc_send(BSC_SOCKET *c, uint8_t *pdu, size_t pdu_len) bws_dispatch_unlock(); } - DEBUG_PRINTF("bsc_send() <<< ret = %d\n", ret); + DEBUG_PRINTF_VERBOSE("bsc_send() <<< ret = %d\n", ret); return ret; } @@ -1790,7 +1796,7 @@ uint16_t bsc_get_next_message_id(void) message_id++; } ret = message_id; - DEBUG_PRINTF("next message id = %u(%04x)\n", ret, ret); + DEBUG_PRINTF_VERBOSE("next message id = %u(%04x)\n", ret, ret); bws_dispatch_unlock(); return ret; } diff --git a/src/bacnet/datalink/bsc/bsc-util.c b/src/bacnet/datalink/bsc/bsc-util.c index c467e22d..0236c9a5 100644 --- a/src/bacnet/datalink/bsc/bsc-util.c +++ b/src/bacnet/datalink/bsc/bsc-util.c @@ -5,12 +5,12 @@ * @date Jule 2022 * SPDX-License-Identifier: GPL-2.0-or-later WITH GCC-exception-2.0 */ -#include "bacnet/datalink/bsc/bsc-util.h" +#include #include "bacnet/basic/object/bacfile.h" #include "bacnet/basic/object/netport.h" #include "bacnet/basic/object/sc_netport.h" #include "bacnet/basic/sys/debug.h" -#include +#include "bacnet/datalink/bsc/bsc-util.h" #define PRINTF debug_printf_stdout #define PRINTF_ERR debug_printf_stderr @@ -88,43 +88,6 @@ char *bsc_uuid_to_string(BACNET_SC_UUID *uuid) return buf; } -/** - * @brief Generate random BACnet Secure Connect VMAC address - * @param p - pointer to the VMAC address - */ -void bsc_generate_random_vmac(BACNET_SC_VMAC_ADDRESS *p) -{ - int i; - - for (i = 0; i < BVLC_SC_VMAC_SIZE; i++) { - p->address[i] = rand() % 256; - if (i == 0) { - /* According H.7.3 EUI-48 and Random-48 VMAC Address: - The Random-48 VMAC is a 6-octet VMAC address in which the least - significant 4 bits (Bit 3 to Bit 0) in the first octet shall be - B'0010' (X'2'), and all other 44 bits are randomly selected to be - 0 or 1. */ - p->address[i] = (p->address[i] & 0xF0) | 0x02; - } - } - debug_printf_hex( - 0, p->address, BVLC_SC_VMAC_SIZE, "bsc_generate_random_vmac"); -} - -/** - * @brief Generate random BACnet Secure Connect UUID - * @param p - pointer to the UUID - */ -void bsc_generate_random_uuid(BACNET_SC_UUID *p) -{ - int i; - - for (i = 0; i < BVLC_SC_UUID_SIZE; i++) { - p->uuid[i] = rand() % 256; - } - debug_printf_hex(0, p->uuid, BVLC_SC_UUID_SIZE, "bsc_generate_random_uuid"); -} - /* * bsc_node_load_cert_bacfile loads one credentional file from bacfile object * Note: the function adds null-terminated byte to loaded file @@ -314,30 +277,223 @@ void bsc_set_timestamp(BACNET_DATE_TIME *timestamp) * @brief Check if BACnet/SC certificate files exist * @return true if all files exist, else false */ -bool bsc_cert_files_check(void) +bool bsc_cert_files_check(uint32_t netport_instance) { - uint32_t instance; uint32_t file_instance; - instance = Network_Port_Index_To_Instance(0); - - file_instance = Network_Port_Issuer_Certificate_File(instance, 0); + file_instance = Network_Port_Issuer_Certificate_File(netport_instance, 0); if (bacfile_file_size(file_instance) == 0) { - PRINTF_ERR("CA certificate file not exist\n"); + PRINTF_ERR( + "Issuer Certificate file %u size=0. Path=%s\n", file_instance, + bacfile_pathname(file_instance)); return false; } - file_instance = Network_Port_Operational_Certificate_File(instance); + file_instance = Network_Port_Operational_Certificate_File(netport_instance); if (bacfile_file_size(file_instance) == 0) { - PRINTF_ERR("Certificate file not exist\n"); + PRINTF_ERR( + "Operational Certificate file %u size=0. Path=%s\n", file_instance, + bacfile_pathname(file_instance)); + PRINTF_ERR("Operational Certificate file not exist\n"); return false; } - file_instance = Network_Port_Certificate_Key_File(instance); + file_instance = Network_Port_Certificate_Key_File(netport_instance); if (bacfile_file_size(file_instance) == 0) { - PRINTF_ERR("Certificate key file not exist\n"); + PRINTF_ERR( + "Certificate Key file %u size=0. Path=%s\n", file_instance, + bacfile_pathname(file_instance)); return false; } return true; } + +/** + * @brief Return a return code string for human readable log messages + * @param ret BACnet/SC return codes + * @return return code string for human readable log messages + */ +const char *bsc_return_code_to_string(BSC_SC_RET ret) +{ + switch (ret) { + case BSC_SC_SUCCESS: + return "SUCCESS"; + case BSC_SC_NO_RESOURCES: + return "NO_RESOURCES"; + case BSC_SC_BAD_PARAM: + return "BAD_PARAM"; + case BSC_SC_INVALID_OPERATION: + return "INVALID_OPERATION"; + default: + break; + } + + return "UNKNOWN"; +} + +/** + * @brief Return a string for human readable log messages + * @param ev BACnet/SC return codes + * @return return code string for human readable log messages + */ +const char *bsc_socket_event_to_string(BSC_SOCKET_EVENT ev) +{ + switch (ev) { + case BSC_SOCKET_EVENT_CONNECTED: + return "CONNECTED"; + case BSC_SOCKET_EVENT_DISCONNECTED: + return "DISCONNECTED"; + case BSC_SOCKET_EVENT_RECEIVED: + return "RECEIVED"; + default: + break; + } + + return "UNKNOWN"; +} + +/** + * @brief Return a string for human readable log messages + * @param ev BACnet/SC return codes + * @return return code string for human readable log messages + */ +const char *bsc_socket_state_to_string(BSC_SOCKET_STATE state) +{ + switch (state) { + case BSC_SOCK_STATE_IDLE: + return "IDLE"; + case BSC_SOCK_STATE_AWAITING_WEBSOCKET: + return "AWAITING_WEBSOCKET"; + case BSC_SOCK_STATE_AWAITING_REQUEST: + return "AWAITING_REQUEST"; + case BSC_SOCK_STATE_AWAITING_ACCEPT: + return "AWAITING_ACCEPT"; + case BSC_SOCK_STATE_CONNECTED: + return "CONNECTED"; + case BSC_SOCK_STATE_DISCONNECTING: + return "DISCONNECTING"; + case BSC_SOCK_STATE_ERROR: + return "ERROR"; + case BSC_SOCK_STATE_ERROR_FLUSH_TX: + return "ERROR_FLUSH_TX"; + default: + break; + } + + return "UNKNOWN"; +} + +/** + * @brief Return a string for human readable log messages + * @param ev BACnet/SC return codes + * @return return code string for human readable log messages + */ +const char *bsc_websocket_return_to_string(BSC_WEBSOCKET_RET ret) +{ + switch (ret) { + case BSC_WEBSOCKET_SUCCESS: + return "SUCCESS"; + case BSC_WEBSOCKET_NO_RESOURCES: + return "NO_RESOURCES"; + case BSC_WEBSOCKET_BAD_PARAM: + return "BAD_PARAM"; + case BSC_WEBSOCKET_INVALID_OPERATION: + return "INVALID_OPERATION"; + default: + break; + } + + return "UNKNOWN"; +} + +/** + * @brief Return a string for human readable log messages + * @param ev BACnet/SC return codes + * @return return code string for human readable log messages + */ +const char *bsc_websocket_event_to_string(BSC_WEBSOCKET_EVENT event) +{ + switch (event) { + case BSC_WEBSOCKET_CONNECTED: + return "CONNECTED"; + case BSC_WEBSOCKET_DISCONNECTED: + return "DISCONNECTED"; + case BSC_WEBSOCKET_RECEIVED: + return "RECEIVED"; + case BSC_WEBSOCKET_SENDABLE: + return "SENDABLE"; + case BSC_WEBSOCKET_SERVER_STARTED: + return "SERVER_STARTED"; + case BSC_WEBSOCKET_SERVER_STOPPED: + return "SERVER_STOPPED"; + default: + break; + } + + return "UNKNOWN"; +} + +/** + * @brief Return a string for human readable log messages + * @param ev BACnet/SC return codes + * @return return code string for human readable log messages + */ +const char *bsc_bvlc_message_type_to_string(BVLC_SC_MESSAGE_TYPE message) +{ + switch (message) { + case BVLC_SC_RESULT: + return "RESULT"; + case BVLC_SC_ENCAPSULATED_NPDU: + return "ENCAPSULATED_NPDU"; + case BVLC_SC_ADDRESS_RESOLUTION: + return "ADDRESS_RESOLUTION"; + case BVLC_SC_ADDRESS_RESOLUTION_ACK: + return "ADDRESS_RESOLUTION_ACK"; + case BVLC_SC_ADVERTISIMENT: + return "ADVERTISIMENT"; + case BVLC_SC_ADVERTISIMENT_SOLICITATION: + return "ADVERTISIMENT_SOLICITATION"; + case BVLC_SC_CONNECT_REQUEST: + return "CONNECT_REQUEST"; + case BVLC_SC_CONNECT_ACCEPT: + return "CONNECT_ACCEPT"; + case BVLC_SC_DISCONNECT_REQUEST: + return "DISCONNECT_REQUEST"; + case BVLC_SC_DISCONNECT_ACK: + return "DISCONNECT_ACK"; + case BVLC_SC_HEARTBEAT_REQUEST: + return "HEARTBEAT_REQUEST"; + case BVLC_SC_HEARTBEAT_ACK: + return "HEARTBEAT_ACK"; + case BVLC_SC_PROPRIETARY_MESSAGE: + return "PROPRIETARY_MESSAGE"; + default: + break; + } + + return "UNKNOWN"; +} + +/** + * @brief Return a string for human readable log messages + * @param ev BACnet/SC return codes + * @return return code string for human readable log messages + */ +const char *bsc_context_state_to_string(BSC_CTX_STATE state) +{ + switch (state) { + case BSC_CTX_STATE_IDLE: + return "IDLE"; + case BSC_CTX_STATE_INITIALIZING: + return "INITIALIZING"; + case BSC_CTX_STATE_INITIALIZED: + return "INITIALIZED"; + case BSC_CTX_STATE_DEINITIALIZING: + return "DEINITIALIZING"; + default: + break; + } + + return "UNKNOWN"; +} diff --git a/src/bacnet/datalink/bsc/bsc-util.h b/src/bacnet/datalink/bsc/bsc-util.h index 29482a6b..37228981 100644 --- a/src/bacnet/datalink/bsc/bsc-util.h +++ b/src/bacnet/datalink/bsc/bsc-util.h @@ -15,6 +15,7 @@ #include "bacnet/basic/sys/debug.h" #include "bacnet/datalink/bsc/bsc-node.h" #include "bacnet/datalink/bsc/bsc-retcodes.h" +#include "bacnet/datalink/bsc/bsc-socket.h" #include "bacnet/datalink/bsc/bvlc-sc.h" #include "bacnet/datalink/bsc/websocket.h" #include "bacnet/datetime.h" @@ -25,12 +26,17 @@ void bsc_copy_vmac(BACNET_SC_VMAC_ADDRESS *dst, BACNET_SC_VMAC_ADDRESS *src); void bsc_copy_uuid(BACNET_SC_UUID *dst, BACNET_SC_UUID *src); char *bsc_vmac_to_string(BACNET_SC_VMAC_ADDRESS *vmac); char *bsc_uuid_to_string(BACNET_SC_UUID *uuid); -void bsc_generate_random_vmac(BACNET_SC_VMAC_ADDRESS *p); -void bsc_generate_random_uuid(BACNET_SC_UUID *p); bool bsc_node_conf_fill_from_netport( BSC_NODE_CONF *bsc_conf, BSC_NODE_EVENT_FUNC event_func); void bsc_node_conf_cleanup(BSC_NODE_CONF *bsc_conf); void bsc_copy_str(char *dst, const char *src, size_t dst_len); void bsc_set_timestamp(BACNET_DATE_TIME *timestamp); +const char *bsc_return_code_to_string(BSC_SC_RET ret); +const char *bsc_socket_event_to_string(BSC_SOCKET_EVENT ev); +const char *bsc_socket_state_to_string(BSC_SOCKET_STATE state); +const char *bsc_websocket_return_to_string(BSC_WEBSOCKET_RET ret); +const char *bsc_websocket_event_to_string(BSC_WEBSOCKET_EVENT event); +const char *bsc_bvlc_message_type_to_string(BVLC_SC_MESSAGE_TYPE message); +const char *bsc_context_state_to_string(BSC_CTX_STATE state); #endif diff --git a/src/bacnet/datalink/dlenv.c b/src/bacnet/datalink/dlenv.c index 47ef8cc6..f9eca4ae 100644 --- a/src/bacnet/datalink/dlenv.c +++ b/src/bacnet/datalink/dlenv.c @@ -16,6 +16,7 @@ /* BACnet Stack API */ #include "bacnet/apdu.h" #include "bacnet/basic/services.h" +#include "bacnet/basic/sys/debug.h" #include "bacnet/basic/tsm/tsm.h" #include "bacnet/basic/bbmd/h_bbmd.h" #include "bacnet/basic/object/netport.h" @@ -611,10 +612,29 @@ void dlenv_network_port_zigbee_init(uint32_t instance) Network_Port_Changes_Pending_Set(instance, false); } +#if defined(BACDL_BSC) +static bool dlenv_hub_connection_status_check(uint32_t instance) +{ + 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; +} +#endif + /** - * @brief Datalink network port object settings + * Datalink network port object settings for BACnet/SC */ -static void bacnet_secure_connect_network_port_init(uint32_t instance) +void dlenv_network_port_bsc_init(uint32_t instance) { #ifdef BACDL_BSC BACNET_SC_UUID uuid = { 0 }; @@ -629,6 +649,8 @@ static void bacnet_secure_connect_network_port_init(uint32_t instance) char *hub_binding; char *direct_connect_initiate; char *direct_connect_accept_urls; + uint32_t file_instance; + char c; primary_hub_uri = getenv("BACNET_SC_PRIMARY_HUB_URI"); failover_hub_uri = getenv("BACNET_SC_FAILOVER_HUB_URI"); @@ -658,9 +680,6 @@ static void bacnet_secure_connect_network_port_init(uint32_t instance) /* SC parameters */ #ifdef BACDL_BSC - if (!bsc_cert_files_check()) { - exit(1); - } bsc_generate_random_uuid(&uuid); Network_Port_SC_Local_UUID_Set(instance, (BACNET_UUID *)&uuid); bsc_generate_random_vmac(&vmac); @@ -675,21 +694,42 @@ static void bacnet_secure_connect_network_port_init(uint32_t instance) 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); + file_instance = bacfile_create(BSC_ISSUER_CERTIFICATE_FILE_1_INSTANCE); + if (file_instance != BSC_ISSUER_CERTIFICATE_FILE_1_INSTANCE) { + fprintf( + stderr, + "BSC_ISSUER_CERTIFICATE_FILE_1_INSTANCE was not created!\n"); + return; + } bacfile_pathname_set( BSC_ISSUER_CERTIFICATE_FILE_1_INSTANCE, filename_ca_1_cert); + if (Datalink_Debug) { + fprintf( + stderr, "Issuer Certificate 1 file %u path=%s\n", file_instance, + bacfile_pathname(file_instance)); + } 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); + file_instance = bacfile_create(BSC_ISSUER_CERTIFICATE_FILE_2_INSTANCE); + if (file_instance != BSC_ISSUER_CERTIFICATE_FILE_2_INSTANCE) { + fprintf( + stderr, + "BSC_ISSUER_CERTIFICATE_FILE_2_INSTANCE was not created!\n"); + return; + } bacfile_pathname_set( BSC_ISSUER_CERTIFICATE_FILE_2_INSTANCE, filename_ca_2_cert); + if (Datalink_Debug) { + fprintf( + stderr, "Issuer Certificate 2 file %u path=%s\n", file_instance, + bacfile_pathname(file_instance)); + } Network_Port_Issuer_Certificate_File_Set( instance, 1, BSC_ISSUER_CERTIFICATE_FILE_2_INSTANCE); } @@ -698,9 +738,20 @@ static void bacnet_secure_connect_network_port_init(uint32_t instance) fprintf(stderr, "BACNET_SC_OPERATIONAL_CERTIFICATE_FILE must be set\n"); return; } - bacfile_create(BSC_OPERATIONAL_CERTIFICATE_FILE_INSTANCE); + file_instance = bacfile_create(BSC_OPERATIONAL_CERTIFICATE_FILE_INSTANCE); + if (file_instance != BSC_OPERATIONAL_CERTIFICATE_FILE_INSTANCE) { + fprintf( + stderr, + "BSC_OPERATIONAL_CERTIFICATE_FILE_INSTANCE was not created!\n"); + return; + } bacfile_pathname_set( BSC_OPERATIONAL_CERTIFICATE_FILE_INSTANCE, filename_cert); + if (Datalink_Debug) { + fprintf( + stderr, "Operational Certificate file %u path=%s\n", file_instance, + bacfile_pathname(file_instance)); + } Network_Port_Operational_Certificate_File_Set( instance, BSC_OPERATIONAL_CERTIFICATE_FILE_INSTANCE); @@ -710,9 +761,21 @@ static void bacnet_secure_connect_network_port_init(uint32_t instance) "BACNET_SC_OPERATIONAL_CERTIFICATE_PRIVATE_KEY_FILE must be set\n"); return; } - bacfile_create(BSC_CERTIFICATE_SIGNING_REQUEST_FILE_INSTANCE); + file_instance = + bacfile_create(BSC_CERTIFICATE_SIGNING_REQUEST_FILE_INSTANCE); + if (file_instance != BSC_CERTIFICATE_SIGNING_REQUEST_FILE_INSTANCE) { + fprintf( + stderr, + "BSC_CERTIFICATE_SIGNING_REQUEST_FILE_INSTANCE was not created!\n"); + return; + } bacfile_pathname_set( BSC_CERTIFICATE_SIGNING_REQUEST_FILE_INSTANCE, filename_key); + if (Datalink_Debug) { + fprintf( + stderr, "Certificate Key file %u path=%s\n", file_instance, + bacfile_pathname(file_instance)); + } Network_Port_Certificate_Key_File_Set( instance, BSC_CERTIFICATE_SIGNING_REQUEST_FILE_INSTANCE); @@ -727,7 +790,6 @@ static void bacnet_secure_connect_network_port_init(uint32_t instance) "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); @@ -735,7 +797,6 @@ static void bacnet_secure_connect_network_port_init(uint32_t instance) Network_Port_SC_Direct_Connect_Accept_Enable_Set( instance, direct_binding != NULL); - char c; 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); @@ -753,43 +814,31 @@ static void bacnet_secure_connect_network_port_init(uint32_t instance) /* last thing - clear pending changes - we don't want to set these since they are already set */ Network_Port_Changes_Pending_Set(instance, false); -} #if defined(BACDL_BSC) -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; + if (!bsc_cert_files_check(instance)) { + debug_printf_stderr("BSC Certificate files missing.\n"); + exit(1); } - - status = Network_Port_SC_Failover_Hub_Connection_Status(instance); - if (status && status->State == BACNET_SC_CONNECTION_STATE_CONNECTED) { - return true; - } - - return false; -} #endif +} -/** - * Datalink network port object settings for BACnet/SC - */ -void dlenv_network_port_bsc_init(void) +void bsc_register_as_node(uint32_t instance) { #if defined(BACDL_BSC) /* if a user has configured BACnet/SC port with primary hub URI, */ /* wait for a establishing 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()) { + if (Network_Port_SC_Primary_Hub_URI_char(instance)) { + debug_printf_stderr("Waiting for a BACnet/SC connection to hub...\n"); + while (!dlenv_hub_connection_status_check(instance)) { bsc_wait(1); bsc_maintenance_timer(1); } + debug_printf_stderr("Connected to a BACnet/SC hub!\n"); } +#else + (void)instance; #endif } @@ -929,6 +978,9 @@ void dlenv_init(void) char *pEnv = NULL; uint8_t port_type = PORT_TYPE_BIP; + if (getenv("BACNET_DATALINK_DEBUG")) { + dlenv_debug_enable(); + } #if defined(BACDL_MULTIPLE) pEnv = getenv("BACNET_DATALINK"); if (pEnv) { @@ -999,6 +1051,9 @@ void dlenv_init(void) #if defined(BACFILE) /* initialize the POSIX file objects */ bacfile_posix_init(); + if (Datalink_Debug) { + debug_printf_stderr("POSIX file services initialized.\n"); + } #endif /* === Initialize the Network Port Object Here === */ Network_Port_Type_Set(Network_Port_Instance, port_type); @@ -1016,8 +1071,7 @@ void dlenv_init(void) dlenv_network_port_zigbee_init(Network_Port_Instance); break; case PORT_TYPE_BSC: - dlenv_network_port_bsc_init(); - bacnet_secure_connect_network_port_init(Network_Port_Instance); + dlenv_network_port_bsc_init(Network_Port_Instance); break; default: break; @@ -1034,7 +1088,7 @@ void dlenv_init(void) if (pEnv) { apdu_retries_set((uint8_t)strtol(pEnv, NULL, 0)); } - /* === Initialize the Datalink Here === */ + /* === INIT - Initialize the Datalink Here === */ pEnv = getenv("BACNET_IFACE"); if (Datalink_Debug) { fprintf(stderr, "BACNET_IFACE=%s\n", pEnv ? pEnv : "none"); @@ -1042,6 +1096,7 @@ void dlenv_init(void) if (!datalink_init(pEnv)) { exit(1); } + /* === POST INIT - After the Datalink is Initialized === */ #if (MAX_TSM_TRANSACTIONS) pEnv = getenv("BACNET_INVOKE_ID"); if (pEnv) { @@ -1052,5 +1107,7 @@ void dlenv_init(void) bbmd_register_as_foreign_device(); } else if (port_type == PORT_TYPE_BIP6) { bbmd6_register_as_foreign_device(); + } else if (port_type == PORT_TYPE_BSC) { + bsc_register_as_node(Network_Port_Instance); } } diff --git a/test/bacnet/basic/object/netport/CMakeLists.txt b/test/bacnet/basic/object/netport/CMakeLists.txt index 6d19dc4d..984387ec 100644 --- a/test/bacnet/basic/object/netport/CMakeLists.txt +++ b/test/bacnet/basic/object/netport/CMakeLists.txt @@ -35,6 +35,7 @@ add_compile_definitions( BACNET_SC_DIRECT_ACCEPT_URI_MAX=6 MAX_TSM_TRANSACTIONS=0 BSC_CONF_TX_PRE=0 + BACFILE=1 ) include_directories( diff --git a/test/bacnet/datalink/bsc-datalink/src/main.c b/test/bacnet/datalink/bsc-datalink/src/main.c index 13b2a711..df2cfb02 100644 --- a/test/bacnet/datalink/bsc-datalink/src/main.c +++ b/test/bacnet/datalink/bsc-datalink/src/main.c @@ -10169,7 +10169,7 @@ static void test_sc_datalink(void) init_node_ev(&node_ev2); init_node_ev(&node_ev3); - zassert_equal(bsc_cert_files_check(), true, NULL); + zassert_equal(bsc_cert_files_check(SC_DATALINK_INSTANCE), true, NULL); zassert_equal(bsc_init(NULL), true, NULL); zassert_equal(bsc_init(NULL), false, NULL); memset(broadcast, 0xFF, sizeof(broadcast)); @@ -10432,7 +10432,7 @@ static void test_sc_datalink_properties(void) init_node_ev(&node_ev2); init_node_ev(&node_ev3); init_node_ev(&node_ev4); - zassert_equal(bsc_cert_files_check(), true, NULL); + zassert_equal(bsc_cert_files_check(SC_DATALINK_INSTANCE), true, NULL); zassert_equal(bsc_init(NULL), true, NULL); conf2.ca_cert_chain = ca_cert;