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 includes definitions for the Joiner role.
32  */
33 
34 #ifndef JOINER_HPP_
35 #define JOINER_HPP_
36 
37 #include "openthread-core-config.h"
38 
39 #if OPENTHREAD_CONFIG_JOINER_ENABLE
40 
41 #include <openthread/joiner.h>
42 
43 #include "coap/coap_message.hpp"
44 #include "coap/coap_secure.hpp"
45 #include "common/as_core_type.hpp"
46 #include "common/callback.hpp"
47 #include "common/locator.hpp"
48 #include "common/log.hpp"
49 #include "common/message.hpp"
50 #include "common/non_copyable.hpp"
51 #include "mac/mac_types.hpp"
52 #include "meshcop/meshcop.hpp"
53 #include "meshcop/meshcop_tlvs.hpp"
54 #include "meshcop/secure_transport.hpp"
55 #include "thread/discover_scanner.hpp"
56 #include "thread/tmf.hpp"
57 
58 namespace ot {
59 
60 namespace MeshCoP {
61 
62 class Joiner : public InstanceLocator, private NonCopyable
63 {
64     friend class Tmf::Agent;
65 
66 public:
67     /**
68      * Type defines the Joiner State.
69      *
70      */
71     enum State : uint8_t
72     {
73         kStateIdle      = OT_JOINER_STATE_IDLE,
74         kStateDiscover  = OT_JOINER_STATE_DISCOVER,
75         kStateConnect   = OT_JOINER_STATE_CONNECT,
76         kStateConnected = OT_JOINER_STATE_CONNECTED,
77         kStateEntrust   = OT_JOINER_STATE_ENTRUST,
78         kStateJoined    = OT_JOINER_STATE_JOINED,
79     };
80 
81     /**
82      * Initializes the Joiner object.
83      *
84      * @param[in]  aInstance     A reference to the OpenThread instance.
85      *
86      */
87     explicit Joiner(Instance &aInstance);
88 
89     /**
90      * Starts the Joiner service.
91      *
92      * @param[in]  aPskd             A pointer to the PSKd.
93      * @param[in]  aProvisioningUrl  A pointer to the Provisioning URL (may be `nullptr`).
94      * @param[in]  aVendorName       A pointer to the Vendor Name (may be `nullptr`).
95      * @param[in]  aVendorModel      A pointer to the Vendor Model (may be `nullptr`).
96      * @param[in]  aVendorSwVersion  A pointer to the Vendor SW Version (may be `nullptr`).
97      * @param[in]  aVendorData       A pointer to the Vendor Data (may be `nullptr`).
98      * @param[in]  aCallback         A pointer to a function that is called when the join operation completes.
99      * @param[in]  aContext          A pointer to application-specific context.
100      *
101      * @retval kErrorNone          Successfully started the Joiner service.
102      * @retval kErrorBusy          The previous attempt is still on-going.
103      * @retval kErrorInvalidState  The IPv6 stack is not enabled or Thread stack is fully enabled.
104      *
105      */
106     Error Start(const char      *aPskd,
107                 const char      *aProvisioningUrl,
108                 const char      *aVendorName,
109                 const char      *aVendorModel,
110                 const char      *aVendorSwVersion,
111                 const char      *aVendorData,
112                 otJoinerCallback aCallback,
113                 void            *aContext);
114 
115     /**
116      * Stops the Joiner service.
117      *
118      */
119     void Stop(void);
120 
121     /**
122      * Gets the Joiner State.
123      *
124      * @returns The Joiner state (see `State`).
125      *
126      */
GetState(void) const127     State GetState(void) const { return mState; }
128 
129     /**
130      * Retrieves the Joiner ID.
131      *
132      * @returns The Joiner ID.
133      *
134      */
GetId(void) const135     const Mac::ExtAddress &GetId(void) const { return mId; }
136 
137     /**
138      * Gets the Jointer Discerner.
139      *
140      * @returns A pointer to the current Joiner Discerner or `nullptr` if none is set.
141      *
142      */
143     const JoinerDiscerner *GetDiscerner(void) const;
144 
145     /**
146      * Sets the Joiner Discerner.
147      *
148      * The Joiner Discerner is used to calculate the Joiner ID used during commissioning/joining process.
149      *
150      * By default (when a discerner is not provided or cleared), Joiner ID is derived as first 64 bits of the
151      * result of computing SHA-256 over factory-assigned IEEE EUI-64. Note that this is the main behavior expected by
152      * Thread specification.
153      *
154      * @param[in]   aDiscerner  A Joiner Discerner
155      *
156      * @retval kErrorNone          The Joiner Discerner updated successfully.
157      * @retval kErrorInvalidArgs   @p aDiscerner is not valid (specified length is not within valid range).
158      * @retval kErrorInvalidState  There is an ongoing Joining process so Joiner Discerner could not be changed.
159      *
160      */
161     Error SetDiscerner(const JoinerDiscerner &aDiscerner);
162 
163     /**
164      * Clears any previously set Joiner Discerner.
165      *
166      * When cleared, Joiner ID is derived as first 64 bits of SHA-256 of factory-assigned IEEE EUI-64.
167      *
168      * @retval kErrorNone          The Joiner Discerner cleared and Joiner ID updated.
169      * @retval kErrorInvalidState  There is an ongoing Joining process so Joiner Discerner could not be changed.
170      *
171      */
172     Error ClearDiscerner(void);
173 
174     /**
175      * Converts a given Joiner state to its human-readable string representation.
176      *
177      * @param[in] aState  The Joiner state to convert.
178      *
179      * @returns A human-readable string representation of @p aState.
180      *
181      */
182     static const char *StateToString(State aState);
183 
184 private:
185     static constexpr uint16_t kJoinerUdpPort = OPENTHREAD_CONFIG_JOINER_UDP_PORT;
186 
187     static constexpr uint32_t kConfigExtAddressDelay = 100;  // in msec.
188     static constexpr uint32_t kResponseTimeout       = 4000; ///< Max wait time to receive response (in msec).
189 
190     struct JoinerRouter
191     {
192         Mac::ExtAddress mExtAddr;
193         Mac::PanId      mPanId;
194         uint16_t        mJoinerUdpPort;
195         uint8_t         mChannel;
196         uint8_t         mPriority;
197     };
198 
199     static void HandleDiscoverResult(Mle::DiscoverScanner::ScanResult *aResult, void *aContext);
200     void        HandleDiscoverResult(Mle::DiscoverScanner::ScanResult *aResult);
201 
202     static void HandleSecureCoapClientConnect(bool aConnected, void *aContext);
203     void        HandleSecureCoapClientConnect(bool aConnected);
204 
205     static void HandleJoinerFinalizeResponse(void                *aContext,
206                                              otMessage           *aMessage,
207                                              const otMessageInfo *aMessageInfo,
208                                              Error                aResult);
209     void HandleJoinerFinalizeResponse(Coap::Message *aMessage, const Ip6::MessageInfo *aMessageInfo, Error aResult);
210 
211     template <Uri kUri> void HandleTmf(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
212 
213     void HandleTimer(void);
214 
215     void    SetState(State aState);
216     void    SetIdFromIeeeEui64(void);
217     void    SaveDiscoveredJoinerRouter(const Mle::DiscoverScanner::ScanResult &aResult);
218     void    TryNextJoinerRouter(Error aPrevError);
219     Error   Connect(JoinerRouter &aRouter);
220     void    Finish(Error aError);
221     uint8_t CalculatePriority(int8_t aRssi, bool aSteeringDataAllowsAny);
222 
223     Error PrepareJoinerFinalizeMessage(const char *aProvisioningUrl,
224                                        const char *aVendorName,
225                                        const char *aVendorModel,
226                                        const char *aVendorSwVersion,
227                                        const char *aVendorData);
228     void  FreeJoinerFinalizeMessage(void);
229     void  SendJoinerFinalize(void);
230     void  SendJoinerEntrustResponse(const Coap::Message &aRequest, const Ip6::MessageInfo &aRequestInfo);
231 
232 #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
233     void LogCertMessage(const char *aText, const Coap::Message &aMessage) const;
234 #endif
235 
236     using JoinerTimer = TimerMilliIn<Joiner, &Joiner::HandleTimer>;
237 
238     Mac::ExtAddress mId;
239     JoinerDiscerner mDiscerner;
240 
241     State mState;
242 
243     Callback<otJoinerCallback> mCallback;
244 
245     JoinerRouter mJoinerRouters[OPENTHREAD_CONFIG_JOINER_MAX_CANDIDATES];
246     uint16_t     mJoinerRouterIndex;
247 
248     Coap::Message *mFinalizeMessage;
249 
250     JoinerTimer mTimer;
251 };
252 
253 DeclareTmfHandler(Joiner, kUriJoinerEntrust);
254 
255 } // namespace MeshCoP
256 
257 DefineMapEnum(otJoinerState, MeshCoP::Joiner::State);
258 
259 } // namespace ot
260 
261 #endif // OPENTHREAD_CONFIG_JOINER_ENABLE
262 
263 #endif // JOINER_HPP_
264