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 <[email protected]> Reviewed-by: waddlesplash <[email protected]>
This commit is contained in:
committed by
waddlesplash
parent
ed66661307
commit
68c1d4b3a8
@@ -39,6 +39,24 @@ static net_stack_module_info *sStackModule;
|
||||
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)
|
||||
{
|
||||
@@ -280,6 +298,38 @@ icmp6_receive_data(net_buffer *buffer)
|
||||
}
|
||||
}
|
||||
|
||||
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:
|
||||
// unrecognized messages go to neighbor discovery protocol handler
|
||||
return sIPv6NDPModule->receive_data(buffer);
|
||||
|
||||
@@ -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 @@ ipv6_deliver_data(net_protocol* _protocol, net_buffer* buffer)
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user