/src/openthread/src/cli/cli_dataset.cpp
Line | Count | Source |
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 the CLI interpreter. |
32 | | */ |
33 | | |
34 | | #include "cli_dataset.hpp" |
35 | | |
36 | | #include <stdio.h> |
37 | | #include <stdlib.h> |
38 | | |
39 | | #include <openthread/dataset.h> |
40 | | #include <openthread/dataset_ftd.h> |
41 | | #include <openthread/dataset_updater.h> |
42 | | |
43 | | #include "cli/cli.hpp" |
44 | | |
45 | | namespace ot { |
46 | | namespace Cli { |
47 | | |
48 | | otOperationalDatasetTlvs Dataset::sDatasetTlvs; |
49 | | |
50 | | const Dataset::ComponentMapper *Dataset::LookupMapper(const char *aName) const |
51 | 951 | { |
52 | 951 | static constexpr ComponentMapper kMappers[] = { |
53 | 951 | { |
54 | 951 | "activetimestamp", |
55 | 951 | &Components::mIsActiveTimestampPresent, |
56 | 951 | &Dataset::OutputActiveTimestamp, |
57 | 951 | &Dataset::ParseActiveTimestamp, |
58 | 951 | }, |
59 | 951 | { |
60 | 951 | "channel", |
61 | 951 | &Components::mIsChannelPresent, |
62 | 951 | &Dataset::OutputChannel, |
63 | 951 | &Dataset::ParseChannel, |
64 | 951 | }, |
65 | 951 | { |
66 | 951 | "channelmask", |
67 | 951 | &Components::mIsChannelMaskPresent, |
68 | 951 | &Dataset::OutputChannelMask, |
69 | 951 | &Dataset::ParseChannelMask, |
70 | 951 | }, |
71 | 951 | { |
72 | 951 | "delay", |
73 | 951 | &Components::mIsDelayPresent, |
74 | 951 | &Dataset::OutputDelay, |
75 | 951 | &Dataset::ParseDelay, |
76 | 951 | }, |
77 | 951 | { |
78 | 951 | "delaytimer", // Alias for "delay "to ensure backward compatibility for "mgmtsetcommand" command |
79 | 951 | &Components::mIsDelayPresent, |
80 | 951 | &Dataset::OutputDelay, |
81 | 951 | &Dataset::ParseDelay, |
82 | 951 | }, |
83 | 951 | { |
84 | 951 | "extpanid", |
85 | 951 | &Components::mIsExtendedPanIdPresent, |
86 | 951 | &Dataset::OutputExtendedPanId, |
87 | 951 | &Dataset::ParseExtendedPanId, |
88 | 951 | }, |
89 | 951 | { |
90 | 951 | "localprefix", // Alias for "meshlocalprefix" to ensure backward compatibility in "mgmtsetcommand" command |
91 | 951 | &Components::mIsMeshLocalPrefixPresent, |
92 | 951 | &Dataset::OutputMeshLocalPrefix, |
93 | 951 | &Dataset::ParseMeshLocalPrefix, |
94 | 951 | }, |
95 | 951 | { |
96 | 951 | "meshlocalprefix", |
97 | 951 | &Components::mIsMeshLocalPrefixPresent, |
98 | 951 | &Dataset::OutputMeshLocalPrefix, |
99 | 951 | &Dataset::ParseMeshLocalPrefix, |
100 | 951 | }, |
101 | 951 | { |
102 | 951 | "networkkey", |
103 | 951 | &Components::mIsNetworkKeyPresent, |
104 | 951 | &Dataset::OutputNetworkKey, |
105 | 951 | &Dataset::ParseNetworkKey, |
106 | 951 | }, |
107 | 951 | { |
108 | 951 | "networkname", |
109 | 951 | &Components::mIsNetworkNamePresent, |
110 | 951 | &Dataset::OutputNetworkName, |
111 | 951 | &Dataset::ParseNetworkName, |
112 | 951 | }, |
113 | 951 | { |
114 | 951 | "panid", |
115 | 951 | &Components::mIsPanIdPresent, |
116 | 951 | &Dataset::OutputPanId, |
117 | 951 | &Dataset::ParsePanId, |
118 | 951 | }, |
119 | 951 | { |
120 | 951 | "pendingtimestamp", |
121 | 951 | &Components::mIsPendingTimestampPresent, |
122 | 951 | &Dataset::OutputPendingTimestamp, |
123 | 951 | &Dataset::ParsePendingTimestamp, |
124 | 951 | }, |
125 | 951 | { |
126 | 951 | "pskc", |
127 | 951 | &Components::mIsPskcPresent, |
128 | 951 | &Dataset::OutputPskc, |
129 | 951 | &Dataset::ParsePskc, |
130 | 951 | }, |
131 | 951 | { |
132 | 951 | "securitypolicy", |
133 | 951 | &Components::mIsSecurityPolicyPresent, |
134 | 951 | &Dataset::OutputSecurityPolicy, |
135 | 951 | &Dataset::ParseSecurityPolicy, |
136 | 951 | }, |
137 | 951 | { |
138 | 951 | "wakeupchannel", |
139 | 951 | &Components::mIsWakeupChannelPresent, |
140 | 951 | &Dataset::OutputWakeupChannel, |
141 | 951 | &Dataset::ParseWakeupChannel, |
142 | 951 | }, |
143 | 951 | }; |
144 | | |
145 | 951 | static_assert(BinarySearch::IsSorted(kMappers), "kMappers is not sorted"); |
146 | | |
147 | 951 | return BinarySearch::Find(aName, kMappers); |
148 | 951 | } |
149 | | |
150 | | //--------------------------------------------------------------------------------------------------------------------- |
151 | | |
152 | | /** |
153 | | * @cli dataset activetimestamp (get, set) |
154 | | * @code |
155 | | * dataset activetimestamp |
156 | | * 123456789 |
157 | | * Done |
158 | | * @endcode |
159 | | * @code |
160 | | * dataset activetimestamp 123456789 |
161 | | * Done |
162 | | * @endcode |
163 | | * @cparam dataset activetimestamp [@ca{timestamp}] |
164 | | * Pass the optional `timestamp` argument to set the active timestamp. |
165 | | * @par |
166 | | * Gets or sets #otOperationalDataset::mActiveTimestamp. |
167 | | */ |
168 | | void Dataset::OutputActiveTimestamp(const otOperationalDataset &aDataset) |
169 | 2 | { |
170 | 2 | OutputUint64Line(aDataset.mActiveTimestamp.mSeconds); |
171 | 2 | } |
172 | | |
173 | | /** |
174 | | * @cli dataset channel (get,set) |
175 | | * @code |
176 | | * dataset channel |
177 | | * 12 |
178 | | * Done |
179 | | * @endcode |
180 | | * @code |
181 | | * dataset channel 12 |
182 | | * Done |
183 | | * @endcode |
184 | | * @cparam dataset channel [@ca{channel-num}] |
185 | | * Use the optional `channel-num` argument to set the channel. |
186 | | * @par |
187 | | * Gets or sets #otOperationalDataset::mChannel. |
188 | | */ |
189 | 2 | void Dataset::OutputChannel(const otOperationalDataset &aDataset) { OutputLine("%u", aDataset.mChannel); } |
190 | | |
191 | | /** |
192 | | * @cli dataset wakeupchannel (get,set) |
193 | | * @code |
194 | | * dataset wakeupchannel |
195 | | * 13 |
196 | | * Done |
197 | | * @endcode |
198 | | * @code |
199 | | * dataset wakeupchannel 13 |
200 | | * Done |
201 | | * @endcode |
202 | | * @cparam dataset wakeupchannel [@ca{channel-num}] |
203 | | * Use the optional `channel-num` argument to set the wake-up channel. |
204 | | * @par |
205 | | * Gets or sets #otOperationalDataset::mWakeupChannel. |
206 | | */ |
207 | 2 | void Dataset::OutputWakeupChannel(const otOperationalDataset &aDataset) { OutputLine("%u", aDataset.mWakeupChannel); } |
208 | | |
209 | | /** |
210 | | * @cli dataset channelmask (get,set) |
211 | | * @code |
212 | | * dataset channelmask |
213 | | * 0x07fff800 |
214 | | * Done |
215 | | * @endcode |
216 | | * @code |
217 | | * dataset channelmask 0x07fff800 |
218 | | * Done |
219 | | * @endcode |
220 | | * @cparam dataset channelmask [@ca{channel-mask}] |
221 | | * Use the optional `channel-mask` argument to set the channel mask. |
222 | | * @par |
223 | | * Gets or sets #otOperationalDataset::mChannelMask |
224 | | */ |
225 | | void Dataset::OutputChannelMask(const otOperationalDataset &aDataset) |
226 | 2 | { |
227 | 2 | OutputLine("0x%08lx", ToUlong(aDataset.mChannelMask)); |
228 | 2 | } |
229 | | |
230 | | /** |
231 | | * @cli dataset delay (get,set) |
232 | | * @code |
233 | | * dataset delay |
234 | | * 1000 |
235 | | * Done |
236 | | * @endcode |
237 | | * @code |
238 | | * dataset delay 1000 |
239 | | * Done |
240 | | * @endcode |
241 | | * @cparam dataset delay [@ca{delay}] |
242 | | * Use the optional `delay` argument to set the delay timer value. |
243 | | * @par |
244 | | * Gets or sets #otOperationalDataset::mDelay. |
245 | | * @sa otDatasetSetDelayTimerMinimal |
246 | | */ |
247 | 1 | void Dataset::OutputDelay(const otOperationalDataset &aDataset) { OutputLine("%lu", ToUlong(aDataset.mDelay)); } |
248 | | |
249 | | /** |
250 | | * @cli dataset extpanid (get,set) |
251 | | * @code |
252 | | * dataset extpanid |
253 | | * 000db80123456789 |
254 | | * Done |
255 | | * @endcode |
256 | | * @code |
257 | | * dataset extpanid 000db80123456789 |
258 | | * Done |
259 | | * @endcode |
260 | | * @cparam dataset extpanid [@ca{extpanid}] |
261 | | * Use the optional `extpanid` argument to set the Extended Personal Area Network ID. |
262 | | * @par |
263 | | * Gets or sets #otOperationalDataset::mExtendedPanId. |
264 | | * @note The commissioning credential in the dataset buffer becomes stale after changing |
265 | | * this value. Use `dataset pskc` to reset. |
266 | | * @csa{dataset pskc (get,set)} |
267 | | */ |
268 | 2 | void Dataset::OutputExtendedPanId(const otOperationalDataset &aDataset) { OutputBytesLine(aDataset.mExtendedPanId.m8); } |
269 | | |
270 | | /** |
271 | | * @cli dataset meshlocalprefix (get,set) |
272 | | * @code |
273 | | * dataset meshlocalprefix |
274 | | * fd00:db8:0:0::/64 |
275 | | * Done |
276 | | * @endcode |
277 | | * @code |
278 | | * dataset meshlocalprefix fd00:db8:0:0:: |
279 | | * Done |
280 | | * @endcode |
281 | | * @cparam dataset meshlocalprefix [@ca{meshlocalprefix}] |
282 | | * Use the optional `meshlocalprefix` argument to set the Mesh-Local Prefix. |
283 | | * @par |
284 | | * Gets or sets #otOperationalDataset::mMeshLocalPrefix. |
285 | | */ |
286 | | void Dataset::OutputMeshLocalPrefix(const otOperationalDataset &aDataset) |
287 | 2 | { |
288 | 2 | OutputIp6PrefixLine(aDataset.mMeshLocalPrefix); |
289 | 2 | } |
290 | | |
291 | | /** |
292 | | * @cli dataset networkkey (get,set) |
293 | | * @code |
294 | | * dataset networkkey |
295 | | * 00112233445566778899aabbccddeeff |
296 | | * Done |
297 | | * @endcode |
298 | | * @code |
299 | | * dataset networkkey 00112233445566778899aabbccddeeff |
300 | | * Done |
301 | | * @endcode |
302 | | * @cparam dataset networkkey [@ca{key}] |
303 | | * Use the optional `key` argument to set the Network Key. |
304 | | * @par |
305 | | * Gets or sets #otOperationalDataset::mNetworkKey. |
306 | | */ |
307 | 2 | void Dataset::OutputNetworkKey(const otOperationalDataset &aDataset) { OutputBytesLine(aDataset.mNetworkKey.m8); } |
308 | | |
309 | | /** |
310 | | * @cli dataset networkname (get,set) |
311 | | * @code |
312 | | * dataset networkname |
313 | | * OpenThread |
314 | | * Done |
315 | | * @endcode |
316 | | * @code |
317 | | * dataset networkname OpenThread |
318 | | * Done |
319 | | * @endcode |
320 | | * @cparam dataset networkname [@ca{name}] |
321 | | * Use the optional `name` argument to set the Network Name. |
322 | | * @par |
323 | | * Gets or sets #otOperationalDataset::mNetworkName. |
324 | | * @note The Commissioning Credential in the dataset buffer becomes stale after changing this value. |
325 | | * Use `dataset pskc` to reset. |
326 | | * @csa{dataset pskc (get,set)} |
327 | | */ |
328 | 2 | void Dataset::OutputNetworkName(const otOperationalDataset &aDataset) { OutputLine("%s", aDataset.mNetworkName.m8); } |
329 | | |
330 | | /** |
331 | | * @cli dataset panid (get,set) |
332 | | * @code |
333 | | * dataset panid |
334 | | * 0x1234 |
335 | | * Done |
336 | | * @endcode |
337 | | * @code |
338 | | * dataset panid 0x1234 |
339 | | * Done |
340 | | * @endcode |
341 | | * @cparam dataset panid [@ca{panid}] |
342 | | * Use the optional `panid` argument to set the PAN ID. |
343 | | * @par |
344 | | * Gets or sets #otOperationalDataset::mPanId. |
345 | | */ |
346 | 4 | void Dataset::OutputPanId(const otOperationalDataset &aDataset) { OutputLine("0x%04x", aDataset.mPanId); } |
347 | | |
348 | | /** |
349 | | * @cli dataset pendingtimestamp (get,set) |
350 | | * @code |
351 | | * dataset pendingtimestamp |
352 | | * 123456789 |
353 | | * Done |
354 | | * @endcode |
355 | | * @code |
356 | | * dataset pendingtimestamp 123456789 |
357 | | * Done |
358 | | * @endcode |
359 | | * @cparam dataset pendingtimestamp [@ca{timestamp}] |
360 | | * Use the optional `timestamp` argument to set the pending timestamp seconds. |
361 | | * @par |
362 | | * Gets or sets #otOperationalDataset::mPendingTimestamp. |
363 | | */ |
364 | | void Dataset::OutputPendingTimestamp(const otOperationalDataset &aDataset) |
365 | 0 | { |
366 | 0 | OutputUint64Line(aDataset.mPendingTimestamp.mSeconds); |
367 | 0 | } |
368 | | |
369 | | /** |
370 | | * @cli dataset pskc (get,set) |
371 | | * @code |
372 | | * dataset pskc |
373 | | * 67c0c203aa0b042bfb5381c47aef4d9e |
374 | | * Done |
375 | | * @endcode |
376 | | * @code |
377 | | * dataset pskc -p 123456 |
378 | | * Done |
379 | | * @endcode |
380 | | * @code |
381 | | * dataset pskc 67c0c203aa0b042bfb5381c47aef4d9e |
382 | | * Done |
383 | | * @endcode |
384 | | * @cparam dataset pskc [@ca{-p} @ca{passphrase}] | [@ca{key}] |
385 | | * For FTD only, use `-p` with the `passphrase` argument. `-p` generates a pskc from |
386 | | * the UTF-8 encoded `passphrase` that you provide, together with |
387 | | * the network name and extended PAN ID. If set, `-p` uses the dataset buffer; |
388 | | * otherwise, it uses the current stack. |
389 | | * Alternatively, you can set pskc as `key` (hex format). |
390 | | * @par |
391 | | * Gets or sets #otOperationalDataset::mPskc. |
392 | | */ |
393 | 2 | void Dataset::OutputPskc(const otOperationalDataset &aDataset) { OutputBytesLine(aDataset.mPskc.m8); } |
394 | | |
395 | | /** |
396 | | * @cli dataset securitypolicy (get,set) |
397 | | * @code |
398 | | * dataset securitypolicy |
399 | | * 672 onrc |
400 | | * Done |
401 | | * @endcode |
402 | | * @code |
403 | | * dataset securitypolicy 672 onrc |
404 | | * Done |
405 | | * @endcode |
406 | | * @cparam dataset securitypolicy [@ca{rotationtime} [@ca{onrcCepR}]] |
407 | | * * Use `rotationtime` for `thrKeyRotation`, in units of hours. |
408 | | * * Security Policy commands use the `onrcCepR` argument mappings to get and set |
409 | | * #otSecurityPolicy members, for example `o` represents |
410 | | * #otSecurityPolicy::mObtainNetworkKeyEnabled. |
411 | | * @moreinfo{@dataset}. |
412 | | * @par |
413 | | * Gets or sets the %Dataset security policy. |
414 | | */ |
415 | | void Dataset::OutputSecurityPolicy(const otOperationalDataset &aDataset) |
416 | 2 | { |
417 | 2 | OutputSecurityPolicy(aDataset.mSecurityPolicy); |
418 | 2 | } |
419 | | |
420 | | //--------------------------------------------------------------------------------------------------------------------- |
421 | | |
422 | | otError Dataset::ParseActiveTimestamp(Arg *&aArgs, otOperationalDataset &aDataset) |
423 | 156 | { |
424 | 156 | otError error; |
425 | | |
426 | 156 | SuccessOrExit(error = aArgs++->ParseAsUint64(aDataset.mActiveTimestamp.mSeconds)); |
427 | 48 | aDataset.mActiveTimestamp.mTicks = 0; |
428 | 48 | aDataset.mActiveTimestamp.mAuthoritative = false; |
429 | | |
430 | 156 | exit: |
431 | 156 | return error; |
432 | 48 | } |
433 | | |
434 | | otError Dataset::ParseChannel(Arg *&aArgs, otOperationalDataset &aDataset) |
435 | 2 | { |
436 | 2 | return aArgs++->ParseAsUint16(aDataset.mChannel); |
437 | 2 | } |
438 | | |
439 | | otError Dataset::ParseWakeupChannel(Arg *&aArgs, otOperationalDataset &aDataset) |
440 | 1 | { |
441 | 1 | return aArgs++->ParseAsUint16(aDataset.mWakeupChannel); |
442 | 1 | } |
443 | | |
444 | | otError Dataset::ParseChannelMask(Arg *&aArgs, otOperationalDataset &aDataset) |
445 | 3 | { |
446 | 3 | return aArgs++->ParseAsUint32(aDataset.mChannelMask); |
447 | 3 | } |
448 | | |
449 | | otError Dataset::ParseDelay(Arg *&aArgs, otOperationalDataset &aDataset) |
450 | 3 | { |
451 | 3 | return aArgs++->ParseAsUint32(aDataset.mDelay); |
452 | 3 | } |
453 | | |
454 | | otError Dataset::ParseExtendedPanId(Arg *&aArgs, otOperationalDataset &aDataset) |
455 | 3 | { |
456 | 3 | return aArgs++->ParseAsHexString(aDataset.mExtendedPanId.m8); |
457 | 3 | } |
458 | | |
459 | | otError Dataset::ParseMeshLocalPrefix(Arg *&aArgs, otOperationalDataset &aDataset) |
460 | 3 | { |
461 | 3 | otError error; |
462 | 3 | otIp6Address prefix; |
463 | | |
464 | 3 | SuccessOrExit(error = aArgs++->ParseAsIp6Address(prefix)); |
465 | | |
466 | 1 | memcpy(aDataset.mMeshLocalPrefix.m8, prefix.mFields.m8, sizeof(aDataset.mMeshLocalPrefix.m8)); |
467 | | |
468 | 3 | exit: |
469 | 3 | return error; |
470 | 1 | } |
471 | | |
472 | | otError Dataset::ParseNetworkKey(Arg *&aArgs, otOperationalDataset &aDataset) |
473 | 2 | { |
474 | 2 | return aArgs++->ParseAsHexString(aDataset.mNetworkKey.m8); |
475 | 2 | } |
476 | | |
477 | | otError Dataset::ParseNetworkName(Arg *&aArgs, otOperationalDataset &aDataset) |
478 | 282 | { |
479 | 282 | otError error = OT_ERROR_NONE; |
480 | | |
481 | 282 | VerifyOrExit(!aArgs->IsEmpty(), error = OT_ERROR_INVALID_ARGS); |
482 | 280 | error = otNetworkNameFromString(&aDataset.mNetworkName, aArgs++->GetCString()); |
483 | | |
484 | 282 | exit: |
485 | 282 | return error; |
486 | 280 | } |
487 | | |
488 | | otError Dataset::ParsePanId(Arg *&aArgs, otOperationalDataset &aDataset) |
489 | 2 | { |
490 | 2 | return aArgs++->ParseAsUint16(aDataset.mPanId); |
491 | 2 | } |
492 | | |
493 | | otError Dataset::ParsePendingTimestamp(Arg *&aArgs, otOperationalDataset &aDataset) |
494 | 3 | { |
495 | 3 | otError error; |
496 | | |
497 | 3 | SuccessOrExit(error = aArgs++->ParseAsUint64(aDataset.mPendingTimestamp.mSeconds)); |
498 | 2 | aDataset.mPendingTimestamp.mTicks = 0; |
499 | 2 | aDataset.mPendingTimestamp.mAuthoritative = false; |
500 | | |
501 | 3 | exit: |
502 | 3 | return error; |
503 | 2 | } |
504 | | |
505 | | otError Dataset::ParsePskc(Arg *&aArgs, otOperationalDataset &aDataset) |
506 | 3 | { |
507 | 3 | otError error; |
508 | | |
509 | 3 | #if OPENTHREAD_FTD |
510 | 3 | if (*aArgs == "-p") |
511 | 0 | { |
512 | 0 | aArgs++; |
513 | 0 | VerifyOrExit(!aArgs->IsEmpty(), error = OT_ERROR_INVALID_ARGS); |
514 | | |
515 | 0 | SuccessOrExit(error = otDatasetGeneratePskc( |
516 | 0 | aArgs->GetCString(), |
517 | 0 | (aDataset.mComponents.mIsNetworkNamePresent |
518 | 0 | ? &aDataset.mNetworkName |
519 | 0 | : reinterpret_cast<const otNetworkName *>(otThreadGetNetworkName(GetInstancePtr()))), |
520 | 0 | (aDataset.mComponents.mIsExtendedPanIdPresent ? &aDataset.mExtendedPanId |
521 | 0 | : otThreadGetExtendedPanId(GetInstancePtr())), |
522 | 0 | &aDataset.mPskc)); |
523 | 0 | aArgs++; |
524 | 0 | } |
525 | 3 | else |
526 | 3 | #endif |
527 | 3 | { |
528 | 3 | ExitNow(error = aArgs++->ParseAsHexString(aDataset.mPskc.m8)); |
529 | 3 | } |
530 | | |
531 | 3 | exit: |
532 | 3 | return error; |
533 | 3 | } |
534 | | |
535 | | otError Dataset::ParseSecurityPolicy(Arg *&aArgs, otOperationalDataset &aDataset) |
536 | 71 | { |
537 | 71 | return ParseSecurityPolicy(aDataset.mSecurityPolicy, aArgs); |
538 | 71 | } |
539 | | |
540 | | otError Dataset::ParseTlvs(Arg &aArg, otOperationalDatasetTlvs &aDatasetTlvs) |
541 | 183 | { |
542 | 183 | otError error; |
543 | 183 | uint16_t length; |
544 | | |
545 | 183 | length = sizeof(aDatasetTlvs.mTlvs); |
546 | 183 | SuccessOrExit(error = aArg.ParseAsHexString(length, aDatasetTlvs.mTlvs)); |
547 | 178 | aDatasetTlvs.mLength = static_cast<uint8_t>(length); |
548 | | |
549 | 183 | exit: |
550 | 183 | return error; |
551 | 178 | } |
552 | | |
553 | | //--------------------------------------------------------------------------------------------------------------------- |
554 | | |
555 | | otError Dataset::ProcessCommand(const ComponentMapper &aMapper, Arg aArgs[]) |
556 | 305 | { |
557 | 305 | otError error = OT_ERROR_NONE; |
558 | 305 | otOperationalDataset dataset; |
559 | | |
560 | 305 | if (aArgs[0].IsEmpty()) |
561 | 7 | { |
562 | 7 | SuccessOrExit(error = otDatasetParseTlvs(&sDatasetTlvs, &dataset)); |
563 | | |
564 | 4 | if (dataset.mComponents.*aMapper.mIsPresentPtr) |
565 | 1 | { |
566 | 1 | (this->*aMapper.mOutput)(dataset); |
567 | 1 | } |
568 | 4 | } |
569 | 298 | else |
570 | 298 | { |
571 | 298 | ClearAllBytes(dataset); |
572 | 298 | SuccessOrExit(error = (this->*aMapper.mParse)(aArgs, dataset)); |
573 | 131 | dataset.mComponents.*aMapper.mIsPresentPtr = true; |
574 | 131 | SuccessOrExit(error = otDatasetUpdateTlvs(&dataset, &sDatasetTlvs)); |
575 | 131 | } |
576 | | |
577 | 305 | exit: |
578 | 305 | return error; |
579 | 305 | } |
580 | | |
581 | | otError Dataset::Print(otOperationalDatasetTlvs &aDatasetTlvs, bool aNonsensitiveOnly) |
582 | 5 | { |
583 | 5 | struct ComponentTitle |
584 | 5 | { |
585 | 5 | const char *mTitle; // Title to output. |
586 | 5 | const char *mName; // To use with `LookupMapper()`. |
587 | 5 | bool mIsSensitive; // Whether the field is sensitive. |
588 | 5 | }; |
589 | | |
590 | 5 | static const ComponentTitle kTitles[] = { |
591 | 5 | {"Pending Timestamp", "pendingtimestamp", false}, |
592 | 5 | {"Active Timestamp", "activetimestamp", false}, |
593 | 5 | {"Channel", "channel", false}, |
594 | 5 | {"Wake-up Channel", "wakeupchannel", false}, |
595 | 5 | {"Channel Mask", "channelmask", false}, |
596 | 5 | {"Delay", "delay", false}, |
597 | 5 | {"Ext PAN ID", "extpanid", false}, |
598 | 5 | {"Mesh Local Prefix", "meshlocalprefix", false}, |
599 | 5 | {"Network Key", "networkkey", true}, |
600 | 5 | {"Network Name", "networkname", false}, |
601 | 5 | {"PAN ID", "panid", false}, |
602 | 5 | {"PSKc", "pskc", true}, |
603 | 5 | {"Security Policy", "securitypolicy", false}, |
604 | 5 | }; |
605 | | |
606 | 5 | otError error; |
607 | 5 | otOperationalDataset dataset; |
608 | | |
609 | 5 | SuccessOrExit(error = otDatasetParseTlvs(&aDatasetTlvs, &dataset)); |
610 | | |
611 | 4 | for (const ComponentTitle &title : kTitles) |
612 | 52 | { |
613 | 52 | const ComponentMapper *mapper; |
614 | | |
615 | 52 | mapper = LookupMapper(title.mName); |
616 | | |
617 | 52 | if (dataset.mComponents.*mapper->mIsPresentPtr) |
618 | 24 | { |
619 | 24 | OutputFormat("%s: ", title.mTitle); |
620 | 24 | if (aNonsensitiveOnly && title.mIsSensitive) |
621 | 0 | { |
622 | 0 | OutputLine("[Redacted]"); |
623 | 0 | } |
624 | 24 | else |
625 | 24 | { |
626 | 24 | (this->*mapper->mOutput)(dataset); |
627 | 24 | } |
628 | 24 | } |
629 | 52 | } |
630 | | |
631 | 5 | exit: |
632 | 5 | return error; |
633 | 4 | } |
634 | | |
635 | | /** |
636 | | * @cli dataset init (active,new,pending,tlvs) |
637 | | * @code |
638 | | * dataset init new |
639 | | * Done |
640 | | * @endcode |
641 | | * @cparam dataset init {@ca{active}|@ca{new}|@ca{pending}|@ca{tlvs}} [@ca{hex-encoded-tlvs}] |
642 | | * Use `new` to initialize a new dataset, then enter the command `dataset commit active`. |
643 | | * Use `tlvs` for hex-encoded TLVs. |
644 | | * @par |
645 | | * OT CLI checks for `active`, `pending`, or `tlvs` and returns the corresponding values. Otherwise, |
646 | | * OT CLI creates a new, random network and returns a new dataset. |
647 | | * @csa{dataset commit active} |
648 | | * @csa{dataset active} |
649 | | */ |
650 | | template <> otError Dataset::Process<Cmd("init")>(Arg aArgs[]) |
651 | 2 | { |
652 | 2 | otError error = OT_ERROR_INVALID_ARGS; |
653 | | |
654 | 2 | if (aArgs[0] == "active") |
655 | 1 | { |
656 | 1 | error = otDatasetGetActiveTlvs(GetInstancePtr(), &sDatasetTlvs); |
657 | 1 | } |
658 | 1 | else if (aArgs[0] == "pending") |
659 | 0 | { |
660 | 0 | error = otDatasetGetPendingTlvs(GetInstancePtr(), &sDatasetTlvs); |
661 | 0 | } |
662 | 1 | #if OPENTHREAD_FTD |
663 | 1 | else if (aArgs[0] == "new") |
664 | 0 | { |
665 | 0 | otOperationalDataset dataset; |
666 | |
|
667 | 0 | SuccessOrExit(error = otDatasetCreateNewNetwork(GetInstancePtr(), &dataset)); |
668 | 0 | otDatasetConvertToTlvs(&dataset, &sDatasetTlvs); |
669 | 0 | } |
670 | 1 | #endif |
671 | 1 | else if (aArgs[0] == "tlvs") |
672 | 0 | { |
673 | 0 | ExitNow(error = ParseTlvs(aArgs[1], sDatasetTlvs)); |
674 | 0 | } |
675 | | |
676 | 2 | exit: |
677 | 2 | return error; |
678 | 2 | } |
679 | | |
680 | | /** |
681 | | * @cli dataset active |
682 | | * @code |
683 | | * dataset active |
684 | | * Active Timestamp: 1 |
685 | | * Channel: 13 |
686 | | * Channel Mask: 0x07fff800 |
687 | | * Ext PAN ID: d63e8e3e495ebbc3 |
688 | | * Mesh Local Prefix: fd3d:b50b:f96d:722d::/64 |
689 | | * Network Key: dfd34f0f05cad978ec4e32b0413038ff |
690 | | * Network Name: OpenThread-8f28 |
691 | | * PAN ID: 0x8f28 |
692 | | * PSKc: c23a76e98f1a6483639b1ac1271e2e27 |
693 | | * Security Policy: 0, onrcb |
694 | | * Done |
695 | | * @endcode |
696 | | * @code |
697 | | * dataset active -x |
698 | | * 0e08000000000001000000030000103506000...3023d82c841eff0e68db86f35740c030000ff |
699 | | * Done |
700 | | * @endcode |
701 | | * @code |
702 | | * dataset active -ns |
703 | | * Active Timestamp: 1 |
704 | | * Channel: 13 |
705 | | * Channel Mask: 0x07fff800 |
706 | | * Ext PAN ID: d63e8e3e495ebbc3 |
707 | | * Mesh Local Prefix: fd3d:b50b:f96d:722d::/64 |
708 | | * Network Key: [Redacted] |
709 | | * Network Name: OpenThread-8f28 |
710 | | * PAN ID: 0x8f28 |
711 | | * PSKc: [Redacted] |
712 | | * Security Policy: 0, onrcb |
713 | | * Done |
714 | | * @endcode |
715 | | * @cparam dataset active [-x|-ns] |
716 | | * * The optional `-x` argument prints the Active Operational Dataset values as hex-encoded TLVs. |
717 | | * * The optional `-ns` argument prints the Active Operational Dataset values and redact the sensitive values, including |
718 | | * the network key and PSKc fields. |
719 | | * @par api_copy |
720 | | * #otDatasetGetActive |
721 | | * @par |
722 | | * OT CLI uses #otOperationalDataset members to return dataset values to the console. |
723 | | */ |
724 | | template <> otError Dataset::Process<Cmd("active")>(Arg aArgs[]) |
725 | 2 | { |
726 | 2 | otError error; |
727 | 2 | otOperationalDatasetTlvs dataset; |
728 | | |
729 | 2 | SuccessOrExit(error = otDatasetGetActiveTlvs(GetInstancePtr(), &dataset)); |
730 | | |
731 | 2 | if (aArgs[0].IsEmpty()) |
732 | 1 | { |
733 | 1 | error = Print(dataset, /* aNonsensitiveOnly */ false); |
734 | 1 | } |
735 | 1 | else if (aArgs[0] == "-x") |
736 | 0 | { |
737 | 0 | OutputBytesLine(dataset.mTlvs, dataset.mLength); |
738 | 0 | } |
739 | 1 | else if (aArgs[0] == "-ns") |
740 | 0 | { |
741 | 0 | error = Print(dataset, /* aNonsensitiveOnly */ true); |
742 | 0 | } |
743 | 1 | else |
744 | 1 | { |
745 | 1 | error = OT_ERROR_INVALID_ARGS; |
746 | 1 | } |
747 | | |
748 | 2 | exit: |
749 | 2 | return error; |
750 | 2 | } |
751 | | |
752 | | template <> otError Dataset::Process<Cmd("pending")>(Arg aArgs[]) |
753 | 1 | { |
754 | 1 | otError error; |
755 | 1 | otOperationalDatasetTlvs datasetTlvs; |
756 | | |
757 | 1 | SuccessOrExit(error = otDatasetGetPendingTlvs(GetInstancePtr(), &datasetTlvs)); |
758 | | |
759 | 0 | if (aArgs[0].IsEmpty()) |
760 | 0 | { |
761 | 0 | error = Print(datasetTlvs, /* aNonsensitiveOnly */ false); |
762 | 0 | } |
763 | 0 | else if (aArgs[0] == "-x") |
764 | 0 | { |
765 | 0 | OutputBytesLine(datasetTlvs.mTlvs, datasetTlvs.mLength); |
766 | 0 | } |
767 | 0 | else if (aArgs[0] == "-ns") |
768 | 0 | { |
769 | 0 | error = Print(datasetTlvs, /* aNonsensitiveOnly */ true); |
770 | 0 | } |
771 | 0 | else |
772 | 0 | { |
773 | 0 | error = OT_ERROR_INVALID_ARGS; |
774 | 0 | } |
775 | |
|
776 | 1 | exit: |
777 | 1 | return error; |
778 | 0 | } |
779 | | |
780 | | /** |
781 | | * @cli dataset clear |
782 | | * @code |
783 | | * dataset clear |
784 | | * Done |
785 | | * @endcode |
786 | | * @par |
787 | | * Reset the Operational %Dataset buffer. |
788 | | */ |
789 | | template <> otError Dataset::Process<Cmd("clear")>(Arg aArgs[]) |
790 | 1 | { |
791 | 1 | OT_UNUSED_VARIABLE(aArgs); |
792 | | |
793 | 1 | ClearAllBytes(sDatasetTlvs); |
794 | 1 | return OT_ERROR_NONE; |
795 | 1 | } |
796 | | |
797 | | template <> otError Dataset::Process<Cmd("commit")>(Arg aArgs[]) |
798 | 1 | { |
799 | 1 | otError error = OT_ERROR_INVALID_ARGS; |
800 | | |
801 | | /** |
802 | | * @cli dataset commit active |
803 | | * @code |
804 | | * dataset commit active |
805 | | * Done |
806 | | * @endcode |
807 | | * @par |
808 | | * Commit the Operational %Dataset buffer to Active Operational %Dataset. |
809 | | * @csa{dataset commit pending} |
810 | | * @sa #otDatasetSetPending |
811 | | */ |
812 | 1 | if (aArgs[0] == "active") |
813 | 0 | { |
814 | 0 | error = otDatasetSetActiveTlvs(GetInstancePtr(), &sDatasetTlvs); |
815 | 0 | } |
816 | | /** |
817 | | * @cli dataset commit pending |
818 | | * @code |
819 | | * dataset commit pending |
820 | | * Done |
821 | | * @endcode |
822 | | * @par |
823 | | * Commit the Operational %Dataset buffer to Pending Operational %Dataset. |
824 | | * @csa{dataset commit active} |
825 | | * @sa #otDatasetSetActive |
826 | | */ |
827 | 1 | else if (aArgs[0] == "pending") |
828 | 0 | { |
829 | 0 | error = otDatasetSetPendingTlvs(GetInstancePtr(), &sDatasetTlvs); |
830 | 0 | } |
831 | | |
832 | 1 | return error; |
833 | 1 | } |
834 | | |
835 | | template <> otError Dataset::Process<Cmd("mgmtsetcommand")>(Arg aArgs[]) |
836 | 87 | { |
837 | 87 | otError error = OT_ERROR_NONE; |
838 | 87 | otOperationalDataset dataset; |
839 | 87 | otOperationalDatasetTlvs tlvs; |
840 | | |
841 | 87 | ClearAllBytes(dataset); |
842 | 87 | ClearAllBytes(tlvs); |
843 | | |
844 | 309 | for (Arg *arg = &aArgs[1]; !arg->IsEmpty();) |
845 | 284 | { |
846 | 284 | const ComponentMapper *mapper = LookupMapper(arg->GetCString()); |
847 | | |
848 | 284 | if (mapper != nullptr) |
849 | 236 | { |
850 | 236 | arg++; |
851 | 236 | SuccessOrExit(error = (this->*mapper->mParse)(arg, dataset)); |
852 | 222 | dataset.mComponents.*mapper->mIsPresentPtr = true; |
853 | 222 | } |
854 | 48 | else if (*arg == "-x") |
855 | 0 | { |
856 | 0 | arg++; |
857 | 0 | SuccessOrExit(error = ParseTlvs(*arg, tlvs)); |
858 | 0 | arg++; |
859 | 0 | } |
860 | 48 | else |
861 | 48 | { |
862 | 48 | ExitNow(error = OT_ERROR_INVALID_ARGS); |
863 | 48 | } |
864 | 284 | } |
865 | | |
866 | | /** |
867 | | * @cli dataset mgmtsetcommand active |
868 | | * @code |
869 | | * dataset mgmtsetcommand active activetimestamp 123 securitypolicy 1 onrcb |
870 | | * Done |
871 | | * @endcode |
872 | | * @cparam dataset mgmtsetcommand active [@ca{dataset-components}] [-x @ca{tlv-list}] |
873 | | * To learn more about these parameters and argument mappings, refer to @dataset. |
874 | | * @par |
875 | | * @note This command is primarily used for testing only. |
876 | | * @par api_copy |
877 | | * #otDatasetSendMgmtActiveSet |
878 | | * @csa{dataset mgmtgetcommand active} |
879 | | * @csa{dataset mgmtgetcommand pending} |
880 | | * @csa{dataset mgmtsetcommand pending} |
881 | | */ |
882 | 25 | if (aArgs[0] == "active") |
883 | 1 | { |
884 | 1 | error = |
885 | 1 | otDatasetSendMgmtActiveSet(GetInstancePtr(), &dataset, tlvs.mTlvs, tlvs.mLength, /* aCallback */ nullptr, |
886 | 1 | /* aContext */ nullptr); |
887 | 1 | } |
888 | | /** |
889 | | * @cli dataset mgmtsetcommand pending |
890 | | * @code |
891 | | * dataset mgmtsetcommand pending activetimestamp 123 securitypolicy 1 onrcb |
892 | | * Done |
893 | | * @endcode |
894 | | * @cparam dataset mgmtsetcommand pending [@ca{dataset-components}] [-x @ca{tlv-list}] |
895 | | * To learn more about these parameters and argument mappings, refer to @dataset. |
896 | | * @par |
897 | | * @note This command is primarily used for testing only. |
898 | | * @par api_copy |
899 | | * #otDatasetSendMgmtPendingSet |
900 | | * @csa{dataset mgmtgetcommand active} |
901 | | * @csa{dataset mgmtgetcommand pending} |
902 | | * @csa{dataset mgmtsetcommand active} |
903 | | */ |
904 | 24 | else if (aArgs[0] == "pending") |
905 | 0 | { |
906 | 0 | error = |
907 | 0 | otDatasetSendMgmtPendingSet(GetInstancePtr(), &dataset, tlvs.mTlvs, tlvs.mLength, /* aCallback */ nullptr, |
908 | 0 | /* aContext */ nullptr); |
909 | 0 | } |
910 | 24 | else |
911 | 24 | { |
912 | 24 | error = OT_ERROR_INVALID_ARGS; |
913 | 24 | } |
914 | | |
915 | 87 | exit: |
916 | 87 | return error; |
917 | 25 | } |
918 | | |
919 | | template <> otError Dataset::Process<Cmd("mgmtgetcommand")>(Arg aArgs[]) |
920 | 9 | { |
921 | 9 | otError error = OT_ERROR_NONE; |
922 | 9 | otOperationalDatasetComponents datasetComponents; |
923 | 9 | otOperationalDatasetTlvs tlvs; |
924 | 9 | bool destAddrSpecified = false; |
925 | 9 | otIp6Address address; |
926 | | |
927 | 9 | ClearAllBytes(datasetComponents); |
928 | 9 | ClearAllBytes(tlvs); |
929 | | |
930 | 24 | for (Arg *arg = &aArgs[1]; !arg->IsEmpty(); arg++) |
931 | 18 | { |
932 | 18 | const ComponentMapper *mapper = LookupMapper(arg->GetCString()); |
933 | | |
934 | 18 | if (mapper != nullptr) |
935 | 15 | { |
936 | 15 | datasetComponents.*mapper->mIsPresentPtr = true; |
937 | 15 | } |
938 | 3 | else if (*arg == "-x") |
939 | 0 | { |
940 | 0 | arg++; |
941 | 0 | SuccessOrExit(error = ParseTlvs(*arg, tlvs)); |
942 | 0 | } |
943 | 3 | else if (*arg == "address") |
944 | 0 | { |
945 | 0 | arg++; |
946 | 0 | SuccessOrExit(error = arg->ParseAsIp6Address(address)); |
947 | 0 | destAddrSpecified = true; |
948 | 0 | } |
949 | 3 | else |
950 | 3 | { |
951 | 3 | ExitNow(error = OT_ERROR_INVALID_ARGS); |
952 | 3 | } |
953 | 18 | } |
954 | | |
955 | | /** |
956 | | * @cli dataset mgmtgetcommand active |
957 | | * @code |
958 | | * dataset mgmtgetcommand active address fdde:ad00:beef:0:558:f56b:d688:799 activetimestamp securitypolicy |
959 | | * Done |
960 | | * @endcode |
961 | | * @code |
962 | | * dataset mgmtgetcommand active networkname |
963 | | * Done |
964 | | * @endcode |
965 | | * @cparam dataset mgmtgetcommand active [address @ca{leader-address}] [@ca{dataset-components}] [-x @ca{tlv-list}] |
966 | | * * Use `address` to specify the IPv6 destination; otherwise, the Leader ALOC is used as default. |
967 | | * * For `dataset-components`, you can pass any combination of #otOperationalDatasetComponents, for |
968 | | * example `activetimestamp`, `pendingtimestamp`, or `networkkey`. |
969 | | * * The optional `-x` argument specifies raw TLVs to be requested. |
970 | | * @par |
971 | | * OT CLI sends a MGMT_ACTIVE_GET with the relevant arguments. |
972 | | * To learn more about these parameters and argument mappings, refer to @dataset. |
973 | | * @note This command is primarily used for testing only. |
974 | | * @par api_copy |
975 | | * #otDatasetSendMgmtActiveGet |
976 | | * @csa{dataset mgmtgetcommand pending} |
977 | | * @csa{dataset mgmtsetcommand active} |
978 | | * @csa{dataset mgmtsetcommand pending} |
979 | | */ |
980 | 6 | if (aArgs[0] == "active") |
981 | 2 | { |
982 | 2 | error = otDatasetSendMgmtActiveGet(GetInstancePtr(), &datasetComponents, tlvs.mTlvs, tlvs.mLength, |
983 | 2 | destAddrSpecified ? &address : nullptr); |
984 | 2 | } |
985 | | /** |
986 | | * @cli dataset mgmtgetcommand pending |
987 | | * @code |
988 | | * dataset mgmtgetcommand pending address fdde:ad00:beef:0:558:f56b:d688:799 activetimestamp securitypolicy |
989 | | * Done |
990 | | * @endcode |
991 | | * @code |
992 | | * dataset mgmtgetcommand pending networkname |
993 | | * Done |
994 | | * @endcode |
995 | | * @cparam dataset mgmtgetcommand pending [address @ca{leader-address}] [@ca{dataset-components}] [-x @ca{tlv-list}] |
996 | | * To learn more about these parameters and argument mappings, refer to @dataset. |
997 | | * @par |
998 | | * @note This command is primarily used for testing only. |
999 | | * @par api_copy |
1000 | | * #otDatasetSendMgmtPendingGet |
1001 | | * @csa{dataset mgmtgetcommand active} |
1002 | | * @csa{dataset mgmtsetcommand active} |
1003 | | * @csa{dataset mgmtsetcommand pending} |
1004 | | */ |
1005 | 4 | else if (aArgs[0] == "pending") |
1006 | 0 | { |
1007 | 0 | error = otDatasetSendMgmtPendingGet(GetInstancePtr(), &datasetComponents, tlvs.mTlvs, tlvs.mLength, |
1008 | 0 | destAddrSpecified ? &address : nullptr); |
1009 | 0 | } |
1010 | 4 | else |
1011 | 4 | { |
1012 | 4 | error = OT_ERROR_INVALID_ARGS; |
1013 | 4 | } |
1014 | | |
1015 | 9 | exit: |
1016 | 9 | return error; |
1017 | 6 | } |
1018 | | |
1019 | | void Dataset::OutputSecurityPolicy(const otSecurityPolicy &aSecurityPolicy) |
1020 | 2 | { |
1021 | 2 | OutputFormat("%u ", aSecurityPolicy.mRotationTime); |
1022 | | |
1023 | 2 | if (aSecurityPolicy.mObtainNetworkKeyEnabled) |
1024 | 2 | { |
1025 | 2 | OutputFormat("o"); |
1026 | 2 | } |
1027 | | |
1028 | 2 | if (aSecurityPolicy.mNativeCommissioningEnabled) |
1029 | 2 | { |
1030 | 2 | OutputFormat("n"); |
1031 | 2 | } |
1032 | | |
1033 | 2 | if (aSecurityPolicy.mRoutersEnabled) |
1034 | 2 | { |
1035 | 2 | OutputFormat("r"); |
1036 | 2 | } |
1037 | | |
1038 | 2 | if (aSecurityPolicy.mExternalCommissioningEnabled) |
1039 | 2 | { |
1040 | 2 | OutputFormat("c"); |
1041 | 2 | } |
1042 | | |
1043 | 2 | if (aSecurityPolicy.mCommercialCommissioningEnabled) |
1044 | 0 | { |
1045 | 0 | OutputFormat("C"); |
1046 | 0 | } |
1047 | | |
1048 | 2 | if (aSecurityPolicy.mAutonomousEnrollmentEnabled) |
1049 | 0 | { |
1050 | 0 | OutputFormat("e"); |
1051 | 0 | } |
1052 | | |
1053 | 2 | if (aSecurityPolicy.mNetworkKeyProvisioningEnabled) |
1054 | 0 | { |
1055 | 0 | OutputFormat("p"); |
1056 | 0 | } |
1057 | | |
1058 | 2 | if (aSecurityPolicy.mNonCcmRoutersEnabled) |
1059 | 0 | { |
1060 | 0 | OutputFormat("R"); |
1061 | 0 | } |
1062 | | |
1063 | 2 | OutputLine(" %u", aSecurityPolicy.mVersionThresholdForRouting); |
1064 | 2 | } |
1065 | | |
1066 | | otError Dataset::ParseSecurityPolicy(otSecurityPolicy &aSecurityPolicy, Arg *&aArgs) |
1067 | 71 | { |
1068 | 71 | static constexpr uint8_t kMaxVersionThreshold = 7; |
1069 | | |
1070 | 71 | otError error; |
1071 | 71 | otSecurityPolicy policy; |
1072 | 71 | uint8_t versionThreshold; |
1073 | | |
1074 | 71 | ClearAllBytes(policy); |
1075 | | |
1076 | 71 | SuccessOrExit(error = aArgs->ParseAsUint16(policy.mRotationTime)); |
1077 | 70 | aArgs++; |
1078 | | |
1079 | 70 | VerifyOrExit(!aArgs->IsEmpty()); |
1080 | | |
1081 | 1.71k | for (const char *flag = aArgs->GetCString(); *flag != '\0'; flag++) |
1082 | 1.66k | { |
1083 | 1.66k | switch (*flag) |
1084 | 1.66k | { |
1085 | 200 | case 'o': |
1086 | 200 | policy.mObtainNetworkKeyEnabled = true; |
1087 | 200 | break; |
1088 | | |
1089 | 210 | case 'n': |
1090 | 210 | policy.mNativeCommissioningEnabled = true; |
1091 | 210 | break; |
1092 | | |
1093 | 212 | case 'r': |
1094 | 212 | policy.mRoutersEnabled = true; |
1095 | 212 | break; |
1096 | | |
1097 | 228 | case 'c': |
1098 | 228 | policy.mExternalCommissioningEnabled = true; |
1099 | 228 | break; |
1100 | | |
1101 | 194 | case 'C': |
1102 | 194 | policy.mCommercialCommissioningEnabled = true; |
1103 | 194 | break; |
1104 | | |
1105 | 205 | case 'e': |
1106 | 205 | policy.mAutonomousEnrollmentEnabled = true; |
1107 | 205 | break; |
1108 | | |
1109 | 199 | case 'p': |
1110 | 199 | policy.mNetworkKeyProvisioningEnabled = true; |
1111 | 199 | break; |
1112 | | |
1113 | 200 | case 'R': |
1114 | 200 | policy.mNonCcmRoutersEnabled = true; |
1115 | 200 | break; |
1116 | | |
1117 | 15 | default: |
1118 | 15 | ExitNow(error = OT_ERROR_INVALID_ARGS); |
1119 | 1.66k | } |
1120 | 1.66k | } |
1121 | | |
1122 | 54 | aArgs++; |
1123 | 54 | VerifyOrExit(!aArgs->IsEmpty()); |
1124 | | |
1125 | 5 | SuccessOrExit(error = aArgs->ParseAsUint8(versionThreshold)); |
1126 | 4 | aArgs++; |
1127 | 4 | VerifyOrExit(versionThreshold <= kMaxVersionThreshold, error = OT_ERROR_INVALID_ARGS); |
1128 | 3 | policy.mVersionThresholdForRouting = versionThreshold; |
1129 | | |
1130 | 71 | exit: |
1131 | 71 | if (error == OT_ERROR_NONE) |
1132 | 53 | { |
1133 | 53 | aSecurityPolicy = policy; |
1134 | 53 | } |
1135 | | |
1136 | 71 | return error; |
1137 | 3 | } |
1138 | | |
1139 | | /** |
1140 | | * @cli dataset set (active,pending) |
1141 | | * @code |
1142 | | * dataset set active 0e08000000000001000000030000103506000...3023d82c841eff0e68db86f35740c030000ff |
1143 | | * Done |
1144 | | * @endcode |
1145 | | * @code |
1146 | | * dataset set pending 0e08000000000001000000030000103506000...3023d82c841eff0e68db86f35740c030000ff |
1147 | | * Done |
1148 | | * @endcode |
1149 | | * @cparam dataset set {active|pending} @ca{tlvs} |
1150 | | * @par |
1151 | | * The CLI `dataset set` command sets the Active Operational %Dataset using hex-encoded TLVs. |
1152 | | * @par api_copy |
1153 | | * #otDatasetSetActive |
1154 | | */ |
1155 | | template <> otError Dataset::Process<Cmd("set")>(Arg aArgs[]) |
1156 | 183 | { |
1157 | 183 | otError error = OT_ERROR_NONE; |
1158 | 183 | otOperationalDatasetTlvs datasetTlvs; |
1159 | | |
1160 | 183 | SuccessOrExit(error = ParseTlvs(aArgs[1], datasetTlvs)); |
1161 | | |
1162 | 178 | if (aArgs[0] == "active") |
1163 | 171 | { |
1164 | 171 | error = otDatasetSetActiveTlvs(GetInstancePtr(), &datasetTlvs); |
1165 | 171 | } |
1166 | 7 | else if (aArgs[0] == "pending") |
1167 | 3 | { |
1168 | 3 | error = otDatasetSetPendingTlvs(GetInstancePtr(), &datasetTlvs); |
1169 | 3 | } |
1170 | 4 | else |
1171 | 4 | { |
1172 | 4 | error = OT_ERROR_INVALID_ARGS; |
1173 | 4 | } |
1174 | | |
1175 | 183 | exit: |
1176 | 183 | return error; |
1177 | 178 | } |
1178 | | |
1179 | | /** |
1180 | | * @cli dataset tlvs |
1181 | | * @code |
1182 | | * dataset tlvs |
1183 | | * 0e080000000000010000000300001635060004001fffe0020...f7f8 |
1184 | | * Done |
1185 | | * @endcode |
1186 | | * @par api_copy |
1187 | | * #otDatasetConvertToTlvs |
1188 | | */ |
1189 | | template <> otError Dataset::Process<Cmd("tlvs")>(Arg aArgs[]) |
1190 | 2 | { |
1191 | 2 | otError error = OT_ERROR_NONE; |
1192 | | |
1193 | 2 | VerifyOrExit(aArgs[0].IsEmpty(), error = OT_ERROR_INVALID_ARGS); |
1194 | 1 | OutputBytesLine(sDatasetTlvs.mTlvs, sDatasetTlvs.mLength); |
1195 | | |
1196 | 2 | exit: |
1197 | 2 | return error; |
1198 | 1 | } |
1199 | | |
1200 | | #if OPENTHREAD_CONFIG_DATASET_UPDATER_ENABLE && OPENTHREAD_FTD |
1201 | | |
1202 | | template <> otError Dataset::Process<Cmd("updater")>(Arg aArgs[]) |
1203 | 2 | { |
1204 | 2 | otError error = OT_ERROR_NONE; |
1205 | | |
1206 | | /** |
1207 | | * @cli dataset updater |
1208 | | * @code |
1209 | | * dataset updater |
1210 | | * Enabled |
1211 | | * Done |
1212 | | * @endcode |
1213 | | * @par api_copy |
1214 | | * #otDatasetUpdaterIsUpdateOngoing |
1215 | | */ |
1216 | 2 | if (aArgs[0].IsEmpty()) |
1217 | 1 | { |
1218 | 1 | OutputEnabledDisabledStatus(otDatasetUpdaterIsUpdateOngoing(GetInstancePtr())); |
1219 | 1 | } |
1220 | | /** |
1221 | | * @cli dataset updater start |
1222 | | * @code |
1223 | | * channel |
1224 | | * 19 |
1225 | | * Done |
1226 | | * dataset clear |
1227 | | * Done |
1228 | | * dataset channel 15 |
1229 | | * Done |
1230 | | * dataset |
1231 | | * Channel: 15 |
1232 | | * Done |
1233 | | * dataset updater start |
1234 | | * Done |
1235 | | * dataset updater |
1236 | | * Enabled |
1237 | | * Done |
1238 | | * Dataset update complete: OK |
1239 | | * channel |
1240 | | * 15 |
1241 | | * Done |
1242 | | * @endcode |
1243 | | * @par api_copy |
1244 | | * #otDatasetUpdaterRequestUpdate |
1245 | | */ |
1246 | 1 | else if (aArgs[0] == "start") |
1247 | 0 | { |
1248 | 0 | otOperationalDataset dataset; |
1249 | |
|
1250 | 0 | SuccessOrExit(error = otDatasetParseTlvs(&sDatasetTlvs, &dataset)); |
1251 | 0 | SuccessOrExit( |
1252 | 0 | error = otDatasetUpdaterRequestUpdate(GetInstancePtr(), &dataset, &Dataset::HandleDatasetUpdater, this)); |
1253 | 0 | } |
1254 | | /** |
1255 | | * @cli dataset updater cancel |
1256 | | * @code |
1257 | | * @dataset updater cancel |
1258 | | * Done |
1259 | | * @endcode |
1260 | | * @par api_copy |
1261 | | * #otDatasetUpdaterCancelUpdate |
1262 | | */ |
1263 | 1 | else if (aArgs[0] == "cancel") |
1264 | 0 | { |
1265 | 0 | otDatasetUpdaterCancelUpdate(GetInstancePtr()); |
1266 | 0 | } |
1267 | 1 | else |
1268 | 1 | { |
1269 | 1 | error = OT_ERROR_INVALID_ARGS; |
1270 | 1 | } |
1271 | | |
1272 | 2 | exit: |
1273 | 2 | return error; |
1274 | 2 | } |
1275 | | |
1276 | | void Dataset::HandleDatasetUpdater(otError aError, void *aContext) |
1277 | 0 | { |
1278 | 0 | static_cast<Dataset *>(aContext)->HandleDatasetUpdater(aError); |
1279 | 0 | } |
1280 | | |
1281 | | void Dataset::HandleDatasetUpdater(otError aError) |
1282 | 0 | { |
1283 | 0 | OutputLine("Dataset update complete: %s", otThreadErrorToString(aError)); |
1284 | 0 | } |
1285 | | |
1286 | | #endif // OPENTHREAD_CONFIG_DATASET_UPDATER_ENABLE && OPENTHREAD_FTD |
1287 | | |
1288 | | otError Dataset::Process(Arg aArgs[]) |
1289 | 601 | { |
1290 | 6.01k | #define CmdEntry(aCommandString) {aCommandString, &Dataset::Process<Cmd(aCommandString)>} |
1291 | | |
1292 | 601 | static constexpr Command kCommands[] = { |
1293 | 601 | CmdEntry("active"), CmdEntry("clear"), CmdEntry("commit"), CmdEntry("init"), |
1294 | 601 | CmdEntry("mgmtgetcommand"), CmdEntry("mgmtsetcommand"), CmdEntry("pending"), CmdEntry("set"), |
1295 | 601 | CmdEntry("tlvs"), |
1296 | 601 | #if OPENTHREAD_CONFIG_DATASET_UPDATER_ENABLE && OPENTHREAD_FTD |
1297 | 601 | CmdEntry("updater"), |
1298 | 601 | #endif |
1299 | 601 | }; |
1300 | | |
1301 | 601 | #undef CmdEntry |
1302 | | |
1303 | 601 | static_assert(BinarySearch::IsSorted(kCommands), "kCommands is not sorted"); |
1304 | | |
1305 | 601 | otError error = OT_ERROR_INVALID_COMMAND; |
1306 | 601 | const Command *command; |
1307 | 601 | const ComponentMapper *mapper; |
1308 | | |
1309 | 601 | if (aArgs[0].IsEmpty()) |
1310 | 4 | { |
1311 | 4 | ExitNow(error = Print(sDatasetTlvs, /* aNonsensitiveOnly */ false)); |
1312 | 4 | } |
1313 | | |
1314 | | /** |
1315 | | * @cli dataset help |
1316 | | * @code |
1317 | | * dataset help |
1318 | | * help |
1319 | | * active |
1320 | | * activetimestamp |
1321 | | * channel |
1322 | | * channelmask |
1323 | | * clear |
1324 | | * commit |
1325 | | * delay |
1326 | | * extpanid |
1327 | | * init |
1328 | | * meshlocalprefix |
1329 | | * mgmtgetcommand |
1330 | | * mgmtsetcommand |
1331 | | * networkkey |
1332 | | * networkname |
1333 | | * panid |
1334 | | * pending |
1335 | | * pendingtimestamp |
1336 | | * pskc |
1337 | | * securitypolicy |
1338 | | * set |
1339 | | * tlvs |
1340 | | * Done |
1341 | | * @endcode |
1342 | | * @par |
1343 | | * Gets a list of `dataset` CLI commands. @moreinfo{@dataset}. |
1344 | | */ |
1345 | 597 | if (aArgs[0] == "help") |
1346 | 0 | { |
1347 | 0 | OutputCommandTable(kCommands); |
1348 | 0 | ExitNow(error = OT_ERROR_NONE); |
1349 | 0 | } |
1350 | | |
1351 | 597 | mapper = LookupMapper(aArgs[0].GetCString()); |
1352 | | |
1353 | 597 | if (mapper != nullptr) |
1354 | 305 | { |
1355 | 305 | error = ProcessCommand(*mapper, aArgs + 1); |
1356 | 305 | ExitNow(); |
1357 | 305 | } |
1358 | | |
1359 | 292 | command = BinarySearch::Find(aArgs[0].GetCString(), kCommands); |
1360 | 292 | VerifyOrExit(command != nullptr); |
1361 | | |
1362 | 290 | error = (this->*command->mHandler)(aArgs + 1); |
1363 | | |
1364 | 601 | exit: |
1365 | 601 | return error; |
1366 | 290 | } |
1367 | | |
1368 | | } // namespace Cli |
1369 | | } // namespace ot |