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
This commit is contained in:
Steve Karg
2025-11-14 15:41:17 -06:00
committed by GitHub
parent 74972bd025
commit 25d14c7c15
30 changed files with 672 additions and 339 deletions
+6
View File
@@ -148,6 +148,12 @@ The git repositories are hosted at the following sites:
### Fixed ### 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 WPM workaround for BTL Specified Test 9.23.2.X5 by reverting.(#1140)
* Fixed the API integration for the additional datatypes now supported * Fixed the API integration for the additional datatypes now supported
in the Channel object by adding CHANNEL_VALUE_ALL to enable and test. (#1135) in the Channel object by adding CHANNEL_VALUE_ALL to enable and test. (#1135)
+6 -2
View File
@@ -62,7 +62,7 @@ ethernet:
# see .github/workflows/gcc.yml # see .github/workflows/gcc.yml
.PHONY: bsc .PHONY: bsc
bsc: bsc:
$(MAKE) BACDL=bsc -s -C apps all $(MAKE) LEGACY=true BACDL=bsc -s -C apps all
.PHONY: apps .PHONY: apps
apps: apps:
@@ -226,7 +226,11 @@ server-mini:
.PHONY: sc-hub .PHONY: sc-hub
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 .PHONY: mstpcap
mstpcap: mstpcap:
+12 -2
View File
@@ -43,8 +43,7 @@ ifeq (${BACDL},bip6)
BACDL_DEFINE=-DBACDL_BIP6=1 BACDL_DEFINE=-DBACDL_BIP6=1
endif endif
ifeq (${BACDL},bsc) ifeq (${BACDL},bsc)
BACDL_DEFINE=-DBACDL_BSC=1 BACDL_DEFINE=-DBACDL_BSC=1 -DBACFILE=1
BACNET_DEFINE=-DBACFILE=1
endif endif
ifeq (${BACDL},zigbee) ifeq (${BACDL},zigbee)
BACDL_DEFINE=-DBACDL_ZIGBEE=1 BACDL_DEFINE=-DBACDL_ZIGBEE=1
@@ -206,6 +205,17 @@ DEBUGGING = -g -DDEBUG_ENABLED=1
ifeq (${BACDL},bip) ifeq (${BACDL},bip)
BACNET_DEFINES += -DBIP_DEBUG BACNET_DEFINES += -DBIP_DEBUG
endif 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 endif
ifeq (${LEGACY},true) ifeq (${LEGACY},true)
+5 -5
View File
@@ -2,23 +2,23 @@
Test BACnet/SC using the following steps: 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 cd bin
./bsc-server.sh ./bsc-server.sh
./bacschub 1 Hubster ./bacschub 1 Hubster
* Run server app: * Run BACnet/SC server application:
cd bin cd bin
./bsc-client.sh ./bsc-client.sh
./bacserv 123 Francine ./bacserv 123 Francine
* Run any client: * Run any BACnet/SC client:
cd bin cd bin
./bsc-client.sh ./bsc-client.sh
+24 -4
View File
@@ -1,6 +1,6 @@
/** /**
* @file * @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 <kirill.neznamov@dsr-corporation.com> * @author Kirill Neznamov <kirill.neznamov@dsr-corporation.com>
* @date August 2022 * @date August 2022
* @copyright SPDX-License-Identifier: GPL-2.0-or-later WITH GCC-exception-2.0 * @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/basic/sys/debug.h"
#include "bacnet/datalink/bsc/bsc-event.h" #include "bacnet/datalink/bsc/bsc-event.h"
#define DEBUG_BSC_EVENT 0
#undef DEBUG_PRINTF #undef DEBUG_PRINTF
#if DEBUG_BSC_EVENT == 1 #if DEBUG_BSC_EVENT
#define DEBUG_PRINTF printf #define DEBUG_PRINTF printf
#else #else
#undef DEBUG_ENABLED #undef DEBUG_ENABLED
@@ -179,3 +177,25 @@ void bsc_wait_ms(int mseconds)
{ {
usleep(mseconds * 1000); 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:");
}
+1 -3
View File
@@ -14,10 +14,8 @@
#include "bacnet/basic/sys/debug.h" #include "bacnet/basic/sys/debug.h"
#include "websocket-global.h" #include "websocket-global.h"
#define DEBUG_WEBSOCKET_CLIENT 0
#undef DEBUG_PRINTF #undef DEBUG_PRINTF
#if DEBUG_WEBSOCKET_CLIENT == 1 #if DEBUG_WEBSOCKET_CLIENT
#define DEBUG_PRINTF debug_printf #define DEBUG_PRINTF debug_printf
#else #else
#undef DEBUG_ENABLED #undef DEBUG_ENABLED
+1 -3
View File
@@ -15,10 +15,8 @@
#include "websocket-global.h" #include "websocket-global.h"
#include <arpa/inet.h> #include <arpa/inet.h>
#define DEBUG_WEBSOCKET_SERVER 0
#undef DEBUG_PRINTF #undef DEBUG_PRINTF
#if DEBUG_WEBSOCKET_SERVER == 1 #if DEBUG_WEBSOCKET_SERVER
#define DEBUG_PRINTF debug_printf #define DEBUG_PRINTF debug_printf
#else #else
#undef DEBUG_ENABLED #undef DEBUG_ENABLED
+25 -4
View File
@@ -1,6 +1,6 @@
/** /**
* @file * @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 <kirill.neznamov@dsr-corporation.com> * @author Kirill Neznamov <kirill.neznamov@dsr-corporation.com>
* @date August 2022 * @date August 2022
* @copyright SPDX-License-Identifier: GPL-2.0-or-later WITH GCC-exception-2.0 * @copyright SPDX-License-Identifier: GPL-2.0-or-later WITH GCC-exception-2.0
@@ -11,13 +11,12 @@
#include <pthread.h> #include <pthread.h>
#include <stdbool.h> #include <stdbool.h>
#include <unistd.h> #include <unistd.h>
#include <sys/random.h>
#include "bacnet/basic/sys/debug.h" #include "bacnet/basic/sys/debug.h"
#include "bacnet/datalink/bsc/bsc-event.h" #include "bacnet/datalink/bsc/bsc-event.h"
#define DEBUG_BSC_EVENT 0
#undef DEBUG_PRINTF #undef DEBUG_PRINTF
#if DEBUG_BSC_EVENT == 1 #if DEBUG_BSC_EVENT
#define DEBUG_PRINTF printf #define DEBUG_PRINTF printf
#else #else
#undef DEBUG_ENABLED #undef DEBUG_ENABLED
@@ -179,3 +178,25 @@ void bsc_wait_ms(int mseconds)
{ {
usleep(mseconds * 1000); 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:");
}
+1 -3
View File
@@ -15,10 +15,8 @@
#include "bacnet/basic/sys/debug.h" #include "bacnet/basic/sys/debug.h"
#include "websocket-global.h" #include "websocket-global.h"
#define DEBUG_WEBSOCKET_CLIENT 0
#undef DEBUG_PRINTF #undef DEBUG_PRINTF
#if DEBUG_WEBSOCKET_CLIENT == 1 #if DEBUG_WEBSOCKET_CLIENT
#define DEBUG_PRINTF debug_printf #define DEBUG_PRINTF debug_printf
#else #else
#undef DEBUG_ENABLED #undef DEBUG_ENABLED
+1 -3
View File
@@ -16,10 +16,8 @@
#include "websocket-global.h" #include "websocket-global.h"
#include <arpa/inet.h> #include <arpa/inet.h>
#define DEBUG_WEBSOCKET_SERVER 0
#undef DEBUG_PRINTF #undef DEBUG_PRINTF
#if DEBUG_WEBSOCKET_SERVER == 1 #if DEBUG_WEBSOCKET_SERVER
#define DEBUG_PRINTF debug_printf #define DEBUG_PRINTF debug_printf
#else #else
#undef DEBUG_ENABLED #undef DEBUG_ENABLED
+13
View File
@@ -13,6 +13,7 @@
#include <string.h> #include <string.h>
/* BACnet Stack defines - first */ /* BACnet Stack defines - first */
#include "bacnet/bacdef.h" #include "bacnet/bacdef.h"
#include "bacnet/basic/sys/debug.h"
#include "bacnet/basic/object/bacfile.h" #include "bacnet/basic/object/bacfile.h"
#ifndef FILE_RECORD_SIZE #ifndef FILE_RECORD_SIZE
@@ -57,6 +58,8 @@ size_t bacfile_posix_file_size(const char *pathname)
file_size = (size_t)file_position; file_size = (size_t)file_position;
} }
fclose(pFile); 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); (void)fseek(pFile, fileStartPosition, SEEK_SET);
len = fread(fileData, 1, fileDataLen, pFile); len = fread(fileData, 1, fileDataLen, pFile);
fclose(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); bytes_written = fwrite(fileData, fileDataLen, 1, pFile);
fclose(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; status = true;
} }
fclose(pFile); 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; status = true;
} }
fclose(pFile); 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_read_record_data_callback_set(bacfile_posix_read_record_data);
bacfile_file_size_callback_set(bacfile_posix_file_size); bacfile_file_size_callback_set(bacfile_posix_file_size);
bacfile_file_size_set_callback_set(bacfile_posix_file_size_set); bacfile_file_size_set_callback_set(bacfile_posix_file_size_set);
#elif defined(BACDL_BSC)
#error BACFILE is not defined for BACnet/SC!
#endif #endif
} }
+23 -4
View File
@@ -1,11 +1,12 @@
/** /**
* @file * @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 <kirill.neznamov@dsr-corporation.com> * @author Kirill Neznamov <kirill.neznamov@dsr-corporation.com>
* @date August 2022 * @date August 2022
* @copyright SPDX-License-Identifier: GPL-2.0-or-later WITH GCC-exception-2.0 * @copyright SPDX-License-Identifier: GPL-2.0-or-later WITH GCC-exception-2.0
*/ */
#include <windows.h> #include <windows.h>
#include <ntsecapi.h>
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@@ -13,10 +14,8 @@
#include "bacnet/basic/sys/debug.h" #include "bacnet/basic/sys/debug.h"
#include "bacnet/datalink/bsc/bsc-event.h" #include "bacnet/datalink/bsc/bsc-event.h"
#define DEBUG_BSC_EVENT 0
#undef DEBUG_PRINTF #undef DEBUG_PRINTF
#if DEBUG_BSC_EVENT == 1 #if DEBUG_BSC_EVENT
#define DEBUG_PRINTF printf #define DEBUG_PRINTF printf
#else #else
#undef DEBUG_ENABLED #undef DEBUG_ENABLED
@@ -144,3 +143,23 @@ void bsc_wait_ms(int mseconds)
{ {
Sleep(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:");
}
+1 -3
View File
@@ -13,10 +13,8 @@
#include "bacnet/basic/sys/debug.h" #include "bacnet/basic/sys/debug.h"
#include "websocket-global.h" #include "websocket-global.h"
#define DEBUG_WEBSOCKET_CLIENT 0
#undef DEBUG_PRINTF #undef DEBUG_PRINTF
#if DEBUG_WEBSOCKET_CLIENT == 1 #if DEBUG_WEBSOCKET_CLIENT
#define DEBUG_PRINTF debug_printf #define DEBUG_PRINTF debug_printf
#else #else
#undef DEBUG_ENABLED #undef DEBUG_ENABLED
+1 -3
View File
@@ -13,10 +13,8 @@
#include "bacnet/basic/sys/debug.h" #include "bacnet/basic/sys/debug.h"
#include "websocket-global.h" #include "websocket-global.h"
#define DEBUG_WEBSOCKET_SERVER 0
#undef DEBUG_PRINTF #undef DEBUG_PRINTF
#if DEBUG_WEBSOCKET_SERVER == 1 #if DEBUG_WEBSOCKET_SERVER
#define DEBUG_PRINTF debug_printf #define DEBUG_PRINTF debug_printf
#else #else
#undef DEBUG_ENABLED #undef DEBUG_ENABLED
+2 -5
View File
@@ -558,15 +558,12 @@ uint32_t bacfile_write(
BACNET_UNSIGNED_INTEGER bacfile_file_size(uint32_t object_instance) BACNET_UNSIGNED_INTEGER bacfile_file_size(uint32_t object_instance)
{ {
const char *pathname = NULL; const char *pathname = NULL;
long file_position = 0;
BACNET_UNSIGNED_INTEGER file_size = 0; BACNET_UNSIGNED_INTEGER file_size = 0;
pathname = bacfile_pathname(object_instance); pathname = bacfile_pathname(object_instance);
if (pathname) { if (pathname) {
file_position = bacfile_file_size_callback(pathname); file_size =
if (file_position >= 0) { (BACNET_UNSIGNED_INTEGER)bacfile_file_size_callback(pathname);
file_size = (BACNET_UNSIGNED_INTEGER)file_position;
}
} }
return file_size; return file_size;
+19
View File
@@ -19,6 +19,25 @@
#include "bacnet/datalink/bsc/bsc-conf.h" #include "bacnet/datalink/bsc/bsc-conf.h"
#include "bacnet/datalink/bsc/bvlc-sc.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 */ /* BACnet file instance numbers */
#ifndef BSC_ISSUER_CERTIFICATE_FILE_1_INSTANCE #ifndef BSC_ISSUER_CERTIFICATE_FILE_1_INSTANCE
#define BSC_ISSUER_CERTIFICATE_FILE_1_INSTANCE \ #define BSC_ISSUER_CERTIFICATE_FILE_1_INSTANCE \
-19
View File
@@ -164,25 +164,6 @@
#endif #endif
#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 */ /* for confirmed messages, this is the number of transactions */
/* that we hold in a queue waiting for timeout. */ /* that we hold in a queue waiting for timeout. */
/* Configure to zero if you don't want any confirmed messages */ /* Configure to zero if you don't want any confirmed messages */
+8 -10
View File
@@ -23,9 +23,8 @@
#include "bacnet/basic/object/bacfile.h" #include "bacnet/basic/object/bacfile.h"
#define PRINTF debug_printf_stderr #define PRINTF debug_printf_stderr
#define DEBUG_BSC_DATALINK 0
#undef DEBUG_PRINTF #undef DEBUG_PRINTF
#if DEBUG_BSC_DATALINK == 1 #if DEBUG_BSC_DATALINK
#define DEBUG_PRINTF debug_printf #define DEBUG_PRINTF debug_printf
#else #else
#define DEBUG_PRINTF debug_printf_disabled #define DEBUG_PRINTF debug_printf_disabled
@@ -94,7 +93,7 @@ static void bsc_node_event(
FIFO_Add(&bsc_fifo, pdu, pdu16_len); FIFO_Add(&bsc_fifo, pdu, pdu16_len);
bsc_event_signal(bsc_data_event); bsc_event_signal(bsc_data_event);
} }
#if DEBUG_ENABLED == 1 #if DEBUG_ENABLED
else { else {
PRINTF("pdu of size %d\n is dropped\n", pdu_len); 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"); PRINTF("bsc_send_pdu() <<< ret = -1, incorrect dest mac address\n");
return len; return len;
} }
len = (int)bvlc_sc_encode_encapsulated_npdu( len = (int)bvlc_sc_encode_encapsulated_npdu(
buf, sizeof(buf), bsc_get_next_message_id(), NULL, &dest_vmac, pdu, buf, sizeof(buf), bsc_get_next_message_id(), NULL, &dest_vmac, pdu,
pdu_len); pdu_len);
@@ -270,6 +268,9 @@ int bsc_send_pdu(
if (ret != BSC_SC_SUCCESS) { if (ret != BSC_SC_SUCCESS) {
len = -1; 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; const char *err_desc = NULL;
static uint8_t buf[BVLC_SC_NPDU_SIZE_CONF]; static uint8_t buf[BVLC_SC_NPDU_SIZE_CONF];
DEBUG_PRINTF("bsc_receive() >>>\n");
bws_dispatch_lock(); bws_dispatch_lock();
if (bsc_datalink_state == BSC_DATALINK_STATE_STARTED) { if (bsc_datalink_state == BSC_DATALINK_STATE_STARTED) {
@@ -355,7 +354,7 @@ uint16_t bsc_receive(
pdu_len = pdu_len =
(uint16_t)dm.payload.encapsulated_npdu.npdu_len; (uint16_t)dm.payload.encapsulated_npdu.npdu_len;
} }
#if DEBUG_ENABLED == 1 #if DEBUG_ENABLED
else { else {
PRINTF( PRINTF(
"bsc_receive() pdu of size %d is dropped " "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); DEBUG_PRINTF("bsc_receive() pdu_len = %d\n", pdu_len);
} }
} }
bws_dispatch_unlock(); bws_dispatch_unlock();
DEBUG_PRINTF("bsc_receive() <<< ret = %d\n", pdu_len);
return 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); Network_Port_SC_Failed_Connection_Requests_Delete_All(instance);
for (i = 0; i < cnt; i++) { for (i = 0; i < cnt; i++) {
if (r[i].Peer_Address.host[0] != 0) { if (r[i].Peer_Address.host[0] != 0) {
#if DEBUG_ENABLED == 1 #if DEBUG_ENABLED
DEBUG_PRINTF( DEBUG_PRINTF(
"failed request record %d, host %s, vmac %s, uuid " "failed request record %d, host %s, vmac %s, uuid "
"%s, error %d, details = %s\n", "%s, error %d, details = %s\n",
+1 -1
View File
@@ -56,7 +56,7 @@ void bsc_cleanup(void);
*/ */
BACNET_STACK_EXPORT 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 * @brief Blocking thread-safe bsc_send_pdu() function
+14
View File
@@ -9,6 +9,8 @@
#define BACNET_DATALINK_BSC_EVENT_H #define BACNET_DATALINK_BSC_EVENT_H
/* BACnet Stack defines - first */ /* BACnet Stack defines - first */
#include "bacnet/bacdef.h" #include "bacnet/bacdef.h"
/* BACnet Stack Datalink API */
#include "bacnet/datalink/bsc/bvlc-sc.h"
struct BSC_Event; struct BSC_Event;
typedef struct BSC_Event 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); 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 #endif
+1 -3
View File
@@ -16,10 +16,8 @@
#include "bacnet/basic/object/sc_netport.h" #include "bacnet/basic/object/sc_netport.h"
#include "bacnet/bactext.h" #include "bacnet/bactext.h"
#define DEBUG_BSC_HUB_CONNECTOR 0
#undef DEBUG_PRINTF #undef DEBUG_PRINTF
#if DEBUG_BSC_HUB_CONNECTOR == 1 #if DEBUG_BSC_HUB_CONNECTOR
#define DEBUG_PRINTF debug_printf #define DEBUG_PRINTF debug_printf
#else #else
#undef DEBUG_ENABLED #undef DEBUG_ENABLED
+70 -47
View File
@@ -14,15 +14,19 @@
#include "bacnet/bacdef.h" #include "bacnet/bacdef.h"
#include "bacnet/npdu.h" #include "bacnet/npdu.h"
#include "bacnet/bacenum.h" #include "bacnet/bacenum.h"
#include "bacnet/bactext.h"
#define DEBUG_BSC_HUB_FUNCTION 0
#undef DEBUG_PRINTF #undef DEBUG_PRINTF
#if DEBUG_BSC_HUB_FUNCTION == 1 #if DEBUG_BSC_HUB_FUNCTION
#define DEBUG_PRINTF debug_printf #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 #else
#undef DEBUG_ENABLED #undef DEBUG_ENABLED
#define DEBUG_PRINTF debug_printf_disabled #define DEBUG_PRINTF debug_printf_disabled
#define DEBUG_PRINTF_VERBOSE debug_printf_disabled
#endif #endif
static BSC_SOCKET *hub_function_find_connection_for_vmac( 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(); bws_dispatch_lock();
f = (BSC_HUB_FUNCTION *)user_arg; f = (BSC_HUB_FUNCTION *)user_arg;
for (i = 0; i < sizeof(f->sock) / sizeof(BSC_SOCKET); i++) { 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], "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)); f->sock[i].state, bsc_uuid_to_string(&f->sock[i].uuid));
if (f->sock[i].state != BSC_SOCK_STATE_IDLE && if (f->sock[i].state != BSC_SOCK_STATE_IDLE &&
!memcmp( !memcmp(
&uuid->uuid[0], &f->sock[i].uuid.uuid[0], sizeof(uuid->uuid))) { &uuid->uuid[0], &f->sock[i].uuid.uuid[0], sizeof(uuid->uuid))) {
bws_dispatch_unlock(); bws_dispatch_unlock();
DEBUG_PRINTF("found socket\n"); DEBUG_PRINTF_VERBOSE("found socket\n");
return &f->sock[i]; return &f->sock[i];
} }
} }
@@ -282,14 +286,17 @@ static void hub_function_socket_event(
BSC_HUB_FUNCTION *f; BSC_HUB_FUNCTION *f;
size_t len; size_t len;
DEBUG_PRINTF( DEBUG_PRINTF_VERBOSE(
"hub_function_socket_event() >>> c = %p, ev = %d, reason = " "hub_function_socket_event() >>> c = %p, ev = %d, reason = "
"%d, desc = %p, pdu = %p, pdu_len = %d, decoded_pdu = %p\n", "%s, desc = %p, pdu = %p, pdu_len = %d, decoded_pdu = %p\n",
c, ev, reason, reason_desc, pdu, pdu_len, decoded_pdu); c, ev, bactext_error_code_name(reason), reason_desc, pdu, pdu_len,
decoded_pdu);
bws_dispatch_lock(); bws_dispatch_lock();
f = (BSC_HUB_FUNCTION *)c->ctx->user_arg; f = (BSC_HUB_FUNCTION *)c->ctx->user_arg;
if (ev == BSC_SOCKET_EVENT_RECEIVED) { 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 */ /* double check that received message does not contain */
/* originating virtual address and contains dest vaddr */ /* originating virtual address and contains dest vaddr */
/* although such kind of check is already in bsc-socket.c */ /* 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(); p_pdu = bsc_socket_get_global_buf();
len = pdu_len; len = pdu_len;
memcpy(p_pdu, pdu, len); memcpy(p_pdu, pdu, len);
for (i = 0; i < sizeof(f->sock) / sizeof(BSC_SOCKET); i++) { for (i = 0; i < sizeof(f->sock) / sizeof(BSC_SOCKET); i++) {
if (&f->sock[i] != c && if ((&f->sock[i] != c) &&
f->sock[i].state == BSC_SOCK_STATE_CONNECTED) { (f->sock[i].state == BSC_SOCK_STATE_CONNECTED)) {
/* change origin address if presented or add origin /* change origin address if presented or add origin
*/ */
/* address into pdu by extending of it's header */ /* address into pdu by extending of it's header */
len = (uint16_t)bvlc_sc_set_orig( len = (uint16_t)bvlc_sc_set_orig(
&p_pdu, len, &c->vmac); &p_pdu, len, &c->vmac);
ret = bsc_send(&f->sock[i], p_pdu, len); ret = bsc_send(&f->sock[i], p_pdu, len);
(void)ret; if (ret == BSC_SC_SUCCESS) {
#if DEBUG_ENABLED == 1
if (ret != BSC_SC_SUCCESS) {
DEBUG_PRINTF( DEBUG_PRINTF(
"BSC-HUB: "
"sent pdu of %d bytes\n",
len);
} else {
DEBUG_PRINTF(
"BSC-HUB: "
"sending of reconstructed pdu failed, " "sending of reconstructed pdu failed, "
"err = %d\n", "err = %s\n",
ret); bsc_return_code_to_string(ret));
}
#endif
} }
} }
} }
#if DEBUG_ENABLED == 1 } else {
else { DEBUG_PRINTF(
DEBUG_PRINTF("pdu with len = %d is dropped\n", pdu_len); "BSC-HUB: received pdu with len = %d is dropped\n",
pdu_len);
} }
#endif
} else { } else {
dst = hub_function_find_connection_for_vmac( dst = hub_function_find_connection_for_vmac(
decoded_pdu->hdr.dest, (void *)f); decoded_pdu->hdr.dest, (void *)f);
if (!dst) { if (!dst) {
DEBUG_PRINTF( 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", "%d for dest vmac %s\n",
pdu_len, bsc_vmac_to_string(decoded_pdu->hdr.dest)); pdu_len, bsc_vmac_to_string(decoded_pdu->hdr.dest));
} else { } else {
bvlc_sc_remove_dest_set_orig(pdu, pdu_len, &c->vmac); bvlc_sc_remove_dest_set_orig(pdu, pdu_len, &c->vmac);
ret = bsc_send(dst, pdu, pdu_len); ret = bsc_send(dst, pdu, pdu_len);
(void)ret; if (ret == BSC_SC_SUCCESS) {
#if DEBUG_ENABLED == 1
if (ret != BSC_SC_SUCCESS) {
DEBUG_PRINTF( DEBUG_PRINTF(
"sending of pdu of %d bytes failed, err = %d\n", "BSC-HUB: "
pdu_len, ret); "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_HUBF_EVENT_ERROR_DUPLICATED_VMAC,
(BSC_HUB_FUNCTION_HANDLE)f, f->user_arg); (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) { } else if (ev == BSC_SOCKET_EVENT_CONNECTED) {
hub_function_update_status(f, c, ev, reason, reason_desc); hub_function_update_status(f, c, ev, reason, reason_desc);
} }
bws_dispatch_unlock(); 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_SC_RET ret;
BSC_HUB_FUNCTION *f; 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 || if (!ca_cert_chain || !ca_cert_chain_size || !cert_chain ||
!cert_chain_size || !key || !key_size || !local_uuid || !local_vmac || !cert_chain_size || !key || !key_size || !local_uuid || !local_vmac ||
!max_local_npdu_len || !max_local_bvlc_len || !connect_timeout_s || !max_local_npdu_len || !max_local_bvlc_len || !connect_timeout_s ||
!heartbeat_timeout_s || !disconnect_timeout_s || !event_func || !h) { !heartbeat_timeout_s || !disconnect_timeout_s || !event_func || !h) {
DEBUG_PRINTF("bsc_hub_function_start() <<< ret = BSC_SC_BAD_PARAM\n"); ret = BSC_SC_BAD_PARAM;
return BSC_SC_BAD_PARAM; DEBUG_PRINTF(
"BSC-HUB: start failed. err=%s\n", bsc_return_code_to_string(ret));
return ret;
} }
*h = NULL; *h = NULL;
bws_dispatch_lock(); bws_dispatch_lock();
f = hub_function_alloc(); f = hub_function_alloc();
if (!f) { if (!f) {
bws_dispatch_unlock(); bws_dispatch_unlock();
ret = BSC_SC_NO_RESOURCES;
DEBUG_PRINTF( DEBUG_PRINTF(
"bsc_hub_function_start() <<< ret = BSC_SC_NO_RESOURCES\n"); "BSC-HUB: alloc failed. err=%s\n", bsc_return_code_to_string(ret));
return BSC_SC_NO_RESOURCES; return ret;
} }
f->user_arg = user_arg; f->user_arg = user_arg;
f->event_func = event_func; f->event_func = event_func;
bsc_init_ctx_cfg( bsc_init_ctx_cfg(
BSC_SOCKET_CTX_ACCEPTOR, &f->cfg, BSC_WEBSOCKET_HUB_PROTOCOL, port, BSC_SOCKET_CTX_ACCEPTOR, &f->cfg, BSC_WEBSOCKET_HUB_PROTOCOL, port,
iface, ca_cert_chain, ca_cert_chain_size, cert_chain, cert_chain_size, 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; f->state = BSC_HUB_FUNCTION_STATE_STARTING;
*h = (BSC_HUB_FUNCTION_HANDLE)f; *h = (BSC_HUB_FUNCTION_HANDLE)f;
} else { } else {
DEBUG_PRINTF(
"BSC-HUB: context initialization failed. err=%s\n",
bsc_return_code_to_string(ret));
hub_function_free(f); hub_function_free(f);
} }
bws_dispatch_unlock(); 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; return ret;
} }
@@ -484,7 +503,7 @@ BSC_SC_RET bsc_hub_function_start(
void bsc_hub_function_stop(BSC_HUB_FUNCTION_HANDLE h) void bsc_hub_function_stop(BSC_HUB_FUNCTION_HANDLE h)
{ {
BSC_HUB_FUNCTION *f = (BSC_HUB_FUNCTION *)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(); bws_dispatch_lock();
if (f && f->state != BSC_HUB_FUNCTION_STATE_IDLE && if (f && f->state != BSC_HUB_FUNCTION_STATE_IDLE &&
f->state != BSC_HUB_FUNCTION_STATE_STOPPING) { 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); bsc_deinit_ctx(&f->ctx);
} }
bws_dispatch_unlock(); 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; BSC_HUB_FUNCTION *f = (BSC_HUB_FUNCTION *)h;
bool ret = false; 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(); bws_dispatch_lock();
if (f && f->state == BSC_HUB_FUNCTION_STATE_IDLE) { if (f && f->state == BSC_HUB_FUNCTION_STATE_IDLE) {
ret = true; ret = true;
} }
bws_dispatch_unlock(); 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; return ret;
} }
@@ -525,12 +546,14 @@ bool bsc_hub_function_started(BSC_HUB_FUNCTION_HANDLE h)
BSC_HUB_FUNCTION *f = (BSC_HUB_FUNCTION *)h; BSC_HUB_FUNCTION *f = (BSC_HUB_FUNCTION *)h;
bool ret = false; 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(); bws_dispatch_lock();
if (f && f->state == BSC_HUB_FUNCTION_STATE_STARTED) { if (f && f->state == BSC_HUB_FUNCTION_STATE_STARTED) {
ret = true; ret = true;
} }
bws_dispatch_unlock(); 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; return ret;
} }
+1 -3
View File
@@ -16,10 +16,8 @@
#include "bacnet/npdu.h" #include "bacnet/npdu.h"
#include "bacnet/bacenum.h" #include "bacnet/bacenum.h"
#define DEBUG_BSC_NODE_SWITCH 0
#undef DEBUG_PRINTF #undef DEBUG_PRINTF
#if DEBUG_BSC_NODE_SWITCH == 1 #if DEBUG_BSC_NODE_SWITCH
#define DEBUG_PRINTF debug_printf #define DEBUG_PRINTF debug_printf
#else #else
#undef DEBUG_ENABLED #undef DEBUG_ENABLED
+1 -3
View File
@@ -19,10 +19,8 @@
#include "bacnet/npdu.h" #include "bacnet/npdu.h"
#include "bacnet/bacenum.h" #include "bacnet/bacenum.h"
#define DEBUG_BSC_NODE 0
#undef DEBUG_PRINTF #undef DEBUG_PRINTF
#if DEBUG_BSC_NODE == 1 #if DEBUG_BSC_NODE
#define DEBUG_PRINTF debug_printf #define DEBUG_PRINTF debug_printf
#else #else
#undef DEBUG_ENABLED #undef DEBUG_ENABLED
+124 -118
View File
@@ -9,20 +9,25 @@
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include "bacnet/bactext.h"
#include "bacnet/datalink/bsc/bvlc-sc.h" #include "bacnet/datalink/bsc/bvlc-sc.h"
#include "bacnet/datalink/bsc/bsc-socket.h" #include "bacnet/datalink/bsc/bsc-socket.h"
#include "bacnet/datalink/bsc/bsc-util.h" #include "bacnet/datalink/bsc/bsc-util.h"
#include "bacnet/basic/sys/mstimer.h" #include "bacnet/basic/sys/mstimer.h"
#include "bacnet/basic/sys/debug.h" #include "bacnet/basic/sys/debug.h"
#define DEBUG_BSC_SOCKET 0
#undef DEBUG_PRINTF #undef DEBUG_PRINTF
#if DEBUG_BSC_SOCKET == 1 #if DEBUG_BSC_SOCKET
#define DEBUG_PRINTF debug_printf #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 #else
#undef DEBUG_ENABLED #undef DEBUG_ENABLED
#define DEBUG_PRINTF debug_printf_disabled #define DEBUG_PRINTF debug_printf_disabled
#define DEBUG_PRINTF_VERBOSE debug_printf_disabled
#endif #endif
static const char *s_error_no_origin = static const char *s_error_no_origin =
@@ -135,7 +140,7 @@ void bsc_init_ctx_cfg(
unsigned int heartbeat_timeout_s, unsigned int heartbeat_timeout_s,
unsigned int disconnect_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) { if (cfg) {
cfg->proto = proto; cfg->proto = proto;
cfg->port = port; cfg->port = port;
@@ -155,7 +160,7 @@ void bsc_init_ctx_cfg(
cfg->heartbeat_timeout_s = heartbeat_timeout_s; cfg->heartbeat_timeout_s = heartbeat_timeout_s;
cfg->disconnect_timeout_s = disconnect_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) static void bsc_srv_process_error(BSC_SOCKET *c, BACNET_ERROR_CODE reason)
{ {
DEBUG_PRINTF( 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->state = BSC_SOCK_STATE_ERROR;
c->reason = reason; c->reason = reason;
bws_srv_disconnect(c->ctx->sh, c->wh); 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) 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->state = BSC_SOCK_STATE_ERROR;
c->reason = reason; c->reason = reason;
bws_cli_disconnect(c->wh); 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 #endif
message_id = bsc_get_next_message_id(); 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( len = bvlc_sc_encode_result(
TX_BUF_PTR(c), TX_BUF_BYTES_AVAIL(c), message_id, origin, dest, 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); "bsc_prepare_error_extended() <<< ret = true, pdu_len = %d\n", len);
return true; return true;
} }
DEBUG_PRINTF("bsc_prepare_error_extended() <<< ret = false\n"); DEBUG_PRINTF_VERBOSE("bsc_prepare_error_extended() <<< ret = false\n");
return false; return false;
} }
@@ -349,6 +358,9 @@ static bool bsc_prepare_protocol_error(
BACNET_ERROR_CODE error_code, BACNET_ERROR_CODE error_code,
const char *utf8_details_string) 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( return bsc_prepare_protocol_error_extended(
c, dm, origin, dest, NULL, error_class, error_code, c, dm, origin, dest, NULL, error_class, error_code,
utf8_details_string); utf8_details_string);
@@ -389,14 +401,14 @@ static void bsc_process_socket_disconnecting(
size_t buflen, size_t buflen,
bool *need_disconnect) 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 (dm->hdr.bvlc_function == BVLC_SC_DISCONNECT_ACK) {
#if DEBUG_BSC_SOCKET == 1 #if DEBUG_BSC_SOCKET == 1
if (dm->hdr.message_id != c->expected_disconnect_message_id) { if (dm->hdr.message_id != c->expected_disconnect_message_id) {
DEBUG_PRINTF( DEBUG_PRINTF(
"bsc_process_socket_disconnecting() got disconnect ack with " "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); dm->hdr.message_id, c);
} else { } else {
DEBUG_PRINTF( DEBUG_PRINTF(
@@ -429,7 +441,7 @@ static void bsc_process_socket_disconnecting(
c->ctx->funcs->socket_event( c->ctx->funcs->socket_event(
c, BSC_SOCKET_EVENT_RECEIVED, 0, NULL, buf, buflen, dm); 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; uint16_t message_id;
size_t len; size_t len;
DEBUG_PRINTF( DEBUG_PRINTF_VERBOSE(
"bsc_process_socket_connected_state() >>> c = %p, dm = %p, buf = %p, " "bsc_process_socket_connected_state() >>> c = %p, dm = %p, buf = %p, "
"buflen = %d\n", "buflen = %d\n",
c, dm, buf, buflen); c, dm, buf, buflen);
if (dm->hdr.bvlc_function == BVLC_SC_HEARTBEAT_ACK) { if (dm->hdr.bvlc_function == BVLC_SC_HEARTBEAT_ACK) {
#if DEBUG_ENABLED == 1
if (dm->hdr.message_id != c->expected_heartbeat_message_id) { if (dm->hdr.message_id != c->expected_heartbeat_message_id) {
DEBUG_PRINTF( DEBUG_PRINTF_VERBOSE(
"bsc_process_socket_connected_state() got heartbeat ack with " "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); dm->hdr.message_id, c);
} else { } else {
DEBUG_PRINTF( DEBUG_PRINTF_VERBOSE(
"bsc_process_socket_connected_state() got heartbeat ack for " "bsc_process_socket_connected_state() got heartbeat ack for "
"socket %p\n", "socket %p\n",
c); c);
} }
#endif
} else if (dm->hdr.bvlc_function == BVLC_SC_HEARTBEAT_REQUEST) { } else if (dm->hdr.bvlc_function == BVLC_SC_HEARTBEAT_REQUEST) {
DEBUG_PRINTF( DEBUG_PRINTF(
"bsc_process_socket_connected_state() got heartbeat " "bsc_process_socket_connected_state() got heartbeat "
"request with message_id %d\n", "request with message id %04x\n",
dm->hdr.message_id); dm->hdr.message_id);
message_id = dm->hdr.message_id; message_id = dm->hdr.message_id;
len = bvlc_sc_encode_heartbeat_ack( len = bvlc_sc_encode_heartbeat_ack(
@@ -482,20 +492,17 @@ static void bsc_process_socket_connected_state(
if (len) { if (len) {
TX_BUF_UPDATE(c, len); TX_BUF_UPDATE(c, len);
*need_send = true; *need_send = true;
} } else {
#if DEBUG_BSC_SOCKET == 1
else {
DEBUG_PRINTF( DEBUG_PRINTF(
"bsc_process_socket_connected_state() no resources to " "bsc_process_socket_connected_state() no resources to "
"answer on heartbeat request " "answer on heartbeat request "
"socket %p\n", "socket %p\n",
c); c);
} }
#endif
} else if (dm->hdr.bvlc_function == BVLC_SC_DISCONNECT_REQUEST) { } else if (dm->hdr.bvlc_function == BVLC_SC_DISCONNECT_REQUEST) {
DEBUG_PRINTF( DEBUG_PRINTF(
"bsc_process_socket_connected_state() got disconnect " "bsc_process_socket_connected_state() got disconnect "
"request with message_id %d\n", "request with message id %04x\n",
dm->hdr.message_id); dm->hdr.message_id);
message_id = dm->hdr.message_id; message_id = dm->hdr.message_id;
len = bvlc_sc_encode_disconnect_ack( 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. */ /* and hope that remote peer clears itself up. */
DEBUG_PRINTF( DEBUG_PRINTF(
"bsc_process_socket_connected_state() got unexpected " "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); dm->hdr.message_id);
c->state = BSC_SOCK_STATE_DISCONNECTING; c->state = BSC_SOCK_STATE_DISCONNECTING;
*need_disconnect = true; *need_disconnect = true;
@@ -545,7 +552,7 @@ static void bsc_process_socket_connected_state(
c, BSC_SOCKET_EVENT_RECEIVED, 0, NULL, buf, buflen, dm); 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; bool valid = true;
size_t len; size_t len;
DEBUG_PRINTF( DEBUG_PRINTF_VERBOSE(
"bsc_process_socket_state() >>> ctx = %p, c = %p, state = %d, " "bsc_process_socket_state() >>> ctx = %p, c = %p, state = %d, "
"rx_buf = %p, rx_buf_size = %d\n", "rx_buf = %p, rx_buf_size = %d\n",
c->ctx, c, c->state, rx_buf, rx_buf_size); 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( *need_send = bsc_prepare_protocol_error(
c, dm, dm->hdr.origin, dm->hdr.dest, error_class, c, dm, dm->hdr.origin, dm->hdr.dest, error_class,
error_code, err_desc); error_code, err_desc);
} } else {
#if DEBUG_BSC_SOCKET == 1
else {
DEBUG_PRINTF( DEBUG_PRINTF(
"bsc_process_socket_state() decoding failed, message " "bsc_process_socket_state() decoding failed, message "
"is silently dropped cause it's length < 4 bytes\n"); "is silently dropped cause it's length < 4 bytes\n");
} }
#endif
} else { } else {
DEBUG_PRINTF( DEBUG_PRINTF_VERBOSE(
"c->dm.hdr.bvlc_function == %d, message_id = %d\n", "bsc_process_socket_state() "
dm->hdr.bvlc_function, dm->hdr.message_id); "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 || if (dm->hdr.bvlc_function == BVLC_SC_ENCAPSULATED_NPDU ||
dm->hdr.bvlc_function == BVLC_SC_ADVERTISIMENT || dm->hdr.bvlc_function == BVLC_SC_ADVERTISIMENT ||
dm->hdr.bvlc_function == BVLC_SC_ADDRESS_RESOLUTION_ACK || 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) { dm->hdr.bvlc_function == BVLC_SC_RESULT) {
if (c->ctx->cfg->type == BSC_SOCKET_CTX_INITIATOR && if (c->ctx->cfg->type == BSC_SOCKET_CTX_INITIATOR &&
c->ctx->cfg->proto == BSC_WEBSOCKET_HUB_PROTOCOL) { c->ctx->cfg->proto == BSC_WEBSOCKET_HUB_PROTOCOL) {
/* this is a case when socket is a hub connector receiving /* this is a case when socket is a hub connector
*/ receiving from hub */
/* from hub */
if (dm->hdr.origin == NULL && if (dm->hdr.origin == NULL &&
dm->hdr.bvlc_function != BVLC_SC_RESULT) { dm->hdr.bvlc_function != BVLC_SC_RESULT) {
error_class = ERROR_CLASS_COMMUNICATION; error_class = ERROR_CLASS_COMMUNICATION;
error_code = ERROR_CODE_HEADER_ENCODING_ERROR; error_code = ERROR_CODE_HEADER_ENCODING_ERROR;
*need_send = bsc_prepare_protocol_error( *need_send = bsc_prepare_protocol_error(
c, dm, NULL, &c->vmac, error_class, error_code, c, dm, NULL, &c->vmac, error_class, error_code,
s_error_no_origin); s_error_no_origin);
@@ -637,8 +641,8 @@ static void bsc_process_socket_state(
} else if ( } else if (
c->ctx->cfg->type == BSC_SOCKET_CTX_ACCEPTOR && c->ctx->cfg->type == BSC_SOCKET_CTX_ACCEPTOR &&
c->ctx->cfg->proto == BSC_WEBSOCKET_HUB_PROTOCOL) { c->ctx->cfg->proto == BSC_WEBSOCKET_HUB_PROTOCOL) {
/* this is a case when socket is hub function receiving */ /* this is a case when socket is hub function
/* from node */ receiving from node */
if (dm->hdr.dest == NULL) { if (dm->hdr.dest == NULL) {
error_class = ERROR_CLASS_COMMUNICATION; error_class = ERROR_CLASS_COMMUNICATION;
error_code = ERROR_CODE_HEADER_ENCODING_ERROR; error_code = ERROR_CODE_HEADER_ENCODING_ERROR;
@@ -656,7 +660,6 @@ static void bsc_process_socket_state(
} }
} }
} }
/* every valid message restarts heartbeat timeout */ /* every valid message restarts heartbeat timeout */
/* and only valid messages are processed */ /* and only valid messages are processed */
if (valid) { if (valid) {
@@ -680,38 +683,39 @@ static void bsc_process_socket_state(
} }
expired = mstimer_expired(&c->t); 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) { if (c->state == BSC_SOCK_STATE_AWAITING_ACCEPT && expired) {
c->state = BSC_SOCK_STATE_ERROR; c->state = BSC_SOCK_STATE_ERROR;
c->reason = ERROR_CODE_TIMEOUT; c->reason = ERROR_CODE_TIMEOUT;
*need_disconnect = true; *need_disconnect = true;
DEBUG_PRINTF("BSC-Socket: connection timeout AWAITING_ACCEPT.\n");
} else if (c->state == BSC_SOCK_STATE_AWAITING_REQUEST && expired) { } else if (c->state == BSC_SOCK_STATE_AWAITING_REQUEST && expired) {
c->state = BSC_SOCK_STATE_ERROR; c->state = BSC_SOCK_STATE_ERROR;
c->reason = ERROR_CODE_TIMEOUT; c->reason = ERROR_CODE_TIMEOUT;
*need_disconnect = true; *need_disconnect = true;
DEBUG_PRINTF("BSC-Socket: connection timeout AWAITING_REQUEST.\n");
} else if (c->state == BSC_SOCK_STATE_DISCONNECTING && expired) { } else if (c->state == BSC_SOCK_STATE_DISCONNECTING && expired) {
c->state = BSC_SOCK_STATE_ERROR; c->state = BSC_SOCK_STATE_ERROR;
c->reason = ERROR_CODE_TIMEOUT; c->reason = ERROR_CODE_TIMEOUT;
*need_disconnect = true; *need_disconnect = true;
DEBUG_PRINTF("BSC-Socket: connection timeout DISCONNECTING.\n");
} else if (c->state == BSC_SOCK_STATE_CONNECTED) { } else if (c->state == BSC_SOCK_STATE_CONNECTED) {
expired = mstimer_expired(&c->heartbeat); expired = mstimer_expired(&c->heartbeat);
DEBUG_PRINTF( DEBUG_PRINTF_VERBOSE(
"bsc_process_socket_state() heartbeat timeout expired = %d\n", "BSC-Socket: heartbeat mstimer_expired() = %d\n", expired);
expired);
if (expired) { if (expired) {
DEBUG_PRINTF( DEBUG_PRINTF_VERBOSE(
"bsc_process_socket_state() heartbeat timeout elapsed " "BSC-Socket: heartbeat timeout elapsed "
"for socket %p\n", "for socket %p\n",
c); c);
if (c->ctx->cfg->type == BSC_SOCKET_CTX_INITIATOR) { if (c->ctx->cfg->type == BSC_SOCKET_CTX_INITIATOR) {
DEBUG_PRINTF( DEBUG_PRINTF(
"bsc_process_socket_state() going to send heartbeat " "BSC-Socket: sending heartbeat request on connection %p\n",
"request on connection %p\n",
c); c);
c->expected_heartbeat_message_id = bsc_get_next_message_id(); c->expected_heartbeat_message_id = bsc_get_next_message_id();
DEBUG_PRINTF( DEBUG_PRINTF_VERBOSE(
"bsc_process_socket_state() heartbeat message_id %04x\n", "BSC-Socket: heartbeat message id %04x\n",
c->expected_heartbeat_message_id); c->expected_heartbeat_message_id);
len = bvlc_sc_encode_heartbeat_request( len = bvlc_sc_encode_heartbeat_request(
@@ -725,14 +729,14 @@ static void bsc_process_socket_state(
*need_send = true; *need_send = true;
} else { } else {
DEBUG_PRINTF( DEBUG_PRINTF(
"bsc_process_socket_state() sending of " "BSC-Socket: sending of "
"heartbeat request failed on connection %p\n", "heartbeat request failed on connection %p\n",
c); c);
} }
} else if (c->ctx->cfg->type == BSC_SOCKET_CTX_ACCEPTOR) { } else if (c->ctx->cfg->type == BSC_SOCKET_CTX_ACCEPTOR) {
DEBUG_PRINTF( DEBUG_PRINTF(
"bsc_process_socket_state() zombie socket %p is " "BSC-Socket: zombie socket %p is "
"disconnecting...\n", "disconnecting by timeout.\n",
c); c);
c->state = BSC_SOCK_STATE_ERROR; c->state = BSC_SOCK_STATE_ERROR;
c->reason = ERROR_CODE_TIMEOUT; 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) void bsc_socket_maintenance_timer(uint16_t seconds)
{ {
int i, j; int i, j, count = 0;
(void)seconds; DEBUG_PRINTF_VERBOSE(
DEBUG_PRINTF("bsc_socket_maintenance_timer() >>>\n"); "bsc_socket_maintenance_timer(%us) >>>\n", (unsigned)seconds);
bws_dispatch_lock(); bws_dispatch_lock();
for (i = 0; i < BSC_SOCKET_CTX_NUM; i++) { for (i = 0; i < BSC_SOCKET_CTX_NUM; i++) {
if (bsc_socket_ctx[i] != NULL) { if (bsc_socket_ctx[i] != NULL) {
if (bsc_socket_ctx[i]->state == BSC_CTX_STATE_INITIALIZED) { if (bsc_socket_ctx[i]->state == BSC_CTX_STATE_INITIALIZED) {
for (j = 0; j < bsc_socket_ctx[i]->sock_num; j++) { for (j = 0; j < bsc_socket_ctx[i]->sock_num; j++) {
count++;
bsc_runloop_socket( bsc_runloop_socket(
&bsc_socket_ctx[i]->sock[j], NULL, NULL, 0); &bsc_socket_ctx[i]->sock[j], NULL, NULL, 0);
} }
} }
} }
} }
bws_dispatch_unlock(); 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; uint16_t uclass;
const char *err_desc = NULL; const char *err_desc = NULL;
DEBUG_PRINTF( DEBUG_PRINTF_VERBOSE(
"bsc_process_srv_awaiting_request() >>> c = %p, dm = %p, buf = %p, " "bsc_process_srv_awaiting_request() >>> c = %p, dm = %p, buf = %p, "
"bufsize = %d\n", "bufsize = %d\n",
c, dm, buf, bufsize); c, dm, buf, bufsize);
@@ -858,8 +862,8 @@ static void bsc_process_srv_awaiting_request(
bsc_vmac_to_string(dm->payload.connect_request.vmac)); bsc_vmac_to_string(dm->payload.connect_request.vmac));
DEBUG_PRINTF( DEBUG_PRINTF(
"bsc_process_srv_awaiting_request() existing = %p, " "bsc_process_srv_awaiting_request() existing = %p, "
"existing->state = %d, c = %p\n", "existing->state = %s, c = %p\n",
existing, existing->state, c); existing, bsc_socket_state_to_string(existing->state), c);
bsc_copy_vmac(&c->vmac, dm->payload.connect_request.vmac); bsc_copy_vmac(&c->vmac, dm->payload.connect_request.vmac);
bsc_copy_uuid(&c->uuid, dm->payload.connect_request.uuid); bsc_copy_uuid(&c->uuid, dm->payload.connect_request.uuid);
c->max_npdu_len = dm->payload.connect_request.max_npdu_len; 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); ERROR_CODE_ABORT_OUT_OF_RESOURCES, NULL);
} }
bsc_srv_process_error(c, ERROR_CODE_ABORT_OUT_OF_RESOURCES); 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; return;
} else { } else {
TX_BUF_UPDATE(c, len); TX_BUF_UPDATE(c, len);
@@ -901,25 +907,28 @@ static void bsc_process_srv_awaiting_request(
TX_BUF_UPDATE(existing, len); TX_BUF_UPDATE(existing, len);
DEBUG_PRINTF( DEBUG_PRINTF(
"bsc_process_srv_awaiting_request() request to " "bsc_process_srv_awaiting_request() request to "
"send disconnect request to socket %d(%p)\n", "send disconnect request with message id %04x "
existing->wh, existing); " to existing socket %d(%p)\n",
existing->expected_disconnect_message_id, existing->wh,
existing);
bws_srv_send(existing->ctx->sh, existing->wh); bws_srv_send(existing->ctx->sh, existing->wh);
} else { } else {
DEBUG_PRINTF( DEBUG_PRINTF(
"bsc_process_srv_awaiting_request() sending of disconnect " "bsc_process_srv_awaiting_request() sending of "
"request failed, err = BSC_SC_NO_RESOURCES\n"); "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 " "bsc_process_srv_awaiting_request() set socket %p to "
"connected state\n", "connected state\n",
c); c);
mstimer_set( mstimer_set(
&c->heartbeat, 2 * c->ctx->cfg->heartbeat_timeout_s * 1000); &c->heartbeat, 2 * c->ctx->cfg->heartbeat_timeout_s * 1000);
c->state = BSC_SOCK_STATE_CONNECTED; c->state = BSC_SOCK_STATE_CONNECTED;
c->ctx->funcs->socket_event( c->ctx->funcs->socket_event(
c, BSC_SOCKET_EVENT_CONNECTED, 0, NULL, NULL, 0, NULL); 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; return;
} }
@@ -959,7 +968,7 @@ static void bsc_process_srv_awaiting_request(
"message failed, err = BSC_SC_NO_RESOURCES\n"); "message failed, err = BSC_SC_NO_RESOURCES\n");
bsc_srv_process_error(c, ERROR_CODE_NODE_DUPLICATE_VMAC); 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; return;
} }
@@ -1011,7 +1020,7 @@ static void bsc_process_srv_awaiting_request(
"message failed, err = BSC_SC_NO_RESOURCES\n"); "message failed, err = BSC_SC_NO_RESOURCES\n");
bsc_srv_process_error(c, ERROR_CODE_NODE_DUPLICATE_VMAC); 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; return;
} }
DEBUG_PRINTF( DEBUG_PRINTF(
@@ -1058,7 +1067,7 @@ static void bsc_process_srv_awaiting_request(
dm->hdr.bvlc_function); dm->hdr.bvlc_function);
} }
#endif #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; (void)sh;
bws_dispatch_lock(); bws_dispatch_lock();
DEBUG_PRINTF( DEBUG_PRINTF_VERBOSE(
"bsc_dispatch_srv_func() >>> sh = %p, h = %d, ev = %d, " "bsc_dispatch_srv_func() >>> sh = %p, h = %d, ev = %d, "
"reason = %d, desc = %p, buf " "reason = %d, desc = %p, buf "
"= %p, bufsize = %ld, ctx = %p\n", "= %p, bufsize = %ld, ctx = %p\n",
@@ -1131,7 +1140,7 @@ static void bsc_dispatch_srv_func(
bws_dispatch_unlock(); bws_dispatch_unlock();
return; return;
} }
DEBUG_PRINTF( DEBUG_PRINTF_VERBOSE(
"bsc_dispatch_srv_func() socket %p, state = %d\n", c, c->state); "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); mstimer_set(&c->t, c->ctx->cfg->connect_timeout_s * 1000);
} }
} else if (ev == BSC_WEBSOCKET_RECEIVED) { } else if (ev == BSC_WEBSOCKET_RECEIVED) {
DEBUG_PRINTF("bsc_dispatch_srv_func() processing "
"BSC_WEBSOCKET_RECEIVED event\n");
DEBUG_PRINTF( 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) { if (c->state == BSC_SOCK_STATE_AWAITING_REQUEST) {
bsc_process_srv_awaiting_request(c, &bsc_dm, buf, bufsize); bsc_process_srv_awaiting_request(c, &bsc_dm, buf, bufsize);
} else if ( } else if (
c->state == BSC_SOCK_STATE_DISCONNECTING || c->state == BSC_SOCK_STATE_DISCONNECTING ||
c->state == BSC_SOCK_STATE_CONNECTED) { c->state == BSC_SOCK_STATE_CONNECTED) {
bsc_runloop_socket(c, &bsc_dm, buf, bufsize); bsc_runloop_socket(c, &bsc_dm, buf, bufsize);
} } else {
#if DEBUG_BSC_SOCKET == 1
else {
DEBUG_PRINTF( DEBUG_PRINTF(
"bsc_dispatch_srv_func() data was dropped for socket " "bsc_dispatch_srv_func() data was dropped for socket "
"%p, state %d, data_size %d\n", "%p, state %s, data_size %d\n",
c, c->state, bufsize); c, bsc_socket_state_to_string(c->state), bufsize);
} }
#endif
} else if (ev == BSC_WEBSOCKET_SENDABLE) { } else if (ev == BSC_WEBSOCKET_SENDABLE) {
p = c->tx_buf; 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); c->ctx->sh, c->wh, &p[sizeof(len) + BSC_CONF_TX_PRE], len);
if (wret != BSC_WEBSOCKET_SUCCESS) { if (wret != BSC_WEBSOCKET_SUCCESS) {
DEBUG_PRINTF( DEBUG_PRINTF(
"bsc_dispatch_srv_func() send data failed, start " "bsc_dispatch_srv_func() send data failed. "
"disconnect operation on socket %p\n", "Error=%s, start disconnect operation on socket %p\n",
c); bsc_websocket_return_to_string(wret), c);
bsc_srv_process_error( bsc_srv_process_error(
c, c,
c->state != BSC_SOCK_STATE_ERROR_FLUSH_TX c->state != BSC_SOCK_STATE_ERROR_FLUSH_TX
@@ -1215,7 +1221,7 @@ static void bsc_dispatch_srv_func(
} }
bsc_socket_maintenance_timer(0); bsc_socket_maintenance_timer(0);
DEBUG_PRINTF("bsc_dispatch_srv_func() <<<\n"); DEBUG_PRINTF_VERBOSE("bsc_dispatch_srv_func() <<<\n");
bws_dispatch_unlock(); bws_dispatch_unlock();
} }
@@ -1233,7 +1239,7 @@ static void bsc_process_cli_awaiting_accept(
uint16_t error_code; uint16_t error_code;
const char *err_desc = NULL; const char *err_desc = NULL;
DEBUG_PRINTF( DEBUG_PRINTF_VERBOSE(
"bsc_process_cli_awaiting_accept() >>> c = %p, dm = %p, buf = " "bsc_process_cli_awaiting_accept() >>> c = %p, dm = %p, buf = "
"%p, bufsize = %d\n", "%p, bufsize = %d\n",
c, dm, buf, bufsize); c, dm, buf, bufsize);
@@ -1329,7 +1335,7 @@ static void bsc_process_cli_awaiting_accept(
dm->hdr.bvlc_function); dm->hdr.bvlc_function);
} }
#endif #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(); bws_dispatch_lock();
DEBUG_PRINTF( DEBUG_PRINTF_VERBOSE(
"bsc_dispatch_cli_func() >>> h = %d, ev = %d, reason = %d, " "bsc_dispatch_cli_func() >>> h = %d, ev = %d, reason = %d, "
"reason_desc = %p, buf = %p, " "reason_desc = %p, buf = %p, "
"bufsize = %ld, ctx = %p\n", "bufsize = %ld, ctx = %p\n",
h, ev, ws_reason, ws_reason_desc, buf, bufsize, ctx); h, ev, ws_reason, ws_reason_desc, buf, bufsize, ctx);
c = bsc_find_conn_by_websocket(ctx, h); c = bsc_find_conn_by_websocket(ctx, h);
if (!c) { if (!c) {
DEBUG_PRINTF( DEBUG_PRINTF(
"bsc_dispatch_cli_func() <<< warning, can not find " "bsc_dispatch_cli_func() <<< warning, can not find "
@@ -1379,11 +1383,13 @@ static void bsc_dispatch_cli_func(
bws_dispatch_unlock(); bws_dispatch_unlock();
return; return;
} }
DEBUG_PRINTF_VERBOSE(
DEBUG_PRINTF("bsc_dispatch_cli_func() ev = %d, state = %d\n", ev, c->state); "bsc_dispatch_cli_func() ev = %d, state = %d\n", ev, c->state);
if (ev == BSC_WEBSOCKET_DISCONNECTED) { 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) { if (ctx->state == BSC_CTX_STATE_DEINITIALIZING) {
bsc_set_socket_idle(c); bsc_set_socket_idle(c);
bsc_clear_vmac_and_uuid(c); bsc_clear_vmac_and_uuid(c);
@@ -1412,6 +1418,10 @@ static void bsc_dispatch_cli_func(
bsc_clear_vmac_and_uuid(c); bsc_clear_vmac_and_uuid(c);
} }
} else if (ev == BSC_WEBSOCKET_CONNECTED) { } 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) { if (c->state == BSC_SOCK_STATE_AWAITING_WEBSOCKET) {
DEBUG_PRINTF( DEBUG_PRINTF(
"bsc_dispatch_cli_func() conn %p, websocket %d, state " "bsc_dispatch_cli_func() conn %p, websocket %d, state "
@@ -1494,7 +1504,7 @@ static void bsc_dispatch_cli_func(
} }
bsc_socket_maintenance_timer(0); bsc_socket_maintenance_timer(0);
DEBUG_PRINTF("bsc_dispatch_cli_func() <<<\n"); DEBUG_PRINTF_VERBOSE("bsc_dispatch_cli_func() <<<\n");
bws_dispatch_unlock(); bws_dispatch_unlock();
} }
@@ -1579,7 +1589,7 @@ BSC_SC_RET bsc_init_ctx(
} }
bws_dispatch_unlock(); 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; return sc_ret;
} }
@@ -1627,7 +1637,7 @@ void bsc_deinit_ctx(BSC_SOCKET_CTX *ctx)
} }
bws_dispatch_unlock(); 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_SC_RET ret = BSC_SC_INVALID_OPERATION;
BSC_WEBSOCKET_RET wret; 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) { if (!ctx || !c || !url) {
ret = BSC_SC_BAD_PARAM; ret = BSC_SC_BAD_PARAM;
} else { } else {
@@ -1654,25 +1664,25 @@ BSC_SC_RET bsc_connect(BSC_SOCKET_CTX *ctx, BSC_SOCKET *c, char *url)
c->ctx = ctx; c->ctx = ctx;
c->state = BSC_SOCK_STATE_AWAITING_WEBSOCKET; c->state = BSC_SOCK_STATE_AWAITING_WEBSOCKET;
c->tx_buf_size = 0; c->tx_buf_size = 0;
wret = bws_cli_connect( wret = bws_cli_connect(
ctx->cfg->proto, url, ctx->cfg->ca_cert_chain, ctx->cfg->proto, url, ctx->cfg->ca_cert_chain,
ctx->cfg->ca_cert_chain_size, ctx->cfg->cert_chain, ctx->cfg->ca_cert_chain_size, ctx->cfg->cert_chain,
ctx->cfg->cert_chain_size, ctx->cfg->priv_key, ctx->cfg->cert_chain_size, ctx->cfg->priv_key,
ctx->cfg->priv_key_size, ctx->cfg->connect_timeout_s, ctx->cfg->priv_key_size, ctx->cfg->connect_timeout_s,
bsc_dispatch_cli_func, ctx, &c->wh); bsc_dispatch_cli_func, ctx, &c->wh);
ret = bsc_map_websocket_retcode(wret); ret = bsc_map_websocket_retcode(wret);
if (wret != BSC_WEBSOCKET_SUCCESS) { if (wret != BSC_WEBSOCKET_SUCCESS) {
DEBUG_PRINTF(
"bsc_connect() failed. %s\n",
bsc_websocket_return_to_string(wret));
bsc_set_socket_idle(c); bsc_set_socket_idle(c);
bsc_clear_vmac_and_uuid(c); bsc_clear_vmac_and_uuid(c);
} }
} }
bws_dispatch_unlock(); bws_dispatch_unlock();
} }
DEBUG_PRINTF("bsc_connect() <<< ret = %d\n", ret); DEBUG_PRINTF_VERBOSE("bsc_connect() <<< ret = %d\n", ret);
return ret; return ret;
} }
@@ -1685,9 +1695,7 @@ void bsc_disconnect(BSC_SOCKET *c)
size_t len; size_t len;
DEBUG_PRINTF("bsc_disconnect() >>> c = %p\n", c); DEBUG_PRINTF("bsc_disconnect() >>> c = %p\n", c);
bws_dispatch_lock(); bws_dispatch_lock();
if (c->ctx->state == BSC_CTX_STATE_INITIALIZED) { if (c->ctx->state == BSC_CTX_STATE_INITIALIZED) {
if (c->state == BSC_SOCK_STATE_CONNECTED) { if (c->state == BSC_SOCK_STATE_CONNECTED) {
c->expected_disconnect_message_id = bsc_get_next_message_id(); c->expected_disconnect_message_id = bsc_get_next_message_id();
@@ -1723,10 +1731,8 @@ void bsc_disconnect(BSC_SOCKET *c)
} }
} }
} }
bws_dispatch_unlock(); bws_dispatch_unlock();
DEBUG_PRINTF_VERBOSE("bsc_disconnect() <<<\n");
DEBUG_PRINTF("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(); bws_dispatch_unlock();
} }
DEBUG_PRINTF("bsc_send() <<< ret = %d\n", ret); DEBUG_PRINTF_VERBOSE("bsc_send() <<< ret = %d\n", ret);
return ret; return ret;
} }
@@ -1790,7 +1796,7 @@ uint16_t bsc_get_next_message_id(void)
message_id++; message_id++;
} }
ret = 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(); bws_dispatch_unlock();
return ret; return ret;
} }
+205 -49
View File
@@ -5,12 +5,12 @@
* @date Jule 2022 * @date Jule 2022
* SPDX-License-Identifier: GPL-2.0-or-later WITH GCC-exception-2.0 * SPDX-License-Identifier: GPL-2.0-or-later WITH GCC-exception-2.0
*/ */
#include "bacnet/datalink/bsc/bsc-util.h" #include <stdlib.h>
#include "bacnet/basic/object/bacfile.h" #include "bacnet/basic/object/bacfile.h"
#include "bacnet/basic/object/netport.h" #include "bacnet/basic/object/netport.h"
#include "bacnet/basic/object/sc_netport.h" #include "bacnet/basic/object/sc_netport.h"
#include "bacnet/basic/sys/debug.h" #include "bacnet/basic/sys/debug.h"
#include <stdlib.h> #include "bacnet/datalink/bsc/bsc-util.h"
#define PRINTF debug_printf_stdout #define PRINTF debug_printf_stdout
#define PRINTF_ERR debug_printf_stderr #define PRINTF_ERR debug_printf_stderr
@@ -88,43 +88,6 @@ char *bsc_uuid_to_string(BACNET_SC_UUID *uuid)
return buf; 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 * bsc_node_load_cert_bacfile loads one credentional file from bacfile object
* Note: the function adds null-terminated byte to loaded file * 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 * @brief Check if BACnet/SC certificate files exist
* @return true if all files exist, else false * @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; uint32_t file_instance;
instance = Network_Port_Index_To_Instance(0); file_instance = Network_Port_Issuer_Certificate_File(netport_instance, 0);
file_instance = Network_Port_Issuer_Certificate_File(instance, 0);
if (bacfile_file_size(file_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; 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) { 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; 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) { 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 false;
} }
return true; 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";
}
+8 -2
View File
@@ -15,6 +15,7 @@
#include "bacnet/basic/sys/debug.h" #include "bacnet/basic/sys/debug.h"
#include "bacnet/datalink/bsc/bsc-node.h" #include "bacnet/datalink/bsc/bsc-node.h"
#include "bacnet/datalink/bsc/bsc-retcodes.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/bvlc-sc.h"
#include "bacnet/datalink/bsc/websocket.h" #include "bacnet/datalink/bsc/websocket.h"
#include "bacnet/datetime.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); void bsc_copy_uuid(BACNET_SC_UUID *dst, BACNET_SC_UUID *src);
char *bsc_vmac_to_string(BACNET_SC_VMAC_ADDRESS *vmac); char *bsc_vmac_to_string(BACNET_SC_VMAC_ADDRESS *vmac);
char *bsc_uuid_to_string(BACNET_SC_UUID *uuid); 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( bool bsc_node_conf_fill_from_netport(
BSC_NODE_CONF *bsc_conf, BSC_NODE_EVENT_FUNC event_func); BSC_NODE_CONF *bsc_conf, BSC_NODE_EVENT_FUNC event_func);
void bsc_node_conf_cleanup(BSC_NODE_CONF *bsc_conf); 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_copy_str(char *dst, const char *src, size_t dst_len);
void bsc_set_timestamp(BACNET_DATE_TIME *timestamp); 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 #endif
+94 -37
View File
@@ -16,6 +16,7 @@
/* BACnet Stack API */ /* BACnet Stack API */
#include "bacnet/apdu.h" #include "bacnet/apdu.h"
#include "bacnet/basic/services.h" #include "bacnet/basic/services.h"
#include "bacnet/basic/sys/debug.h"
#include "bacnet/basic/tsm/tsm.h" #include "bacnet/basic/tsm/tsm.h"
#include "bacnet/basic/bbmd/h_bbmd.h" #include "bacnet/basic/bbmd/h_bbmd.h"
#include "bacnet/basic/object/netport.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); 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 #ifdef BACDL_BSC
BACNET_SC_UUID uuid = { 0 }; BACNET_SC_UUID uuid = { 0 };
@@ -629,6 +649,8 @@ static void bacnet_secure_connect_network_port_init(uint32_t instance)
char *hub_binding; char *hub_binding;
char *direct_connect_initiate; char *direct_connect_initiate;
char *direct_connect_accept_urls; char *direct_connect_accept_urls;
uint32_t file_instance;
char c;
primary_hub_uri = getenv("BACNET_SC_PRIMARY_HUB_URI"); primary_hub_uri = getenv("BACNET_SC_PRIMARY_HUB_URI");
failover_hub_uri = getenv("BACNET_SC_FAILOVER_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 */ /* SC parameters */
#ifdef BACDL_BSC #ifdef BACDL_BSC
if (!bsc_cert_files_check()) {
exit(1);
}
bsc_generate_random_uuid(&uuid); bsc_generate_random_uuid(&uuid);
Network_Port_SC_Local_UUID_Set(instance, (BACNET_UUID *)&uuid); Network_Port_SC_Local_UUID_Set(instance, (BACNET_UUID *)&uuid);
bsc_generate_random_vmac(&vmac); 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); instance, SC_NETPORT_DISCONNECT_TIMEOUT);
Network_Port_SC_Maximum_Reconnect_Time_Set( Network_Port_SC_Maximum_Reconnect_Time_Set(
instance, SC_NETPORT_RECONNECT_TIME); instance, SC_NETPORT_RECONNECT_TIME);
if (filename_ca_1_cert == NULL) { if (filename_ca_1_cert == NULL) {
fprintf(stderr, "BACNET_SC_ISSUER_1_CERTIFICATE_FILE must be set\n"); fprintf(stderr, "BACNET_SC_ISSUER_1_CERTIFICATE_FILE must be set\n");
return; 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( bacfile_pathname_set(
BSC_ISSUER_CERTIFICATE_FILE_1_INSTANCE, filename_ca_1_cert); 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( Network_Port_Issuer_Certificate_File_Set(
instance, 0, BSC_ISSUER_CERTIFICATE_FILE_1_INSTANCE); instance, 0, BSC_ISSUER_CERTIFICATE_FILE_1_INSTANCE);
if (filename_ca_2_cert) { 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( bacfile_pathname_set(
BSC_ISSUER_CERTIFICATE_FILE_2_INSTANCE, filename_ca_2_cert); 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( Network_Port_Issuer_Certificate_File_Set(
instance, 1, BSC_ISSUER_CERTIFICATE_FILE_2_INSTANCE); 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"); fprintf(stderr, "BACNET_SC_OPERATIONAL_CERTIFICATE_FILE must be set\n");
return; 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( bacfile_pathname_set(
BSC_OPERATIONAL_CERTIFICATE_FILE_INSTANCE, filename_cert); 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( Network_Port_Operational_Certificate_File_Set(
instance, BSC_OPERATIONAL_CERTIFICATE_FILE_INSTANCE); 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"); "BACNET_SC_OPERATIONAL_CERTIFICATE_PRIVATE_KEY_FILE must be set\n");
return; return;
} }
file_instance =
bacfile_create(BSC_CERTIFICATE_SIGNING_REQUEST_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( bacfile_pathname_set(
BSC_CERTIFICATE_SIGNING_REQUEST_FILE_INSTANCE, filename_key); 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( Network_Port_Certificate_Key_File_Set(
instance, BSC_CERTIFICATE_SIGNING_REQUEST_FILE_INSTANCE); 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"); "BACNET_SC_DIRECT_CONNECT_BINDING for direct connect.\n");
return; return;
} }
Network_Port_SC_Primary_Hub_URI_Set(instance, primary_hub_uri); 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_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( Network_Port_SC_Direct_Connect_Accept_Enable_Set(
instance, direct_binding != NULL); instance, direct_binding != NULL);
char c;
c = direct_connect_initiate ? direct_connect_initiate[0] : '0'; c = direct_connect_initiate ? direct_connect_initiate[0] : '0';
if ((c != '0') && (c != 'n') && (c != 'N')) { if ((c != '0') && (c != 'n') && (c != 'N')) {
Network_Port_SC_Direct_Connect_Initiate_Enable_Set(instance, true); 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 /* last thing - clear pending changes - we don't want to set these
since they are already set */ since they are already set */
Network_Port_Changes_Pending_Set(instance, false); Network_Port_Changes_Pending_Set(instance, false);
}
#if defined(BACDL_BSC) #if defined(BACDL_BSC)
static bool dlenv_hub_connection_status_check(void) if (!bsc_cert_files_check(instance)) {
{ debug_printf_stderr("BSC Certificate files missing.\n");
uint32_t instance = Network_Port_Index_To_Instance(0); exit(1);
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 #endif
}
/** void bsc_register_as_node(uint32_t instance)
* Datalink network port object settings for BACnet/SC
*/
void dlenv_network_port_bsc_init(void)
{ {
#if defined(BACDL_BSC) #if defined(BACDL_BSC)
/* if a user has configured BACnet/SC port with primary hub URI, */ /* 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 */ /* wait for a establishing of a connection to BACnet/SC hub at first */
/* to reduce possibility of packet losses. */ /* to reduce possibility of packet losses. */
if (Network_Port_SC_Primary_Hub_URI_char(1)) { if (Network_Port_SC_Primary_Hub_URI_char(instance)) {
while (!dlenv_hub_connection_status_check()) { debug_printf_stderr("Waiting for a BACnet/SC connection to hub...\n");
while (!dlenv_hub_connection_status_check(instance)) {
bsc_wait(1); bsc_wait(1);
bsc_maintenance_timer(1); bsc_maintenance_timer(1);
} }
debug_printf_stderr("Connected to a BACnet/SC hub!\n");
} }
#else
(void)instance;
#endif #endif
} }
@@ -929,6 +978,9 @@ void dlenv_init(void)
char *pEnv = NULL; char *pEnv = NULL;
uint8_t port_type = PORT_TYPE_BIP; uint8_t port_type = PORT_TYPE_BIP;
if (getenv("BACNET_DATALINK_DEBUG")) {
dlenv_debug_enable();
}
#if defined(BACDL_MULTIPLE) #if defined(BACDL_MULTIPLE)
pEnv = getenv("BACNET_DATALINK"); pEnv = getenv("BACNET_DATALINK");
if (pEnv) { if (pEnv) {
@@ -999,6 +1051,9 @@ void dlenv_init(void)
#if defined(BACFILE) #if defined(BACFILE)
/* initialize the POSIX file objects */ /* initialize the POSIX file objects */
bacfile_posix_init(); bacfile_posix_init();
if (Datalink_Debug) {
debug_printf_stderr("POSIX file services initialized.\n");
}
#endif #endif
/* === Initialize the Network Port Object Here === */ /* === Initialize the Network Port Object Here === */
Network_Port_Type_Set(Network_Port_Instance, port_type); 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); dlenv_network_port_zigbee_init(Network_Port_Instance);
break; break;
case PORT_TYPE_BSC: case PORT_TYPE_BSC:
dlenv_network_port_bsc_init(); dlenv_network_port_bsc_init(Network_Port_Instance);
bacnet_secure_connect_network_port_init(Network_Port_Instance);
break; break;
default: default:
break; break;
@@ -1034,7 +1088,7 @@ void dlenv_init(void)
if (pEnv) { if (pEnv) {
apdu_retries_set((uint8_t)strtol(pEnv, NULL, 0)); apdu_retries_set((uint8_t)strtol(pEnv, NULL, 0));
} }
/* === Initialize the Datalink Here === */ /* === INIT - Initialize the Datalink Here === */
pEnv = getenv("BACNET_IFACE"); pEnv = getenv("BACNET_IFACE");
if (Datalink_Debug) { if (Datalink_Debug) {
fprintf(stderr, "BACNET_IFACE=%s\n", pEnv ? pEnv : "none"); fprintf(stderr, "BACNET_IFACE=%s\n", pEnv ? pEnv : "none");
@@ -1042,6 +1096,7 @@ void dlenv_init(void)
if (!datalink_init(pEnv)) { if (!datalink_init(pEnv)) {
exit(1); exit(1);
} }
/* === POST INIT - After the Datalink is Initialized === */
#if (MAX_TSM_TRANSACTIONS) #if (MAX_TSM_TRANSACTIONS)
pEnv = getenv("BACNET_INVOKE_ID"); pEnv = getenv("BACNET_INVOKE_ID");
if (pEnv) { if (pEnv) {
@@ -1052,5 +1107,7 @@ void dlenv_init(void)
bbmd_register_as_foreign_device(); bbmd_register_as_foreign_device();
} else if (port_type == PORT_TYPE_BIP6) { } else if (port_type == PORT_TYPE_BIP6) {
bbmd6_register_as_foreign_device(); bbmd6_register_as_foreign_device();
} else if (port_type == PORT_TYPE_BSC) {
bsc_register_as_node(Network_Port_Instance);
} }
} }
@@ -35,6 +35,7 @@ add_compile_definitions(
BACNET_SC_DIRECT_ACCEPT_URI_MAX=6 BACNET_SC_DIRECT_ACCEPT_URI_MAX=6
MAX_TSM_TRANSACTIONS=0 MAX_TSM_TRANSACTIONS=0
BSC_CONF_TX_PRE=0 BSC_CONF_TX_PRE=0
BACFILE=1
) )
include_directories( include_directories(
+2 -2
View File
@@ -10169,7 +10169,7 @@ static void test_sc_datalink(void)
init_node_ev(&node_ev2); init_node_ev(&node_ev2);
init_node_ev(&node_ev3); 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), true, NULL);
zassert_equal(bsc_init(NULL), false, NULL); zassert_equal(bsc_init(NULL), false, NULL);
memset(broadcast, 0xFF, sizeof(broadcast)); 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_ev2);
init_node_ev(&node_ev3); init_node_ev(&node_ev3);
init_node_ev(&node_ev4); 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); zassert_equal(bsc_init(NULL), true, NULL);
conf2.ca_cert_chain = ca_cert; conf2.ca_cert_chain = ca_cert;