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