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  * @brief
32  *   This file includes functions for the Thread Border Agent role.
33  */
34 
35 #ifndef OPENTHREAD_BORDER_AGENT_H_
36 #define OPENTHREAD_BORDER_AGENT_H_
37 
38 #include <openthread/instance.h>
39 
40 #ifdef __cplusplus
41 extern "C" {
42 #endif
43 
44 /**
45  * @addtogroup api-border-agent
46  *
47  * @brief
48  *   This module includes functions for the Thread Border Agent role.
49  *
50  * @{
51  */
52 
53 /**
54  * The length of Border Agent/Router ID in bytes.
55  */
56 #define OT_BORDER_AGENT_ID_LENGTH (16)
57 
58 /**
59  * Minimum length of the ephemeral key string.
60  */
61 #define OT_BORDER_AGENT_MIN_EPHEMERAL_KEY_LENGTH (6)
62 
63 /**
64  * Maximum length of the ephemeral key string.
65  */
66 #define OT_BORDER_AGENT_MAX_EPHEMERAL_KEY_LENGTH (32)
67 
68 /**
69  * Default ephemeral key timeout interval in milliseconds.
70  */
71 #define OT_BORDER_AGENT_DEFAULT_EPHEMERAL_KEY_TIMEOUT (2 * 60 * 1000u)
72 
73 /**
74  * Maximum ephemeral key timeout interval in milliseconds.
75  */
76 #define OT_BORDER_AGENT_MAX_EPHEMERAL_KEY_TIMEOUT (10 * 60 * 1000u)
77 
78 /**
79  * Represents a Border Agent Identifier.
80  */
81 typedef struct otBorderAgentId
82 {
83     uint8_t mId[OT_BORDER_AGENT_ID_LENGTH]; ///< Border Agent ID bytes.
84 } otBorderAgentId;
85 
86 /**
87  * Defines the Border Agent state.
88  */
89 typedef enum otBorderAgentState
90 {
91     OT_BORDER_AGENT_STATE_STOPPED = 0, ///< Border agent role is disabled.
92     OT_BORDER_AGENT_STATE_STARTED = 1, ///< Border agent is started.
93     OT_BORDER_AGENT_STATE_ACTIVE  = 2, ///< Border agent is connected with external commissioner.
94 } otBorderAgentState;
95 
96 typedef struct otBorderAgentCounters
97 {
98     uint32_t mEpskcActivations;              ///< The number of ePSKc activations
99     uint32_t mEpskcDeactivationClears;       ///< The number of ePSKc deactivations via API
100     uint32_t mEpskcDeactivationTimeouts;     ///< The number of ePSKc deactivations due to timeout
101     uint32_t mEpskcDeactivationMaxAttempts;  ///< The number of ePSKc deactivations due to reached max attempts
102     uint32_t mEpskcDeactivationDisconnects;  ///< The number of ePSKc deactivations due to commissioner disconnected
103     uint32_t mEpskcInvalidBaStateErrors;     ///< The number of invalid border agent state errors at ePSKc activation
104     uint32_t mEpskcInvalidArgsErrors;        ///< The number of invalid args errors at ePSKc activation
105     uint32_t mEpskcStartSecureSessionErrors; ///< The number of start secure session errors at ePSKc activation
106     uint32_t mEpskcSecureSessionSuccesses;   ///< The number of established secure sessions with ePSKc
107     uint32_t mEpskcSecureSessionFailures;    ///< The number of failed secure sessions with ePSKc
108     uint32_t mEpskcCommissionerPetitions;    ///< The number of successful commissioner petitions with ePSKc
109 
110     uint32_t mPskcSecureSessionSuccesses; ///< The number of established secure sessions with PSKc
111     uint32_t mPskcSecureSessionFailures;  ///< The number of failed secure sessions with PSKc
112     uint32_t mPskcCommissionerPetitions;  ///< The number of successful commissioner petitions with PSKc
113 
114     uint32_t mMgmtActiveGets;  ///< The number of MGMT_ACTIVE_GET.req sent over secure sessions
115     uint32_t mMgmtPendingGets; ///< The number of MGMT_PENDING_GET.req sent over secure sessions
116 } otBorderAgentCounters;
117 
118 /**
119  * Gets the counters of the Thread Border Agent.
120  *
121  * @param[in]  aInstance  A pointer to an OpenThread instance.
122  *
123  * @returns A pointer to the Border Agent counters.
124  */
125 const otBorderAgentCounters *otBorderAgentGetCounters(otInstance *aInstance);
126 
127 /**
128  * Gets the #otBorderAgentState of the Thread Border Agent role.
129  *
130  * @param[in]  aInstance  A pointer to an OpenThread instance.
131  *
132  * @returns The current #otBorderAgentState of the Border Agent.
133  */
134 otBorderAgentState otBorderAgentGetState(otInstance *aInstance);
135 
136 /**
137  * Gets the UDP port of the Thread Border Agent service.
138  *
139  * @param[in]  aInstance  A pointer to an OpenThread instance.
140  *
141  * @returns UDP port of the Border Agent.
142  */
143 uint16_t otBorderAgentGetUdpPort(otInstance *aInstance);
144 
145 /**
146  * Gets the randomly generated Border Agent ID.
147  *
148  * Requires `OPENTHREAD_CONFIG_BORDER_AGENT_ID_ENABLE`.
149  *
150  * The ID is saved in persistent storage and survives reboots. The typical use case of the ID is to
151  * be published in the MeshCoP mDNS service as the `id` TXT value for the client to identify this
152  * Border Router/Agent device.
153  *
154  * @param[in]    aInstance  A pointer to an OpenThread instance.
155  * @param[out]   aId        A pointer to buffer to receive the ID.
156  *
157  * @retval OT_ERROR_NONE  If successfully retrieved the Border Agent ID.
158  * @retval ...            If failed to retrieve the Border Agent ID.
159  *
160  * @sa otBorderAgentSetId
161  */
162 otError otBorderAgentGetId(otInstance *aInstance, otBorderAgentId *aId);
163 
164 /**
165  * Sets the Border Agent ID.
166  *
167  * Requires `OPENTHREAD_CONFIG_BORDER_AGENT_ID_ENABLE`.
168  *
169  * The Border Agent ID will be saved in persistent storage and survive reboots. It's required to
170  * set the ID only once after factory reset. If the ID has never been set by calling this function,
171  * a random ID will be generated and returned when `otBorderAgentGetId` is called.
172  *
173  * @param[in]    aInstance  A pointer to an OpenThread instance.
174  * @param[out]   aId        A pointer to the Border Agent ID.
175  *
176  * @retval OT_ERROR_NONE  If successfully set the Border Agent ID.
177  * @retval ...            If failed to set the Border Agent ID.
178  *
179  * @sa otBorderAgentGetId
180  */
181 otError otBorderAgentSetId(otInstance *aInstance, const otBorderAgentId *aId);
182 
183 /**
184  * Sets the ephemeral key for a given timeout duration.
185  *
186  * Requires `OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE`.
187  *
188  * The ephemeral key can be set when the Border Agent is already running and is not currently connected to any external
189  * commissioner (i.e., it is in `OT_BORDER_AGENT_STATE_STARTED` state). Otherwise `OT_ERROR_INVALID_STATE` is returned.
190  * To terminate active commissioner sessions, use the `otBorderAgentDisconnect()` API.
191  *
192  * The given @p aKeyString is directly used as the ephemeral PSK (excluding the trailing null `\0` character ).
193  * The @p aKeyString length must be between `OT_BORDER_AGENT_MIN_EPHEMERAL_KEY_LENGTH` and
194  * `OT_BORDER_AGENT_MAX_EPHEMERAL_KEY_LENGTH`, inclusive.
195  *
196  * Setting the ephemeral key again before a previously set key has timed out will replace the previously set key and
197  * reset the timeout.
198  *
199  * During the timeout interval, the ephemeral key can be used only once by an external commissioner to establish a
200  * connection. After the commissioner disconnects, the ephemeral key is cleared, and the Border Agent reverts to
201  * using PSKc. If the timeout expires while a commissioner is still connected, the session will be terminated, and the
202  * Border Agent will cease using the ephemeral key and revert to PSKc.
203  *
204  * @param[in] aInstance    The OpenThread instance.
205  * @param[in] aKeyString   The ephemeral key string (used as PSK excluding the trailing null `\0` character).
206  * @param[in] aTimeout     The timeout duration in milliseconds to use the ephemeral key.
207  *                         If zero, the default `OT_BORDER_AGENT_DEFAULT_EPHEMERAL_KEY_TIMEOUT` value will be used.
208  *                         If the given timeout value is larger than `OT_BORDER_AGENT_MAX_EPHEMERAL_KEY_TIMEOUT`, the
209  *                         max value `OT_BORDER_AGENT_MAX_EPHEMERAL_KEY_TIMEOUT` will be used instead.
210  * @param[in] aUdpPort     The UDP port to use with ephemeral key. If zero, an ephemeral port will be used.
211  *                         `otBorderAgentGetUdpPort()` will return the current UDP port being used.
212  *
213  * @retval OT_ERROR_NONE           Successfully set the ephemeral key.
214  * @retval OT_ERROR_INVALID_STATE  Border Agent is not running or it is connected to an external commissioner.
215  * @retval OT_ERROR_INVALID_ARGS   The given @p aKeyString is not valid (too short or too long).
216  * @retval OT_ERROR_FAILED         Failed to set the key (e.g., could not bind to UDP port).
217 
218  */
219 otError otBorderAgentSetEphemeralKey(otInstance *aInstance,
220                                      const char *aKeyString,
221                                      uint32_t    aTimeout,
222                                      uint16_t    aUdpPort);
223 
224 /**
225  * Cancels the ephemeral key that is in use.
226  *
227  * Requires `OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE`.
228  *
229  * Can be used to cancel a previously set ephemeral key before it times out. If the Border Agent is not running or
230  * there is no ephemeral key in use, calling this function has no effect.
231  *
232  * If a commissioner is connected using the ephemeral key and is currently active, calling this function does not
233  * change its state. In this case the `otBorderAgentIsEphemeralKeyActive()` will continue to return `TRUE` until the
234  * commissioner disconnects, or the ephemeral key timeout expires. To terminate active commissioner sessions, use the
235  * `otBorderAgentDisconnect()` API.
236  *
237  * @param[in] aInstance    The OpenThread instance.
238  */
239 void otBorderAgentClearEphemeralKey(otInstance *aInstance);
240 
241 /**
242  * Indicates whether or not an ephemeral key is currently active.
243  *
244  * Requires `OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE`.
245  *
246  * @param[in] aInstance    The OpenThread instance.
247  *
248  * @retval TRUE    An ephemeral key is active.
249  * @retval FALSE   No ephemeral key is active.
250  */
251 bool otBorderAgentIsEphemeralKeyActive(otInstance *aInstance);
252 
253 /**
254  * Callback function pointer to signal changes related to the Border Agent's ephemeral key.
255  *
256  * This callback is invoked whenever:
257  *
258  * - The Border Agent starts using an ephemeral key.
259  * - Any parameter related to the ephemeral key, such as the port number, changes.
260  * - A commissioner candidate successfully establishes a secure session with the Border Agent using the ephemeral key.
261  *   This situation can be identified by `otBorderAgentGetState()` being `OT_BORDER_AGENT_STATE_ACTIVE` (this event
262  *   can be used to stop advertising the mDNS service "_meshcop-e._udp").
263  * - The Border Agent stops using the ephemeral key due to:
264  *   - A direct call to `otBorderAgentClearEphemeralKey()`.
265  *   - The ephemeral key timing out.
266  *   - An external commissioner successfully using the key to connect and then disconnecting.
267  *   - Reaching the maximum number of allowed failed connection attempts.
268  *
269  * Any OpenThread API, including `otBorderAgent` APIs, can be safely called from this callback.
270  *
271  * @param[in] aContext   A pointer to an arbitrary context (provided when callback is set).
272  */
273 typedef void (*otBorderAgentEphemeralKeyCallback)(void *aContext);
274 
275 /**
276  * Sets the callback function used by the Border Agent to notify any changes related to use of ephemeral key.
277  *
278  * Requires `OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE`.
279  *
280  * A subsequent call to this function will replace any previously set callback.
281  *
282  * @param[in] aInstance    The OpenThread instance.
283  * @param[in] aCallback    The callback function pointer.
284  * @param[in] aContext     The arbitrary context to use with callback.
285  */
286 void otBorderAgentSetEphemeralKeyCallback(otInstance                       *aInstance,
287                                           otBorderAgentEphemeralKeyCallback aCallback,
288                                           void                             *aContext);
289 
290 /**
291  * Disconnects the Border Agent from any active secure sessions.
292  *
293  * If Border Agent is connected to a commissioner candidate with ephemeral key, calling this API
294  * will cause the ephemeral key to be cleared after the session is disconnected.
295  *
296  * The Border Agent state may not change immediately upon calling this method. The state will be
297  * updated when the connection update is notified with a delay.
298  *
299  * @param[in] aInstance    The OpenThread instance.
300  */
301 void otBorderAgentDisconnect(otInstance *aInstance);
302 
303 /**
304  * @}
305  */
306 
307 #ifdef __cplusplus
308 } // end of extern "C"
309 #endif
310 
311 #endif // OPENTHREAD_BORDER_AGENT_H_
312