From 5fed29dcb02f528bb269443598bd1f821994e367 Mon Sep 17 00:00:00 2001 From: Christof Meerwald Date: Mon, 29 Dec 2025 21:14:44 +0000 Subject: [PATCH] IPv6: implement multicast support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 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 Reviewed-by: waddlesplash Tested-by: Commit checker robot --- .../kernel/network/protocols/icmp6/icmp6.cpp | 10 +- .../kernel/network/protocols/ipv6/ipv6.cpp | 97 ++++++++++--------- 2 files changed, 50 insertions(+), 57 deletions(-) diff --git a/src/add-ons/kernel/network/protocols/icmp6/icmp6.cpp b/src/add-ons/kernel/network/protocols/icmp6/icmp6.cpp index ae75d03240..ee8a4b0fb4 100644 --- a/src/add-ons/kernel/network/protocols/icmp6/icmp6.cpp +++ b/src/add-ons/kernel/network/protocols/icmp6/icmp6.cpp @@ -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 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_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 08e7c4d05c..c6aa23894e 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 @@ send_fragments(ipv6_protocol* protocol, struct net_route* route, } -static status_t -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 +static bool deliver_multicast(net_protocol_module_info* module, net_buffer* buffer, bool deliverToRaw) { + TRACE("deliver_multicast(%p [%" B_PRIu32 " bytes])", buffer, buffer->size); if (module->deliver_data == NULL) - return B_OK; + return false; MutexLocker _(sMulticastGroupsLock); - 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); + sockaddr_in6* multicastAddr = (sockaddr_in6*)buffer->destination; - net_interface* interface = NULL; - while (true) { - interface = (net_interface*)list_get_next_item( - &domain->interfaces, interface); - if (interface == NULL) - break; + uint32 index = buffer->index; + if (buffer->interface_address != NULL) + index = buffer->interface_address->interface->index; - status = deliver_multicast(module, buffer, deliverToRaw, interface); - if (status < B_OK) - break; + MulticastState::ValueIterator it = sMulticastState->Lookup(std::make_pair( + &multicastAddr->sin6_addr, index)); + + 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 // 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);