/src/openthread/src/core/thread/network_diagnostic.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (c) 2016, 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 Thread's Network Diagnostic processing. |
32 | | */ |
33 | | |
34 | | #include "network_diagnostic.hpp" |
35 | | |
36 | | #include "instance/instance.hpp" |
37 | | |
38 | | namespace ot { |
39 | | |
40 | | RegisterLogModule("NetDiag"); |
41 | | |
42 | | namespace NetworkDiagnostic { |
43 | | |
44 | | const char Server::kVendorName[] = OPENTHREAD_CONFIG_NET_DIAG_VENDOR_NAME; |
45 | | const char Server::kVendorModel[] = OPENTHREAD_CONFIG_NET_DIAG_VENDOR_MODEL; |
46 | | const char Server::kVendorSwVersion[] = OPENTHREAD_CONFIG_NET_DIAG_VENDOR_SW_VERSION; |
47 | | const char Server::kVendorAppUrl[] = OPENTHREAD_CONFIG_NET_DIAG_VENDOR_APP_URL; |
48 | | |
49 | | //--------------------------------------------------------------------------------------------------------------------- |
50 | | // Server |
51 | | |
52 | | Server::Server(Instance &aInstance) |
53 | 21.3k | : InstanceLocator(aInstance) |
54 | 21.3k | , mNonPreferredChannels(0) |
55 | 21.3k | { |
56 | 21.3k | static_assert(sizeof(kVendorName) <= sizeof(VendorNameTlv::StringType), "VENDOR_NAME is too long"); |
57 | 21.3k | static_assert(sizeof(kVendorModel) <= sizeof(VendorModelTlv::StringType), "VENDOR_MODEL is too long"); |
58 | 21.3k | static_assert(sizeof(kVendorSwVersion) <= sizeof(VendorSwVersionTlv::StringType), "VENDOR_SW_VERSION is too long"); |
59 | 21.3k | static_assert(sizeof(kVendorAppUrl) <= sizeof(VendorAppUrlTlv::StringType), "VENDOR_APP_URL is too long"); |
60 | | |
61 | | #if OPENTHREAD_CONFIG_NET_DIAG_VENDOR_INFO_SET_API_ENABLE |
62 | | memcpy(mVendorName, kVendorName, sizeof(kVendorName)); |
63 | | memcpy(mVendorModel, kVendorModel, sizeof(kVendorModel)); |
64 | | memcpy(mVendorSwVersion, kVendorSwVersion, sizeof(kVendorSwVersion)); |
65 | | memcpy(mVendorAppUrl, kVendorAppUrl, sizeof(kVendorAppUrl)); |
66 | | #endif |
67 | 21.3k | } |
68 | | |
69 | | #if OPENTHREAD_CONFIG_NET_DIAG_VENDOR_INFO_SET_API_ENABLE |
70 | | |
71 | | Error Server::SetVendorName(const char *aVendorName) |
72 | | { |
73 | | return StringCopy(mVendorName, aVendorName, kStringCheckUtf8Encoding); |
74 | | } |
75 | | |
76 | | Error Server::SetVendorModel(const char *aVendorModel) |
77 | | { |
78 | | return StringCopy(mVendorModel, aVendorModel, kStringCheckUtf8Encoding); |
79 | | } |
80 | | |
81 | | Error Server::SetVendorSwVersion(const char *aVendorSwVersion) |
82 | | { |
83 | | return StringCopy(mVendorSwVersion, aVendorSwVersion, kStringCheckUtf8Encoding); |
84 | | } |
85 | | |
86 | | Error Server::SetVendorAppUrl(const char *aVendorAppUrl) |
87 | | { |
88 | | return StringCopy(mVendorAppUrl, aVendorAppUrl, kStringCheckUtf8Encoding); |
89 | | } |
90 | | |
91 | | #endif |
92 | | |
93 | | void Server::PrepareMessageInfoForDest(const Ip6::Address &aDestination, Tmf::MessageInfo &aMessageInfo) const |
94 | 6.07k | { |
95 | 6.07k | if (aDestination.IsMulticast()) |
96 | 0 | { |
97 | 0 | aMessageInfo.SetMulticastLoop(true); |
98 | 0 | } |
99 | | |
100 | 6.07k | if (aDestination.IsLinkLocalUnicastOrMulticast()) |
101 | 456 | { |
102 | 456 | aMessageInfo.SetSockAddr(Get<Mle::Mle>().GetLinkLocalAddress()); |
103 | 456 | } |
104 | 5.62k | else |
105 | 5.62k | { |
106 | 5.62k | aMessageInfo.SetSockAddrToRloc(); |
107 | 5.62k | } |
108 | | |
109 | 6.07k | aMessageInfo.SetPeerAddr(aDestination); |
110 | 6.07k | } |
111 | | |
112 | | Error Server::AppendIp6AddressList(Message &aMessage) |
113 | 2.26k | { |
114 | 2.26k | Error error = kErrorNone; |
115 | 2.26k | uint16_t count = 0; |
116 | | |
117 | 2.26k | for (const Ip6::Netif::UnicastAddress &addr : Get<ThreadNetif>().GetUnicastAddresses()) |
118 | 9.46k | { |
119 | 9.46k | OT_UNUSED_VARIABLE(addr); |
120 | 9.46k | count++; |
121 | 9.46k | } |
122 | | |
123 | 2.26k | if (count * Ip6::Address::kSize <= Tlv::kBaseTlvMaxLength) |
124 | 2.26k | { |
125 | 2.26k | Tlv tlv; |
126 | | |
127 | 2.26k | tlv.SetType(Tlv::kIp6AddressList); |
128 | 2.26k | tlv.SetLength(static_cast<uint8_t>(count * Ip6::Address::kSize)); |
129 | 2.26k | SuccessOrExit(error = aMessage.Append(tlv)); |
130 | 2.26k | } |
131 | 0 | else |
132 | 0 | { |
133 | 0 | ExtendedTlv extTlv; |
134 | |
|
135 | 0 | extTlv.SetType(Tlv::kIp6AddressList); |
136 | 0 | extTlv.SetLength(count * Ip6::Address::kSize); |
137 | 0 | SuccessOrExit(error = aMessage.Append(extTlv)); |
138 | 0 | } |
139 | | |
140 | 2.26k | for (const Ip6::Netif::UnicastAddress &addr : Get<ThreadNetif>().GetUnicastAddresses()) |
141 | 9.33k | { |
142 | 9.33k | SuccessOrExit(error = aMessage.Append(addr.GetAddress())); |
143 | 9.33k | } |
144 | | |
145 | 2.26k | exit: |
146 | 2.26k | return error; |
147 | 2.26k | } |
148 | | |
149 | | #if OPENTHREAD_FTD |
150 | | Error Server::AppendChildTable(Message &aMessage) |
151 | 211 | { |
152 | 211 | Error error = kErrorNone; |
153 | 211 | uint16_t count; |
154 | | |
155 | 211 | VerifyOrExit(Get<Mle::Mle>().IsRouterOrLeader()); |
156 | | |
157 | 0 | count = Min(Get<ChildTable>().GetNumChildren(Child::kInStateValid), kMaxChildEntries); |
158 | |
|
159 | 0 | if (count * sizeof(ChildTableEntry) <= Tlv::kBaseTlvMaxLength) |
160 | 0 | { |
161 | 0 | Tlv tlv; |
162 | |
|
163 | 0 | tlv.SetType(Tlv::kChildTable); |
164 | 0 | tlv.SetLength(static_cast<uint8_t>(count * sizeof(ChildTableEntry))); |
165 | 0 | SuccessOrExit(error = aMessage.Append(tlv)); |
166 | 0 | } |
167 | 0 | else |
168 | 0 | { |
169 | 0 | ExtendedTlv extTlv; |
170 | |
|
171 | 0 | extTlv.SetType(Tlv::kChildTable); |
172 | 0 | extTlv.SetLength(count * sizeof(ChildTableEntry)); |
173 | 0 | SuccessOrExit(error = aMessage.Append(extTlv)); |
174 | 0 | } |
175 | | |
176 | 0 | for (Child &child : Get<ChildTable>().Iterate(Child::kInStateValid)) |
177 | 0 | { |
178 | 0 | uint8_t timeout = 0; |
179 | 0 | ChildTableEntry entry; |
180 | |
|
181 | 0 | VerifyOrExit(count--); |
182 | | |
183 | 0 | while (static_cast<uint32_t>(1 << timeout) < child.GetTimeout()) |
184 | 0 | { |
185 | 0 | timeout++; |
186 | 0 | } |
187 | |
|
188 | 0 | entry.Clear(); |
189 | 0 | entry.SetTimeout(timeout + 4); |
190 | 0 | entry.SetLinkQuality(child.GetLinkQualityIn()); |
191 | 0 | entry.SetChildId(Mle::ChildIdFromRloc16(child.GetRloc16())); |
192 | 0 | entry.SetMode(child.GetDeviceMode()); |
193 | |
|
194 | 0 | SuccessOrExit(error = aMessage.Append(entry)); |
195 | 0 | } |
196 | | |
197 | 211 | exit: |
198 | 211 | return error; |
199 | 0 | } |
200 | | |
201 | | Error Server::AppendEnhancedRoute(Message &aMessage) |
202 | 195 | { |
203 | 195 | Error error = kErrorNone; |
204 | 195 | Tlv tlv; |
205 | 195 | Mle::RouterIdSet routerIdSet; |
206 | 195 | EnhancedRouteTlvEntry entry; |
207 | | |
208 | 195 | VerifyOrExit(Get<Mle::Mle>().IsRouterOrLeader()); |
209 | | |
210 | 0 | Get<RouterTable>().GetRouterIdSet(routerIdSet); |
211 | |
|
212 | 0 | tlv.SetType(Tlv::kEnhancedRoute); |
213 | 0 | tlv.SetLength(sizeof(Mle::RouterIdSet) + routerIdSet.GetNumberOfAllocatedIds() * sizeof(entry)); |
214 | |
|
215 | 0 | SuccessOrExit(error = aMessage.Append(tlv)); |
216 | 0 | SuccessOrExit(error = aMessage.Append(routerIdSet)); |
217 | | |
218 | 0 | for (uint8_t routerId = 0; routerId <= Mle::kMaxRouterId; routerId++) |
219 | 0 | { |
220 | 0 | if (!routerIdSet.Contains(routerId)) |
221 | 0 | { |
222 | 0 | continue; |
223 | 0 | } |
224 | | |
225 | 0 | if (Get<Mle::Mle>().MatchesRouterId(routerId)) |
226 | 0 | { |
227 | 0 | entry.InitAsSelf(); |
228 | 0 | } |
229 | 0 | else |
230 | 0 | { |
231 | 0 | entry.InitFrom(*Get<RouterTable>().FindRouterById(routerId)); |
232 | 0 | } |
233 | |
|
234 | 0 | SuccessOrExit(error = aMessage.Append(entry)); |
235 | 0 | } |
236 | | |
237 | 195 | exit: |
238 | 195 | return error; |
239 | 0 | } |
240 | | |
241 | | #if OPENTHREAD_CONFIG_BLE_TCAT_ENABLE |
242 | | Error Server::AppendChildTableAsChildTlvs(Message &aMessage) |
243 | | { |
244 | | Error error = kErrorNone; |
245 | | ChildTlv childTlv; |
246 | | |
247 | | for (Child &child : Get<ChildTable>().Iterate(Child::kInStateValid)) |
248 | | { |
249 | | childTlv.InitFrom(child); |
250 | | |
251 | | SuccessOrExit(error = childTlv.AppendTo(aMessage)); |
252 | | } |
253 | | |
254 | | // Add empty TLV to indicate end of the list |
255 | | |
256 | | childTlv.InitAsEmpty(); |
257 | | SuccessOrExit(error = childTlv.AppendTo(aMessage)); |
258 | | |
259 | | exit: |
260 | | return error; |
261 | | } |
262 | | |
263 | | Error Server::AppendRouterNeighborTlvs(Message &aMessage) |
264 | | { |
265 | | Error error = kErrorNone; |
266 | | RouterNeighborTlv neighborTlv; |
267 | | |
268 | | for (Router &router : Get<RouterTable>()) |
269 | | { |
270 | | if (router.IsStateValid()) |
271 | | { |
272 | | neighborTlv.InitFrom(router); |
273 | | SuccessOrExit(error = neighborTlv.AppendTo(aMessage)); |
274 | | } |
275 | | } |
276 | | |
277 | | // Add empty TLV to indicate end of the list |
278 | | |
279 | | neighborTlv.InitAsEmpty(); |
280 | | SuccessOrExit(error = neighborTlv.AppendTo(aMessage)); |
281 | | |
282 | | exit: |
283 | | return error; |
284 | | } |
285 | | |
286 | | Error Server::AppendChildTableIp6AddressList(Message &aMessage) |
287 | | { |
288 | | Error error = kErrorNone; |
289 | | Tlv tlv; |
290 | | |
291 | | for (const Child &child : Get<ChildTable>().Iterate(Child::kInStateValid)) |
292 | | { |
293 | | SuccessOrExit(error = AppendChildIp6AddressListTlv(aMessage, child)); |
294 | | } |
295 | | |
296 | | // Add empty TLV to indicate end of the list |
297 | | |
298 | | tlv.SetType(Tlv::kChildIp6AddressList); |
299 | | tlv.SetLength(0); |
300 | | SuccessOrExit(error = aMessage.Append(tlv)); |
301 | | |
302 | | exit: |
303 | | return error; |
304 | | } |
305 | | #endif // OPENTHREAD_CONFIG_BLE_TCAT_ENABLE |
306 | | #endif // OPENTHREAD_FTD |
307 | | |
308 | | Error Server::AppendMacCounters(Message &aMessage) |
309 | 262 | { |
310 | 262 | MacCountersTlv tlv; |
311 | 262 | const otMacCounters &counters = Get<Mac::Mac>().GetCounters(); |
312 | | |
313 | 262 | ClearAllBytes(tlv); |
314 | | |
315 | 262 | tlv.Init(); |
316 | 262 | tlv.SetIfInUnknownProtos(counters.mRxOther); |
317 | 262 | tlv.SetIfInErrors(counters.mRxErrNoFrame + counters.mRxErrUnknownNeighbor + counters.mRxErrInvalidSrcAddr + |
318 | 262 | counters.mRxErrSec + counters.mRxErrFcs + counters.mRxErrOther); |
319 | 262 | tlv.SetIfOutErrors(counters.mTxErrCca); |
320 | 262 | tlv.SetIfInUcastPkts(counters.mRxUnicast); |
321 | 262 | tlv.SetIfInBroadcastPkts(counters.mRxBroadcast); |
322 | 262 | tlv.SetIfInDiscards(counters.mRxAddressFiltered + counters.mRxDestAddrFiltered + counters.mRxDuplicated); |
323 | 262 | tlv.SetIfOutUcastPkts(counters.mTxUnicast); |
324 | 262 | tlv.SetIfOutBroadcastPkts(counters.mTxBroadcast); |
325 | 262 | tlv.SetIfOutDiscards(counters.mTxErrBusyChannel); |
326 | | |
327 | 262 | return tlv.AppendTo(aMessage); |
328 | 262 | } |
329 | | |
330 | | Error Server::AppendRequestedTlvs(const Message &aRequest, Message &aResponse) |
331 | 835 | { |
332 | 835 | Error error; |
333 | 835 | OffsetRange offsetRange; |
334 | | |
335 | 835 | SuccessOrExit(error = Tlv::FindTlvValueOffsetRange(aRequest, Tlv::kTypeList, offsetRange)); |
336 | | |
337 | 711 | while (!offsetRange.IsEmpty()) |
338 | 550 | { |
339 | 550 | uint8_t tlvType; |
340 | | |
341 | 550 | SuccessOrExit(error = aRequest.Read(offsetRange, tlvType)); |
342 | 550 | offsetRange.AdvanceOffset(sizeof(tlvType)); |
343 | 550 | SuccessOrExit(error = AppendDiagTlv(tlvType, aResponse)); |
344 | 550 | } |
345 | | |
346 | 835 | exit: |
347 | 835 | return error; |
348 | 352 | } |
349 | | |
350 | | #if OPENTHREAD_CONFIG_BLE_TCAT_ENABLE |
351 | | Error Server::AppendRequestedTlvsForTcat(const Message &aRequest, Message &aResponse, OffsetRange &aOffsetRange) |
352 | | { |
353 | | Error error = kErrorNone; |
354 | | |
355 | | while (!aOffsetRange.IsEmpty()) |
356 | | { |
357 | | uint8_t tlvType; |
358 | | |
359 | | SuccessOrExit(error = aRequest.Read(aOffsetRange, tlvType)); |
360 | | aOffsetRange.AdvanceOffset(sizeof(uint8_t)); |
361 | | |
362 | | #if OPENTHREAD_FTD |
363 | | switch (tlvType) |
364 | | { |
365 | | case ChildTlv::kType: |
366 | | SuccessOrExit(error = AppendChildTableAsChildTlvs(aResponse)); |
367 | | break; |
368 | | |
369 | | case ChildIp6AddressListTlv::kType: |
370 | | SuccessOrExit(error = AppendChildTableIp6AddressList(aResponse)); |
371 | | break; |
372 | | |
373 | | case RouterNeighborTlv::kType: |
374 | | SuccessOrExit(error = AppendRouterNeighborTlvs(aResponse)); |
375 | | break; |
376 | | |
377 | | default: |
378 | | SuccessOrExit(error = AppendDiagTlv(tlvType, aResponse)); |
379 | | break; |
380 | | } |
381 | | |
382 | | #elif OPENTHREAD_MTD |
383 | | SuccessOrExit(error = AppendDiagTlv(tlvType, aResponse)); |
384 | | #endif |
385 | | } |
386 | | |
387 | | exit: |
388 | | return error; |
389 | | } |
390 | | #endif // OPENTHREAD_CONFIG_BLE_TCAT_ENABLE |
391 | | |
392 | | Error Server::AppendDiagTlv(uint8_t aTlvType, Message &aMessage) |
393 | 12.9k | { |
394 | 12.9k | Error error = kErrorNone; |
395 | | |
396 | 12.9k | switch (aTlvType) |
397 | 12.9k | { |
398 | 219 | case Tlv::kExtMacAddress: |
399 | 219 | error = Tlv::Append<ExtMacAddressTlv>(aMessage, Get<Mac::Mac>().GetExtAddress()); |
400 | 219 | break; |
401 | | |
402 | 211 | case Tlv::kAddress16: |
403 | 211 | error = Tlv::Append<Address16Tlv>(aMessage, Get<Mle::Mle>().GetRloc16()); |
404 | 211 | break; |
405 | | |
406 | 208 | case Tlv::kMode: |
407 | 208 | error = Tlv::Append<ModeTlv>(aMessage, Get<Mle::Mle>().GetDeviceMode().Get()); |
408 | 208 | break; |
409 | | |
410 | 66 | case Tlv::kEui64: |
411 | 66 | { |
412 | 66 | Mac::ExtAddress eui64; |
413 | | |
414 | 66 | Get<Radio>().GetIeeeEui64(eui64); |
415 | 66 | error = Tlv::Append<Eui64Tlv>(aMessage, eui64); |
416 | 66 | break; |
417 | 0 | } |
418 | | |
419 | 1.15k | case Tlv::kVersion: |
420 | 1.15k | error = Tlv::Append<VersionTlv>(aMessage, kThreadVersion); |
421 | 1.15k | break; |
422 | | |
423 | 2.15k | case Tlv::kTimeout: |
424 | 2.15k | VerifyOrExit(!Get<Mle::Mle>().IsRxOnWhenIdle()); |
425 | 298 | error = Tlv::Append<TimeoutTlv>(aMessage, Get<Mle::Mle>().GetTimeout()); |
426 | 298 | break; |
427 | | |
428 | 208 | case Tlv::kLeaderData: |
429 | 208 | { |
430 | 208 | LeaderDataTlv tlv; |
431 | | |
432 | 208 | tlv.Init(); |
433 | 208 | tlv.Set(Get<Mle::Mle>().GetLeaderData()); |
434 | 208 | error = tlv.AppendTo(aMessage); |
435 | 208 | break; |
436 | 2.15k | } |
437 | | |
438 | 202 | case Tlv::kNetworkData: |
439 | 202 | error = Tlv::Append<NetworkDataTlv>(aMessage, Get<NetworkData::Leader>().GetBytes(), |
440 | 202 | Get<NetworkData::Leader>().GetLength()); |
441 | 202 | break; |
442 | | |
443 | 2.26k | case Tlv::kIp6AddressList: |
444 | 2.26k | error = AppendIp6AddressList(aMessage); |
445 | 2.26k | break; |
446 | | |
447 | 262 | case Tlv::kMacCounters: |
448 | 262 | error = AppendMacCounters(aMessage); |
449 | 262 | break; |
450 | | |
451 | 322 | case Tlv::kMleCounters: |
452 | 322 | { |
453 | 322 | MleCountersTlv tlv; |
454 | | |
455 | 322 | tlv.Init(Get<Mle::Mle>().GetCounters()); |
456 | 322 | error = tlv.AppendTo(aMessage); |
457 | 322 | break; |
458 | 2.15k | } |
459 | | |
460 | 752 | case Tlv::kVendorName: |
461 | 752 | error = Tlv::Append<VendorNameTlv>(aMessage, GetVendorName()); |
462 | 752 | break; |
463 | | |
464 | 1.37k | case Tlv::kVendorModel: |
465 | 1.37k | error = Tlv::Append<VendorModelTlv>(aMessage, GetVendorModel()); |
466 | 1.37k | break; |
467 | | |
468 | 67 | case Tlv::kVendorSwVersion: |
469 | 67 | error = Tlv::Append<VendorSwVersionTlv>(aMessage, GetVendorSwVersion()); |
470 | 67 | break; |
471 | | |
472 | 608 | case Tlv::kVendorAppUrl: |
473 | 608 | error = Tlv::Append<VendorAppUrlTlv>(aMessage, GetVendorAppUrl()); |
474 | 608 | break; |
475 | | |
476 | 170 | case Tlv::kThreadStackVersion: |
477 | 170 | error = Tlv::Append<ThreadStackVersionTlv>(aMessage, otGetVersionString()); |
478 | 170 | break; |
479 | | |
480 | 203 | case Tlv::kChannelPages: |
481 | 203 | { |
482 | 203 | ChannelPagesTlv tlv; |
483 | 203 | uint8_t length = 0; |
484 | | |
485 | 203 | tlv.Init(); |
486 | | |
487 | 203 | for (uint8_t page : Radio::kSupportedChannelPages) |
488 | 203 | { |
489 | 203 | tlv.GetChannelPages()[length++] = page; |
490 | 203 | } |
491 | | |
492 | 203 | tlv.SetLength(length); |
493 | 203 | error = tlv.AppendTo(aMessage); |
494 | | |
495 | 203 | break; |
496 | 2.15k | } |
497 | | |
498 | 200 | case Tlv::kNonPreferredChannels: |
499 | 200 | { |
500 | 200 | MeshCoP::ChannelMaskTlv::Value value; |
501 | | |
502 | 200 | MeshCoP::ChannelMaskTlv::PrepareValue(value, mNonPreferredChannels, /* aIncludeZeroPageMasks */ true); |
503 | 200 | error = Tlv::AppendTlv(aMessage, Tlv::kNonPreferredChannels, value.mData, value.mLength); |
504 | 200 | break; |
505 | 2.15k | } |
506 | | |
507 | 0 | #if OPENTHREAD_FTD |
508 | | |
509 | 407 | case Tlv::kConnectivity: |
510 | 407 | { |
511 | 407 | ConnectivityTlv tlv; |
512 | | |
513 | 407 | tlv.Init(); |
514 | 407 | Get<Mle::Mle>().FillConnectivityTlv(tlv); |
515 | 407 | error = tlv.AppendTo(aMessage); |
516 | 407 | break; |
517 | 2.15k | } |
518 | | |
519 | 968 | case Tlv::kRoute: |
520 | 968 | { |
521 | 968 | RouteTlv tlv; |
522 | | |
523 | 968 | tlv.Init(); |
524 | 968 | Get<RouterTable>().FillRouteTlv(tlv); |
525 | 968 | SuccessOrExit(error = tlv.AppendTo(aMessage)); |
526 | 968 | break; |
527 | 968 | } |
528 | | |
529 | 968 | case Tlv::kEnhancedRoute: |
530 | 195 | error = AppendEnhancedRoute(aMessage); |
531 | 195 | break; |
532 | | |
533 | 211 | case Tlv::kChildTable: |
534 | 211 | error = AppendChildTable(aMessage); |
535 | 211 | break; |
536 | | |
537 | 66 | case Tlv::kMaxChildTimeout: |
538 | 66 | { |
539 | 66 | uint32_t maxTimeout; |
540 | | |
541 | 66 | SuccessOrExit(Get<Mle::Mle>().GetMaxChildTimeout(maxTimeout)); |
542 | 0 | error = Tlv::Append<MaxChildTimeoutTlv>(aMessage, maxTimeout); |
543 | 0 | break; |
544 | 66 | } |
545 | | |
546 | 0 | #endif // OPENTHREAD_FTD |
547 | | |
548 | 436 | default: |
549 | 436 | break; |
550 | 12.9k | } |
551 | | |
552 | 12.9k | exit: |
553 | 12.9k | return error; |
554 | 12.9k | } |
555 | | |
556 | | template <> |
557 | | void Server::HandleTmf<kUriDiagnosticGetQuery>(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo) |
558 | 8.02k | { |
559 | 8.02k | VerifyOrExit(aMessage.IsPostRequest()); |
560 | | |
561 | 7.83k | LogInfo("Received %s from %s", UriToString<kUriDiagnosticGetQuery>(), |
562 | 7.83k | aMessageInfo.GetPeerAddr().ToString().AsCString()); |
563 | | |
564 | | // DIAG_GET.qry may be sent as a confirmable request. |
565 | 7.83k | if (aMessage.IsConfirmable()) |
566 | 270 | { |
567 | 270 | IgnoreError(Get<Tmf::Agent>().SendEmptyAck(aMessage, aMessageInfo)); |
568 | 270 | } |
569 | | |
570 | | #if OPENTHREAD_MTD |
571 | | SendAnswer(aMessageInfo.GetPeerAddr(), aMessage); |
572 | | #elif OPENTHREAD_FTD |
573 | | PrepareAndSendAnswers(aMessageInfo.GetPeerAddr(), aMessage); |
574 | 7.83k | #endif |
575 | | |
576 | 8.02k | exit: |
577 | 8.02k | return; |
578 | 7.83k | } |
579 | | |
580 | | #if OPENTHREAD_MTD |
581 | | |
582 | | void Server::SendAnswer(const Ip6::Address &aDestination, const Message &aRequest) |
583 | | { |
584 | | Error error = kErrorNone; |
585 | | Coap::Message *answer = nullptr; |
586 | | Tmf::MessageInfo messageInfo(GetInstance()); |
587 | | AnswerTlv answerTlv; |
588 | | uint16_t queryId; |
589 | | |
590 | | answer = Get<Tmf::Agent>().NewConfirmablePostMessage(kUriDiagnosticGetAnswer); |
591 | | VerifyOrExit(answer != nullptr, error = kErrorNoBufs); |
592 | | |
593 | | IgnoreError(answer->SetPriority(aRequest.GetPriority())); |
594 | | |
595 | | if (Tlv::Find<QueryIdTlv>(aRequest, queryId) == kErrorNone) |
596 | | { |
597 | | SuccessOrExit(error = Tlv::Append<QueryIdTlv>(*answer, queryId)); |
598 | | } |
599 | | |
600 | | SuccessOrExit(error = AppendRequestedTlvs(aRequest, *answer)); |
601 | | |
602 | | answerTlv.Init(0, /* aIsLast */ true); |
603 | | SuccessOrExit(answer->Append(answerTlv)); |
604 | | |
605 | | PrepareMessageInfoForDest(aDestination, messageInfo); |
606 | | |
607 | | error = Get<Tmf::Agent>().SendMessage(*answer, messageInfo); |
608 | | |
609 | | exit: |
610 | | FreeMessageOnError(answer, error); |
611 | | } |
612 | | |
613 | | #endif // OPENTHREAD_MTD |
614 | | |
615 | | #if OPENTHREAD_FTD |
616 | | |
617 | | Error Server::AllocateAnswer(Coap::Message *&aAnswer, AnswerInfo &aInfo) |
618 | 7.83k | { |
619 | | // Allocate an `Answer` message, adds it in `mAnswerQueue`, |
620 | | // update the `aInfo.mFirstAnswer` if it is the first allocated |
621 | | // messages, and appends `QueryIdTlv` to the message (if needed). |
622 | | |
623 | 7.83k | Error error = kErrorNone; |
624 | | |
625 | 7.83k | aAnswer = Get<Tmf::Agent>().NewConfirmablePostMessage(kUriDiagnosticGetAnswer); |
626 | 7.83k | VerifyOrExit(aAnswer != nullptr, error = kErrorNoBufs); |
627 | 7.37k | IgnoreError(aAnswer->SetPriority(aInfo.mPriority)); |
628 | | |
629 | 7.37k | mAnswerQueue.Enqueue(*aAnswer); |
630 | | |
631 | 7.37k | if (aInfo.mFirstAnswer == nullptr) |
632 | 7.37k | { |
633 | 7.37k | aInfo.mFirstAnswer = aAnswer; |
634 | 7.37k | } |
635 | | |
636 | 7.37k | if (aInfo.mHasQueryId) |
637 | 194 | { |
638 | 194 | SuccessOrExit(error = Tlv::Append<QueryIdTlv>(*aAnswer, aInfo.mQueryId)); |
639 | 194 | } |
640 | | |
641 | 7.83k | exit: |
642 | 7.83k | return error; |
643 | 7.37k | } |
644 | | |
645 | | bool Server::IsLastAnswer(const Coap::Message &aAnswer) const |
646 | 7.37k | { |
647 | | // Indicates whether `aAnswer` is the last one associated with |
648 | | // the same query. |
649 | | |
650 | 7.37k | bool isLast = true; |
651 | 7.37k | AnswerTlv answerTlv; |
652 | | |
653 | | // If there is no Answer TLV, we assume it is the last answer. |
654 | | |
655 | 7.37k | SuccessOrExit(Tlv::FindTlv(aAnswer, answerTlv)); |
656 | 6.07k | isLast = answerTlv.IsLast(); |
657 | | |
658 | 7.37k | exit: |
659 | 7.37k | return isLast; |
660 | 6.07k | } |
661 | | |
662 | | void Server::FreeAllRelatedAnswers(Coap::Message &aFirstAnswer) |
663 | 1.29k | { |
664 | | // This method dequeues and frees all answer messages related to |
665 | | // same query as `aFirstAnswer`. Note that related answers are |
666 | | // enqueued in order. |
667 | | |
668 | 1.29k | Coap::Message *answer = &aFirstAnswer; |
669 | | |
670 | 2.59k | while (answer != nullptr) |
671 | 1.29k | { |
672 | 1.29k | Coap::Message *next = IsLastAnswer(*answer) ? nullptr : answer->GetNextCoapMessage(); |
673 | | |
674 | 1.29k | mAnswerQueue.DequeueAndFree(*answer); |
675 | 1.29k | answer = next; |
676 | 1.29k | } |
677 | 1.29k | } |
678 | | |
679 | | void Server::PrepareAndSendAnswers(const Ip6::Address &aDestination, const Message &aRequest) |
680 | 7.83k | { |
681 | 7.83k | Coap::Message *answer; |
682 | 7.83k | Error error; |
683 | 7.83k | AnswerInfo info; |
684 | 7.83k | OffsetRange offsetRange; |
685 | 7.83k | AnswerTlv answerTlv; |
686 | | |
687 | 7.83k | if (Tlv::Find<QueryIdTlv>(aRequest, info.mQueryId) == kErrorNone) |
688 | 194 | { |
689 | 194 | info.mHasQueryId = true; |
690 | 194 | } |
691 | | |
692 | 7.83k | info.mPriority = aRequest.GetPriority(); |
693 | | |
694 | 7.83k | SuccessOrExit(error = AllocateAnswer(answer, info)); |
695 | | |
696 | 7.37k | SuccessOrExit(error = Tlv::FindTlvValueOffsetRange(aRequest, Tlv::kTypeList, offsetRange)); |
697 | | |
698 | 18.8k | while (!offsetRange.IsEmpty()) |
699 | 12.7k | { |
700 | 12.7k | uint8_t tlvType; |
701 | | |
702 | 12.7k | SuccessOrExit(error = aRequest.Read(offsetRange, tlvType)); |
703 | 12.7k | offsetRange.AdvanceOffset(sizeof(tlvType)); |
704 | | |
705 | 12.7k | switch (tlvType) |
706 | 12.7k | { |
707 | 195 | case ChildTlv::kType: |
708 | 195 | SuccessOrExit(error = AppendChildTableAsChildTlvs(answer, info)); |
709 | 195 | break; |
710 | 195 | case ChildIp6AddressListTlv::kType: |
711 | 76 | SuccessOrExit(error = AppendChildTableIp6AddressList(answer, info)); |
712 | 76 | break; |
713 | 76 | case RouterNeighborTlv::kType: |
714 | 66 | SuccessOrExit(error = AppendRouterNeighborTlvs(answer, info)); |
715 | 66 | break; |
716 | 12.3k | default: |
717 | 12.3k | SuccessOrExit(error = AppendDiagTlv(tlvType, *answer)); |
718 | 12.1k | break; |
719 | 12.7k | } |
720 | | |
721 | 12.4k | SuccessOrExit(error = CheckAnswerLength(answer, info)); |
722 | 12.4k | } |
723 | | |
724 | 6.13k | answerTlv.Init(info.mAnswerIndex, /* aIsLast */ true); |
725 | 6.13k | SuccessOrExit(error = answer->Append(answerTlv)); |
726 | | |
727 | 6.07k | SendNextAnswer(*info.mFirstAnswer, aDestination); |
728 | | |
729 | 7.83k | exit: |
730 | 7.83k | if ((error != kErrorNone) && (info.mFirstAnswer != nullptr)) |
731 | 1.29k | { |
732 | 1.29k | FreeAllRelatedAnswers(*info.mFirstAnswer); |
733 | 1.29k | } |
734 | 7.83k | } |
735 | | |
736 | | Error Server::CheckAnswerLength(Coap::Message *&aAnswer, AnswerInfo &aInfo) |
737 | 12.4k | { |
738 | | // This method checks the length of the `aAnswer` message and if it |
739 | | // is above the threshold, it enqueues the message for transmission |
740 | | // after appending an Answer TLV with the current index to the |
741 | | // message. In this case, it will also allocate a new answer |
742 | | // message. |
743 | | |
744 | 12.4k | Error error = kErrorNone; |
745 | 12.4k | AnswerTlv answerTlv; |
746 | | |
747 | 12.4k | VerifyOrExit(aAnswer->GetLength() >= kAnswerMessageLengthThreshold); |
748 | | |
749 | 0 | answerTlv.Init(aInfo.mAnswerIndex++, /* aIsLast */ false); |
750 | 0 | SuccessOrExit(error = aAnswer->Append(answerTlv)); |
751 | | |
752 | 0 | error = AllocateAnswer(aAnswer, aInfo); |
753 | |
|
754 | 12.4k | exit: |
755 | 12.4k | return error; |
756 | 0 | } |
757 | | |
758 | | void Server::SendNextAnswer(Coap::Message &aAnswer, const Ip6::Address &aDestination) |
759 | 6.07k | { |
760 | | // This method send the given next `aAnswer` associated with |
761 | | // a query to the `aDestination`. |
762 | | |
763 | 6.07k | Error error = kErrorNone; |
764 | 6.07k | Coap::Message *nextAnswer = IsLastAnswer(aAnswer) ? nullptr : aAnswer.GetNextCoapMessage(); |
765 | 6.07k | Tmf::MessageInfo messageInfo(GetInstance()); |
766 | | |
767 | 6.07k | mAnswerQueue.Dequeue(aAnswer); |
768 | | |
769 | 6.07k | PrepareMessageInfoForDest(aDestination, messageInfo); |
770 | | |
771 | | // When sending the message, we pass `nextAnswer` as `aContext` |
772 | | // to be used when invoking callback `HandleAnswerResponse()`. |
773 | | |
774 | 6.07k | error = Get<Tmf::Agent>().SendMessage(aAnswer, messageInfo, HandleAnswerResponse, nextAnswer); |
775 | | |
776 | 6.07k | if (error != kErrorNone) |
777 | 4.13k | { |
778 | | // If the `SendMessage()` fails, we `Free` the dequeued |
779 | | // `aAnswer` and all the related next answers in the queue. |
780 | | |
781 | 4.13k | aAnswer.Free(); |
782 | | |
783 | 4.13k | if (nextAnswer != nullptr) |
784 | 0 | { |
785 | 0 | FreeAllRelatedAnswers(*nextAnswer); |
786 | 0 | } |
787 | 4.13k | } |
788 | 6.07k | } |
789 | | |
790 | | void Server::HandleAnswerResponse(void *aContext, |
791 | | otMessage *aMessage, |
792 | | const otMessageInfo *aMessageInfo, |
793 | | otError aResult) |
794 | 1.94k | { |
795 | 1.94k | Coap::Message *nextAnswer = static_cast<Coap::Message *>(aContext); |
796 | | |
797 | 1.94k | VerifyOrExit(nextAnswer != nullptr); |
798 | | |
799 | 0 | nextAnswer->Get<Server>().HandleAnswerResponse(*nextAnswer, AsCoapMessagePtr(aMessage), AsCoreTypePtr(aMessageInfo), |
800 | 0 | aResult); |
801 | |
|
802 | 1.94k | exit: |
803 | 1.94k | return; |
804 | 0 | } |
805 | | |
806 | | void Server::HandleAnswerResponse(Coap::Message &aNextAnswer, |
807 | | Coap::Message *aResponse, |
808 | | const Ip6::MessageInfo *aMessageInfo, |
809 | | Error aResult) |
810 | 0 | { |
811 | 0 | Error error = aResult; |
812 | |
|
813 | 0 | SuccessOrExit(error); |
814 | 0 | VerifyOrExit(aResponse != nullptr && aMessageInfo != nullptr, error = kErrorDrop); |
815 | 0 | VerifyOrExit(aResponse->GetCode() == Coap::kCodeChanged, error = kErrorDrop); |
816 | | |
817 | 0 | SendNextAnswer(aNextAnswer, aMessageInfo->GetPeerAddr()); |
818 | |
|
819 | 0 | exit: |
820 | 0 | if (error != kErrorNone) |
821 | 0 | { |
822 | 0 | FreeAllRelatedAnswers(aNextAnswer); |
823 | 0 | } |
824 | 0 | } |
825 | | |
826 | | Error Server::AppendChildTableAsChildTlvs(Coap::Message *&aAnswer, AnswerInfo &aInfo) |
827 | 195 | { |
828 | 195 | Error error = kErrorNone; |
829 | 195 | ChildTlv childTlv; |
830 | | |
831 | 195 | for (Child &child : Get<ChildTable>().Iterate(Child::kInStateValid)) |
832 | 0 | { |
833 | 0 | childTlv.InitFrom(child); |
834 | |
|
835 | 0 | SuccessOrExit(error = childTlv.AppendTo(*aAnswer)); |
836 | 0 | SuccessOrExit(error = CheckAnswerLength(aAnswer, aInfo)); |
837 | 0 | } |
838 | | |
839 | | // Add empty TLV to indicate end of the list |
840 | | |
841 | 195 | childTlv.InitAsEmpty(); |
842 | 195 | SuccessOrExit(error = childTlv.AppendTo(*aAnswer)); |
843 | | |
844 | 195 | exit: |
845 | 195 | return error; |
846 | 195 | } |
847 | | |
848 | | Error Server::AppendRouterNeighborTlvs(Coap::Message *&aAnswer, AnswerInfo &aInfo) |
849 | 66 | { |
850 | 66 | Error error = kErrorNone; |
851 | 66 | RouterNeighborTlv neighborTlv; |
852 | | |
853 | 66 | for (Router &router : Get<RouterTable>()) |
854 | 0 | { |
855 | 0 | if (!router.IsStateValid()) |
856 | 0 | { |
857 | 0 | continue; |
858 | 0 | } |
859 | | |
860 | 0 | neighborTlv.InitFrom(router); |
861 | |
|
862 | 0 | SuccessOrExit(error = neighborTlv.AppendTo(*aAnswer)); |
863 | 0 | SuccessOrExit(error = CheckAnswerLength(aAnswer, aInfo)); |
864 | 0 | } |
865 | | |
866 | | // Add empty TLV to indicate end of the list |
867 | | |
868 | 66 | neighborTlv.InitAsEmpty(); |
869 | 66 | SuccessOrExit(error = neighborTlv.AppendTo(*aAnswer)); |
870 | | |
871 | 66 | exit: |
872 | 66 | return error; |
873 | 66 | } |
874 | | |
875 | | Error Server::AppendChildTableIp6AddressList(Coap::Message *&aAnswer, AnswerInfo &aInfo) |
876 | 76 | { |
877 | 76 | Error error = kErrorNone; |
878 | 76 | Tlv tlv; |
879 | | |
880 | 76 | for (const Child &child : Get<ChildTable>().Iterate(Child::kInStateValid)) |
881 | 0 | { |
882 | 0 | SuccessOrExit(error = AppendChildIp6AddressListTlv(*aAnswer, child)); |
883 | 0 | SuccessOrExit(error = CheckAnswerLength(aAnswer, aInfo)); |
884 | 0 | } |
885 | | |
886 | | // Add empty TLV to indicate end of the list |
887 | | |
888 | 76 | tlv.SetType(Tlv::kChildIp6AddressList); |
889 | 76 | tlv.SetLength(0); |
890 | 76 | SuccessOrExit(error = aAnswer->Append(tlv)); |
891 | | |
892 | 76 | exit: |
893 | 76 | return error; |
894 | 76 | } |
895 | | |
896 | | Error Server::AppendChildIp6AddressListTlv(Message &aAnswer, const Child &aChild) |
897 | 0 | { |
898 | 0 | Error error = kErrorNone; |
899 | 0 | uint16_t numIp6Addr = aChild.GetIp6Addresses().GetLength(); |
900 | 0 | ChildIp6AddressListTlvValue tlvValue; |
901 | 0 | Ip6::Address mlEid; |
902 | |
|
903 | 0 | if (aChild.GetMeshLocalIp6Address(mlEid) == kErrorNone) |
904 | 0 | { |
905 | 0 | numIp6Addr++; |
906 | 0 | } |
907 | 0 | else |
908 | 0 | { |
909 | 0 | mlEid.Clear(); |
910 | 0 | } |
911 | |
|
912 | 0 | VerifyOrExit(numIp6Addr > 0); |
913 | | |
914 | 0 | if ((numIp6Addr * sizeof(Ip6::Address) + sizeof(ChildIp6AddressListTlvValue)) <= Tlv::kBaseTlvMaxLength) |
915 | 0 | { |
916 | 0 | Tlv tlv; |
917 | |
|
918 | 0 | tlv.SetType(Tlv::kChildIp6AddressList); |
919 | 0 | tlv.SetLength(static_cast<uint8_t>(numIp6Addr * sizeof(Ip6::Address) + sizeof(ChildIp6AddressListTlvValue))); |
920 | 0 | SuccessOrExit(error = aAnswer.Append(tlv)); |
921 | 0 | } |
922 | 0 | else |
923 | 0 | { |
924 | 0 | ExtendedTlv extTlv; |
925 | |
|
926 | 0 | extTlv.SetType(Tlv::kChildIp6AddressList); |
927 | 0 | extTlv.SetLength(numIp6Addr * sizeof(Ip6::Address) + sizeof(ChildIp6AddressListTlvValue)); |
928 | 0 | SuccessOrExit(error = aAnswer.Append(extTlv)); |
929 | 0 | } |
930 | | |
931 | 0 | tlvValue.SetRloc16(aChild.GetRloc16()); |
932 | |
|
933 | 0 | SuccessOrExit(error = aAnswer.Append(tlvValue)); |
934 | | |
935 | 0 | if (!mlEid.IsUnspecified()) |
936 | 0 | { |
937 | 0 | SuccessOrExit(error = aAnswer.Append(mlEid)); |
938 | 0 | } |
939 | | |
940 | 0 | for (const Ip6::Address &address : aChild.GetIp6Addresses()) |
941 | 0 | { |
942 | 0 | SuccessOrExit(error = aAnswer.Append(address)); |
943 | 0 | } |
944 | | |
945 | 0 | exit: |
946 | 0 | return error; |
947 | 0 | } |
948 | | |
949 | | #endif // OPENTHREAD_FTD |
950 | | |
951 | | template <> |
952 | | void Server::HandleTmf<kUriDiagnosticGetRequest>(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo) |
953 | 1.22k | { |
954 | 1.22k | Error error = kErrorNone; |
955 | 1.22k | Coap::Message *response = nullptr; |
956 | | |
957 | 1.22k | VerifyOrExit(aMessage.IsConfirmablePostRequest(), error = kErrorDrop); |
958 | | |
959 | 1.02k | LogInfo("Received %s from %s", UriToString<kUriDiagnosticGetRequest>(), |
960 | 1.02k | aMessageInfo.GetPeerAddr().ToString().AsCString()); |
961 | | |
962 | 1.02k | response = Get<Tmf::Agent>().NewResponseMessage(aMessage); |
963 | 1.02k | VerifyOrExit(response != nullptr, error = kErrorNoBufs); |
964 | | |
965 | 835 | IgnoreError(response->SetPriority(aMessage.GetPriority())); |
966 | 835 | SuccessOrExit(error = AppendRequestedTlvs(aMessage, *response)); |
967 | 161 | SuccessOrExit(error = Get<Tmf::Agent>().SendMessage(*response, aMessageInfo)); |
968 | | |
969 | 1.22k | exit: |
970 | 1.22k | FreeMessageOnError(response, error); |
971 | 1.22k | } |
972 | | |
973 | | template <> void Server::HandleTmf<kUriDiagnosticReset>(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo) |
974 | 1.86k | { |
975 | 1.86k | uint16_t offset = 0; |
976 | 1.86k | uint8_t type; |
977 | 1.86k | Tlv tlv; |
978 | | |
979 | 1.86k | VerifyOrExit(aMessage.IsConfirmablePostRequest()); |
980 | | |
981 | 1.67k | LogInfo("Received %s from %s", UriToString<kUriDiagnosticReset>(), |
982 | 1.67k | aMessageInfo.GetPeerAddr().ToString().AsCString()); |
983 | | |
984 | 1.67k | SuccessOrExit(aMessage.Read(aMessage.GetOffset(), tlv)); |
985 | | |
986 | 1.47k | VerifyOrExit(tlv.GetType() == Tlv::kTypeList); |
987 | | |
988 | 1.28k | offset = aMessage.GetOffset() + sizeof(Tlv); |
989 | | |
990 | 2.67k | for (uint8_t i = 0; i < tlv.GetLength(); i++) |
991 | 2.28k | { |
992 | 2.28k | SuccessOrExit(aMessage.Read(offset + i, type)); |
993 | | |
994 | 1.39k | switch (type) |
995 | 1.39k | { |
996 | 195 | case Tlv::kMacCounters: |
997 | 195 | Get<Mac::Mac>().ResetCounters(); |
998 | 195 | break; |
999 | | |
1000 | 194 | case Tlv::kMleCounters: |
1001 | 194 | Get<Mle::Mle>().ResetCounters(); |
1002 | 194 | break; |
1003 | | |
1004 | 225 | case Tlv::kNonPreferredChannels: |
1005 | 225 | mNonPreferredChannelsResetCallback.InvokeIfSet(); |
1006 | 225 | break; |
1007 | | |
1008 | 783 | default: |
1009 | 783 | break; |
1010 | 1.39k | } |
1011 | 1.39k | } |
1012 | | |
1013 | 390 | IgnoreError(Get<Tmf::Agent>().SendEmptyAck(aMessage, aMessageInfo)); |
1014 | | |
1015 | 1.86k | exit: |
1016 | 1.86k | return; |
1017 | 390 | } |
1018 | | |
1019 | | #if OPENTHREAD_CONFIG_TMF_NETDIAG_CLIENT_ENABLE |
1020 | | |
1021 | | //--------------------------------------------------------------------------------------------------------------------- |
1022 | | // Client |
1023 | | |
1024 | | Client::Client(Instance &aInstance) |
1025 | 21.3k | : InstanceLocator(aInstance) |
1026 | 21.3k | , mQueryId(Random::NonCrypto::GetUint16()) |
1027 | 21.3k | { |
1028 | 21.3k | } |
1029 | | |
1030 | | Error Client::SendDiagnosticGet(const Ip6::Address &aDestination, |
1031 | | const uint8_t aTlvTypes[], |
1032 | | uint8_t aCount, |
1033 | | GetCallback aCallback, |
1034 | | void *aContext) |
1035 | 0 | { |
1036 | 0 | Error error; |
1037 | |
|
1038 | 0 | if (aDestination.IsMulticast()) |
1039 | 0 | { |
1040 | 0 | error = SendCommand(kUriDiagnosticGetQuery, Message::kPriorityNormal, aDestination, aTlvTypes, aCount); |
1041 | 0 | } |
1042 | 0 | else |
1043 | 0 | { |
1044 | 0 | error = SendCommand(kUriDiagnosticGetRequest, Message::kPriorityNormal, aDestination, aTlvTypes, aCount, |
1045 | 0 | &HandleGetResponse, this); |
1046 | 0 | } |
1047 | |
|
1048 | 0 | SuccessOrExit(error); |
1049 | | |
1050 | 0 | mGetCallback.Set(aCallback, aContext); |
1051 | |
|
1052 | 0 | exit: |
1053 | 0 | return error; |
1054 | 0 | } |
1055 | | |
1056 | | Error Client::SendCommand(Uri aUri, |
1057 | | Message::Priority aPriority, |
1058 | | const Ip6::Address &aDestination, |
1059 | | const uint8_t aTlvTypes[], |
1060 | | uint8_t aCount, |
1061 | | Coap::ResponseHandler aHandler, |
1062 | | void *aContext) |
1063 | 0 | { |
1064 | 0 | Error error; |
1065 | 0 | Coap::Message *message = nullptr; |
1066 | 0 | Tmf::MessageInfo messageInfo(GetInstance()); |
1067 | |
|
1068 | 0 | switch (aUri) |
1069 | 0 | { |
1070 | 0 | case kUriDiagnosticGetQuery: |
1071 | 0 | message = Get<Tmf::Agent>().NewNonConfirmablePostMessage(aUri); |
1072 | 0 | break; |
1073 | | |
1074 | 0 | case kUriDiagnosticGetRequest: |
1075 | 0 | case kUriDiagnosticReset: |
1076 | 0 | message = Get<Tmf::Agent>().NewConfirmablePostMessage(aUri); |
1077 | 0 | break; |
1078 | | |
1079 | 0 | default: |
1080 | 0 | OT_ASSERT(false); |
1081 | 0 | } |
1082 | | |
1083 | 0 | VerifyOrExit(message != nullptr, error = kErrorNoBufs); |
1084 | 0 | IgnoreError(message->SetPriority(aPriority)); |
1085 | |
|
1086 | 0 | if (aCount > 0) |
1087 | 0 | { |
1088 | 0 | SuccessOrExit(error = Tlv::Append<TypeListTlv>(*message, aTlvTypes, aCount)); |
1089 | 0 | } |
1090 | | |
1091 | 0 | if (aUri == kUriDiagnosticGetQuery) |
1092 | 0 | { |
1093 | 0 | SuccessOrExit(error = Tlv::Append<QueryIdTlv>(*message, ++mQueryId)); |
1094 | 0 | } |
1095 | | |
1096 | 0 | Get<Server>().PrepareMessageInfoForDest(aDestination, messageInfo); |
1097 | |
|
1098 | 0 | SuccessOrExit(error = Get<Tmf::Agent>().SendMessage(*message, messageInfo, aHandler, aContext)); |
1099 | | |
1100 | 0 | LogInfo("Sent %s to %s", UriToString(aUri), aDestination.ToString().AsCString()); |
1101 | |
|
1102 | 0 | exit: |
1103 | 0 | FreeMessageOnError(message, error); |
1104 | 0 | return error; |
1105 | 0 | } |
1106 | | |
1107 | | void Client::HandleGetResponse(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo, otError aResult) |
1108 | 0 | { |
1109 | 0 | static_cast<Client *>(aContext)->HandleGetResponse(AsCoapMessagePtr(aMessage), AsCoreTypePtr(aMessageInfo), |
1110 | 0 | aResult); |
1111 | 0 | } |
1112 | | |
1113 | | void Client::HandleGetResponse(Coap::Message *aMessage, const Ip6::MessageInfo *aMessageInfo, Error aResult) |
1114 | 0 | { |
1115 | 0 | SuccessOrExit(aResult); |
1116 | 0 | VerifyOrExit(aMessage->GetCode() == Coap::kCodeChanged, aResult = kErrorFailed); |
1117 | | |
1118 | 0 | exit: |
1119 | 0 | mGetCallback.InvokeIfSet(aResult, aMessage, aMessageInfo); |
1120 | 0 | } |
1121 | | |
1122 | | template <> |
1123 | | void Client::HandleTmf<kUriDiagnosticGetAnswer>(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo) |
1124 | 398 | { |
1125 | 398 | VerifyOrExit(aMessage.IsConfirmablePostRequest()); |
1126 | | |
1127 | 195 | LogInfo("Received %s from %s", ot::UriToString<kUriDiagnosticGetAnswer>(), |
1128 | 195 | aMessageInfo.GetPeerAddr().ToString().AsCString()); |
1129 | | |
1130 | 195 | #if OPENTHREAD_CONFIG_MESH_DIAG_ENABLE && OPENTHREAD_FTD |
1131 | | // Let the `MeshDiag` process the message first. |
1132 | 195 | if (!Get<Utils::MeshDiag>().HandleDiagnosticGetAnswer(aMessage, aMessageInfo)) |
1133 | 195 | #endif |
1134 | 195 | { |
1135 | 195 | mGetCallback.InvokeIfSet(kErrorNone, &aMessage, &aMessageInfo); |
1136 | 195 | } |
1137 | | |
1138 | 195 | IgnoreError(Get<Tmf::Agent>().SendEmptyAck(aMessage, aMessageInfo)); |
1139 | | |
1140 | 398 | exit: |
1141 | 398 | return; |
1142 | 195 | } |
1143 | | |
1144 | | Error Client::SendDiagnosticReset(const Ip6::Address &aDestination, const uint8_t aTlvTypes[], uint8_t aCount) |
1145 | 0 | { |
1146 | 0 | return SendCommand(kUriDiagnosticReset, Message::kPriorityNormal, aDestination, aTlvTypes, aCount); |
1147 | 0 | } |
1148 | | |
1149 | | static void ParseRoute(const RouteTlv &aRouteTlv, otNetworkDiagRoute &aNetworkDiagRoute) |
1150 | 0 | { |
1151 | 0 | uint8_t routeCount = 0; |
1152 | |
|
1153 | 0 | for (uint8_t i = 0; i <= Mle::kMaxRouterId; ++i) |
1154 | 0 | { |
1155 | 0 | if (!aRouteTlv.IsRouterIdSet(i)) |
1156 | 0 | { |
1157 | 0 | continue; |
1158 | 0 | } |
1159 | 0 | aNetworkDiagRoute.mRouteData[routeCount].mRouterId = i; |
1160 | 0 | aNetworkDiagRoute.mRouteData[routeCount].mRouteCost = aRouteTlv.GetRouteCost(routeCount); |
1161 | 0 | aNetworkDiagRoute.mRouteData[routeCount].mLinkQualityIn = aRouteTlv.GetLinkQualityIn(routeCount); |
1162 | 0 | aNetworkDiagRoute.mRouteData[routeCount].mLinkQualityOut = aRouteTlv.GetLinkQualityOut(routeCount); |
1163 | 0 | ++routeCount; |
1164 | 0 | } |
1165 | 0 | aNetworkDiagRoute.mRouteCount = routeCount; |
1166 | 0 | aNetworkDiagRoute.mIdSequence = aRouteTlv.GetRouterIdSequence(); |
1167 | 0 | } |
1168 | | |
1169 | | static Error ParseEnhancedRoute(const Message &aMessage, uint16_t aOffset, otNetworkDiagEnhRoute &aNetworkDiagEnhRoute) |
1170 | 0 | { |
1171 | 0 | Error error; |
1172 | 0 | OffsetRange offsetRange; |
1173 | 0 | Tlv tlv; |
1174 | 0 | Mle::RouterIdSet routerIdSet; |
1175 | 0 | uint8_t index; |
1176 | |
|
1177 | 0 | SuccessOrExit(error = aMessage.Read(aOffset, tlv)); |
1178 | | |
1179 | 0 | VerifyOrExit(!tlv.IsExtended(), error = kErrorParse); |
1180 | 0 | VerifyOrExit(tlv.GetType() == Tlv::kEnhancedRoute, error = kErrorParse); |
1181 | | |
1182 | 0 | aOffset += sizeof(tlv); |
1183 | 0 | offsetRange.Init(aOffset, tlv.GetLength()); |
1184 | |
|
1185 | 0 | SuccessOrExit(error = aMessage.Read(offsetRange, routerIdSet)); |
1186 | 0 | offsetRange.AdvanceOffset(sizeof(routerIdSet)); |
1187 | |
|
1188 | 0 | index = 0; |
1189 | |
|
1190 | 0 | for (uint8_t routerId = 0; routerId <= Mle::kMaxRouterId; routerId++) |
1191 | 0 | { |
1192 | 0 | EnhancedRouteTlvEntry entry; |
1193 | |
|
1194 | 0 | if (!routerIdSet.Contains(routerId)) |
1195 | 0 | { |
1196 | 0 | continue; |
1197 | 0 | } |
1198 | | |
1199 | 0 | SuccessOrExit(error = aMessage.Read(offsetRange, entry)); |
1200 | 0 | offsetRange.AdvanceOffset(sizeof(entry)); |
1201 | |
|
1202 | 0 | aNetworkDiagEnhRoute.mRouteData[index].mRouterId = routerId; |
1203 | 0 | entry.Parse(aNetworkDiagEnhRoute.mRouteData[index]); |
1204 | |
|
1205 | 0 | index++; |
1206 | 0 | } |
1207 | | |
1208 | 0 | aNetworkDiagEnhRoute.mRouteCount = index; |
1209 | |
|
1210 | 0 | exit: |
1211 | 0 | return error; |
1212 | 0 | } |
1213 | | |
1214 | | static inline void ParseMacCounters(const MacCountersTlv &aMacCountersTlv, otNetworkDiagMacCounters &aMacCounters) |
1215 | 0 | { |
1216 | 0 | aMacCounters.mIfInUnknownProtos = aMacCountersTlv.GetIfInUnknownProtos(); |
1217 | 0 | aMacCounters.mIfInErrors = aMacCountersTlv.GetIfInErrors(); |
1218 | 0 | aMacCounters.mIfOutErrors = aMacCountersTlv.GetIfOutErrors(); |
1219 | 0 | aMacCounters.mIfInUcastPkts = aMacCountersTlv.GetIfInUcastPkts(); |
1220 | 0 | aMacCounters.mIfInBroadcastPkts = aMacCountersTlv.GetIfInBroadcastPkts(); |
1221 | 0 | aMacCounters.mIfInDiscards = aMacCountersTlv.GetIfInDiscards(); |
1222 | 0 | aMacCounters.mIfOutUcastPkts = aMacCountersTlv.GetIfOutUcastPkts(); |
1223 | 0 | aMacCounters.mIfOutBroadcastPkts = aMacCountersTlv.GetIfOutBroadcastPkts(); |
1224 | 0 | aMacCounters.mIfOutDiscards = aMacCountersTlv.GetIfOutDiscards(); |
1225 | 0 | } |
1226 | | |
1227 | | Error Client::GetNextDiagTlv(const Coap::Message &aMessage, Iterator &aIterator, TlvInfo &aTlvInfo) |
1228 | 0 | { |
1229 | 0 | Error error; |
1230 | 0 | uint16_t offset = (aIterator == 0) ? aMessage.GetOffset() : aIterator; |
1231 | |
|
1232 | 0 | while (offset < aMessage.GetLength()) |
1233 | 0 | { |
1234 | 0 | bool skipTlv = false; |
1235 | 0 | OffsetRange valueOffsetRange; |
1236 | 0 | union |
1237 | 0 | { |
1238 | 0 | Tlv tlv; |
1239 | 0 | ExtendedTlv extTlv; |
1240 | 0 | }; |
1241 | |
|
1242 | 0 | SuccessOrExit(error = aMessage.Read(offset, tlv)); |
1243 | | |
1244 | 0 | if (tlv.IsExtended()) |
1245 | 0 | { |
1246 | 0 | SuccessOrExit(error = aMessage.Read(offset, extTlv)); |
1247 | 0 | valueOffsetRange.Init(offset + sizeof(ExtendedTlv), extTlv.GetLength()); |
1248 | 0 | } |
1249 | 0 | else |
1250 | 0 | { |
1251 | 0 | valueOffsetRange.Init(offset + sizeof(Tlv), tlv.GetLength()); |
1252 | 0 | } |
1253 | | |
1254 | 0 | VerifyOrExit(offset + tlv.GetSize() <= aMessage.GetLength(), error = kErrorParse); |
1255 | | |
1256 | 0 | switch (tlv.GetType()) |
1257 | 0 | { |
1258 | 0 | case Tlv::kExtMacAddress: |
1259 | 0 | SuccessOrExit(error = |
1260 | 0 | Tlv::Read<ExtMacAddressTlv>(aMessage, offset, AsCoreType(&aTlvInfo.mData.mExtAddress))); |
1261 | 0 | break; |
1262 | | |
1263 | 0 | case Tlv::kAddress16: |
1264 | 0 | SuccessOrExit(error = Tlv::Read<Address16Tlv>(aMessage, offset, aTlvInfo.mData.mAddr16)); |
1265 | 0 | break; |
1266 | | |
1267 | 0 | case Tlv::kMode: |
1268 | 0 | { |
1269 | 0 | uint8_t mode; |
1270 | |
|
1271 | 0 | SuccessOrExit(error = Tlv::Read<ModeTlv>(aMessage, offset, mode)); |
1272 | 0 | Mle::DeviceMode(mode).Get(aTlvInfo.mData.mMode); |
1273 | 0 | break; |
1274 | 0 | } |
1275 | | |
1276 | 0 | case Tlv::kTimeout: |
1277 | 0 | SuccessOrExit(error = Tlv::Read<TimeoutTlv>(aMessage, offset, aTlvInfo.mData.mTimeout)); |
1278 | 0 | break; |
1279 | | |
1280 | 0 | case Tlv::kConnectivity: |
1281 | 0 | { |
1282 | 0 | ConnectivityTlv connectivityTlv; |
1283 | |
|
1284 | 0 | VerifyOrExit(!tlv.IsExtended(), error = kErrorParse); |
1285 | 0 | SuccessOrExit(error = aMessage.Read(offset, connectivityTlv)); |
1286 | 0 | VerifyOrExit(connectivityTlv.IsValid(), error = kErrorParse); |
1287 | 0 | connectivityTlv.GetConnectivity(aTlvInfo.mData.mConnectivity); |
1288 | 0 | break; |
1289 | 0 | } |
1290 | | |
1291 | 0 | case Tlv::kRoute: |
1292 | 0 | { |
1293 | 0 | RouteTlv routeTlv; |
1294 | 0 | uint16_t bytesToRead = static_cast<uint16_t>(Min(tlv.GetSize(), static_cast<uint32_t>(sizeof(routeTlv)))); |
1295 | |
|
1296 | 0 | VerifyOrExit(!tlv.IsExtended(), error = kErrorParse); |
1297 | 0 | SuccessOrExit(error = aMessage.Read(offset, &routeTlv, bytesToRead)); |
1298 | 0 | VerifyOrExit(routeTlv.IsValid(), error = kErrorParse); |
1299 | 0 | ParseRoute(routeTlv, aTlvInfo.mData.mRoute); |
1300 | 0 | break; |
1301 | 0 | } |
1302 | | |
1303 | 0 | case Tlv::kEnhancedRoute: |
1304 | 0 | SuccessOrExit(error = ParseEnhancedRoute(aMessage, offset, aTlvInfo.mData.mEnhRoute)); |
1305 | 0 | break; |
1306 | | |
1307 | 0 | case Tlv::kLeaderData: |
1308 | 0 | { |
1309 | 0 | LeaderDataTlv leaderDataTlv; |
1310 | |
|
1311 | 0 | VerifyOrExit(!tlv.IsExtended(), error = kErrorParse); |
1312 | 0 | SuccessOrExit(error = aMessage.Read(offset, leaderDataTlv)); |
1313 | 0 | VerifyOrExit(leaderDataTlv.IsValid(), error = kErrorParse); |
1314 | 0 | leaderDataTlv.Get(AsCoreType(&aTlvInfo.mData.mLeaderData)); |
1315 | 0 | break; |
1316 | 0 | } |
1317 | | |
1318 | 0 | case Tlv::kNetworkData: |
1319 | 0 | static_assert(sizeof(aTlvInfo.mData.mNetworkData.m8) >= NetworkData::NetworkData::kMaxSize, |
1320 | 0 | "NetworkData array in `otNetworkDiagTlv` is too small"); |
1321 | |
|
1322 | 0 | VerifyOrExit(valueOffsetRange.GetLength() <= NetworkData::NetworkData::kMaxSize, error = kErrorParse); |
1323 | 0 | aTlvInfo.mData.mNetworkData.mCount = static_cast<uint8_t>(valueOffsetRange.GetLength()); |
1324 | 0 | aMessage.ReadBytes(valueOffsetRange, aTlvInfo.mData.mNetworkData.m8); |
1325 | 0 | break; |
1326 | | |
1327 | 0 | case Tlv::kIp6AddressList: |
1328 | 0 | { |
1329 | 0 | uint16_t addrListLength = GetArrayLength(aTlvInfo.mData.mIp6AddrList.mList); |
1330 | 0 | Ip6::Address *addrEntry = AsCoreTypePtr(&aTlvInfo.mData.mIp6AddrList.mList[0]); |
1331 | 0 | uint8_t &addrCount = aTlvInfo.mData.mIp6AddrList.mCount; |
1332 | |
|
1333 | 0 | VerifyOrExit((valueOffsetRange.GetLength() % Ip6::Address::kSize) == 0, error = kErrorParse); |
1334 | | |
1335 | | // `TlvInfo` has a fixed array for IPv6 addresses. If there |
1336 | | // are more addresses in the message, we read and return as |
1337 | | // many as can fit in array and ignore the rest. |
1338 | | |
1339 | 0 | addrCount = 0; |
1340 | |
|
1341 | 0 | while (!valueOffsetRange.IsEmpty() && (addrCount < addrListLength)) |
1342 | 0 | { |
1343 | 0 | SuccessOrExit(error = aMessage.Read(valueOffsetRange, *addrEntry)); |
1344 | 0 | addrCount++; |
1345 | 0 | addrEntry++; |
1346 | 0 | valueOffsetRange.AdvanceOffset(Ip6::Address::kSize); |
1347 | 0 | } |
1348 | | |
1349 | 0 | break; |
1350 | 0 | } |
1351 | | |
1352 | 0 | case Tlv::kMacCounters: |
1353 | 0 | { |
1354 | 0 | MacCountersTlv macCountersTlv; |
1355 | |
|
1356 | 0 | SuccessOrExit(error = aMessage.Read(offset, macCountersTlv)); |
1357 | 0 | VerifyOrExit(macCountersTlv.IsValid(), error = kErrorParse); |
1358 | 0 | ParseMacCounters(macCountersTlv, aTlvInfo.mData.mMacCounters); |
1359 | 0 | break; |
1360 | 0 | } |
1361 | | |
1362 | 0 | case Tlv::kMleCounters: |
1363 | 0 | { |
1364 | 0 | MleCountersTlv mleCoutersTlv; |
1365 | |
|
1366 | 0 | SuccessOrExit(error = aMessage.Read(offset, mleCoutersTlv)); |
1367 | 0 | VerifyOrExit(mleCoutersTlv.IsValid(), error = kErrorParse); |
1368 | 0 | mleCoutersTlv.Read(aTlvInfo.mData.mMleCounters); |
1369 | 0 | break; |
1370 | 0 | } |
1371 | | |
1372 | 0 | case Tlv::kBatteryLevel: |
1373 | 0 | SuccessOrExit(error = Tlv::Read<BatteryLevelTlv>(aMessage, offset, aTlvInfo.mData.mBatteryLevel)); |
1374 | 0 | break; |
1375 | | |
1376 | 0 | case Tlv::kSupplyVoltage: |
1377 | 0 | SuccessOrExit(error = Tlv::Read<SupplyVoltageTlv>(aMessage, offset, aTlvInfo.mData.mSupplyVoltage)); |
1378 | 0 | break; |
1379 | | |
1380 | 0 | case Tlv::kChildTable: |
1381 | 0 | { |
1382 | 0 | uint16_t childInfoLength = GetArrayLength(aTlvInfo.mData.mChildTable.mTable); |
1383 | 0 | ChildInfo *childInfo = &aTlvInfo.mData.mChildTable.mTable[0]; |
1384 | 0 | uint8_t &childCount = aTlvInfo.mData.mChildTable.mCount; |
1385 | |
|
1386 | 0 | VerifyOrExit((valueOffsetRange.GetLength() % sizeof(ChildTableEntry)) == 0, error = kErrorParse); |
1387 | | |
1388 | | // `TlvInfo` has a fixed array Child Table entries. If there |
1389 | | // are more entries in the message, we read and return as |
1390 | | // many as can fit in array and ignore the rest. |
1391 | | |
1392 | 0 | childCount = 0; |
1393 | |
|
1394 | 0 | while (!valueOffsetRange.IsEmpty() && (childCount < childInfoLength)) |
1395 | 0 | { |
1396 | 0 | ChildTableEntry entry; |
1397 | |
|
1398 | 0 | SuccessOrExit(error = aMessage.Read(valueOffsetRange, entry)); |
1399 | | |
1400 | 0 | childInfo->mTimeout = entry.GetTimeout(); |
1401 | 0 | childInfo->mLinkQuality = entry.GetLinkQuality(); |
1402 | 0 | childInfo->mChildId = entry.GetChildId(); |
1403 | 0 | entry.GetMode().Get(childInfo->mMode); |
1404 | |
|
1405 | 0 | childCount++; |
1406 | 0 | childInfo++; |
1407 | 0 | valueOffsetRange.AdvanceOffset(sizeof(ChildTableEntry)); |
1408 | 0 | } |
1409 | | |
1410 | 0 | break; |
1411 | 0 | } |
1412 | | |
1413 | 0 | case Tlv::kChannelPages: |
1414 | 0 | aTlvInfo.mData.mChannelPages.mCount = static_cast<uint8_t>( |
1415 | 0 | Min(valueOffsetRange.GetLength(), GetArrayLength(aTlvInfo.mData.mChannelPages.m8))); |
1416 | 0 | aMessage.ReadBytes(valueOffsetRange.GetOffset(), aTlvInfo.mData.mChannelPages.m8, |
1417 | 0 | aTlvInfo.mData.mChannelPages.mCount); |
1418 | 0 | break; |
1419 | | |
1420 | 0 | case Tlv::kMaxChildTimeout: |
1421 | 0 | SuccessOrExit(error = Tlv::Read<MaxChildTimeoutTlv>(aMessage, offset, aTlvInfo.mData.mMaxChildTimeout)); |
1422 | 0 | break; |
1423 | | |
1424 | 0 | case Tlv::kEui64: |
1425 | 0 | SuccessOrExit(error = Tlv::Read<Eui64Tlv>(aMessage, offset, AsCoreType(&aTlvInfo.mData.mEui64))); |
1426 | 0 | break; |
1427 | | |
1428 | 0 | case Tlv::kVersion: |
1429 | 0 | SuccessOrExit(error = Tlv::Read<VersionTlv>(aMessage, offset, aTlvInfo.mData.mVersion)); |
1430 | 0 | break; |
1431 | | |
1432 | 0 | case Tlv::kVendorName: |
1433 | 0 | SuccessOrExit(error = Tlv::Read<VendorNameTlv>(aMessage, offset, aTlvInfo.mData.mVendorName)); |
1434 | 0 | break; |
1435 | | |
1436 | 0 | case Tlv::kVendorModel: |
1437 | 0 | SuccessOrExit(error = Tlv::Read<VendorModelTlv>(aMessage, offset, aTlvInfo.mData.mVendorModel)); |
1438 | 0 | break; |
1439 | | |
1440 | 0 | case Tlv::kVendorSwVersion: |
1441 | 0 | SuccessOrExit(error = Tlv::Read<VendorSwVersionTlv>(aMessage, offset, aTlvInfo.mData.mVendorSwVersion)); |
1442 | 0 | break; |
1443 | | |
1444 | 0 | case Tlv::kVendorAppUrl: |
1445 | 0 | SuccessOrExit(error = Tlv::Read<VendorAppUrlTlv>(aMessage, offset, aTlvInfo.mData.mVendorAppUrl)); |
1446 | 0 | break; |
1447 | | |
1448 | 0 | case Tlv::kThreadStackVersion: |
1449 | 0 | SuccessOrExit(error = |
1450 | 0 | Tlv::Read<ThreadStackVersionTlv>(aMessage, offset, aTlvInfo.mData.mThreadStackVersion)); |
1451 | 0 | break; |
1452 | | |
1453 | 0 | case Tlv::kNonPreferredChannels: |
1454 | 0 | SuccessOrExit(error = MeshCoP::ChannelMaskTlv::ParseValue(aMessage, valueOffsetRange, |
1455 | 0 | aTlvInfo.mData.mNonPreferredChannels)); |
1456 | 0 | break; |
1457 | | |
1458 | 0 | default: |
1459 | | // Skip unrecognized TLVs. |
1460 | 0 | skipTlv = true; |
1461 | 0 | break; |
1462 | 0 | } |
1463 | | |
1464 | 0 | offset += tlv.GetSize(); |
1465 | |
|
1466 | 0 | if (!skipTlv) |
1467 | 0 | { |
1468 | | // Exit if a TLV is recognized and parsed successfully. |
1469 | 0 | aTlvInfo.mType = tlv.GetType(); |
1470 | 0 | aIterator = offset; |
1471 | 0 | error = kErrorNone; |
1472 | 0 | ExitNow(); |
1473 | 0 | } |
1474 | 0 | } |
1475 | | |
1476 | 0 | error = kErrorNotFound; |
1477 | |
|
1478 | 0 | exit: |
1479 | 0 | return error; |
1480 | 0 | } |
1481 | | |
1482 | | #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO) |
1483 | | |
1484 | | const char *Client::UriToString(Uri aUri) |
1485 | | { |
1486 | | const char *str = ""; |
1487 | | |
1488 | | switch (aUri) |
1489 | | { |
1490 | | case kUriDiagnosticGetQuery: |
1491 | | str = ot::UriToString<kUriDiagnosticGetQuery>(); |
1492 | | break; |
1493 | | case kUriDiagnosticGetRequest: |
1494 | | str = ot::UriToString<kUriDiagnosticGetRequest>(); |
1495 | | break; |
1496 | | case kUriDiagnosticReset: |
1497 | | str = ot::UriToString<kUriDiagnosticReset>(); |
1498 | | break; |
1499 | | default: |
1500 | | break; |
1501 | | } |
1502 | | |
1503 | | return str; |
1504 | | } |
1505 | | |
1506 | | #endif // #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO) |
1507 | | |
1508 | | #endif // OPENTHREAD_CONFIG_TMF_NETDIAG_CLIENT_ENABLE |
1509 | | |
1510 | | } // namespace NetworkDiagnostic |
1511 | | |
1512 | | } // namespace ot |