From 80875add0a376fe5a0bc5fe745c5fbf9e3aca702 Mon Sep 17 00:00:00 2001 From: Steve Karg Date: Tue, 3 Jun 2025 19:49:03 -0500 Subject: [PATCH] Fixed BACnet/IP initialization on a network interface where the system reports the interface's unicast IP address as being the same. (#1011) --- CHANGELOG.md | 3 +++ Makefile | 2 +- ports/bsd/bip-init.c | 32 ++++++++++++++++++++++++-------- ports/linux/bip-init.c | 33 +++++++++++++++++++++++++-------- ports/win32/bip-init.c | 35 ++++++++++++++++++++++++++--------- 5 files changed, 79 insertions(+), 26 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0cf2500f..d8c7a293 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -46,6 +46,9 @@ The git repositories are hosted at the following sites: ### Fixed +* Fixed BACnet/IP initialization on a network interface where the system + reports the interface's unicast IP address as being the same as its + broadcast IP address (e.g., utunX interfaces for VPNs on macOS). (#1011) * Fixed ports/xplained conversion of double warning. (#1004) * Fixed BACNET_USE_DOUBLE usage in AVR ports. (#1004) * Fixed integer out-of-range in AVR port. (#1004) diff --git a/Makefile b/Makefile index f92d3da6..cdf5bef0 100644 --- a/Makefile +++ b/Makefile @@ -24,7 +24,7 @@ mingw32: ORIGINAL_LD=$(LD) ; \ export CC=i686-w64-mingw32-gcc ; \ export LD=i686-w64-mingw32-ld ; \ - $(MAKE) BACNET_PORT=win32 -s -C apps all ; \ + $(MAKE) BACNET_PORT=win32 LEGACY=true -s -C apps all ; \ export CC=$(ORIGINAL_CC) ; \ export LD=$(ORIGINAL_LD) diff --git a/ports/bsd/bip-init.c b/ports/bsd/bip-init.c index d0b17bfe..d284a6ae 100644 --- a/ports/bsd/bip-init.c +++ b/ports/bsd/bip-init.c @@ -693,6 +693,8 @@ bool bip_init(char *ifname) { struct sockaddr_in sin; int sock_fd = -1; + struct sockaddr_in broadcast_sin_config; + int broadcast_sock_fd; if (ifname) { snprintf(BIP_Interface_Name, sizeof(BIP_Interface_Name), "%s", ifname); @@ -718,21 +720,35 @@ bool bip_init(char *ifname) if (sock_fd < 0) { return false; } + + broadcast_sin_config.sin_family = AF_INET; + broadcast_sin_config.sin_port = BIP_Port; + memset(&(broadcast_sin_config.sin_zero), '\0', + sizeof(broadcast_sin_config.sin_zero)); if (BIP_Broadcast_Binding_Address_Override) { - sin.sin_addr.s_addr = BIP_Broadcast_Binding_Address.s_addr; + broadcast_sin_config.sin_addr.s_addr = + BIP_Broadcast_Binding_Address.s_addr; } else { #if defined(BACNET_IP_BROADCAST_USE_INADDR_ANY) - sin.sin_addr.s_addr = htonl(INADDR_ANY); + broadcast_sin_config.sin_addr.s_addr = htonl(INADDR_ANY); #elif defined(BACNET_IP_BROADCAST_USE_INADDR_BROADCAST) - sin.sin_addr.s_addr = htonl(INADDR_BROADCAST); + broadcast_sin_config.sin_addr.s_addr = htonl(INADDR_BROADCAST); #else - sin.sin_addr.s_addr = BIP_Broadcast_Addr.s_addr; + broadcast_sin_config.sin_addr.s_addr = BIP_Broadcast_Addr.s_addr; #endif } - sock_fd = createSocket(&sin); - BIP_Broadcast_Socket = sock_fd; - if (sock_fd < 0) { - return false; + if (broadcast_sin_config.sin_addr.s_addr == BIP_Address.s_addr) { + /* handle the case when a network interface on the system + reports the interface's unicast IP address as being + the same as its broadcast IP address */ + BIP_Broadcast_Socket = BIP_Socket; + } else { + broadcast_sock_fd = createSocket(&broadcast_sin_config); + BIP_Broadcast_Socket = broadcast_sock_fd; + if (broadcast_sock_fd < 0) { + bip_cleanup(); + return false; + } } bvlc_init(); diff --git a/ports/linux/bip-init.c b/ports/linux/bip-init.c index 182112f5..cdd10b93 100644 --- a/ports/linux/bip-init.c +++ b/ports/linux/bip-init.c @@ -885,6 +885,8 @@ bool bip_init(char *ifname) { struct sockaddr_in sin; int sock_fd = -1; + struct sockaddr_in broadcast_sin_config; + int broadcast_sock_fd; if (ifname) { snprintf(BIP_Interface_Name, sizeof(BIP_Interface_Name), "%s", ifname); @@ -910,21 +912,36 @@ bool bip_init(char *ifname) if (sock_fd < 0) { return false; } + + broadcast_sin_config.sin_family = AF_INET; + broadcast_sin_config.sin_port = BIP_Port; + memset( + &(broadcast_sin_config.sin_zero), '\0', + sizeof(broadcast_sin_config.sin_zero)); if (BIP_Broadcast_Binding_Address_Override) { - sin.sin_addr.s_addr = BIP_Broadcast_Binding_Address.s_addr; + broadcast_sin_config.sin_addr.s_addr = + BIP_Broadcast_Binding_Address.s_addr; } else { #if defined(BACNET_IP_BROADCAST_USE_INADDR_ANY) - sin.sin_addr.s_addr = htonl(INADDR_ANY); + broadcast_sin_config.sin_addr.s_addr = htonl(INADDR_ANY); #elif defined(BACNET_IP_BROADCAST_USE_INADDR_BROADCAST) - sin.sin_addr.s_addr = htonl(INADDR_BROADCAST); + broadcast_sin_config.sin_addr.s_addr = htonl(INADDR_BROADCAST); #else - sin.sin_addr.s_addr = BIP_Broadcast_Addr.s_addr; + broadcast_sin_config.sin_addr.s_addr = BIP_Broadcast_Addr.s_addr; #endif } - sock_fd = createSocket(&sin); - BIP_Broadcast_Socket = sock_fd; - if (sock_fd < 0) { - return false; + if (broadcast_sin_config.sin_addr.s_addr == BIP_Address.s_addr) { + /* handle the case when a network interface on the system + reports the interface's unicast IP address as being + the same as its broadcast IP address */ + BIP_Broadcast_Socket = BIP_Socket; + } else { + broadcast_sock_fd = createSocket(&broadcast_sin_config); + BIP_Broadcast_Socket = broadcast_sock_fd; + if (broadcast_sock_fd < 0) { + bip_cleanup(); + return false; + } } bvlc_init(); diff --git a/ports/win32/bip-init.c b/ports/win32/bip-init.c index 9b4c8d92..7329cabb 100644 --- a/ports/win32/bip-init.c +++ b/ports/win32/bip-init.c @@ -822,6 +822,8 @@ bool bip_init(char *ifname) { struct sockaddr_in sin; SOCKET sock_fd = INVALID_SOCKET; + struct sockaddr_in broadcast_sin_config; + SOCKET broadcast_sock_fd = INVALID_SOCKET; bip_init_windows(); if (ifname) { @@ -859,29 +861,44 @@ bool bip_init(char *ifname) sock_fd = createSocket(&sin); BIP_Socket = sock_fd; if (sock_fd == INVALID_SOCKET) { + bip_cleanup(); return false; } + broadcast_sin_config.sin_family = AF_INET; + broadcast_sin_config.sin_port = BIP_Port; + memset( + &(broadcast_sin_config.sin_zero), '\0', + sizeof(broadcast_sin_config.sin_zero)); if (BIP_Broadcast_Binding_Address_Override) { sin.sin_addr.s_addr = BIP_Broadcast_Binding_Address.s_addr; } else { #if defined(BACNET_IP_BROADCAST_USE_INADDR_ANY) - sin.sin_addr.s_addr = htonl(INADDR_ANY); + broadcast_sin_config.sin_addr.s_addr = htonl(INADDR_ANY); #elif defined(BACNET_IP_BROADCAST_USE_INADDR_BROADCAST) - sin.sin_addr.s_addr = htonl(INADDR_BROADCAST); + broadcast_sin_config.sin_addr.s_addr = htonl(INADDR_BROADCAST); #else - sin.sin_addr.s_addr = BIP_Address.s_addr; + broadcast_sin_config.sin_addr.s_addr = BIP_Address.s_addr; #endif } if (BIP_Debug) { fprintf( - stderr, "BIP: broadcast bind %s:%hu\n", inet_ntoa(sin.sin_addr), - ntohs(sin.sin_port)); + stderr, "BIP: broadcast bind %s:%hu\n", + inet_ntoa(broadcast_sin_config.sin_addr), + ntohs(broadcast_sin_config.sin_port)); fflush(stderr); } - sock_fd = createSocket(&sin); - BIP_Broadcast_Socket = sock_fd; - if (sock_fd == INVALID_SOCKET) { - return false; + if (broadcast_sin_config.sin_addr.s_addr == BIP_Address.s_addr) { + /* handle the case when a network interface on the system + reports the interface's unicast IP address as being + the same as its broadcast IP address */ + BIP_Broadcast_Socket = BIP_Socket; + } else { + broadcast_sock_fd = createSocket(&broadcast_sin_config); + BIP_Broadcast_Socket = broadcast_sock_fd; + if (broadcast_sock_fd == INVALID_SOCKET) { + bip_cleanup(); + return false; + } } bvlc_init();