1 /*
2  *  Copyright (c) 2018, 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 BorderAgent role.
32  */
33 
34 #ifndef BORDER_AGENT_HPP_
35 #define BORDER_AGENT_HPP_
36 
37 #include "openthread-core-config.h"
38 
39 #if OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE
40 
41 #include <openthread/border_agent.h>
42 
43 #include "common/as_core_type.hpp"
44 #include "common/heap_allocatable.hpp"
45 #include "common/locator.hpp"
46 #include "common/non_copyable.hpp"
47 #include "common/notifier.hpp"
48 #include "common/tasklet.hpp"
49 #include "meshcop/secure_transport.hpp"
50 #include "net/udp6.hpp"
51 #include "thread/tmf.hpp"
52 #include "thread/uri_paths.hpp"
53 
54 namespace ot {
55 
56 namespace MeshCoP {
57 
58 class BorderAgent : public InstanceLocator, private NonCopyable
59 {
60     friend class ot::Notifier;
61     friend class Tmf::Agent;
62     friend class Tmf::SecureAgent;
63 
64 public:
65     /**
66      * Minimum length of the ephemeral key string.
67      *
68      */
69     static constexpr uint16_t kMinEphemeralKeyLength = OT_BORDER_AGENT_MIN_EPHEMERAL_KEY_LENGTH;
70 
71     /**
72      * Maximum length of the ephemeral key string.
73      *
74      */
75     static constexpr uint16_t kMaxEphemeralKeyLength = OT_BORDER_AGENT_MAX_EPHEMERAL_KEY_LENGTH;
76 
77     /**
78      * Default ephemeral key timeout interval in milliseconds.
79      *
80      */
81     static constexpr uint32_t kDefaultEphemeralKeyTimeout = OT_BORDER_AGENT_DEFAULT_EPHEMERAL_KEY_TIMEOUT;
82 
83     /**
84      * Maximum ephemeral key timeout interval in milliseconds.
85      *
86      */
87     static constexpr uint32_t kMaxEphemeralKeyTimeout = OT_BORDER_AGENT_MAX_EPHEMERAL_KEY_TIMEOUT;
88 
89     typedef otBorderAgentId Id; ///< Border Agent ID.
90 
91     /**
92      * Defines the Border Agent state.
93      *
94      */
95     enum State : uint8_t
96     {
97         kStateStopped = OT_BORDER_AGENT_STATE_STOPPED, ///< Border agent is stopped/disabled.
98         kStateStarted = OT_BORDER_AGENT_STATE_STARTED, ///< Border agent is started.
99         kStateActive  = OT_BORDER_AGENT_STATE_ACTIVE,  ///< Border agent is connected with external commissioner.
100     };
101 
102     /**
103      * Initializes the `BorderAgent` object.
104      *
105      * @param[in]  aInstance     A reference to the OpenThread instance.
106      *
107      */
108     explicit BorderAgent(Instance &aInstance);
109 
110 #if OPENTHREAD_CONFIG_BORDER_AGENT_ID_ENABLE
111     /**
112      * Gets the randomly generated Border Agent ID.
113      *
114      * The ID is saved in persistent storage and survives reboots. The typical use case of the ID is to
115      * be published in the MeshCoP mDNS service as the `id` TXT value for the client to identify this
116      * Border Router/Agent device.
117      *
118      * @param[out] aId  Reference to return the Border Agent ID.
119      *
120      * @retval kErrorNone  If successfully retrieved the Border Agent ID.
121      * @retval ...         If failed to retrieve the Border Agent ID.
122      *
123      */
124     Error GetId(Id &aId);
125 
126     /**
127      * Sets the Border Agent ID.
128      *
129      * The Border Agent ID will be saved in persistent storage and survive reboots. It's required
130      * to set the ID only once after factory reset. If the ID has never been set by calling this
131      * method, a random ID will be generated and returned when `GetId()` is called.
132      *
133      * @param[out] aId  specifies the Border Agent ID.
134      *
135      * @retval kErrorNone  If successfully set the Border Agent ID.
136      * @retval ...         If failed to set the Border Agent ID.
137      *
138      */
139     Error SetId(const Id &aId);
140 #endif
141 
142     /**
143      * Gets the UDP port of this service.
144      *
145      * @returns  UDP port number.
146      *
147      */
148     uint16_t GetUdpPort(void) const;
149 
150     /**
151      * Starts the Border Agent service.
152      *
153      */
Start(void)154     void Start(void) { IgnoreError(Start(kUdpPort)); }
155 
156     /**
157      * Stops the Border Agent service.
158      *
159      */
160     void Stop(void);
161 
162     /**
163      * Gets the state of the Border Agent service.
164      *
165      * @returns The state of the Border Agent service.
166      *
167      */
GetState(void) const168     State GetState(void) const { return mState; }
169 
170 #if OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE
171     /**
172      * Sets the ephemeral key for a given timeout duration.
173      *
174      * The ephemeral key can be set when the Border Agent is already running and is not currently connected to any
175      * external commissioner (i.e., it is in `kStateStarted` state).
176      *
177      * The given @p aKeyString is directly used as the ephemeral PSK (excluding the trailing null `\0` character). Its
178      * length must be between `kMinEphemeralKeyLength` and `kMaxEphemeralKeyLength`, inclusive.
179      *
180      * Setting the ephemeral key again before a previously set one is timed out will replace the previous one and will
181      * reset the timeout.
182      *
183      * While the timeout interval is in effect, the ephemeral key can be used only once by an external commissioner to
184      * connect. Once the commissioner disconnects, the ephemeral key is cleared, and Border Agent reverts to using
185      * PSKc.
186      *
187      * @param[in] aKeyString   The ephemeral key.
188      * @param[in] aTimeout     The timeout duration in milliseconds to use the ephemeral key.
189      *                         If zero, the default `kDefaultEphemeralKeyTimeout` value will be used.
190      *                         If the timeout value is larger than `kMaxEphemeralKeyTimeout`, the max value will be
191      *                         used instead.
192      * @param[in] aUdpPort     The UDP port to use with ephemeral key. If UDP port is zero, an ephemeral port will be
193      *                         used. `GetUdpPort()` will return the current UDP port being used.
194      *
195      * @retval kErrorNone           Successfully set the ephemeral key.
196      * @retval kErrorInvalidState   Agent is not running or connected to external commissioner.
197      * @retval kErrorInvalidArgs    The given @p aKeyString is not valid.
198      * @retval kErrorFailed         Failed to set the key (e.g., could not bind to UDP port).
199      *
200      */
201     Error SetEphemeralKey(const char *aKeyString, uint32_t aTimeout, uint16_t aUdpPort);
202 
203     /**
204      * Cancels the ephemeral key in use if any.
205      *
206      * Can be used to cancel a previously set ephemeral key before it times out. If the Border Agent is not running or
207      * there is no ephemeral key in use, calling this function has no effect.
208      *
209      * If a commissioner is connected using the ephemeral key and is currently active, calling this method does not
210      * change its state. In this case the `IsEphemeralKeyActive()` will continue to return `true` until the commissioner
211      * disconnects.
212      *
213      */
214     void ClearEphemeralKey(void);
215 
216     /**
217      * Indicates whether or not an ephemeral key is currently active.
218      *
219      * @retval TRUE    An ephemeral key is active.
220      * @retval FALSE   No ephemeral key is active.
221      *
222      */
IsEphemeralKeyActive(void) const223     bool IsEphemeralKeyActive(void) const { return mUsingEphemeralKey; }
224 
225     /**
226      * Callback function pointer to notify when there is any changes related to use of ephemeral key by Border Agent.
227      *
228      *
229      */
230     typedef otBorderAgentEphemeralKeyCallback EphemeralKeyCallback;
231 
SetEphemeralKeyCallback(EphemeralKeyCallback aCallback,void * aContext)232     void SetEphemeralKeyCallback(EphemeralKeyCallback aCallback, void *aContext)
233     {
234         mEphemeralKeyCallback.Set(aCallback, aContext);
235     }
236 
237 #endif // OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE
238 
239     /**
240      * Returns the UDP Proxy port to which the commissioner is currently
241      * bound.
242      *
243      * @returns  The current UDP Proxy port or 0 if no Proxy Transmit has been received yet.
244      *
245      */
GetUdpProxyPort(void) const246     uint16_t GetUdpProxyPort(void) const { return mUdpProxyPort; }
247 
248 private:
249     static_assert(kMaxEphemeralKeyLength <= SecureTransport::kPskMaxLength,
250                   "Max ephemeral key length is larger than max PSK len");
251 
252     static constexpr uint16_t kUdpPort          = OPENTHREAD_CONFIG_BORDER_AGENT_UDP_PORT;
253     static constexpr uint32_t kKeepAliveTimeout = 50 * 1000; // Timeout to reject a commissioner (in msec)
254 
255 #if OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE
256     static constexpr uint16_t kMaxEphemeralKeyConnectionAttempts = 10;
257 #endif
258 
259     class ForwardContext : public InstanceLocatorInit, public Heap::Allocatable<ForwardContext>
260     {
261     public:
262         Error    Init(Instance &aInstance, const Coap::Message &aMessage, bool aPetition, bool aSeparate);
IsPetition(void) const263         bool     IsPetition(void) const { return mPetition; }
GetMessageId(void) const264         uint16_t GetMessageId(void) const { return mMessageId; }
265         Error    ToHeader(Coap::Message &aMessage, uint8_t aCode) const;
266 
267     private:
268         uint16_t mMessageId;                             // The CoAP Message ID of the original request.
269         bool     mPetition : 1;                          // Whether the forwarding request is leader petition.
270         bool     mSeparate : 1;                          // Whether the original request expects separate response.
271         uint8_t  mTokenLength : 4;                       // The CoAP Token Length of the original request.
272         uint8_t  mType : 2;                              // The CoAP Type of the original request.
273         uint8_t  mToken[Coap::Message::kMaxTokenLength]; // The CoAP Token of the original request.
274     };
275 
276     Error Start(uint16_t aUdpPort);
277     Error Start(uint16_t aUdpPort, const uint8_t *aPsk, uint8_t aPskLength);
278 
279     void HandleNotifierEvents(Events aEvents);
280 
281     Coap::Message::Code CoapCodeFromError(Error aError);
282     Error               SendMessage(Coap::Message &aMessage);
283     void                SendErrorMessage(const ForwardContext &aForwardContext, Error aError);
284     void                SendErrorMessage(const Coap::Message &aRequest, bool aSeparate, Error aError);
285 
286     static void HandleConnected(bool aConnected, void *aContext);
287     void        HandleConnected(bool aConnected);
288 
289     template <Uri kUri> void HandleTmf(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
290 
291     void HandleTimeout(void);
292 
293 #if OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE
294     void        RestartAfterRemovingEphemeralKey(void);
295     void        HandleEphemeralKeyTimeout(void);
296     void        InvokeEphemeralKeyCallback(void);
297     static void HandleSecureAgentStopped(void *aContext);
298     void        HandleSecureAgentStopped(void);
299 #endif
300 
301     static void HandleCoapResponse(void                *aContext,
302                                    otMessage           *aMessage,
303                                    const otMessageInfo *aMessageInfo,
304                                    Error                aResult);
305     void  HandleCoapResponse(const ForwardContext &aForwardContext, const Coap::Message *aResponse, Error aResult);
306     Error ForwardToLeader(const Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo, Uri aUri);
307     Error ForwardToCommissioner(Coap::Message &aForwardMessage, const Message &aMessage);
308     static bool HandleUdpReceive(void *aContext, const otMessage *aMessage, const otMessageInfo *aMessageInfo);
309     bool        HandleUdpReceive(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
310 
311     using TimeoutTimer = TimerMilliIn<BorderAgent, &BorderAgent::HandleTimeout>;
312 #if OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE
313     using EphemeralKeyTimer = TimerMilliIn<BorderAgent, &BorderAgent::HandleEphemeralKeyTimeout>;
314     using EphemeralKeyTask  = TaskletIn<BorderAgent, &BorderAgent::InvokeEphemeralKeyCallback>;
315 #endif
316 
317     State                      mState;
318     uint16_t                   mUdpProxyPort;
319     Ip6::Udp::Receiver         mUdpReceiver;
320     Ip6::Netif::UnicastAddress mCommissionerAloc;
321     TimeoutTimer               mTimer;
322 #if OPENTHREAD_CONFIG_BORDER_AGENT_ID_ENABLE
323     Id   mId;
324     bool mIdInitialized;
325 #endif
326 #if OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE
327     bool                           mUsingEphemeralKey;
328     uint16_t                       mOldUdpPort;
329     EphemeralKeyTimer              mEphemeralKeyTimer;
330     EphemeralKeyTask               mEphemeralKeyTask;
331     Callback<EphemeralKeyCallback> mEphemeralKeyCallback;
332 #endif
333 };
334 
335 DeclareTmfHandler(BorderAgent, kUriRelayRx);
336 DeclareTmfHandler(BorderAgent, kUriCommissionerPetition);
337 DeclareTmfHandler(BorderAgent, kUriCommissionerKeepAlive);
338 DeclareTmfHandler(BorderAgent, kUriRelayTx);
339 DeclareTmfHandler(BorderAgent, kUriCommissionerGet);
340 DeclareTmfHandler(BorderAgent, kUriCommissionerSet);
341 DeclareTmfHandler(BorderAgent, kUriActiveGet);
342 DeclareTmfHandler(BorderAgent, kUriActiveSet);
343 DeclareTmfHandler(BorderAgent, kUriPendingGet);
344 DeclareTmfHandler(BorderAgent, kUriPendingSet);
345 DeclareTmfHandler(BorderAgent, kUriProxyTx);
346 
347 } // namespace MeshCoP
348 
349 DefineMapEnum(otBorderAgentState, MeshCoP::BorderAgent::State);
350 DefineCoreType(otBorderAgentId, MeshCoP::BorderAgent::Id);
351 
352 } // namespace ot
353 
354 #endif // OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE
355 
356 #endif // BORDER_AGENT_HPP_
357