Merge pull request #69 from edmont/pr/upmerge-20220711

upmerge: merge up to commit '2ce3d3b'
This commit is contained in:
Robert Lubos 2022-07-12 11:51:17 +02:00 committed by GitHub
commit b21e99b4b3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
237 changed files with 1488 additions and 794 deletions

View File

@ -216,7 +216,7 @@ jobs:
strategy:
fail-fast: false
matrix:
clang_ver: ["6.0", "7", "8", "9"]
clang_ver: ["6.0", "7", "8", "9", "10", "11", "12", "13"]
env:
CC: clang-${{ matrix.clang_ver }}
CXX: clang++-${{ matrix.clang_ver }}
@ -226,7 +226,14 @@ jobs:
submodules: true
- name: Bootstrap
run: |
sudo rm /etc/apt/sources.list.d/* && sudo apt-get update
sudo rm /etc/apt/sources.list.d/*
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
echo 'deb http://apt.llvm.org/focal/ llvm-toolchain-focal main
deb-src http://apt.llvm.org/focal/ llvm-toolchain-focal main
# 13
deb http://apt.llvm.org/focal/ llvm-toolchain-focal-13 main
deb-src http://apt.llvm.org/focal/ llvm-toolchain-focal-13 main' | sudo tee -a /etc/apt/sources.list
sudo apt-get update
sudo apt-get --no-install-recommends install -y clang-${{ matrix.clang_ver }} clang++-${{ matrix.clang_ver }} ninja-build libreadline-dev libncurses-dev
- name: Build
run: |
@ -239,7 +246,7 @@ jobs:
strategy:
fail-fast: false
matrix:
clang_ver: ["6.0", "7", "8", "9"]
clang_ver: ["6.0", "7", "8", "9", "10", "11", "12", "13"]
env:
CC: clang-${{ matrix.clang_ver }}
CXX: clang++-${{ matrix.clang_ver }}
@ -253,6 +260,12 @@ jobs:
- name: Bootstrap
run: |
sudo dpkg --add-architecture i386
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
echo 'deb http://apt.llvm.org/focal/ llvm-toolchain-focal main
deb-src http://apt.llvm.org/focal/ llvm-toolchain-focal main
# 13
deb http://apt.llvm.org/focal/ llvm-toolchain-focal-13 main
deb-src http://apt.llvm.org/focal/ llvm-toolchain-focal-13 main' | sudo tee -a /etc/apt/sources.list
sudo apt-get update
sudo apt-get --no-install-recommends install -y clang-${{ matrix.clang_ver }} clang++-${{ matrix.clang_ver }} ninja-build
sudo apt-get --no-install-recommends install -y g++-multilib libreadline-dev:i386 libncurses-dev:i386

View File

@ -83,7 +83,7 @@ send "ifconfig up\r\n"
expect "Done"
send "thread start\r\n"
expect "Done"
sleep 5
sleep 10
send "state\r\n"
expect "leader"
expect "Done"

View File

@ -182,7 +182,7 @@ send "ifconfig up\r\n"
expect "Done"
send "thread start\r\n"
expect "Done"
sleep 5
sleep 10
send "state\r\n"
expect "leader"
expect "Done"
@ -207,7 +207,7 @@ EOF
sleep 5
# wait until the node becomes leader
timeout_run 5 wait_for_leader
timeout_run 10 wait_for_leader
# wait coap service start
sleep 5

View File

@ -64,6 +64,7 @@ RoutingManager::RoutingManager(Instance &aInstance)
, mIsRunning(false)
, mIsEnabled(false)
, mInfraIf(aInstance)
, mLocalOmrPrefix(aInstance)
, mRouteInfoOptionPreference(NetworkData::kRoutePreferenceMedium)
, mIsAdvertisingLocalOnLinkPrefix(false)
, mOnLinkPrefixDeprecateTimer(aInstance, HandleOnLinkPrefixDeprecateTimer)
@ -82,8 +83,6 @@ RoutingManager::RoutingManager(Instance &aInstance)
mBrUlaPrefix.Clear();
mLocalOmrPrefix.Clear();
mLocalOnLinkPrefix.Clear();
mLocalNat64Prefix.Clear();
@ -96,7 +95,7 @@ Error RoutingManager::Init(uint32_t aInfraIfIndex, bool aInfraIfIsRunning)
SuccessOrExit(error = mInfraIf.Init(aInfraIfIndex));
SuccessOrExit(error = LoadOrGenerateRandomBrUlaPrefix());
GenerateOmrPrefix();
mLocalOmrPrefix.GenerateFrom(mBrUlaPrefix);
#if OPENTHREAD_CONFIG_BORDER_ROUTING_NAT64_ENABLE
GenerateNat64Prefix();
#endif
@ -146,7 +145,7 @@ Error RoutingManager::GetOmrPrefix(Ip6::Prefix &aPrefix)
Error error = kErrorNone;
VerifyOrExit(IsInitialized(), error = kErrorInvalidState);
aPrefix = mLocalOmrPrefix;
aPrefix = mLocalOmrPrefix.GetPrefix();
exit:
return error;
@ -209,15 +208,6 @@ exit:
return error;
}
void RoutingManager::GenerateOmrPrefix(void)
{
mLocalOmrPrefix = mBrUlaPrefix;
mLocalOmrPrefix.SetSubnetId(kOmrPrefixSubnetId);
mLocalOmrPrefix.SetLength(kOmrPrefixLength);
LogInfo("Generated OMR prefix: %s", mLocalOmrPrefix.ToString().AsCString());
}
#if OPENTHREAD_CONFIG_BORDER_ROUTING_NAT64_ENABLE
void RoutingManager::GenerateNat64Prefix(void)
{
@ -272,7 +262,7 @@ void RoutingManager::Stop(void)
{
VerifyOrExit(mIsRunning);
UnpublishLocalOmrPrefix();
mLocalOmrPrefix.RemoveFromNetData();
mFavoredDiscoveredOnLinkPrefix.Clear();
@ -470,7 +460,7 @@ void RoutingManager::EvaluateOmrPrefix(OmrPrefixArray &aNewOmrPrefixes)
}
}
if (entry->GetPrefix() == mLocalOmrPrefix)
if (entry->GetPrefix() == mLocalOmrPrefix.GetPrefix())
{
localOmrEntry = entry;
}
@ -480,33 +470,34 @@ void RoutingManager::EvaluateOmrPrefix(OmrPrefixArray &aNewOmrPrefixes)
if (favoredOmrEntry == nullptr)
{
LogInfo("EvaluateOmrPrefix: No preferred OMR prefixes found in Thread network");
LogInfo("EvaluateOmrPrefix: No preferred OMR prefix found in Thread network");
// The `aNewOmrPrefixes` remains empty if we fail to publish
// the local OMR prefix.
SuccessOrExit(PublishLocalOmrPrefix());
SuccessOrExit(mLocalOmrPrefix.AddToNetData());
localOmrEntry = aNewOmrPrefixes.PushBack();
VerifyOrExit(localOmrEntry != nullptr);
if (localOmrEntry == nullptr)
{
localOmrEntry = aNewOmrPrefixes.PushBack();
VerifyOrExit(localOmrEntry != nullptr);
localOmrEntry->Init(mLocalOmrPrefix, NetworkData::kRoutePreferenceLow);
localOmrEntry->Init(mLocalOmrPrefix.GetPrefix(), NetworkData::kRoutePreferenceLow);
}
}
else if (favoredOmrEntry == localOmrEntry)
{
IgnoreError(PublishLocalOmrPrefix());
IgnoreError(mLocalOmrPrefix.AddToNetData());
}
else if (IsOmrPrefixAddedToLocalNetworkData())
else if (mLocalOmrPrefix.IsAddedInNetData())
{
LogInfo("EvaluateOmrPrefix: There is already a preferred OMR prefix %s in the Thread network",
favoredOmrEntry->ToString().AsCString());
UnpublishLocalOmrPrefix();
mLocalOmrPrefix.RemoveFromNetData();
if (localOmrEntry != nullptr)
{
// Remove the local OMR prefix from the list by overwriting it
// with popped last entry in the list.
*localOmrEntry = *aNewOmrPrefixes.PopBack();
aNewOmrPrefixes.Remove(*localOmrEntry);
}
}
@ -514,66 +505,6 @@ exit:
return;
}
Error RoutingManager::PublishLocalOmrPrefix(void)
{
Error error = kErrorNone;
NetworkData::OnMeshPrefixConfig omrPrefixConfig;
OT_ASSERT(mIsRunning);
VerifyOrExit(!IsOmrPrefixAddedToLocalNetworkData());
omrPrefixConfig.Clear();
omrPrefixConfig.mPrefix = mLocalOmrPrefix;
omrPrefixConfig.mStable = true;
omrPrefixConfig.mSlaac = true;
omrPrefixConfig.mPreferred = true;
omrPrefixConfig.mOnMesh = true;
omrPrefixConfig.mDefaultRoute = false;
omrPrefixConfig.mPreference = NetworkData::kRoutePreferenceLow;
error = Get<NetworkData::Local>().AddOnMeshPrefix(omrPrefixConfig);
if (error != kErrorNone)
{
LogWarn("Failed to publish local OMR prefix %s in Thread network: %s", mLocalOmrPrefix.ToString().AsCString(),
ErrorToString(error));
}
else
{
Get<NetworkData::Notifier>().HandleServerDataUpdated();
LogInfo("Publishing local OMR prefix %s in Thread network", mLocalOmrPrefix.ToString().AsCString());
}
exit:
return error;
}
void RoutingManager::UnpublishLocalOmrPrefix(void)
{
Error error = kErrorNone;
VerifyOrExit(mIsRunning);
VerifyOrExit(IsOmrPrefixAddedToLocalNetworkData());
SuccessOrExit(error = Get<NetworkData::Local>().RemoveOnMeshPrefix(mLocalOmrPrefix));
Get<NetworkData::Notifier>().HandleServerDataUpdated();
LogInfo("Unpublishing local OMR prefix %s from Thread network", mLocalOmrPrefix.ToString().AsCString());
exit:
if (error != kErrorNone && error != kErrorNotFound)
{
LogWarn("Failed to unpublish local OMR prefix %s from Thread network: %s",
mLocalOmrPrefix.ToString().AsCString(), ErrorToString(error));
}
}
bool RoutingManager::IsOmrPrefixAddedToLocalNetworkData(void) const
{
return Get<NetworkData::Local>().ContainsOnMeshPrefix(mLocalOmrPrefix);
}
Error RoutingManager::PublishExternalRoute(const Ip6::Prefix &aPrefix, RoutePreference aRoutePreference, bool aNat64)
{
Error error;
@ -1181,7 +1112,7 @@ bool RoutingManager::ShouldProcessRouteInfoOption(const Ip6::Nd::RouteInfoOption
ExitNow();
}
VerifyOrExit(mLocalOmrPrefix != aPrefix);
VerifyOrExit(mLocalOmrPrefix.GetPrefix() != aPrefix);
// Ignore OMR prefixes advertised by ourselves or in current Thread Network Data.
// The `mAdvertisedOmrPrefixes` and the OMR prefix set in Network Data should eventually
@ -2038,6 +1969,80 @@ RoutingManager::OmrPrefix::InfoString RoutingManager::OmrPrefix::ToString(void)
return string;
}
//---------------------------------------------------------------------------------------------------------------------
// LocalOmrPrefix
RoutingManager::LocalOmrPrefix::LocalOmrPrefix(Instance &aInstance)
: InstanceLocator(aInstance)
, mIsAddedInNetData(false)
{
}
void RoutingManager::LocalOmrPrefix::GenerateFrom(const Ip6::Prefix &aBrUlaPrefix)
{
mPrefix = aBrUlaPrefix;
mPrefix.SetSubnetId(kOmrPrefixSubnetId);
mPrefix.SetLength(kOmrPrefixLength);
LogInfo("Generated OMR prefix: %s", mPrefix.ToString().AsCString());
}
Error RoutingManager::LocalOmrPrefix::AddToNetData(void)
{
Error error = kErrorNone;
NetworkData::OnMeshPrefixConfig config;
VerifyOrExit(!mIsAddedInNetData);
config.Clear();
config.mPrefix = mPrefix;
config.mStable = true;
config.mSlaac = true;
config.mPreferred = true;
config.mOnMesh = true;
config.mDefaultRoute = false;
config.mPreference = NetworkData::kRoutePreferenceLow;
error = Get<NetworkData::Local>().AddOnMeshPrefix(config);
if (error != kErrorNone)
{
LogWarn("Failed to add local OMR prefix %s in Thread Network Data: %s", mPrefix.ToString().AsCString(),
ErrorToString(error));
ExitNow();
}
mIsAddedInNetData = true;
Get<NetworkData::Notifier>().HandleServerDataUpdated();
LogInfo("Added local OMR prefix %s in Thread Network Data", mPrefix.ToString().AsCString());
exit:
return error;
}
void RoutingManager::LocalOmrPrefix::RemoveFromNetData(void)
{
Error error = kErrorNone;
VerifyOrExit(mIsAddedInNetData);
error = Get<NetworkData::Local>().RemoveOnMeshPrefix(mPrefix);
if (error != kErrorNone)
{
LogWarn("Failed to remove local OMR prefix %s from Thread Network Data: %s", mPrefix.ToString().AsCString(),
ErrorToString(error));
ExitNow();
}
mIsAddedInNetData = false;
Get<NetworkData::Notifier>().HandleServerDataUpdated();
LogInfo("Removed local OMR prefix %s from Thread Network Data", mPrefix.ToString().AsCString());
exit:
return;
}
} // namespace BorderRouter
} // namespace ot

View File

@ -451,6 +451,21 @@ private:
typedef Array<OmrPrefix, kMaxOmrPrefixNum> OmrPrefixArray;
class LocalOmrPrefix : InstanceLocator
{
public:
explicit LocalOmrPrefix(Instance &aInstance);
void GenerateFrom(const Ip6::Prefix &aBrUlaPrefix);
const Ip6::Prefix &GetPrefix(void) const { return mPrefix; }
Error AddToNetData(void);
void RemoveFromNetData(void);
bool IsAddedInNetData(void) const { return mIsAddedInNetData; }
private:
Ip6::Prefix mPrefix;
bool mIsAddedInNetData;
};
void EvaluateState(void);
void Start(void);
void Stop(void);
@ -458,7 +473,6 @@ private:
bool IsInitialized(void) const { return mInfraIf.IsInitialized(); }
bool IsEnabled(void) const { return mIsEnabled; }
Error LoadOrGenerateRandomBrUlaPrefix(void);
void GenerateOmrPrefix(void);
void GenerateOnLinkPrefix(void);
void EvaluateOnLinkPrefix(void);
@ -472,9 +486,6 @@ private:
void StartRoutingPolicyEvaluationJitter(uint32_t aJitterMilli);
void StartRoutingPolicyEvaluationDelay(uint32_t aDelayMilli);
void EvaluateOmrPrefix(OmrPrefixArray &aNewOmrPrefixes);
Error PublishLocalOmrPrefix(void);
void UnpublishLocalOmrPrefix(void);
bool IsOmrPrefixAddedToLocalNetworkData(void) const;
Error PublishExternalRoute(const Ip6::Prefix &aPrefix, RoutePreference aRoutePreference, bool aNat64 = false);
void UnpublishExternalRoute(const Ip6::Prefix &aPrefix);
void StartRouterSolicitationDelay(void);
@ -521,8 +532,7 @@ private:
// randomly generated if none is found in persistent storage.
Ip6::Prefix mBrUlaPrefix;
// The OMR prefix allocated from the /48 BR ULA prefix.
Ip6::Prefix mLocalOmrPrefix;
LocalOmrPrefix mLocalOmrPrefix;
// The advertised OMR prefixes. For a stable Thread network without
// manually configured OMR prefixes, there should be a single OMR

View File

@ -421,6 +421,68 @@
#define OPENTHREAD_CONFIG_NUM_FRAGMENT_PRIORITY_ENTRIES 8
#endif
/**
* @def OPENTHREAD_CONFIG_DELAY_AWARE_QUEUE_MANAGEMENT_ENABLE
*
* Define to 1 to enable delay-aware queue management for the send queue.
*
* When enabled device will monitor time-in-queue of messages in the direct tx queue and if the wait time is lager than
* specified thresholds it may update ECN flag (if message indicates it is ECN-capable) or drop the message.
*
*/
#ifndef OPENTHREAD_CONFIG_DELAY_AWARE_QUEUE_MANAGEMENT_ENABLE
#define OPENTHREAD_CONFIG_DELAY_AWARE_QUEUE_MANAGEMENT_ENABLE \
(OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_3)
#endif
/**
* @OPENTHREAD_CONFIG_DELAY_AWARE_QUEUE_MANAGEMENT_MARK_ECN_INTERVAL
*
* Specifies the time-in-queue threshold interval in milliseconds to mark ECN on a message if it is ECN-capable or
* drop the message if not ECN-capable.
*
*/
#ifndef OPENTHREAD_CONFIG_DELAY_AWARE_QUEUE_MANAGEMENT_MARK_ECN_INTERVAL
#define OPENTHREAD_CONFIG_DELAY_AWARE_QUEUE_MANAGEMENT_MARK_ECN_INTERVAL 500
#endif
/**
* @OPENTHREAD_CONFIG_DELAY_AWARE_QUEUE_MANAGEMENT_DROP_MSG_INTERVAL
*
* Specifies the time-in-queue threshold interval in milliseconds to drop a message.
*
*/
#ifndef OPENTHREAD_CONFIG_DELAY_AWARE_QUEUE_MANAGEMENT_DROP_MSG_INTERVAL
#define OPENTHREAD_CONFIG_DELAY_AWARE_QUEUE_MANAGEMENT_DROP_MSG_INTERVAL 1000
#endif
/**
* OPENTHREAD_CONFIG_DELAY_AWARE_QUEUE_MANAGEMENT_FRAG_TAG_RETAIN_TIME
*
* Specifies the max retain time in seconds of a mesh header fragmentation tag entry in the list.
*
* The entry in list is used to track whether an earlier fragment of same message was dropped by the router and if so
* the next fragments are also dropped. The entry is removed once last fragment is processed or after the retain time
* specified by this config parameter expires.
*
*/
#ifndef OPENTHREAD_CONFIG_DELAY_AWARE_QUEUE_MANAGEMENT_FRAG_TAG_RETAIN_TIME
#define OPENTHREAD_CONFIG_DELAY_AWARE_QUEUE_MANAGEMENT_FRAG_TAG_RETAIN_TIME (4 * 60) // 4 minutes
#endif
/**
* OPENTHREAD_CONFIG_DELAY_AWARE_QUEUE_MANAGEMENT_FRAG_TAG_ENTRY_LIST_SIZE
*
* Specifies the number of mesh header fragmentation tag entries in the list for delay-aware queue management.
*
* The list is used to track whether an earlier fragment of same message was dropped by the router and if so the next
* fragments are also dropped.
*
*/
#ifndef OPENTHREAD_CONFIG_DELAY_AWARE_QUEUE_MANAGEMENT_FRAG_TAG_ENTRY_LIST_SIZE
#define OPENTHREAD_CONFIG_DELAY_AWARE_QUEUE_MANAGEMENT_FRAG_TAG_ENTRY_LIST_SIZE 16
#endif
/**
* @def OPENTHREAD_CONFIG_PLATFORM_RADIO_PROPRIETARY_SUPPORT
*

View File

@ -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

View File

@ -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;
};
/**
* @}
*

View File

@ -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;

View File

@ -1001,7 +1001,7 @@ Error Client::AppendServiceInstructions(Service &aService, Message &aMessage, In
UpdateRecordLengthInMessage(rr, offset, aMessage);
aInfo.mRecordCount++;
if (aService.HasSubType())
if (aService.HasSubType() && !removing)
{
const char *subTypeLabel;
uint16_t subServiceNameOffset = 0;
@ -1023,7 +1023,7 @@ Error Client::AppendServiceInstructions(Service &aService, Message &aMessage, In
SuccessOrExit(error = Dns::Name::AppendPointerLabel(subServiceNameOffset, aMessage));
}
// `rr` is already initialized as PTR (add or remove).
// `rr` is already initialized as PTR.
offset = aMessage.GetLength();
SuccessOrExit(error = aMessage.Append(rr));

View File

@ -213,6 +213,7 @@ void DiscoverScanner::HandleDiscoveryRequestFrameTxDone(Message &aMessage)
// the next scan channel. Also pause message tx on `MeshForwarder`
// while listening to receive Discovery Responses.
aMessage.SetDirectTransmission();
aMessage.SetTimestampToNow();
Get<MeshForwarder>().PauseMessageTransmissions();
mTimer.Start(kDefaultScanDuration);
break;

View File

@ -1179,6 +1179,46 @@ exit:
return (error == kErrorNone) ? static_cast<int>(compressedLength) : -1;
}
Ip6::Ecn Lowpan::DecompressEcn(const Message &aMessage, uint16_t aOffset) const
{
Ip6::Ecn ecn = Ip6::kEcnNotCapable;
uint16_t hcCtl;
uint8_t byte;
SuccessOrExit(aMessage.Read(aOffset, hcCtl));
hcCtl = HostSwap16(hcCtl);
VerifyOrExit((hcCtl & kHcDispatchMask) == kHcDispatch);
aOffset += sizeof(uint16_t);
if ((hcCtl & kHcTrafficFlowMask) == kHcTrafficFlow)
{
// ECN is elided and is zero (`kEcnNotCapable`).
ExitNow();
}
// When ECN is not elided, it is always included as the
// first two bits of the next byte.
SuccessOrExit(aMessage.Read(aOffset, byte));
ecn = static_cast<Ip6::Ecn>((byte & kEcnMask) >> kEcnOffset);
exit:
return ecn;
}
void Lowpan::MarkCompressedEcn(Message &aMessage, uint16_t aOffset)
{
uint8_t byte;
aOffset += sizeof(uint16_t);
IgnoreError(aMessage.Read(aOffset, byte));
byte &= ~kEcnMask;
byte |= static_cast<uint8_t>(Ip6::kEcnMarked << kEcnOffset);
aMessage.Write(aOffset, byte);
}
//---------------------------------------------------------------------------------------------------------------------
// MeshHeader

View File

@ -43,6 +43,7 @@
#include "mac/mac_types.hpp"
#include "net/ip6.hpp"
#include "net/ip6_address.hpp"
#include "net/ip6_types.hpp"
namespace ot {
@ -308,6 +309,29 @@ public:
*/
int DecompressUdpHeader(Ip6::Udp::Header &aUdpHeader, const uint8_t *aBuf, uint16_t aBufLength);
/**
* This method decompresses the IPv6 ECN field in a LOWPAN_IPHC header.
*
* @param[in] aMessage The message to read the IPHC header from.
* @param[in] aOffset The offset in @p aMessage to start of IPHC header.
*
* @returns The decompressed ECN field. If the IPHC header is not valid `kEcnNotCapable` is returned.
*
*/
Ip6::Ecn DecompressEcn(const Message &aMessage, uint16_t aOffset) const;
/**
* This method updates the compressed ECN field in a LOWPAN_IPHC header to `kEcnMarked`.
*
* This method MUST be used when the ECN field is not elided in the IPHC header. Note that the ECN is not elided
* when it is not zero (`kEcnNotCapable`).
*
* @param[in,out] aMessage The message containing the IPHC header and to update.
* @param[in] aOffset The offset in @p aMessage to start of IPHC header.
*
*/
void MarkCompressedEcn(Message &aMessage, uint16_t aOffset);
private:
static constexpr uint16_t kHcDispatch = 3 << 13;
static constexpr uint16_t kHcDispatchMask = 7 << 13;
@ -336,6 +360,9 @@ private:
static constexpr uint16_t kHcDstAddrMode3 = 3 << 0;
static constexpr uint16_t kHcDstAddrModeMask = 3 << 0;
static constexpr uint8_t kEcnOffset = 6;
static constexpr uint8_t kEcnMask = 3 << kEcnOffset;
static constexpr uint8_t kExtHdrDispatch = 0xe0;
static constexpr uint8_t kExtHdrDispatchMask = 0xf0;

