1 /*
2 * Copyright (c) 2020, 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 implements Thread Management Framework (TMF) functionalities.
32 */
33
34 #include "thread/tmf.hpp"
35
36 #include "common/locator_getters.hpp"
37 #include "net/ip6_types.hpp"
38
39 namespace ot {
40 namespace Tmf {
41
42 //----------------------------------------------------------------------------------------------------------------------
43 // MessageInfo
44
SetSockAddrToRloc(void)45 void MessageInfo::SetSockAddrToRloc(void) { SetSockAddr(Get<Mle::MleRouter>().GetMeshLocal16()); }
46
SetSockAddrToRlocPeerAddrToLeaderAloc(void)47 Error MessageInfo::SetSockAddrToRlocPeerAddrToLeaderAloc(void)
48 {
49 SetSockAddrToRloc();
50 return Get<Mle::MleRouter>().GetLeaderAloc(GetPeerAddr());
51 }
52
SetSockAddrToRlocPeerAddrToLeaderRloc(void)53 Error MessageInfo::SetSockAddrToRlocPeerAddrToLeaderRloc(void)
54 {
55 SetSockAddrToRloc();
56 return Get<Mle::MleRouter>().GetLeaderAddress(GetPeerAddr());
57 }
58
SetSockAddrToRlocPeerAddrToRealmLocalAllRoutersMulticast(void)59 void MessageInfo::SetSockAddrToRlocPeerAddrToRealmLocalAllRoutersMulticast(void)
60 {
61 SetSockAddrToRloc();
62 GetPeerAddr().SetToRealmLocalAllRoutersMulticast();
63 }
64
SetSockAddrToRlocPeerAddrTo(uint16_t aRloc16)65 void MessageInfo::SetSockAddrToRlocPeerAddrTo(uint16_t aRloc16)
66 {
67 SetSockAddrToRloc();
68 SetPeerAddr(Get<Mle::MleRouter>().GetMeshLocal16());
69 GetPeerAddr().GetIid().SetLocator(aRloc16);
70 }
71
SetSockAddrToRlocPeerAddrTo(const Ip6::Address & aPeerAddress)72 void MessageInfo::SetSockAddrToRlocPeerAddrTo(const Ip6::Address &aPeerAddress)
73 {
74 SetSockAddrToRloc();
75 SetPeerAddr(aPeerAddress);
76 }
77
78 //----------------------------------------------------------------------------------------------------------------------
79 // Agent
80
Agent(Instance & aInstance)81 Agent::Agent(Instance &aInstance)
82 : Coap::Coap(aInstance)
83 {
84 SetInterceptor(&Filter, this);
85 SetResourceHandler(&HandleResource);
86 }
87
Start(void)88 Error Agent::Start(void) { return Coap::Start(kUdpPort, Ip6::kNetifThread); }
89
HandleTmf(Message & aMessage,const Ip6::MessageInfo & aMessageInfo)90 template <> void Agent::HandleTmf<kUriRelayRx>(Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
91 {
92 OT_UNUSED_VARIABLE(aMessage);
93 OT_UNUSED_VARIABLE(aMessageInfo);
94
95 #if (OPENTHREAD_FTD && OPENTHREAD_CONFIG_COMMISSIONER_ENABLE)
96 Get<MeshCoP::Commissioner>().HandleTmf<kUriRelayRx>(aMessage, aMessageInfo);
97 #endif
98 #if OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE
99 Get<MeshCoP::BorderAgent>().HandleTmf<kUriRelayRx>(aMessage, aMessageInfo);
100 #endif
101 }
102
HandleResource(CoapBase & aCoapBase,const char * aUriPath,Message & aMessage,const Ip6::MessageInfo & aMessageInfo)103 bool Agent::HandleResource(CoapBase &aCoapBase,
104 const char *aUriPath,
105 Message &aMessage,
106 const Ip6::MessageInfo &aMessageInfo)
107 {
108 return static_cast<Agent &>(aCoapBase).HandleResource(aUriPath, aMessage, aMessageInfo);
109 }
110
HandleResource(const char * aUriPath,Message & aMessage,const Ip6::MessageInfo & aMessageInfo)111 bool Agent::HandleResource(const char *aUriPath, Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
112 {
113 bool didHandle = true;
114 Uri uri = UriFromPath(aUriPath);
115
116 #define Case(kUri, Type) \
117 case kUri: \
118 Get<Type>().HandleTmf<kUri>(aMessage, aMessageInfo); \
119 break
120
121 switch (uri)
122 {
123 Case(kUriAddressError, AddressResolver);
124 Case(kUriEnergyScan, EnergyScanServer);
125 Case(kUriActiveGet, MeshCoP::ActiveDatasetManager);
126 Case(kUriPendingGet, MeshCoP::PendingDatasetManager);
127 Case(kUriPanIdQuery, PanIdQueryServer);
128
129 #if OPENTHREAD_FTD
130 Case(kUriAddressQuery, AddressResolver);
131 Case(kUriAddressNotify, AddressResolver);
132 Case(kUriAddressSolicit, Mle::MleRouter);
133 Case(kUriAddressRelease, Mle::MleRouter);
134 Case(kUriActiveSet, MeshCoP::ActiveDatasetManager);
135 Case(kUriPendingSet, MeshCoP::PendingDatasetManager);
136 Case(kUriLeaderPetition, MeshCoP::Leader);
137 Case(kUriLeaderKeepAlive, MeshCoP::Leader);
138 Case(kUriServerData, NetworkData::Leader);
139 Case(kUriCommissionerGet, NetworkData::Leader);
140 Case(kUriCommissionerSet, NetworkData::Leader);
141 Case(kUriAnnounceBegin, AnnounceBeginServer);
142 Case(kUriRelayTx, MeshCoP::JoinerRouter);
143 #endif
144
145 #if OPENTHREAD_CONFIG_JOINER_ENABLE
146 Case(kUriJoinerEntrust, MeshCoP::Joiner);
147 #endif
148
149 #if OPENTHREAD_CONFIG_COMMISSIONER_ENABLE && OPENTHREAD_FTD
150 Case(kUriPanIdConflict, PanIdQueryClient);
151 Case(kUriEnergyReport, EnergyScanClient);
152 Case(kUriDatasetChanged, MeshCoP::Commissioner);
153 // kUriRelayRx is handled below
154 #endif
155
156 #if OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE || (OPENTHREAD_FTD && OPENTHREAD_CONFIG_COMMISSIONER_ENABLE)
157 Case(kUriRelayRx, Agent);
158 #endif
159
160 #if OPENTHREAD_CONFIG_DUA_ENABLE || (OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE)
161 Case(kUriDuaRegistrationNotify, DuaManager);
162 #endif
163
164 #if OPENTHREAD_CONFIG_TMF_ANYCAST_LOCATOR_ENABLE
165 Case(kUriAnycastLocate, AnycastLocator);
166 #endif
167
168 Case(kUriDiagnosticGetRequest, NetworkDiagnostic::Server);
169 Case(kUriDiagnosticGetQuery, NetworkDiagnostic::Server);
170 Case(kUriDiagnosticReset, NetworkDiagnostic::Server);
171
172 #if OPENTHREAD_CONFIG_TMF_NETDIAG_CLIENT_ENABLE
173 Case(kUriDiagnosticGetAnswer, NetworkDiagnostic::Client);
174 #endif
175
176 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
177 #if OPENTHREAD_CONFIG_BACKBONE_ROUTER_MULTICAST_ROUTING_ENABLE
178 Case(kUriMlr, BackboneRouter::Manager);
179 #endif
180 #if OPENTHREAD_CONFIG_BACKBONE_ROUTER_DUA_NDPROXYING_ENABLE
181 Case(kUriDuaRegistrationRequest, BackboneRouter::Manager);
182 #endif
183 #endif
184
185 default:
186 didHandle = false;
187 break;
188 }
189
190 #undef Case
191
192 return didHandle;
193 }
194
Filter(const Message & aMessage,const Ip6::MessageInfo & aMessageInfo,void * aContext)195 Error Agent::Filter(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo, void *aContext)
196 {
197 OT_UNUSED_VARIABLE(aMessage);
198
199 return static_cast<Agent *>(aContext)->IsTmfMessage(aMessageInfo.GetPeerAddr(), aMessageInfo.GetSockAddr(),
200 aMessageInfo.GetSockPort())
201 ? kErrorNone
202 : kErrorNotTmf;
203 }
204
IsTmfMessage(const Ip6::Address & aSourceAddress,const Ip6::Address & aDestAddress,uint16_t aDestPort) const205 bool Agent::IsTmfMessage(const Ip6::Address &aSourceAddress, const Ip6::Address &aDestAddress, uint16_t aDestPort) const
206 {
207 bool isTmf = false;
208
209 VerifyOrExit(aDestPort == kUdpPort);
210
211 if (aSourceAddress.IsLinkLocal())
212 {
213 isTmf = aDestAddress.IsLinkLocal() || aDestAddress.IsLinkLocalMulticast();
214 ExitNow();
215 }
216
217 VerifyOrExit(Get<Mle::Mle>().IsMeshLocalAddress(aSourceAddress));
218 VerifyOrExit(Get<Mle::Mle>().IsMeshLocalAddress(aDestAddress) || aDestAddress.IsLinkLocalMulticast() ||
219 aDestAddress.IsRealmLocalMulticast());
220
221 isTmf = true;
222
223 exit:
224 return isTmf;
225 }
226
PriorityToDscp(Message::Priority aPriority)227 uint8_t Agent::PriorityToDscp(Message::Priority aPriority)
228 {
229 uint8_t dscp = Ip6::kDscpTmfNormalPriority;
230
231 switch (aPriority)
232 {
233 case Message::kPriorityNet:
234 dscp = Ip6::kDscpTmfNetPriority;
235 break;
236
237 case Message::kPriorityHigh:
238 case Message::kPriorityNormal:
239 break;
240
241 case Message::kPriorityLow:
242 dscp = Ip6::kDscpTmfLowPriority;
243 break;
244 }
245
246 return dscp;
247 }
248
DscpToPriority(uint8_t aDscp)249 Message::Priority Agent::DscpToPriority(uint8_t aDscp)
250 {
251 Message::Priority priority = Message::kPriorityNet;
252
253 // If the sender does not use TMF specific DSCP value, we use
254 // `kPriorityNet`. This ensures that senders that do not use the
255 // new value (older firmware) experience the same behavior as
256 // before where all TMF message were treated as `kPriorityNet`.
257
258 switch (aDscp)
259 {
260 case Ip6::kDscpTmfNetPriority:
261 default:
262 break;
263 case Ip6::kDscpTmfNormalPriority:
264 priority = Message::kPriorityNormal;
265 break;
266 case Ip6::kDscpTmfLowPriority:
267 priority = Message::kPriorityLow;
268 break;
269 }
270
271 return priority;
272 }
273
274 #if OPENTHREAD_CONFIG_DTLS_ENABLE
275
SecureAgent(Instance & aInstance)276 SecureAgent::SecureAgent(Instance &aInstance)
277 : Coap::CoapSecure(aInstance)
278 {
279 SetResourceHandler(&HandleResource);
280 }
281
HandleResource(CoapBase & aCoapBase,const char * aUriPath,Message & aMessage,const Ip6::MessageInfo & aMessageInfo)282 bool SecureAgent::HandleResource(CoapBase &aCoapBase,
283 const char *aUriPath,
284 Message &aMessage,
285 const Ip6::MessageInfo &aMessageInfo)
286 {
287 return static_cast<SecureAgent &>(aCoapBase).HandleResource(aUriPath, aMessage, aMessageInfo);
288 }
289
HandleResource(const char * aUriPath,Message & aMessage,const Ip6::MessageInfo & aMessageInfo)290 bool SecureAgent::HandleResource(const char *aUriPath, Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
291 {
292 OT_UNUSED_VARIABLE(aMessage);
293 OT_UNUSED_VARIABLE(aMessageInfo);
294
295 bool didHandle = true;
296 Uri uri = UriFromPath(aUriPath);
297
298 #define Case(kUri, Type) \
299 case kUri: \
300 Get<Type>().HandleTmf<kUri>(aMessage, aMessageInfo); \
301 break
302
303 switch (uri)
304 {
305 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_COMMISSIONER_ENABLE
306 Case(kUriJoinerFinalize, MeshCoP::Commissioner);
307 #endif
308
309 #if OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE
310 Case(kUriCommissionerPetition, MeshCoP::BorderAgent);
311 Case(kUriCommissionerKeepAlive, MeshCoP::BorderAgent);
312 Case(kUriRelayTx, MeshCoP::BorderAgent);
313 Case(kUriCommissionerGet, MeshCoP::BorderAgent);
314 Case(kUriCommissionerSet, MeshCoP::BorderAgent);
315 Case(kUriActiveGet, MeshCoP::BorderAgent);
316 Case(kUriActiveSet, MeshCoP::BorderAgent);
317 Case(kUriPendingGet, MeshCoP::BorderAgent);
318 Case(kUriPendingSet, MeshCoP::BorderAgent);
319 Case(kUriProxyTx, MeshCoP::BorderAgent);
320 #endif
321
322 default:
323 didHandle = false;
324 break;
325 }
326
327 #undef Case
328
329 return didHandle;
330 }
331
332 #endif // OPENTHREAD_CONFIG_DTLS_ENABLE
333
334 } // namespace Tmf
335 } // namespace ot
336