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