⛏️ index : haiku.git

author Christof Meerwald <cmeerw@cmeerw.org> 2025-12-29 21:52:55.0 +00:00:00
committer waddlesplash <waddlesplash@gmail.com> 2026-01-06 21:25:16.0 +00:00:00
commit
68c1d4b3a8f014b9366ae19c32c063e89d991b7c [patch]
tree
9f51f041f9bea95b28f1e783aa41b5b31874f731
parent
ed666613078d97710c85ba6007015fc3ba633114
download
68c1d4b3a8f014b9366ae19c32c063e89d991b7c.tar.gz

IPv6: Path MTU Discovery

* Copied and adapted IPv4 error handling code for IPv6 (to handle
  ICMP6_PACKET_TOO_BIG)

Change-Id: Id14cf6221626b5c723fbe77f19aa0d6b9d25f36a
Reviewed-on: https://review.haiku-os.org/c/haiku/+/10170
Tested-by: Commit checker robot <no-reply+buildbot@haiku-os.org>
Reviewed-by: waddlesplash <waddlesplash@gmail.com>

Diff

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

diff --git a/src/add-ons/kernel/network/protocols/icmp6/icmp6.cpp b/src/add-ons/kernel/network/protocols/icmp6/icmp6.cpp
index def182d..ae75d03 100644
--- a/src/add-ons/kernel/network/protocols/icmp6/icmp6.cpp
+++ b/src/add-ons/kernel/network/protocols/icmp6/icmp6.cpp
@@ -39,6 +39,24 @@
static net_ndp_module_info *sIPv6NDPModule;


static net_error
icmp6_to_net_error(uint8 type, uint8 code)
{
	switch (type) {
		case ICMP6_PARAM_PROB:
			return B_NET_ERROR_PARAMETER_PROBLEM;

		case ICMP6_PACKET_TOO_BIG:
			return B_NET_ERROR_MESSAGE_SIZE;

		default:
			break;
	}

	return (net_error)0;
}


net_protocol *
icmp6_init_protocol(net_socket *socket)
{
@@ -278,6 +296,38 @@
				gBufferModule->free(reply);
				return status;
			}
		}

		case ICMP6_DST_UNREACH:
		case ICMP6_PACKET_TOO_BIG:
		case ICMP6_TIME_EXCEEDED:
		case ICMP6_PARAM_PROB:
		{
			net_domain* domain = get_domain(buffer);
			if (domain == NULL)
				break;

			net_error error = icmp6_to_net_error(header.icmp6_type,
				header.icmp6_code);
			if (error == 0)
				break;

			net_error_data dataStorage = {};
			net_error_data* data = NULL;
			if (error == B_NET_ERROR_MESSAGE_SIZE) {
				data = &dataStorage;
				data->mtu = ntohl(header.icmp6_mtu);

				// IPv6 minimum fragment size is 1280 bytes, so if the "next MTU"
				// is smaller than that, we can be sure it's invalid.
				if (data->mtu < 1280)
					data = NULL;
			}

			// Deliver the error to the domain protocol which will
			// propagate the error to the upper protocols
			bufferHeader.Remove();
			return domain->module->error_received(error, data, buffer);
		}

		default:
diff --git a/src/add-ons/kernel/network/protocols/ipv6/ipv6.cpp b/src/add-ons/kernel/network/protocols/ipv6/ipv6.cpp
index 386cd47..08e7c4d 100644
--- a/src/add-ons/kernel/network/protocols/ipv6/ipv6.cpp
+++ b/src/add-ons/kernel/network/protocols/ipv6/ipv6.cpp
@@ -45,9 +45,11 @@
	#define TRACE_SK(protocol, format, args...) \
		dprintf("IPv6 [%" B_PRIdBIGTIME "] %p " format "\n", system_time(), \
			protocol, ##args)
	#define TRACE_ONLY(x) x
#else
	#define TRACE(args...)
	#define TRACE_SK(args...)
	#define TRACE_ONLY(x)
#endif


@@ -1579,9 +1581,56 @@


status_t
ipv6_error_received(net_error error, net_error_data* errorData, net_buffer* data)
ipv6_error_received(net_error error, net_error_data* errorData, net_buffer* buffer)
{
	return B_ERROR;
	TRACE("  ipv6_error_received(error %d, buffer %p [%" B_PRIu32 " bytes])",
		(int)error, buffer, buffer->size);

	NetBufferHeaderReader<IPv6Header> bufferHeader(buffer);
	if (bufferHeader.Status() != B_OK)
		return bufferHeader.Status();

	IPv6Header& header = bufferHeader.Data();
	TRACE_ONLY(dump_ipv6_header(header));

	// We do not check the packet length, as we usually only get a part of it
	if (header.ProtocolVersion() != IPV6_VERSION)
		return B_BAD_DATA;

	// Restore addresses of the original buffer

	// lower layers notion of broadcast or multicast have no relevance to us
	// TODO: they actually have when deciding whether to send an ICMP error
	buffer->msg_flags &= ~(MSG_BCAST | MSG_MCAST);

	fill_sockaddr_in6((struct sockaddr_in6*)buffer->source, header.Src());
	fill_sockaddr_in6((struct sockaddr_in6*)buffer->destination,
		header.Dst());

	// test if the packet is really from us
	if (!sDatalinkModule->is_local_address(sDomain, buffer->source, NULL,
			NULL)) {
		TRACE("  ipv6_error_received(): packet was not for us");
		return B_ERROR;
	}

	if (error == B_NET_ERROR_MESSAGE_SIZE) {
		if (errorData != NULL)
			errorData->mtu -= sizeof(IPv6Header);
	} else if (error == B_NET_ERROR_REDIRECT_HOST) {
		// TODO: Update the routing table!
	}

	buffer->protocol = header.NextHeader();

	bufferHeader.Remove(sizeof(IPv6Header));

	net_protocol_module_info* protocol = receiving_protocol(buffer->protocol);
	if (protocol == NULL)
		return B_ERROR;

	// propagate error
	return protocol->error_received(error, errorData, buffer);
}