View File

@ -260,6 +260,184 @@ void MeshForwarder::HandleTxDelayTimer(void)
}
#endif
#if OPENTHREAD_CONFIG_DELAY_AWARE_QUEUE_MANAGEMENT_ENABLE
Error MeshForwarder::UpdateEcnOrDrop(Message &aMessage, bool aPreparingToSend)
{
// This method performs delay-aware active queue management for
// direct message transmission. It parses the IPv6 header from
// `aMessage` to determine if message is ECN-capable. This is
// then used along with the message's time-in-queue to decide
// whether to keep the message as is, change the ECN field to
// mark congestion, or drop the message. If the message is to be
// dropped, this method clears the direct tx flag on `aMessage`
// and removes it from the send queue (if no pending indirect tx)
// and returns `kErrorDrop`. This method returns `kErrorNone`
// when the message is kept as is or ECN field is updated.
Error error = kErrorNone;
uint32_t timeInQueue = TimerMilli::GetNow() - aMessage.GetTimestamp();
bool shouldMarkEcn = (timeInQueue >= kTimeInQueueMarkEcn);
bool isEcnCapable = false;
VerifyOrExit(aMessage.IsDirectTransmission() && (aMessage.GetOffset() == 0));
if (aMessage.GetType() == Message::kTypeIp6)
{
Ip6::Header ip6Header;
IgnoreError(aMessage.Read(0, ip6Header));
VerifyOrExit(!Get<ThreadNetif>().HasUnicastAddress(ip6Header.GetSource()));
isEcnCapable = (ip6Header.GetEcn() != Ip6::kEcnNotCapable);
if ((shouldMarkEcn && !isEcnCapable) || (timeInQueue >= kTimeInQueueDropMsg))
{
ExitNow(error = kErrorDrop);
}
if (shouldMarkEcn)
{
switch (ip6Header.GetEcn())
{
case Ip6::kEcnCapable0:
case Ip6::kEcnCapable1:
ip6Header.SetEcn(Ip6::kEcnMarked);
aMessage.Write(0, ip6Header);
LogMessage(kMessageMarkEcn, aMessage);
break;
case Ip6::kEcnMarked:
case Ip6::kEcnNotCapable:
break;
}
}
}
#if OPENTHREAD_FTD
else if (aMessage.GetType() == Message::kType6lowpan)
{
uint16_t headerLength = 0;
uint16_t offset;
bool hasFragmentHeader = false;
Lowpan::FragmentHeader fragmentHeader;
Lowpan::MeshHeader meshHeader;
IgnoreError(meshHeader.ParseFrom(aMessage, headerLength));
offset = headerLength;
if (fragmentHeader.ParseFrom(aMessage, offset, headerLength) == kErrorNone)
{
hasFragmentHeader = true;
offset += headerLength;
}
if (!hasFragmentHeader || (fragmentHeader.GetDatagramOffset() == 0))
{
Ip6::Ecn ecn = Get<Lowpan::Lowpan>().DecompressEcn(aMessage, offset);
isEcnCapable = (ecn != Ip6::kEcnNotCapable);
if ((shouldMarkEcn && !isEcnCapable) || (timeInQueue >= kTimeInQueueDropMsg))
{
FragmentPriorityList::Entry *entry;
entry = mFragmentPriorityList.FindEntry(meshHeader.GetSource(), fragmentHeader.GetDatagramTag());
if (entry != nullptr)
{
entry->MarkToDrop();
entry->ResetLifetime();
}
ExitNow(error = kErrorDrop);
}
if (shouldMarkEcn)
{
switch (ecn)
{
case Ip6::kEcnCapable0:
case Ip6::kEcnCapable1:
Get<Lowpan::Lowpan>().MarkCompressedEcn(aMessage, offset);
LogMessage(kMessageMarkEcn, aMessage);
break;
case Ip6::kEcnMarked:
case Ip6::kEcnNotCapable:
break;
}
}
}
else if (hasFragmentHeader)
{
FragmentPriorityList::Entry *entry;
entry = mFragmentPriorityList.FindEntry(meshHeader.GetSource(), fragmentHeader.GetDatagramTag());
VerifyOrExit(entry != nullptr);
if (entry->ShouldDrop())
{
error = kErrorDrop;
}
// We can clear the entry if it is the last fragment and
// only if the message is being prepared to be sent out.
if (aPreparingToSend && (fragmentHeader.GetDatagramOffset() + aMessage.GetLength() - offset >=
fragmentHeader.GetDatagramSize()))
{
entry->Clear();
}
}
}
#else
OT_UNUSED_VARIABLE(aPreparingToSend);
#endif // OPENTHREAD_FTD
exit:
if (error == kErrorDrop)
{
LogMessage(kMessageQueueMgmtDrop, aMessage);
aMessage.ClearDirectTransmission();
RemoveMessageIfNoPendingTx(aMessage);
}
return error;
}
Error MeshForwarder::RemoveAgedMessages(void)
{
// This method goes through all messages in the send queue and
// removes all aged messages determined based on the delay-aware
// active queue management rules. It may also mark ECN on some
// messages. It returns `kErrorNone` if at least one message was
// removed, or `kErrorNotFound` if none was removed.
Error error = kErrorNotFound;
Message *nextMessage;
for (Message *message = mSendQueue.GetHead(); message != nullptr; message = nextMessage)
{
nextMessage = message->GetNext();
// Exclude the current message being sent `mSendMessage`.
if ((message == mSendMessage) || !message->IsDirectTransmission())
{
continue;
}
if (UpdateEcnOrDrop(*message, /* aPreparingToSend */ false) == kErrorDrop)
{
error = kErrorNone;
}
}
return error;
}
#endif // OPENTHREAD_CONFIG_DELAY_AWARE_QUEUE_MANAGEMENT_ENABLE
void MeshForwarder::ScheduleTransmissionTask(Tasklet &aTasklet)
{
aTasklet.Get<MeshForwarder>().ScheduleTransmissionTask();
@ -294,12 +472,24 @@ Message *MeshForwarder::PrepareNextDirectTransmission(void)
for (curMessage = mSendQueue.GetHead(); curMessage; curMessage = nextMessage)
{
// We set the `nextMessage` here but it can be updated again
// after the `switch(message.GetType())` since it may be
// evicted during message processing (e.g., from the call to
// `UpdateIp6Route()` due to Address Solicit).
nextMessage = curMessage->GetNext();
if (!curMessage->IsDirectTransmission() || curMessage->IsResolvingAddress())
{
nextMessage = curMessage->GetNext();
continue;
}
#if OPENTHREAD_CONFIG_DELAY_AWARE_QUEUE_MANAGEMENT_ENABLE
if (UpdateEcnOrDrop(*curMessage) == kErrorDrop)
{
continue;
}
#endif
curMessage->SetDoNotEvict(true);
switch (curMessage->GetType())
@ -469,39 +659,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 +1682,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 +1813,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)
@ -1745,6 +1824,10 @@ const char *MeshForwarder::MessageActionToString(MessageAction aAction, Error aE
"Dropping", // (3) kMessageDrop
"Dropping (reassembly queue)", // (4) kMessageReassemblyDrop
"Evicting", // (5) kMessageEvict
#if OPENTHREAD_CONFIG_DELAY_AWARE_QUEUE_MANAGEMENT_ENABLE
"Marked ECN", // (6) kMessageMarkEcn
"Dropping (queue mgmt)", // (7) kMessageQueueMgmtDrop
#endif
};
const char *string = kMessageActionStrings[aAction];
@ -1755,6 +1838,10 @@ const char *MeshForwarder::MessageActionToString(MessageAction aAction, Error aE
static_assert(kMessageDrop == 3, "kMessageDrop value is incorrect");
static_assert(kMessageReassemblyDrop == 4, "kMessageReassemblyDrop value is incorrect");
static_assert(kMessageEvict == 5, "kMessageEvict value is incorrect");
#if OPENTHREAD_CONFIG_DELAY_AWARE_QUEUE_MANAGEMENT_ENABLE
static_assert(kMessageMarkEcn == 6, "kMessageMarkEcn is incorrect");
static_assert(kMessageQueueMgmtDrop == 7, "kMessageQueueMgmtDrop is incorrect");
#endif
if ((aAction == kMessageTransmit) && (aError != kErrorNone))
{
@ -1770,31 +1857,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 +1892,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 +1907,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 +1919,7 @@ void MeshForwarder::LogIp6Message(MessageAction aAction,
if (aAction != kMessagePrepareIndirect)
{
LogIp6SourceDestAddresses(ip6Header, sourcePort, destPort, aLogLevel);
LogIp6SourceDestAddresses(headers, aLogLevel);
}
exit:
@ -1855,12 +1939,18 @@ void MeshForwarder::LogMessage(MessageAction aAction,
case kMessageReceive:
case kMessageTransmit:
case kMessagePrepareIndirect:
#if OPENTHREAD_CONFIG_DELAY_AWARE_QUEUE_MANAGEMENT_ENABLE
case kMessageMarkEcn:
#endif
logLevel = (aError == kErrorNone) ? kLogLevelInfo : kLogLevelNote;
break;
case kMessageDrop:
case kMessageReassemblyDrop:
case kMessageEvict:
#if OPENTHREAD_CONFIG_DELAY_AWARE_QUEUE_MANAGEMENT_ENABLE
case kMessageQueueMgmtDrop:
#endif
logLevel = kLogLevelNote;
break;
}

View File

@ -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:
/**
@ -336,14 +335,23 @@ private:
static constexpr uint32_t kTxDelayInterval = OPENTHREAD_CONFIG_MAC_COLLISION_AVOIDANCE_DELAY_INTERVAL; // In msec
#if OPENTHREAD_CONFIG_DELAY_AWARE_QUEUE_MANAGEMENT_ENABLE
static constexpr uint32_t kTimeInQueueMarkEcn = OPENTHREAD_CONFIG_DELAY_AWARE_QUEUE_MANAGEMENT_MARK_ECN_INTERVAL;
static constexpr uint32_t kTimeInQueueDropMsg = OPENTHREAD_CONFIG_DELAY_AWARE_QUEUE_MANAGEMENT_DROP_MSG_INTERVAL;
#endif
enum MessageAction : uint8_t
{
kMessageReceive, // Indicates that the message was received.
kMessageTransmit, // Indicates that the message was sent.
kMessagePrepareIndirect, // Indicates that the message is being prepared for indirect tx.
kMessageDrop, // Indicates that the outbound message is being dropped (e.g., dst unknown).
kMessageDrop, // Indicates that the outbound message is dropped (e.g., dst unknown).
kMessageReassemblyDrop, // Indicates that the message is being dropped from reassembly list.
kMessageEvict, // Indicates that the message was evicted.
#if OPENTHREAD_CONFIG_DELAY_AWARE_QUEUE_MANAGEMENT_ENABLE
kMessageMarkEcn, // Indicates that ECN is marked on an outbound message by delay-aware queue management.
kMessageQueueMgmtDrop, // Indicates that an outbound message is dropped by delay-aware queue management.
#endif
};
enum AnycastType : uint8_t
@ -362,21 +370,39 @@ private:
friend class FragmentPriorityList;
public:
Message::Priority GetPriority(void) const { return mPriority; }
// Lifetime of an entry in seconds.
static constexpr uint8_t kLifetime =
#if OPENTHREAD_CONFIG_DELAY_AWARE_QUEUE_MANAGEMENT_ENABLE
OT_MAX(kReassemblyTimeout, OPENTHREAD_CONFIG_DELAY_AWARE_QUEUE_MANAGEMENT_FRAG_TAG_RETAIN_TIME);
#else
kReassemblyTimeout;
#endif
Message::Priority GetPriority(void) const { return static_cast<Message::Priority>(mPriority); }
bool IsExpired(void) const { return (mLifetime == 0); }
void DecrementLifetime(void) { mLifetime--; }
void ResetLifetime(void) { mLifetime = kReassemblyTimeout; }
void ResetLifetime(void) { mLifetime = kLifetime; }
bool Matches(uint16_t aSrcRloc16, uint16_t aTag) const
{
return (mSrcRloc16 == aSrcRloc16) && (mDatagramTag == aTag);
}
#if OPENTHREAD_CONFIG_DELAY_AWARE_QUEUE_MANAGEMENT_ENABLE
bool ShouldDrop(void) const { return mShouldDrop; }
void MarkToDrop(void) { mShouldDrop = true; }
#endif
private:
uint16_t mSrcRloc16;
uint16_t mDatagramTag;
Message::Priority mPriority;
uint8_t mLifetime;
uint16_t mSrcRloc16;
uint16_t mDatagramTag;
uint8_t mLifetime;
uint8_t mPriority : 2;
#if OPENTHREAD_CONFIG_DELAY_AWARE_QUEUE_MANAGEMENT_ENABLE
bool mShouldDrop : 1;
#endif
static_assert(Message::kNumPriorities <= 4, "mPriority as a 2-bit does not fit all `Priority` values");
};
Entry *AllocateEntry(uint16_t aSrcRloc16, uint16_t aTag, Message::Priority aPriority);
@ -384,42 +410,35 @@ private:
bool UpdateOnTimeTick(void);
private:
static constexpr uint16_t kNumEntries = OPENTHREAD_CONFIG_NUM_FRAGMENT_PRIORITY_ENTRIES;
static constexpr uint16_t kNumEntries =
#if OPENTHREAD_CONFIG_DELAY_AWARE_QUEUE_MANAGEMENT_ENABLE
OT_MAX(OPENTHREAD_CONFIG_NUM_FRAGMENT_PRIORITY_ENTRIES,
OPENTHREAD_CONFIG_DELAY_AWARE_QUEUE_MANAGEMENT_FRAG_TAG_ENTRY_LIST_SIZE);
#else
OPENTHREAD_CONFIG_NUM_FRAGMENT_PRIORITY_ENTRIES;
#endif
Entry mEntries[kNumEntries];
};
#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);
@ -447,6 +466,10 @@ private:
bool aAddFragHeader = false);
void PrepareEmptyFrame(Mac::TxFrame &aFrame, const Mac::Address &aMacDest, bool aAckRequest);
#if OPENTHREAD_CONFIG_DELAY_AWARE_QUEUE_MANAGEMENT_ENABLE
Error UpdateEcnOrDrop(Message &aMessage, bool aPreparingToSend = true);
Error RemoveAgedMessages(void);
#endif
void SendMesh(Message &aMessage, Mac::TxFrame &aFrame);
void SendDestinationUnreachable(uint16_t aMeshSource, const Message &aMessage);
Error UpdateIp6Route(Message &aMessage);
@ -527,25 +550,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 +574,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,

View File

@ -53,6 +53,7 @@ Error MeshForwarder::SendMessage(Message &aMessage)
aMessage.SetOffset(0);
aMessage.SetDatagramTag(0);
aMessage.SetTimestampToNow();
mSendQueue.Enqueue(aMessage);
switch (aMessage.GetType())
@ -199,6 +200,11 @@ Error MeshForwarder::EvictMessage(Message::Priority aPriority)
Error error = kErrorNotFound;
Message *evict = nullptr;
#if OPENTHREAD_CONFIG_DELAY_AWARE_QUEUE_MANAGEMENT_ENABLE
error = RemoveAgedMessages();
VerifyOrExit(error == kErrorNotFound);
#endif
// Search for a lower priority message to evict
for (uint8_t priority = 0; priority < aPriority; priority++)
{
@ -245,8 +251,7 @@ Error MeshForwarder::EvictMessage(Message::Priority aPriority)
}
exit:
if (error == kErrorNone)
if ((error == kErrorNone) && (evict != nullptr))
{
RemoveMessage(*evict);
}
@ -632,19 +637,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 +818,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()))
@ -892,11 +886,18 @@ void MeshForwarder::UpdateFragmentPriority(Lowpan::FragmentHeader &aFragmentHead
ExitNow();
}
#if OPENTHREAD_CONFIG_DELAY_AWARE_QUEUE_MANAGEMENT_ENABLE
OT_UNUSED_VARIABLE(aFragmentLength);
#else
// We can clear the entry in `mFragmentPriorityList` if it is the
// last fragment. But if "delay aware active queue management" is
// used we need to keep entry until the message is sent.
if (aFragmentHeader.GetDatagramOffset() + aFragmentLength >= aFragmentHeader.GetDatagramSize())
{
entry->Clear();
}
else
#endif
{
entry->ResetLifetime();
}
@ -933,6 +934,7 @@ MeshForwarder::FragmentPriorityList::Entry *MeshForwarder::FragmentPriorityList:
{
if (entry.IsExpired())
{
entry.Clear();
entry.mSrcRloc16 = aSrcRloc16;
entry.mDatagramTag = aTag;
entry.mPriority = aPriority;
@ -1067,97 +1069,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;

View File

@ -42,6 +42,7 @@ Error MeshForwarder::SendMessage(Message &aMessage)
aMessage.SetDirectTransmission();
aMessage.SetOffset(0);
aMessage.SetDatagramTag(0);
aMessage.SetTimestampToNow();
mSendQueue.Enqueue(aMessage);
mScheduleTransmissionTask.Post();
@ -54,6 +55,11 @@ Error MeshForwarder::EvictMessage(Message::Priority aPriority)
Error error = kErrorNotFound;
Message *message;
#if OPENTHREAD_CONFIG_DELAY_AWARE_QUEUE_MANAGEMENT_ENABLE
error = RemoveAgedMessages();
VerifyOrExit(error == kErrorNotFound);
#endif
VerifyOrExit((message = mSendQueue.GetTail()) != nullptr);
if (message->GetPriority() < static_cast<uint8_t>(aPriority))

View File

@ -1282,10 +1282,64 @@ void Mle::HandleAttachTimer(Timer &aTimer)
aTimer.Get<Mle>().HandleAttachTimer();
}
Error Mle::DetermineParentRequestType(ParentRequestType &aType) const
{
// This method determines the Parent Request type to use during an
// attach cycle based on `mAttachMode`, `mAttachCounter` and
// `mParentRequestCounter`. This method MUST be used while in
// `kAttachStateParentRequest` state.
//
// On success it returns `kErrorNone` and sets `aType`. It returns
// `kErrorNotFound` to indicate that device can now transition
// from `kAttachStateParentRequest` state (has already sent the
// required number of Parent Requests for this attach attempt
// cycle).
Error error = kErrorNone;
OT_ASSERT(mAttachState == kAttachStateParentRequest);
aType = kToRoutersAndReeds;
// If device is not yet attached, `mAttachCounter` will track the
// number of attach attempt cycles so far, starting from one for
// the first attempt. `mAttachCounter` will be zero if device is
// already attached. Examples of this situation include a leader or
// router trying to attach to a better partition, or a child trying
// to find a better parent.
if ((mAttachCounter <= 1) && (mAttachMode != kBetterParent))
{
VerifyOrExit(mParentRequestCounter <= kFirstAttachCycleTotalParentRequests, error = kErrorNotFound);
// During reattach to the same partition all the Parent
// Request are sent to Routers and REEDs.
if ((mAttachMode != kSamePartition) && (mAttachMode != kSamePartitionRetry) &&
(mParentRequestCounter <= kFirstAttachCycleNumParentRequestToRouters))
{
aType = kToRouters;
}
}
else
{
VerifyOrExit(mParentRequestCounter <= kNextAttachCycleTotalParentRequests, error = kErrorNotFound);
if (mParentRequestCounter <= kNextAttachCycleNumParentRequestToRouters)
{
aType = kToRouters;
}
}
exit:
return error;
}
bool Mle::HasAcceptableParentCandidate(void) const
{
bool hasAcceptableParent = false;
LinkQuality linkQuality;
bool hasAcceptableParent = false;
LinkQuality linkQuality;
ParentRequestType parentReqType;
VerifyOrExit(mParentCandidate.IsStateParentResponse());
@ -1295,16 +1349,19 @@ bool Mle::HasAcceptableParentCandidate(void) const
VerifyOrExit(!HasMoreChannelsToAnnouce());
break;
case kAttachStateParentRequestRouter:
// If we cannot find a parent with best link quality (3) when
// in `kAttachStateParentRequestRouter` state we will keep the
// candidate and forward to REED stage to potentially find a
// better parent.
linkQuality = OT_MIN(mParentCandidate.GetLinkInfo().GetLinkQuality(), mParentCandidate.GetLinkQualityOut());
VerifyOrExit(linkQuality == kLinkQuality3);
break;
case kAttachStateParentRequest:
SuccessOrAssert(DetermineParentRequestType(parentReqType));
if (parentReqType == kToRouters)
{
// If we cannot find a parent with best link quality (3) when
// in Parent Request was sent to routers, we will keep the
// candidate and forward to REED stage to potentially find a
// better parent.
linkQuality = OT_MIN(mParentCandidate.GetLinkInfo().GetLinkQuality(), mParentCandidate.GetLinkQualityOut());
VerifyOrExit(linkQuality == kLinkQuality3);
}
case kAttachStateParentRequestReed:
break;
default:
@ -1331,8 +1388,9 @@ exit:
void Mle::HandleAttachTimer(void)
{
uint32_t delay = 0;
bool shouldAnnounce = true;
uint32_t delay = 0;
bool shouldAnnounce = true;
ParentRequestType type;
// First, check if we are waiting to receive parent responses and
// found an acceptable parent candidate.
@ -1355,46 +1413,26 @@ void Mle::HandleAttachTimer(void)
break;
case kAttachStateStart:
if (mAttachCounter > 0)
{
LogNote("Attempt to attach - attempt %d, %s %s", mAttachCounter, AttachModeToString(mAttachMode),
ReattachStateToString(mReattachState));
}
else
{
LogNote("Attempt to attach - %s %s", AttachModeToString(mAttachMode),
ReattachStateToString(mReattachState));
}
LogNote("Attach attempt %d, %s %s", mAttachCounter, AttachModeToString(mAttachMode),
ReattachStateToString(mReattachState));
SetAttachState(kAttachStateParentRequestRouter);
SetAttachState(kAttachStateParentRequest);
mParentCandidate.SetState(Neighbor::kStateInvalid);
mReceivedResponseFromParent = false;
mParentRequestCounter = 0;
Get<MeshForwarder>().SetRxOnWhenIdle(true);
// initial MLE Parent Request has both E and R flags set in Scan Mask TLV
// during reattach when losing connectivity.
if (mAttachMode == kSamePartition || mAttachMode == kSamePartitionRetry)
OT_FALL_THROUGH;
case kAttachStateParentRequest:
mParentRequestCounter++;
if (DetermineParentRequestType(type) == kErrorNone)
{
SendParentRequest(kToRoutersAndReeds);
delay = kParentRequestReedTimeout;
}
// initial MLE Parent Request has only R flag set in Scan Mask TLV for
// during initial attach or downgrade process
else
{
SendParentRequest(kToRouters);
delay = kParentRequestRouterTimeout;
SendParentRequest(type);
delay = (type == kToRouters) ? kParentRequestRouterTimeout : kParentRequestReedTimeout;
break;
}
break;
case kAttachStateParentRequestRouter:
SetAttachState(kAttachStateParentRequestReed);
SendParentRequest(kToRoutersAndReeds);
delay = kParentRequestReedTimeout;
break;
case kAttachStateParentRequestReed:
shouldAnnounce = PrepareAnnounceState();
if (shouldAnnounce)
@ -4199,22 +4237,20 @@ const char *Mle::AttachModeToString(AttachMode aMode)
const char *Mle::AttachStateToString(AttachState aState)
{
static const char *const kAttachStateStrings[] = {
"Idle", // (0) kAttachStateIdle
"ProcessAnnounce", // (1) kAttachStateProcessAnnounce
"Start", // (2) kAttachStateStart
"ParentReqRouters", // (3) kAttachStateParentRequestRouter
"ParentReqReeds", // (4) kAttachStateParentRequestReed
"Announce", // (5) kAttachStateAnnounce
"ChildIdReq", // (6) kAttachStateChildIdRequest
"Idle", // (0) kAttachStateIdle
"ProcessAnnounce", // (1) kAttachStateProcessAnnounce
"Start", // (2) kAttachStateStart
"ParentReq", // (3) kAttachStateParent
"Announce", // (4) kAttachStateAnnounce
"ChildIdReq", // (5) kAttachStateChildIdRequest
};
static_assert(kAttachStateIdle == 0, "kAttachStateIdle value is incorrect");
static_assert(kAttachStateProcessAnnounce == 1, "kAttachStateProcessAnnounce value is incorrect");
static_assert(kAttachStateStart == 2, "kAttachStateStart value is incorrect");
static_assert(kAttachStateParentRequestRouter == 3, "kAttachStateParentRequestRouter value is incorrect");
static_assert(kAttachStateParentRequestReed == 4, "kAttachStateParentRequestReed value is incorrect");
static_assert(kAttachStateAnnounce == 5, "kAttachStateAnnounce value is incorrect");
static_assert(kAttachStateChildIdRequest == 6, "kAttachStateChildIdRequest value is incorrect");
static_assert(kAttachStateParentRequest == 3, "kAttachStateParentRequest value is incorrect");
static_assert(kAttachStateAnnounce == 4, "kAttachStateAnnounce value is incorrect");
static_assert(kAttachStateChildIdRequest == 5, "kAttachStateChildIdRequest value is incorrect");
return kAttachStateStrings[aState];
}

View File

@ -812,13 +812,12 @@ protected:
*/
enum AttachState : uint8_t
{
kAttachStateIdle, ///< Not currently searching for a parent.
kAttachStateProcessAnnounce, ///< Waiting to process a received Announce (to switch channel/pan-id).
kAttachStateStart, ///< Starting to look for a parent.
kAttachStateParentRequestRouter, ///< Searching for a Router to attach to.
kAttachStateParentRequestReed, ///< Searching for Routers or REEDs to attach to.
kAttachStateAnnounce, ///< Send Announce messages
kAttachStateChildIdRequest, ///< Sending a Child ID Request message.
kAttachStateIdle, ///< Not currently searching for a parent.
kAttachStateProcessAnnounce, ///< Waiting to process a received Announce (to switch channel/pan-id).
kAttachStateStart, ///< Starting to look for a parent.
kAttachStateParentRequest, ///< Send Parent Request (current number tracked by `mParentRequestCounter`).
kAttachStateAnnounce, ///< Send Announce messages
kAttachStateChildIdRequest, ///< Sending a Child ID Request message.
};
/**
@ -1698,7 +1697,8 @@ protected:
Router mParentCandidate; ///< Parent candidate information.
NeighborTable mNeighborTable; ///< The neighbor table.
DeviceMode mDeviceMode; ///< Device mode setting.
AttachState mAttachState; ///< The parent request state.
AttachState mAttachState; ///< The attach state.
uint8_t mParentRequestCounter; ///< Number of parent requests while in `kAttachStateParentRequest`.
ReattachState mReattachState; ///< Reattach state
uint16_t mAttachCounter; ///< Attach attempt counter.
uint16_t mAnnounceDelay; ///< Delay in between sending Announce messages during attach.
@ -1731,6 +1731,20 @@ private:
static constexpr uint32_t kAttachBackoffDelayToResetCounter =
OPENTHREAD_CONFIG_MLE_ATTACH_BACKOFF_DELAY_TO_RESET_BACKOFF_INTERVAL;
#if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_3
// First attach cycle includes two Parent Requests to routers, followed by four to routers and REEDs.
static constexpr uint8_t kFirstAttachCycleTotalParentRequests = 6;
static constexpr uint8_t kFirstAttachCycleNumParentRequestToRouters = 2;
#else
// First attach cycle in Thread 1.1/1.2 includes a Parent Requests to routers, followed by one to routers and REEDs.
static constexpr uint8_t kFirstAttachCycleTotalParentRequests = 2;
static constexpr uint8_t kFirstAttachCycleNumParentRequestToRouters = 1;
#endif
// Next attach cycles includes one Parent Request to routers, followed by one to routers and REEDs.
static constexpr uint8_t kNextAttachCycleTotalParentRequests = 2;
static constexpr uint8_t kNextAttachCycleNumParentRequestToRouters = 1;
enum StartMode : uint8_t // Used in `Start()`.
{
kNormalAttach,
@ -1887,6 +1901,7 @@ private:
#endif
uint32_t Reattach(void);
bool HasAcceptableParentCandidate(void) const;
Error DetermineParentRequestType(ParentRequestType &aType) const;
bool IsBetterParent(uint16_t aRloc16,
LinkQuality aLinkQuality,

View File

@ -399,6 +399,10 @@ void MleRouter::SetStateRouter(uint16_t aRloc16)
RemoveNeighbor(child);
}
}
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
Get<Mac::Mac>().UpdateCsl();
#endif
}
void MleRouter::SetStateLeader(uint16_t aRloc16, LeaderStartMode aStartMode)
@ -440,6 +444,10 @@ void MleRouter::SetStateLeader(uint16_t aRloc16, LeaderStartMode aStartMode)
}
}
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
Get<Mac::Mac>().UpdateCsl();
#endif
LogNote("Leader partition id 0x%x", mLeaderData.GetPartitionId());
}

View File

@ -776,7 +776,7 @@ void MlrManager::LogMlrResponse(Error aResult,
void MlrManager::CheckInvariants(void) const
{
#if OPENTHREAD_EXAMPLES_SIMULATION
#if OPENTHREAD_EXAMPLES_SIMULATION && OPENTHREAD_CONFIG_ASSERT_ENABLE
uint16_t registeringNum = 0;
OT_ASSERT(!mMlrPending || mSendDelay == 0);

View File

@ -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;

View File

@ -30,7 +30,8 @@
#define OT_LIB_PLATFORM_RESET_UTIL_H_
#if defined(OPENTHREAD_ENABLE_COVERAGE) && OPENTHREAD_ENABLE_COVERAGE && defined(__GNUC__)
#if __GNUC__ >= 11
#if __GNUC__ >= 11 || (defined(__clang__) && (defined(__APPLE__) && (__clang_major__ >= 13)) || \
(!defined(__APPLE__) && (__clang_major__ >= 12)))
void __gcov_dump();
void __gcov_reset();
@ -42,7 +43,8 @@ static void flush_gcov(void)
#else
void __gcov_flush(void);
#define flush_gcov __gcov_flush
#endif // __GNUC__ >= 11
#endif /* __GNUC__ >= 11 || (defined(__clang__) && (defined(__APPLE__) && (__clang_major__ >= 13)) || \
(!defined(__APPLE__) && (__clang_major__ >= 12))) */
#else
#define flush_gcov()
#endif // defined(OPENTHREAD_ENABLE_COVERAGE) && OPENTHREAD_ENABLE_COVERAGE && defined(__GNUC__)

View File

@ -135,6 +135,8 @@ HdlcInterface::HdlcInterface(SpinelInterface::ReceiveFrameCallback aCallback,
, mHdlcDecoder(aFrameBuffer, HandleHdlcFrame, this)
, mRadioUrl(nullptr)
{
memset(&mInterfaceMetrics, 0, sizeof(mInterfaceMetrics));
mInterfaceMetrics.mRcpInterfaceType = OT_POSIX_RCP_BUS_UART;
}
void HdlcInterface::OnRcpReset(void)
@ -252,6 +254,19 @@ otError HdlcInterface::Write(const uint8_t *aFrame, uint16_t aLength)
exit:
#endif // OPENTHREAD_POSIX_VIRTUAL_TIME
mInterfaceMetrics.mTransferredFrameCount++;
if (error == OT_ERROR_NONE)
{
mInterfaceMetrics.mTxFrameCount++;
mInterfaceMetrics.mTxFrameByteCount += aLength;
mInterfaceMetrics.mTransferredValidFrameCount++;
}
else
{
mInterfaceMetrics.mTransferredGarbageFrameCount++;
}
return error;
}
@ -654,12 +669,18 @@ void HdlcInterface::HandleHdlcFrame(void *aContext, otError aError)
void HdlcInterface::HandleHdlcFrame(otError aError)
{
mInterfaceMetrics.mTransferredFrameCount++;
if (aError == OT_ERROR_NONE)
{
mInterfaceMetrics.mRxFrameCount++;
mInterfaceMetrics.mRxFrameByteCount += mReceiveFrameBuffer.GetLength();
mInterfaceMetrics.mTransferredValidFrameCount++;
mReceiveFrameCallback(mReceiveFrameContext);
}
else
{
mInterfaceMetrics.mTransferredGarbageFrameCount++;
mReceiveFrameBuffer.DiscardFrame();
otLogWarnPlat("Error decoding hdlc frame: %s", otThreadErrorToString(aError));
}

View File

@ -169,6 +169,14 @@ public:
*/
otError ResetConnection(void);
/**
* This method returns the RCP interface metrics.
*
* @returns The RCP interface metrics.
*
*/
const otRcpInterfaceMetrics *GetRcpInterfaceMetrics(void) const { return &mInterfaceMetrics; }
private:
/**
* This method instructs `HdlcInterface` to read and decode data from radio over the socket.
@ -258,6 +266,8 @@ private:
Hdlc::Decoder mHdlcDecoder;
const Url::Url *mRadioUrl;
otRcpInterfaceMetrics mInterfaceMetrics;
// Non-copyable, intentionally not implemented.
HdlcInterface(const HdlcInterface &);
HdlcInterface &operator=(const HdlcInterface &);

View File

@ -84,6 +84,22 @@ typedef struct otPlatformConfig
///< directly after initialization.
} otPlatformConfig;
/**
* This structure represents RCP interface metrics.
*
*/
typedef struct otRcpInterfaceMetrics
{
uint8_t mRcpInterfaceType; ///< The RCP interface type.
uint64_t mTransferredFrameCount; ///< The number of transferred frames.
uint64_t mTransferredValidFrameCount; ///< The number of transferred valid frames.
uint64_t mTransferredGarbageFrameCount; ///< The number of transferred garbage frames.
uint64_t mRxFrameCount; ///< The number of received frames.
uint64_t mRxFrameByteCount; ///< The number of received bytes.
uint64_t mTxFrameCount; ///< The number of transmitted frames.
uint64_t mTxFrameByteCount; ///< The number of transmitted bytes.
} otRcpInterfaceMetrics;
/**
* This function performs all platform-specific initialization of OpenThread's drivers and initializes the OpenThread
* instance.
@ -194,6 +210,14 @@ const char *otSysGetInfraNetifName(void);
*/
const otRadioSpinelMetrics *otSysGetRadioSpinelMetrics(void);
/**
* This method returns the RCP interface metrics.
*
* @returns The RCP interface metrics.
*
*/
const otRcpInterfaceMetrics *otSysGetRcpInterfaceMetrics(void);
#ifdef __cplusplus
} // end of extern "C"
#endif

View File

@ -665,3 +665,8 @@ const otRadioSpinelMetrics *otSysGetRadioSpinelMetrics(void)
{
return sRadioSpinel.GetRadioSpinelMetrics();
}
const otRcpInterfaceMetrics *otSysGetRcpInterfaceMetrics(void)
{
return sRadioSpinel.GetSpinelInterface().GetRcpInterfaceMetrics();
}

View File

@ -74,15 +74,8 @@ SpiInterface::SpiInterface(SpinelInterface::ReceiveFrameCallback aCallback,
, mResetGpioValueFd(-1)
, mIntGpioValueFd(-1)
, mSlaveResetCount(0)
, mSpiFrameCount(0)
, mSpiValidFrameCount(0)
, mSpiGarbageFrameCount(0)
, mSpiDuplexFrameCount(0)
, mSpiUnresponsiveFrameCount(0)
, mSpiRxFrameCount(0)
, mSpiRxFrameByteCount(0)
, mSpiTxFrameCount(0)
, mSpiTxFrameByteCount(0)
, mSpiTxIsReady(false)
, mSpiTxRefusedCount(0)
, mSpiTxPayloadSize(0)
@ -94,13 +87,14 @@ SpiInterface::SpiInterface(SpinelInterface::ReceiveFrameCallback aCallback,
void SpiInterface::OnRcpReset(void)
{
mSpiValidFrameCount = 0;
mSpiTxIsReady = false;
mSpiTxRefusedCount = 0;
mSpiTxPayloadSize = 0;
mDidPrintRateLimitLog = false;
mSpiSlaveDataLen = 0;
memset(mSpiTxFrameBuffer, 0, sizeof(mSpiTxFrameBuffer));
memset(&mInterfaceMetrics, 0, sizeof(mInterfaceMetrics));
mInterfaceMetrics.mRcpInterfaceType = OT_POSIX_RCP_BUS_SPI;
TriggerReset();
usleep(static_cast<useconds_t>(mSpiResetDelay) * kUsecPerMsec);
@ -402,7 +396,7 @@ otError SpiInterface::DoSpiTransfer(uint8_t *aSpiRxFrameBuffer, uint32_t aTransf
otDumpDebgPlat("SPI-TX", mSpiTxFrameBuffer, static_cast<uint16_t>(transfer[1].len));
otDumpDebgPlat("SPI-RX", aSpiRxFrameBuffer, static_cast<uint16_t>(transfer[1].len));
mSpiFrameCount++;
mInterfaceMetrics.mTransferredFrameCount++;
}
return (ret < 0) ? OT_ERROR_FAILED : OT_ERROR_NONE;
@ -421,7 +415,7 @@ otError SpiInterface::PushPullSpi(void)
Ncp::SpiFrame txFrame(mSpiTxFrameBuffer);
uint16_t skipAlignAllowanceLength;
if (mSpiValidFrameCount == 0)
if (mInterfaceMetrics.mTransferredValidFrameCount == 0)
{
// Set the reset flag to indicate to our slave that we are coming up from scratch.
txFrame.SetHeaderFlagByte(true);
@ -525,7 +519,7 @@ otError SpiInterface::PushPullSpi(void)
else
{
// Header is full of garbage
mSpiGarbageFrameCount++;
mInterfaceMetrics.mTransferredGarbageFrameCount++;
otLogWarnPlat("Garbage in header : %02X %02X %02X %02X %02X", spiRxFrame[0], spiRxFrame[1],
spiRxFrame[2], spiRxFrame[3], spiRxFrame[4]);
@ -542,7 +536,7 @@ otError SpiInterface::PushPullSpi(void)
if (!rxFrame.IsValid() || (slaveAcceptLen > kMaxFrameSize) || (mSpiSlaveDataLen > kMaxFrameSize))
{
mSpiGarbageFrameCount++;
mInterfaceMetrics.mTransferredGarbageFrameCount++;
mSpiTxRefusedCount++;
mSpiSlaveDataLen = 0;
@ -554,7 +548,7 @@ otError SpiInterface::PushPullSpi(void)
ExitNow();
}
mSpiValidFrameCount++;
mInterfaceMetrics.mTransferredValidFrameCount++;
if (rxFrame.IsResetFlagSet())
{
@ -567,9 +561,9 @@ otError SpiInterface::PushPullSpi(void)
// Handle received packet, if any.
if ((mSpiSlaveDataLen != 0) && (mSpiSlaveDataLen <= txFrame.GetHeaderAcceptLen()))
{
mSpiRxFrameByteCount += mSpiSlaveDataLen;
mInterfaceMetrics.mRxFrameByteCount += mSpiSlaveDataLen;
mSpiSlaveDataLen = 0;
mSpiRxFrameCount++;
mInterfaceMetrics.mRxFrameCount++;
successfulExchanges++;
// Set the skip length to skip align bytes and SPI frame header.
@ -594,8 +588,8 @@ otError SpiInterface::PushPullSpi(void)
// that uplayer can pull another packet for us to send.
successfulExchanges++;
mSpiTxFrameCount++;
mSpiTxFrameByteCount += mSpiTxPayloadSize;
mInterfaceMetrics.mTxFrameCount++;
mInterfaceMetrics.mTxFrameByteCount += mSpiTxPayloadSize;
mSpiTxIsReady = false;
mSpiTxPayloadSize = 0;
@ -833,16 +827,16 @@ void SpiInterface::LogError(const char *aString)
void SpiInterface::LogStats(void)
{
otLogInfoPlat("INFO: mSlaveResetCount=%" PRIu64, mSlaveResetCount);
otLogInfoPlat("INFO: mSpiFrameCount=%" PRIu64, mSpiFrameCount);
otLogInfoPlat("INFO: mSpiValidFrameCount=%" PRIu64, mSpiValidFrameCount);
otLogInfoPlat("INFO: mSpiDuplexFrameCount=%" PRIu64, mSpiDuplexFrameCount);
otLogInfoPlat("INFO: mSpiUnresponsiveFrameCount=%" PRIu64, mSpiUnresponsiveFrameCount);
otLogInfoPlat("INFO: mSpiGarbageFrameCount=%" PRIu64, mSpiGarbageFrameCount);
otLogInfoPlat("INFO: mSpiRxFrameCount=%" PRIu64, mSpiRxFrameCount);
otLogInfoPlat("INFO: mSpiRxFrameByteCount=%" PRIu64, mSpiRxFrameByteCount);
otLogInfoPlat("INFO: mSpiTxFrameCount=%" PRIu64, mSpiTxFrameCount);
otLogInfoPlat("INFO: mSpiTxFrameByteCount=%" PRIu64, mSpiTxFrameByteCount);
otLogInfoPlat("INFO: SlaveResetCount=%" PRIu64, mSlaveResetCount);
otLogInfoPlat("INFO: SpiDuplexFrameCount=%" PRIu64, mSpiDuplexFrameCount);
otLogInfoPlat("INFO: SpiUnresponsiveFrameCount=%" PRIu64, mSpiUnresponsiveFrameCount);
otLogInfoPlat("INFO: TransferredFrameCount=%" PRIu64, mInterfaceMetrics.mTransferredFrameCount);
otLogInfoPlat("INFO: TransferredValidFrameCount=%" PRIu64, mInterfaceMetrics.mTransferredValidFrameCount);
otLogInfoPlat("INFO: TransferredGarbageFrameCount=%" PRIu64, mInterfaceMetrics.mTransferredGarbageFrameCount);
otLogInfoPlat("INFO: RxFrameCount=%" PRIu64, mInterfaceMetrics.mRxFrameCount);
otLogInfoPlat("INFO: RxFrameByteCount=%" PRIu64, mInterfaceMetrics.mRxFrameByteCount);
otLogInfoPlat("INFO: TxFrameCount=%" PRIu64, mInterfaceMetrics.mTxFrameCount);
otLogInfoPlat("INFO: TxFrameByteCount=%" PRIu64, mInterfaceMetrics.mTxFrameByteCount);
}
} // namespace Posix
} // namespace ot

View File

@ -159,6 +159,14 @@ public:
*/
otError ResetConnection(void) { return OT_ERROR_NONE; }
/**
* This method returns the RCP interface metrics.
*
* @returns The RCP interface metrics.
*
*/
const otRcpInterfaceMetrics *GetRcpInterfaceMetrics(void) const { return &mInterfaceMetrics; }
private:
int SetupGpioHandle(int aFd, uint8_t aLine, uint32_t aHandleFlags, const char *aLabel);
int SetupGpioEvent(int aFd, uint8_t aLine, uint32_t aHandleFlags, uint32_t aEventFlags, const char *aLabel);
@ -228,15 +236,8 @@ private:
uint32_t mSpiSpeedHz;
uint64_t mSlaveResetCount;
uint64_t mSpiFrameCount;
uint64_t mSpiValidFrameCount;
uint64_t mSpiGarbageFrameCount;
uint64_t mSpiDuplexFrameCount;
uint64_t mSpiUnresponsiveFrameCount;
uint64_t mSpiRxFrameCount;
uint64_t mSpiRxFrameByteCount;
uint64_t mSpiTxFrameCount;
uint64_t mSpiTxFrameByteCount;
bool mSpiTxIsReady;
uint16_t mSpiTxRefusedCount;
@ -248,6 +249,8 @@ private:
bool mDidRxFrame;
otRcpInterfaceMetrics mInterfaceMetrics;
// Non-copyable, intentionally not implemented.
SpiInterface(const SpiInterface &);
SpiInterface &operator=(const SpiInterface &);

View File

@ -38,7 +38,7 @@ setup_leader
setup_node 3 "rdn" "router"
setup_node 2 "rdn" "router"
sleep 2
sleep 15
###########################################
# Verify topology and commissioners

View File

@ -38,7 +38,7 @@ expect_line "Done"
send "thread start\n"
expect_line "Done"
sleep 3
sleep 10
send "reset\n"
sleep 3

View File

@ -75,7 +75,7 @@ class Cert_5_1_01_RouterAttach(thread_cert.TestCase):
def test(self):
self.nodes[LEADER].start()
self.simulator.go(5)
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
self.nodes[ROUTER].start()

View File

@ -93,7 +93,7 @@ class Cert_5_1_02_ChildAddressTimeout(thread_cert.TestCase):
def test(self):
self.nodes[LEADER].start()
self.simulator.go(5)
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
self.nodes[ROUTER].start()

View File

@ -81,7 +81,7 @@ class Cert_5_1_03_RouterAddressReallocation(thread_cert.TestCase):
def test(self):
self.nodes[LEADER].start()
self.simulator.go(5)
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
self.nodes[ROUTER1].start()

View File

@ -83,7 +83,7 @@ class Cert_5_1_04_RouterAddressReallocation(thread_cert.TestCase):
def test(self):
self.nodes[LEADER].start()
self.simulator.go(5)
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
self.nodes[ROUTER1].start()

View File

@ -79,7 +79,7 @@ class Cert_5_1_05_RouterAddressTimeout(thread_cert.TestCase):
def test(self):
self.nodes[LEADER].start()
self.simulator.go(5)
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
self.nodes[ROUTER1].start()

View File

@ -75,7 +75,7 @@ class Cert_5_1_06_RemoveRouterId(thread_cert.TestCase):
def test(self):
self.nodes[LEADER].start()
self.simulator.go(5)
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
self.nodes[ROUTER1].start()

View File

@ -152,7 +152,7 @@ class Cert_5_1_07_MaxChildCount(thread_cert.TestCase):
def test(self):
self.nodes[LEADER].start()
self.simulator.go(5)
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
self.nodes[ROUTER].start()

View File

@ -93,7 +93,7 @@ class Cert_5_1_08_RouterAttachConnectivity(thread_cert.TestCase):
def test(self):
self.nodes[LEADER].start()
self.simulator.go(5)
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
for i in range(2, 5):

View File

@ -95,7 +95,7 @@ class Cert_5_1_09_REEDAttachConnectivity(thread_cert.TestCase):
def test(self):
self.nodes[LEADER].start()
self.simulator.go(5)
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
for i in range(2, 5):

View File

@ -87,7 +87,7 @@ class Cert_5_1_10_RouterAttachLinkQuality(thread_cert.TestCase):
def test(self):
self.nodes[LEADER].start()
self.simulator.go(5)
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
self.nodes[ROUTER1].start()

View File

@ -89,7 +89,7 @@ class Cert_5_1_11_REEDAttachLinkQuality(thread_cert.TestCase):
def test(self):
self.nodes[LEADER].start()
self.simulator.go(5)
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
self.nodes[REED].start()

View File

@ -78,7 +78,7 @@ class Cert_5_1_12_NewRouterSync(thread_cert.TestCase):
def test(self):
self.nodes[LEADER].start()
self.simulator.go(5)
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
self.nodes[ROUTER1].start()

View File

@ -80,7 +80,7 @@ class Cert_5_1_13_RouterReset(thread_cert.TestCase):
def test(self):
self.nodes[LEADER].start()
self.simulator.go(5)
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
self.nodes[ROUTER].start()

View File

@ -92,7 +92,7 @@ class Cert_5_2_01_REEDAttach(thread_cert.TestCase):
def test(self):
self.nodes[LEADER].start()
self.simulator.go(5)
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
self.nodes[DUT_ROUTER1].start()

View File

@ -311,7 +311,7 @@ class Cert_5_2_3_LeaderReject2Hops(thread_cert.TestCase):
def test(self):
self.nodes[DUT_LEADER].start()
self.simulator.go(5)
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[DUT_LEADER].get_state(), 'leader')
for i in range(2, 32):

View File

@ -169,7 +169,7 @@ class Cert_5_2_4_REEDUpgrade(thread_cert.TestCase):
def test(self):
self.nodes[LEADER].start()
self.simulator.go(5)
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
for i in range(2, 17):

View File

@ -177,7 +177,7 @@ class Cert_5_2_5_AddressQuery(thread_cert.TestCase):
def test(self):
# 1. LEADER: DHCPv6 Server for prefix 2001::/64.
self.nodes[LEADER].start()
self.simulator.go(5)
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
self.nodes[LEADER].add_prefix('2001::/64', 'pdros')
self.nodes[LEADER].register_netdata()

View File

@ -211,7 +211,7 @@ class Cert_5_2_06_RouterDowngrade(thread_cert.TestCase):
def test(self):
# 1 Ensure topology is formed correctly without ROUTER23.
self.nodes[LEADER].start()
self.simulator.go(5)
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
for i in range(2, 24):

View File

@ -146,7 +146,7 @@ class Cert_5_2_7_REEDSynchronization_Base(thread_cert.TestCase):
def test(self):
self.nodes[LEADER].start()
self.simulator.go(5)
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
for i in range(2, 17):

View File

@ -71,7 +71,7 @@ class Cert_5_3_1_LinkLocal(thread_cert.TestCase):
def test(self):
# 1
self.nodes[LEADER].start()
self.simulator.go(5)
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
self.nodes[DUT_ROUTER1].start()

View File

@ -89,7 +89,7 @@ class Cert_5_3_2_RealmLocal(thread_cert.TestCase):
def test(self):
# 1
self.nodes[LEADER].start()
self.simulator.go(5)
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
self.nodes[ROUTER1].start()

View File

@ -96,7 +96,7 @@ class Cert_5_3_3_AddressQuery(thread_cert.TestCase):
def test(self):
# 1
self.nodes[LEADER].start()
self.simulator.go(5)
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
self.nodes[ROUTER1].start()

View File

@ -113,7 +113,7 @@ class Cert_5_3_4_AddressMapCache(thread_cert.TestCase):
def test(self):
# 1
self.nodes[LEADER].start()
self.simulator.go(5)
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
self.nodes[DUT_ROUTER1].start()

View File

@ -86,7 +86,7 @@ class Cert_5_3_5_RoutingLinkQuality(thread_cert.TestCase):
def test(self):
# 1
self.nodes[LEADER].start()
self.simulator.go(5)
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
for router in range(DUT_ROUTER1, ROUTER3 + 1):

View File

@ -86,7 +86,7 @@ class Cert_5_3_6_RouterIdMask(thread_cert.TestCase):
def test(self):
# 1
self.nodes[DUT_LEADER].start()
self.simulator.go(5)
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[DUT_LEADER].get_state(), 'leader')
self.nodes[ROUTER1].start()

View File

@ -111,7 +111,7 @@ class Cert_5_3_7_DuplicateAddress(thread_cert.TestCase):
def test(self):
self.nodes[DUT_LEADER].start()
self.simulator.go(5)
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[DUT_LEADER].get_state(), 'leader')
for i in range(ROUTER1, MED2 + 1):

View File

@ -96,7 +96,7 @@ class Cert_5_3_8_ChildAddressSet(thread_cert.TestCase):
def test(self):
self.nodes[DUT_LEADER].start()
self.simulator.go(5)
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[DUT_LEADER].get_state(), 'leader')
self.nodes[BR].start()

View File

@ -109,7 +109,7 @@ class Cert_5_3_09_AddressQuery(thread_cert.TestCase):
def test(self):
# 1 & 2 ALL: Build and verify the topology
self.nodes[LEADER].start()
self.simulator.go(5)
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
# Configure the LEADER to be a DHCPv6 Border Router for prefixes

View File

@ -109,7 +109,7 @@ class Cert_5_3_10_AddressQuery(thread_cert.TestCase):
def test(self):
# 1 & 2
self.nodes[LEADER].start()
self.simulator.go(5)
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
self.nodes[BR].start()

View File

@ -85,7 +85,7 @@ class Cert_5_3_11_AddressQueryTimeoutIntervals(thread_cert.TestCase):
def test(self):
self.nodes[LEADER].start()
self.simulator.go(5)
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
self.nodes[DUT_ROUTER1].start()

View File

@ -79,7 +79,7 @@ class Cert_5_5_1_LeaderReboot(thread_cert.TestCase):
def test(self):
self.nodes[DUT_LEADER].start()
self.simulator.go(5)
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[DUT_LEADER].get_state(), 'leader')
self.nodes[DUT_ROUTER1].start()
@ -97,7 +97,7 @@ class Cert_5_5_1_LeaderReboot(thread_cert.TestCase):
self.nodes[DUT_LEADER].start()
self.simulator.go(5)
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[DUT_LEADER].get_state(), 'leader')
self.assertEqual(self.nodes[DUT_LEADER].get_addr16(), leader_rloc16)

View File

@ -67,7 +67,7 @@ class Cert_5_5_2_LeaderReboot(thread_cert.TestCase):
def test(self):
self.nodes[LEADER].start()
self.simulator.go(5)
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
self.nodes[ROUTER].start()
@ -80,7 +80,7 @@ class Cert_5_5_2_LeaderReboot(thread_cert.TestCase):
self.nodes[LEADER].reset()
self._setUpLeader()
self.simulator.go(140)
self.simulator.go(150)
self.assertEqual(self.nodes[ROUTER].get_state(), 'leader')
self.nodes[LEADER].start()

View File

@ -85,7 +85,7 @@ class Cert_5_5_3_SplitMergeChildren(thread_cert.TestCase):
def test(self):
self.nodes[LEADER].start()
self.simulator.go(5)
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
self.nodes[ROUTER1].start()
@ -108,7 +108,7 @@ class Cert_5_5_3_SplitMergeChildren(thread_cert.TestCase):
self._setUpLeader()
self.nodes[ROUTER2].set_preferred_partition_id(0xffffffff)
self.simulator.go(140)
self.simulator.go(150)
self.assertEqual(self.nodes[ROUTER1].get_state(), 'leader')
self.assertEqual(self.nodes[ROUTER2].get_state(), 'leader')

View File

@ -78,7 +78,7 @@ class Cert_5_5_4_SplitMergeRouters(thread_cert.TestCase):
def test(self):
self.nodes[LEADER].start()
self.simulator.go(5)
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
self.nodes[ROUTER1].start()

View File

@ -121,7 +121,7 @@ class Cert_5_5_5_SplitMergeREED(thread_cert.TestCase):
def test(self):
self.nodes[LEADER].start()
self.simulator.go(5)
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
for i in range(ROUTER2, ROUTER15 + 1):

View File

@ -73,7 +73,7 @@ class Cert_5_5_7_SplitMergeThreeWay(thread_cert.TestCase):
def test(self):
self.nodes[LEADER1].start()
self.simulator.go(5)
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER1].get_state(), 'leader')
self.nodes[ROUTER1].start()

View File

@ -72,7 +72,7 @@ class Cert_5_6_1_NetworkDataLeaderAsBr(thread_cert.TestCase):
def test(self):
self.nodes[LEADER].start()
self.simulator.go(4)
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
self.nodes[LEADER].add_prefix('2001:2:0:1::/64', 'paros')

View File

@ -72,7 +72,7 @@ class Cert_5_6_2_NetworkDataRouterAsBr(thread_cert.TestCase):
def test(self):
self.nodes[LEADER].start()
self.simulator.go(4)
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
self.nodes[ROUTER].start()

View File

@ -72,7 +72,7 @@ class Cert_5_6_3_NetworkDataRegisterAfterAttachLeader(thread_cert.TestCase):
def test(self):
self.nodes[LEADER].start()
self.simulator.go(4)
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
self.nodes[ROUTER].start()

View File

@ -72,7 +72,7 @@ class Cert_5_6_4_NetworkDataRegisterAfterAttachRouter(thread_cert.TestCase):
def test(self):
self.nodes[LEADER].start()
self.simulator.go(4)
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
self.nodes[ROUTER].start()

View File

@ -72,7 +72,7 @@ class Cert_5_6_5_NetworkDataRegisterAfterAttachRouter(thread_cert.TestCase):
def test(self):
self.nodes[LEADER].start()
self.simulator.go(4)
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
self.nodes[ROUTER].start()

View File

@ -72,7 +72,7 @@ class Cert_5_6_6_NetworkDataExpiration(thread_cert.TestCase):
def test(self):
self.nodes[LEADER].start()
self.simulator.go(4)
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
self.nodes[ROUTER].start()

View File

@ -120,7 +120,7 @@ class Cert_5_6_7_NetworkDataRequestREED(thread_cert.TestCase):
def test(self):
self.nodes[LEADER].start()
self.simulator.go(4)
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
for i in range(ROUTER1, ROUTER15 + 1):

View File

@ -78,7 +78,7 @@ class Cert_5_6_9_NetworkDataForwarding(thread_cert.TestCase):
def test(self):
self.nodes[LEADER].start()
self.simulator.go(4)
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
self.nodes[ROUTER1].start()

View File

@ -110,7 +110,7 @@ class Cert_5_7_01_CoapDiagCommands_Base(thread_cert.TestCase):
def test(self):
# 1 - Form topology
self.nodes[LEADER].start()
self.simulator.go(5)
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
self.nodes[ROUTER1].start()

View File

@ -159,7 +159,7 @@ class Cert_5_7_02_CoapDiagCommands(thread_cert.TestCase):
def test(self):
# 1 - Form topology
self.nodes[LEADER].start()
self.simulator.go(5)
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
for i in range(2, 17):

View File

@ -104,7 +104,7 @@ class Cert_5_7_03_CoapDiagCommands_Base(thread_cert.TestCase):
def test(self):
# 1 - Form topology
self.nodes[LEADER].start()
self.simulator.go(5)
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
self.nodes[ROUTER1].start()

View File

@ -56,7 +56,7 @@ class Cert_5_8_2_KeyIncrement(thread_cert.TestCase):
def test(self):
self.nodes[LEADER].start()
self.simulator.go(4)
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), "leader")
self.nodes[ROUTER].start()

