[mle] improve MLE module comments (#9972)

This commit streamlines MLE module comments by simplifying
explanations and removing redundant ones that are clear from source
code.
This commit is contained in:
Abtin Keshavarzian
2024-03-27 14:36:46 -07:00
committed by GitHub
parent 7271b199d3
commit 34a0b0dd7e
2 changed files with 96 additions and 184 deletions
+40 -72
View File
@@ -454,7 +454,8 @@ void Mle::Restore(void)
mWasLeader = networkInfo.GetRole() == kRoleLeader;
#endif
// Successfully restored the network information from non-volatile settings after boot.
// Successfully restored the network information from
// non-volatile settings after boot.
mHasRestored = true;
exit:
@@ -533,7 +534,7 @@ Error Mle::BecomeDetached(void)
VerifyOrExit(!IsDetached() || mAttachState != kAttachStateStart);
// not in reattach stage after reset
// Not in reattach stage after reset
if (mReattachState == kReattachStop)
{
Get<MeshCoP::PendingDatasetManager>().HandleDetach();
@@ -1120,7 +1121,6 @@ void Mle::HandleNotifierEvents(Events aEvents)
{
if (!Get<ThreadNetif>().HasUnicastAddress(mMeshLocal64.GetAddress()))
{
// Mesh Local EID was removed, choose a new one and add it back
mMeshLocal64.GetAddress().GetIid().GenerateRandom();
Get<ThreadNetif>().AddUnicastAddress(mMeshLocal64);
@@ -1135,9 +1135,12 @@ void Mle::HandleNotifierEvents(Events aEvents)
if (aEvents.ContainsAny(kEventIp6MulticastSubscribed | kEventIp6MulticastUnsubscribed))
{
// When multicast subscription changes, SED always notifies its parent as it depends on its
// parent for indirect transmission. Since Thread 1.2, MED MAY also notify its parent of 1.2
// or higher version as it could depend on its parent to perform Multicast Listener Report.
// When multicast subscription changes, SED always notifies
// its parent as it depends on its parent for indirect
// transmission. Since Thread 1.2, MED MAY also notify its
// parent of 1.2 or higher version as it could depend on its
// parent to perform Multicast Listener Report.
if (IsChild() && !IsFullThreadDevice() &&
(!IsRxOnWhenIdle()
#if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2)
@@ -1577,7 +1580,7 @@ uint32_t Mle::Reattach(void)
}
else if (!IsRxOnWhenIdle())
{
// return to sleepy operation
// Return to sleepy operation
Get<DataPollSender>().SetAttachMode(false);
Get<MeshForwarder>().SetRxOnWhenIdle(false);
}
@@ -1653,7 +1656,6 @@ void Mle::SendDelayedResponse(TxMessage &aMessage, const DelayedResponseMetadata
exit:
if (error != kErrorNone)
{
// do not use `FreeMessageOnError()` to avoid null check on nonnull pointer
aMessage.Free();
}
}
@@ -1782,9 +1784,13 @@ Error Mle::SendChildIdRequest(void)
{
// Invalidate stale parent state.
//
// Parent state is not normally invalidated after becoming a Router/Leader (see #1875). When trying to
// attach to a better partition, invalidating old parent state (especially when in kStateRestored) ensures
// that FindNeighbor() returns mParentCandidate when processing the Child ID Response.
// Parent state is not normally invalidated after becoming
// a Router/Leader (see #1875). When trying to attach to
// a better partition, invalidating old parent state
// (especially when in `kStateRestored`) ensures that
// `FindNeighbor()` returns `mParentCandidate` when
// processing the Child ID Response.
mParent.SetState(Neighbor::kStateInvalid);
}
}
@@ -1802,7 +1808,7 @@ Error Mle::SendChildIdRequest(void)
{
SuccessOrExit(error = message->AppendAddressRegistrationTlv(mAddressRegistrationMode));
// no need to request the last Route64 TLV for MTD
// No need to request the last Route64 TLV for MTD
tlvsLen -= 1;
}
@@ -2011,9 +2017,8 @@ void Mle::HandleMessageTransmissionTimer(void)
case kChildUpdateRequestPending:
if (Get<Notifier>().IsPending())
{
// Here intentionally delay another kChildUpdateRequestPendingDelay
// cycle to ensure we only send a Child Update Request after we
// know there are no more pending changes.
// Add another delay to ensures the Child Update Request is sent
// only after all pending changes are incorporated.
ScheduleMessageTransmissionTimer();
ExitNow();
}
@@ -2880,11 +2885,8 @@ void Mle::HandleDataResponse(RxInfo &aRxInfo)
if (mDataRequestState == kDataRequestNone && !IsRxOnWhenIdle())
{
// Here simply stops fast data poll request by Mle Data Request.
// Note that in some cases fast data poll may continue after below stop operation until
// running out the specified number. E.g. other component also trigger fast poll, and
// is waiting for response; or the corner case where multiple Mle Data Request attempts
// happened due to the retransmission mechanism.
// Stop fast data poll request by MLE since we received
// the response.
Get<DataPollSender>().StopFastPolls();
}
@@ -2918,7 +2920,6 @@ Error Mle::HandleLeaderData(RxInfo &aRxInfo)
uint16_t pendingDatasetLength = 0;
bool dataRequest = false;
// Leader Data
SuccessOrExit(error = aRxInfo.mMessage.ReadLeaderDataTlv(leaderData));
if ((leaderData.GetPartitionId() != mLeaderData.GetPartitionId()) ||
@@ -2939,7 +2940,6 @@ Error Mle::HandleLeaderData(RxInfo &aRxInfo)
VerifyOrExit(IsNetworkDataNewer(leaderData));
}
// Active Timestamp
switch (Tlv::Find<ActiveTimestampTlv>(aRxInfo.mMessage, activeTimestamp))
{
case kErrorNone:
@@ -2947,8 +2947,9 @@ Error Mle::HandleLeaderData(RxInfo &aRxInfo)
timestamp = Get<MeshCoP::ActiveDatasetManager>().GetTimestamp();
// if received timestamp does not match the local value and message does not contain the dataset,
// send MLE Data Request
// Send an MLE Data Request if the received timestamp
// mismatches the local value and the message does not
// include the dataset.
if (!IsLeader() && (MeshCoP::Timestamp::Compare(&activeTimestamp, timestamp) != 0) &&
(Tlv::FindTlvValueOffset(aRxInfo.mMessage, Tlv::kActiveDataset, activeDatasetOffset, activeDatasetLength) !=
kErrorNone))
@@ -2965,7 +2966,6 @@ Error Mle::HandleLeaderData(RxInfo &aRxInfo)
ExitNow(error = kErrorParse);
}
// Pending Timestamp
switch (Tlv::Find<PendingTimestampTlv>(aRxInfo.mMessage, pendingTimestamp))
{
case kErrorNone:
@@ -2973,8 +2973,6 @@ Error Mle::HandleLeaderData(RxInfo &aRxInfo)
timestamp = Get<MeshCoP::PendingDatasetManager>().GetTimestamp();
// if received timestamp does not match the local value and message does not contain the dataset,
// send MLE Data Request
if (!IsLeader() && (MeshCoP::Timestamp::Compare(&pendingTimestamp, timestamp) != 0) &&
(Tlv::FindTlvValueOffset(aRxInfo.mMessage, Tlv::kPendingDataset, pendingDatasetOffset,
pendingDatasetLength) != kErrorNone))
@@ -3012,7 +3010,6 @@ Error Mle::HandleLeaderData(RxInfo &aRxInfo)
else
#endif
{
// Active Dataset
if (hasActiveTimestamp)
{
if (activeDatasetOffset > 0)
@@ -3022,7 +3019,6 @@ Error Mle::HandleLeaderData(RxInfo &aRxInfo)
}
}
// Pending Dataset
if (hasPendingTimestamp)
{
if (pendingDatasetOffset > 0)
@@ -3154,16 +3150,13 @@ void Mle::HandleParentResponse(RxInfo &aRxInfo)
TimeParameterTlv timeParameterTlv;
#endif
// Source Address
SuccessOrExit(error = Tlv::Find<SourceAddressTlv>(aRxInfo.mMessage, sourceAddress));
Log(kMessageReceive, kTypeParentResponse, aRxInfo.mMessageInfo.GetPeerAddr(), sourceAddress);
// Version
SuccessOrExit(error = Tlv::Find<VersionTlv>(aRxInfo.mMessage, version));
VerifyOrExit(version >= kThreadVersion1p1, error = kErrorParse);
// Response
SuccessOrExit(error = aRxInfo.mMessage.ReadResponseTlv(response));
VerifyOrExit(response == mParentRequestChallenge, error = kErrorParse);
@@ -3174,20 +3167,16 @@ void Mle::HandleParentResponse(RxInfo &aRxInfo)
mReceivedResponseFromParent = true;
}
// Leader Data
SuccessOrExit(error = aRxInfo.mMessage.ReadLeaderDataTlv(leaderData));
// Link Margin
SuccessOrExit(error = Tlv::Find<LinkMarginTlv>(aRxInfo.mMessage, linkMarginFromTlv));
linkMargin = Min(Get<Mac::Mac>().ComputeLinkMargin(rss), linkMarginFromTlv);
linkQuality = LinkQualityForLinkMargin(linkMargin);
// Connectivity
SuccessOrExit(error = Tlv::FindTlv(aRxInfo.mMessage, connectivityTlv));
VerifyOrExit(connectivityTlv.IsValid(), error = kErrorParse);
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
// CSL Accuracy
switch (aRxInfo.mMessage.ReadCslClockAccuracyTlv(cslAccuracy))
{
case kErrorNone:
@@ -3260,7 +3249,7 @@ void Mle::HandleParentResponse(RxInfo &aRxInfo)
if (mParentCandidate.IsStateParentResponse() && (mParentCandidate.GetExtAddress() != extAddress))
{
// if already have a candidate parent, only seek a better parent
// If already have a candidate parent, only seek a better parent
int compare = 0;
@@ -3271,23 +3260,21 @@ void Mle::HandleParentResponse(RxInfo &aRxInfo)
mParentCandidate.mIsSingleton, mParentCandidate.mLeaderData);
}
// only consider partitions that are the same or better
// Only consider partitions that are the same or better
VerifyOrExit(compare >= 0);
#endif
// only consider better parents if the partitions are the same
// Only consider better parents if the partitions are the same
if (compare == 0)
{
VerifyOrExit(IsBetterParent(sourceAddress, linkQuality, linkMargin, connectivityTlv, version, cslAccuracy));
}
}
// Link/MLE Frame Counters
SuccessOrExit(error = aRxInfo.mMessage.ReadFrameCounterTlvs(linkFrameCounter, mleFrameCounter));
#if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
// Time Parameter
if (Tlv::FindTlv(aRxInfo.mMessage, timeParameterTlv) == kErrorNone)
{
VerifyOrExit(timeParameterTlv.IsValid());
@@ -3299,14 +3286,13 @@ void Mle::HandleParentResponse(RxInfo &aRxInfo)
#if OPENTHREAD_CONFIG_TIME_SYNC_REQUIRED
else
{
// If the time sync feature is required, don't choose the parent which doesn't support it.
// If the time sync feature is required, don't choose the
// parent which doesn't support it.
ExitNow();
}
#endif // OPENTHREAD_CONFIG_TIME_SYNC_REQUIRED
#endif
#endif // OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
// Challenge
SuccessOrExit(error = aRxInfo.mMessage.ReadChallengeTlv(mParentCandidate.mRxChallenge));
InitNeighbor(mParentCandidate, aRxInfo);
@@ -3351,7 +3337,6 @@ void Mle::HandleChildIdResponse(RxInfo &aRxInfo)
uint16_t offset;
uint16_t length;
// Source Address
SuccessOrExit(error = Tlv::Find<SourceAddressTlv>(aRxInfo.mMessage, sourceAddress));
Log(kMessageReceive, kTypeChildIdResponse, aRxInfo.mMessageInfo.GetPeerAddr(), sourceAddress);
@@ -3360,22 +3345,17 @@ void Mle::HandleChildIdResponse(RxInfo &aRxInfo)
VerifyOrExit(mAttachState == kAttachStateChildIdRequest);
// ShortAddress
SuccessOrExit(error = Tlv::Find<Address16Tlv>(aRxInfo.mMessage, shortAddress));
VerifyOrExit(RouterIdMatch(sourceAddress, shortAddress), error = kErrorRejected);
// Leader Data
SuccessOrExit(error = aRxInfo.mMessage.ReadLeaderDataTlv(leaderData));
// Network Data
SuccessOrExit(
error = Tlv::FindTlvValueOffset(aRxInfo.mMessage, Tlv::kNetworkData, networkDataOffset, networkDataLength));
// Active Timestamp
switch (Tlv::Find<ActiveTimestampTlv>(aRxInfo.mMessage, timestamp))
{
case kErrorNone:
// Active Dataset
if (Tlv::FindTlvValueOffset(aRxInfo.mMessage, Tlv::kActiveDataset, offset, length) == kErrorNone)
{
SuccessOrExit(error =
@@ -3390,17 +3370,15 @@ void Mle::HandleChildIdResponse(RxInfo &aRxInfo)
ExitNow(error = kErrorParse);
}
// clear Pending Dataset if device succeed to reattach using stored Pending Dataset
// Clear Pending Dataset if device succeed to reattach using stored Pending Dataset
if (mReattachState == kReattachPending)
{
Get<MeshCoP::PendingDatasetManager>().Clear();
}
// Pending Timestamp
switch (Tlv::Find<PendingTimestampTlv>(aRxInfo.mMessage, timestamp))
{
case kErrorNone:
// Pending Dataset
if (Tlv::FindTlvValueOffset(aRxInfo.mMessage, Tlv::kPendingDataset, offset, length) == kErrorNone)
{
IgnoreError(Get<MeshCoP::PendingDatasetManager>().Save(timestamp, aRxInfo.mMessage, offset, length));
@@ -3416,7 +3394,6 @@ void Mle::HandleChildIdResponse(RxInfo &aRxInfo)
}
#if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
// Sync to Thread network time
if (aRxInfo.mMessage.GetTimeSyncSeq() != OT_TIME_SYNC_INVALID_SEQ)
{
Get<TimeSync>().HandleTimeSyncMessage(aRxInfo.mMessage);
@@ -3472,12 +3449,10 @@ void Mle::HandleChildUpdateRequest(RxInfo &aRxInfo)
TlvList requestedTlvList;
TlvList tlvList;
// Source Address
SuccessOrExit(error = Tlv::Find<SourceAddressTlv>(aRxInfo.mMessage, sourceAddress));
Log(kMessageReceive, kTypeChildUpdateRequestAsChild, aRxInfo.mMessageInfo.GetPeerAddr(), sourceAddress);
// Challenge
switch (aRxInfo.mMessage.ReadChallengeTlv(challenge))
{
case kErrorNone:
@@ -3513,7 +3488,6 @@ void Mle::HandleChildUpdateRequest(RxInfo &aRxInfo)
ExitNow();
}
// Leader Data, Network Data, Active Timestamp, Pending Timestamp
SuccessOrExit(error = HandleLeaderData(aRxInfo));
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
@@ -3522,7 +3496,8 @@ void Mle::HandleChildUpdateRequest(RxInfo &aRxInfo)
if (aRxInfo.mMessage.ReadCslClockAccuracyTlv(cslAccuracy) == kErrorNone)
{
// MUST include CSL timeout TLV when request includes CSL accuracy
// MUST include CSL timeout TLV when request includes
// CSL accuracy
tlvList.Add(Tlv::kCslTimeout);
}
}
@@ -3530,11 +3505,10 @@ void Mle::HandleChildUpdateRequest(RxInfo &aRxInfo)
}
else
{
// this device is not a child of the Child Update Request source
// This device is not a child of the Child Update Request source
tlvList.Add(Tlv::kStatus);
}
// TLV Request
switch (aRxInfo.mMessage.ReadTlvRequestTlv(requestedTlvList))
{
case kErrorNone:
@@ -3556,7 +3530,8 @@ void Mle::HandleChildUpdateRequest(RxInfo &aRxInfo)
}
#endif
// Send the response to the requester, regardless if it's this device's parent or not
// Send the response to the requester, regardless if it's this
// device's parent or not.
SuccessOrExit(error = SendChildUpdateResponse(tlvList, challenge, aRxInfo.mMessageInfo.GetPeerAddr()));
exit:
@@ -3601,14 +3576,12 @@ void Mle::HandleChildUpdateResponse(RxInfo &aRxInfo)
OT_ASSERT(false);
}
// Status
if (Tlv::Find<StatusTlv>(aRxInfo.mMessage, status) == kErrorNone)
{
IgnoreError(BecomeDetached());
ExitNow();
}
// Mode
SuccessOrExit(error = Tlv::Find<ModeTlv>(aRxInfo.mMessage, mode));
VerifyOrExit(DeviceMode(mode) == mDeviceMode, error = kErrorDrop);
@@ -3636,7 +3609,6 @@ void Mle::HandleChildUpdateResponse(RxInfo &aRxInfo)
OT_FALL_THROUGH;
case kRoleChild:
// Source Address
SuccessOrExit(error = Tlv::Find<SourceAddressTlv>(aRxInfo.mMessage, sourceAddress));
if (RouterIdFromRloc16(sourceAddress) != RouterIdFromRloc16(GetRloc16()))
@@ -3645,10 +3617,8 @@ void Mle::HandleChildUpdateResponse(RxInfo &aRxInfo)
ExitNow();
}
// Leader Data, Network Data, Active Timestamp, Pending Timestamp
SuccessOrExit(error = HandleLeaderData(aRxInfo));
// Timeout optional
switch (Tlv::Find<TimeoutTlv>(aRxInfo.mMessage, timeout))
{
case kErrorNone:
@@ -3671,7 +3641,6 @@ void Mle::HandleChildUpdateResponse(RxInfo &aRxInfo)
{
Mac::CslAccuracy cslAccuracy;
// CSL Accuracy
switch (aRxInfo.mMessage.ReadCslClockAccuracyTlv(cslAccuracy))
{
case kErrorNone:
@@ -3820,8 +3789,7 @@ void Mle::HandleLinkMetricsManagementRequest(RxInfo &aRxInfo)
exit:
LogProcessError(kTypeLinkMetricsManagementRequest, error);
}
#endif // OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
#endif
#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE
void Mle::HandleLinkMetricsManagementResponse(RxInfo &aRxInfo)
@@ -3840,7 +3808,7 @@ void Mle::HandleLinkMetricsManagementResponse(RxInfo &aRxInfo)
exit:
LogProcessError(kTypeLinkMetricsManagementResponse, error);
}
#endif // OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE
#endif
#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
void Mle::HandleLinkProbe(RxInfo &aRxInfo)
@@ -3861,7 +3829,7 @@ void Mle::HandleLinkProbe(RxInfo &aRxInfo)
exit:
LogProcessError(kTypeLinkProbe, error);
}
#endif // OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
#endif
void Mle::ProcessAnnounce(void)
{
+56 -112
View File
@@ -363,15 +363,22 @@ void MleRouter::HandleChildStart(AttachMode aMode)
case kAnyPartition:
case kBetterParent:
// If attach was started due to receiving MLE Announce Messages, all rx-on-when-idle devices would
// start attach immediately when receiving such Announce message as in Thread 1.1 specification,
// Section 4.8.1,
// "If the received value is newer and the channel and/or PAN ID in the Announce message differ
// from those currently in use, the receiving device attempts to attach using the channel and
// PAN ID received from the Announce message."
// If attach was initiated due to receiving an MLE Announce
// message, all rx-on-when-idle devices will immediately
// attempt to attach as well. This aligns with the Thread 1.1
// specification (Section 4.8.1):
//
// That is, Parent-child relationship is highly unlikely to be kept in the new partition, so here
// removes all children, leaving whether to become router according to the new partition status.
// "If the received value is newer and the channel and/or PAN
// ID in the Announce message differ from those currently in
// use, the receiving device attempts to attach using the
// channel and PAN ID received from the Announce message."
//
// Since parent-child relationships are unlikely to persist in
// the new partition, we remove all children here. The
// decision to become router is determined based on the new
// partition's status.
if (IsAnnounceAttach() && HasChildren())
{
RemoveChildren();
@@ -442,7 +449,7 @@ void MleRouter::SetStateRouterOrLeader(DeviceRole aRole, uint16_t aRloc16, Leade
Get<AddressResolver>().Clear();
}
// Remove children that do not have matching RLOC16
// Remove children that do not have a matching RLOC16
for (Child &child : Get<ChildTable>().Iterate(Child::kInStateValidOrRestoring))
{
if (RouterIdFromRloc16(child.GetRloc16()) != mRouterId)
@@ -521,17 +528,19 @@ void MleRouter::SendAdvertisement(void)
Ip6::Address destination;
TxMessage *message = nullptr;
// Suppress MLE Advertisements when trying to attach to a better partition.
//
// Without this suppression, a device may send an MLE Advertisement before receiving the MLE Child ID Response.
// The candidate parent then removes the attaching device because the Source Address TLV includes an RLOC16 that
// indicates a Router role (i.e. a Child ID equal to zero).
// Suppress MLE Advertisements when trying to attach to a better
// partition. Without this, a candidate parent might incorrectly
// interpret this advertisement (Source Address TLV containing an
// RLOC16 indicating device is acting as router) and reject the
// attaching device.
VerifyOrExit(!IsAttaching());
// Suppress MLE Advertisements when transitioning to the router role.
//
// When trying to attach to a new partition, sending out advertisements as a REED can cause already-attached
// children to detach.
// Suppress MLE Advertisements when attempting to transition to
// router role. Advertisements as a REED while attaching to a new
// partition can cause existing children to detach
// unnecessarily.
VerifyOrExit(!mAddressSolicitPending);
VerifyOrExit((message = NewMleMessage(kCommandAdvertisement)) != nullptr, error = kErrorNoBufs);
@@ -665,14 +674,11 @@ void MleRouter::HandleLinkRequest(RxInfo &aRxInfo)
VerifyOrExit(!IsAttaching(), error = kErrorInvalidState);
// Challenge
SuccessOrExit(error = aRxInfo.mMessage.ReadChallengeTlv(challenge));
// Version
SuccessOrExit(error = Tlv::Find<VersionTlv>(aRxInfo.mMessage, version));
VerifyOrExit(version >= kThreadVersion1p1, error = kErrorParse);
// Leader Data
switch (aRxInfo.mMessage.ReadLeaderDataTlv(leaderData))
{
case kErrorNone:
@@ -684,7 +690,6 @@ void MleRouter::HandleLinkRequest(RxInfo &aRxInfo)
ExitNow(error = kErrorParse);
}
// Source Address
switch (Tlv::Find<SourceAddressTlv>(aRxInfo.mMessage, sourceAddress))
{
case kErrorNone:
@@ -711,7 +716,8 @@ void MleRouter::HandleLinkRequest(RxInfo &aRxInfo)
break;
case kErrorNotFound:
// lack of source address indicates router coming out of reset
// A missing source address indicates that the router was
// recently reset.
VerifyOrExit(aRxInfo.IsNeighborStateValid() && IsActiveRouter(aRxInfo.mNeighbor->GetRloc16()),
error = kErrorDrop);
neighbor = aRxInfo.mNeighbor;
@@ -721,7 +727,6 @@ void MleRouter::HandleLinkRequest(RxInfo &aRxInfo)
ExitNow(error = kErrorParse);
}
// TLV Request
switch (aRxInfo.mMessage.ReadTlvRequestTlv(requestedTlvList))
{
case kErrorNone:
@@ -775,9 +780,7 @@ Error MleRouter::SendLinkAccept(const RxInfo &aRxInfo,
SuccessOrExit(error = message->AppendLinkFrameCounterTlv());
SuccessOrExit(error = message->AppendMleFrameCounterTlv());
// always append a link margin, regardless of whether or not it was requested
linkMargin = Get<Mac::Mac>().ComputeLinkMargin(aRxInfo.mMessage.GetAverageRss());
SuccessOrExit(error = message->AppendLinkMarginTlv(linkMargin));
if (aNeighbor != nullptr && IsActiveRouter(aNeighbor->GetRloc16()))
@@ -874,7 +877,6 @@ Error MleRouter::HandleLinkAccept(RxInfo &aRxInfo, bool aRequest)
LeaderData leaderData;
uint8_t linkMargin;
// Source Address
SuccessOrExit(error = Tlv::Find<SourceAddressTlv>(aRxInfo.mMessage, sourceAddress));
Log(kMessageReceive, aRequest ? kTypeLinkAcceptAndRequest : kTypeLinkAccept, aRxInfo.mMessageInfo.GetPeerAddr(),
@@ -886,10 +888,8 @@ Error MleRouter::HandleLinkAccept(RxInfo &aRxInfo, bool aRequest)
router = mRouterTable.FindRouterById(routerId);
neighborState = (router != nullptr) ? router->GetState() : Neighbor::kStateInvalid;
// Response
SuccessOrExit(error = aRxInfo.mMessage.ReadResponseTlv(response));
// verify response
switch (neighborState)
{
case Neighbor::kStateLinkRequest:
@@ -915,22 +915,20 @@ Error MleRouter::HandleLinkAccept(RxInfo &aRxInfo, bool aRequest)
RemoveNeighbor(*aRxInfo.mNeighbor);
}
// Version
SuccessOrExit(error = Tlv::Find<VersionTlv>(aRxInfo.mMessage, version));
VerifyOrExit(version >= kThreadVersion1p1, error = kErrorParse);
// Link and MLE Frame Counters
SuccessOrExit(error = aRxInfo.mMessage.ReadFrameCounterTlvs(linkFrameCounter, mleFrameCounter));
// Link Margin
switch (Tlv::Find<LinkMarginTlv>(aRxInfo.mMessage, linkMargin))
{
case kErrorNone:
break;
case kErrorNotFound:
// Link Margin TLV may be skipped in Router Synchronization process after Reset
// The Link Margin TLV may be omitted after a reset. We wait
// for MLE Advertisements to establish the routing cost to
// the neighbor
VerifyOrExit(IsDetached(), error = kErrorNotFound);
// Wait for an MLE Advertisement to establish a routing cost to the neighbor
linkMargin = 0;
break;
default:
@@ -940,15 +938,12 @@ Error MleRouter::HandleLinkAccept(RxInfo &aRxInfo, bool aRequest)
switch (mRole)
{
case kRoleDetached:
// Address16
SuccessOrExit(error = Tlv::Find<Address16Tlv>(aRxInfo.mMessage, address16));
VerifyOrExit(GetRloc16() == address16, error = kErrorDrop);
// Leader Data
SuccessOrExit(error = aRxInfo.mMessage.ReadLeaderDataTlv(leaderData));
SetLeaderData(leaderData.GetPartitionId(), leaderData.GetWeighting(), leaderData.GetLeaderRouterId());
// Route
mRouterTable.Clear();
SuccessOrExit(error = aRxInfo.mMessage.ReadRouteTlv(routeTlv));
SuccessOrExit(error = ProcessRouteTlv(routeTlv, aRxInfo));
@@ -964,7 +959,7 @@ Error MleRouter::HandleLinkAccept(RxInfo &aRxInfo, bool aRequest)
SetStateRouter(GetRloc16());
}
mLinkRequestAttempts = 0; // completed router sync after reset, no more link request to retransmit
mLinkRequestAttempts = 0;
mRetrieveNewNetworkData = true;
IgnoreError(SendDataRequest(aRxInfo.mMessageInfo.GetPeerAddr()));
@@ -981,7 +976,6 @@ Error MleRouter::HandleLinkAccept(RxInfo &aRxInfo, bool aRequest)
case kRoleLeader:
VerifyOrExit(router != nullptr);
// Leader Data
SuccessOrExit(error = aRxInfo.mMessage.ReadLeaderDataTlv(leaderData));
VerifyOrExit(leaderData.GetPartitionId() == mLeaderData.GetPartitionId());
@@ -992,7 +986,6 @@ Error MleRouter::HandleLinkAccept(RxInfo &aRxInfo, bool aRequest)
IgnoreError(SendDataRequest(aRxInfo.mMessageInfo.GetPeerAddr()));
}
// Route (optional)
switch (aRxInfo.mMessage.ReadRouteTlv(routeTlv))
{
case kErrorNone:
@@ -1026,7 +1019,6 @@ Error MleRouter::HandleLinkAccept(RxInfo &aRxInfo, bool aRequest)
OT_ASSERT(false);
}
// finish link synchronization
InitNeighbor(*router, aRxInfo);
router->SetRloc16(sourceAddress);
router->GetLinkFrameCounters().SetAll(linkFrameCounter);
@@ -1049,10 +1041,8 @@ Error MleRouter::HandleLinkAccept(RxInfo &aRxInfo, bool aRequest)
RxChallenge challenge;
TlvList requestedTlvList;
// Challenge
SuccessOrExit(error = aRxInfo.mMessage.ReadChallengeTlv(challenge));
// TLV Request
switch (aRxInfo.mMessage.ReadTlvRequestTlv(requestedTlvList))
{
case kErrorNone:
@@ -1218,7 +1208,7 @@ Error MleRouter::HandleAdvertisement(RxInfo &aRxInfo, uint16_t aSourceAddress, c
if (ComparePartitions(routeTlv.IsSingleton(), aLeaderData, IsSingleton(), mLeaderData) > 0
#if OPENTHREAD_CONFIG_TIME_SYNC_REQUIRED
// if time sync is required, it will only migrate to a better network which also enables time sync.
// Allow a better partition if it also enables time sync.
&& aRxInfo.mMessage.GetTimeSyncSeq() != OT_TIME_SYNC_INVALID_SEQ
#endif
)
@@ -1333,7 +1323,9 @@ Error MleRouter::HandleAdvertisement(RxInfo &aRxInfo, uint16_t aSourceAddress, c
Get<AddressResolver>().ReplaceEntriesForRloc16(aRxInfo.mNeighbor->GetRloc16(), router->GetRloc16());
}
// Send unicast link request if no link to router and no unicast/multicast link request in progress
// Send unicast link request if no link to router and no
// unicast/multicast link request in progress
if (!router->IsStateValid() && !router->IsStateLinkRequest() && (mChallengeTimeout == 0) &&
(linkMargin >= kLinkRequestMinMargin))
{
@@ -1350,7 +1342,6 @@ Error MleRouter::HandleAdvertisement(RxInfo &aRxInfo, uint16_t aSourceAddress, c
exit:
if (aRxInfo.mNeighbor && aRxInfo.mNeighbor->GetRloc16() != aSourceAddress)
{
// Remove stale neighbors
RemoveNeighbor(*aRxInfo.mNeighbor);
}
@@ -1395,11 +1386,9 @@ void MleRouter::HandleParentRequest(RxInfo &aRxInfo)
aRxInfo.mMessageInfo.GetPeerAddr().GetIid().ConvertToExtAddress(extAddr);
// Version
SuccessOrExit(error = Tlv::Find<VersionTlv>(aRxInfo.mMessage, version));
VerifyOrExit(version >= kThreadVersion1p1, error = kErrorParse);
// Scan Mask
SuccessOrExit(error = Tlv::Find<ScanMaskTlv>(aRxInfo.mMessage, scanMask));
switch (mRole)
@@ -1419,7 +1408,6 @@ void MleRouter::HandleParentRequest(RxInfo &aRxInfo)
break;
}
// Challenge
SuccessOrExit(error = aRxInfo.mMessage.ReadChallengeTlv(challenge));
child = mChildTable.FindChild(extAddr, Child::kInStateAnyExceptInvalid);
@@ -1428,7 +1416,6 @@ void MleRouter::HandleParentRequest(RxInfo &aRxInfo)
{
VerifyOrExit((child = mChildTable.GetNewChild()) != nullptr, error = kErrorNoBufs);
// MAC Address
InitNeighbor(*child, aRxInfo);
child->SetState(Neighbor::kStateParentRequest);
#if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
@@ -1510,6 +1497,9 @@ void MleRouter::HandleTimeTick(void)
mPreviousPartitionIdTimeout--;
}
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Role transitions
roleTransitionTimeoutExpired = mRouterRoleTransition.HandleTimeTick();
switch (mRole)
@@ -1532,7 +1522,6 @@ void MleRouter::HandleTimeTick(void)
}
else
{
// send announce after decided to stay in REED if needed
InformPreviousChannel();
}
@@ -1578,7 +1567,9 @@ void MleRouter::HandleTimeTick(void)
OT_ASSERT(false);
}
// update children state
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Update `ChildTable`
for (Child &child : Get<ChildTable>().Iterate(Child::kInStateAnyExceptInvalid))
{
uint32_t timeout = 0;
@@ -1622,7 +1613,9 @@ void MleRouter::HandleTimeTick(void)
}
}
// update router state
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Update `RouterTable`
for (Router &router : Get<RouterTable>())
{
uint32_t age;
@@ -1789,7 +1782,6 @@ Error MleRouter::ProcessAddressRegistrationTlv(RxInfo &aRxInfo, Child &aChild)
#endif
#if OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE
// Retrieve registered multicast addresses of the Child
if (aChild.HasAnyMlrRegisteredAddress())
{
OT_ASSERT(aChild.IsStateValid());
@@ -1853,7 +1845,8 @@ Error MleRouter::ProcessAddressRegistrationTlv(RxInfo &aRxInfo, Child &aChild)
#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
if (mMaxChildIpAddresses > 0 && storedCount >= mMaxChildIpAddresses)
{
// Skip remaining address registration entries but keep logging skipped addresses.
// Skip remaining address registration entries but keep logging
// skipped addresses.
error = kErrorNoBufs;
}
else
@@ -1899,7 +1892,7 @@ Error MleRouter::ProcessAddressRegistrationTlv(RxInfo &aRxInfo, Child &aChild)
}
else
{
// if not able to store DUA, then assume child does not have one
// It cannot store DUA, then assume child does not have one.
hasNewDua = false;
}
}
@@ -1981,43 +1974,33 @@ void MleRouter::HandleChildIdRequest(RxInfo &aRxInfo)
VerifyOrExit(IsRouterEligible(), error = kErrorInvalidState);
// only process message when operating as a child, router, or leader
VerifyOrExit(IsAttached(), error = kErrorInvalidState);
// Find Child
aRxInfo.mMessageInfo.GetPeerAddr().GetIid().ConvertToExtAddress(extAddr);
child = mChildTable.FindChild(extAddr, Child::kInStateAnyExceptInvalid);
VerifyOrExit(child != nullptr, error = kErrorAlready);
// Version
SuccessOrExit(error = Tlv::Find<VersionTlv>(aRxInfo.mMessage, version));
VerifyOrExit(version >= kThreadVersion1p1, error = kErrorParse);
// Response
SuccessOrExit(error = aRxInfo.mMessage.ReadResponseTlv(response));
VerifyOrExit(response == child->GetChallenge(), error = kErrorSecurity);
// Remove existing MLE messages
Get<MeshForwarder>().RemoveMessages(*child, Message::kSubTypeMleGeneral);
Get<MeshForwarder>().RemoveMessages(*child, Message::kSubTypeMleChildIdRequest);
Get<MeshForwarder>().RemoveMessages(*child, Message::kSubTypeMleChildUpdateRequest);
Get<MeshForwarder>().RemoveMessages(*child, Message::kSubTypeMleDataResponse);
// Link-Layer and MLE Frame Counters
SuccessOrExit(error = aRxInfo.mMessage.ReadFrameCounterTlvs(linkFrameCounter, mleFrameCounter));
// Mode
SuccessOrExit(error = Tlv::Find<ModeTlv>(aRxInfo.mMessage, modeBitmask));
mode.Set(modeBitmask);
// Timeout
SuccessOrExit(error = Tlv::Find<TimeoutTlv>(aRxInfo.mMessage, timeout));
// Requested TLVs
SuccessOrExit(error = aRxInfo.mMessage.ReadTlvRequestTlv(tlvList));
// Supervision interval
switch (Tlv::Find<SupervisionIntervalTlv>(aRxInfo.mMessage, supervisionInterval))
{
case kErrorNone:
@@ -2030,7 +2013,6 @@ void MleRouter::HandleChildIdRequest(RxInfo &aRxInfo)
ExitNow(error = kErrorParse);
}
// Active Timestamp
switch (Tlv::Find<ActiveTimestampTlv>(aRxInfo.mMessage, timestamp))
{
case kErrorNone:
@@ -2049,7 +2031,6 @@ void MleRouter::HandleChildIdRequest(RxInfo &aRxInfo)
ExitNow(error = kErrorParse);
}
// Pending Timestamp
switch (Tlv::Find<PendingTimestampTlv>(aRxInfo.mMessage, timestamp))
{
case kErrorNone:
@@ -2075,12 +2056,10 @@ void MleRouter::HandleChildIdRequest(RxInfo &aRxInfo)
SuccessOrExit(error = ProcessAddressRegistrationTlv(aRxInfo, *child));
}
// Remove from router table
router = mRouterTable.FindRouter(extAddr);
if (router != nullptr)
{
// The `router` here can be invalid
RemoveNeighbor(*router);
}
@@ -2161,11 +2140,9 @@ void MleRouter::HandleChildUpdateRequest(RxInfo &aRxInfo)
Log(kMessageReceive, kTypeChildUpdateRequestOfChild, aRxInfo.mMessageInfo.GetPeerAddr());
// Mode
SuccessOrExit(error = Tlv::Find<ModeTlv>(aRxInfo.mMessage, modeBitmask));
mode.Set(modeBitmask);
// Challenge
switch (aRxInfo.mMessage.ReadChallengeTlv(challenge))
{
case kErrorNone:
@@ -2218,7 +2195,6 @@ void MleRouter::HandleChildUpdateRequest(RxInfo &aRxInfo)
tlvList.Add(Tlv::kLinkFrameCounter);
}
// IPv6 Address TLV
switch (ProcessAddressRegistrationTlv(aRxInfo, *child))
{
case kErrorNone:
@@ -2230,7 +2206,6 @@ void MleRouter::HandleChildUpdateRequest(RxInfo &aRxInfo)
ExitNow(error = kErrorParse);
}
// Leader Data
switch (aRxInfo.mMessage.ReadLeaderDataTlv(leaderData))
{
case kErrorNone:
@@ -2242,7 +2217,6 @@ void MleRouter::HandleChildUpdateRequest(RxInfo &aRxInfo)
ExitNow(error = kErrorParse);
}
// Timeout
switch (Tlv::Find<TimeoutTlv>(aRxInfo.mMessage, timeout))
{
case kErrorNone:
@@ -2262,7 +2236,6 @@ void MleRouter::HandleChildUpdateRequest(RxInfo &aRxInfo)
ExitNow(error = kErrorParse);
}
// Supervision interval
switch (Tlv::Find<SupervisionIntervalTlv>(aRxInfo.mMessage, supervisionInterval))
{
case kErrorNone:
@@ -2280,7 +2253,6 @@ void MleRouter::HandleChildUpdateRequest(RxInfo &aRxInfo)
child->SetSupervisionInterval(supervisionInterval);
// TLV Request
switch (aRxInfo.mMessage.ReadTlvRequestTlv(requestedTlvList))
{
case kErrorNone:
@@ -2390,7 +2362,6 @@ void MleRouter::HandleChildUpdateResponse(RxInfo &aRxInfo)
child = static_cast<Child *>(aRxInfo.mNeighbor);
// Response
switch (aRxInfo.mMessage.ReadResponseTlv(response))
{
case kErrorNone:
@@ -2406,7 +2377,6 @@ void MleRouter::HandleChildUpdateResponse(RxInfo &aRxInfo)
Log(kMessageReceive, kTypeChildUpdateResponseOfChild, aRxInfo.mMessageInfo.GetPeerAddr(), child->GetRloc16());
// Source Address
switch (Tlv::Find<SourceAddressTlv>(aRxInfo.mMessage, sourceAddress))
{
case kErrorNone:
@@ -2425,7 +2395,6 @@ void MleRouter::HandleChildUpdateResponse(RxInfo &aRxInfo)
ExitNow(error = kErrorParse);
}
// Status
switch (Tlv::Find<StatusTlv>(aRxInfo.mMessage, status))
{
case kErrorNone:
@@ -2437,8 +2406,6 @@ void MleRouter::HandleChildUpdateResponse(RxInfo &aRxInfo)
ExitNow(error = kErrorParse);
}
// Link-Layer Frame Counter
switch (Tlv::Find<LinkFrameCounterTlv>(aRxInfo.mMessage, linkFrameCounter))
{
case kErrorNone:
@@ -2451,7 +2418,6 @@ void MleRouter::HandleChildUpdateResponse(RxInfo &aRxInfo)
ExitNow(error = kErrorParse);
}
// MLE Frame Counter
switch (Tlv::Find<MleFrameCounterTlv>(aRxInfo.mMessage, mleFrameCounter))
{
case kErrorNone:
@@ -2463,7 +2429,6 @@ void MleRouter::HandleChildUpdateResponse(RxInfo &aRxInfo)
ExitNow(error = kErrorNone);
}
// Timeout
switch (Tlv::Find<TimeoutTlv>(aRxInfo.mMessage, timeout))
{
case kErrorNone:
@@ -2490,7 +2455,6 @@ void MleRouter::HandleChildUpdateResponse(RxInfo &aRxInfo)
}
}
// IPv6 Address
switch (ProcessAddressRegistrationTlv(aRxInfo, *child))
{
case kErrorNone:
@@ -2500,7 +2464,6 @@ void MleRouter::HandleChildUpdateResponse(RxInfo &aRxInfo)
ExitNow(error = kErrorParse);
}
// Leader Data
switch (aRxInfo.mMessage.ReadLeaderDataTlv(leaderData))
{
case kErrorNone:
@@ -2533,10 +2496,8 @@ void MleRouter::HandleDataRequest(RxInfo &aRxInfo)
VerifyOrExit(aRxInfo.IsNeighborStateValid(), error = kErrorSecurity);
// TLV Request
SuccessOrExit(error = aRxInfo.mMessage.ReadTlvRequestTlv(tlvList));
// Active Timestamp
switch (Tlv::Find<ActiveTimestampTlv>(aRxInfo.mMessage, timestamp))
{
case kErrorNone:
@@ -2555,7 +2516,6 @@ void MleRouter::HandleDataRequest(RxInfo &aRxInfo)
ExitNow(error = kErrorParse);
}
// Pending Timestamp
switch (Tlv::Find<PendingTimestampTlv>(aRxInfo.mMessage, timestamp))
{
case kErrorNone:
@@ -2667,7 +2627,6 @@ void MleRouter::HandleDiscoveryRequest(RxInfo &aRxInfo)
discoveryRequestTlv.SetLength(0);
// only Routers and REEDs respond
VerifyOrExit(IsRouterEligible(), error = kErrorInvalidState);
SuccessOrExit(error = Tlv::FindTlvValueStartEndOffsets(aRxInfo.mMessage, Tlv::kDiscovery, offset, end));
@@ -2749,13 +2708,11 @@ Error MleRouter::SendDiscoveryResponse(const Ip6::Address &aDestination, const M
message->SetRadioType(aDiscoverRequestMessage.GetRadioType());
#endif
// Discovery TLV
tlv.SetType(Tlv::kDiscovery);
SuccessOrExit(error = message->Append(tlv));
startOffset = message->GetLength();
// Discovery Response TLV
discoveryResponseTlv.Init();
discoveryResponseTlv.SetVersion(kThreadVersion);
@@ -2780,11 +2737,9 @@ Error MleRouter::SendDiscoveryResponse(const Ip6::Address &aDestination, const M
SuccessOrExit(error = discoveryResponseTlv.AppendTo(*message));
// Extended PAN ID TLV
SuccessOrExit(
error = Tlv::Append<MeshCoP::ExtendedPanIdTlv>(*message, Get<MeshCoP::ExtendedPanIdManager>().GetExtPanId()));
// Network Name TLV
networkNameTlv.Init();
networkNameTlv.SetNetworkName(Get<MeshCoP::NetworkNameManager>().GetNetworkName().GetAsData());
SuccessOrExit(error = networkNameTlv.AppendTo(*message));
@@ -2825,7 +2780,7 @@ Error MleRouter::SendChildIdResponse(Child &aChild)
{
uint16_t rloc16;
// pick next Child ID that is not being used
// Pick next Child ID that is not being used
do
{
mNextChildId++;
@@ -2839,7 +2794,6 @@ Error MleRouter::SendChildIdResponse(Child &aChild)
} while (mChildTable.FindChild(rloc16, Child::kInStateAnyExceptInvalid) != nullptr);
// allocate Child ID
aChild.SetRloc16(rloc16);
}
@@ -2919,14 +2873,16 @@ Error MleRouter::SendChildUpdateRequest(Child &aChild)
{
if (msg.GetChildMask(childIndex) && msg.GetSubType() == Message::kSubTypeMleChildUpdateRequest)
{
// No need to send the resync "Child Update Request" to the sleepy child
// if there is one already queued.
// No need to send the resync "Child Update Request"
// to the sleepy child if there is one already
// queued.
if (aChild.IsStateRestoring())
{
ExitNow();
}
// Remove queued outdated "Child Update Request" when there is newer Network Data is to send.
// Remove queued outdated "Child Update Request" when
// there is newer Network Data is to send.
Get<MeshForwarder>().RemoveMessages(aChild, Message::kSubTypeMleChildUpdateRequest);
break;
}
@@ -3137,10 +3093,8 @@ void MleRouter::SendDataResponse(const Ip6::Address &aDestination,
if (aDelay)
{
// Remove MLE Data Responses from Send Message Queue.
Get<MeshForwarder>().RemoveDataResponseMessages();
// Remove multicast MLE Data Response from Delayed Message Queue.
RemoveDelayedDataResponseMessage();
SuccessOrExit(error = message->SendAfterDelay(aDestination, aDelay));
@@ -3222,7 +3176,6 @@ void MleRouter::RemoveNeighbor(Neighbor &aNeighbor)
if (aNeighbor.IsFullThreadDevice())
{
// Clear all EID-to-RLOC entries associated with the child.
Get<AddressResolver>().RemoveEntriesForRloc16(aNeighbor.GetRloc16());
}
@@ -3273,11 +3226,9 @@ void MleRouter::ResolveRoutingLoops(uint16_t aSourceMac, uint16_t aDestRloc16)
ExitNow();
}
// loop exists
router = mRouterTable.FindRouterByRloc16(aDestRloc16);
VerifyOrExit(router != nullptr);
// invalidate next hop
router->SetNextHopToInvalid();
ResetAdvertiseInterval();
@@ -3297,7 +3248,6 @@ Error MleRouter::CheckReachability(uint16_t aMeshDest, const Ip6::Header &aIp6He
if (aMeshDest == Get<Mac::Mac>().GetShortAddress())
{
// mesh destination is this device
if (Get<ThreadNetif>().HasUnicastAddress(aIp6Header.GetDestination()))
{
// IPv6 destination is this device
@@ -3311,15 +3261,14 @@ Error MleRouter::CheckReachability(uint16_t aMeshDest, const Ip6::Header &aIp6He
}
else if (RouterIdFromRloc16(aMeshDest) == mRouterId)
{
// mesh destination is a child of this device
if (mChildTable.FindChild(aMeshDest, Child::kInStateValidOrRestoring))
{
// Mesh destination is a child of this device
ExitNow();
}
}
else if (GetNextHop(aMeshDest) != Mac::kShortAddrInvalid)
{
// forwarding to another router and route is known
ExitNow();
}
@@ -3440,7 +3389,6 @@ void MleRouter::HandleAddressSolicitResponse(Coap::Message *aMessage,
SuccessOrExit(Tlv::FindTlv(*aMessage, routerMaskTlv));
VerifyOrExit(routerMaskTlv.IsValid());
// assign short address
SetRouterId(routerId);
SetStateRouter(Rloc16FromRouterId(mRouterId));
@@ -3503,7 +3451,6 @@ void MleRouter::HandleAddressSolicitResponse(Coap::Message *aMessage,
}
exit:
// Send announce after received address solicit reply if needed
InformPreviousChannel();
}
@@ -3564,7 +3511,6 @@ template <> void MleRouter::HandleTmf<kUriAddressSolicit>(Coap::Message &aMessag
}
#endif
// Check if allocation already exists
router = mRouterTable.FindRouter(extAddress);
if (router != nullptr)
@@ -3746,13 +3692,11 @@ void MleRouter::FillConnectivityTlv(ConnectivityTlv &aTlv)
{
if (router.GetRloc16() == GetRloc16())
{
// skip self
continue;
}
if (!router.IsStateValid())
{
// skip non-neighbor routers
continue;
}