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 <[email protected]>
Reviewed-by: waddlesplash <[email protected]>
Tested-by: Commit checker robot <[email protected]>
This commit is contained in:
Christof Meerwald
2026-01-08 20:17:42 +00:00
committed by waddlesplash
parent 04ebf3d669
commit 5fed29dcb0
2 changed files with 50 additions and 57 deletions
@@ -340,14 +340,6 @@ icmp6_receive_data(net_buffer *buffer)
} }
status_t
icmp6_deliver_data(net_protocol *protocol, net_buffer *buffer)
{
// TODO: does this look OK?
return icmp6_receive_data(buffer);
}
status_t status_t
icmp6_error_received(net_error code, net_error_data* errorData, net_buffer* data) icmp6_error_received(net_error code, net_error_data* errorData, net_buffer* data)
{ {
@@ -427,7 +419,7 @@ net_protocol_module_info sICMP6Module = {
icmp6_get_domain, icmp6_get_domain,
icmp6_get_mtu, icmp6_get_mtu,
icmp6_receive_data, icmp6_receive_data,
icmp6_deliver_data, NULL, // deliver_data
icmp6_error_received, icmp6_error_received,
icmp6_error_reply, icmp6_error_reply,
NULL, // add_ancillary_data() NULL, // add_ancillary_data()
@@ -723,64 +723,58 @@ send_fragments(ipv6_protocol* protocol, struct net_route* route,
} }
static status_t static bool
deliver_multicast(net_protocol_module_info* module, net_buffer* buffer,
bool deliverToRaw, net_interface *interface)
{
sockaddr_in6* multicastAddr = (sockaddr_in6*)buffer->destination;
MulticastState::ValueIterator it = sMulticastState->Lookup(std::make_pair(
&multicastAddr->sin6_addr, interface->index));
while (it.HasNext()) {
IPv6GroupInterface* state = it.Next();
ipv6_protocol* ipproto = state->Parent()->Socket();
if (deliverToRaw && ipproto->raw == NULL)
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, deliver_multicast(net_protocol_module_info* module, net_buffer* buffer,
bool deliverToRaw) bool deliverToRaw)
{ {
TRACE("deliver_multicast(%p [%" B_PRIu32 " bytes])", buffer, buffer->size);
if (module->deliver_data == NULL) if (module->deliver_data == NULL)
return B_OK; return false;
MutexLocker _(sMulticastGroupsLock); MutexLocker _(sMulticastGroupsLock);
status_t status = B_OK; sockaddr_in6* multicastAddr = (sockaddr_in6*)buffer->destination;
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; uint32 index = buffer->index;
while (true) { if (buffer->interface_address != NULL)
interface = (net_interface*)list_get_next_item( index = buffer->interface_address->interface->index;
&domain->interfaces, interface);
if (interface == NULL)
break;
status = deliver_multicast(module, buffer, deliverToRaw, interface); MulticastState::ValueIterator it = sMulticastState->Lookup(std::make_pair(
if (status < B_OK) &multicastAddr->sin6_addr, index));
break;
size_t count = 0;
while (it.HasNext()) {
IPv6GroupInterface* state = it.Next();
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)) {
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;
}
if (protocol != NULL) {
module->deliver_data(protocol, buffer);
count++;
}
} }
#endif
} }
return status;
return count > 0;
} }
@@ -1561,7 +1555,14 @@ ipv6_receive_data(net_buffer* buffer)
// model be a little different from the unicast one. We deliver // model be a little different from the unicast one. We deliver
// this frame directly to all sockets registered with interest // this frame directly to all sockets registered with interest
// for this multicast group. // 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); return module->receive_data(buffer);