[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 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<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.SetType(aType);
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));
+16
View File
@@ -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.
*
+1 -1
View File
@@ -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;
+22 -40
View File
@@ -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<ChildTable>().FindChild(aMacSource.GetShort(), Child::kInStateAnyExceptInvalid);
VerifyOrExit((child == nullptr) || child->IsFullThreadDevice());
IgnoreError(aMessage.Read(0, ip6header));
VerifyOrExit(!ip6header.GetDestination().IsMulticast() &&
Get<NetworkData::Leader>().IsOnMesh(ip6header.GetDestination()));
SuccessOrExit(ip6Headers.ParseFrom(aMessage));
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)
{
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<Mle::MleRouter>().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<Mle::MleRouter>().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<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,
+1 -1
View File
@@ -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;
+1 -1
View File
@@ -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.
+1 -1
View File
@@ -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;
+1 -1
View File
@@ -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.