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