From adc62ecfe52c47ea6c23821b710a186b2ba1e3d7 Mon Sep 17 00:00:00 2001 From: Jonathan Hui Date: Tue, 7 Apr 2020 13:34:35 -0700 Subject: [PATCH] [icmp] pass full error-causing message when sending error (#4800) --- src/core/net/icmp6.cpp | 8 +++-- src/core/net/icmp6.hpp | 4 +-- src/core/net/ip6.cpp | 2 +- src/core/thread/mesh_forwarder.cpp | 2 +- src/core/thread/mesh_forwarder.hpp | 6 ++-- src/core/thread/mesh_forwarder_ftd.cpp | 44 ++++++++++++++++++++------ 6 files changed, 46 insertions(+), 20 deletions(-) diff --git a/src/core/net/icmp6.cpp b/src/core/net/icmp6.cpp index 754000b5d..b392209be 100644 --- a/src/core/net/icmp6.cpp +++ b/src/core/net/icmp6.cpp @@ -90,19 +90,21 @@ exit: otError Icmp::SendError(IcmpHeader::Type aType, IcmpHeader::Code aCode, const MessageInfo &aMessageInfo, - const Header & aHeader) + const Message & aMessage) { otError error = OT_ERROR_NONE; MessageInfo messageInfoLocal; Message * message = NULL; IcmpHeader icmp6Header; + Header ip6Header; messageInfoLocal = aMessageInfo; VerifyOrExit((message = Get().NewMessage(0)) != NULL, error = OT_ERROR_NO_BUFS); - SuccessOrExit(error = message->SetLength(sizeof(icmp6Header) + sizeof(aHeader))); + SuccessOrExit(error = message->SetLength(sizeof(icmp6Header) + sizeof(ip6Header))); - message->Write(sizeof(icmp6Header), sizeof(aHeader), &aHeader); + aMessage.Read(0, sizeof(ip6Header), &ip6Header); + message->Write(sizeof(icmp6Header), sizeof(ip6Header), &ip6Header); icmp6Header.Init(); icmp6Header.SetType(aType); diff --git a/src/core/net/icmp6.hpp b/src/core/net/icmp6.hpp index 100af7f20..b15cbb9ac 100644 --- a/src/core/net/icmp6.hpp +++ b/src/core/net/icmp6.hpp @@ -284,7 +284,7 @@ public: * @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] aHeader The IPv6 header of the error-causing message. + * @param[in] aMessage The error-causing IPv6 message. * * @retval OT_ERROR_NONE Successfully enqueued the ICMPv6 error message. * @retval OT_ERROR_NO_BUFS Insufficient buffers available. @@ -293,7 +293,7 @@ public: otError SendError(IcmpHeader::Type aType, IcmpHeader::Code aCode, const MessageInfo &aMessageInfo, - const Header & aHeader); + const Message & aMessage); /** * This method handles an ICMPv6 message. diff --git a/src/core/net/ip6.cpp b/src/core/net/ip6.cpp index 83d3a3d4b..24f93fa7b 100644 --- a/src/core/net/ip6.cpp +++ b/src/core/net/ip6.cpp @@ -905,7 +905,7 @@ otError Ip6::SendIcmpError(Message &aMessage, IcmpHeader::Type aIcmpType, IcmpHe messageInfo.SetHopLimit(header.GetHopLimit()); messageInfo.SetLinkInfo(NULL); - SuccessOrExit(error = mIcmp.SendError(aIcmpType, aIcmpCode, messageInfo, header)); + SuccessOrExit(error = mIcmp.SendError(aIcmpType, aIcmpCode, messageInfo, aMessage)); exit: return error; diff --git a/src/core/thread/mesh_forwarder.cpp b/src/core/thread/mesh_forwarder.cpp index f10e47bd3..eaba2fd79 100644 --- a/src/core/thread/mesh_forwarder.cpp +++ b/src/core/thread/mesh_forwarder.cpp @@ -332,7 +332,7 @@ otError MeshForwarder::UpdateIp6Route(Message &aMessage) else { #if OPENTHREAD_FTD - error = UpdateIp6RouteFtd(ip6Header); + error = UpdateIp6RouteFtd(ip6Header, aMessage); #else OT_ASSERT(false); #endif diff --git a/src/core/thread/mesh_forwarder.hpp b/src/core/thread/mesh_forwarder.hpp index 7a8334d6b..c3ab1672b 100644 --- a/src/core/thread/mesh_forwarder.hpp +++ b/src/core/thread/mesh_forwarder.hpp @@ -336,7 +336,7 @@ private: kMessageEvict, ///< Indicates that the message was evicted. }; - otError CheckReachability(uint8_t * aFrame, + otError CheckReachability(const uint8_t * aFrame, uint16_t aFrameLength, const Mac::Address &aMeshSource, const Mac::Address &aMeshDest); @@ -390,9 +390,9 @@ private: uint16_t aMeshDest = 0xffff); void SendMesh(Message &aMessage, Mac::TxFrame &aFrame); - void SendDestinationUnreachable(uint16_t aMeshSource, const Ip6::Header &aIp6Header); + void SendDestinationUnreachable(uint16_t aMeshSource, const Message &aMessage); otError UpdateIp6Route(Message &aMessage); - otError UpdateIp6RouteFtd(Ip6::Header &ip6Header); + otError UpdateIp6RouteFtd(Ip6::Header &ip6Header, const Message &aMessage); otError UpdateMeshRoute(Message &aMessage); bool UpdateReassemblyList(void); bool UpdateFragmentLifetime(void); diff --git a/src/core/thread/mesh_forwarder_ftd.cpp b/src/core/thread/mesh_forwarder_ftd.cpp index 048f1f7a9..85ec873fa 100644 --- a/src/core/thread/mesh_forwarder_ftd.cpp +++ b/src/core/thread/mesh_forwarder_ftd.cpp @@ -404,7 +404,7 @@ exit: return error; } -otError MeshForwarder::UpdateIp6RouteFtd(Ip6::Header &ip6Header) +otError MeshForwarder::UpdateIp6RouteFtd(Ip6::Header &ip6Header, const Message &aMessage) { Mle::MleRouter &mle = Get(); otError error = OT_ERROR_NONE; @@ -497,7 +497,7 @@ otError MeshForwarder::UpdateIp6RouteFtd(Ip6::Header &ip6Header) exit: if (error == OT_ERROR_NO_ROUTE) { - SendDestinationUnreachable(mMeshSource, ip6Header); + SendDestinationUnreachable(mMeshSource, aMessage); } return error; @@ -516,32 +516,56 @@ otError MeshForwarder::GetIp6Header(const uint8_t * aFrame, nextHeaderCompressed); } -otError MeshForwarder::CheckReachability(uint8_t * aFrame, +otError MeshForwarder::CheckReachability(const uint8_t * aFrame, uint16_t aFrameLength, const Mac::Address &aMeshSource, const Mac::Address &aMeshDest) { - otError error = OT_ERROR_NONE; - Ip6::Header ip6Header; + otError error = OT_ERROR_NONE; + Ip6::Header ip6Header; + Message * message = NULL; + Lowpan::FragmentHeader fragmentHeader; + uint16_t fragmentHeaderLength; + uint16_t datagramSize = 0; - SuccessOrExit(error = GetIp6Header(aFrame, aFrameLength, aMeshSource, aMeshDest, ip6Header)); + if (fragmentHeader.ParseFrom(aFrame, aFrameLength, fragmentHeaderLength) == OT_ERROR_NONE) + { + // Only the first fragment header is followed by a LOWPAN_IPHC header + VerifyOrExit(fragmentHeader.GetDatagramOffset() == 0, error = OT_ERROR_NOT_FOUND); + aFrame += fragmentHeaderLength; + aFrameLength -= fragmentHeaderLength; + + datagramSize = fragmentHeader.GetDatagramSize(); + } + + VerifyOrExit(aFrameLength >= 1 && Lowpan::Lowpan::IsLowpanHc(aFrame), error = OT_ERROR_NOT_FOUND); + + error = FrameToMessage(aFrame, aFrameLength, datagramSize, aMeshSource, aMeshDest, message); + SuccessOrExit(error); + + message->Read(0, sizeof(ip6Header), &ip6Header); error = Get().CheckReachability(aMeshDest.GetShort(), ip6Header); exit: - // the message may not contain an IPv6 header if (error == OT_ERROR_NOT_FOUND) { + // the message may not contain an IPv6 header error = OT_ERROR_NONE; } else if (error == OT_ERROR_NO_ROUTE) { - SendDestinationUnreachable(aMeshSource.GetShort(), ip6Header); + SendDestinationUnreachable(aMeshSource.GetShort(), *message); + } + + if (message != NULL) + { + message->Free(); } return error; } -void MeshForwarder::SendDestinationUnreachable(uint16_t aMeshSource, const Ip6::Header &aIp6Header) +void MeshForwarder::SendDestinationUnreachable(uint16_t aMeshSource, const Message &aMessage) { Ip6::MessageInfo messageInfo; @@ -549,7 +573,7 @@ void MeshForwarder::SendDestinationUnreachable(uint16_t aMeshSource, const Ip6:: messageInfo.GetPeerAddr().SetLocator(aMeshSource); Get().SendError(Ip6::IcmpHeader::kTypeDstUnreach, Ip6::IcmpHeader::kCodeDstUnreachNoRoute, messageInfo, - aIp6Header); + aMessage); } void MeshForwarder::HandleMesh(uint8_t * aFrame,