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