1 /*
2 * Copyright (c) 2019, 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 a simple CLI for the Joiner role.
32 */
33
34 #include "cli_joiner.hpp"
35
36 #include <inttypes.h>
37
38 #include "cli/cli.hpp"
39
40 #if OPENTHREAD_CONFIG_JOINER_ENABLE
41
42 namespace ot {
43 namespace Cli {
44
45 constexpr Joiner::Command Joiner::sCommands[];
46
ProcessDiscerner(Arg aArgs[])47 otError Joiner::ProcessDiscerner(Arg aArgs[])
48 {
49 otError error = OT_ERROR_INVALID_ARGS;
50
51 if (aArgs[0].IsEmpty())
52 {
53 const otJoinerDiscerner *discerner = otJoinerGetDiscerner(mInterpreter.mInstance);
54
55 VerifyOrExit(discerner != nullptr, error = OT_ERROR_NOT_FOUND);
56
57 mInterpreter.OutputLine("0x%llx/%u", static_cast<unsigned long long>(discerner->mValue), discerner->mLength);
58 error = OT_ERROR_NONE;
59 }
60 else
61 {
62 otJoinerDiscerner discerner;
63
64 memset(&discerner, 0, sizeof(discerner));
65
66 if (aArgs[0] == "clear")
67 {
68 error = otJoinerSetDiscerner(mInterpreter.mInstance, nullptr);
69 }
70 else
71 {
72 VerifyOrExit(aArgs[1].IsEmpty());
73 SuccessOrExit(Interpreter::ParseJoinerDiscerner(aArgs[0], discerner));
74 error = otJoinerSetDiscerner(mInterpreter.mInstance, &discerner);
75 }
76 }
77
78 exit:
79 return error;
80 }
81
ProcessHelp(Arg aArgs[])82 otError Joiner::ProcessHelp(Arg aArgs[])
83 {
84 OT_UNUSED_VARIABLE(aArgs);
85
86 for (const Command &command : sCommands)
87 {
88 mInterpreter.OutputLine(command.mName);
89 }
90
91 return OT_ERROR_NONE;
92 }
93
ProcessId(Arg aArgs[])94 otError Joiner::ProcessId(Arg aArgs[])
95 {
96 OT_UNUSED_VARIABLE(aArgs);
97
98 mInterpreter.OutputExtAddress(*otJoinerGetId(mInterpreter.mInstance));
99 mInterpreter.OutputLine("");
100
101 return OT_ERROR_NONE;
102 }
103
ProcessStart(Arg aArgs[])104 otError Joiner::ProcessStart(Arg aArgs[])
105 {
106 otError error;
107
108 VerifyOrExit(!aArgs[0].IsEmpty(), error = OT_ERROR_INVALID_ARGS);
109
110 error = otJoinerStart(mInterpreter.mInstance,
111 aArgs[0].GetCString(), // aPskd
112 aArgs[1].GetCString(), // aProvisioningUrl (nullptr if aArgs[1] is empty)
113 PACKAGE_NAME, // aVendorName
114 OPENTHREAD_CONFIG_PLATFORM_INFO, // aVendorModel
115 PACKAGE_VERSION, // aVendorSwVersion
116 nullptr, // aVendorData
117 &Joiner::HandleCallback, this);
118
119 exit:
120 return error;
121 }
122
ProcessStop(Arg aArgs[])123 otError Joiner::ProcessStop(Arg aArgs[])
124 {
125 OT_UNUSED_VARIABLE(aArgs);
126
127 otJoinerStop(mInterpreter.mInstance);
128
129 return OT_ERROR_NONE;
130 }
131
Process(Arg aArgs[])132 otError Joiner::Process(Arg aArgs[])
133 {
134 otError error = OT_ERROR_INVALID_COMMAND;
135 const Command *command;
136
137 if (aArgs[0].IsEmpty())
138 {
139 IgnoreError(ProcessHelp(aArgs));
140 ExitNow();
141 }
142
143 command = Utils::LookupTable::Find(aArgs[0].GetCString(), sCommands);
144 VerifyOrExit(command != nullptr);
145
146 error = (this->*command->mHandler)(aArgs + 1);
147
148 exit:
149 return error;
150 }
151
HandleCallback(otError aError,void * aContext)152 void Joiner::HandleCallback(otError aError, void *aContext)
153 {
154 static_cast<Joiner *>(aContext)->HandleCallback(aError);
155 }
156
HandleCallback(otError aError)157 void Joiner::HandleCallback(otError aError)
158 {
159 switch (aError)
160 {
161 case OT_ERROR_NONE:
162 mInterpreter.OutputLine("Join success");
163 break;
164
165 default:
166 mInterpreter.OutputLine("Join failed [%s]", otThreadErrorToString(aError));
167 break;
168 }
169 }
170
171 } // namespace Cli
172 } // namespace ot
173
174 #endif // OPENTHREAD_CONFIG_JOINER_ENABLE
175