[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.
This commit is contained in:
Duda, Lukasz
2020-05-11 15:22:18 -07:00
committed by Jonathan Hui
parent 069afa5a17
commit 2f683e6e76
2 changed files with 14 additions and 14 deletions
+14 -11
View File
@@ -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;
@@ -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()