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:
+78
-32
@@ -78,8 +78,6 @@ void bip6_set_interface(char *ifname)
|
||||
int i, RetVal;
|
||||
struct addrinfo Hints, *AddrInfo, *AI;
|
||||
struct sockaddr_in6 *sin;
|
||||
struct in6_addr broadcast_address = { 0 };
|
||||
struct ipv6_mreq join_request = { 0 };
|
||||
SOCKET ServSock[FD_SETSIZE] = { 0 };
|
||||
char port[6] = "";
|
||||
int sockopt = 0;
|
||||
@@ -102,7 +100,7 @@ void bip6_set_interface(char *ifname)
|
||||
}
|
||||
RetVal = getaddrinfo(ifname, &port[0], &Hints, &AddrInfo);
|
||||
if (RetVal != 0) {
|
||||
fprintf(
|
||||
debug_fprintf(
|
||||
stderr, "BIP6: getaddrinfo failed with error %d: %s\n", RetVal,
|
||||
gai_strerror(RetVal));
|
||||
WSACleanup();
|
||||
@@ -117,7 +115,7 @@ void bip6_set_interface(char *ifname)
|
||||
for (i = 0, AI = AddrInfo; AI != NULL; AI = AI->ai_next) {
|
||||
/* Highly unlikely, but check anyway. */
|
||||
if (i == FD_SETSIZE) {
|
||||
fprintf(
|
||||
debug_fprintf(
|
||||
stderr,
|
||||
"BIP6: getaddrinfo returned more addresses than we could "
|
||||
"use.\n");
|
||||
@@ -137,7 +135,7 @@ void bip6_set_interface(char *ifname)
|
||||
}
|
||||
BIP6_Socket = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
|
||||
if (BIP6_Socket == INVALID_SOCKET) {
|
||||
fprintf(
|
||||
debug_fprintf(
|
||||
stderr, "BIP6: socket() failed with error %d: %s\n",
|
||||
WSAGetLastError(), PrintError(WSAGetLastError()));
|
||||
continue;
|
||||
@@ -146,9 +144,10 @@ void bip6_set_interface(char *ifname)
|
||||
if ((AI->ai_family == AF_INET6) &&
|
||||
IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr) &&
|
||||
(sin->sin6_scope_id == 0)) {
|
||||
fprintf(
|
||||
debug_fprintf(
|
||||
stderr, "BIP6: IPv6 link local addresses needs a scope ID!\n");
|
||||
}
|
||||
BIP6_Socket_Scope_Id = if_nametoindex(ifname);
|
||||
/* Allow us to use the same socket for sending and receiving */
|
||||
/* This makes sure that the src port is correct when sending */
|
||||
sockopt = 1;
|
||||
@@ -158,7 +157,7 @@ void bip6_set_interface(char *ifname)
|
||||
if (RetVal < 0) {
|
||||
closesocket(BIP6_Socket);
|
||||
BIP6_Socket = INVALID_SOCKET;
|
||||
fprintf(
|
||||
debug_fprintf(
|
||||
stderr,
|
||||
"BIP6: setsockopt(SO_REUSEADDR) failed with error %d: %s\n",
|
||||
WSAGetLastError(), PrintError(WSAGetLastError()));
|
||||
@@ -171,39 +170,20 @@ void bip6_set_interface(char *ifname)
|
||||
if (RetVal < 0) {
|
||||
closesocket(BIP6_Socket);
|
||||
BIP6_Socket = INVALID_SOCKET;
|
||||
fprintf(
|
||||
debug_fprintf(
|
||||
stderr,
|
||||
"BIP6: setsockopt(SO_BROADCAST) failed "
|
||||
"with error %d: %s\n",
|
||||
WSAGetLastError(), PrintError(WSAGetLastError()));
|
||||
continue;
|
||||
}
|
||||
/* 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 */
|
||||
BIP6_Socket_Scope_Id = if_nametoindex(ifname);
|
||||
join_request.ipv6mr_interface = BIP6_Socket_Scope_Id;
|
||||
RetVal = setsockopt(
|
||||
BIP6_Socket, IPPROTO_IPV6, IPV6_JOIN_GROUP, (char *)&join_request,
|
||||
sizeof(join_request));
|
||||
if (RetVal < 0) {
|
||||
fprintf(
|
||||
stderr,
|
||||
"BIP6: setsockopt(IPV6_JOIN_GROUP) failed "
|
||||
"with error %d: %s\n",
|
||||
WSAGetLastError(), PrintError(WSAGetLastError()));
|
||||
}
|
||||
bip6_join_group();
|
||||
/* bind() associates a local address and port combination
|
||||
with the socket just created. This is most useful when
|
||||
the application is a server that has a well-known port
|
||||
that clients know about in advance. */
|
||||
if (bind(BIP6_Socket, AI->ai_addr, AI->ai_addrlen) == SOCKET_ERROR) {
|
||||
fprintf(
|
||||
debug_fprintf(
|
||||
stderr, "BIP6: bind() failed with error %d: %s\n",
|
||||
WSAGetLastError(), PrintError(WSAGetLastError()));
|
||||
closesocket(ServSock[i]);
|
||||
@@ -230,7 +210,8 @@ void bip6_set_interface(char *ifname)
|
||||
}
|
||||
freeaddrinfo(AddrInfo);
|
||||
if (BIP6_Socket == INVALID_SOCKET) {
|
||||
fprintf(stderr, "BIP6: AF_INET6 address not found getaddrinfo()\n");
|
||||
debug_fprintf(
|
||||
stderr, "BIP6: AF_INET6 address not found getaddrinfo()\n");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -497,6 +478,70 @@ 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 == INVALID_SOCKET) {
|
||||
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, (char *)&join_request,
|
||||
sizeof(join_request));
|
||||
if (status < 0) {
|
||||
debug_fprintf(
|
||||
stderr,
|
||||
"BIP6: setsockopt(IPV6_JOIN_GROUP) failed "
|
||||
"with error %d: %s\n",
|
||||
WSAGetLastError(), PrintError(WSAGetLastError()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @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 == INVALID_SOCKET) {
|
||||
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, (char *)&leave_request,
|
||||
sizeof(leave_request));
|
||||
if (status < 0) {
|
||||
debug_fprintf(
|
||||
stderr,
|
||||
"BIP6: setsockopt(IPV6_LEAVE_GROUP) failed "
|
||||
"with error %d: %s\n",
|
||||
WSAGetLastError(), PrintError(WSAGetLastError()));
|
||||
}
|
||||
}
|
||||
|
||||
/** Initialize the BACnet/IP services at the given interface.
|
||||
* @ingroup DLBIP6
|
||||
* -# Gets the local IP address and local broadcast address from the system,
|
||||
@@ -523,7 +568,7 @@ bool bip6_init(char *ifname)
|
||||
|
||||
/* Ask for Winsock version 2.2. */
|
||||
if ((RetVal = WSAStartup(MAKEWORD(2, 2), &wd)) != 0) {
|
||||
fprintf(
|
||||
debug_fprintf(
|
||||
stderr, "BIP6: WSAStartup failed with error %d: %s\n", RetVal,
|
||||
PrintError(RetVal));
|
||||
WSACleanup();
|
||||
@@ -543,7 +588,8 @@ bool bip6_init(char *ifname)
|
||||
BIP6_MULTICAST_GROUP_ID);
|
||||
}
|
||||
if (BIP6_Socket == INVALID_SOCKET) {
|
||||
fprintf(stderr, "BIP6: Fatal error: unable to serve on any address.\n");
|
||||
debug_fprintf(
|
||||
stderr, "BIP6: Fatal error: unable to serve on any address.\n");
|
||||
WSACleanup();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user