mirror of
https://github.com/espressif/openthread.git
synced 2026-09-01 06:49:54 +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 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));
|
||||
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user