Merge pull request #69 from edmont/pr/upmerge-20220711
upmerge: merge up to commit '2ce3d3b'
This commit is contained in:
commit
b21e99b4b3
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
*
|
||||
|
|
|
@ -1495,5 +1495,181 @@ const char *Ip6::EcnToString(Ecn aEcn)
|
|||
|
||||
// LCOV_EXCL_STOP
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
// Headers
|
||||
|
||||
Error Headers::ParseFrom(const Message &aMessage)
|
||||
{
|
||||
Error error = kErrorParse;
|
||||
|
||||
Clear();
|
||||
|
||||
SuccessOrExit(mIp6Header.ParseFrom(aMessage));
|
||||
|
||||
switch (mIp6Header.GetNextHeader())
|
||||
{
|
||||
case kProtoUdp:
|
||||
SuccessOrExit(aMessage.Read(sizeof(Header), mHeader.mUdp));
|
||||
break;
|
||||
case kProtoTcp:
|
||||
SuccessOrExit(aMessage.Read(sizeof(Header), mHeader.mTcp));
|
||||
break;
|
||||
case kProtoIcmp6:
|
||||
SuccessOrExit(aMessage.Read(sizeof(Header), mHeader.mIcmp));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
error = kErrorNone;
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
Error Headers::DecompressFrom(const Message & aMessage,
|
||||
uint16_t aOffset,
|
||||
const Mac::Address &aMacSource,
|
||||
const Mac::Address &aMacDest)
|
||||
{
|
||||
static constexpr uint16_t kReadLength = Lowpan::FragmentHeader::kSubsequentFragmentHeaderSize + sizeof(Headers);
|
||||
|
||||
uint8_t frameBuffer[kReadLength];
|
||||
uint16_t frameLength;
|
||||
|
||||
frameLength = aMessage.ReadBytes(aOffset, frameBuffer, sizeof(frameBuffer));
|
||||
|
||||
return DecompressFrom(frameBuffer, frameLength, aMacSource, aMacDest, aMessage.GetInstance());
|
||||
}
|
||||
|
||||
Error Headers::DecompressFrom(const uint8_t * aFrame,
|
||||
uint16_t aFrameLength,
|
||||
const Mac::Address &aMacSource,
|
||||
const Mac::Address &aMacDest,
|
||||
Instance & aInstance)
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
Lowpan::FragmentHeader fragmentHeader;
|
||||
uint16_t fragmentHeaderLength;
|
||||
int headerLength;
|
||||
bool nextHeaderCompressed;
|
||||
|
||||
if (fragmentHeader.ParseFrom(aFrame, aFrameLength, fragmentHeaderLength) == kErrorNone)
|
||||
{
|
||||
// Only the first fragment header is followed by a LOWPAN_IPHC header
|
||||
VerifyOrExit(fragmentHeader.GetDatagramOffset() == 0, error = kErrorNotFound);
|
||||
aFrame += fragmentHeaderLength;
|
||||
aFrameLength -= fragmentHeaderLength;
|
||||
}
|
||||
|
||||
VerifyOrExit(aFrameLength >= 1 && Lowpan::Lowpan::IsLowpanHc(aFrame), error = kErrorNotFound);
|
||||
headerLength = aInstance.Get<Lowpan::Lowpan>().DecompressBaseHeader(mIp6Header, nextHeaderCompressed, aMacSource,
|
||||
aMacDest, aFrame, aFrameLength);
|
||||
|
||||
VerifyOrExit(headerLength > 0, error = kErrorParse);
|
||||
|
||||
aFrame += headerLength;
|
||||
aFrameLength -= headerLength;
|
||||
|
||||
switch (mIp6Header.GetNextHeader())
|
||||
{
|
||||
case kProtoUdp:
|
||||
if (nextHeaderCompressed)
|
||||
{
|
||||
headerLength = aInstance.Get<Lowpan::Lowpan>().DecompressUdpHeader(mHeader.mUdp, aFrame, aFrameLength);
|
||||
VerifyOrExit(headerLength >= 0, error = kErrorParse);
|
||||
}
|
||||
else
|
||||
{
|
||||
VerifyOrExit(aFrameLength >= sizeof(Udp::Header), error = kErrorParse);
|
||||
mHeader.mUdp = *reinterpret_cast<const Udp::Header *>(aFrame);
|
||||
}
|
||||
break;
|
||||
|
||||
case kProtoTcp:
|
||||
VerifyOrExit(aFrameLength >= sizeof(Tcp::Header), error = kErrorParse);
|
||||
mHeader.mTcp = *reinterpret_cast<const Tcp::Header *>(aFrame);
|
||||
break;
|
||||
|
||||
case kProtoIcmp6:
|
||||
VerifyOrExit(aFrameLength >= sizeof(Icmp::Header), error = kErrorParse);
|
||||
mHeader.mIcmp = *reinterpret_cast<const Icmp::Header *>(aFrame);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
uint16_t Headers::GetSourcePort(void) const
|
||||
{
|
||||
uint16_t port = 0;
|
||||
|
||||
switch (GetIpProto())
|
||||
{
|
||||
case kProtoUdp:
|
||||
port = mHeader.mUdp.GetSourcePort();
|
||||
break;
|
||||
|
||||
case kProtoTcp:
|
||||
port = mHeader.mTcp.GetSourcePort();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return port;
|
||||
}
|
||||
|
||||
uint16_t Headers::GetDestinationPort(void) const
|
||||
{
|
||||
uint16_t port = 0;
|
||||
|
||||
switch (GetIpProto())
|
||||
{
|
||||
case kProtoUdp:
|
||||
port = mHeader.mUdp.GetDestinationPort();
|
||||
break;
|
||||
|
||||
case kProtoTcp:
|
||||
port = mHeader.mTcp.GetDestinationPort();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return port;
|
||||
}
|
||||
|
||||
uint16_t Headers::GetChecksum(void) const
|
||||
{
|
||||
uint16_t checksum = 0;
|
||||
|
||||
switch (GetIpProto())
|
||||
{
|
||||
case kProtoUdp:
|
||||
checksum = mHeader.mUdp.GetChecksum();
|
||||
break;
|
||||
|
||||
case kProtoTcp:
|
||||
checksum = mHeader.mTcp.GetChecksum();
|
||||
break;
|
||||
|
||||
case kProtoIcmp6:
|
||||
checksum = mHeader.mIcmp.GetChecksum();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return checksum;
|
||||
}
|
||||
|
||||
} // namespace Ip6
|
||||
} // namespace ot
|
||||
|
|
|
@ -377,6 +377,193 @@ private:
|
|||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
* This class represents parsed IPv6 header along with UDP/TCP/ICMP6 headers from a received message/frame.
|
||||
*
|
||||
*/
|
||||
class Headers : private Clearable<Headers>
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* This method parses the IPv6 and UDP/TCP/ICMP6 headers from a given message.
|
||||
*
|
||||
* @param[in] aMessage The message to parse the headers from.
|
||||
*
|
||||
* @retval kErrorNone The headers are parsed successfully.
|
||||
* @retval kErrorParse Failed to parse the headers.
|
||||
*
|
||||
*/
|
||||
Error ParseFrom(const Message &aMessage);
|
||||
|
||||
/**
|
||||
* This method decompresses lowpan frame and parses the IPv6 and UDP/TCP/ICMP6 headers.
|
||||
*
|
||||
* @param[in] aMessage The message from which to read the lowpan frame.
|
||||
* @param[in] aOffset The offset in @p aMessage to start reading the frame.
|
||||
* @param[in] aMacSource The MAC source address.
|
||||
* @param[in] aMacDest The MAC destination address.
|
||||
*
|
||||
* @retval kErrorNone Successfully decompressed and parsed IPv6 and UDP/TCP/ICMP6 headers.
|
||||
* @retval kErrorNotFound Lowpan frame is a next fragment and does not contain IPv6 headers.
|
||||
* @retval kErrorParse Failed to parse the headers.
|
||||
*
|
||||
*/
|
||||
Error DecompressFrom(const Message & aMessage,
|
||||
uint16_t aOffset,
|
||||
const Mac::Address &aMacSource,
|
||||
const Mac::Address &aMacDest);
|
||||
|
||||
/**
|
||||
* This method decompresses lowpan frame and parses the IPv6 and UDP/TCP/ICMP6 headers.
|
||||
*
|
||||
* @param[in] aFrame Buffer containig the lowpan frame.
|
||||
* @param[in] aFrameLength Number of bytes in @p aFrame.
|
||||
* @param[in] aMacSource The MAC source address.
|
||||
* @param[in] aMacDest The MAC destination address.
|
||||
* @param[in] aInstance The OpenThread instance.
|
||||
*
|
||||
* @retval kErrorNone Successfully decompressed and parsed IPv6 and UDP/TCP/ICMP6 headers.
|
||||
* @retval kErrorNotFound Lowpan frame is a next fragment and does not contain IPv6 headers.
|
||||
* @retval kErrorParse Failed to parse the headers.
|
||||
*
|
||||
*/
|
||||
Error DecompressFrom(const uint8_t * aFrame,
|
||||
uint16_t aFrameLength,
|
||||
const Mac::Address &aMacSource,
|
||||
const Mac::Address &aMacDest,
|
||||
Instance & aInstance);
|
||||
|
||||
/**
|
||||
* This method returns the IPv6 header.
|
||||
*
|
||||
* @returns The IPv6 header.
|
||||
*
|
||||
*/
|
||||
const Header &GetIp6Header(void) const { return mIp6Header; }
|
||||
|
||||
/**
|
||||
* This method returns the IP protocol number from IPv6 Next Header field.
|
||||
*
|
||||
* @returns The IP protocol number.
|
||||
*
|
||||
*/
|
||||
uint8_t GetIpProto(void) const { return mIp6Header.GetNextHeader(); }
|
||||
|
||||
/**
|
||||
* This method returns the 2-bit Explicit Congestion Notification (ECN) from Traffic Class field from IPv6 header.
|
||||
*
|
||||
* @returns The ECN value.
|
||||
*
|
||||
*/
|
||||
Ecn GetEcn(void) const { return mIp6Header.GetEcn(); }
|
||||
|
||||
/**
|
||||
* This method indicates if the protocol number from IPv6 header is UDP.
|
||||
*
|
||||
* @retval TRUE If the protocol number in IPv6 header is UDP.
|
||||
* @retval FALSE If the protocol number in IPv6 header is not UDP.
|
||||
*
|
||||
*/
|
||||
bool IsUdp(void) const { return GetIpProto() == kProtoUdp; }
|
||||
|
||||
/**
|
||||
* This method indicates if the protocol number from IPv6 header is TCP.
|
||||
*
|
||||
* @retval TRUE If the protocol number in IPv6 header is TCP.
|
||||
* @retval FALSE If the protocol number in IPv6 header is not TCP.
|
||||
*
|
||||
*/
|
||||
bool IsTcp(void) const { return GetIpProto() == kProtoTcp; }
|
||||
|
||||
/**
|
||||
* This method indicates if the protocol number from IPv6 header is ICMPv6.
|
||||
*
|
||||
* @retval TRUE If the protocol number in IPv6 header is ICMPv6.
|
||||
* @retval FALSE If the protocol number in IPv6 header is not ICMPv6.
|
||||
*
|
||||
*/
|
||||
bool IsIcmp6(void) const { return GetIpProto() == kProtoIcmp6; }
|
||||
|
||||
/**
|
||||
* This method returns the source IPv6 address from IPv6 header.
|
||||
*
|
||||
* @returns The source IPv6 address.
|
||||
*
|
||||
*/
|
||||
const Address &GetSourceAddress(void) const { return mIp6Header.GetSource(); }
|
||||
|
||||
/**
|
||||
* This method returns the destination IPv6 address from IPv6 header.
|
||||
*
|
||||
* @returns The destination IPv6 address.
|
||||
*
|
||||
*/
|
||||
const Address &GetDestinationAddress(void) const { return mIp6Header.GetDestination(); }
|
||||
|
||||
/**
|
||||
* This method returns the UDP header.
|
||||
*
|
||||
* This method MUST be used when `IsUdp() == true`. Otherwise its behavior is undefined
|
||||
*
|
||||
* @returns The UDP header.
|
||||
*
|
||||
*/
|
||||
const Udp::Header &GetUdpHeader(void) const { return mHeader.mUdp; }
|
||||
|
||||
/**
|
||||
* This method returns the TCP header.
|
||||
*
|
||||
* This method MUST be used when `IsTcp() == true`. Otherwise its behavior is undefined
|
||||
*
|
||||
* @returns The TCP header.
|
||||
*
|
||||
*/
|
||||
const Tcp::Header &GetTcpHeader(void) const { return mHeader.mTcp; }
|
||||
|
||||
/**
|
||||
* This method returns the ICMPv6 header.
|
||||
*
|
||||
* This method MUST be used when `IsIcmp6() == true`. Otherwise its behavior is undefined
|
||||
*
|
||||
* @returns The ICMPv6 header.
|
||||
*
|
||||
*/
|
||||
const Icmp::Header &GetIcmpHeader(void) const { return mHeader.mIcmp; }
|
||||
|
||||
/**
|
||||
* This method returns the source port number if header is UDP or TCP, or zero otherwise
|
||||
*
|
||||
* @returns The source port number under UDP / TCP or zero.
|
||||
*
|
||||
*/
|
||||
uint16_t GetSourcePort(void) const;
|
||||
|
||||
/**
|
||||
* This method returns the destination port number if header is UDP or TCP, or zero otherwise.
|
||||
*
|
||||
* @returns The destination port number under UDP / TCP or zero.
|
||||
*
|
||||
*/
|
||||
uint16_t GetDestinationPort(void) const;
|
||||
|
||||
/**
|
||||
* This method returns the checksum values from corresponding UDP, TCP, or ICMPv6 header.
|
||||
*
|
||||
* @returns The checksum value.
|
||||
*
|
||||
*/
|
||||
uint16_t GetChecksum(void) const;
|
||||
|
||||
private:
|
||||
Header mIp6Header;
|
||||
union
|
||||
{
|
||||
Udp::Header mUdp;
|
||||
Tcp::Header mTcp;
|
||||
Icmp::Header mIcmp;
|
||||
} mHeader;
|
||||
};
|
||||
|
||||
/**
|
||||
* @}
|
||||
*
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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));
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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__)
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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 &);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -665,3 +665,8 @@ const otRadioSpinelMetrics *otSysGetRadioSpinelMetrics(void)
|
|||
{
|
||||
return sRadioSpinel.GetRadioSpinelMetrics();
|
||||
}
|
||||
|
||||
const otRcpInterfaceMetrics *otSysGetRcpInterfaceMetrics(void)
|
||||
{
|
||||
return sRadioSpinel.GetSpinelInterface().GetRcpInterfaceMetrics();
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 &);
|
||||
|
|
|
@ -38,7 +38,7 @@ setup_leader
|
|||
setup_node 3 "rdn" "router"
|
||||
setup_node 2 "rdn" "router"
|
||||
|
||||
sleep 2
|
||||
sleep 15
|
||||
|
||||
###########################################
|
||||
# Verify topology and commissioners
|
||||
|
|
|
@ -38,7 +38,7 @@ expect_line "Done"
|
|||
send "thread start\n"
|
||||
expect_line "Done"
|
||||
|
||||
sleep 3
|
||||
sleep 10
|
||||
|
||||
send "reset\n"
|
||||
sleep 3
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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')
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
Loading…
Reference in New Issue