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