View File

@ -57,7 +57,7 @@ class Cert_5_8_3_KeyIncrementRollOver(thread_cert.TestCase):
def test(self):
self.nodes[LEADER].start()
self.simulator.go(4)
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
self.nodes[ROUTER].start()

View File

@ -112,7 +112,7 @@ class Cert_5_8_04_SecurityPolicyTLV(thread_cert.TestCase):
def test(self):
self.nodes[LEADER].start()
self.simulator.go(5)
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
self.nodes[COMMISSIONER_1].start()

View File

@ -75,7 +75,7 @@ class Cert_6_1_1_RouterAttach_Base(thread_cert.TestCase):
def test(self):
self.nodes[LEADER].start()
self.simulator.go(5)
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
self.nodes[ED].start()

View File

@ -84,7 +84,7 @@ class Cert_6_1_2_REEDAttach_Base(thread_cert.TestCase):
def test(self):
self.nodes[LEADER].start()
self.simulator.go(5)
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
self.nodes[REED].start()

View File

@ -73,7 +73,7 @@ class Cert_6_1_3_RouterAttachConnectivity(thread_cert.TestCase):
def test(self):
self.nodes[LEADER].start()
self.simulator.go(5)
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
for i in range(2, 5):

View File

@ -96,7 +96,7 @@ class Cert_6_1_4_REEDAttachConnectivity_Base(thread_cert.TestCase):
def test(self):
self.nodes[LEADER].start()
self.simulator.go(5)
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
self.nodes[ROUTER].start()

