mirror of
https://github.com/espressif/openthread.git
synced 2026-08-02 00:57:47 +00:00
[ip6] Headers class to parse IPv6 and UDP/TCP/ICMPv6 headers from message (#7851)
This commit adds `Ip6::Headers` class which represents IPv6 header along with related transport layer header (UDP, TCP or ICMP6). It provides helper methods to parse all headers from an IPv6 message or decompress and read them from a lowpan frame. This helps simplify the code and allows us to remove multiple similar methods in `MeshForwarder` performing decompression/parsing.
This commit is contained in:
@@ -1495,5 +1495,181 @@ const char *Ip6::EcnToString(Ecn aEcn)
|
||||
|
||||
// LCOV_EXCL_STOP
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
// Headers
|
||||
|
||||
Error Headers::ParseFrom(const Message &aMessage)
|
||||
{
|
||||
Error error = kErrorParse;
|
||||
|
||||
Clear();
|
||||
|
||||
SuccessOrExit(mIp6Header.ParseFrom(aMessage));
|
||||
|
||||
switch (mIp6Header.GetNextHeader())
|
||||
{
|
||||
case kProtoUdp:
|
||||
SuccessOrExit(aMessage.Read(sizeof(Header), mHeader.mUdp));
|
||||
break;
|
||||
case kProtoTcp:
|
||||
SuccessOrExit(aMessage.Read(sizeof(Header), mHeader.mTcp));
|
||||
break;
|
||||
case kProtoIcmp6:
|
||||
SuccessOrExit(aMessage.Read(sizeof(Header), mHeader.mIcmp));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
error = kErrorNone;
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
Error Headers::DecompressFrom(const Message & aMessage,
|
||||
uint16_t aOffset,
|
||||
const Mac::Address &aMacSource,
|
||||
const Mac::Address &aMacDest)
|
||||
{
|
||||
static constexpr uint16_t kReadLength = Lowpan::FragmentHeader::kSubsequentFragmentHeaderSize + sizeof(Headers);
|
||||
|
||||
uint8_t frameBuffer[kReadLength];
|
||||
uint16_t frameLength;
|
||||
|
||||
frameLength = aMessage.ReadBytes(aOffset, frameBuffer, sizeof(frameBuffer));
|
||||
|
||||
return DecompressFrom(frameBuffer, frameLength, aMacSource, aMacDest, aMessage.GetInstance());
|
||||
}
|
||||
|
||||
Error Headers::DecompressFrom(const uint8_t * aFrame,
|
||||
uint16_t aFrameLength,
|
||||
const Mac::Address &aMacSource,
|
||||
const Mac::Address &aMacDest,
|
||||
Instance & aInstance)
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
Lowpan::FragmentHeader fragmentHeader;
|
||||
uint16_t fragmentHeaderLength;
|
||||
int headerLength;
|
||||
bool nextHeaderCompressed;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
VerifyOrExit(aFrameLength >= 1 && Lowpan::Lowpan::IsLowpanHc(aFrame), error = kErrorNotFound);
|
||||
headerLength = aInstance.Get<Lowpan::Lowpan>().DecompressBaseHeader(mIp6Header, nextHeaderCompressed, aMacSource,
|
||||
aMacDest, aFrame, aFrameLength);
|
||||
|
||||
VerifyOrExit(headerLength > 0, error = kErrorParse);
|
||||
|
||||
aFrame += headerLength;
|
||||
aFrameLength -= headerLength;
|
||||
|
||||
switch (mIp6Header.GetNextHeader())
|
||||
{
|
||||
case kProtoUdp:
|
||||
if (nextHeaderCompressed)
|
||||
{
|
||||
headerLength = aInstance.Get<Lowpan::Lowpan>().DecompressUdpHeader(mHeader.mUdp, aFrame, aFrameLength);
|
||||
VerifyOrExit(headerLength >= 0, error = kErrorParse);
|
||||
}
|
||||
else
|
||||
{
|
||||
VerifyOrExit(aFrameLength >= sizeof(Udp::Header), error = kErrorParse);
|
||||
mHeader.mUdp = *reinterpret_cast<const Udp::Header *>(aFrame);
|
||||
}
|
||||
break;
|
||||
|
||||
case kProtoTcp:
|
||||
VerifyOrExit(aFrameLength >= sizeof(Tcp::Header), error = kErrorParse);
|
||||
mHeader.mTcp = *reinterpret_cast<const Tcp::Header *>(aFrame);
|
||||
break;
|
||||
|
||||
case kProtoIcmp6:
|
||||
VerifyOrExit(aFrameLength >= sizeof(Icmp::Header), error = kErrorParse);
|
||||
mHeader.mIcmp = *reinterpret_cast<const Icmp::Header *>(aFrame);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
uint16_t Headers::GetSourcePort(void) const
|
||||
{
|
||||
uint16_t port = 0;
|
||||
|
||||
switch (GetIpProto())
|
||||
{
|
||||
case kProtoUdp:
|
||||
port = mHeader.mUdp.GetSourcePort();
|
||||
break;
|
||||
|
||||
case kProtoTcp:
|
||||
port = mHeader.mTcp.GetSourcePort();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return port;
|
||||
}
|
||||
|
||||
uint16_t Headers::GetDestinationPort(void) const
|
||||
{
|
||||
uint16_t port = 0;
|
||||
|
||||
switch (GetIpProto())
|
||||
{
|
||||
case kProtoUdp:
|
||||
port = mHeader.mUdp.GetDestinationPort();
|
||||
break;
|
||||
|
||||
case kProtoTcp:
|
||||
port = mHeader.mTcp.GetDestinationPort();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return port;
|
||||
}
|
||||
|
||||
uint16_t Headers::GetChecksum(void) const
|
||||
{
|
||||
uint16_t checksum = 0;
|
||||
|
||||
switch (GetIpProto())
|
||||
{
|
||||
case kProtoUdp:
|
||||
checksum = mHeader.mUdp.GetChecksum();
|
||||
break;
|
||||
|
||||
case kProtoTcp:
|
||||
checksum = mHeader.mTcp.GetChecksum();
|
||||
break;
|
||||
|
||||
case kProtoIcmp6:
|
||||
checksum = mHeader.mIcmp.GetChecksum();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return checksum;
|
||||
}
|
||||
|
||||
} // namespace Ip6
|
||||
} // namespace ot
|
||||
|
||||
@@ -377,6 +377,193 @@ private:
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
* This class represents parsed IPv6 header along with UDP/TCP/ICMP6 headers from a received message/frame.
|
||||
*
|
||||
*/
|
||||
class Headers : private Clearable<Headers>
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* This method parses the IPv6 and UDP/TCP/ICMP6 headers from a given message.
|
||||
*
|
||||
* @param[in] aMessage The message to parse the headers from.
|
||||
*
|
||||
* @retval kErrorNone The headers are parsed successfully.
|
||||
* @retval kErrorParse Failed to parse the headers.
|
||||
*
|
||||
*/
|
||||
Error ParseFrom(const Message &aMessage);
|
||||
|
||||
/**
|
||||
* This method decompresses lowpan frame and parses the IPv6 and UDP/TCP/ICMP6 headers.
|
||||
*
|
||||
* @param[in] aMessage The message from which to read the lowpan frame.
|
||||
* @param[in] aOffset The offset in @p aMessage to start reading the frame.
|
||||
* @param[in] aMacSource The MAC source address.
|
||||
* @param[in] aMacDest The MAC destination address.
|
||||
*
|
||||
* @retval kErrorNone Successfully decompressed and parsed IPv6 and UDP/TCP/ICMP6 headers.
|
||||
* @retval kErrorNotFound Lowpan frame is a next fragment and does not contain IPv6 headers.
|
||||
* @retval kErrorParse Failed to parse the headers.
|
||||
*
|
||||
*/
|
||||
Error DecompressFrom(const Message & aMessage,
|
||||
uint16_t aOffset,
|
||||
const Mac::Address &aMacSource,
|
||||
const Mac::Address &aMacDest);
|
||||
|
||||
/**
|
||||
* This method decompresses lowpan frame and parses the IPv6 and UDP/TCP/ICMP6 headers.
|
||||
*
|
||||
* @param[in] aFrame Buffer containig the lowpan frame.
|
||||
* @param[in] aFrameLength Number of bytes in @p aFrame.
|
||||
* @param[in] aMacSource The MAC source address.
|
||||
* @param[in] aMacDest The MAC destination address.
|
||||
* @param[in] aInstance The OpenThread instance.
|
||||
*
|
||||
* @retval kErrorNone Successfully decompressed and parsed IPv6 and UDP/TCP/ICMP6 headers.
|
||||
* @retval kErrorNotFound Lowpan frame is a next fragment and does not contain IPv6 headers.
|
||||
* @retval kErrorParse Failed to parse the headers.
|
||||
*
|
||||
*/
|
||||
Error DecompressFrom(const uint8_t * aFrame,
|
||||
uint16_t aFrameLength,
|
||||
const Mac::Address &aMacSource,
|
||||
const Mac::Address &aMacDest,
|
||||
Instance & aInstance);
|
||||
|
||||
/**
|
||||
* This method returns the IPv6 header.
|
||||
*
|
||||
* @returns The IPv6 header.
|
||||
*
|
||||
*/
|
||||
const Header &GetIp6Header(void) const { return mIp6Header; }
|
||||
|
||||
/**
|
||||
* This method returns the IP protocol number from IPv6 Next Header field.
|
||||
*
|
||||
* @returns The IP protocol number.
|
||||
*
|
||||
*/
|
||||
uint8_t GetIpProto(void) const { return mIp6Header.GetNextHeader(); }
|
||||
|
||||
/**
|
||||
* This method returns the 2-bit Explicit Congestion Notification (ECN) from Traffic Class field from IPv6 header.
|
||||
*
|
||||
* @returns The ECN value.
|
||||
*
|
||||
*/
|
||||
Ecn GetEcn(void) const { return mIp6Header.GetEcn(); }
|
||||
|
||||
/**
|
||||
* This method indicates if the protocol number from IPv6 header is UDP.
|
||||
*
|
||||
* @retval TRUE If the protocol number in IPv6 header is UDP.
|
||||
* @retval FALSE If the protocol number in IPv6 header is not UDP.
|
||||
*
|
||||
*/
|
||||
bool IsUdp(void) const { return GetIpProto() == kProtoUdp; }
|
||||
|
||||
/**
|
||||
* This method indicates if the protocol number from IPv6 header is TCP.
|
||||
*
|
||||
* @retval TRUE If the protocol number in IPv6 header is TCP.
|
||||
* @retval FALSE If the protocol number in IPv6 header is not TCP.
|
||||
*
|
||||
*/
|
||||
bool IsTcp(void) const { return GetIpProto() == kProtoTcp; }
|
||||
|
||||
/**
|
||||
* This method indicates if the protocol number from IPv6 header is ICMPv6.
|
||||
*
|
||||
* @retval TRUE If the protocol number in IPv6 header is ICMPv6.
|
||||
* @retval FALSE If the protocol number in IPv6 header is not ICMPv6.
|
||||
*
|
||||
*/
|
||||
bool IsIcmp6(void) const { return GetIpProto() == kProtoIcmp6; }
|
||||
|
||||
/**
|
||||
* This method returns the source IPv6 address from IPv6 header.
|
||||
*
|
||||
* @returns The source IPv6 address.
|
||||
*
|
||||
*/
|
||||
const Address &GetSourceAddress(void) const { return mIp6Header.GetSource(); }
|
||||
|
||||
/**
|
||||
* This method returns the destination IPv6 address from IPv6 header.
|
||||
*
|
||||
* @returns The destination IPv6 address.
|
||||
*
|
||||
*/
|
||||
const Address &GetDestinationAddress(void) const { return mIp6Header.GetDestination(); }
|
||||
|
||||
/**
|
||||
* This method returns the UDP header.
|
||||
*
|
||||
* This method MUST be used when `IsUdp() == true`. Otherwise its behavior is undefined
|
||||
*
|
||||
* @returns The UDP header.
|
||||
*
|
||||
*/
|
||||
const Udp::Header &GetUdpHeader(void) const { return mHeader.mUdp; }
|
||||
|
||||
/**
|
||||
* This method returns the TCP header.
|
||||
*
|
||||
* This method MUST be used when `IsTcp() == true`. Otherwise its behavior is undefined
|
||||
*
|
||||
* @returns The TCP header.
|
||||
*
|
||||
*/
|
||||
const Tcp::Header &GetTcpHeader(void) const { return mHeader.mTcp; }
|
||||
|
||||
/**
|
||||
* This method returns the ICMPv6 header.
|
||||
*
|
||||
* This method MUST be used when `IsIcmp6() == true`. Otherwise its behavior is undefined
|
||||
*
|
||||
* @returns The ICMPv6 header.
|
||||
*
|
||||
*/
|
||||
const Icmp::Header &GetIcmpHeader(void) const { return mHeader.mIcmp; }
|
||||
|
||||
/**
|
||||
* This method returns the source port number if header is UDP or TCP, or zero otherwise
|
||||
*
|
||||
* @returns The source port number under UDP / TCP or zero.
|
||||
*
|
||||
*/
|
||||
uint16_t GetSourcePort(void) const;
|
||||
|
||||
/**
|
||||
* This method returns the destination port number if header is UDP or TCP, or zero otherwise.
|
||||
*
|
||||
* @returns The destination port number under UDP / TCP or zero.
|
||||
*
|
||||
*/
|
||||
uint16_t GetDestinationPort(void) const;
|
||||
|
||||
/**
|
||||
* This method returns the checksum values from corresponding UDP, TCP, or ICMPv6 header.
|
||||
*
|
||||
* @returns The checksum value.
|
||||
*
|
||||
*/
|
||||
uint16_t GetChecksum(void) const;
|
||||
|
||||
private:
|
||||
Header mIp6Header;
|
||||
union
|
||||
{
|
||||
Udp::Header mUdp;
|
||||
Tcp::Header mTcp;
|
||||
Icmp::Header mIcmp;
|
||||
} mHeader;
|
||||
};
|
||||
|
||||
/**
|
||||
* @}
|
||||
*
|
||||
|
||||
+12
-16
@@ -52,11 +52,9 @@ RegisterLogModule("Ip6Filter");
|
||||
|
||||
bool Filter::Accept(Message &aMessage) const
|
||||
{
|
||||
bool rval = false;
|
||||
Header ip6;
|
||||
Udp::Header udp;
|
||||
Tcp::Header tcp;
|
||||
uint16_t dstport;
|
||||
bool rval = false;
|
||||
Headers headers;
|
||||
uint16_t dstPort;
|
||||
|
||||
// Allow all received IPv6 datagrams with link security enabled
|
||||
if (aMessage.IsLinkSecurityEnabled())
|
||||
@@ -64,10 +62,11 @@ bool Filter::Accept(Message &aMessage) const
|
||||
ExitNow(rval = true);
|
||||
}
|
||||
|
||||
SuccessOrExit(aMessage.Read(0, ip6));
|
||||
SuccessOrExit(headers.ParseFrom(aMessage));
|
||||
|
||||
// Allow only link-local unicast or multicast
|
||||
VerifyOrExit(ip6.GetDestination().IsLinkLocal() || ip6.GetDestination().IsLinkLocalMulticast());
|
||||
VerifyOrExit(headers.GetDestinationAddress().IsLinkLocal() ||
|
||||
headers.GetDestinationAddress().IsLinkLocalMulticast());
|
||||
|
||||
// Allow all link-local IPv6 datagrams when Thread is not enabled
|
||||
if (Get<Mle::MleRouter>().GetRole() == Mle::kRoleDisabled)
|
||||
@@ -75,14 +74,13 @@ bool Filter::Accept(Message &aMessage) const
|
||||
ExitNow(rval = true);
|
||||
}
|
||||
|
||||
switch (ip6.GetNextHeader())
|
||||
dstPort = headers.GetDestinationPort();
|
||||
|
||||
switch (headers.GetIpProto())
|
||||
{
|
||||
case kProtoUdp:
|
||||
SuccessOrExit(aMessage.Read(sizeof(ip6), udp));
|
||||
dstport = udp.GetDestinationPort();
|
||||
|
||||
// Allow MLE traffic
|
||||
if (dstport == Mle::kUdpPort)
|
||||
if (dstPort == Mle::kUdpPort)
|
||||
{
|
||||
ExitNow(rval = true);
|
||||
}
|
||||
@@ -90,7 +88,7 @@ bool Filter::Accept(Message &aMessage) const
|
||||
#if OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE
|
||||
// Allow native commissioner traffic
|
||||
if (Get<KeyManager>().GetSecurityPolicy().mNativeCommissioningEnabled &&
|
||||
dstport == Get<MeshCoP::BorderAgent>().GetUdpPort())
|
||||
dstPort == Get<MeshCoP::BorderAgent>().GetUdpPort())
|
||||
{
|
||||
ExitNow(rval = true);
|
||||
}
|
||||
@@ -98,8 +96,6 @@ bool Filter::Accept(Message &aMessage) const
|
||||
break;
|
||||
|
||||
case kProtoTcp:
|
||||
SuccessOrExit(aMessage.Read(sizeof(ip6), tcp));
|
||||
dstport = tcp.GetDestinationPort();
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -108,7 +104,7 @@ bool Filter::Accept(Message &aMessage) const
|
||||
}
|
||||
|
||||
// Check against allowed unsecure port list
|
||||
rval = mUnsecurePorts.Contains(dstport);
|
||||
rval = mUnsecurePorts.Contains(dstPort);
|
||||
|
||||
exit:
|
||||
return rval;
|
||||
|
||||
@@ -469,39 +469,6 @@ void MeshForwarder::GetMacDestinationAddress(const Ip6::Address &aIp6Addr, Mac::
|
||||
}
|
||||
}
|
||||
|
||||
Error MeshForwarder::DecompressIp6Header(const uint8_t * aFrame,
|
||||
uint16_t aFrameLength,
|
||||
const Mac::Address &aMacSource,
|
||||
const Mac::Address &aMacDest,
|
||||
Ip6::Header & aIp6Header,
|
||||
uint8_t & aHeaderLength,
|
||||
bool & aNextHeaderCompressed)
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
const uint8_t * start = aFrame;
|
||||
Lowpan::FragmentHeader fragmentHeader;
|
||||
uint16_t fragmentHeaderLength;
|
||||
int headerLength;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
VerifyOrExit(aFrameLength >= 1 && Lowpan::Lowpan::IsLowpanHc(aFrame), error = kErrorNotFound);
|
||||
headerLength = Get<Lowpan::Lowpan>().DecompressBaseHeader(aIp6Header, aNextHeaderCompressed, aMacSource, aMacDest,
|
||||
aFrame, aFrameLength);
|
||||
|
||||
VerifyOrExit(headerLength > 0, error = kErrorParse);
|
||||
aHeaderLength = static_cast<uint8_t>(aFrame - start) + static_cast<uint8_t>(headerLength);
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
Mac::TxFrame *MeshForwarder::HandleFrameRequest(Mac::TxFrames &aTxFrames)
|
||||
{
|
||||
Mac::TxFrame *frame = nullptr;
|
||||
@@ -1525,59 +1492,27 @@ Error MeshForwarder::GetFramePriority(const uint8_t * aFrame,
|
||||
const Mac::Address &aMacDest,
|
||||
Message::Priority & aPriority)
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
Ip6::Header ip6Header;
|
||||
uint16_t dstPort;
|
||||
uint8_t headerLength;
|
||||
bool nextHeaderCompressed;
|
||||
Error error = kErrorNone;
|
||||
Ip6::Headers headers;
|
||||
|
||||
SuccessOrExit(error = DecompressIp6Header(aFrame, aFrameLength, aMacSource, aMacDest, ip6Header, headerLength,
|
||||
nextHeaderCompressed));
|
||||
aPriority = Ip6::Ip6::DscpToPriority(ip6Header.GetDscp());
|
||||
SuccessOrExit(error = headers.DecompressFrom(aFrame, aFrameLength, aMacSource, aMacDest, GetInstance()));
|
||||
|
||||
aFrame += headerLength;
|
||||
aFrameLength -= headerLength;
|
||||
aPriority = Ip6::Ip6::DscpToPriority(headers.GetIp6Header().GetDscp());
|
||||
|
||||
switch (ip6Header.GetNextHeader())
|
||||
// Only ICMPv6 error messages are prioritized.
|
||||
if (headers.IsIcmp6() && headers.GetIcmpHeader().IsError())
|
||||
{
|
||||
case Ip6::kProtoIcmp6:
|
||||
aPriority = Message::kPriorityNet;
|
||||
}
|
||||
|
||||
VerifyOrExit(aFrameLength >= sizeof(Ip6::Icmp::Header), error = kErrorParse);
|
||||
if (headers.IsUdp())
|
||||
{
|
||||
uint16_t destPort = headers.GetUdpHeader().GetDestinationPort();
|
||||
|
||||
// Only ICMPv6 error messages are prioritized.
|
||||
if (reinterpret_cast<const Ip6::Icmp::Header *>(aFrame)->IsError())
|
||||
if ((destPort == Mle::kUdpPort) || (destPort == Tmf::kUdpPort))
|
||||
{
|
||||
aPriority = Message::kPriorityNet;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case Ip6::kProtoUdp:
|
||||
|
||||
if (nextHeaderCompressed)
|
||||
{
|
||||
Ip6::Udp::Header udpHeader;
|
||||
|
||||
VerifyOrExit(Get<Lowpan::Lowpan>().DecompressUdpHeader(udpHeader, aFrame, aFrameLength) >= 0,
|
||||
error = kErrorParse);
|
||||
|
||||
dstPort = udpHeader.GetDestinationPort();
|
||||
}
|
||||
else
|
||||
{
|
||||
VerifyOrExit(aFrameLength >= sizeof(Ip6::Udp::Header), error = kErrorParse);
|
||||
dstPort = reinterpret_cast<const Ip6::Udp::Header *>(aFrame)->GetDestinationPort();
|
||||
}
|
||||
|
||||
if ((dstPort == Mle::kUdpPort) || (dstPort == Tmf::kUdpPort))
|
||||
{
|
||||
aPriority = Message::kPriorityNet;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
exit:
|
||||
@@ -1688,52 +1623,6 @@ uint16_t MeshForwarder::CalcFrameVersion(const Neighbor *aNeighbor, bool aIePres
|
||||
|
||||
// LCOV_EXCL_START
|
||||
|
||||
Error MeshForwarder::ParseIp6UdpTcpHeader(const Message &aMessage,
|
||||
Ip6::Header & aIp6Header,
|
||||
uint16_t & aChecksum,
|
||||
uint16_t & aSourcePort,
|
||||
uint16_t & aDestPort)
|
||||
{
|
||||
Error error = kErrorParse;
|
||||
union
|
||||
{
|
||||
Ip6::Udp::Header udp;
|
||||
Ip6::Tcp::Header tcp;
|
||||
} header;
|
||||
|
||||
aChecksum = 0;
|
||||
aSourcePort = 0;
|
||||
aDestPort = 0;
|
||||
|
||||
SuccessOrExit(aMessage.Read(0, aIp6Header));
|
||||
VerifyOrExit(aIp6Header.IsVersion6());
|
||||
|
||||
switch (aIp6Header.GetNextHeader())
|
||||
{
|
||||
case Ip6::kProtoUdp:
|
||||
SuccessOrExit(aMessage.Read(sizeof(Ip6::Header), header.udp));
|
||||
aChecksum = header.udp.GetChecksum();
|
||||
aSourcePort = header.udp.GetSourcePort();
|
||||
aDestPort = header.udp.GetDestinationPort();
|
||||
break;
|
||||
|
||||
case Ip6::kProtoTcp:
|
||||
SuccessOrExit(aMessage.Read(sizeof(Ip6::Header), header.tcp));
|
||||
aChecksum = header.tcp.GetChecksum();
|
||||
aSourcePort = header.tcp.GetSourcePort();
|
||||
aDestPort = header.tcp.GetDestinationPort();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
error = kErrorNone;
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
#if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_NOTE)
|
||||
|
||||
const char *MeshForwarder::MessageActionToString(MessageAction aAction, Error aError)
|
||||
@@ -1770,31 +1659,31 @@ const char *MeshForwarder::MessagePriorityToString(const Message &aMessage)
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_LOG_SRC_DST_IP_ADDRESSES
|
||||
void MeshForwarder::LogIp6SourceDestAddresses(Ip6::Header &aIp6Header,
|
||||
uint16_t aSourcePort,
|
||||
uint16_t aDestPort,
|
||||
LogLevel aLogLevel)
|
||||
void MeshForwarder::LogIp6SourceDestAddresses(const Ip6::Headers &aHeaders, LogLevel aLogLevel)
|
||||
{
|
||||
if (aSourcePort != 0)
|
||||
uint16_t srcPort = aHeaders.GetSourcePort();
|
||||
uint16_t dstPort = aHeaders.GetDestinationPort();
|
||||
|
||||
if (srcPort != 0)
|
||||
{
|
||||
LogAt(aLogLevel, " src:[%s]:%d", aIp6Header.GetSource().ToString().AsCString(), aSourcePort);
|
||||
LogAt(aLogLevel, " src:[%s]:%d", aHeaders.GetSourceAddress().ToString().AsCString(), srcPort);
|
||||
}
|
||||
else
|
||||
{
|
||||
LogAt(aLogLevel, " src:[%s]", aIp6Header.GetSource().ToString().AsCString());
|
||||
LogAt(aLogLevel, " src:[%s]", aHeaders.GetSourceAddress().ToString().AsCString());
|
||||
}
|
||||
|
||||
if (aDestPort != 0)
|
||||
if (dstPort != 0)
|
||||
{
|
||||
LogAt(aLogLevel, " dst:[%s]:%d", aIp6Header.GetDestination().ToString().AsCString(), aDestPort);
|
||||
LogAt(aLogLevel, " dst:[%s]:%d", aHeaders.GetDestinationAddress().ToString().AsCString(), dstPort);
|
||||
}
|
||||
else
|
||||
{
|
||||
LogAt(aLogLevel, " dst:[%s]", aIp6Header.GetDestination().ToString().AsCString());
|
||||
LogAt(aLogLevel, " dst:[%s]", aHeaders.GetDestinationAddress().ToString().AsCString());
|
||||
}
|
||||
}
|
||||
#else
|
||||
void MeshForwarder::LogIp6SourceDestAddresses(Ip6::Header &, uint16_t, uint16_t, LogLevel)
|
||||
void MeshForwarder::LogIp6SourceDestAddresses(const Ip6::Headers &, LogLevel)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
@@ -1805,15 +1694,12 @@ void MeshForwarder::LogIp6Message(MessageAction aAction,
|
||||
Error aError,
|
||||
LogLevel aLogLevel)
|
||||
{
|
||||
Ip6::Header ip6Header;
|
||||
uint16_t checksum;
|
||||
uint16_t sourcePort;
|
||||
uint16_t destPort;
|
||||
bool shouldLogRss;
|
||||
bool shouldLogRadio = false;
|
||||
const char *radioString = "";
|
||||
Ip6::Headers headers;
|
||||
bool shouldLogRss;
|
||||
bool shouldLogRadio = false;
|
||||
const char * radioString = "";
|
||||
|
||||
SuccessOrExit(ParseIp6UdpTcpHeader(aMessage, ip6Header, checksum, sourcePort, destPort));
|
||||
SuccessOrExit(headers.ParseFrom(aMessage));
|
||||
|
||||
shouldLogRss = (aAction == kMessageReceive) || (aAction == kMessageReassemblyDrop);
|
||||
|
||||
@@ -1823,8 +1709,8 @@ void MeshForwarder::LogIp6Message(MessageAction aAction,
|
||||
#endif
|
||||
|
||||
LogAt(aLogLevel, "%s IPv6 %s msg, len:%d, chksum:%04x, ecn:%s%s%s, sec:%s%s%s, prio:%s%s%s%s%s",
|
||||
MessageActionToString(aAction, aError), Ip6::Ip6::IpProtoToString(ip6Header.GetNextHeader()),
|
||||
aMessage.GetLength(), checksum, Ip6::Ip6::EcnToString(ip6Header.GetEcn()),
|
||||
MessageActionToString(aAction, aError), Ip6::Ip6::IpProtoToString(headers.GetIpProto()), aMessage.GetLength(),
|
||||
headers.GetChecksum(), Ip6::Ip6::EcnToString(headers.GetEcn()),
|
||||
(aMacAddress == nullptr) ? "" : ((aAction == kMessageReceive) ? ", from:" : ", to:"),
|
||||
(aMacAddress == nullptr) ? "" : aMacAddress->ToString().AsCString(),
|
||||
ToYesNo(aMessage.IsLinkSecurityEnabled()),
|
||||
@@ -1835,7 +1721,7 @@ void MeshForwarder::LogIp6Message(MessageAction aAction,
|
||||
|
||||
if (aAction != kMessagePrepareIndirect)
|
||||
{
|
||||
LogIp6SourceDestAddresses(ip6Header, sourcePort, destPort, aLogLevel);
|
||||
LogIp6SourceDestAddresses(headers, aLogLevel);
|
||||
}
|
||||
|
||||
exit:
|
||||
|
||||
@@ -170,7 +170,6 @@ class MeshForwarder : public InstanceLocator, private NonCopyable
|
||||
friend class Ip6::Ip6;
|
||||
friend class Mle::DiscoverScanner;
|
||||
friend class TimeTicker;
|
||||
friend class Utils::HistoryTracker;
|
||||
|
||||
public:
|
||||
/**
|
||||
@@ -390,36 +389,23 @@ private:
|
||||
};
|
||||
#endif // OPENTHREAD_FTD
|
||||
|
||||
void SendIcmpErrorIfDstUnreach(const Message & aMessage,
|
||||
const Mac::Address &aMacSource,
|
||||
const Mac::Address &aMacDest);
|
||||
Error CheckReachability(const uint8_t * aFrame,
|
||||
uint16_t aFrameLength,
|
||||
const Mac::Address &aMeshSource,
|
||||
const Mac::Address &aMeshDest);
|
||||
void UpdateRoutes(const uint8_t * aFrame,
|
||||
uint16_t aFrameLength,
|
||||
const Mac::Address &aMeshSource,
|
||||
const Mac::Address &aMeshDest);
|
||||
|
||||
Error DecompressIp6Header(const uint8_t * aFrame,
|
||||
uint16_t aFrameLength,
|
||||
const Mac::Address &aMacSource,
|
||||
const Mac::Address &aMacDest,
|
||||
Ip6::Header & aIp6Header,
|
||||
uint8_t & aHeaderLength,
|
||||
bool & aNextHeaderCompressed);
|
||||
void SendIcmpErrorIfDstUnreach(const Message & aMessage,
|
||||
const Mac::Address &aMacSource,
|
||||
const Mac::Address &aMacDest);
|
||||
Error CheckReachability(const uint8_t * aFrame,
|
||||
uint16_t aFrameLength,
|
||||
const Mac::Address &aMeshSource,
|
||||
const Mac::Address &aMeshDest);
|
||||
void UpdateRoutes(const uint8_t * aFrame,
|
||||
uint16_t aFrameLength,
|
||||
const Mac::Address &aMeshSource,
|
||||
const Mac::Address &aMeshDest);
|
||||
Error FrameToMessage(const uint8_t * aFrame,
|
||||
uint16_t aFrameLength,
|
||||
uint16_t aDatagramSize,
|
||||
const Mac::Address &aMacSource,
|
||||
const Mac::Address &aMacDest,
|
||||
Message *& aMessage);
|
||||
Error GetIp6Header(const uint8_t * aFrame,
|
||||
uint16_t aFrameLength,
|
||||
const Mac::Address &aMacSource,
|
||||
const Mac::Address &aMacDest,
|
||||
Ip6::Header & aIp6Header);
|
||||
void GetMacDestinationAddress(const Ip6::Address &aIp6Addr, Mac::Address &aMacAddr);
|
||||
void GetMacSourceAddress(const Ip6::Address &aIp6Addr, Mac::Address &aMacAddr);
|
||||
Message *PrepareNextDirectTransmission(void);
|
||||
@@ -527,25 +513,11 @@ private:
|
||||
const Mac::Address &aMacDest,
|
||||
bool aIsSecure);
|
||||
|
||||
static Error ParseIp6UdpTcpHeader(const Message &aMessage,
|
||||
Ip6::Header & aIp6Header,
|
||||
uint16_t & aChecksum,
|
||||
uint16_t & aSourcePort,
|
||||
uint16_t & aDestPort);
|
||||
|
||||
#if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_NOTE)
|
||||
const char *MessageActionToString(MessageAction aAction, Error aError);
|
||||
const char *MessagePriorityToString(const Message &aMessage);
|
||||
|
||||
#if OPENTHREAD_FTD
|
||||
Error DecompressIp6UdpTcpHeader(const Message & aMessage,
|
||||
uint16_t aOffset,
|
||||
const Mac::Address &aMeshSource,
|
||||
const Mac::Address &aMeshDest,
|
||||
Ip6::Header & aIp6Header,
|
||||
uint16_t & aChecksum,
|
||||
uint16_t & aSourcePort,
|
||||
uint16_t & aDestPort);
|
||||
Error LogMeshFragmentHeader(MessageAction aAction,
|
||||
const Message & aMessage,
|
||||
const Mac::Address *aMacAddress,
|
||||
@@ -565,10 +537,7 @@ private:
|
||||
Error aError,
|
||||
LogLevel aLogLevel);
|
||||
#endif
|
||||
void LogIp6SourceDestAddresses(Ip6::Header &aIp6Header,
|
||||
uint16_t aSourcePort,
|
||||
uint16_t aDestPort,
|
||||
LogLevel aLogLevel);
|
||||
void LogIp6SourceDestAddresses(const Ip6::Headers &aHeaders, LogLevel aLogLevel);
|
||||
void LogIp6Message(MessageAction aAction,
|
||||
const Message & aMessage,
|
||||
const Mac::Address *aAddress,
|
||||
|
||||
@@ -632,19 +632,6 @@ exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
Error MeshForwarder::GetIp6Header(const uint8_t * aFrame,
|
||||
uint16_t aFrameLength,
|
||||
const Mac::Address &aMacSource,
|
||||
const Mac::Address &aMacDest,
|
||||
Ip6::Header & aIp6Header)
|
||||
{
|
||||
uint8_t headerLength;
|
||||
bool nextHeaderCompressed;
|
||||
|
||||
return DecompressIp6Header(aFrame, aFrameLength, aMacSource, aMacDest, aIp6Header, headerLength,
|
||||
nextHeaderCompressed);
|
||||
}
|
||||
|
||||
void MeshForwarder::SendIcmpErrorIfDstUnreach(const Message & aMessage,
|
||||
const Mac::Address &aMacSource,
|
||||
const Mac::Address &aMacDest)
|
||||
@@ -826,23 +813,25 @@ void MeshForwarder::UpdateRoutes(const uint8_t * aFrame,
|
||||
const Mac::Address &aMeshSource,
|
||||
const Mac::Address &aMeshDest)
|
||||
{
|
||||
Ip6::Header ip6Header;
|
||||
Neighbor * neighbor;
|
||||
Ip6::Headers ip6Headers;
|
||||
Neighbor * neighbor;
|
||||
|
||||
VerifyOrExit(!aMeshDest.IsBroadcast() && aMeshSource.IsShort());
|
||||
SuccessOrExit(GetIp6Header(aFrame, aFrameLength, aMeshSource, aMeshDest, ip6Header));
|
||||
|
||||
if (!ip6Header.GetSource().GetIid().IsLocator() &&
|
||||
Get<NetworkData::Leader>().IsOnMesh(ip6Header.GetSource()) /* only for on mesh address which may require AQ */)
|
||||
SuccessOrExit(ip6Headers.DecompressFrom(aFrame, aFrameLength, aMeshSource, aMeshDest, GetInstance()));
|
||||
|
||||
if (!ip6Headers.GetSourceAddress().GetIid().IsLocator() &&
|
||||
Get<NetworkData::Leader>().IsOnMesh(ip6Headers.GetSourceAddress()))
|
||||
{
|
||||
// FTDs MAY add/update EID-to-RLOC Map Cache entries by
|
||||
// inspecting packets being received.
|
||||
// inspecting packets being received only for on mesh
|
||||
// addresses.
|
||||
|
||||
Get<AddressResolver>().UpdateSnoopedCacheEntry(ip6Header.GetSource(), aMeshSource.GetShort(),
|
||||
Get<AddressResolver>().UpdateSnoopedCacheEntry(ip6Headers.GetSourceAddress(), aMeshSource.GetShort(),
|
||||
aMeshDest.GetShort());
|
||||
}
|
||||
|
||||
neighbor = Get<NeighborTable>().FindNeighbor(ip6Header.GetSource());
|
||||
neighbor = Get<NeighborTable>().FindNeighbor(ip6Headers.GetSourceAddress());
|
||||
VerifyOrExit(neighbor != nullptr && !neighbor->IsFullThreadDevice());
|
||||
|
||||
if (!Mle::Mle::RouterIdMatch(aMeshSource.GetShort(), Get<Mac::Mac>().GetShortAddress()))
|
||||
@@ -1067,97 +1056,20 @@ exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
Error MeshForwarder::DecompressIp6UdpTcpHeader(const Message & aMessage,
|
||||
uint16_t aOffset,
|
||||
const Mac::Address &aMeshSource,
|
||||
const Mac::Address &aMeshDest,
|
||||
Ip6::Header & aIp6Header,
|
||||
uint16_t & aChecksum,
|
||||
uint16_t & aSourcePort,
|
||||
uint16_t & aDestPort)
|
||||
{
|
||||
Error error = kErrorParse;
|
||||
int headerLength;
|
||||
bool nextHeaderCompressed;
|
||||
uint8_t frameBuffer[sizeof(Ip6::Header)];
|
||||
uint16_t frameLength;
|
||||
union
|
||||
{
|
||||
Ip6::Udp::Header udp;
|
||||
Ip6::Tcp::Header tcp;
|
||||
} header;
|
||||
|
||||
aChecksum = 0;
|
||||
aSourcePort = 0;
|
||||
aDestPort = 0;
|
||||
|
||||
// Read and decompress the IPv6 header
|
||||
|
||||
frameLength = aMessage.ReadBytes(aOffset, frameBuffer, sizeof(frameBuffer));
|
||||
|
||||
headerLength = Get<Lowpan::Lowpan>().DecompressBaseHeader(aIp6Header, nextHeaderCompressed, aMeshSource, aMeshDest,
|
||||
frameBuffer, frameLength);
|
||||
VerifyOrExit(headerLength >= 0);
|
||||
|
||||
aOffset += headerLength;
|
||||
|
||||
// Read and decompress UDP or TCP header
|
||||
|
||||
switch (aIp6Header.GetNextHeader())
|
||||
{
|
||||
case Ip6::kProtoUdp:
|
||||
if (nextHeaderCompressed)
|
||||
{
|
||||
frameLength = aMessage.ReadBytes(aOffset, frameBuffer, sizeof(Ip6::Udp::Header));
|
||||
headerLength = Get<Lowpan::Lowpan>().DecompressUdpHeader(header.udp, frameBuffer, frameLength);
|
||||
VerifyOrExit(headerLength >= 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
SuccessOrExit(aMessage.Read(aOffset, header.udp));
|
||||
}
|
||||
|
||||
aChecksum = header.udp.GetChecksum();
|
||||
aSourcePort = header.udp.GetSourcePort();
|
||||
aDestPort = header.udp.GetDestinationPort();
|
||||
break;
|
||||
|
||||
case Ip6::kProtoTcp:
|
||||
SuccessOrExit(aMessage.Read(aOffset, header.tcp));
|
||||
aChecksum = header.tcp.GetChecksum();
|
||||
aSourcePort = header.tcp.GetSourcePort();
|
||||
aDestPort = header.tcp.GetDestinationPort();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
error = kErrorNone;
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
void MeshForwarder::LogMeshIpHeader(const Message & aMessage,
|
||||
uint16_t aOffset,
|
||||
const Mac::Address &aMeshSource,
|
||||
const Mac::Address &aMeshDest,
|
||||
LogLevel aLogLevel)
|
||||
{
|
||||
uint16_t checksum;
|
||||
uint16_t sourcePort;
|
||||
uint16_t destPort;
|
||||
Ip6::Header ip6Header;
|
||||
Ip6::Headers headers;
|
||||
|
||||
SuccessOrExit(DecompressIp6UdpTcpHeader(aMessage, aOffset, aMeshSource, aMeshDest, ip6Header, checksum, sourcePort,
|
||||
destPort));
|
||||
SuccessOrExit(headers.DecompressFrom(aMessage, aOffset, aMeshSource, aMeshDest));
|
||||
|
||||
LogAt(aLogLevel, " IPv6 %s msg, chksum:%04x, ecn:%s, prio:%s",
|
||||
Ip6::Ip6::IpProtoToString(ip6Header.GetNextHeader()), checksum, Ip6::Ip6::EcnToString(ip6Header.GetEcn()),
|
||||
MessagePriorityToString(aMessage));
|
||||
LogAt(aLogLevel, " IPv6 %s msg, chksum:%04x, ecn:%s, prio:%s", Ip6::Ip6::IpProtoToString(headers.GetIpProto()),
|
||||
headers.GetChecksum(), Ip6::Ip6::EcnToString(headers.GetEcn()), MessagePriorityToString(aMessage));
|
||||
|
||||
LogIp6SourceDestAddresses(ip6Header, sourcePort, destPort, aLogLevel);
|
||||
LogIp6SourceDestAddresses(headers, aLogLevel);
|
||||
|
||||
exit:
|
||||
return;
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
#include "common/locator_getters.hpp"
|
||||
#include "common/string.hpp"
|
||||
#include "common/timer.hpp"
|
||||
#include "net/ip6_headers.hpp"
|
||||
|
||||
namespace ot {
|
||||
namespace Utils {
|
||||
@@ -78,33 +79,26 @@ exit:
|
||||
|
||||
void HistoryTracker::RecordMessage(const Message &aMessage, const Mac::Address &aMacAddresss, MessageType aType)
|
||||
{
|
||||
MessageInfo * entry = nullptr;
|
||||
Ip6::Header ip6Header;
|
||||
Ip6::Icmp::Header icmp6Header;
|
||||
uint8_t ip6Proto;
|
||||
uint16_t checksum;
|
||||
uint16_t sourcePort;
|
||||
uint16_t destPort;
|
||||
MessageInfo *entry = nullptr;
|
||||
Ip6::Headers headers;
|
||||
|
||||
VerifyOrExit(aMessage.GetType() == Message::kTypeIp6);
|
||||
|
||||
SuccessOrExit(MeshForwarder::ParseIp6UdpTcpHeader(aMessage, ip6Header, checksum, sourcePort, destPort));
|
||||
|
||||
ip6Proto = ip6Header.GetNextHeader();
|
||||
SuccessOrExit(headers.ParseFrom(aMessage));
|
||||
|
||||
#if OPENTHREAD_CONFIG_HISTORY_TRACKER_EXCLUDE_THREAD_CONTROL_MESSAGES
|
||||
if (ip6Proto == Ip6::kProtoUdp)
|
||||
if (headers.IsUdp())
|
||||
{
|
||||
uint16_t port = 0;
|
||||
|
||||
switch (aType)
|
||||
{
|
||||
case kRxMessage:
|
||||
port = destPort;
|
||||
port = headers.GetDestinationPort();
|
||||
break;
|
||||
|
||||
case kTxMessage:
|
||||
port = sourcePort;
|
||||
port = headers.GetSourcePort();
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -112,16 +106,6 @@ void HistoryTracker::RecordMessage(const Message &aMessage, const Mac::Address &
|
||||
}
|
||||
#endif
|
||||
|
||||
if (ip6Proto == Ip6::kProtoIcmp6)
|
||||
{
|
||||
SuccessOrExit(aMessage.Read(sizeof(Ip6::Header), icmp6Header));
|
||||
checksum = icmp6Header.GetChecksum();
|
||||
}
|
||||
else
|
||||
{
|
||||
icmp6Header.Clear();
|
||||
}
|
||||
|
||||
switch (aType)
|
||||
{
|
||||
case kRxMessage:
|
||||
@@ -135,15 +119,15 @@ void HistoryTracker::RecordMessage(const Message &aMessage, const Mac::Address &
|
||||
|
||||
VerifyOrExit(entry != nullptr);
|
||||
|
||||
entry->mPayloadLength = ip6Header.GetPayloadLength();
|
||||
entry->mPayloadLength = headers.GetIp6Header().GetPayloadLength();
|
||||
entry->mNeighborRloc16 = aMacAddresss.IsShort() ? aMacAddresss.GetShort() : kInvalidRloc16;
|
||||
entry->mSource.mAddress = ip6Header.GetSource();
|
||||
entry->mSource.mPort = sourcePort;
|
||||
entry->mDestination.mAddress = ip6Header.GetDestination();
|
||||
entry->mDestination.mPort = destPort;
|
||||
entry->mChecksum = checksum;
|
||||
entry->mIpProto = ip6Proto;
|
||||
entry->mIcmp6Type = icmp6Header.GetType();
|
||||
entry->mSource.mAddress = headers.GetSourceAddress();
|
||||
entry->mSource.mPort = headers.GetSourcePort();
|
||||
entry->mDestination.mAddress = headers.GetDestinationAddress();
|
||||
entry->mDestination.mPort = headers.GetDestinationPort();
|
||||
entry->mChecksum = headers.GetChecksum();
|
||||
entry->mIpProto = headers.GetIpProto();
|
||||
entry->mIcmp6Type = headers.IsIcmp6() ? headers.GetIcmpHeader().GetType() : 0;
|
||||
entry->mAveRxRss = (aType == kRxMessage) ? aMessage.GetRssAverager().GetAverage() : kInvalidRss;
|
||||
entry->mLinkSecurity = aMessage.IsLinkSecurityEnabled();
|
||||
entry->mTxSuccess = (aType == kTxMessage) ? aMessage.GetTxSuccess() : true;
|
||||
|
||||
Reference in New Issue
Block a user