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 "net/udp6.hpp"
49 #include "thread/tmf.hpp"
50 #include "thread/uri_paths.hpp"
51 
52 namespace ot {
53 
54 namespace MeshCoP {
55 
56 class BorderAgent : public InstanceLocator, private NonCopyable
57 {
58     friend class ot::Notifier;
59     friend class Tmf::Agent;
60     friend class Tmf::SecureAgent;
61 
62 public:
63     typedef otBorderAgentId Id; ///< Border Agent ID.
64 
65     /**
66      * Defines the Border Agent state.
67      *
68      */
69     enum State : uint8_t
70     {
71         kStateStopped = OT_BORDER_AGENT_STATE_STOPPED, ///< Border agent is stopped/disabled.
72         kStateStarted = OT_BORDER_AGENT_STATE_STARTED, ///< Border agent is started.
73         kStateActive  = OT_BORDER_AGENT_STATE_ACTIVE,  ///< Border agent is connected with external commissioner.
74     };
75 
76     /**
77      * Initializes the `BorderAgent` object.
78      *
79      * @param[in]  aInstance     A reference to the OpenThread instance.
80      *
81      */
82     explicit BorderAgent(Instance &aInstance);
83 
84 #if OPENTHREAD_CONFIG_BORDER_AGENT_ID_ENABLE
85     /**
86      * Gets the randomly generated Border Agent ID.
87      *
88      * The ID is saved in persistent storage and survives reboots. The typical use case of the ID is to
89      * be published in the MeshCoP mDNS service as the `id` TXT value for the client to identify this
90      * Border Router/Agent device.
91      *
92      * @param[out] aId  Reference to return the Border Agent ID.
93      *
94      * @retval kErrorNone  If successfully retrieved the Border Agent ID.
95      * @retval ...         If failed to retrieve the Border Agent ID.
96      *
97      */
98     Error GetId(Id &aId);
99 
100     /**
101      * Sets the Border Agent ID.
102      *
103      * The Border Agent ID will be saved in persistent storage and survive reboots. It's required
104      * to set the ID only once after factory reset. If the ID has never been set by calling this
105      * method, a random ID will be generated and returned when `GetId()` is called.
106      *
107      * @param[out] aId  specifies the Border Agent ID.
108      *
109      * @retval kErrorNone  If successfully set the Border Agent ID.
110      * @retval ...         If failed to set the Border Agent ID.
111      *
112      */
113     Error SetId(const Id &aId);
114 #endif
115 
116     /**
117      * Gets the UDP port of this service.
118      *
119      * @returns  UDP port number.
120      *
121      */
122     uint16_t GetUdpPort(void) const;
123 
124     /**
125      * Starts the Border Agent service.
126      *
127      */
128     void Start(void);
129 
130     /**
131      * Stops the Border Agent service.
132      *
133      */
134     void Stop(void);
135 
136     /**
137      * Gets the state of the Border Agent service.
138      *
139      * @returns The state of the Border Agent service.
140      *
141      */
GetState(void) const142     State GetState(void) const { return mState; }
143 
144     /**
145      * Returns the UDP Proxy port to which the commissioner is currently
146      * bound.
147      *
148      * @returns  The current UDP Proxy port or 0 if no Proxy Transmit has been received yet.
149      *
150      */
GetUdpProxyPort(void) const151     uint16_t GetUdpProxyPort(void) const { return mUdpProxyPort; }
152 
153 private:
154     static constexpr uint16_t kUdpPort          = OPENTHREAD_CONFIG_BORDER_AGENT_UDP_PORT;
155     static constexpr uint32_t kKeepAliveTimeout = 50 * 1000; // Timeout to reject a commissioner (in msec)
156 
157     class ForwardContext : public InstanceLocatorInit, public Heap::Allocatable<ForwardContext>
158     {
159     public:
160         Error    Init(Instance &aInstance, const Coap::Message &aMessage, bool aPetition, bool aSeparate);
IsPetition(void) const161         bool     IsPetition(void) const { return mPetition; }
GetMessageId(void) const162         uint16_t GetMessageId(void) const { return mMessageId; }
163         Error    ToHeader(Coap::Message &aMessage, uint8_t aCode) const;
164 
165     private:
166         uint16_t mMessageId;                             // The CoAP Message ID of the original request.
167         bool     mPetition : 1;                          // Whether the forwarding request is leader petition.
168         bool     mSeparate : 1;                          // Whether the original request expects separate response.
169         uint8_t  mTokenLength : 4;                       // The CoAP Token Length of the original request.
170         uint8_t  mType : 2;                              // The CoAP Type of the original request.
171         uint8_t  mToken[Coap::Message::kMaxTokenLength]; // The CoAP Token of the original request.
172     };
173 
174     void HandleNotifierEvents(Events aEvents);
175 
176     Coap::Message::Code CoapCodeFromError(Error aError);
177     Error               SendMessage(Coap::Message &aMessage);
178     void                SendErrorMessage(const ForwardContext &aForwardContext, Error aError);
179     void                SendErrorMessage(const Coap::Message &aRequest, bool aSeparate, Error aError);
180 
181     static void HandleConnected(bool aConnected, void *aContext);
182     void        HandleConnected(bool aConnected);
183 
184     template <Uri kUri> void HandleTmf(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
185 
186     void HandleTimeout(void);
187 
188     static void HandleCoapResponse(void                *aContext,
189                                    otMessage           *aMessage,
190                                    const otMessageInfo *aMessageInfo,
191                                    Error                aResult);
192     void  HandleCoapResponse(const ForwardContext &aForwardContext, const Coap::Message *aResponse, Error aResult);
193     Error ForwardToLeader(const Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo, Uri aUri);
194     Error ForwardToCommissioner(Coap::Message &aForwardMessage, const Message &aMessage);
195     static bool HandleUdpReceive(void *aContext, const otMessage *aMessage, const otMessageInfo *aMessageInfo);
196     bool        HandleUdpReceive(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
197 
198 #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_WARN)
199     void LogError(const char *aActionText, Error aError);
200 #else
LogError(const char *,Error)201     void LogError(const char *, Error) {}
202 #endif
203 
204     using TimeoutTimer = TimerMilliIn<BorderAgent, &BorderAgent::HandleTimeout>;
205 
206     State                      mState;
207     uint16_t                   mUdpProxyPort;
208     Ip6::Udp::Receiver         mUdpReceiver;
209     Ip6::Netif::UnicastAddress mCommissionerAloc;
210     TimeoutTimer               mTimer;
211 #if OPENTHREAD_CONFIG_BORDER_AGENT_ID_ENABLE
212     Id   mId;
213     bool mIdInitialized;
214 #endif
215 };
216 
217 DeclareTmfHandler(BorderAgent, kUriRelayRx);
218 DeclareTmfHandler(BorderAgent, kUriCommissionerPetition);
219 DeclareTmfHandler(BorderAgent, kUriCommissionerKeepAlive);
220 DeclareTmfHandler(BorderAgent, kUriRelayTx);
221 DeclareTmfHandler(BorderAgent, kUriCommissionerGet);
222 DeclareTmfHandler(BorderAgent, kUriCommissionerSet);
223 DeclareTmfHandler(BorderAgent, kUriActiveGet);
224 DeclareTmfHandler(BorderAgent, kUriActiveSet);
225 DeclareTmfHandler(BorderAgent, kUriPendingGet);
226 DeclareTmfHandler(BorderAgent, kUriPendingSet);
227 DeclareTmfHandler(BorderAgent, kUriProxyTx);
228 
229 } // namespace MeshCoP
230 
231 DefineMapEnum(otBorderAgentState, MeshCoP::BorderAgent::State);
232 DefineCoreType(otBorderAgentId, MeshCoP::BorderAgent::Id);
233 
234 } // namespace ot
235 
236 #endif // OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE
237 
238 #endif // BORDER_AGENT_HPP_
239