mirror of
https://github.com/espressif/openthread.git
synced 2026-09-13 12:40:05 +00:00
[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:
+18
-9
@@ -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));
|
||||||
|
|
||||||
|
|||||||
@@ -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.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
Reference in New Issue
Block a user