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