BIP: add option - listen to broadcast on a separate socket (#293)

* BIP: add socket to listen to broadcast packets for Linux/Windows/BSD/Zephyr

* BIP: added BVLC broadcast handler to drop a packet when confirmed broadcast request is sent.

* https://sourceforge.net/p/bacnet/bugs/65/
This commit is contained in:
Mikhail Antropov
2022-07-01 17:48:41 +03:00
committed by GitHub
parent 1a76db015b
commit 144017f861
9 changed files with 324 additions and 185 deletions
-1
View File
@@ -13,7 +13,6 @@ BACDL_BIP=1 - chooses BACnet/IP for the datalink layer
BACDL_ETHERNET=0 - chooses BACnet Ethernet for the datalink layer
BACDL_ARCNET=0 - chooses BACnet ARCNET for the datalink layer
BACDL_MSTP=0 - chooses BACnet MS/TP for the datalink layer
USE_INADDR=1 - uses INADDR_BROADCAST for broadcast rather than CLASSx
TSM_ENABLED=1 - enables the Transaction State Machine for clients
BIP_DEBUG=1 - enables print statements for debugging
In Visual C++, add a Preprocessor Definition by:
+73 -36
View File
@@ -47,8 +47,9 @@
* @brief Initializes BACnet/IP interface (BSD/MAC OS X).
*/
/* unix socket */
/* unix sockets */
static int BIP_Socket = -1;
static int BIP_Broadcast_Socket = -1;
/* NOTE: we store address and port in network byte order
since BACnet/IP uses network byte order for all address byte arrays
@@ -315,6 +316,7 @@ uint16_t bip_receive(
int received_bytes = 0;
int offset = 0;
uint16_t i = 0;
int socket;
/* Make sure the socket is open */
if (BIP_Socket < 0) {
@@ -333,10 +335,15 @@ uint16_t bip_receive(
}
FD_ZERO(&read_fds);
FD_SET(BIP_Socket, &read_fds);
max = BIP_Socket;
FD_SET(BIP_Broadcast_Socket, &read_fds);
max = BIP_Socket > BIP_Broadcast_Socket ? BIP_Socket : BIP_Broadcast_Socket;
/* see if there is a packet for us */
if (select(max + 1, &read_fds, NULL, NULL, &select_timeout) > 0) {
received_bytes = recvfrom(max, (char *)&npdu[0], max_npdu, 0,
socket = FD_ISSET(BIP_Socket, &read_fds) ? BIP_Socket :
BIP_Broadcast_Socket;
received_bytes = recvfrom(socket, (char *)&npdu[0], max_npdu, 0,
(struct sockaddr *)&sin, &sin_len);
} else {
return 0;
@@ -374,7 +381,9 @@ uint16_t bip_receive(
debug_print_ipv4(
"Received MPDU->", &sin.sin_addr, sin.sin_port, received_bytes);
/* pass the packet into the BBMD handler */
offset = bvlc_handler(&addr, src, npdu, received_bytes);
offset = socket == BIP_Socket ?
bvlc_handler(&addr, src, npdu, received_bytes) :
bvlc_broadcast_handler(&addr, src, npdu, received_bytes);
if (offset > 0) {
npdu_len = received_bytes - offset;
debug_print_ipv4(
@@ -556,6 +565,45 @@ void bip_set_interface(char *ifname)
}
}
static int createSocket(struct sockaddr_in *sin)
{
int status = 0; /* return from socket lib calls */
int sockopt = 0;
int sock_fd = -1;
/* assumes that the driver has already been initialized */
sock_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (sock_fd < 0) {
return sock_fd;
}
/* Allow us to use the same socket for sending and receiving */
/* This makes sure that the src port is correct when sending */
sockopt = 1;
status = setsockopt(
sock_fd, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof(sockopt));
if (status < 0) {
close(sock_fd);
return status;
}
/* allow us to send a broadcast */
status = setsockopt(
sock_fd, SOL_SOCKET, SO_BROADCAST, &sockopt, sizeof(sockopt));
if (status < 0) {
close(sock_fd);
return status;
}
/* bind the socket to the local port number and IP address */
status =
bind(sock_fd, (const struct sockaddr *)sin, sizeof(struct sockaddr));
if (status < 0) {
close(sock_fd);
return status;
}
return sock_fd;
}
/** Initialize the BACnet/IP services at the given interface.
* @ingroup DLBIP
* -# Gets the local IP address and local broadcast address from the system,
@@ -575,9 +623,7 @@ void bip_set_interface(char *ifname)
*/
bool bip_init(char *ifname)
{
int status = 0; /* return from socket lib calls */
struct sockaddr_in sin;
int sockopt = 0;
int sock_fd = -1;
if (ifname) {
@@ -586,42 +632,28 @@ bool bip_init(char *ifname)
} else {
bip_set_interface("en0");
}
/* assumes that the driver has already been initialized */
sock_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
BIP_Socket = sock_fd;
if (sock_fd < 0)
return false;
/* Allow us to use the same socket for sending and receiving */
/* This makes sure that the src port is correct when sending */
sockopt = 1;
status = setsockopt(
sock_fd, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof(sockopt));
if (status < 0) {
close(sock_fd);
BIP_Socket = -1;
return status;
}
/* allow us to send a broadcast */
status = setsockopt(
sock_fd, SOL_SOCKET, SO_BROADCAST, &sockopt, sizeof(sockopt));
if (status < 0) {
close(sock_fd);
BIP_Socket = -1;
return false;
}
/* bind the socket to the local port number and IP address */
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = htonl(INADDR_ANY);
sin.sin_port = BIP_Port;
memset(&(sin.sin_zero), '\0', sizeof(sin.sin_zero));
status =
bind(sock_fd, (const struct sockaddr *)&sin, sizeof(struct sockaddr));
if (status < 0) {
close(sock_fd);
BIP_Socket = -1;
sin.sin_addr.s_addr = BIP_Address.s_addr;
sock_fd = createSocket(&sin);
BIP_Socket = sock_fd;
if (sock_fd < 0) {
return false;
}
sin.sin_addr.s_addr = htonl(INADDR_ANY);
sock_fd = createSocket(&sin);
BIP_Broadcast_Socket = sock_fd;
if (sock_fd < 0) {
return false;
}
bvlc_init();
return true;
}
@@ -646,5 +678,10 @@ void bip_cleanup(void)
}
BIP_Socket = -1;
if (BIP_Broadcast_Socket != -1) {
close(BIP_Broadcast_Socket);
}
BIP_Broadcast_Socket = -1;
return;
}
-1
View File
@@ -111,5 +111,4 @@ extern int bip_get_local_address_ioctl(
char *ifname,
struct in_addr *addr,
int request);
#endif
+72 -38
View File
@@ -59,8 +59,9 @@
/** @file linux/bip-init.c Initializes BACnet/IP interface (Linux). */
/* unix socket */
/* unix sockets */
static int BIP_Socket = -1;
static int BIP_Broadcast_Socket = -1;
/* NOTE: we store address and port in network byte order
since BACnet/IP uses network byte order for all address byte arrays
@@ -331,6 +332,7 @@ uint16_t bip_receive(
int received_bytes = 0;
int offset = 0;
uint16_t i = 0;
int socket;
/* Make sure the socket is open */
if (BIP_Socket < 0) {
@@ -349,10 +351,15 @@ uint16_t bip_receive(
}
FD_ZERO(&read_fds);
FD_SET(BIP_Socket, &read_fds);
max = BIP_Socket;
FD_SET(BIP_Broadcast_Socket, &read_fds);
max = BIP_Socket > BIP_Broadcast_Socket ? BIP_Socket : BIP_Broadcast_Socket;
/* see if there is a packet for us */
if (select(max + 1, &read_fds, NULL, NULL, &select_timeout) > 0) {
received_bytes = recvfrom(max, (char *)&npdu[0], max_npdu, 0,
socket = FD_ISSET(BIP_Socket, &read_fds) ? BIP_Socket :
BIP_Broadcast_Socket;
received_bytes = recvfrom(socket, (char *)&npdu[0], max_npdu, 0,
(struct sockaddr *)&sin, &sin_len);
} else {
return 0;
@@ -390,7 +397,9 @@ uint16_t bip_receive(
debug_print_ipv4(
"Received MPDU->", &sin.sin_addr, sin.sin_port, received_bytes);
/* pass the packet into the BBMD handler */
offset = bvlc_handler(&addr, src, npdu, received_bytes);
offset = socket == BIP_Socket ?
bvlc_handler(&addr, src, npdu, received_bytes) :
bvlc_broadcast_handler(&addr, src, npdu, received_bytes);
if (offset > 0) {
npdu_len = received_bytes - offset;
debug_print_ipv4(
@@ -736,6 +745,7 @@ void bip_set_interface(char *ifname)
{
struct in_addr local_address;
struct in_addr netmask;
short flags;
int rv = 0;
/* setup local address */
@@ -766,6 +776,48 @@ void bip_set_interface(char *ifname)
}
}
static int createSocket(struct sockaddr_in *sin)
{
int status = 0; /* return from socket lib calls */
int sockopt = 0;
int sock_fd = -1;
/* assumes that the driver has already been initialized */
sock_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (sock_fd < 0) {
return sock_fd;
}
/* Allow us to use the same socket for sending and receiving */
/* This makes sure that the src port is correct when sending */
sockopt = 1;
status = setsockopt(
sock_fd, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof(sockopt));
if (status < 0) {
close(sock_fd);
return status;
}
/* allow us to send a broadcast */
status = setsockopt(
sock_fd, SOL_SOCKET, SO_BROADCAST, &sockopt, sizeof(sockopt));
if (status < 0) {
close(sock_fd);
return status;
}
/* Bind to the proper interface to send without default gateway */
setsockopt(sock_fd, SOL_SOCKET, SO_BINDTODEVICE, BIP_Interface_Name,
strlen(BIP_Interface_Name));
/* bind the socket to the local port number and IP address */
status =
bind(sock_fd, (const struct sockaddr *)sin, sizeof(struct sockaddr));
if (status < 0) {
close(sock_fd);
return status;
}
return sock_fd;
}
/** Initialize the BACnet/IP services at the given interface.
* @ingroup DLBIP
* -# Gets the local IP address and local broadcast address from the system,
@@ -785,9 +837,7 @@ void bip_set_interface(char *ifname)
*/
bool bip_init(char *ifname)
{
int status = 0; /* return from socket lib calls */
struct sockaddr_in sin;
int sockopt = 0;
int sock_fd = -1;
if (ifname) {
@@ -802,46 +852,25 @@ bool bip_init(char *ifname)
fflush(stderr);
return false;
}
/* assumes that the driver has already been initialized */
sock_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
sin.sin_family = AF_INET;
sin.sin_port = BIP_Port;
memset(&(sin.sin_zero), '\0', sizeof(sin.sin_zero));
sin.sin_addr.s_addr = BIP_Address.s_addr;
sock_fd = createSocket(&sin);
BIP_Socket = sock_fd;
if (sock_fd < 0) {
return false;
}
/* Allow us to use the same socket for sending and receiving */
/* This makes sure that the src port is correct when sending */
sockopt = 1;
status = setsockopt(
sock_fd, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof(sockopt));
if (status < 0) {
close(sock_fd);
BIP_Socket = -1;
return status;
}
/* allow us to send a broadcast */
status = setsockopt(
sock_fd, SOL_SOCKET, SO_BROADCAST, &sockopt, sizeof(sockopt));
if (status < 0) {
close(sock_fd);
BIP_Socket = -1;
return false;
}
/* Bind to the proper interface to send without default gateway */
setsockopt(sock_fd, SOL_SOCKET, SO_BINDTODEVICE, BIP_Interface_Name,
sizeof(BIP_Interface_Name));
/* bind the socket to the local port number and IP address */
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = htonl(INADDR_ANY);
sin.sin_port = BIP_Port;
memset(&(sin.sin_zero), '\0', sizeof(sin.sin_zero));
status =
bind(sock_fd, (const struct sockaddr *)&sin, sizeof(struct sockaddr));
if (status < 0) {
close(sock_fd);
BIP_Socket = -1;
sock_fd = createSocket(&sin);
BIP_Broadcast_Socket = sock_fd;
if (sock_fd < 0) {
return false;
}
bvlc_init();
return true;
@@ -866,5 +895,10 @@ void bip_cleanup(void)
}
BIP_Socket = -1;
if (BIP_Broadcast_Socket != -1) {
close(BIP_Broadcast_Socket);
}
BIP_Broadcast_Socket = -1;
return;
}
+1 -2
View File
@@ -39,8 +39,7 @@
#endif
#include <windows.h>
#if (!defined(USE_INADDR) || (USE_INADDR == 0)) && \
(!defined(USE_CLASSADDR) || (USE_CLASSADDR == 0))
#if (!defined(USE_CLASSADDR) || (USE_CLASSADDR == 0))
#include <iphlpapi.h>
#if defined(_MSC_VER)
#pragma comment(lib, "IPHLPAPI.lib")
+82 -69
View File
@@ -45,16 +45,13 @@
#include "bacnet/basic/bbmd/h_bbmd.h"
#include "bacport.h"
/* alternate methods of choosing broadcast address */
#ifndef USE_INADDR
#define USE_INADDR 0
#endif
#ifndef USE_CLASSADDR
#define USE_CLASSADDR 0
#endif
/* Windows socket */
/* Windows sockets */
static SOCKET BIP_Socket = INVALID_SOCKET;
static SOCKET BIP_Broadcast_Socket = INVALID_SOCKET;
/* NOTE: we store address and port in network byte order
since BACnet/IP uses network byte order for all address byte arrays
@@ -482,6 +479,7 @@ uint16_t bip_receive(
int received_bytes = 0;
int offset = 0;
uint16_t i = 0;
SOCKET socket;
/* Make sure the socket is open */
if (BIP_Socket == INVALID_SOCKET) {
@@ -500,10 +498,15 @@ uint16_t bip_receive(
}
FD_ZERO(&read_fds);
FD_SET(BIP_Socket, &read_fds);
max = BIP_Socket;
FD_SET(BIP_Broadcast_Socket, &read_fds);
max = BIP_Socket > BIP_Broadcast_Socket ? BIP_Socket : BIP_Broadcast_Socket;
/* see if there is a packet for us */
if (select(max + 1, &read_fds, NULL, NULL, &select_timeout) > 0) {
received_bytes = recvfrom(max, (char *)&npdu[0], max_npdu, 0,
socket = FD_ISSET(BIP_Socket, &read_fds) ? BIP_Socket :
BIP_Broadcast_Socket;
received_bytes = recvfrom(socket, (char *)&npdu[0], max_npdu, 0,
(struct sockaddr *)&sin, &sin_len);
} else {
return 0;
@@ -541,7 +544,9 @@ uint16_t bip_receive(
debug_print_ipv4(
"Received MPDU->", &sin.sin_addr, sin.sin_port, received_bytes);
/* pass the packet into the BBMD handler */
offset = bvlc_handler(&addr, src, npdu, received_bytes);
offset = socket == BIP_Socket ?
bvlc_handler(&addr, src, npdu, received_bytes) :
bvlc_broadcast_handler(&addr, src, npdu, received_bytes);
if (offset > 0) {
npdu_len = received_bytes - offset;
if (npdu_len <= max_npdu) {
@@ -632,7 +637,7 @@ static long gethostaddr(void)
return *(long *)host_ent->h_addr;
}
#if ((USE_INADDR == 0) || (USE_CLASSADDR == 0))
#if (USE_CLASSADDR == 0)
/* returns the subnet mask in network byte order */
static uint32_t getIpMaskForIpAddress(uint32_t ipAddress)
{
@@ -679,12 +684,7 @@ static uint32_t getIpMaskForIpAddress(uint32_t ipAddress)
static void set_broadcast_address(uint32_t net_address)
{
#if USE_INADDR
/* Note: sometimes INADDR_BROADCAST does not let me get
any unicast messages. Not sure why... */
(void)net_address;
BIP_Broadcast_Address.s_addr = INADDR_BROADCAST;
#elif USE_CLASSADDR
#if USE_CLASSADDR
long broadcast_address = 0;
if (IN_CLASSA(ntohl(net_address)))
@@ -701,7 +701,7 @@ static void set_broadcast_address(uint32_t net_address)
(ntohl(net_address) & ~IN_CLASSD_HOST) | IN_CLASSD_HOST;
else
broadcast_address = INADDR_BROADCAST;
BIP_Broadcast_Address.s_addr = htonl(broadcast_address));
BIP_Broadcast_Address.s_addr = htonl(broadcast_address);
#else
/* these are network byte order variables */
long broadcast_address = 0;
@@ -728,7 +728,6 @@ static void set_broadcast_address(uint32_t net_address)
*/
void bip_set_interface(char *ifname)
{
bip_init_windows();
/* setup local address */
if (BIP_Address.s_addr == 0) {
BIP_Address.s_addr = inet_addr(ifname);
@@ -744,6 +743,45 @@ void bip_set_interface(char *ifname)
}
}
static int createSocket(struct sockaddr_in *sin)
{
int rv = 0; /* return from socket lib calls */
int value = 1;
SOCKET sock_fd = INVALID_SOCKET;
/* assumes that the driver has already been initialized */
sock_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (sock_fd < 0) {
print_last_error("failed to allocate a socket");
return sock_fd;
}
/* Allow us to use the same socket for sending and receiving */
/* This makes sure that the src port is correct when sending */
rv = setsockopt(
sock_fd, SOL_SOCKET, SO_REUSEADDR, (char *)&value, sizeof(value));
if (rv < 0) {
print_last_error("failed to set REUSEADDR socket option");
closesocket(sock_fd);
return rv;
}
/* Enables transmission and receipt of broadcast messages on the socket. */
rv = setsockopt(
sock_fd, SOL_SOCKET, SO_BROADCAST, (char *)&value, sizeof(value));
if (rv < 0) {
print_last_error("failed to set BROADCAST socket option");
closesocket(sock_fd);
return rv;
}
rv = bind(sock_fd, (const struct sockaddr *)sin, sizeof(struct sockaddr));
if (rv < 0) {
print_last_error("failed to bind");
closesocket(sock_fd);
return rv;
}
return sock_fd;
}
/** Initialize the BACnet/IP services at the given interface.
* @ingroup DLBIP
* -# Gets the local IP address and local broadcast address from the system,
@@ -763,9 +801,7 @@ void bip_set_interface(char *ifname)
*/
bool bip_init(char *ifname)
{
int rv = 0; /* return from socket lib calls */
struct sockaddr_in sin = { -1 };
int value = 1;
SOCKET sock_fd = INVALID_SOCKET;
bip_init_windows();
@@ -788,68 +824,38 @@ bool bip_init(char *ifname)
ntohs(BIP_Port));
fflush(stderr);
}
/* assumes that the driver has already been initialized */
sock_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
BIP_Socket = sock_fd;
if (sock_fd < 0) {
print_last_error("failed to allocate a socket");
return false;
}
/* Allow us to use the same socket for sending and receiving */
/* This makes sure that the src port is correct when sending */
rv = setsockopt(
sock_fd, SOL_SOCKET, SO_REUSEADDR, (char *)&value, sizeof(value));
if (rv < 0) {
print_last_error("failed to set REUSEADDR socket option");
closesocket(sock_fd);
BIP_Socket = INVALID_SOCKET;
return false;
}
/* Enables transmission and receipt of broadcast messages on the socket. */
rv = setsockopt(
sock_fd, SOL_SOCKET, SO_BROADCAST, (char *)&value, sizeof(value));
if (rv < 0) {
print_last_error("failed to set BROADCAST socket option");
closesocket(sock_fd);
BIP_Socket = INVALID_SOCKET;
return false;
}
/* bind the socket to the local port number and IP address */
sin.sin_family = AF_INET;
#if USE_INADDR
/* by setting sin.sin_addr.s_addr to INADDR_ANY,
I am telling the IP stack to automatically fill
in the IP address of the machine the process
is running on.
Some server computers have multiple IP addresses.
A socket bound to one of these will not accept
connections to another address. Frequently you prefer
to allow any one of the computer's IP addresses
to be used for connections. Use INADDR_ANY (0L) to
allow clients to connect using any one of the host's
IP addresses. */
sin.sin_addr.s_addr = htonl(INADDR_ANY);
#else
/* or we could use the specific adapter address
note: already in network byte order */
sin.sin_addr.s_addr = BIP_Address.s_addr;
#endif
sin.sin_port = BIP_Port;
memset(&(sin.sin_zero), '\0', sizeof(sin.sin_zero));
sin.sin_addr.s_addr = BIP_Address.s_addr;
if (BIP_Debug) {
fprintf(stderr, "BIP: bind %s:%hu\n", inet_ntoa(sin.sin_addr),
ntohs(sin.sin_port));
fflush(stderr);
}
rv = bind(sock_fd, (const struct sockaddr *)&sin, sizeof(struct sockaddr));
if (rv < 0) {
print_last_error("failed to bind");
closesocket(sock_fd);
BIP_Socket = INVALID_SOCKET;
sock_fd = createSocket(&sin);
BIP_Socket = sock_fd;
if (sock_fd < 0) {
return false;
}
sin.sin_addr.s_addr = htonl(INADDR_ANY);
if (BIP_Debug) {
fprintf(stderr, "BIP: broadcast bind %s:%hu\n", inet_ntoa(sin.sin_addr),
ntohs(sin.sin_port));
fflush(stderr);
}
sock_fd = createSocket(&sin);
BIP_Broadcast_Socket = sock_fd;
if (sock_fd < 0) {
return false;
}
bvlc_init();
return true;
}
@@ -874,6 +880,13 @@ void bip_cleanup(void)
closesocket(sock_fd);
}
BIP_Socket = INVALID_SOCKET;
if (BIP_Broadcast_Socket != INVALID_SOCKET) {
sock_fd = BIP_Broadcast_Socket;
closesocket(sock_fd);
}
BIP_Broadcast_Socket = INVALID_SOCKET;
WSACleanup();
return;
+64 -38
View File
@@ -55,8 +55,9 @@ LOG_MODULE_DECLARE(bacnet, CONFIG_BACNETSTACK_LOG_LEVEL);
#define THIS_FILE "bip-init.c"
/* zephyr socket */
/* zephyr sockets */
static int BIP_Socket = -1;
static int BIP_Broadcast_Socket = -1;
/* NOTE: we store address and port in network byte order
since BACnet/IP uses network byte order for all address byte arrays
@@ -320,6 +321,7 @@ uint16_t bip_receive(
int received_bytes = 0;
int offset = 0;
uint16_t i = 0;
int socket;
/* Make sure the socket is open */
if (BIP_Socket < 0) {
@@ -339,11 +341,15 @@ uint16_t bip_receive(
}
ZSOCK_FD_ZERO(&read_fds);
ZSOCK_FD_SET(BIP_Socket, &read_fds);
max = BIP_Socket;
FD_SET(BIP_Broadcast_Socket, &read_fds);
max = BIP_Socket > BIP_Broadcast_Socket ? BIP_Socket : BIP_Broadcast_Socket;
/* see if there is a packet for us */
if (zsock_select(max + 1, &read_fds, NULL, NULL, &select_timeout) > 0) {
received_bytes = zsock_recvfrom(BIP_Socket, (char *)&npdu[0], max_npdu,
socket = FD_ISSET(BIP_Socket, &read_fds) ? BIP_Socket :
BIP_Broadcast_Socket;
received_bytes = zsock_recvfrom(socket, (char *)&npdu[0], max_npdu,
0, (struct sockaddr *)&sin, &sin_len);
}
else
@@ -378,7 +384,9 @@ uint16_t bip_receive(
debug_print_ipv4("Received MPDU->", &sin.sin_addr, sin.sin_port,
received_bytes);
/* pass the packet into the BBMD handler */
offset = bvlc_handler(&addr, src, npdu, received_bytes);
offset = socket == BIP_Socket ?
bvlc_handler(&addr, src, npdu, received_bytes) :
bvlc_broadcast_handler(&addr, src, npdu, received_bytes);
if (offset > 0) {
npdu_len = received_bytes - offset;
debug_print_ipv4("Received NPDU->", &sin.sin_addr, sin.sin_port,
@@ -504,6 +512,48 @@ void bip_set_interface(char *ifname)
}
}
static int createSocket(struct sockaddr_in *sin)
{
int sock_fd = -1;
const int sockopt = 1;
int status = -1;
/* assumes that the driver has already been initialized */
sock_fd = zsock_socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (sock_fd < 0) {
LOG_ERR("%s:%d - Failed to create socket", THIS_FILE, __LINE__);
return sock_fd;
}
else
{
LOG_DBG("Socket created");
}
/* Allow us to use the same socket for sending and receiving */
/* This makes sure that the src port is correct when sending */
status = zsock_setsockopt(
sock_fd, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof(sockopt));
if (status < 0) {
zsock_close(sock_fd);
return status;
}
/* bind the socket to the local port number and IP address */
status =
zsock_bind(sock_fd, (const struct sockaddr *)sin, sizeof(struct sockaddr));
if (status < 0) {
zsock_close(sock_fd);
LOG_ERR("%s:%d - zsock_bind() failure", THIS_FILE, __LINE__);
return status;
}
else
{
LOG_DBG("Socket bound");
}
return sock_fd;
}
/** Initialize the BACnet/IP services at the given interface.
* @ingroup DLBIP
* -# Gets the local IP address and local broadcast address from the system,
@@ -523,8 +573,6 @@ void bip_set_interface(char *ifname)
*/
bool bip_init(char *ifname)
{
int sock_fd = -1;
const int sockopt = 1;
int status = -1;
struct sockaddr_in sin = { 0 };
@@ -535,44 +583,22 @@ bool bip_init(char *ifname)
return false;
}
/* assumes that the driver has already been initialized */
sock_fd = zsock_socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
BIP_Socket = sock_fd;
if (sock_fd < 0) {
LOG_ERR("%s:%d - Failed to create socket", THIS_FILE, __LINE__);
return false;
}
else
{
LOG_DBG("Socket created");
}
/* Allow us to use the same socket for sending and receiving */
/* This makes sure that the src port is correct when sending */
status = zsock_setsockopt(
sock_fd, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof(sockopt));
if (status < 0) {
zsock_close(sock_fd);
BIP_Socket = -1;
return false;
}
/* bind the socket to the local port number and IP address */
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = htonl(INADDR_ANY);
sin.sin_port = BIP_Port;
status =
zsock_bind(sock_fd, (const struct sockaddr *)&sin, sizeof(struct sockaddr));
if (status < 0) {
zsock_close(sock_fd);
BIP_Socket = -1;
LOG_ERR("%s:%d - zsock_bind() failure", THIS_FILE, __LINE__);
sin.sin_addr.s_addr = BIP_Address.s_addr;
sock_fd = createSocket(&sin);
BIP_Socket = sock_fd;
if (sock_fd < 0) {
return false;
}
else
{
LOG_DBG("Socket bound");
sin.sin_addr.s_addr = htonl(INADDR_ANY);
sock_fd = createSocket(&sin);
BIP_Broadcast_Socket = sock_fd;
if (sock_fd < 0) {
return false;
}
bvlc_init();
+26
View File
@@ -1159,6 +1159,32 @@ int bvlc_handler(BACNET_IP_ADDRESS *addr,
#endif
}
int bvlc_broadcast_handler(BACNET_IP_ADDRESS *addr,
BACNET_ADDRESS *src,
uint8_t *npdu,
uint16_t npdu_len)
{
int offset = 0;
uint8_t message_type = 0;
uint16_t message_length = 0;
int header_len = 0;
header_len =
bvlc_decode_header(npdu, npdu_len, &message_type, &message_length);
if (header_len == 4) {
switch (message_type) {
case BVLC_ORIGINAL_UNICAST_NPDU:
/* drop unicast when sent as a broadcast */
break;
default:
offset = bvlc_handler(addr, src, npdu, npdu_len);
break;
}
}
return offset;
}
#if BBMD_CLIENT_ENABLED
/** Register as a foreign device with the indicated BBMD.
* @param bbmd_addr - IPv4 address of BBMD with which to register
+6
View File
@@ -47,6 +47,12 @@ int bvlc_handler(BACNET_IP_ADDRESS *addr,
uint8_t *npdu,
uint16_t npdu_len);
BACNET_STACK_EXPORT
int bvlc_broadcast_handler(BACNET_IP_ADDRESS *addr,
BACNET_ADDRESS *src,
uint8_t *npdu,
uint16_t npdu_len);
BACNET_STACK_EXPORT
int bvlc_bbmd_enabled_handler(BACNET_IP_ADDRESS *addr,
BACNET_ADDRESS *src,