Bugfix/ipv6 leave multicast on foreign device registration (#899)

* Fixed IPv6 handler to ignore original-broadcast when registered as a foreign-device

* Fixed IPv6 to leave multicast when registering as foreign device.
This commit is contained in:
Steve Karg
2025-02-17 09:07:27 -06:00
committed by GitHub
parent adff1f9c0f
commit aa87bd8051
7 changed files with 224 additions and 70 deletions
+60 -20
View File
@@ -14,6 +14,7 @@
#include "bacnet/bacdcode.h"
#include "bacnet/config.h"
#include "bacnet/datalink/bip6.h"
#include "bacnet/basic/sys/debug.h"
#include "bacnet/basic/object/device.h"
#include "bacnet/basic/bbmd6/h_bbmd6.h"
#if DEBUG_ENABLED
@@ -98,7 +99,7 @@ void bip6_set_interface(char *ifname)
bool found = false;
if (getifaddrs(&ifa) == -1) {
perror("BIP6: getifaddrs failed");
debug_perror("BIP6: getifaddrs failed");
exit(1);
}
ifa_tmp = ifa;
@@ -391,6 +392,62 @@ void bip6_cleanup(void)
return;
}
/**
* @brief Join a multicast group
*/
void bip6_join_group(void)
{
struct in6_addr broadcast_address = { 0 };
struct ipv6_mreq join_request = { 0 };
int status = 0; /* return from socket lib calls */
if (BIP6_Socket < 0) {
return;
}
/* join a multicast group */
memcpy(
&broadcast_address.s6_addr[0], &BIP6_Broadcast_Addr.address[0],
IP6_ADDRESS_MAX);
memcpy(
&join_request.ipv6mr_multiaddr, &broadcast_address,
sizeof(struct in6_addr));
/* Let system not choose the interface */
join_request.ipv6mr_interface = BIP6_Socket_Scope_Id;
status = setsockopt(
BIP6_Socket, IPPROTO_IPV6, IPV6_JOIN_GROUP, &join_request,
sizeof(join_request));
if (status < 0) {
debug_perror("BIP6: setsockopt(IPV6_JOIN_GROUP)");
}
}
/**
* @brief Leave a multicast group
*/
void bip6_leave_group(void)
{
struct in6_addr broadcast_address = { 0 };
struct ipv6_mreq leave_request = { 0 };
int status = 0; /* return from socket lib calls */
if (BIP6_Socket < 0) {
return;
}
/* leave a multicast address */
memcpy(
&broadcast_address.s6_addr[0], &BIP6_Broadcast_Addr.address[0],
IP6_ADDRESS_MAX);
memcpy(
&leave_request.ipv6mr_multiaddr, &broadcast_address,
sizeof(struct in6_addr));
status = setsockopt(
BIP6_Socket, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &leave_request,
sizeof(leave_request));
if (status < 0) {
debug_perror("BIP6: setsockopt(IPV6_LEAVE_GROUP)");
}
}
/** Initialize the BACnet/IP services at the given interface.
* @ingroup DLBIP6
* -# Gets the local IP address and local broadcast address from the system,
@@ -412,8 +469,6 @@ bool bip6_init(char *ifname)
{
int status = 0; /* return from socket lib calls */
struct sockaddr_in6 server = { 0 };
struct in6_addr broadcast_address;
struct ipv6_mreq join_request;
int sockopt = 0;
if (ifname) {
@@ -453,22 +508,7 @@ bool bip6_init(char *ifname)
BIP6_Socket = -1;
return false;
}
/* subscribe to a multicast address */
memcpy(
&broadcast_address.s6_addr[0], &BIP6_Broadcast_Addr.address[0],
IP6_ADDRESS_MAX);
memcpy(
&join_request.ipv6mr_multiaddr, &broadcast_address,
sizeof(struct in6_addr));
/* Let system not choose the interface */
join_request.ipv6mr_interface = BIP6_Socket_Scope_Id;
status = setsockopt(
BIP6_Socket, IPPROTO_IPV6, IPV6_JOIN_GROUP, &join_request,
sizeof(join_request));
if (status < 0) {
perror("BIP: setsockopt(IPV6_JOIN_GROUP)");
}
bip6_join_group();
/* bind the socket to the local port number and IP address */
server.sin6_family = AF_INET6;
#if 0
@@ -490,7 +530,7 @@ bool bip6_init(char *ifname)
debug_print_ipv6("Binding->", &server.sin6_addr);
status = bind(BIP6_Socket, (const void *)&server, sizeof(server));
if (status < 0) {
perror("BIP: bind");
debug_perror("BIP6: bind");
close(BIP6_Socket);
BIP6_Socket = -1;
return false;