[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.
This commit is contained in:
Abtin Keshavarzian
2022-07-11 11:59:06 -07:00
committed by GitHub
parent 5876ff79ae
commit 6e0eb8addf
8 changed files with 61 additions and 54 deletions
+18 -9
View File
@@ -88,33 +88,42 @@ exit:
} }
Error Icmp::SendError(Header::Type aType, Header::Code aCode, const MessageInfo &aMessageInfo, const Message &aMessage) 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; Error error = kErrorNone;
MessageInfo messageInfoLocal; MessageInfo messageInfoLocal;
Message * message = nullptr; Message * message = nullptr;
Header icmp6Header; Header icmp6Header;
ot::Ip6::Header ip6Header;
Message::Settings settings(Message::kWithLinkSecurity, Message::kPriorityNet); Message::Settings settings(Message::kWithLinkSecurity, Message::kPriorityNet);
SuccessOrExit(error = aMessage.Read(0, ip6Header)); if (aHeaders.GetIpProto() == kProtoIcmp6)
if (ip6Header.GetNextHeader() == kProtoIcmp6)
{ {
SuccessOrExit(aMessage.Read(sizeof(ip6Header), icmp6Header)); VerifyOrExit(!aHeaders.GetIcmpHeader().IsError());
VerifyOrExit(!icmp6Header.IsError());
} }
messageInfoLocal = aMessageInfo; messageInfoLocal = aMessageInfo;
VerifyOrExit((message = Get<Ip6>().NewMessage(0, settings)) != nullptr, error = kErrorNoBufs); VerifyOrExit((message = Get<Ip6>().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.Clear();
icmp6Header.SetType(aType); icmp6Header.SetType(aType);
icmp6Header.SetCode(aCode); icmp6Header.SetCode(aCode);
message->Write(0, icmp6Header); SuccessOrExit(error = message->Append(icmp6Header));
SuccessOrExit(error = message->Append(aHeaders.GetIp6Header()));
SuccessOrExit(error = Get<Ip6>().SendDatagram(*message, messageInfoLocal, kProtoIcmp6)); SuccessOrExit(error = Get<Ip6>().SendDatagram(*message, messageInfoLocal, kProtoIcmp6));
+16
View File
@@ -61,6 +61,8 @@ using ot::Encoding::BigEndian::HostSwap16;
* *
*/ */
class Headers;
/** /**
* This class implements ICMPv6. * This class implements ICMPv6.
* *
@@ -284,6 +286,20 @@ public:
*/ */
Error SendError(Header::Type aType, Header::Code aCode, const MessageInfo &aMessageInfo, const Message &aMessage); 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. * This method handles an ICMPv6 message.
* *
+1 -1
View File
@@ -471,7 +471,7 @@ private:
Error RemoveAgedMessages(void); Error RemoveAgedMessages(void);
#endif #endif
void SendMesh(Message &aMessage, Mac::TxFrame &aFrame); 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 UpdateIp6Route(Message &aMessage);
Error UpdateIp6RouteFtd(Ip6::Header &ip6Header, Message &aMessage); Error UpdateIp6RouteFtd(Ip6::Header &ip6Header, Message &aMessage);
void EvaluateRoutingCost(uint16_t aDest, uint8_t &aBestCost, uint16_t &aBestDest) const; void EvaluateRoutingCost(uint16_t aDest, uint8_t &aBestCost, uint16_t &aBestDest) const;
+22 -40
View File
@@ -641,24 +641,25 @@ void MeshForwarder::SendIcmpErrorIfDstUnreach(const Message & aMessage,
const Mac::Address &aMacSource, const Mac::Address &aMacSource,
const Mac::Address &aMacDest) const Mac::Address &aMacDest)
{ {
Error error; Error error;
Ip6::Header ip6header; Ip6::Headers ip6Headers;
Child * child; Child * child;
VerifyOrExit(aMacSource.IsShort() && aMacDest.IsShort()); VerifyOrExit(aMacSource.IsShort() && aMacDest.IsShort());
child = Get<ChildTable>().FindChild(aMacSource.GetShort(), Child::kInStateAnyExceptInvalid); child = Get<ChildTable>().FindChild(aMacSource.GetShort(), Child::kInStateAnyExceptInvalid);
VerifyOrExit((child == nullptr) || child->IsFullThreadDevice()); VerifyOrExit((child == nullptr) || child->IsFullThreadDevice());
IgnoreError(aMessage.Read(0, ip6header)); SuccessOrExit(ip6Headers.ParseFrom(aMessage));
VerifyOrExit(!ip6header.GetDestination().IsMulticast() &&
Get<NetworkData::Leader>().IsOnMesh(ip6header.GetDestination()));
error = Get<Mle::MleRouter>().CheckReachability(aMacDest.GetShort(), ip6header); VerifyOrExit(!ip6Headers.GetDestinationAddress().IsMulticast() &&
Get<NetworkData::Leader>().IsOnMesh(ip6Headers.GetDestinationAddress()));
error = Get<Mle::MleRouter>().CheckReachability(aMacDest.GetShort(), ip6Headers.GetIp6Header());
if (error == kErrorNoRoute) if (error == kErrorNoRoute)
{ {
SendDestinationUnreachable(aMacSource.GetShort(), aMessage); SendDestinationUnreachable(aMacSource.GetShort(), ip6Headers);
} }
exit: exit:
@@ -670,48 +671,29 @@ Error MeshForwarder::CheckReachability(const uint8_t * aFrame,
const Mac::Address &aMeshSource, const Mac::Address &aMeshSource,
const Mac::Address &aMeshDest) const Mac::Address &aMeshDest)
{ {
Error error = kErrorNone; Error error;
Ip6::Header ip6Header; Ip6::Headers ip6Headers;
Message * message = nullptr;
Lowpan::FragmentHeader fragmentHeader;
uint16_t fragmentHeaderLength;
uint16_t datagramSize = 0;
if (fragmentHeader.ParseFrom(aFrame, aFrameLength, fragmentHeaderLength) == kErrorNone) error = ip6Headers.DecompressFrom(aFrame, aFrameLength, aMeshSource, aMeshDest, GetInstance());
{
// Only the first fragment header is followed by a LOWPAN_IPHC header
VerifyOrExit(fragmentHeader.GetDatagramOffset() == 0, error = kErrorNotFound);
aFrame += fragmentHeaderLength;
aFrameLength -= fragmentHeaderLength;
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<Mle::MleRouter>().CheckReachability(aMeshDest.GetShort(), ip6Header);
exit:
if (error == kErrorNotFound) if (error == kErrorNotFound)
{ {
// the message may not contain an IPv6 header // Frame may not contain an IPv6 header.
error = kErrorNone; ExitNow(error = kErrorNone);
} }
else if (error == kErrorNoRoute)
error = Get<Mle::MleRouter>().CheckReachability(aMeshDest.GetShort(), ip6Headers.GetIp6Header());
if (error == kErrorNoRoute)
{ {
SendDestinationUnreachable(aMeshSource.GetShort(), *message); SendDestinationUnreachable(aMeshSource.GetShort(), ip6Headers);
} }
FreeMessage(message); exit:
return error; return error;
} }
void MeshForwarder::SendDestinationUnreachable(uint16_t aMeshSource, const Message &aMessage) void MeshForwarder::SendDestinationUnreachable(uint16_t aMeshSource, const Ip6::Headers &aIp6Headers)
{ {
Ip6::MessageInfo messageInfo; Ip6::MessageInfo messageInfo;
@@ -719,7 +701,7 @@ void MeshForwarder::SendDestinationUnreachable(uint16_t aMeshSource, const Messa
messageInfo.GetPeerAddr().GetIid().SetLocator(aMeshSource); messageInfo.GetPeerAddr().GetIid().SetLocator(aMeshSource);
IgnoreError(Get<Ip6::Icmp>().SendError(Ip6::Icmp::Header::kTypeDstUnreach, IgnoreError(Get<Ip6::Icmp>().SendError(Ip6::Icmp::Header::kTypeDstUnreach,
Ip6::Icmp::Header::kCodeDstUnreachNoRoute, messageInfo, aMessage)); Ip6::Icmp::Header::kCodeDstUnreachNoRoute, messageInfo, aIp6Headers));
} }
void MeshForwarder::HandleMesh(uint8_t * aFrame, void MeshForwarder::HandleMesh(uint8_t * aFrame,
+1 -1
View File
@@ -3836,7 +3836,7 @@ bool Mle::IsMeshLocalAddress(const Ip6::Address &aAddress) const
return (aAddress.GetPrefix() == GetMeshLocalPrefix()); 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; Error error;
+1 -1
View File
@@ -1456,7 +1456,7 @@ protected:
* @retval kErrorNoRoute The destination is not reachable and the message should be dropped. * @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. * This method returns the next hop towards an RLOC16 destination.
+1 -1
View File
@@ -3677,7 +3677,7 @@ exit:
return; return;
} }
Error MleRouter::CheckReachability(uint16_t aMeshDest, Ip6::Header &aIp6Header) Error MleRouter::CheckReachability(uint16_t aMeshDest, const Ip6::Header &aIp6Header)
{ {
Error error = kErrorNone; Error error = kErrorNone;
+1 -1
View File
@@ -388,7 +388,7 @@ public:
* @retval kErrorNoRoute The destination is not reachable and the message should be dropped. * @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. * This method resolves 2-hop routing loops.