From 2f683e6e765cb10c511fa36c6a8f240485899d11 Mon Sep 17 00:00:00 2001 From: "Duda, Lukasz" Date: Fri, 8 May 2020 22:49:49 +0200 Subject: [PATCH] [ip6] enhance handling of IPv6 fragmentation (#4940) This commit introduces a few enhancements: - In NCP architecture forward the IPv6 fragments instead of the full reassembled IPv6 packet (which in the default configuration can't be forwarder due to SPINEL limitations). Without this fix the fragmentation does not work if Thread device wants to send more than MTU data through the Border Router (to the IPv6 address of NCP). - Use OPENTHREAD_CONFIG_IP6_MAX_ASSEMBLED_DATAGRAM only for the receiving path. For transmitting path, relay on the message buffers pool. This is especially important for some of the use-cases we have, and also reduce a need for regenerating OpenThread libraries. - In case receiving IPv6 packet is bigger than supported OPENTHREAD_CONFIG_IP6_MAX_ASSEMBLED_DATAGRAM, exit before trying to allocate the next message buffer. --- src/core/net/ip6.cpp | 25 +++++++++++-------- .../thread-cert/test_ipv6_fragmentation.py | 3 --- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/core/net/ip6.cpp b/src/core/net/ip6.cpp index 75485a505..d2db236b0 100644 --- a/src/core/net/ip6.cpp +++ b/src/core/net/ip6.cpp @@ -646,8 +646,6 @@ otError Ip6::FragmentDatagram(Message &aMessage, uint8_t aIpProto) FragmentHeader::MakeDivisibleByEight(kMinimalMtu - aMessage.GetOffset() - sizeof(fragmentHeader)); uint16_t payloadLeft = aMessage.GetLength() - aMessage.GetOffset(); - VerifyOrExit(aMessage.GetLength() <= kMaxAssembledDatagramLength, error = OT_ERROR_NO_BUFS); - VerifyOrExit(aMessage.Read(0, sizeof(header), &header) == sizeof(header), error = OT_ERROR_PARSE); header.SetNextHeader(kProtoFragment); @@ -699,6 +697,7 @@ otError Ip6::FragmentDatagram(Message &aMessage, uint8_t aIpProto) otLogInfoIp6("Fragment %d with %d bytes sent", fragmentCnt, payloadFragment); } + aMessage.Free(); exit: @@ -757,6 +756,15 @@ otError Ip6::HandleFragment(Message &aMessage, Netif *aNetif, MessageInfo &aMess offset = FragmentHeader::FragmentOffsetToBytes(fragmentHeader.GetOffset()); payloadFragment = aMessage.GetLength() - aMessage.GetOffset() - sizeof(fragmentHeader); + otLogInfoIp6("Fragment with id %d received > %d bytes, offset %d", fragmentHeader.GetIdentification(), + payloadFragment, offset); + + if (offset + payloadFragment + aMessage.GetOffset() > kMaxAssembledDatagramLength) + { + otLogWarnIp6("Packet too large for fragment buffer"); + ExitNow(error = OT_ERROR_NO_BUFS); + } + if (message == NULL) { VerifyOrExit((message = NewMessage(0)) != NULL, error = OT_ERROR_NO_BUFS); @@ -780,15 +788,6 @@ otError Ip6::HandleFragment(Message &aMessage, Netif *aNetif, MessageInfo &aMess otLogDebgIp6("start reassembly."); } - otLogInfoIp6("Fragment with id %d received > %d bytes, offset %d", message->GetDatagramTag(), payloadFragment, - offset); - - if (offset + payloadFragment + aMessage.GetOffset() > kMaxAssembledDatagramLength) - { - otLogWarnIp6("Package too large for fragment buffer"); - ExitNow(error = OT_ERROR_NO_BUFS); - } - // increase message buffer if necessary if (message->GetLength() < offset + payloadFragment + aMessage.GetOffset()) { @@ -833,6 +832,7 @@ exit: } otLogWarnIp6("Reassembly failed: %s", otThreadErrorToString(error)); } + if (isFragmented) { // drop all fragments, the payload is stored in the fragment buffer @@ -970,6 +970,9 @@ otError Ip6::HandleExtensionHeaders(Message & aMessage, break; case kProtoFragment: + // Always forward IPv6 fragments to the Host. + IgnoreError(ProcessReceiveCallback(aMessage, aMessageInfo, aNextHeader, aFromNcpHost)); + SuccessOrExit(error = HandleFragment(aMessage, aNetif, aMessageInfo, aFromNcpHost)); break; diff --git a/tests/scripts/thread-cert/test_ipv6_fragmentation.py b/tests/scripts/thread-cert/test_ipv6_fragmentation.py index f669e528d..00506d205 100755 --- a/tests/scripts/thread-cert/test_ipv6_fragmentation.py +++ b/tests/scripts/thread-cert/test_ipv6_fragmentation.py @@ -77,9 +77,6 @@ class TestIPv6Fragmentation(thread_cert.TestCase): self.simulator.go(5) self.nodes[LEADER].udp_check_rx(1831) - self.nodes[ROUTER].udp_send(1953, mleid_leader, common.UDP_TEST_PORT, - False) - self.nodes[ROUTER].udp_stop() self.nodes[LEADER].udp_stop()