xref: /aosp_15_r20/external/openthread/src/cli/cli_joiner.cpp (revision cfb92d1480a9e65faed56933e9c12405f45898b4)
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