From 6e0eb8addfa2595112d350dc2dc45d7d6ac4e8b8 Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Mon, 11 Jul 2022 11:59:06 -0700 Subject: [PATCH] [mesh-forwarder] simplify `CheckReachability()` and `Icmp::SendError()` (#7887) A new flavor of `Icmp::SendError()` is added which allows the caller to provide the parsed `Ip6::Headers` of the error-causing message instead the full `Message` instance. Note that the implementation of `SendError()` only includes the IPv6 header of the error-causing message in the payload of the ICMPv6 error message. `MeshForwarder::CheckReachability()` method is updated to use the recently added `Ip6::Headers` to parse the IPv6 headers from the received frame. With the changes in this commit, we no longer need to allocate a temporary `Message` which was used for reading the decompressed IPv6 header and also to pass to `Icmp::SendError()` in case of "destination unreachable" error. --- src/core/net/icmp6.cpp | 27 +++++++---- src/core/net/icmp6.hpp | 16 +++++++ src/core/thread/mesh_forwarder.hpp | 2 +- src/core/thread/mesh_forwarder_ftd.cpp | 62 +++++++++----------------- src/core/thread/mle.cpp | 2 +- src/core/thread/mle.hpp | 2 +- src/core/thread/mle_router.cpp | 2 +- src/core/thread/mle_router.hpp | 2 +- 8 files changed, 61 insertions(+), 54 deletions(-) diff --git a/src/core/net/icmp6.cpp b/src/core/net/icmp6.cpp index fee412d71..93542f688 100644 --- a/src/core/net/icmp6.cpp +++ b/src/core/net/icmp6.cpp @@ -88,33 +88,42 @@ exit: } Error Icmp::SendError(Header::Type aType, Header::Code aCode, const MessageInfo &aMessageInfo, const Message &aMessage) +{ + Error error; + Headers headers; + + SuccessOrExit(error = headers.ParseFrom(aMessage)); + error = SendError(aType, aCode, aMessageInfo, headers); + +exit: + return error; +} + +Error Icmp::SendError(Header::Type aType, Header::Code aCode, const MessageInfo &aMessageInfo, const Headers &aHeaders) { Error error = kErrorNone; MessageInfo messageInfoLocal; Message * message = nullptr; Header icmp6Header; - ot::Ip6::Header ip6Header; Message::Settings settings(Message::kWithLinkSecurity, Message::kPriorityNet); - SuccessOrExit(error = aMessage.Read(0, ip6Header)); - - if (ip6Header.GetNextHeader() == kProtoIcmp6) + if (aHeaders.GetIpProto() == kProtoIcmp6) { - SuccessOrExit(aMessage.Read(sizeof(ip6Header), icmp6Header)); - VerifyOrExit(!icmp6Header.IsError()); + VerifyOrExit(!aHeaders.GetIcmpHeader().IsError()); } messageInfoLocal = aMessageInfo; VerifyOrExit((message = Get().NewMessage(0, settings)) != nullptr, error = kErrorNoBufs); - SuccessOrExit(error = message->SetLength(sizeof(icmp6Header) + sizeof(ip6Header))); - message->Write(sizeof(icmp6Header), ip6Header); + // Prepare the ICMPv6 error message. We only include the IPv6 header + // of the original message causing the error. icmp6Header.Clear(); icmp6Header.SetType(aType); icmp6Header.SetCode(aCode); - message->Write(0, icmp6Header); + SuccessOrExit(error = message->Append(icmp6Header)); + SuccessOrExit(error = message->Append(aHeaders.GetIp6Header())); SuccessOrExit(error = Get().SendDatagram(*message, messageInfoLocal, kProtoIcmp6)); diff --git a/src/core/net/icmp6.hpp b/src/core/net/icmp6.hpp index ba73d6093..594da57b1 100644 --- a/src/core/net/icmp6.hpp +++ b/src/core/net/icmp6.hpp @@ -61,6 +61,8 @@ using ot::Encoding::BigEndian::HostSwap16; * */ +class Headers; + /** * This class implements ICMPv6. * @@ -284,6 +286,20 @@ public: */ Error SendError(Header::Type aType, Header::Code aCode, const MessageInfo &aMessageInfo, const Message &aMessage); + /** + * This method sends an ICMPv6 error message. + * + * @param[in] aType The ICMPv6 message type. + * @param[in] aCode The ICMPv6 message code. + * @param[in] aMessageInfo A reference to the message info. + * @param[in] aHeaders The parsed headers from the error-causing IPv6 message. + * + * @retval kErrorNone Successfully enqueued the ICMPv6 error message. + * @retval kErrorNoBufs Insufficient buffers available. + * + */ + Error SendError(Header::Type aType, Header::Code aCode, const MessageInfo &aMessageInfo, const Headers &aHeaders); + /** * This method handles an ICMPv6 message. * diff --git a/src/core/thread/mesh_forwarder.hpp b/src/core/thread/mesh_forwarder.hpp index 317a16640..adcc2d3e3 100644 --- a/src/core/thread/mesh_forwarder.hpp +++ b/src/core/thread/mesh_forwarder.hpp @@ -471,7 +471,7 @@ private: Error RemoveAgedMessages(void); #endif void SendMesh(Message &aMessage, Mac::TxFrame &aFrame); - void SendDestinationUnreachable(uint16_t aMeshSource, const Message &aMessage); + void SendDestinationUnreachable(uint16_t aMeshSource, const Ip6::Headers &aIp6Headers); Error UpdateIp6Route(Message &aMessage); Error UpdateIp6RouteFtd(Ip6::Header &ip6Header, Message &aMessage); void EvaluateRoutingCost(uint16_t aDest, uint8_t &aBestCost, uint16_t &aBestDest) const; diff --git a/src/core/thread/mesh_forwarder_ftd.cpp b/src/core/thread/mesh_forwarder_ftd.cpp index ab9cdbcde..d3c5932ad 100644 --- a/src/core/thread/mesh_forwarder_ftd.cpp +++ b/src/core/thread/mesh_forwarder_ftd.cpp @@ -641,24 +641,25 @@ void MeshForwarder::SendIcmpErrorIfDstUnreach(const Message & aMessage, const Mac::Address &aMacSource, const Mac::Address &aMacDest) { - Error error; - Ip6::Header ip6header; - Child * child; + Error error; + Ip6::Headers ip6Headers; + Child * child; VerifyOrExit(aMacSource.IsShort() && aMacDest.IsShort()); child = Get().FindChild(aMacSource.GetShort(), Child::kInStateAnyExceptInvalid); VerifyOrExit((child == nullptr) || child->IsFullThreadDevice()); - IgnoreError(aMessage.Read(0, ip6header)); - VerifyOrExit(!ip6header.GetDestination().IsMulticast() && - Get().IsOnMesh(ip6header.GetDestination())); + SuccessOrExit(ip6Headers.ParseFrom(aMessage)); - error = Get().CheckReachability(aMacDest.GetShort(), ip6header); + VerifyOrExit(!ip6Headers.GetDestinationAddress().IsMulticast() && + Get().IsOnMesh(ip6Headers.GetDestinationAddress())); + + error = Get().CheckReachability(aMacDest.GetShort(), ip6Headers.GetIp6Header()); if (error == kErrorNoRoute) { - SendDestinationUnreachable(aMacSource.GetShort(), aMessage); + SendDestinationUnreachable(aMacSource.GetShort(), ip6Headers); } exit: @@ -670,48 +671,29 @@ Error MeshForwarder::CheckReachability(const uint8_t * aFrame, const Mac::Address &aMeshSource, const Mac::Address &aMeshDest) { - Error error = kErrorNone; - Ip6::Header ip6Header; - Message * message = nullptr; - Lowpan::FragmentHeader fragmentHeader; - uint16_t fragmentHeaderLength; - uint16_t datagramSize = 0; + Error error; + Ip6::Headers ip6Headers; - if (fragmentHeader.ParseFrom(aFrame, aFrameLength, fragmentHeaderLength) == kErrorNone) - { - // Only the first fragment header is followed by a LOWPAN_IPHC header - VerifyOrExit(fragmentHeader.GetDatagramOffset() == 0, error = kErrorNotFound); - aFrame += fragmentHeaderLength; - aFrameLength -= fragmentHeaderLength; + error = ip6Headers.DecompressFrom(aFrame, aFrameLength, aMeshSource, aMeshDest, GetInstance()); - datagramSize = fragmentHeader.GetDatagramSize(); - } - - VerifyOrExit(aFrameLength >= 1 && Lowpan::Lowpan::IsLowpanHc(aFrame), error = kErrorNotFound); - - error = FrameToMessage(aFrame, aFrameLength, datagramSize, aMeshSource, aMeshDest, message); - SuccessOrExit(error); - - IgnoreError(message->Read(0, ip6Header)); - error = Get().CheckReachability(aMeshDest.GetShort(), ip6Header); - -exit: if (error == kErrorNotFound) { - // the message may not contain an IPv6 header - error = kErrorNone; + // Frame may not contain an IPv6 header. + ExitNow(error = kErrorNone); } - else if (error == kErrorNoRoute) + + error = Get().CheckReachability(aMeshDest.GetShort(), ip6Headers.GetIp6Header()); + + if (error == kErrorNoRoute) { - SendDestinationUnreachable(aMeshSource.GetShort(), *message); + SendDestinationUnreachable(aMeshSource.GetShort(), ip6Headers); } - FreeMessage(message); - +exit: return error; } -void MeshForwarder::SendDestinationUnreachable(uint16_t aMeshSource, const Message &aMessage) +void MeshForwarder::SendDestinationUnreachable(uint16_t aMeshSource, const Ip6::Headers &aIp6Headers) { Ip6::MessageInfo messageInfo; @@ -719,7 +701,7 @@ void MeshForwarder::SendDestinationUnreachable(uint16_t aMeshSource, const Messa messageInfo.GetPeerAddr().GetIid().SetLocator(aMeshSource); IgnoreError(Get().SendError(Ip6::Icmp::Header::kTypeDstUnreach, - Ip6::Icmp::Header::kCodeDstUnreachNoRoute, messageInfo, aMessage)); + Ip6::Icmp::Header::kCodeDstUnreachNoRoute, messageInfo, aIp6Headers)); } void MeshForwarder::HandleMesh(uint8_t * aFrame, diff --git a/src/core/thread/mle.cpp b/src/core/thread/mle.cpp index 06d06b416..451aa9261 100644 --- a/src/core/thread/mle.cpp +++ b/src/core/thread/mle.cpp @@ -3836,7 +3836,7 @@ bool Mle::IsMeshLocalAddress(const Ip6::Address &aAddress) const return (aAddress.GetPrefix() == GetMeshLocalPrefix()); } -Error Mle::CheckReachability(uint16_t aMeshDest, Ip6::Header &aIp6Header) +Error Mle::CheckReachability(uint16_t aMeshDest, const Ip6::Header &aIp6Header) { Error error; diff --git a/src/core/thread/mle.hpp b/src/core/thread/mle.hpp index 961d9ad52..063761309 100644 --- a/src/core/thread/mle.hpp +++ b/src/core/thread/mle.hpp @@ -1456,7 +1456,7 @@ protected: * @retval kErrorNoRoute The destination is not reachable and the message should be dropped. * */ - Error CheckReachability(uint16_t aMeshDest, Ip6::Header &aIp6Header); + Error CheckReachability(uint16_t aMeshDest, const Ip6::Header &aIp6Header); /** * This method returns the next hop towards an RLOC16 destination. diff --git a/src/core/thread/mle_router.cpp b/src/core/thread/mle_router.cpp index f991e3d28..d630347f9 100644 --- a/src/core/thread/mle_router.cpp +++ b/src/core/thread/mle_router.cpp @@ -3677,7 +3677,7 @@ exit: return; } -Error MleRouter::CheckReachability(uint16_t aMeshDest, Ip6::Header &aIp6Header) +Error MleRouter::CheckReachability(uint16_t aMeshDest, const Ip6::Header &aIp6Header) { Error error = kErrorNone; diff --git a/src/core/thread/mle_router.hpp b/src/core/thread/mle_router.hpp index 87af6de57..e0c7778c4 100644 --- a/src/core/thread/mle_router.hpp +++ b/src/core/thread/mle_router.hpp @@ -388,7 +388,7 @@ public: * @retval kErrorNoRoute The destination is not reachable and the message should be dropped. * */ - Error CheckReachability(uint16_t aMeshDest, Ip6::Header &aIp6Header); + Error CheckReachability(uint16_t aMeshDest, const Ip6::Header &aIp6Header); /** * This method resolves 2-hop routing loops.