View File

@ -75,7 +75,7 @@ class Cert_6_1_5_REEDAttachConnectivity(thread_cert.TestCase):
def test(self):
self.nodes[LEADER].start()
self.simulator.go(5)
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
self.nodes[ROUTER1].start()
@ -95,6 +95,8 @@ class Cert_6_1_5_REEDAttachConnectivity(thread_cert.TestCase):
self.assertEqual(self.nodes[ED].get_state(), 'child')
self.assertEqual(self.nodes[REED1].get_state(), 'router')
self.num_parent_requests = 1 if self.nodes[ED].version in ['1.1', '1.2'] else 2
self.collect_ipaddrs()
addrs = self.nodes[ED].get_addrs()
for addr in addrs:
@ -109,12 +111,14 @@ class Cert_6_1_5_REEDAttachConnectivity(thread_cert.TestCase):
_reed1_pkts = pkts.filter_wpan_src64(REED_1)
_ed_pkts = pkts.filter_wpan_src64(ED)
# Step 2: The DUT MUST send a MLE Parent Request to the
# Step 2: The DUT MUST send MLE Parent Requests to the
# All-Routers multicast address
_ed_pkts.filter_mle_cmd(MLE_PARENT_REQUEST).filter_ipv6_dst(
LINK_LOCAL_ALL_ROUTERS_MULTICAST_ADDRESS).must_next().must_verify(
lambda p: {MODE_TLV, CHALLENGE_TLV, SCAN_MASK_TLV, VERSION_TLV} == set(p.mle.tlv.type
) and p.mle.tlv.scan_mask.r == 1)
for num in range(self.num_parent_requests):
_ed_pkts.filter_mle_cmd(MLE_PARENT_REQUEST).filter_ipv6_dst(
LINK_LOCAL_ALL_ROUTERS_MULTICAST_ADDRESS).must_next().must_verify(
lambda p: {MODE_TLV, CHALLENGE_TLV, SCAN_MASK_TLV, VERSION_TLV} == set(
p.mle.tlv.type) and p.mle.tlv.scan_mask.r == 1)
# Step 3: REED_1 and REED_2 No response to Parent Request
# Step 4: DUT Send MLE Parent Request with Scan Mask set to Routers AND REEDs

