1*cfb92d14SAndroid Build Coastguard Worker /*
2*cfb92d14SAndroid Build Coastguard Worker * Copyright (c) 2019, The OpenThread Authors.
3*cfb92d14SAndroid Build Coastguard Worker * All rights reserved.
4*cfb92d14SAndroid Build Coastguard Worker *
5*cfb92d14SAndroid Build Coastguard Worker * Redistribution and use in source and binary forms, with or without
6*cfb92d14SAndroid Build Coastguard Worker * modification, are permitted provided that the following conditions are met:
7*cfb92d14SAndroid Build Coastguard Worker * 1. Redistributions of source code must retain the above copyright
8*cfb92d14SAndroid Build Coastguard Worker * notice, this list of conditions and the following disclaimer.
9*cfb92d14SAndroid Build Coastguard Worker * 2. Redistributions in binary form must reproduce the above copyright
10*cfb92d14SAndroid Build Coastguard Worker * notice, this list of conditions and the following disclaimer in the
11*cfb92d14SAndroid Build Coastguard Worker * documentation and/or other materials provided with the distribution.
12*cfb92d14SAndroid Build Coastguard Worker * 3. Neither the name of the copyright holder nor the
13*cfb92d14SAndroid Build Coastguard Worker * names of its contributors may be used to endorse or promote products
14*cfb92d14SAndroid Build Coastguard Worker * derived from this software without specific prior written permission.
15*cfb92d14SAndroid Build Coastguard Worker *
16*cfb92d14SAndroid Build Coastguard Worker * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17*cfb92d14SAndroid Build Coastguard Worker * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18*cfb92d14SAndroid Build Coastguard Worker * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19*cfb92d14SAndroid Build Coastguard Worker * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20*cfb92d14SAndroid Build Coastguard Worker * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21*cfb92d14SAndroid Build Coastguard Worker * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22*cfb92d14SAndroid Build Coastguard Worker * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23*cfb92d14SAndroid Build Coastguard Worker * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24*cfb92d14SAndroid Build Coastguard Worker * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25*cfb92d14SAndroid Build Coastguard Worker * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26*cfb92d14SAndroid Build Coastguard Worker * POSSIBILITY OF SUCH DAMAGE.
27*cfb92d14SAndroid Build Coastguard Worker */
28*cfb92d14SAndroid Build Coastguard Worker
29*cfb92d14SAndroid Build Coastguard Worker /**
30*cfb92d14SAndroid Build Coastguard Worker * @file
31*cfb92d14SAndroid Build Coastguard Worker * This file implements a simple CLI for the Joiner role.
32*cfb92d14SAndroid Build Coastguard Worker */
33*cfb92d14SAndroid Build Coastguard Worker
34*cfb92d14SAndroid Build Coastguard Worker #include "cli_joiner.hpp"
35*cfb92d14SAndroid Build Coastguard Worker
36*cfb92d14SAndroid Build Coastguard Worker #include <inttypes.h>
37*cfb92d14SAndroid Build Coastguard Worker
38*cfb92d14SAndroid Build Coastguard Worker #include "cli/cli.hpp"
39*cfb92d14SAndroid Build Coastguard Worker
40*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_CONFIG_JOINER_ENABLE
41*cfb92d14SAndroid Build Coastguard Worker
42*cfb92d14SAndroid Build Coastguard Worker namespace ot {
43*cfb92d14SAndroid Build Coastguard Worker namespace Cli {
44*cfb92d14SAndroid Build Coastguard Worker
Process(Arg aArgs[])45*cfb92d14SAndroid Build Coastguard Worker template <> otError Joiner::Process<Cmd("discerner")>(Arg aArgs[])
46*cfb92d14SAndroid Build Coastguard Worker {
47*cfb92d14SAndroid Build Coastguard Worker otError error = OT_ERROR_INVALID_ARGS;
48*cfb92d14SAndroid Build Coastguard Worker
49*cfb92d14SAndroid Build Coastguard Worker /**
50*cfb92d14SAndroid Build Coastguard Worker * @cli joiner discerner
51*cfb92d14SAndroid Build Coastguard Worker * @code
52*cfb92d14SAndroid Build Coastguard Worker * joiner discerner
53*cfb92d14SAndroid Build Coastguard Worker * 0xabc/12
54*cfb92d14SAndroid Build Coastguard Worker * Done
55*cfb92d14SAndroid Build Coastguard Worker * @endcode
56*cfb92d14SAndroid Build Coastguard Worker * @par api_copy
57*cfb92d14SAndroid Build Coastguard Worker * #otJoinerGetDiscerner
58*cfb92d14SAndroid Build Coastguard Worker */
59*cfb92d14SAndroid Build Coastguard Worker if (aArgs[0].IsEmpty())
60*cfb92d14SAndroid Build Coastguard Worker {
61*cfb92d14SAndroid Build Coastguard Worker const otJoinerDiscerner *discerner = otJoinerGetDiscerner(GetInstancePtr());
62*cfb92d14SAndroid Build Coastguard Worker
63*cfb92d14SAndroid Build Coastguard Worker VerifyOrExit(discerner != nullptr, error = OT_ERROR_NOT_FOUND);
64*cfb92d14SAndroid Build Coastguard Worker
65*cfb92d14SAndroid Build Coastguard Worker if (discerner->mValue <= 0xffffffff)
66*cfb92d14SAndroid Build Coastguard Worker {
67*cfb92d14SAndroid Build Coastguard Worker OutputLine("0x%lx/%u", static_cast<unsigned long>(discerner->mValue & 0xffffffff), discerner->mLength);
68*cfb92d14SAndroid Build Coastguard Worker }
69*cfb92d14SAndroid Build Coastguard Worker else
70*cfb92d14SAndroid Build Coastguard Worker {
71*cfb92d14SAndroid Build Coastguard Worker OutputLine("0x%lx%08lx/%u", static_cast<unsigned long>(discerner->mValue >> 32),
72*cfb92d14SAndroid Build Coastguard Worker static_cast<unsigned long>(discerner->mValue & 0xffffffff), discerner->mLength);
73*cfb92d14SAndroid Build Coastguard Worker }
74*cfb92d14SAndroid Build Coastguard Worker
75*cfb92d14SAndroid Build Coastguard Worker error = OT_ERROR_NONE;
76*cfb92d14SAndroid Build Coastguard Worker }
77*cfb92d14SAndroid Build Coastguard Worker else
78*cfb92d14SAndroid Build Coastguard Worker {
79*cfb92d14SAndroid Build Coastguard Worker otJoinerDiscerner discerner;
80*cfb92d14SAndroid Build Coastguard Worker
81*cfb92d14SAndroid Build Coastguard Worker ClearAllBytes(discerner);
82*cfb92d14SAndroid Build Coastguard Worker
83*cfb92d14SAndroid Build Coastguard Worker /**
84*cfb92d14SAndroid Build Coastguard Worker * @cli joiner discerner clear
85*cfb92d14SAndroid Build Coastguard Worker * @code
86*cfb92d14SAndroid Build Coastguard Worker * joiner discerner clear
87*cfb92d14SAndroid Build Coastguard Worker * Done
88*cfb92d14SAndroid Build Coastguard Worker * @endcode
89*cfb92d14SAndroid Build Coastguard Worker * @par
90*cfb92d14SAndroid Build Coastguard Worker * Clear the %Joiner discerner.
91*cfb92d14SAndroid Build Coastguard Worker */
92*cfb92d14SAndroid Build Coastguard Worker if (aArgs[0] == "clear")
93*cfb92d14SAndroid Build Coastguard Worker {
94*cfb92d14SAndroid Build Coastguard Worker error = otJoinerSetDiscerner(GetInstancePtr(), nullptr);
95*cfb92d14SAndroid Build Coastguard Worker }
96*cfb92d14SAndroid Build Coastguard Worker /**
97*cfb92d14SAndroid Build Coastguard Worker * @cli joiner discerner (set)
98*cfb92d14SAndroid Build Coastguard Worker * @code
99*cfb92d14SAndroid Build Coastguard Worker * joiner discerner 0xabc/12
100*cfb92d14SAndroid Build Coastguard Worker * Done
101*cfb92d14SAndroid Build Coastguard Worker * @endcode
102*cfb92d14SAndroid Build Coastguard Worker * @cparam joiner discerner @ca{discerner}
103*cfb92d14SAndroid Build Coastguard Worker * * Use `{number}/{length}` to set the `discerner`.
104*cfb92d14SAndroid Build Coastguard Worker * * `joiner discerner clear` sets `aDiscerner` to `nullptr`.
105*cfb92d14SAndroid Build Coastguard Worker * @par api_copy
106*cfb92d14SAndroid Build Coastguard Worker * #otJoinerSetDiscerner
107*cfb92d14SAndroid Build Coastguard Worker */
108*cfb92d14SAndroid Build Coastguard Worker else
109*cfb92d14SAndroid Build Coastguard Worker {
110*cfb92d14SAndroid Build Coastguard Worker VerifyOrExit(aArgs[1].IsEmpty());
111*cfb92d14SAndroid Build Coastguard Worker SuccessOrExit(ParseJoinerDiscerner(aArgs[0], discerner));
112*cfb92d14SAndroid Build Coastguard Worker error = otJoinerSetDiscerner(GetInstancePtr(), &discerner);
113*cfb92d14SAndroid Build Coastguard Worker }
114*cfb92d14SAndroid Build Coastguard Worker }
115*cfb92d14SAndroid Build Coastguard Worker
116*cfb92d14SAndroid Build Coastguard Worker exit:
117*cfb92d14SAndroid Build Coastguard Worker return error;
118*cfb92d14SAndroid Build Coastguard Worker }
119*cfb92d14SAndroid Build Coastguard Worker
120*cfb92d14SAndroid Build Coastguard Worker /**
121*cfb92d14SAndroid Build Coastguard Worker * @cli joiner id
122*cfb92d14SAndroid Build Coastguard Worker * @code
123*cfb92d14SAndroid Build Coastguard Worker * joiner id
124*cfb92d14SAndroid Build Coastguard Worker * d65e64fa83f81cf7
125*cfb92d14SAndroid Build Coastguard Worker * Done
126*cfb92d14SAndroid Build Coastguard Worker * @endcode
127*cfb92d14SAndroid Build Coastguard Worker * @par api_copy
128*cfb92d14SAndroid Build Coastguard Worker * #otJoinerGetId
129*cfb92d14SAndroid Build Coastguard Worker */
Process(Arg aArgs[])130*cfb92d14SAndroid Build Coastguard Worker template <> otError Joiner::Process<Cmd("id")>(Arg aArgs[])
131*cfb92d14SAndroid Build Coastguard Worker {
132*cfb92d14SAndroid Build Coastguard Worker OT_UNUSED_VARIABLE(aArgs);
133*cfb92d14SAndroid Build Coastguard Worker
134*cfb92d14SAndroid Build Coastguard Worker OutputExtAddressLine(*otJoinerGetId(GetInstancePtr()));
135*cfb92d14SAndroid Build Coastguard Worker
136*cfb92d14SAndroid Build Coastguard Worker return OT_ERROR_NONE;
137*cfb92d14SAndroid Build Coastguard Worker }
138*cfb92d14SAndroid Build Coastguard Worker
139*cfb92d14SAndroid Build Coastguard Worker /**
140*cfb92d14SAndroid Build Coastguard Worker * @cli joiner start
141*cfb92d14SAndroid Build Coastguard Worker * @code
142*cfb92d14SAndroid Build Coastguard Worker * joiner start J01NM3
143*cfb92d14SAndroid Build Coastguard Worker * Done
144*cfb92d14SAndroid Build Coastguard Worker * @endcode
145*cfb92d14SAndroid Build Coastguard Worker * @cparam joiner start @ca{joining-device-credential} [@ca{provisioning-url}]
146*cfb92d14SAndroid Build Coastguard Worker * * `joining-device-credential`: %Joiner Passphrase. Must be a string of all uppercase alphanumeric
147*cfb92d14SAndroid Build Coastguard Worker * characters (0-9 and A-Y, excluding I, O, Q, and Z for readability), with a length between 6 and
148*cfb92d14SAndroid Build Coastguard Worker * 32 characters.
149*cfb92d14SAndroid Build Coastguard Worker * * `provisioning-url`: Provisioning URL for the %Joiner (optional).
150*cfb92d14SAndroid Build Coastguard Worker * @par api_copy
151*cfb92d14SAndroid Build Coastguard Worker * #otJoinerStart
152*cfb92d14SAndroid Build Coastguard Worker */
Process(Arg aArgs[])153*cfb92d14SAndroid Build Coastguard Worker template <> otError Joiner::Process<Cmd("start")>(Arg aArgs[])
154*cfb92d14SAndroid Build Coastguard Worker {
155*cfb92d14SAndroid Build Coastguard Worker otError error;
156*cfb92d14SAndroid Build Coastguard Worker
157*cfb92d14SAndroid Build Coastguard Worker VerifyOrExit(!aArgs[0].IsEmpty(), error = OT_ERROR_INVALID_ARGS);
158*cfb92d14SAndroid Build Coastguard Worker
159*cfb92d14SAndroid Build Coastguard Worker error = otJoinerStart(GetInstancePtr(),
160*cfb92d14SAndroid Build Coastguard Worker aArgs[0].GetCString(), // aPskd
161*cfb92d14SAndroid Build Coastguard Worker aArgs[1].GetCString(), // aProvisioningUrl (`nullptr` if aArgs[1] is empty)
162*cfb92d14SAndroid Build Coastguard Worker PACKAGE_NAME, // aVendorName
163*cfb92d14SAndroid Build Coastguard Worker OPENTHREAD_CONFIG_PLATFORM_INFO, // aVendorModel
164*cfb92d14SAndroid Build Coastguard Worker PACKAGE_VERSION, // aVendorSwVersion
165*cfb92d14SAndroid Build Coastguard Worker nullptr, // aVendorData
166*cfb92d14SAndroid Build Coastguard Worker &Joiner::HandleCallback, this);
167*cfb92d14SAndroid Build Coastguard Worker
168*cfb92d14SAndroid Build Coastguard Worker exit:
169*cfb92d14SAndroid Build Coastguard Worker return error;
170*cfb92d14SAndroid Build Coastguard Worker }
171*cfb92d14SAndroid Build Coastguard Worker
172*cfb92d14SAndroid Build Coastguard Worker /**
173*cfb92d14SAndroid Build Coastguard Worker * @cli joiner stop
174*cfb92d14SAndroid Build Coastguard Worker * @code
175*cfb92d14SAndroid Build Coastguard Worker * joiner stop
176*cfb92d14SAndroid Build Coastguard Worker * Done
177*cfb92d14SAndroid Build Coastguard Worker * @endcode
178*cfb92d14SAndroid Build Coastguard Worker * @par api_copy
179*cfb92d14SAndroid Build Coastguard Worker * #otJoinerStop
180*cfb92d14SAndroid Build Coastguard Worker */
Process(Arg aArgs[])181*cfb92d14SAndroid Build Coastguard Worker template <> otError Joiner::Process<Cmd("stop")>(Arg aArgs[])
182*cfb92d14SAndroid Build Coastguard Worker {
183*cfb92d14SAndroid Build Coastguard Worker OT_UNUSED_VARIABLE(aArgs);
184*cfb92d14SAndroid Build Coastguard Worker
185*cfb92d14SAndroid Build Coastguard Worker otJoinerStop(GetInstancePtr());
186*cfb92d14SAndroid Build Coastguard Worker
187*cfb92d14SAndroid Build Coastguard Worker return OT_ERROR_NONE;
188*cfb92d14SAndroid Build Coastguard Worker }
189*cfb92d14SAndroid Build Coastguard Worker
190*cfb92d14SAndroid Build Coastguard Worker /**
191*cfb92d14SAndroid Build Coastguard Worker * @cli joiner state
192*cfb92d14SAndroid Build Coastguard Worker * @code
193*cfb92d14SAndroid Build Coastguard Worker * joiner state
194*cfb92d14SAndroid Build Coastguard Worker * Idle
195*cfb92d14SAndroid Build Coastguard Worker * Done
196*cfb92d14SAndroid Build Coastguard Worker * @endcode
197*cfb92d14SAndroid Build Coastguard Worker * @par api_copy
198*cfb92d14SAndroid Build Coastguard Worker * #otJoinerGetState
199*cfb92d14SAndroid Build Coastguard Worker * @par
200*cfb92d14SAndroid Build Coastguard Worker * Returns one of the following states:
201*cfb92d14SAndroid Build Coastguard Worker * * `Idle`
202*cfb92d14SAndroid Build Coastguard Worker * * `Discover`
203*cfb92d14SAndroid Build Coastguard Worker * * `Connecting`
204*cfb92d14SAndroid Build Coastguard Worker * * `Connected`
205*cfb92d14SAndroid Build Coastguard Worker * * `Entrust`
206*cfb92d14SAndroid Build Coastguard Worker * * `Joined`
207*cfb92d14SAndroid Build Coastguard Worker */
Process(Arg aArgs[])208*cfb92d14SAndroid Build Coastguard Worker template <> otError Joiner::Process<Cmd("state")>(Arg aArgs[])
209*cfb92d14SAndroid Build Coastguard Worker {
210*cfb92d14SAndroid Build Coastguard Worker OT_UNUSED_VARIABLE(aArgs);
211*cfb92d14SAndroid Build Coastguard Worker
212*cfb92d14SAndroid Build Coastguard Worker OutputLine("%s", otJoinerStateToString(otJoinerGetState(GetInstancePtr())));
213*cfb92d14SAndroid Build Coastguard Worker
214*cfb92d14SAndroid Build Coastguard Worker return OT_ERROR_NONE;
215*cfb92d14SAndroid Build Coastguard Worker }
216*cfb92d14SAndroid Build Coastguard Worker
Process(Arg aArgs[])217*cfb92d14SAndroid Build Coastguard Worker otError Joiner::Process(Arg aArgs[])
218*cfb92d14SAndroid Build Coastguard Worker {
219*cfb92d14SAndroid Build Coastguard Worker #define CmdEntry(aCommandString) \
220*cfb92d14SAndroid Build Coastguard Worker { \
221*cfb92d14SAndroid Build Coastguard Worker aCommandString, &Joiner::Process<Cmd(aCommandString)> \
222*cfb92d14SAndroid Build Coastguard Worker }
223*cfb92d14SAndroid Build Coastguard Worker
224*cfb92d14SAndroid Build Coastguard Worker static constexpr Command kCommands[] = {
225*cfb92d14SAndroid Build Coastguard Worker CmdEntry("discerner"), CmdEntry("id"), CmdEntry("start"), CmdEntry("state"), CmdEntry("stop"),
226*cfb92d14SAndroid Build Coastguard Worker };
227*cfb92d14SAndroid Build Coastguard Worker
228*cfb92d14SAndroid Build Coastguard Worker #undef CmdEntry
229*cfb92d14SAndroid Build Coastguard Worker
230*cfb92d14SAndroid Build Coastguard Worker static_assert(BinarySearch::IsSorted(kCommands), "kCommands is not sorted");
231*cfb92d14SAndroid Build Coastguard Worker
232*cfb92d14SAndroid Build Coastguard Worker otError error = OT_ERROR_INVALID_COMMAND;
233*cfb92d14SAndroid Build Coastguard Worker const Command *command;
234*cfb92d14SAndroid Build Coastguard Worker
235*cfb92d14SAndroid Build Coastguard Worker /**
236*cfb92d14SAndroid Build Coastguard Worker * @cli joiner help
237*cfb92d14SAndroid Build Coastguard Worker * @code
238*cfb92d14SAndroid Build Coastguard Worker * joiner help
239*cfb92d14SAndroid Build Coastguard Worker * help
240*cfb92d14SAndroid Build Coastguard Worker * id
241*cfb92d14SAndroid Build Coastguard Worker * start
242*cfb92d14SAndroid Build Coastguard Worker * state
243*cfb92d14SAndroid Build Coastguard Worker * stop
244*cfb92d14SAndroid Build Coastguard Worker * Done
245*cfb92d14SAndroid Build Coastguard Worker * @endcode
246*cfb92d14SAndroid Build Coastguard Worker * @par
247*cfb92d14SAndroid Build Coastguard Worker * Print the `joiner` help menu.
248*cfb92d14SAndroid Build Coastguard Worker */
249*cfb92d14SAndroid Build Coastguard Worker if (aArgs[0].IsEmpty() || (aArgs[0] == "help"))
250*cfb92d14SAndroid Build Coastguard Worker {
251*cfb92d14SAndroid Build Coastguard Worker OutputCommandTable(kCommands);
252*cfb92d14SAndroid Build Coastguard Worker ExitNow(error = aArgs[0].IsEmpty() ? error : OT_ERROR_NONE);
253*cfb92d14SAndroid Build Coastguard Worker }
254*cfb92d14SAndroid Build Coastguard Worker
255*cfb92d14SAndroid Build Coastguard Worker command = BinarySearch::Find(aArgs[0].GetCString(), kCommands);
256*cfb92d14SAndroid Build Coastguard Worker VerifyOrExit(command != nullptr);
257*cfb92d14SAndroid Build Coastguard Worker
258*cfb92d14SAndroid Build Coastguard Worker error = (this->*command->mHandler)(aArgs + 1);
259*cfb92d14SAndroid Build Coastguard Worker
260*cfb92d14SAndroid Build Coastguard Worker exit:
261*cfb92d14SAndroid Build Coastguard Worker return error;
262*cfb92d14SAndroid Build Coastguard Worker }
263*cfb92d14SAndroid Build Coastguard Worker
HandleCallback(otError aError,void * aContext)264*cfb92d14SAndroid Build Coastguard Worker void Joiner::HandleCallback(otError aError, void *aContext) { static_cast<Joiner *>(aContext)->HandleCallback(aError); }
265*cfb92d14SAndroid Build Coastguard Worker
HandleCallback(otError aError)266*cfb92d14SAndroid Build Coastguard Worker void Joiner::HandleCallback(otError aError)
267*cfb92d14SAndroid Build Coastguard Worker {
268*cfb92d14SAndroid Build Coastguard Worker switch (aError)
269*cfb92d14SAndroid Build Coastguard Worker {
270*cfb92d14SAndroid Build Coastguard Worker case OT_ERROR_NONE:
271*cfb92d14SAndroid Build Coastguard Worker OutputLine("Join success");
272*cfb92d14SAndroid Build Coastguard Worker break;
273*cfb92d14SAndroid Build Coastguard Worker
274*cfb92d14SAndroid Build Coastguard Worker default:
275*cfb92d14SAndroid Build Coastguard Worker OutputLine("Join failed [%s]", otThreadErrorToString(aError));
276*cfb92d14SAndroid Build Coastguard Worker break;
277*cfb92d14SAndroid Build Coastguard Worker }
278*cfb92d14SAndroid Build Coastguard Worker }
279*cfb92d14SAndroid Build Coastguard Worker
280*cfb92d14SAndroid Build Coastguard Worker } // namespace Cli
281*cfb92d14SAndroid Build Coastguard Worker } // namespace ot
282*cfb92d14SAndroid Build Coastguard Worker
283*cfb92d14SAndroid Build Coastguard Worker #endif // OPENTHREAD_CONFIG_JOINER_ENABLE
284