Feature/bacnet ipv6 foreign device registration (#355)

* Added IPv6 Foreign Device Registration for apps

* Fix debug message in BACnet/IPv6 Linux port

Co-authored-by: Steve Karg <skarg@users.sourceforge.net>
This commit is contained in:
Steve Karg
2022-11-17 08:14:33 -06:00
committed by GitHub
parent 27d368e0e8
commit 70c290d1ad
5 changed files with 150 additions and 21 deletions
+16 -1
View File
@@ -422,7 +422,7 @@ bool bip6_init(char *ifname)
if (BIP6_Addr.port == 0) {
bip6_set_port(0xBAC0U);
}
PRINTF("BIP6: IPv6 UDP port: 0x%04X\n", htons(BIP6_Addr.port));
PRINTF("BIP6: IPv6 UDP port: 0x%04X\n", BIP6_Addr.port);
if (BIP6_Broadcast_Addr.address[0] == 0) {
bvlc6_address_set(&BIP6_Broadcast_Addr, BIP6_MULTICAST_SITE_LOCAL, 0, 0,
0, 0, 0, 0, BIP6_MULTICAST_GROUP_ID);
@@ -464,8 +464,23 @@ bool bip6_init(char *ifname)
/* bind the socket to the local port number and IP address */
server.sin6_family = AF_INET6;
#if 0
uint16_t addr16[8];
bvlc6_address_get(&BIP6_Addr, &addr16[0], &addr16[1], &addr16[2],
&addr16[3], &addr16[4], &addr16[5], &addr16[6], &addr16[7]);
server.sin6_addr.s6_addr16[0] = htons(addr16[0]);
server.sin6_addr.s6_addr16[1] = htons(addr16[1]);
server.sin6_addr.s6_addr16[2] = htons(addr16[2]);
server.sin6_addr.s6_addr16[3] = htons(addr16[3]);
server.sin6_addr.s6_addr16[4] = htons(addr16[4]);
server.sin6_addr.s6_addr16[5] = htons(addr16[5]);
server.sin6_addr.s6_addr16[6] = htons(addr16[6]);
server.sin6_addr.s6_addr16[7] = htons(addr16[7]);
#else
server.sin6_addr = in6addr_any;
#endif
server.sin6_port = htons(BIP6_Addr.port);
debug_print_ipv6("Binding->", &server.sin6_addr);
status = bind(BIP6_Socket, (const void *)&server, sizeof(server));
if (status < 0) {
perror("BIP: bind");
+1 -7
View File
@@ -113,7 +113,6 @@ void bip6_set_interface(char *ifname)
int i, RetVal;
struct addrinfo Hints, *AddrInfo, *AI;
struct sockaddr_in6 *sin;
struct sockaddr_in6 server = {};
struct in6_addr broadcast_address = {};
struct ipv6_mreq join_request = {};
SOCKET ServSock[FD_SETSIZE] = {};
@@ -224,12 +223,7 @@ void bip6_set_interface(char *ifname)
// the application is a server that has a well-known port
// that clients know about in advance.
//
memset(&server, 0, sizeof(server));
server.sin6_family = AF_INET6;
server.sin6_port = htons(BIP6_Addr.port);
server.sin6_addr = in6addr_any;
if (bind(BIP6_Socket, (struct sockaddr *)&server, sizeof(server)) ==
SOCKET_ERROR) {
if (bind(BIP6_Socket, AI->ai_addr, AI->ai_addrlen) == SOCKET_ERROR) {
fprintf(stderr, "BIP6: bind() failed with error %d: %s\n",
WSAGetLastError(), PrintError(WSAGetLastError()));
closesocket(ServSock[i]);
+29 -4
View File
@@ -64,6 +64,8 @@ static uint8_t BVLC6_Function_Code = BVLC6_RESULT;
/** if we are a foreign device, store the remote BBMD address/port here */
static BACNET_IP6_ADDRESS Remote_BBMD;
/** if we are a foreign device, store the Time-To-Live Seconds here */
static uint16_t Remote_BBMD_TTL_Seconds;
#if defined(BACDL_BIP6) && BBMD6_ENABLED
/* local buffer & length for sending */
static uint8_t BVLC6_Buffer[BIP6_MPDU_MAX];
@@ -1024,24 +1026,47 @@ int bvlc6_handler(BACNET_IP6_ADDRESS *addr,
* @param bbmd_address - IPv4 address (long) of BBMD to register with,
* in network byte order.
* @param bbmd_port - Network port of BBMD, in network byte order
* @param time_to_live_seconds - Lease time to use when registering.
* @param ttl_seconds - Lease time to use when registering.
* @return Positive number (of bytes sent) on success,
* 0 if no registration request is sent, or
* -1 if registration fails.
*/
int bvlc6_register_with_bbmd(BACNET_IP6_ADDRESS *bbmd_addr,
uint32_t vmac_src,
uint16_t time_to_live_seconds)
uint16_t ttl_seconds)
{
uint8_t mtu[BIP6_MPDU_MAX] = { 0 };
uint16_t mtu_len = 0;
uint32_t vmac_src = 0;
/* Store the BBMD address and port so that we won't broadcast locally. */
/* We are a foreign device! */
bvlc6_address_copy(&Remote_BBMD, bbmd_addr);
Remote_BBMD_TTL_Seconds = ttl_seconds;
vmac_src = Device_Object_Instance_Number();
mtu_len = bvlc6_encode_register_foreign_device(
&mtu[0], sizeof(mtu), vmac_src, time_to_live_seconds);
&mtu[0], sizeof(mtu), vmac_src, ttl_seconds);
return bip6_send_mpdu(bbmd_addr, &mtu[0], mtu_len);
}
/** Get the remote BBMD address that was used to Register as a foreign device
* @param bbmd_addr - IPv6 address of BBMD used to register
*/
void bvlc6_remote_bbmd_address(BACNET_IP6_ADDRESS *bbmd_addr)
{
bvlc6_address_copy(bbmd_addr, &Remote_BBMD);
}
/**
* @brief Get the remote BBMD time-to-live seconds used to
* Register Foreign Device
* @return Lease time in seconds to use when registering.
*/
uint16_t bvlc6_remote_bbmd_lifetime(void)
{
return Remote_BBMD_TTL_Seconds;
}
/** Returns the last BVLL Result we received, either as the result of a BBMD
* request we sent, or (if not a BBMD or Client), from trying to register
* as a foreign device.
+8 -1
View File
@@ -69,9 +69,16 @@ extern "C" {
BACNET_STACK_EXPORT
int bvlc6_register_with_bbmd(
BACNET_IP6_ADDRESS *bbmd_addr,
uint32_t vmac_src,
uint16_t time_to_live_seconds);
BACNET_STACK_EXPORT
void bvlc6_remote_bbmd_address(
BACNET_IP6_ADDRESS *bbmd_addr);
BACNET_STACK_EXPORT
uint16_t bvlc6_remote_bbmd_lifetime(
void);
BACNET_STACK_EXPORT
uint16_t bvlc6_get_last_result(
void);
+96 -8
View File
@@ -40,14 +40,17 @@
#endif
/** @file dlenv.c Initialize the DataLink configuration. */
/* timer used to renew Foreign Device Registration */
#if defined(BACDL_BIP) || defined(BACDL_BIP6)
static uint16_t BBMD_Timer_Seconds;
static uint16_t BBMD_TTL_Seconds = 60000;
#endif
#if defined(BACDL_BIP)
#ifndef BBMD_ENABLED
#define BBMD_ENABLED 1
#endif
/* timer used to renew Foreign Device Registration */
static uint16_t BBMD_Timer_Seconds;
/* BBMD variables */
static uint16_t BBMD_TTL_Seconds = 60000;
static BACNET_IP_ADDRESS BBMD_Address;
static bool BBMD_Address_Valid;
static uint16_t BBMD_Result = 0;
@@ -120,6 +123,7 @@ int dlenv_bbmd_result(void)
}
#endif
#if defined(BACDL_BIP) && BBMD_ENABLED
/** Register as a Foreign Device with the designated BBMD.
* @ingroup DataLink
* The BBMD's address, port, and lease time must be provided by
@@ -134,10 +138,9 @@ int dlenv_bbmd_result(void)
* 0 if no registration request is sent, or
* -1 if registration fails.
*/
int dlenv_register_as_foreign_device(void)
static int bbmd_register_as_foreign_device(void)
{
int retval = 0;
#if defined(BACDL_BIP) && BBMD_ENABLED
bool bdt_entry_valid = false;
uint16_t bdt_entry_port = 0;
char *pEnv = NULL;
@@ -187,7 +190,7 @@ int dlenv_register_as_foreign_device(void)
(unsigned)BBMD_Address.address[2],
(unsigned)BBMD_Address.address[3], (unsigned)BBMD_Address.port);
}
BBMD_Timer_Seconds = (uint16_t)BBMD_TTL_Seconds;
BBMD_Timer_Seconds = BBMD_TTL_Seconds;
} else {
for (entry_number = 1; entry_number <= 128; entry_number++) {
bdt_entry_valid = false;
@@ -259,9 +262,94 @@ int dlenv_register_as_foreign_device(void)
}
}
BBMD_Result = retval;
#endif
return retval;
}
#endif
#if defined(BACDL_BIP6) && BBMD6_ENABLED
/** Register as a Foreign Device with the designated BBMD.
* @ingroup DataLink
* The BBMD's address, port, and lease time must be provided by
* internal variables or Environment variables.
* If no address for the BBMD is provided, no BBMD registration will occur.
*
* The Environment Variables depend on define of BACDL_BIP:
* - BACNET_BBMD6_PORT - 0..65534, defaults to 47808
* - BACNET_BBMD6_TIMETOLIVE - 0..65535 seconds, defaults to 60000
* - BACNET_BBMD6_ADDRESS - IPv6 address
* @return Positive number (of bytes sent) on success,
* 0 if no registration request is sent, or
* -1 if registration fails.
*/
static int bbmd6_register_as_foreign_device(void)
{
int retval = 0;
bool bdt_entry_valid = false;
uint16_t bdt_entry_port = 0;
char *pEnv = NULL;
unsigned a[4] = { 0 };
char bbmd_env[32] = "";
unsigned entry_number = 0;
long long_value = 0;
int c;
BACNET_IP6_ADDRESS bip6_addr = { 0 };
uint16_t bip6_port = 0xBAC0;
pEnv = getenv("BACNET_BBMD6_PORT");
if (pEnv) {
long_value = strtol(pEnv, NULL, 0);
if (long_value <= UINT16_MAX) {
bip6_port = (uint16_t)long_value;
}
}
pEnv = getenv("BACNET_BBMD6_TIMETOLIVE");
if (pEnv) {
long_value = strtol(pEnv, NULL, 0);
if (long_value <= 60000) {
BBMD_TTL_Seconds = (uint16_t)long_value;
}
}
pEnv = getenv("BACNET_BBMD6_ADDRESS");
if (bvlc6_address_from_ascii(pEnv, &bip6_addr)) {
if (BIP_DL_Debug) {
fprintf(stderr,
"Registering with BBMD6 at %s for %u seconds\n",
pEnv, (unsigned)bip6_port, (unsigned)BBMD_TTL_Seconds);
}
retval = bvlc6_register_with_bbmd(&bip6_addr, BBMD_TTL_Seconds);
if (retval < 0) {
fprintf(stderr, "FAILED to Register with BBMD6 at %s:%u\n",
pEnv, (unsigned)BBMD_Address.port);
}
BBMD_Timer_Seconds = BBMD_TTL_Seconds;
}
BBMD_Result = retval;
return retval;
}
#endif
/** Register as a Foreign Device with the designated BBMD.
* @ingroup DataLink
* The BBMD's address, port, and lease time must be provided by
* internal variables or Environment variables.
* If no address for the BBMD is provided, no BBMD registration will occur.
*
* @return Positive number (of bytes sent) on success,
* 0 if no registration request is sent, or
* -1 if registration fails.
*/
int dlenv_register_as_foreign_device(void)
{
#if defined(BACDL_BIP) && BBMD_ENABLED
return bbmd_register_as_foreign_device();
#elif defined(BACDL_BIP) && BBMD_ENABLED
return bbmd6_register_as_foreign_device();
#else
return 0;
#endif
}
#if (BACNET_PROTOCOL_REVISION >= 17)
#if defined(BACDL_BIP)
@@ -381,7 +469,7 @@ void dlenv_network_port_init(void)
*/
void dlenv_maintenance_timer(uint16_t elapsed_seconds)
{
#if defined(BACDL_BIP)
#if defined(BACDL_BIP) || defined(BACDL_BIP6)
if (BBMD_Timer_Seconds) {
if (BBMD_Timer_Seconds <= elapsed_seconds) {
BBMD_Timer_Seconds = 0;