View File

@ -91,7 +91,7 @@ class Cert_6_1_6_REEDAttachLinkQuality_Base(thread_cert.TestCase):
def test(self):
self.nodes[LEADER].start()
self.simulator.go(5)
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
self.nodes[REED].start()

View File

@ -67,7 +67,7 @@ class Cert_6_1_7_RouterAttachLinkQuality(thread_cert.TestCase):
def test(self):
self.nodes[LEADER].start()
self.simulator.go(5)
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
self.nodes[ROUTER1].start()

View File

@ -83,7 +83,7 @@ class Cert_6_2_1_NewPartition_Base(thread_cert.TestCase):
def test(self):
self.nodes[LEADER].start()
self.simulator.go(5)
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
self.nodes[ROUTER1].start()
@ -95,7 +95,7 @@ class Cert_6_2_1_NewPartition_Base(thread_cert.TestCase):
self.assertEqual(self.nodes[MTD].get_state(), 'child')
self.nodes[LEADER].stop()
self.simulator.go(140)
self.simulator.go(150)
self.assertEqual(self.nodes[ROUTER1].get_state(), 'leader')
self.assertEqual(self.nodes[MTD].get_state(), 'child')

View File

@ -68,7 +68,7 @@ class Cert_6_2_2_NewPartition(thread_cert.TestCase):
def test(self):
self.nodes[LEADER].start()
self.simulator.go(5)
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
self.nodes[ROUTER1].start()

