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(-)
@@ -341,14 +341,6 @@
status_t
icmp6_deliver_data(net_protocol *protocol, net_buffer *buffer)
{
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,
icmp6_error_received,
icmp6_error_reply,
NULL,
@@ -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();
if (ipProtocol->socket == NULL)
continue;
if (deliverToRaw && (ipProtocol->raw == NULL
|| ipProtocol->socket->protocol != buffer->protocol))
continue;
if (state->FilterAccepts(buffer)) {
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) {
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
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 @@
return deliver_multicast(module, buffer, false);
deliver_multicast(module, buffer, false);
if (protocol != IPPROTO_ICMPV6) {
gBufferModule->free(buffer);
return B_OK;
}
}
return module->receive_data(buffer);