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_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 *
|
net_protocol *
|
||||||
icmp6_init_protocol(net_socket *socket)
|
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:
|
default:
|
||||||
// unrecognized messages go to neighbor discovery protocol handler
|
// unrecognized messages go to neighbor discovery protocol handler
|
||||||
return sIPv6NDPModule->receive_data(buffer);
|
return sIPv6NDPModule->receive_data(buffer);
|
||||||
|
|||||||
@@ -45,9 +45,11 @@
|
|||||||
#define TRACE_SK(protocol, format, args...) \
|
#define TRACE_SK(protocol, format, args...) \
|
||||||
dprintf("IPv6 [%" B_PRIdBIGTIME "] %p " format "\n", system_time(), \
|
dprintf("IPv6 [%" B_PRIdBIGTIME "] %p " format "\n", system_time(), \
|
||||||
protocol, ##args)
|
protocol, ##args)
|
||||||
|
#define TRACE_ONLY(x) x
|
||||||
#else
|
#else
|
||||||
#define TRACE(args...)
|
#define TRACE(args...)
|
||||||
#define TRACE_SK(args...)
|
#define TRACE_SK(args...)
|
||||||
|
#define TRACE_ONLY(x)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
@@ -1579,9 +1581,56 @@ ipv6_deliver_data(net_protocol* _protocol, net_buffer* buffer)
|
|||||||
|
|
||||||
|
|
||||||
status_t
|
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