View File

@ -62,7 +62,7 @@ class Cert_6_3_1_OrphanReattach(thread_cert.TestCase):
def test(self):
self.nodes[LEADER].start()
self.simulator.go(5)
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
self.nodes[ROUTER].start()

View File

@ -56,7 +56,7 @@ class Cert_6_3_2_NetworkDataUpdate(thread_cert.TestCase):
def test(self):
self.nodes[LEADER].start()
self.simulator.go(5)
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
self.nodes[ED].start()

View File

@ -75,7 +75,7 @@ class Cert_6_4_1_LinkLocal_Base(thread_cert.TestCase):
def test(self):
self.nodes[LEADER].start()
self.simulator.go(5)
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
self.nodes[MTD].start()

View File

@ -80,7 +80,7 @@ class Cert_6_4_2_RealmLocal_Base(thread_cert.TestCase):
def test(self):
self.nodes[LEADER].start()
self.simulator.go(5)
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
self.nodes[ROUTER].start()

View File

@ -59,7 +59,7 @@ class Cert_6_5_1_ChildResetReattach(thread_cert.TestCase):
def test(self):
self.nodes[LEADER].start()
self.simulator.go(5)
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
self.nodes[ED].start()

View File

@ -91,7 +91,7 @@ class Cert_6_5_2_ChildResetReattach_Base(thread_cert.TestCase):
def test(self):
self.nodes[LEADER].start()
self.simulator.go(5)
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
self.nodes[ROUTER].start()

View File

@ -60,7 +60,7 @@ class Cert_6_5_3_ChildResetSynchronize(thread_cert.TestCase):
def test(self):
self.nodes[LEADER].start()
self.simulator.go(5)
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
self.nodes[ED].start()

View File

@ -57,7 +57,7 @@ class Cert_6_6_1_KeyIncrement(thread_cert.TestCase):
def test(self):
self.nodes[LEADER].start()
self.simulator.go(5)
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), "leader")
self.nodes[ED].start()

View File

@ -58,7 +58,7 @@ class Cert_6_6_2_KeyIncrement1(thread_cert.TestCase):
def test(self):
self.nodes[LEADER].start()
self.simulator.go(5)
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
self.nodes[ED].start()

View File

@ -98,7 +98,7 @@ class Cert_7_1_1_BorderRouterAsLeader(thread_cert.TestCase):
def test(self):
self.nodes[LEADER].start()
self.simulator.go(5)
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
self.nodes[LEADER].add_prefix(PREFIX_2001, 'paros')

Some files were not shown because too many files have changed in this diff Show More