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