1 /*
2 * Copyright (c) 2020, 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 CLI commands for Network Data.
32 */
33
34 #include "cli_network_data.hpp"
35
36 #include <openthread/border_router.h>
37 #include <openthread/netdata_publisher.h>
38 #include <openthread/server.h>
39
40 #include "cli/cli.hpp"
41 #include "common/encoding.hpp"
42
43 namespace ot {
44 namespace Cli {
45
46 constexpr NetworkData::Command NetworkData::sCommands[];
47
NetworkData(Interpreter & aInterpreter)48 NetworkData::NetworkData(Interpreter &aInterpreter)
49 : mInterpreter(aInterpreter)
50 {
51 }
52
OutputPrefix(const otBorderRouterConfig & aConfig)53 void NetworkData::OutputPrefix(const otBorderRouterConfig &aConfig)
54 {
55 enum
56 {
57 // BorderRouter flag is `uint16_t` (though some of the bits are
58 // reserved for future use), so we use 17 chars string (16 flags
59 // plus null char at end of string).
60 kMaxFlagStringSize = 17,
61 };
62
63 char flagsString[kMaxFlagStringSize];
64 char *flagsPtr = &flagsString[0];
65
66 mInterpreter.OutputIp6Prefix(aConfig.mPrefix);
67
68 if (aConfig.mPreferred)
69 {
70 *flagsPtr++ = 'p';
71 }
72
73 if (aConfig.mSlaac)
74 {
75 *flagsPtr++ = 'a';
76 }
77
78 if (aConfig.mDhcp)
79 {
80 *flagsPtr++ = 'd';
81 }
82
83 if (aConfig.mConfigure)
84 {
85 *flagsPtr++ = 'c';
86 }
87
88 if (aConfig.mDefaultRoute)
89 {
90 *flagsPtr++ = 'r';
91 }
92
93 if (aConfig.mOnMesh)
94 {
95 *flagsPtr++ = 'o';
96 }
97
98 if (aConfig.mStable)
99 {
100 *flagsPtr++ = 's';
101 }
102
103 if (aConfig.mNdDns)
104 {
105 *flagsPtr++ = 'n';
106 }
107
108 if (aConfig.mDp)
109 {
110 *flagsPtr++ = 'D';
111 }
112
113 *flagsPtr = '\0';
114
115 if (flagsPtr != &flagsString[0])
116 {
117 mInterpreter.OutputFormat(" %s", flagsString);
118 }
119
120 OutputPreference(aConfig.mPreference);
121
122 mInterpreter.OutputLine(" %04x", aConfig.mRloc16);
123 }
124
OutputRoute(const otExternalRouteConfig & aConfig)125 void NetworkData::OutputRoute(const otExternalRouteConfig &aConfig)
126 {
127 enum
128 {
129 // ExternalRoute flag is `uint8_t` (though some of the bits are
130 // reserved for future use), so we use 9 chars string (8 flags
131 // plus null char at end of string).
132 kMaxFlagStringSize = 9,
133 };
134
135 char flagsString[kMaxFlagStringSize];
136 char *flagsPtr = &flagsString[0];
137
138 mInterpreter.OutputIp6Prefix(aConfig.mPrefix);
139
140 if (aConfig.mStable)
141 {
142 *flagsPtr++ = 's';
143 }
144
145 if (aConfig.mNat64)
146 {
147 *flagsPtr++ = 'n';
148 }
149
150 *flagsPtr = '\0';
151
152 if (flagsPtr != &flagsString[0])
153 {
154 mInterpreter.OutputFormat(" %s", flagsString);
155 }
156
157 OutputPreference(aConfig.mPreference);
158
159 mInterpreter.OutputLine(" %04x", aConfig.mRloc16);
160 }
161
OutputPreference(signed int aPreference)162 void NetworkData::OutputPreference(signed int aPreference)
163 {
164 switch (aPreference)
165 {
166 case OT_ROUTE_PREFERENCE_LOW:
167 mInterpreter.OutputFormat(" low");
168 break;
169
170 case OT_ROUTE_PREFERENCE_MED:
171 mInterpreter.OutputFormat(" med");
172 break;
173
174 case OT_ROUTE_PREFERENCE_HIGH:
175 mInterpreter.OutputFormat(" high");
176 break;
177
178 default:
179 break;
180 }
181 }
182
OutputService(const otServiceConfig & aConfig)183 void NetworkData::OutputService(const otServiceConfig &aConfig)
184 {
185 mInterpreter.OutputFormat("%u ", aConfig.mEnterpriseNumber);
186 mInterpreter.OutputBytes(aConfig.mServiceData, aConfig.mServiceDataLength);
187 mInterpreter.OutputFormat(" ");
188 mInterpreter.OutputBytes(aConfig.mServerConfig.mServerData, aConfig.mServerConfig.mServerDataLength);
189
190 if (aConfig.mServerConfig.mStable)
191 {
192 mInterpreter.OutputFormat(" s");
193 }
194
195 mInterpreter.OutputLine(" %04x", aConfig.mServerConfig.mRloc16);
196 }
197
ProcessHelp(Arg aArgs[])198 otError NetworkData::ProcessHelp(Arg aArgs[])
199 {
200 OT_UNUSED_VARIABLE(aArgs);
201
202 for (const Command &command : sCommands)
203 {
204 mInterpreter.OutputLine(command.mName);
205 }
206
207 return OT_ERROR_NONE;
208 }
209
210 #if OPENTHREAD_CONFIG_NETDATA_PUBLISHER_ENABLE
ProcessPublish(Arg aArgs[])211 otError NetworkData::ProcessPublish(Arg aArgs[])
212 {
213 otError error = OT_ERROR_NONE;
214
215 #if OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
216 if (aArgs[0] == "dnssrp")
217 {
218 if (aArgs[1] == "anycast")
219 {
220 uint8_t sequenceNumber;
221
222 SuccessOrExit(error = aArgs[2].ParseAsUint8(sequenceNumber));
223 otNetDataPublishDnsSrpServiceAnycast(mInterpreter.mInstance, sequenceNumber);
224 ExitNow();
225 }
226
227 if (aArgs[1] == "unicast")
228 {
229 otIp6Address address;
230 uint16_t port;
231
232 if (aArgs[3].IsEmpty())
233 {
234 SuccessOrExit(error = aArgs[2].ParseAsUint16(port));
235 otNetDataPublishDnsSrpServiceUnicastMeshLocalEid(mInterpreter.mInstance, port);
236 ExitNow();
237 }
238
239 SuccessOrExit(error = aArgs[2].ParseAsIp6Address(address));
240 SuccessOrExit(error = aArgs[3].ParseAsUint16(port));
241 otNetDataPublishDnsSrpServiceUnicast(mInterpreter.mInstance, &address, port);
242 ExitNow();
243 }
244 }
245 #endif // OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
246
247 #if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE
248 if (aArgs[0] == "prefix")
249 {
250 otBorderRouterConfig config;
251
252 SuccessOrExit(error = Interpreter::ParsePrefix(aArgs + 1, config));
253 error = otNetDataPublishOnMeshPrefix(mInterpreter.mInstance, &config);
254 ExitNow();
255 }
256
257 if (aArgs[0] == "route")
258 {
259 otExternalRouteConfig config;
260
261 SuccessOrExit(error = Interpreter::ParseRoute(aArgs + 1, config));
262 error = otNetDataPublishExternalRoute(mInterpreter.mInstance, &config);
263 ExitNow();
264 }
265 #endif // OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE
266
267 error = OT_ERROR_INVALID_ARGS;
268
269 exit:
270 return error;
271 }
272
ProcessUnpublish(Arg aArgs[])273 otError NetworkData::ProcessUnpublish(Arg aArgs[])
274 {
275 otError error = OT_ERROR_NONE;
276
277 #if OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
278 if (aArgs[0] == "dnssrp")
279 {
280 otNetDataUnpublishDnsSrpService(mInterpreter.mInstance);
281 ExitNow();
282 }
283 #endif
284
285 #if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE
286 {
287 otIp6Prefix prefix;
288
289 if (aArgs[0].ParseAsIp6Prefix(prefix) == OT_ERROR_NONE)
290 {
291 error = otNetDataUnpublishPrefix(mInterpreter.mInstance, &prefix);
292 ExitNow();
293 }
294 }
295 #endif
296
297 error = OT_ERROR_INVALID_ARGS;
298
299 exit:
300 return error;
301 }
302 #endif // OPENTHREAD_CONFIG_NETDATA_PUBLISHER_ENABLE
303
304 #if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE || OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
ProcessRegister(Arg aArgs[])305 otError NetworkData::ProcessRegister(Arg aArgs[])
306 {
307 OT_UNUSED_VARIABLE(aArgs);
308
309 otError error = OT_ERROR_NONE;
310
311 #if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE
312 SuccessOrExit(error = otBorderRouterRegister(mInterpreter.mInstance));
313 #else
314 SuccessOrExit(error = otServerRegister(mInterpreter.mInstance));
315 #endif
316
317 exit:
318 return error;
319 }
320 #endif
321
ProcessSteeringData(Arg aArgs[])322 otError NetworkData::ProcessSteeringData(Arg aArgs[])
323 {
324 otError error;
325 otExtAddress addr;
326 otJoinerDiscerner discerner;
327
328 VerifyOrExit(aArgs[0] == "check", error = OT_ERROR_INVALID_ARGS);
329
330 error = Interpreter::ParseJoinerDiscerner(aArgs[1], discerner);
331
332 if (error == OT_ERROR_NOT_FOUND)
333 {
334 discerner.mLength = 0;
335 error = aArgs[1].ParseAsHexString(addr.m8);
336 }
337
338 SuccessOrExit(error);
339
340 if (discerner.mLength)
341 {
342 error = otNetDataSteeringDataCheckJoinerWithDiscerner(mInterpreter.mInstance, &discerner);
343 }
344 else
345 {
346 error = otNetDataSteeringDataCheckJoiner(mInterpreter.mInstance, &addr);
347 }
348
349 exit:
350 return error;
351 }
352
OutputPrefixes(void)353 void NetworkData::OutputPrefixes(void)
354 {
355 otNetworkDataIterator iterator = OT_NETWORK_DATA_ITERATOR_INIT;
356 otBorderRouterConfig config;
357
358 mInterpreter.OutputLine("Prefixes:");
359
360 while (otNetDataGetNextOnMeshPrefix(mInterpreter.mInstance, &iterator, &config) == OT_ERROR_NONE)
361 {
362 OutputPrefix(config);
363 }
364 }
365
OutputRoutes(void)366 void NetworkData::OutputRoutes(void)
367 {
368 otNetworkDataIterator iterator = OT_NETWORK_DATA_ITERATOR_INIT;
369 otExternalRouteConfig config;
370
371 mInterpreter.OutputLine("Routes:");
372
373 while (otNetDataGetNextRoute(mInterpreter.mInstance, &iterator, &config) == OT_ERROR_NONE)
374 {
375 OutputRoute(config);
376 }
377 }
378
OutputServices(void)379 void NetworkData::OutputServices(void)
380 {
381 otNetworkDataIterator iterator = OT_NETWORK_DATA_ITERATOR_INIT;
382 otServiceConfig config;
383
384 mInterpreter.OutputLine("Services:");
385
386 while (otNetDataGetNextService(mInterpreter.mInstance, &iterator, &config) == OT_ERROR_NONE)
387 {
388 OutputService(config);
389 }
390 }
391
OutputBinary(void)392 otError NetworkData::OutputBinary(void)
393 {
394 otError error = OT_ERROR_NONE;
395 uint8_t data[255];
396 uint8_t len = sizeof(data);
397
398 SuccessOrExit(error = otNetDataGet(mInterpreter.mInstance, false, data, &len));
399
400 mInterpreter.OutputBytes(data, static_cast<uint8_t>(len));
401 mInterpreter.OutputLine("");
402
403 exit:
404 return error;
405 }
406
ProcessShow(Arg aArgs[])407 otError NetworkData::ProcessShow(Arg aArgs[])
408 {
409 otError error = OT_ERROR_INVALID_ARGS;
410
411 if (aArgs[0].IsEmpty())
412 {
413 OutputPrefixes();
414 OutputRoutes();
415 OutputServices();
416 error = OT_ERROR_NONE;
417 }
418 else if (aArgs[0] == "-x")
419 {
420 error = OutputBinary();
421 }
422
423 return error;
424 }
425
Process(Arg aArgs[])426 otError NetworkData::Process(Arg aArgs[])
427 {
428 otError error = OT_ERROR_INVALID_COMMAND;
429 const Command *command;
430
431 if (aArgs[0].IsEmpty())
432 {
433 IgnoreError(ProcessHelp(aArgs));
434 ExitNow();
435 }
436
437 command = Utils::LookupTable::Find(aArgs[0].GetCString(), sCommands);
438 VerifyOrExit(command != nullptr);
439
440 error = (this->*command->mHandler)(aArgs + 1);
441
442 exit:
443 return error;
444 }
445
446 } // namespace Cli
447 } // namespace ot
448