mirror of
https://github.com/espressif/openthread.git
synced 2026-08-07 19:27:46 +00:00
[nat64-translator] enhance and harmonize code style (#11847)
This commit updates the `Translator` class to improve code style, readability, and consistency with the OpenThread coding conventions. This is a pure refactoring commit with no intended logic changes. Key changes include: - Renamed types and variables for brevity (e.g., `AddressMapping` to `Mapping`). - Renamed members within the `Mapping` struct for clarity(e.g., `mIp4` to `mIp4Address`). - Standardized local variable names (e.g., `err` to `error`). - Added `const` to methods that do not modify the class state. - Improved and reformatted Doxygen and inline comments.
This commit is contained in:
+227
-184
@@ -66,13 +66,13 @@ const char *StateToString(State aState)
|
||||
Translator::Translator(Instance &aInstance)
|
||||
: InstanceLocator(aInstance)
|
||||
, mState(State::kStateDisabled)
|
||||
, mMappingExpirerTimer(aInstance)
|
||||
, mTimer(aInstance)
|
||||
{
|
||||
Random::NonCrypto::Fill(mNextMappingId);
|
||||
|
||||
mNat64Prefix.Clear();
|
||||
mIp4Cidr.Clear();
|
||||
mMappingExpirerTimer.Start(kAddressMappingIdleTimeoutMsec);
|
||||
mTimer.Start(kIdleTimeout);
|
||||
}
|
||||
|
||||
Message *Translator::NewIp4Message(const Message::Settings &aSettings)
|
||||
@@ -109,38 +109,40 @@ exit:
|
||||
|
||||
Translator::Result Translator::TranslateFromIp6(Message &aMessage)
|
||||
{
|
||||
Result res = kDrop;
|
||||
ErrorCounters::Reason dropReason = ErrorCounters::kUnknown;
|
||||
Ip6::Headers ip6Headers;
|
||||
Ip4::Header ip4Header;
|
||||
uint16_t srcPortOrId = 0;
|
||||
AddressMapping *mapping = nullptr;
|
||||
Result result = kDrop;
|
||||
DropReason dropReason = kReasonUnknown;
|
||||
Ip6::Headers ip6Headers;
|
||||
Ip4::Header ip4Header;
|
||||
uint16_t srcPortOrId = 0;
|
||||
Mapping *mapping = nullptr;
|
||||
|
||||
if (mIp4Cidr.mLength == 0 || !mNat64Prefix.IsValidNat64())
|
||||
{
|
||||
ExitNow(res = kNotTranslated);
|
||||
ExitNow(result = kNotTranslated);
|
||||
}
|
||||
|
||||
// ParseFrom will do basic checks for the message, including the message length and IP protocol version.
|
||||
// `ParseFrom()` will do basic checks for the message, including
|
||||
// the message length and IP protocol version.
|
||||
if (ip6Headers.ParseFrom(aMessage) != kErrorNone)
|
||||
{
|
||||
LogWarn("outgoing datagram is not a valid IPv6 datagram, drop");
|
||||
dropReason = ErrorCounters::Reason::kIllegalPacket;
|
||||
ExitNow(res = kDrop);
|
||||
LogWarn("Outgoing datagram is not a valid IPv6 datagram, drop");
|
||||
dropReason = kReasonIllegalPacket;
|
||||
ExitNow(result = kDrop);
|
||||
}
|
||||
|
||||
if (!ip6Headers.GetDestinationAddress().MatchesPrefix(mNat64Prefix))
|
||||
{
|
||||
ExitNow(res = kNotTranslated);
|
||||
ExitNow(result = kNotTranslated);
|
||||
}
|
||||
|
||||
mapping = FindOrAllocateMapping(ip6Headers);
|
||||
|
||||
if (mapping == nullptr)
|
||||
{
|
||||
LogWarn("failed to get a mapping for %s (mapping pool full?)",
|
||||
LogWarn("Failed to get a mapping for %s (mapping pool full?)",
|
||||
ip6Headers.GetSourceAddress().ToString().AsCString());
|
||||
dropReason = ErrorCounters::Reason::kNoMapping;
|
||||
ExitNow(res = kDrop);
|
||||
dropReason = kReasonNoMapping;
|
||||
ExitNow(result = kDrop);
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_NAT64_PORT_TRANSLATION_ENABLE
|
||||
@@ -153,100 +155,106 @@ Translator::Result Translator::TranslateFromIp6(Message &aMessage)
|
||||
|
||||
ip4Header.Clear();
|
||||
ip4Header.InitVersionIhl();
|
||||
ip4Header.SetSource(mapping->mIp4);
|
||||
ip4Header.SetSource(mapping->mIp4Address);
|
||||
ip4Header.GetDestination().ExtractFromIp6Address(mNat64Prefix.mLength, ip6Headers.GetDestinationAddress());
|
||||
ip4Header.SetTtl(ip6Headers.GetIpHopLimit());
|
||||
ip4Header.SetIdentification(0);
|
||||
|
||||
switch (ip6Headers.GetIpProto())
|
||||
{
|
||||
// The IP header is consumed , so the next header is at offset 0.
|
||||
// The IP header is consumed, so the next header is at offset 0.
|
||||
case Ip6::kProtoUdp:
|
||||
ip4Header.SetProtocol(Ip4::kProtoUdp);
|
||||
ip6Headers.SetSourcePort(srcPortOrId);
|
||||
aMessage.Write(0, ip6Headers.GetUdpHeader());
|
||||
res = kForward;
|
||||
result = kForward;
|
||||
break;
|
||||
case Ip6::kProtoTcp:
|
||||
ip4Header.SetProtocol(Ip4::kProtoTcp);
|
||||
ip6Headers.SetSourcePort(srcPortOrId);
|
||||
aMessage.Write(0, ip6Headers.GetTcpHeader());
|
||||
res = kForward;
|
||||
result = kForward;
|
||||
break;
|
||||
case Ip6::kProtoIcmp6:
|
||||
ip4Header.SetProtocol(Ip4::kProtoIcmp);
|
||||
SuccessOrExit(TranslateIcmp6(aMessage, srcPortOrId));
|
||||
res = kForward;
|
||||
result = kForward;
|
||||
break;
|
||||
default:
|
||||
dropReason = ErrorCounters::Reason::kUnsupportedProto;
|
||||
ExitNow(res = kDrop);
|
||||
dropReason = kReasonUnsupportedProto;
|
||||
ExitNow(result = kDrop);
|
||||
}
|
||||
|
||||
// res here must be kForward based on the switch above.
|
||||
// `result` here must be kForward based on the switch above.
|
||||
// TODO: Implement the logic for replying ICMP messages.
|
||||
ip4Header.SetTotalLength(sizeof(Ip4::Header) + aMessage.GetLength() - aMessage.GetOffset());
|
||||
|
||||
Checksum::UpdateMessageChecksum(aMessage, ip4Header.GetSource(), ip4Header.GetDestination(),
|
||||
ip4Header.GetProtocol());
|
||||
Checksum::UpdateIp4HeaderChecksum(ip4Header);
|
||||
|
||||
if (aMessage.Prepend(ip4Header) != kErrorNone)
|
||||
{
|
||||
// This should never happen since the IPv4 header is shorter than the IPv6 header.
|
||||
// This should never happen since the IPv4 header is shorter
|
||||
// than the IPv6 header.
|
||||
LogCrit("failed to prepend IPv4 head to translated message");
|
||||
ExitNow(res = kDrop);
|
||||
ExitNow(result = kDrop);
|
||||
}
|
||||
|
||||
aMessage.SetType(Message::kTypeIp4);
|
||||
|
||||
mCounters.Count6To4Packet(ip6Headers.GetIpProto(), ip6Headers.GetIpLength());
|
||||
mapping->mCounters.Count6To4Packet(ip6Headers.GetIpProto(), ip6Headers.GetIpLength());
|
||||
|
||||
exit:
|
||||
if (res == Result::kDrop)
|
||||
if (result == kDrop)
|
||||
{
|
||||
mErrorCounters.Count6To4(dropReason);
|
||||
}
|
||||
return res;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Translator::Result Translator::TranslateToIp6(Message &aMessage)
|
||||
{
|
||||
Result res = Result::kDrop;
|
||||
ErrorCounters::Reason dropReason = ErrorCounters::kUnknown;
|
||||
Ip6::Header ip6Header;
|
||||
Ip4::Headers ip4Headers;
|
||||
uint16_t dstPortOrId = 0;
|
||||
AddressMapping *mapping = nullptr;
|
||||
Result result = kDrop;
|
||||
DropReason dropReason = kReasonUnknown;
|
||||
Ip6::Header ip6Header;
|
||||
Ip4::Headers ip4Headers;
|
||||
uint16_t dstPortOrId = 0;
|
||||
Mapping *mapping = nullptr;
|
||||
|
||||
// Ip6::Header::ParseFrom may return an error value when the incoming message is an IPv4 datagram.
|
||||
// If the message is already an IPv6 datagram, forward it directly.
|
||||
VerifyOrExit(ip6Header.ParseFrom(aMessage) != kErrorNone, res = kNotTranslated);
|
||||
// `ParseFrom()` may return an error value when the incoming
|
||||
// message is an IPv4 datagram. If the message is already an IPv6
|
||||
// datagram, forward it directly.
|
||||
VerifyOrExit(ip6Header.ParseFrom(aMessage) != kErrorNone, result = kNotTranslated);
|
||||
|
||||
if (mIp4Cidr.mLength == 0)
|
||||
{
|
||||
// The NAT64 translation is bypassed (will be handled externally)
|
||||
LogWarn("incoming message is an IPv4 datagram but no IPv4 CIDR for NAT64 configured, drop");
|
||||
ExitNow(res = kForward);
|
||||
LogWarn("Incoming message is an IPv4 datagram but no IPv4 CIDR for NAT64 configured, drop");
|
||||
ExitNow(result = kForward);
|
||||
}
|
||||
|
||||
if (!mNat64Prefix.IsValidNat64())
|
||||
{
|
||||
LogWarn("incoming message is an IPv4 datagram but no NAT64 prefix configured, drop");
|
||||
ExitNow(res = kDrop);
|
||||
LogWarn("Incoming message is an IPv4 datagram but no NAT64 prefix configured, drop");
|
||||
ExitNow(result = kDrop);
|
||||
}
|
||||
|
||||
if (ip4Headers.ParseFrom(aMessage) != kErrorNone)
|
||||
{
|
||||
LogWarn("incoming message is neither IPv4 nor an IPv6 datagram, drop");
|
||||
dropReason = ErrorCounters::Reason::kIllegalPacket;
|
||||
ExitNow(res = kDrop);
|
||||
LogWarn("Incoming message is neither IPv4 nor an IPv6 datagram, drop");
|
||||
dropReason = kReasonIllegalPacket;
|
||||
ExitNow(result = kDrop);
|
||||
}
|
||||
|
||||
mapping = FindMapping(ip4Headers);
|
||||
|
||||
if (mapping == nullptr)
|
||||
{
|
||||
LogWarn("no mapping found for the IPv4 address");
|
||||
dropReason = ErrorCounters::Reason::kNoMapping;
|
||||
ExitNow(res = kDrop);
|
||||
LogWarn("No mapping found for the IPv4 address");
|
||||
dropReason = kReasonNoMapping;
|
||||
ExitNow(result = kDrop);
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_NAT64_PORT_TRANSLATION_ENABLE
|
||||
@@ -260,12 +268,14 @@ Translator::Result Translator::TranslateToIp6(Message &aMessage)
|
||||
ip6Header.Clear();
|
||||
ip6Header.InitVersionTrafficClassFlow();
|
||||
ip6Header.GetSource().SynthesizeFromIp4Address(mNat64Prefix, ip4Headers.GetSourceAddress());
|
||||
ip6Header.SetDestination(mapping->mIp6);
|
||||
ip6Header.SetDestination(mapping->mIp6Address);
|
||||
ip6Header.SetFlow(0);
|
||||
ip6Header.SetHopLimit(ip4Headers.GetIpTtl());
|
||||
|
||||
// Note: TCP and UDP are the same for both IPv4 and IPv6 except for the checksum calculation, we will update the
|
||||
// checksum in the payload later. However, we need to translate ICMPv6 messages to ICMP messages in IPv4.
|
||||
// Note: TCP and UDP are the same for both IPv4 and IPv6 except
|
||||
// for the checksum calculation, we will update the checksum in
|
||||
// the payload later. However, we need to translate ICMPv6
|
||||
// messages to ICMP messages in IPv4.
|
||||
switch (ip4Headers.GetIpProto())
|
||||
{
|
||||
// The IP header is consumed , so the next header is at offset 0.
|
||||
@@ -273,95 +283,99 @@ Translator::Result Translator::TranslateToIp6(Message &aMessage)
|
||||
ip6Header.SetNextHeader(Ip6::kProtoUdp);
|
||||
ip4Headers.SetDestinationPort(dstPortOrId);
|
||||
aMessage.Write(0, ip4Headers.GetUdpHeader());
|
||||
res = kForward;
|
||||
result = kForward;
|
||||
break;
|
||||
case Ip4::kProtoTcp:
|
||||
ip6Header.SetNextHeader(Ip6::kProtoTcp);
|
||||
ip4Headers.SetDestinationPort(dstPortOrId);
|
||||
aMessage.Write(0, ip4Headers.GetTcpHeader());
|
||||
res = kForward;
|
||||
result = kForward;
|
||||
break;
|
||||
case Ip4::kProtoIcmp:
|
||||
ip6Header.SetNextHeader(Ip6::kProtoIcmp6);
|
||||
SuccessOrExit(TranslateIcmp4(aMessage, dstPortOrId));
|
||||
res = kForward;
|
||||
result = kForward;
|
||||
break;
|
||||
default:
|
||||
dropReason = ErrorCounters::Reason::kUnsupportedProto;
|
||||
ExitNow(res = kDrop);
|
||||
dropReason = kReasonUnsupportedProto;
|
||||
ExitNow(result = kDrop);
|
||||
}
|
||||
|
||||
// res here must be kForward based on the switch above.
|
||||
// result here must be kForward based on the switch above.
|
||||
// TODO: Implement the logic for replying ICMP datagrams.
|
||||
ip6Header.SetPayloadLength(aMessage.GetLength() - aMessage.GetOffset());
|
||||
|
||||
Checksum::UpdateMessageChecksum(aMessage, ip6Header.GetSource(), ip6Header.GetDestination(),
|
||||
ip6Header.GetNextHeader());
|
||||
|
||||
if (aMessage.Prepend(ip6Header) != kErrorNone)
|
||||
{
|
||||
// This might happen when the platform failed to reserve enough space before the original IPv4 datagram.
|
||||
LogWarn("failed to prepend IPv6 head to translated message");
|
||||
ExitNow(res = kDrop);
|
||||
// This might happen when the platform failed to reserve
|
||||
// enough space before the original IPv4 datagram.
|
||||
LogWarn("Failed to prepend IPv6 head to translated message");
|
||||
ExitNow(result = kDrop);
|
||||
}
|
||||
|
||||
aMessage.SetType(Message::kTypeIp6);
|
||||
|
||||
mCounters.Count4To6Packet(ip4Headers.GetIpProto(), ip4Headers.GetIpLength() - sizeof(Ip4::Header));
|
||||
mapping->mCounters.Count4To6Packet(ip4Headers.GetIpProto(), ip4Headers.GetIpLength() - sizeof(Ip4::Header));
|
||||
|
||||
exit:
|
||||
if (res == Result::kDrop)
|
||||
if (result == kDrop)
|
||||
{
|
||||
mErrorCounters.Count4To6(dropReason);
|
||||
}
|
||||
|
||||
return res;
|
||||
return result;
|
||||
}
|
||||
|
||||
Translator::AddressMapping::InfoString Translator::AddressMapping::ToString(void) const
|
||||
Translator::Mapping::InfoString Translator::Mapping::ToString(void) const
|
||||
{
|
||||
InfoString string;
|
||||
|
||||
string.Append("%s -> %s", mIp6.ToString().AsCString(), mIp4.ToString().AsCString());
|
||||
string.Append("%s -> %s", mIp6Address.ToString().AsCString(), mIp4Address.ToString().AsCString());
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
void Translator::AddressMapping::CopyTo(otNat64AddressMapping &aMapping, TimeMilli aNow) const
|
||||
void Translator::Mapping::CopyTo(AddressMapping &aMapping, TimeMilli aNow) const
|
||||
{
|
||||
aMapping.mId = mId;
|
||||
aMapping.mIp4 = mIp4;
|
||||
aMapping.mIp6 = mIp6;
|
||||
aMapping.mIp4 = mIp4Address;
|
||||
aMapping.mIp6 = mIp6Address;
|
||||
aMapping.mSrcPortOrId = mSrcPortOrId;
|
||||
aMapping.mTranslatedPortOrId = mTranslatedPortOrId;
|
||||
aMapping.mCounters = mCounters;
|
||||
|
||||
// We are removing expired mappings lazily, and an expired mapping might become active again before actually
|
||||
// removed. Report the mapping to be "just expired" to avoid confusion.
|
||||
if (mExpiry < aNow)
|
||||
{
|
||||
aMapping.mRemainingTimeMs = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
aMapping.mRemainingTimeMs = mExpiry - aNow;
|
||||
}
|
||||
// We are removing expired mappings lazily, and an expired mapping
|
||||
// might become active again before actually removed. Report the
|
||||
// mapping to be "just expired" to avoid confusion.
|
||||
|
||||
aMapping.mRemainingTimeMs = (mExpiry < aNow) ? 0 : mExpiry - aNow;
|
||||
}
|
||||
|
||||
void Translator::ReleaseMapping(AddressMapping &aMapping)
|
||||
void Translator::ReleaseMapping(Mapping &aMapping)
|
||||
{
|
||||
if (mIp4Cidr.mLength <= kMaxCidrLenForValidAddrPool)
|
||||
{
|
||||
// IPv4 addresses are allocated from the pool only when the pool size is above a minimum value.
|
||||
// Otherwise use just the first address from the list and we are not removing it from the array.
|
||||
IgnoreError(mIp4AddressPool.PushBack(aMapping.mIp4));
|
||||
// IPv4 addresses are allocated from the pool only when the
|
||||
// pool size is above a minimum value. Otherwise use just the
|
||||
// first address from the list and we are not removing it
|
||||
// from the array.
|
||||
IgnoreError(mIp4AddressPool.PushBack(aMapping.mIp4Address));
|
||||
}
|
||||
mAddressMappingPool.Free(aMapping);
|
||||
LogInfo("mapping removed: %s", aMapping.ToString().AsCString());
|
||||
|
||||
mMappingPool.Free(aMapping);
|
||||
|
||||
LogInfo("Mapping removed: %s", aMapping.ToString().AsCString());
|
||||
}
|
||||
|
||||
uint16_t Translator::ReleaseMappings(LinkedList<AddressMapping> &aMappings)
|
||||
uint16_t Translator::ReleaseMappings(LinkedList<Mapping> &aMappings)
|
||||
{
|
||||
uint16_t numRemoved = 0;
|
||||
|
||||
for (AddressMapping *mapping = aMappings.Pop(); mapping != nullptr; mapping = aMappings.Pop())
|
||||
for (Mapping *mapping = aMappings.Pop(); mapping != nullptr; mapping = aMappings.Pop())
|
||||
{
|
||||
numRemoved++;
|
||||
ReleaseMapping(*mapping);
|
||||
@@ -372,46 +386,57 @@ uint16_t Translator::ReleaseMappings(LinkedList<AddressMapping> &aMappings)
|
||||
|
||||
uint16_t Translator::ReleaseExpiredMappings(void)
|
||||
{
|
||||
LinkedList<AddressMapping> idleMappings;
|
||||
LinkedList<Mapping> idleMappings;
|
||||
|
||||
mActiveAddressMappings.RemoveAllMatching(idleMappings, TimerMilli::GetNow());
|
||||
mActiveMappings.RemoveAllMatching(idleMappings, TimerMilli::GetNow());
|
||||
|
||||
return ReleaseMappings(idleMappings);
|
||||
}
|
||||
#if OPENTHREAD_CONFIG_NAT64_PORT_TRANSLATION_ENABLE
|
||||
uint16_t Translator::AllocateSourcePort(uint16_t aSrcPort)
|
||||
{
|
||||
// The translated port is randomly allocated from the range of dynamic or private ports (RFC 7605 section 4).
|
||||
// In this way, we will not pick a random port that could be a well-known port preventing an unknown situation on
|
||||
// the receiver side.
|
||||
uint16_t retPort;
|
||||
// The translated port is randomly allocated from the range of
|
||||
// dynamic or private ports (RFC 7605 section 4). In this way, we
|
||||
// will not pick a random port that could be a well-known port
|
||||
// preventing an unknown situation on the receiver side.
|
||||
|
||||
uint16_t port;
|
||||
|
||||
do
|
||||
{
|
||||
retPort = Random::NonCrypto::GetUint16InRange(kTranslationPortRangeStart, kTranslationPortRangeEnd);
|
||||
// The NAT64 SHOULD preserve the port parity (odd/even), as per Section 4.2.2 of [RFC4787]).
|
||||
// Determine if original and allocated port have different parity
|
||||
if (((aSrcPort ^ retPort) & 1) == 1)
|
||||
{
|
||||
retPort++;
|
||||
}
|
||||
} while (mActiveAddressMappings.ContainsMatching(retPort));
|
||||
port = Random::NonCrypto::GetUint16InRange(kMinTranslationPort, kMaxTranslationPort);
|
||||
|
||||
return retPort;
|
||||
// The NAT64 SHOULD preserve the port parity (odd/even), as
|
||||
// per Section 4.2.2 of [RFC4787]). Determine if original and
|
||||
// allocated port have different parity
|
||||
|
||||
if (((aSrcPort ^ port) & 1) == 1)
|
||||
{
|
||||
port++;
|
||||
}
|
||||
|
||||
} while (mActiveMappings.ContainsMatching(port));
|
||||
|
||||
return port;
|
||||
}
|
||||
#endif
|
||||
|
||||
Translator::AddressMapping *Translator::AllocateMapping(const Ip6::Headers &aIp6Headers)
|
||||
Translator::Mapping *Translator::AllocateMapping(const Ip6::Headers &aIp6Headers)
|
||||
{
|
||||
AddressMapping *mapping = nullptr;
|
||||
Ip4::Address ip4Addr;
|
||||
Mapping *mapping = nullptr;
|
||||
Ip4::Address ip4Addr;
|
||||
|
||||
// The NAT64 translator can work in 2 ways, either with a single
|
||||
// IPv4 address or a larger pool of addresses. There is also the
|
||||
// corner case where the address pool is generated from a big
|
||||
// CIDR length and the number of available IPv4 addresses is not
|
||||
// big enough to apply a 1 to 1 translation from IPv6 to IPv4
|
||||
// address. When operating in the first case, there is no need to
|
||||
// manage the address pool and all active mappings will use 1
|
||||
// single address (or the limited number alternatively). If a
|
||||
// larger pool is available each active mapping will use a
|
||||
// separate IPv4 address.
|
||||
|
||||
// The NAT64 translator can work in 2 ways, either with a single IPv4 address or a larger pool of addresses. There
|
||||
// is also the corner case where the address pool is generated from a big CIDR length and the number of available
|
||||
// IPv4 addresses is not big enough to apply a 1 to 1 translation from IPv6 to IPv4 address. When operating in the
|
||||
// first case, there is no need to manage the address pool and all active mappings will use 1 single address (or the
|
||||
// limited number alternatively). If a larger pool is available each active mapping will use a separate IPv4
|
||||
// address.
|
||||
if (mIp4Cidr.mLength > kMaxCidrLenForValidAddrPool)
|
||||
{
|
||||
// TODO: add logic to cycle between available IPv4 addresses
|
||||
@@ -421,44 +446,47 @@ Translator::AddressMapping *Translator::AllocateMapping(const Ip6::Headers &aIp6
|
||||
{
|
||||
if (mIp4AddressPool.IsEmpty())
|
||||
{
|
||||
// ReleaseExpiredMappings returns the number of mappings removed.
|
||||
// `ReleaseExpiredMappings()` returns the number of
|
||||
// mappings removed.
|
||||
|
||||
VerifyOrExit(ReleaseExpiredMappings() > 0);
|
||||
}
|
||||
ip4Addr = *mIp4AddressPool.PopBack();
|
||||
}
|
||||
|
||||
mapping = mAddressMappingPool.Allocate();
|
||||
// We should get a valid item, there is enough space in the mapping pool. Otherwise return null and fail the
|
||||
// translation.
|
||||
mapping = mMappingPool.Allocate();
|
||||
|
||||
// We should get a valid item, there is enough space in the
|
||||
// mapping pool. Otherwise return null and fail the translation.
|
||||
VerifyOrExit(mapping != nullptr);
|
||||
|
||||
mActiveAddressMappings.Push(*mapping);
|
||||
mActiveMappings.Push(*mapping);
|
||||
mapping->mCounters.Clear();
|
||||
mapping->mId = ++mNextMappingId;
|
||||
mapping->mIp6 = aIp6Headers.GetSourceAddress();
|
||||
mapping->mIp4 = ip4Addr;
|
||||
mapping->mId = ++mNextMappingId;
|
||||
mapping->mIp6Address = aIp6Headers.GetSourceAddress();
|
||||
mapping->mIp4Address = ip4Addr;
|
||||
#if OPENTHREAD_CONFIG_NAT64_PORT_TRANSLATION_ENABLE
|
||||
mapping->mSrcPortOrId = aIp6Headers.IsIcmp6() ? aIp6Headers.GetIcmpHeader().GetId() : aIp6Headers.GetSourcePort();
|
||||
// Allocate a unique source port or ICMP Id
|
||||
mapping->mTranslatedPortOrId = AllocateSourcePort(mapping->mSrcPortOrId);
|
||||
#else
|
||||
mapping->mSrcPortOrId = 0;
|
||||
mapping->mTranslatedPortOrId = 0;
|
||||
#endif
|
||||
mapping->Touch(TimerMilli::GetNow(), aIp6Headers.GetIpProto());
|
||||
LogInfo("mapping created: %s", mapping->ToString().AsCString());
|
||||
|
||||
LogInfo("Mapping created: %s", mapping->ToString().AsCString());
|
||||
|
||||
exit:
|
||||
return mapping;
|
||||
}
|
||||
|
||||
Translator::AddressMapping *Translator::FindOrAllocateMapping(const Ip6::Headers &aIp6Headers)
|
||||
Translator::Mapping *Translator::FindOrAllocateMapping(const Ip6::Headers &aIp6Headers)
|
||||
{
|
||||
#if OPENTHREAD_CONFIG_NAT64_PORT_TRANSLATION_ENABLE
|
||||
uint16_t srcPortOrId = aIp6Headers.IsIcmp6() ? aIp6Headers.GetIcmpHeader().GetId() : aIp6Headers.GetSourcePort();
|
||||
AddressMapping *mapping = mActiveAddressMappings.FindMatching(aIp6Headers.GetSourceAddress(), srcPortOrId);
|
||||
uint16_t srcPortOrId = aIp6Headers.IsIcmp6() ? aIp6Headers.GetIcmpHeader().GetId() : aIp6Headers.GetSourcePort();
|
||||
Mapping *mapping = mActiveMappings.FindMatching(aIp6Headers.GetSourceAddress(), srcPortOrId);
|
||||
#else
|
||||
AddressMapping *mapping = mActiveAddressMappings.FindMatching(aIp6Headers.GetSourceAddress());
|
||||
Mapping *mapping = mActiveMappings.FindMatching(aIp6Headers.GetSourceAddress());
|
||||
#endif
|
||||
|
||||
// Exit if we found a valid mapping.
|
||||
@@ -470,15 +498,15 @@ exit:
|
||||
return mapping;
|
||||
}
|
||||
|
||||
Translator::AddressMapping *Translator::FindMapping(const Ip4::Headers &aIp4Headers)
|
||||
Translator::Mapping *Translator::FindMapping(const Ip4::Headers &aIp4Headers)
|
||||
{
|
||||
uint16_t dstPortOrId =
|
||||
aIp4Headers.IsIcmp4() ? aIp4Headers.GetIcmpHeader().GetId() : aIp4Headers.GetDestinationPort();
|
||||
|
||||
#if OPENTHREAD_CONFIG_NAT64_PORT_TRANSLATION_ENABLE
|
||||
AddressMapping *mapping = mActiveAddressMappings.FindMatching(aIp4Headers.GetDestinationAddress(), dstPortOrId);
|
||||
Mapping *mapping = mActiveMappings.FindMatching(aIp4Headers.GetDestinationAddress(), dstPortOrId);
|
||||
#else
|
||||
AddressMapping *mapping = mActiveAddressMappings.FindMatching(aIp4Headers.GetDestinationAddress());
|
||||
Mapping *mapping = mActiveMappings.FindMatching(aIp4Headers.GetDestinationAddress());
|
||||
OT_UNUSED_VARIABLE(dstPortOrId);
|
||||
#endif
|
||||
|
||||
@@ -489,93 +517,108 @@ Translator::AddressMapping *Translator::FindMapping(const Ip4::Headers &aIp4Head
|
||||
return mapping;
|
||||
}
|
||||
|
||||
void Translator::AddressMapping::Touch(TimeMilli aNow, uint8_t aProtocol)
|
||||
void Translator::Mapping::Touch(TimeMilli aNow, uint8_t aProtocol)
|
||||
{
|
||||
if ((aProtocol == Ip6::kProtoIcmp6) || (aProtocol == Ip4::kProtoIcmp))
|
||||
{
|
||||
mExpiry = aNow + kAddressMappingIcmpIdleTimeoutMsec;
|
||||
mExpiry = aNow + kIcmpTimeout;
|
||||
}
|
||||
else
|
||||
{
|
||||
mExpiry = aNow + kAddressMappingIdleTimeoutMsec;
|
||||
mExpiry = aNow + kIdleTimeout;
|
||||
}
|
||||
}
|
||||
|
||||
bool Translator::Mapping::Matches(const Ip6::Address &aIp6Address, const uint16_t aPort) const
|
||||
{
|
||||
return ((mIp6Address == aIp6Address) && (mSrcPortOrId == aPort));
|
||||
}
|
||||
|
||||
bool Translator::Mapping::Matches(const Ip4::Address &aIp4Address, const uint16_t aPort) const
|
||||
{
|
||||
return ((mIp4Address == aIp4Address) && (mTranslatedPortOrId == aPort));
|
||||
}
|
||||
|
||||
Error Translator::TranslateIcmp4(Message &aMessage, uint16_t aOriginalId)
|
||||
{
|
||||
Error err = kErrorNone;
|
||||
Error error = kErrorNone;
|
||||
Ip4::Icmp::Header icmp4Header;
|
||||
Ip6::Icmp::Header icmp6Header;
|
||||
|
||||
// TODO: Implement the translation of other ICMP messages.
|
||||
|
||||
// Note: The caller consumed the IP header, so the ICMP header is at offset 0.
|
||||
SuccessOrExit(err = aMessage.Read(0, icmp4Header));
|
||||
// Note: The caller consumed the IP header, so the ICMP header is
|
||||
// at offset 0.
|
||||
SuccessOrExit(error = aMessage.Read(0, icmp4Header));
|
||||
|
||||
switch (icmp4Header.GetType())
|
||||
{
|
||||
case Ip4::Icmp::Header::Type::kTypeEchoReply:
|
||||
{
|
||||
// The only difference between ICMPv6 echo and ICMP4 echo is the message type field, so we can reinterpret it as
|
||||
// ICMP6 header and set the message type.
|
||||
SuccessOrExit(err = aMessage.Read(0, icmp6Header));
|
||||
icmp6Header.SetType(Ip6::Icmp::Header::Type::kTypeEchoReply);
|
||||
// The only difference between ICMPv6 echo and ICMP4 echo is
|
||||
// the message type field, so we can reinterpret it as ICMP6
|
||||
// header and set the message type.
|
||||
SuccessOrExit(error = aMessage.Read(0, icmp6Header));
|
||||
icmp6Header.SetType(Ip6::Icmp::Header::kTypeEchoReply);
|
||||
icmp6Header.SetId(aOriginalId);
|
||||
aMessage.Write(0, icmp6Header);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
err = kErrorInvalidArgs;
|
||||
error = kErrorInvalidArgs;
|
||||
break;
|
||||
}
|
||||
|
||||
exit:
|
||||
return err;
|
||||
return error;
|
||||
}
|
||||
|
||||
Error Translator::TranslateIcmp6(Message &aMessage, uint16_t aTranslatedId)
|
||||
{
|
||||
Error err = kErrorNone;
|
||||
Error error = kErrorNone;
|
||||
Ip4::Icmp::Header icmp4Header;
|
||||
Ip6::Icmp::Header icmp6Header;
|
||||
|
||||
// TODO: Implement the translation of other ICMP messages.
|
||||
|
||||
// Note: The caller have consumed the IP header, so the ICMP header is at offset 0.
|
||||
SuccessOrExit(err = aMessage.Read(0, icmp6Header));
|
||||
// Note: The caller have consumed the IP header, so the ICMP
|
||||
// header is at offset 0.
|
||||
SuccessOrExit(error = aMessage.Read(0, icmp6Header));
|
||||
|
||||
switch (icmp6Header.GetType())
|
||||
{
|
||||
case Ip6::Icmp::Header::Type::kTypeEchoRequest:
|
||||
{
|
||||
// The only difference between ICMPv6 echo and ICMP4 echo is the message type field, so we can reinterpret it as
|
||||
// ICMP6 header and set the message type.
|
||||
SuccessOrExit(err = aMessage.Read(0, icmp4Header));
|
||||
case Ip6::Icmp::Header::kTypeEchoRequest:
|
||||
// The only difference between ICMPv6 echo and ICMP4 echo is
|
||||
// the message type field, so we can reinterpret it as ICMP6
|
||||
// header and set the message type.
|
||||
SuccessOrExit(error = aMessage.Read(0, icmp4Header));
|
||||
icmp4Header.SetType(Ip4::Icmp::Header::Type::kTypeEchoRequest);
|
||||
icmp4Header.SetId(aTranslatedId);
|
||||
aMessage.Write(0, icmp4Header);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
err = kErrorInvalidArgs;
|
||||
error = kErrorInvalidArgs;
|
||||
break;
|
||||
}
|
||||
|
||||
exit:
|
||||
return err;
|
||||
return error;
|
||||
}
|
||||
|
||||
Error Translator::SetIp4Cidr(const Ip4::Cidr &aCidr)
|
||||
{
|
||||
Error err = kErrorNone;
|
||||
Error error = kErrorNone;
|
||||
|
||||
uint32_t numberOfHosts;
|
||||
uint32_t hostIdBegin;
|
||||
|
||||
VerifyOrExit(aCidr.mLength > 0 && aCidr.mLength <= 32, err = kErrorInvalidArgs);
|
||||
VerifyOrExit(aCidr.mLength > 0 && aCidr.mLength <= 32, error = kErrorInvalidArgs);
|
||||
|
||||
VerifyOrExit(mIp4Cidr != aCidr);
|
||||
|
||||
// Avoid using the 0s and 1s in the host id of an address, but what if the user provides us with /32 or /31
|
||||
// addresses?
|
||||
// Avoid using the 0s and 1s in the host id of an address, but
|
||||
// what if the user provides us with /32 or /31 addresses?
|
||||
|
||||
if (aCidr.mLength == 32)
|
||||
{
|
||||
hostIdBegin = 0;
|
||||
@@ -591,10 +634,11 @@ Error Translator::SetIp4Cidr(const Ip4::Cidr &aCidr)
|
||||
hostIdBegin = 1;
|
||||
numberOfHosts = static_cast<uint32_t>((1 << (Ip4::Address::kSize * 8 - aCidr.mLength)) - 2);
|
||||
}
|
||||
numberOfHosts = OT_MIN(numberOfHosts, kAddressMappingPoolSize);
|
||||
|
||||
mAddressMappingPool.FreeAll();
|
||||
mActiveAddressMappings.Clear();
|
||||
numberOfHosts = OT_MIN(numberOfHosts, kPoolSize);
|
||||
|
||||
mMappingPool.FreeAll();
|
||||
mActiveMappings.Clear();
|
||||
mIp4AddressPool.Clear();
|
||||
|
||||
for (uint32_t i = 0; i < numberOfHosts; i++)
|
||||
@@ -608,22 +652,22 @@ Error Translator::SetIp4Cidr(const Ip4::Cidr &aCidr)
|
||||
LogInfo("IPv4 CIDR for NAT64: %s (actual address pool: %s - %s, %lu addresses)", aCidr.ToString().AsCString(),
|
||||
mIp4AddressPool.Front()->ToString().AsCString(), mIp4AddressPool.Back()->ToString().AsCString(),
|
||||
ToUlong(numberOfHosts));
|
||||
|
||||
mIp4Cidr = aCidr;
|
||||
|
||||
UpdateState();
|
||||
|
||||
// Notify the platform when the CIDR is changed.
|
||||
Get<Notifier>().Signal(kEventNat64TranslatorStateChanged);
|
||||
|
||||
exit:
|
||||
return err;
|
||||
return error;
|
||||
}
|
||||
|
||||
void Translator::ClearIp4Cidr(void)
|
||||
{
|
||||
mIp4Cidr.Clear();
|
||||
mAddressMappingPool.FreeAll();
|
||||
mActiveAddressMappings.Clear();
|
||||
mMappingPool.FreeAll();
|
||||
mActiveMappings.Clear();
|
||||
mIp4AddressPool.Clear();
|
||||
|
||||
UpdateState();
|
||||
@@ -654,58 +698,57 @@ exit:
|
||||
return;
|
||||
}
|
||||
|
||||
void Translator::HandleMappingExpirerTimer(void)
|
||||
void Translator::HandleTimer(void)
|
||||
{
|
||||
uint16_t numReleased = ReleaseExpiredMappings();
|
||||
|
||||
LogInfo("Released %u expired mappings", numReleased);
|
||||
|
||||
mMappingExpirerTimer.Start(Min(kAddressMappingIcmpIdleTimeoutMsec, kAddressMappingIdleTimeoutMsec));
|
||||
mTimer.Start(Min(kIcmpTimeout, kIdleTimeout));
|
||||
|
||||
OT_UNUSED_VARIABLE(numReleased);
|
||||
}
|
||||
|
||||
void Translator::InitAddressMappingIterator(AddressMappingIterator &aIterator)
|
||||
{
|
||||
aIterator.mPtr = mActiveAddressMappings.GetHead();
|
||||
aIterator.mPtr = mActiveMappings.GetHead();
|
||||
}
|
||||
|
||||
Error Translator::GetNextAddressMapping(AddressMappingIterator &aIterator, otNat64AddressMapping &aMapping)
|
||||
Error Translator::GetNextAddressMapping(AddressMappingIterator &aIterator, AddressMapping &aMapping)
|
||||
{
|
||||
Error err = kErrorNotFound;
|
||||
TimeMilli now = TimerMilli::GetNow();
|
||||
AddressMapping *item = static_cast<AddressMapping *>(aIterator.mPtr);
|
||||
Error error = kErrorNotFound;
|
||||
Mapping *mapping = static_cast<Mapping *>(aIterator.mPtr);
|
||||
|
||||
VerifyOrExit(item != nullptr);
|
||||
VerifyOrExit(mapping != nullptr);
|
||||
|
||||
item->CopyTo(aMapping, now);
|
||||
aIterator.mPtr = item->GetNext();
|
||||
err = kErrorNone;
|
||||
mapping->CopyTo(aMapping, TimerMilli::GetNow());
|
||||
aIterator.mPtr = mapping->GetNext();
|
||||
error = kErrorNone;
|
||||
|
||||
exit:
|
||||
return err;
|
||||
return error;
|
||||
}
|
||||
|
||||
Error Translator::GetIp4Cidr(Ip4::Cidr &aCidr)
|
||||
Error Translator::GetIp4Cidr(Ip4::Cidr &aCidr) const
|
||||
{
|
||||
Error err = kErrorNone;
|
||||
Error error = kErrorNone;
|
||||
|
||||
VerifyOrExit(mIp4Cidr.mLength > 0, err = kErrorNotFound);
|
||||
VerifyOrExit(mIp4Cidr.mLength > 0, error = kErrorNotFound);
|
||||
aCidr = mIp4Cidr;
|
||||
|
||||
exit:
|
||||
return err;
|
||||
return error;
|
||||
}
|
||||
|
||||
Error Translator::GetIp6Prefix(Ip6::Prefix &aPrefix)
|
||||
Error Translator::GetIp6Prefix(Ip6::Prefix &aPrefix) const
|
||||
{
|
||||
Error err = kErrorNone;
|
||||
Error error = kErrorNone;
|
||||
|
||||
VerifyOrExit(mNat64Prefix.mLength > 0, err = kErrorNotFound);
|
||||
VerifyOrExit(mNat64Prefix.mLength > 0, error = kErrorNotFound);
|
||||
aPrefix = mNat64Prefix;
|
||||
|
||||
exit:
|
||||
return err;
|
||||
return error;
|
||||
}
|
||||
|
||||
void Translator::ProtocolCounters::Count6To4Packet(uint8_t aProtocol, uint64_t aPacketSize)
|
||||
@@ -786,7 +829,7 @@ void Translator::SetEnabled(bool aEnabled)
|
||||
|
||||
if (!aEnabled)
|
||||
{
|
||||
ReleaseMappings(mActiveAddressMappings);
|
||||
ReleaseMappings(mActiveMappings);
|
||||
}
|
||||
|
||||
UpdateState();
|
||||
|
||||
@@ -72,32 +72,18 @@ const char *StateToString(State aState);
|
||||
class Translator : public InstanceLocator, private NonCopyable
|
||||
{
|
||||
public:
|
||||
static constexpr uint32_t kAddressMappingIdleTimeoutMsec =
|
||||
OPENTHREAD_CONFIG_NAT64_IDLE_TIMEOUT_SECONDS * Time::kOneSecondInMsec;
|
||||
// ICMP mappings can expire fast since the identifier field will usually be the same only for
|
||||
// a ping sessing that can have multiple ping requests. Once a new session is started the
|
||||
// identifier will change.
|
||||
static constexpr uint32_t kAddressMappingIcmpIdleTimeoutMsec =
|
||||
OPENTHREAD_CONFIG_NAT64_ICMP_IDLE_TIMEOUT_SECONDS * Time::kOneSecondInMsec;
|
||||
static constexpr uint32_t kAddressMappingPoolSize = OPENTHREAD_CONFIG_NAT64_MAX_MAPPINGS;
|
||||
static constexpr uint16_t kTranslationPortRangeStart = 49152;
|
||||
static constexpr uint16_t kTranslationPortRangeEnd = 65535;
|
||||
// The maximum value the CIDR len can have in order to have a big enough pool to support a
|
||||
// minimal number of devices
|
||||
static constexpr uint8_t kMaxCidrLenForValidAddrPool = 28;
|
||||
|
||||
typedef otNat64AddressMapping AddressMapping; ///< Address mapping.
|
||||
typedef otNat64AddressMappingIterator AddressMappingIterator; ///< Address mapping Iterator.
|
||||
typedef otNat64DropReason DropReason; ///< Drop reason.
|
||||
|
||||
/**
|
||||
* The possible results of NAT64 translation.
|
||||
*/
|
||||
enum Result : uint8_t
|
||||
{
|
||||
kNotTranslated, ///< The message is not translated, it might be sending to an non-nat64 prefix (for outgoing
|
||||
///< datagrams), or it is already an IPv6 message (for incoming datagrams).
|
||||
kForward, ///< Message is successfully translated, the caller should continue forwarding the translated
|
||||
///< datagram.
|
||||
kDrop, ///< The caller should drop the datagram silently.
|
||||
kNotTranslated, ///< Not translated (e.g., Outgoing msg using a non-NAT64 prefix, or incoming is already IPv6).
|
||||
kForward, ///< Successfully translated and the translated message should be forwarded.
|
||||
kDrop, ///< Silently drop the message.
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -105,21 +91,10 @@ public:
|
||||
*/
|
||||
class ProtocolCounters : public otNat64ProtocolCounters, public Clearable<ProtocolCounters>
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Adds the packet to the counter for the given IPv6 protocol.
|
||||
*
|
||||
* @param[in] aProtocol The protocol of the packet.
|
||||
* @param[in] aPacketSize The size of the packet.
|
||||
*/
|
||||
void Count6To4Packet(uint8_t aProtocol, uint64_t aPacketSize);
|
||||
friend class Translator;
|
||||
|
||||
/**
|
||||
* Adds the packet to the counter for the given IPv4 protocol.
|
||||
*
|
||||
* @param[in] aProtocol The protocol of the packet.
|
||||
* @param[in] aPacketSize The size of the packet.
|
||||
*/
|
||||
private:
|
||||
void Count6To4Packet(uint8_t aProtocol, uint64_t aPacketSize);
|
||||
void Count4To6Packet(uint8_t aProtocol, uint64_t aPacketSize);
|
||||
};
|
||||
|
||||
@@ -128,32 +103,17 @@ public:
|
||||
*/
|
||||
class ErrorCounters : public otNat64ErrorCounters, public Clearable<otNat64ErrorCounters>
|
||||
{
|
||||
friend class Translator;
|
||||
|
||||
public:
|
||||
enum Reason : uint8_t
|
||||
{
|
||||
kUnknown = OT_NAT64_DROP_REASON_UNKNOWN,
|
||||
kIllegalPacket = OT_NAT64_DROP_REASON_ILLEGAL_PACKET,
|
||||
kUnsupportedProto = OT_NAT64_DROP_REASON_UNSUPPORTED_PROTO,
|
||||
kNoMapping = OT_NAT64_DROP_REASON_NO_MAPPING,
|
||||
};
|
||||
|
||||
/**
|
||||
* Adds the counter for the given reason when translating an IPv4 datagram.
|
||||
*
|
||||
* @param[in] aReason The reason of packet drop.
|
||||
*/
|
||||
void Count4To6(Reason aReason) { mCount4To6[aReason]++; }
|
||||
|
||||
/**
|
||||
* Adds the counter for the given reason when translating an IPv6 datagram.
|
||||
*
|
||||
* @param[in] aReason The reason of packet drop.
|
||||
*/
|
||||
void Count6To4(Reason aReason) { mCount6To4[aReason]++; }
|
||||
void Count4To6(DropReason aReason) { mCount4To6[aReason]++; }
|
||||
void Count6To4(DropReason aReason) { mCount6To4[aReason]++; }
|
||||
};
|
||||
|
||||
/**
|
||||
* Initializes the NAT64 translator.
|
||||
*
|
||||
* @param[in] aInstance The OpenThread instance.
|
||||
*/
|
||||
explicit Translator(Instance &aInstance);
|
||||
|
||||
@@ -266,7 +226,7 @@ public:
|
||||
void ClearNat64Prefix(void);
|
||||
|
||||
/**
|
||||
* Initializes an `otNat64AddressMappingIterator`.
|
||||
* Initializes an `AddressMappingIterator`.
|
||||
*
|
||||
* An iterator MUST be initialized before it is used.
|
||||
*
|
||||
@@ -279,17 +239,14 @@ public:
|
||||
/**
|
||||
* Gets the next AddressMapping info (using an iterator).
|
||||
*
|
||||
* @param[in,out] aIterator The iterator. On success the iterator will be updated to point to next NAT64
|
||||
* address mapping record. To get the first entry the iterator should be set to
|
||||
* OT_NAT64_ADDRESS_MAPPING_ITERATOR_INIT.
|
||||
* @param[out] aMapping An `otNat64AddressMapping` where information of next NAT64 address mapping record
|
||||
* is placed (on success).
|
||||
* @param[in,out] aIterator The iterator.
|
||||
* @param[out] aMapping An `AddressMapping` to output to next NAT64 address mapping.
|
||||
*
|
||||
* @retval kErrorNone Successfully found the next NAT64 address mapping info (@p aMapping was successfully
|
||||
* updated).
|
||||
* @retval kErrorNone Successfully found the next NAT64 address mapping info (@p aMapping and @p aIterator
|
||||
* are updated.
|
||||
* @retval kErrorNotFound No subsequent NAT64 address mapping info was found.
|
||||
*/
|
||||
Error GetNextAddressMapping(AddressMappingIterator &aIterator, otNat64AddressMapping &aMapping);
|
||||
Error GetNextAddressMapping(AddressMappingIterator &aIterator, AddressMapping &aMapping);
|
||||
|
||||
/**
|
||||
* Gets the NAT64 translator counters.
|
||||
@@ -317,7 +274,7 @@ public:
|
||||
* @retval kErrorNone @p aCidr is set to the configured CIDR.
|
||||
* @retval kErrorNotFound The translator is not configured with an IPv4 CIDR.
|
||||
*/
|
||||
Error GetIp4Cidr(Ip4::Cidr &aCidr);
|
||||
Error GetIp4Cidr(Ip4::Cidr &aCidr) const;
|
||||
|
||||
/**
|
||||
* Gets the configured IPv6 prefix in the NAT64 translator.
|
||||
@@ -327,83 +284,79 @@ public:
|
||||
* @retval kErrorNone @p aPrefix is set to the configured prefix.
|
||||
* @retval kErrorNotFound The translator is not configured with an IPv6 prefix.
|
||||
*/
|
||||
Error GetIp6Prefix(Ip6::Prefix &aPrefix);
|
||||
Error GetIp6Prefix(Ip6::Prefix &aPrefix) const;
|
||||
|
||||
private:
|
||||
class AddressMapping : public LinkedListEntry<AddressMapping>
|
||||
{
|
||||
public:
|
||||
friend class LinkedListEntry<AddressMapping>;
|
||||
friend class LinkedList<AddressMapping>;
|
||||
// Timeouts are in milliseconds
|
||||
static constexpr uint32_t kIdleTimeout = OPENTHREAD_CONFIG_NAT64_IDLE_TIMEOUT_SECONDS * Time::kOneSecondInMsec;
|
||||
static constexpr uint32_t kIcmpTimeout = OPENTHREAD_CONFIG_NAT64_ICMP_IDLE_TIMEOUT_SECONDS * Time::kOneSecondInMsec;
|
||||
|
||||
typedef String<Ip6::Address::kInfoStringSize + Ip4::Address::kAddressStringSize + 4> InfoString;
|
||||
static constexpr uint32_t kPoolSize = OPENTHREAD_CONFIG_NAT64_MAX_MAPPINGS;
|
||||
static constexpr uint16_t kMinTranslationPort = 49152;
|
||||
static constexpr uint16_t kMaxTranslationPort = 65535;
|
||||
|
||||
// The maximum value the CIDR len can have in order to have a big
|
||||
// enough pool to support a minimal number of devices
|
||||
static constexpr uint8_t kMaxCidrLenForValidAddrPool = 28;
|
||||
|
||||
static constexpr DropReason kReasonUnknown = OT_NAT64_DROP_REASON_UNKNOWN;
|
||||
static constexpr DropReason kReasonIllegalPacket = OT_NAT64_DROP_REASON_ILLEGAL_PACKET;
|
||||
static constexpr DropReason kReasonUnsupportedProto = OT_NAT64_DROP_REASON_UNSUPPORTED_PROTO;
|
||||
static constexpr DropReason kReasonNoMapping = OT_NAT64_DROP_REASON_NO_MAPPING;
|
||||
|
||||
struct Mapping : public LinkedListEntry<Mapping>
|
||||
{
|
||||
static constexpr uint16_t kInfoStringSize = 70;
|
||||
|
||||
typedef String<kInfoStringSize> InfoString;
|
||||
|
||||
void Touch(TimeMilli aNow, uint8_t aProtocol);
|
||||
InfoString ToString(void) const;
|
||||
void CopyTo(otNat64AddressMapping &aMapping, TimeMilli aNow) const;
|
||||
|
||||
uint64_t mId; // The unique id for a mapping session.
|
||||
|
||||
Ip4::Address mIp4;
|
||||
Ip6::Address mIp6;
|
||||
uint16_t mSrcPortOrId;
|
||||
uint16_t mTranslatedPortOrId;
|
||||
TimeMilli mExpiry; // The timestamp when this mapping expires, in milliseconds.
|
||||
void CopyTo(AddressMapping &aMapping, TimeMilli aNow) const;
|
||||
bool Matches(const Ip4::Address &aIp4Address) const { return mIp4Address == aIp4Address; }
|
||||
bool Matches(const Ip6::Address &aIp6Address) const { return mIp6Address == aIp6Address; }
|
||||
bool Matches(const uint16_t aPort) const { return mTranslatedPortOrId == aPort; }
|
||||
bool Matches(const TimeMilli aNow) const { return mExpiry < aNow; }
|
||||
bool Matches(const Ip6::Address &aIp6Address, const uint16_t aPort) const;
|
||||
bool Matches(const Ip4::Address &aIp4Address, const uint16_t aPort) const;
|
||||
|
||||
Mapping *mNext;
|
||||
uint64_t mId;
|
||||
Ip4::Address mIp4Address;
|
||||
Ip6::Address mIp6Address;
|
||||
uint16_t mSrcPortOrId;
|
||||
uint16_t mTranslatedPortOrId;
|
||||
TimeMilli mExpiry;
|
||||
ProtocolCounters mCounters;
|
||||
|
||||
private:
|
||||
bool Matches(const Ip4::Address &aIp4) const { return mIp4 == aIp4; }
|
||||
bool Matches(const Ip6::Address &aIp6) const { return mIp6 == aIp6; }
|
||||
bool Matches(const uint16_t aPort) const { return mTranslatedPortOrId == aPort; }
|
||||
bool Matches(const TimeMilli aNow) const { return mExpiry < aNow; }
|
||||
|
||||
bool Matches(const Ip6::Address &aIp6, const uint16_t aPort) const
|
||||
{
|
||||
return ((mIp6 == aIp6) && (mSrcPortOrId == aPort));
|
||||
}
|
||||
bool Matches(const Ip4::Address &aIp4, const uint16_t aPort) const
|
||||
{
|
||||
return ((mIp4 == aIp4) && (mTranslatedPortOrId == aPort));
|
||||
}
|
||||
|
||||
AddressMapping *mNext;
|
||||
};
|
||||
|
||||
Error TranslateIcmp4(Message &aMessage, uint16_t aOriginalId);
|
||||
Error TranslateIcmp6(Message &aMessage, uint16_t aTranslatedId);
|
||||
|
||||
Error TranslateIcmp4(Message &aMessage, uint16_t aOriginalId);
|
||||
Error TranslateIcmp6(Message &aMessage, uint16_t aTranslatedId);
|
||||
uint16_t ReleaseMappings(LinkedList<Mapping> &aMappings);
|
||||
void ReleaseMapping(Mapping &aMapping);
|
||||
uint16_t ReleaseExpiredMappings(void);
|
||||
Mapping *AllocateMapping(const Ip6::Headers &aIp6Headers);
|
||||
Mapping *FindOrAllocateMapping(const Ip6::Headers &aIp6Headers);
|
||||
Mapping *FindMapping(const Ip4::Headers &aIp4Headers);
|
||||
void HandleTimer(void);
|
||||
void UpdateState(void);
|
||||
#if OPENTHREAD_CONFIG_NAT64_PORT_TRANSLATION_ENABLE
|
||||
uint16_t AllocateSourcePort(uint16_t aSrcPort);
|
||||
#endif
|
||||
uint16_t ReleaseMappings(LinkedList<AddressMapping> &aMappings);
|
||||
void ReleaseMapping(AddressMapping &aMapping);
|
||||
uint16_t ReleaseExpiredMappings(void);
|
||||
AddressMapping *AllocateMapping(const Ip6::Headers &aIp6Headers);
|
||||
AddressMapping *FindOrAllocateMapping(const Ip6::Headers &aIp6Headers);
|
||||
AddressMapping *FindMapping(const Ip4::Headers &aIp4Headers);
|
||||
void HandleMappingExpirerTimer(void);
|
||||
|
||||
using MappingTimer = TimerMilliIn<Translator, &Translator::HandleMappingExpirerTimer>;
|
||||
using TranslatorTimer = TimerMilliIn<Translator, &Translator::HandleTimer>;
|
||||
|
||||
void UpdateState(void);
|
||||
|
||||
bool mEnabled;
|
||||
State mState;
|
||||
|
||||
uint64_t mNextMappingId;
|
||||
|
||||
Array<Ip4::Address, kAddressMappingPoolSize> mIp4AddressPool;
|
||||
Pool<AddressMapping, kAddressMappingPoolSize> mAddressMappingPool;
|
||||
LinkedList<AddressMapping> mActiveAddressMappings;
|
||||
|
||||
Ip6::Prefix mNat64Prefix;
|
||||
Ip4::Cidr mIp4Cidr;
|
||||
|
||||
MappingTimer mMappingExpirerTimer;
|
||||
|
||||
ProtocolCounters mCounters;
|
||||
ErrorCounters mErrorCounters;
|
||||
bool mEnabled;
|
||||
State mState;
|
||||
uint64_t mNextMappingId;
|
||||
Array<Ip4::Address, kPoolSize> mIp4AddressPool;
|
||||
Pool<Mapping, kPoolSize> mMappingPool;
|
||||
LinkedList<Mapping> mActiveMappings;
|
||||
Ip6::Prefix mNat64Prefix;
|
||||
Ip4::Cidr mIp4Cidr;
|
||||
TranslatorTimer mTimer;
|
||||
ProtocolCounters mCounters;
|
||||
ErrorCounters mErrorCounters;
|
||||
};
|
||||
#endif // OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE
|
||||
|
||||
|
||||
Reference in New Issue
Block a user