⛏️ index : haiku.git

author Christof Meerwald <cmeerw@cmeerw.org> 2025-12-29 21:14:44.0 +00:00:00
committer waddlesplash <waddlesplash@gmail.com> 2026-01-08 20:17:42.0 +00:00:00
commit
5fed29dcb02f528bb269443598bd1f821994e367 [patch]
tree
c9ef08b9962bbd8dc659baabfd2210036c9eafa4
parent
04ebf3d66962c423c0a69f06410272f43506458f
download
5fed29dcb02f528bb269443598bd1f821994e367.tar.gz

IPv6: implement multicast support

* Copied and adapted deliver_multicast from IPv4

* However, we still need special handling for the Neighbor Discovery
  Protocol as there is no associated socket. So for now we just pass
  any multicast ICMPv6 packets to the ICMPv6 module's receive_data
  that in turn passes it to the NDP module.

Change-Id: Idc9db0ec2132dffcf65c3b767dd1e428c44b27ba
Reviewed-on: https://review.haiku-os.org/c/haiku/+/10169
Reviewed-by: Jérôme Duval <jerome.duval@gmail.com>
Reviewed-by: waddlesplash <waddlesplash@gmail.com>
Tested-by: Commit checker robot <no-reply+buildbot@haiku-os.org>

Diff

 src/add-ons/kernel/network/protocols/icmp6/icmp6.cpp | 10 +---------
 src/add-ons/kernel/network/protocols/ipv6/ipv6.cpp   | 89 +++++++++++++++++++++++++++++++++++++++++++++-----------------------------------
 2 files changed, 46 insertions(+), 53 deletions(-)

diff --git a/src/add-ons/kernel/network/protocols/icmp6/icmp6.cpp b/src/add-ons/kernel/network/protocols/icmp6/icmp6.cpp
index ae75d03..ee8a4b0 100644
--- a/src/add-ons/kernel/network/protocols/icmp6/icmp6.cpp
+++ b/src/add-ons/kernel/network/protocols/icmp6/icmp6.cpp
@@ -341,14 +341,6 @@


status_t
icmp6_deliver_data(net_protocol *protocol, net_buffer *buffer)
{
	// TODO: does this look OK?
	return icmp6_receive_data(buffer);
}


status_t
icmp6_error_received(net_error code, net_error_data* errorData, net_buffer* data)
{
 	return B_ERROR;
@@ -427,7 +419,7 @@
	icmp6_get_domain,
	icmp6_get_mtu,
	icmp6_receive_data,
	icmp6_deliver_data,
	NULL,		// deliver_data
	icmp6_error_received,
	icmp6_error_reply,
	NULL,		// add_ancillary_data()
diff --git a/src/add-ons/kernel/network/protocols/ipv6/ipv6.cpp b/src/add-ons/kernel/network/protocols/ipv6/ipv6.cpp
index 08e7c4d..c6aa238 100644
--- a/src/add-ons/kernel/network/protocols/ipv6/ipv6.cpp
+++ b/src/add-ons/kernel/network/protocols/ipv6/ipv6.cpp
@@ -723,64 +723,58 @@
}


static status_t
static bool
deliver_multicast(net_protocol_module_info* module, net_buffer* buffer,
	bool deliverToRaw, net_interface *interface)
	bool deliverToRaw)
{
	TRACE("deliver_multicast(%p [%" B_PRIu32 " bytes])", buffer, buffer->size);
	if (module->deliver_data == NULL)
		return false;

	MutexLocker _(sMulticastGroupsLock);

	sockaddr_in6* multicastAddr = (sockaddr_in6*)buffer->destination;

	uint32 index = buffer->index;
	if (buffer->interface_address != NULL)
		index = buffer->interface_address->interface->index;

	MulticastState::ValueIterator it = sMulticastState->Lookup(std::make_pair(
		&multicastAddr->sin6_addr, interface->index));
		&multicastAddr->sin6_addr, index));

	size_t count = 0;

	while (it.HasNext()) {
		IPv6GroupInterface* state = it.Next();
		ipv6_protocol* ipproto = state->Parent()->Socket();

		if (deliverToRaw && ipproto->raw == NULL)
		ipv6_protocol* ipProtocol = state->Parent()->Socket();
		// There is no socket for Neighbor Discovery Protocol
		if (ipProtocol->socket == NULL)
			continue;
		if (deliverToRaw && (ipProtocol->raw == NULL
				|| ipProtocol->socket->protocol != buffer->protocol))
			continue;

		if (state->FilterAccepts(buffer)) {
			// TODO: do as in IPv4 code
			module->deliver_data(ipproto, buffer);
		}
	}

	return B_OK;
}


static status_t
deliver_multicast(net_protocol_module_info* module, net_buffer* buffer,
	bool deliverToRaw)
{
	if (module->deliver_data == NULL)
		return B_OK;

	MutexLocker _(sMulticastGroupsLock);
			net_protocol* protocol = ipProtocol;
			if (protocol->module != module) {
				// as multicast filters are installed with an IPv6 protocol
				// reference, we need to go and find the appropriate instance
				// related to the 'receiving protocol' with module 'module'.
				protocol = ipProtocol->socket->first_protocol;

				while (protocol != NULL && protocol->module != module)
					protocol = protocol->next;
			}

	status_t status = B_OK;
	if (buffer->interface_address != NULL) {
		status = deliver_multicast(module, buffer, deliverToRaw,
			buffer->interface_address->interface);
	} else {
#if 0 //  FIXME: multicast

		net_domain_private* domain = (net_domain_private*)sDomain;
		RecursiveLocker locker(domain->lock);

		net_interface* interface = NULL;
		while (true) {
			interface = (net_interface*)list_get_next_item(
				&domain->interfaces, interface);
			if (interface == NULL)
				break;

			status = deliver_multicast(module, buffer, deliverToRaw, interface);
			if (status < B_OK)
				break;
			if (protocol != NULL) {
				module->deliver_data(protocol, buffer);
				count++;
			}
		}
#endif
	}
	return status;

	return count > 0;
}


@@ -1561,7 +1555,14 @@
		// model be a little different from the unicast one. We deliver
		// this frame directly to all sockets registered with interest
		// for this multicast group.
		return deliver_multicast(module, buffer, false);
		deliver_multicast(module, buffer, false);
		if (protocol != IPPROTO_ICMPV6) {
			// ICMPv6 will still be passed to receive_data below,
			// as it might be a neighbor solicitation; otherwise,
			// we are done.
			gBufferModule->free(buffer);
			return B_OK;
		}
	}

	return module->receive_data(buffer);