1 /*
2 * Copyright (c) 2023, The OpenThread Authors.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. Neither the name of the copyright holder nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 /**
30 * @file
31 * This file implements the Mesh Diag module.
32 */
33
34 #include "mesh_diag.hpp"
35
36 #if OPENTHREAD_CONFIG_MESH_DIAG_ENABLE && OPENTHREAD_FTD
37
38 #include "instance/instance.hpp"
39
40 namespace ot {
41 namespace Utils {
42
43 using namespace NetworkDiagnostic;
44
45 RegisterLogModule("MeshDiag");
46
47 //---------------------------------------------------------------------------------------------------------------------
48 // MeshDiag
49
MeshDiag(Instance & aInstance)50 MeshDiag::MeshDiag(Instance &aInstance)
51 : InstanceLocator(aInstance)
52 , mState(kStateIdle)
53 , mExpectedQueryId(0)
54 , mExpectedAnswerIndex(0)
55 , mTimer(aInstance)
56 {
57 }
58
DiscoverTopology(const DiscoverConfig & aConfig,DiscoverCallback aCallback,void * aContext)59 Error MeshDiag::DiscoverTopology(const DiscoverConfig &aConfig, DiscoverCallback aCallback, void *aContext)
60 {
61 static constexpr uint8_t kMaxTlvsToRequest = 6;
62
63 Error error = kErrorNone;
64 uint8_t tlvs[kMaxTlvsToRequest];
65 uint8_t tlvsLength = 0;
66
67 VerifyOrExit(Get<Mle::Mle>().IsAttached(), error = kErrorInvalidState);
68 VerifyOrExit(mState == kStateIdle, error = kErrorBusy);
69
70 tlvs[tlvsLength++] = Address16Tlv::kType;
71 tlvs[tlvsLength++] = ExtMacAddressTlv::kType;
72 tlvs[tlvsLength++] = RouteTlv::kType;
73 tlvs[tlvsLength++] = VersionTlv::kType;
74
75 if (aConfig.mDiscoverIp6Addresses)
76 {
77 tlvs[tlvsLength++] = Ip6AddressListTlv::kType;
78 }
79
80 if (aConfig.mDiscoverChildTable)
81 {
82 tlvs[tlvsLength++] = ChildTableTlv::kType;
83 }
84
85 Get<RouterTable>().GetRouterIdSet(mDiscover.mExpectedRouterIdSet);
86
87 for (uint8_t routerId = 0; routerId <= Mle::kMaxRouterId; routerId++)
88 {
89 Ip6::Address destination;
90
91 if (!mDiscover.mExpectedRouterIdSet.Contains(routerId))
92 {
93 continue;
94 }
95
96 destination.SetToRoutingLocator(Get<Mle::Mle>().GetMeshLocalPrefix(), Mle::Rloc16FromRouterId(routerId));
97
98 SuccessOrExit(error = Get<Client>().SendCommand(kUriDiagnosticGetRequest, Message::kPriorityLow, destination,
99 tlvs, tlvsLength, HandleDiagGetResponse, this));
100 }
101
102 mDiscover.mCallback.Set(aCallback, aContext);
103 mState = kStateDiscoverTopology;
104 mTimer.Start(kResponseTimeout);
105
106 exit:
107 return error;
108 }
109
HandleDiagGetResponse(void * aContext,otMessage * aMessage,const otMessageInfo * aMessageInfo,otError aResult)110 void MeshDiag::HandleDiagGetResponse(void *aContext,
111 otMessage *aMessage,
112 const otMessageInfo *aMessageInfo,
113 otError aResult)
114 {
115 static_cast<MeshDiag *>(aContext)->HandleDiagGetResponse(AsCoapMessagePtr(aMessage), AsCoreTypePtr(aMessageInfo),
116 aResult);
117 }
118
HandleDiagGetResponse(Coap::Message * aMessage,const Ip6::MessageInfo * aMessageInfo,Error aResult)119 void MeshDiag::HandleDiagGetResponse(Coap::Message *aMessage, const Ip6::MessageInfo *aMessageInfo, Error aResult)
120 {
121 OT_UNUSED_VARIABLE(aMessageInfo);
122
123 Error error;
124 RouterInfo routerInfo;
125 Ip6AddrIterator ip6AddrIterator;
126 ChildIterator childIterator;
127
128 SuccessOrExit(aResult);
129 VerifyOrExit(aMessage != nullptr);
130 VerifyOrExit(mState == kStateDiscoverTopology);
131
132 SuccessOrExit(routerInfo.ParseFrom(*aMessage));
133
134 if (ip6AddrIterator.InitFrom(*aMessage) == kErrorNone)
135 {
136 routerInfo.mIp6AddrIterator = &ip6AddrIterator;
137 }
138
139 if (childIterator.InitFrom(*aMessage, routerInfo.mRloc16) == kErrorNone)
140 {
141 routerInfo.mChildIterator = &childIterator;
142 }
143
144 mDiscover.mExpectedRouterIdSet.Remove(routerInfo.mRouterId);
145
146 if (mDiscover.mExpectedRouterIdSet.GetNumberOfAllocatedIds() == 0)
147 {
148 error = kErrorNone;
149 mState = kStateIdle;
150 mTimer.Stop();
151 }
152 else
153 {
154 error = kErrorPending;
155 }
156
157 mDiscover.mCallback.InvokeIfSet(error, &routerInfo);
158
159 exit:
160 return;
161 }
162
SendQuery(uint16_t aRloc16,const uint8_t * aTlvs,uint8_t aTlvsLength)163 Error MeshDiag::SendQuery(uint16_t aRloc16, const uint8_t *aTlvs, uint8_t aTlvsLength)
164 {
165 Error error = kErrorNone;
166 Ip6::Address destination;
167
168 VerifyOrExit(Get<Mle::Mle>().IsAttached(), error = kErrorInvalidState);
169 VerifyOrExit(mState == kStateIdle, error = kErrorBusy);
170 VerifyOrExit(Mle::IsRouterRloc16(aRloc16), error = kErrorInvalidArgs);
171 VerifyOrExit(Get<RouterTable>().IsAllocated(Mle::RouterIdFromRloc16(aRloc16)), error = kErrorNotFound);
172
173 destination.SetToRoutingLocator(Get<Mle::Mle>().GetMeshLocalPrefix(), aRloc16);
174
175 SuccessOrExit(error = Get<Client>().SendCommand(kUriDiagnosticGetQuery, Message::kPriorityNormal, destination,
176 aTlvs, aTlvsLength));
177
178 mExpectedQueryId = Get<Client>().GetLastQueryId();
179 mExpectedAnswerIndex = 0;
180
181 mTimer.Start(kResponseTimeout);
182
183 exit:
184 return error;
185 }
186
QueryChildTable(uint16_t aRloc16,QueryChildTableCallback aCallback,void * aContext)187 Error MeshDiag::QueryChildTable(uint16_t aRloc16, QueryChildTableCallback aCallback, void *aContext)
188 {
189 static const uint8_t kTlvTypes[] = {ChildTlv::kType};
190
191 Error error;
192
193 SuccessOrExit(error = SendQuery(aRloc16, kTlvTypes, sizeof(kTlvTypes)));
194
195 mQueryChildTable.mCallback.Set(aCallback, aContext);
196 mQueryChildTable.mRouterRloc16 = aRloc16;
197 mState = kStateQueryChildTable;
198
199 exit:
200 return error;
201 }
202
QueryChildrenIp6Addrs(uint16_t aRloc16,ChildIp6AddrsCallback aCallback,void * aContext)203 Error MeshDiag::QueryChildrenIp6Addrs(uint16_t aRloc16, ChildIp6AddrsCallback aCallback, void *aContext)
204 {
205 static const uint8_t kTlvTypes[] = {ChildIp6AddressListTlv::kType};
206
207 Error error;
208
209 SuccessOrExit(error = SendQuery(aRloc16, kTlvTypes, sizeof(kTlvTypes)));
210
211 mQueryChildrenIp6Addrs.mCallback.Set(aCallback, aContext);
212 mQueryChildrenIp6Addrs.mParentRloc16 = aRloc16;
213 mState = kStateQueryChildrenIp6Addrs;
214
215 exit:
216 return error;
217 }
218
QueryRouterNeighborTable(uint16_t aRloc16,RouterNeighborTableCallback aCallback,void * aContext)219 Error MeshDiag::QueryRouterNeighborTable(uint16_t aRloc16, RouterNeighborTableCallback aCallback, void *aContext)
220 {
221 static const uint8_t kTlvTypes[] = {RouterNeighborTlv::kType};
222
223 Error error;
224
225 SuccessOrExit(error = SendQuery(aRloc16, kTlvTypes, sizeof(kTlvTypes)));
226
227 mQueryRouterNeighborTable.mCallback.Set(aCallback, aContext);
228 mQueryRouterNeighborTable.mRouterRloc16 = aRloc16;
229 mState = kStateQueryRouterNeighborTable;
230
231 exit:
232 return error;
233 }
234
HandleDiagnosticGetAnswer(Coap::Message & aMessage,const Ip6::MessageInfo & aMessageInfo)235 bool MeshDiag::HandleDiagnosticGetAnswer(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
236 {
237 bool didProcess = false;
238
239 switch (mState)
240 {
241 case kStateQueryChildTable:
242 didProcess = ProcessChildTableAnswer(aMessage, aMessageInfo);
243 break;
244
245 case kStateQueryChildrenIp6Addrs:
246 didProcess = ProcessChildrenIp6AddrsAnswer(aMessage, aMessageInfo);
247 break;
248
249 case kStateQueryRouterNeighborTable:
250 didProcess = ProcessRouterNeighborTableAnswer(aMessage, aMessageInfo);
251 break;
252
253 default:
254 break;
255 }
256
257 return didProcess;
258 }
259
ProcessMessage(Coap::Message & aMessage,const Ip6::MessageInfo & aMessageInfo,uint16_t aSenderRloc16)260 Error MeshDiag::ProcessMessage(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo, uint16_t aSenderRloc16)
261 {
262 // This method processes the received answer message to
263 // check whether it is from the intended sender and matches
264 // the expected query ID and answer index.
265
266 Error error = kErrorFailed;
267 AnswerTlv answerTlv;
268 uint16_t queryId;
269
270 VerifyOrExit(Get<Mle::Mle>().IsRoutingLocator(aMessageInfo.GetPeerAddr()));
271 VerifyOrExit(aMessageInfo.GetPeerAddr().GetIid().GetLocator() == aSenderRloc16);
272
273 SuccessOrExit(Tlv::Find<QueryIdTlv>(aMessage, queryId));
274 VerifyOrExit(queryId == mExpectedQueryId);
275
276 SuccessOrExit(Tlv::FindTlv(aMessage, answerTlv));
277
278 if (answerTlv.GetIndex() != mExpectedAnswerIndex)
279 {
280 Finalize(kErrorResponseTimeout);
281 ExitNow();
282 }
283
284 mExpectedAnswerIndex++;
285 error = kErrorNone;
286
287 exit:
288 return error;
289 }
290
ProcessChildTableAnswer(Coap::Message & aMessage,const Ip6::MessageInfo & aMessageInfo)291 bool MeshDiag::ProcessChildTableAnswer(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
292 {
293 bool didProcess = false;
294 ChildTlv childTlv;
295 ChildEntry entry;
296 uint16_t offset;
297
298 SuccessOrExit(ProcessMessage(aMessage, aMessageInfo, mQueryChildTable.mRouterRloc16));
299
300 while (true)
301 {
302 SuccessOrExit(Tlv::FindTlv(aMessage, childTlv, offset));
303 VerifyOrExit(!childTlv.IsExtended());
304
305 didProcess = true;
306
307 if (childTlv.GetLength() == 0)
308 {
309 // We reached end of the list.
310 mState = kStateIdle;
311 mTimer.Stop();
312 mQueryChildTable.mCallback.InvokeIfSet(kErrorNone, nullptr);
313 ExitNow();
314 }
315
316 VerifyOrExit(childTlv.GetLength() >= sizeof(ChildTlv) - sizeof(Tlv));
317 IgnoreError(aMessage.Read(offset, childTlv));
318
319 entry.SetFrom(childTlv);
320 mQueryChildTable.mCallback.InvokeIfSet(kErrorPending, &entry);
321
322 // Make sure query operation is not canceled from the
323 // callback.
324 VerifyOrExit(mState == kStateQueryChildTable);
325
326 aMessage.SetOffset(static_cast<uint16_t>(offset + childTlv.GetSize()));
327 }
328
329 exit:
330 return didProcess;
331 }
332
ProcessRouterNeighborTableAnswer(Coap::Message & aMessage,const Ip6::MessageInfo & aMessageInfo)333 bool MeshDiag::ProcessRouterNeighborTableAnswer(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
334 {
335 bool didProcess = false;
336 RouterNeighborTlv neighborTlv;
337 RouterNeighborEntry entry;
338 uint16_t offset;
339
340 SuccessOrExit(ProcessMessage(aMessage, aMessageInfo, mQueryRouterNeighborTable.mRouterRloc16));
341
342 while (true)
343 {
344 SuccessOrExit(Tlv::FindTlv(aMessage, neighborTlv, offset));
345 VerifyOrExit(!neighborTlv.IsExtended());
346
347 didProcess = true;
348
349 if (neighborTlv.GetLength() == 0)
350 {
351 // We reached end of the list.
352 mState = kStateIdle;
353 mTimer.Stop();
354 mQueryRouterNeighborTable.mCallback.InvokeIfSet(kErrorNone, nullptr);
355 ExitNow();
356 }
357
358 VerifyOrExit(neighborTlv.GetLength() >= sizeof(RouterNeighborTlv) - sizeof(Tlv));
359
360 entry.SetFrom(neighborTlv);
361 mQueryRouterNeighborTable.mCallback.InvokeIfSet(kErrorPending, &entry);
362
363 // Make sure query operation is not canceled from the
364 // callback.
365 VerifyOrExit(mState == kStateQueryRouterNeighborTable);
366
367 aMessage.SetOffset(static_cast<uint16_t>(offset + neighborTlv.GetSize()));
368 }
369
370 exit:
371 return didProcess;
372 }
373
ProcessChildrenIp6AddrsAnswer(Coap::Message & aMessage,const Ip6::MessageInfo & aMessageInfo)374 bool MeshDiag::ProcessChildrenIp6AddrsAnswer(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
375 {
376 bool didProcess = false;
377 OffsetRange offsetRange;
378 ChildIp6AddressListTlvValue tlvValue;
379 Ip6AddrIterator ip6AddrIterator;
380
381 SuccessOrExit(ProcessMessage(aMessage, aMessageInfo, mQueryChildrenIp6Addrs.mParentRloc16));
382
383 while (true)
384 {
385 SuccessOrExit(Tlv::FindTlvValueOffsetRange(aMessage, ChildIp6AddressListTlv::kType, offsetRange));
386
387 didProcess = true;
388
389 if (offsetRange.IsEmpty())
390 {
391 // We reached end of the list
392 mState = kStateIdle;
393 mTimer.Stop();
394 mQueryChildrenIp6Addrs.mCallback.InvokeIfSet(kErrorNone, Mle::kInvalidRloc16, nullptr);
395 ExitNow();
396 }
397
398 // Read the `ChildIp6AddressListTlvValue` (which contains the
399 // child RLOC16) and then prepare the `Ip6AddrIterator`.
400
401 SuccessOrExit(aMessage.Read(offsetRange, tlvValue));
402 offsetRange.AdvanceOffset(sizeof(tlvValue));
403
404 ip6AddrIterator.mMessage = &aMessage;
405 ip6AddrIterator.mOffsetRange = offsetRange;
406
407 mQueryChildrenIp6Addrs.mCallback.InvokeIfSet(kErrorPending, tlvValue.GetRloc16(), &ip6AddrIterator);
408
409 // Make sure query operation is not canceled from the
410 // callback.
411 VerifyOrExit(mState == kStateQueryChildrenIp6Addrs);
412
413 aMessage.SetOffset(offsetRange.GetEndOffset());
414 }
415
416 exit:
417 return didProcess;
418 }
419
Cancel(void)420 void MeshDiag::Cancel(void)
421 {
422 switch (mState)
423 {
424 case kStateIdle:
425 case kStateQueryChildTable:
426 case kStateQueryChildrenIp6Addrs:
427 case kStateQueryRouterNeighborTable:
428 break;
429
430 case kStateDiscoverTopology:
431 IgnoreError(Get<Tmf::Agent>().AbortTransaction(HandleDiagGetResponse, this));
432 break;
433 }
434
435 mState = kStateIdle;
436 mTimer.Stop();
437 }
438
Finalize(Error aError)439 void MeshDiag::Finalize(Error aError)
440 {
441 // Finalize an ongoing query operation (if any) invoking
442 // the corresponding callback with `aError`.
443
444 State oldState = mState;
445
446 Cancel();
447
448 switch (oldState)
449 {
450 case kStateIdle:
451 break;
452
453 case kStateDiscoverTopology:
454 mDiscover.mCallback.InvokeIfSet(aError, nullptr);
455 break;
456
457 case kStateQueryChildTable:
458 mQueryChildTable.mCallback.InvokeIfSet(aError, nullptr);
459 break;
460
461 case kStateQueryChildrenIp6Addrs:
462 mQueryChildrenIp6Addrs.mCallback.InvokeIfSet(aError, Mle::kInvalidRloc16, nullptr);
463 break;
464
465 case kStateQueryRouterNeighborTable:
466 mQueryRouterNeighborTable.mCallback.InvokeIfSet(aError, nullptr);
467 break;
468 }
469 }
470
HandleTimer(void)471 void MeshDiag::HandleTimer(void) { Finalize(kErrorResponseTimeout); }
472
473 //---------------------------------------------------------------------------------------------------------------------
474 // MeshDiag::RouterInfo
475
ParseFrom(const Message & aMessage)476 Error MeshDiag::RouterInfo::ParseFrom(const Message &aMessage)
477 {
478 Error error = kErrorNone;
479 Mle::Mle &mle = aMessage.Get<Mle::Mle>();
480 RouteTlv routeTlv;
481
482 Clear();
483
484 SuccessOrExit(error = Tlv::Find<Address16Tlv>(aMessage, mRloc16));
485 SuccessOrExit(error = Tlv::Find<ExtMacAddressTlv>(aMessage, AsCoreType(&mExtAddress)));
486 SuccessOrExit(error = Tlv::FindTlv(aMessage, routeTlv));
487
488 switch (error = Tlv::Find<VersionTlv>(aMessage, mVersion))
489 {
490 case kErrorNone:
491 break;
492 case kErrorNotFound:
493 mVersion = kVersionUnknown;
494 error = kErrorNone;
495 break;
496 default:
497 ExitNow();
498 }
499
500 mRouterId = Mle::RouterIdFromRloc16(mRloc16);
501 mIsThisDevice = mle.HasRloc16(mRloc16);
502 mIsThisDeviceParent = mle.IsChild() && (mRloc16 == mle.GetParent().GetRloc16());
503 mIsLeader = (mRouterId == mle.GetLeaderId());
504 mIsBorderRouter = aMessage.Get<NetworkData::Leader>().ContainsBorderRouterWithRloc(mRloc16);
505
506 for (uint8_t id = 0, index = 0; id <= Mle::kMaxRouterId; id++)
507 {
508 if (routeTlv.IsRouterIdSet(id))
509 {
510 mLinkQualities[id] = routeTlv.GetLinkQualityIn(index);
511 index++;
512 }
513 }
514
515 exit:
516 return error;
517 }
518
519 //---------------------------------------------------------------------------------------------------------------------
520 // MeshDiag::Ip6AddrIterator
521
InitFrom(const Message & aMessage)522 Error MeshDiag::Ip6AddrIterator::InitFrom(const Message &aMessage)
523 {
524 Error error;
525
526 SuccessOrExit(error = Tlv::FindTlvValueOffsetRange(aMessage, Ip6AddressListTlv::kType, mOffsetRange));
527 mMessage = &aMessage;
528
529 exit:
530 return error;
531 }
532
GetNextAddress(Ip6::Address & aAddress)533 Error MeshDiag::Ip6AddrIterator::GetNextAddress(Ip6::Address &aAddress)
534 {
535 Error error = kErrorNone;
536
537 VerifyOrExit(mMessage != nullptr, error = kErrorNotFound);
538
539 VerifyOrExit(mMessage->Read(mOffsetRange, aAddress) == kErrorNone, error = kErrorNotFound);
540 mOffsetRange.AdvanceOffset(sizeof(Ip6::Address));
541
542 exit:
543 return error;
544 }
545
546 //---------------------------------------------------------------------------------------------------------------------
547 // MeshDiag::ChildIterator
548
InitFrom(const Message & aMessage,uint16_t aParentRloc16)549 Error MeshDiag::ChildIterator::InitFrom(const Message &aMessage, uint16_t aParentRloc16)
550 {
551 Error error;
552
553 SuccessOrExit(error = Tlv::FindTlvValueOffsetRange(aMessage, ChildTableTlv::kType, mOffsetRange));
554
555 mMessage = &aMessage;
556 mParentRloc16 = aParentRloc16;
557
558 exit:
559 return error;
560 }
561
GetNextChildInfo(ChildInfo & aChildInfo)562 Error MeshDiag::ChildIterator::GetNextChildInfo(ChildInfo &aChildInfo)
563 {
564 Error error = kErrorNone;
565 ChildTableEntry entry;
566
567 VerifyOrExit(mMessage != nullptr, error = kErrorNotFound);
568
569 VerifyOrExit(mMessage->Read(mOffsetRange, entry) == kErrorNone, error = kErrorNotFound);
570 mOffsetRange.AdvanceOffset(sizeof(ChildTableEntry));
571
572 aChildInfo.mRloc16 = mParentRloc16 + entry.GetChildId();
573 entry.GetMode().Get(aChildInfo.mMode);
574 aChildInfo.mLinkQuality = entry.GetLinkQuality();
575
576 aChildInfo.mIsThisDevice = mMessage->Get<Mle::Mle>().HasRloc16(aChildInfo.mRloc16);
577 aChildInfo.mIsBorderRouter = mMessage->Get<NetworkData::Leader>().ContainsBorderRouterWithRloc(aChildInfo.mRloc16);
578
579 exit:
580 return error;
581 }
582
583 //---------------------------------------------------------------------------------------------------------------------
584 // MeshDiag::ChildEntry
585
SetFrom(const ChildTlv & aChildTlv)586 void MeshDiag::ChildEntry::SetFrom(const ChildTlv &aChildTlv)
587 {
588 mRxOnWhenIdle = (aChildTlv.GetFlags() & ChildTlv::kFlagsRxOnWhenIdle);
589 mDeviceTypeFtd = (aChildTlv.GetFlags() & ChildTlv::kFlagsFtd);
590 mFullNetData = (aChildTlv.GetFlags() & ChildTlv::kFlagsFullNetdta);
591 mCslSynchronized = (aChildTlv.GetFlags() & ChildTlv::kFlagsCslSync);
592 mSupportsErrRate = (aChildTlv.GetFlags() & ChildTlv::kFlagsTrackErrRate);
593 mRloc16 = aChildTlv.GetRloc16();
594 mExtAddress = aChildTlv.GetExtAddress();
595 mVersion = aChildTlv.GetVersion();
596 mTimeout = aChildTlv.GetTimeout();
597 mAge = aChildTlv.GetAge();
598 mConnectionTime = aChildTlv.GetConnectionTime();
599 mSupervisionInterval = aChildTlv.GetSupervisionInterval();
600 mLinkMargin = aChildTlv.GetLinkMargin();
601 mAverageRssi = aChildTlv.GetAverageRssi();
602 mLastRssi = aChildTlv.GetLastRssi();
603 mFrameErrorRate = aChildTlv.GetFrameErrorRate();
604 mMessageErrorRate = aChildTlv.GetMessageErrorRate();
605 mQueuedMessageCount = aChildTlv.GetQueuedMessageCount();
606 mCslPeriod = aChildTlv.GetCslPeriod();
607 mCslTimeout = aChildTlv.GetCslTimeout();
608 mCslChannel = aChildTlv.GetCslChannel();
609 }
610
611 //---------------------------------------------------------------------------------------------------------------------
612 // MeshDiag::RouterNeighborEntry
613
SetFrom(const RouterNeighborTlv & aTlv)614 void MeshDiag::RouterNeighborEntry::SetFrom(const RouterNeighborTlv &aTlv)
615 {
616 mSupportsErrRate = (aTlv.GetFlags() & RouterNeighborTlv::kFlagsTrackErrRate);
617 mRloc16 = aTlv.GetRloc16();
618 mExtAddress = aTlv.GetExtAddress();
619 mVersion = aTlv.GetVersion();
620 mConnectionTime = aTlv.GetConnectionTime();
621 mLinkMargin = aTlv.GetLinkMargin();
622 mAverageRssi = aTlv.GetAverageRssi();
623 mLastRssi = aTlv.GetLastRssi();
624 mFrameErrorRate = aTlv.GetFrameErrorRate();
625 mMessageErrorRate = aTlv.GetMessageErrorRate();
626 }
627
628 } // namespace Utils
629 } // namespace ot
630
631 #endif // #if OPENTHREAD_CONFIG_MESH_DIAG_ENABLE && OPENTHREAD_FTD
632