diff --git a/ports/linux/bip6.c b/ports/linux/bip6.c index c100d106..e457ec39 100644 --- a/ports/linux/bip6.c +++ b/ports/linux/bip6.c @@ -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"); diff --git a/ports/win32/bip6.c b/ports/win32/bip6.c index 7fb2440b..c3a297b5 100644 --- a/ports/win32/bip6.c +++ b/ports/win32/bip6.c @@ -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]); diff --git a/src/bacnet/basic/bbmd6/h_bbmd6.c b/src/bacnet/basic/bbmd6/h_bbmd6.c index be527bc7..c9159248 100644 --- a/src/bacnet/basic/bbmd6/h_bbmd6.c +++ b/src/bacnet/basic/bbmd6/h_bbmd6.c @@ -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. diff --git a/src/bacnet/basic/bbmd6/h_bbmd6.h b/src/bacnet/basic/bbmd6/h_bbmd6.h index da8eaa65..9a4e3be0 100644 --- a/src/bacnet/basic/bbmd6/h_bbmd6.h +++ b/src/bacnet/basic/bbmd6/h_bbmd6.h @@ -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); diff --git a/src/bacnet/datalink/dlenv.c b/src/bacnet/datalink/dlenv.c index ceec33f9..e2478ef4 100644 --- a/src/bacnet/datalink/dlenv.c +++ b/src/bacnet/datalink/dlenv.c @@ -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;