1 /*
2 * Copyright (c) 2016, 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 the Joiner Router role.
32 */
33
34 #include "joiner_router.hpp"
35
36 #if OPENTHREAD_FTD
37
38 #include "instance/instance.hpp"
39
40 namespace ot {
41 namespace MeshCoP {
42
43 RegisterLogModule("JoinerRouter");
44
JoinerRouter(Instance & aInstance)45 JoinerRouter::JoinerRouter(Instance &aInstance)
46 : InstanceLocator(aInstance)
47 , mSocket(aInstance, *this)
48 , mTimer(aInstance)
49 , mJoinerUdpPort(0)
50 , mIsJoinerPortConfigured(false)
51 {
52 }
53
HandleNotifierEvents(Events aEvents)54 void JoinerRouter::HandleNotifierEvents(Events aEvents)
55 {
56 if (aEvents.Contains(kEventThreadNetdataChanged))
57 {
58 Start();
59 }
60 }
61
Start(void)62 void JoinerRouter::Start(void)
63 {
64 VerifyOrExit(Get<Mle::MleRouter>().IsFullThreadDevice());
65
66 if (Get<NetworkData::Leader>().IsJoiningAllowed())
67 {
68 uint16_t port = GetJoinerUdpPort();
69
70 VerifyOrExit(!mSocket.IsBound());
71
72 IgnoreError(mSocket.Open(Ip6::kNetifThreadInternal));
73 IgnoreError(mSocket.Bind(port));
74 IgnoreError(Get<Ip6::Filter>().AddUnsecurePort(port));
75 LogInfo("Joiner Router: start");
76 }
77 else
78 {
79 VerifyOrExit(mSocket.IsBound());
80
81 IgnoreError(Get<Ip6::Filter>().RemoveUnsecurePort(mSocket.GetSockName().mPort));
82
83 IgnoreError(mSocket.Close());
84 }
85
86 exit:
87 return;
88 }
89
GetJoinerUdpPort(void) const90 uint16_t JoinerRouter::GetJoinerUdpPort(void) const
91 {
92 uint16_t port;
93
94 if (mIsJoinerPortConfigured)
95 {
96 ExitNow(port = mJoinerUdpPort);
97 }
98
99 if (Get<NetworkData::Leader>().FindJoinerUdpPort(port) == kErrorNone)
100 {
101 ExitNow();
102 }
103
104 port = kDefaultJoinerUdpPort;
105
106 exit:
107 return port;
108 }
109
SetJoinerUdpPort(uint16_t aJoinerUdpPort)110 void JoinerRouter::SetJoinerUdpPort(uint16_t aJoinerUdpPort)
111 {
112 mJoinerUdpPort = aJoinerUdpPort;
113 mIsJoinerPortConfigured = true;
114 Start();
115 }
116
HandleUdpReceive(Message & aMessage,const Ip6::MessageInfo & aMessageInfo)117 void JoinerRouter::HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
118 {
119 Error error;
120 Coap::Message *message = nullptr;
121 Tmf::MessageInfo messageInfo(GetInstance());
122 ExtendedTlv tlv;
123 uint16_t borderAgentRloc;
124 OffsetRange offsetRange;
125
126 LogInfo("JoinerRouter::HandleUdpReceive");
127
128 SuccessOrExit(error = Get<NetworkData::Leader>().FindBorderAgentRloc(borderAgentRloc));
129
130 message = Get<Tmf::Agent>().NewPriorityNonConfirmablePostMessage(kUriRelayRx);
131 VerifyOrExit(message != nullptr, error = kErrorNoBufs);
132
133 SuccessOrExit(error = Tlv::Append<JoinerUdpPortTlv>(*message, aMessageInfo.GetPeerPort()));
134 SuccessOrExit(error = Tlv::Append<JoinerIidTlv>(*message, aMessageInfo.GetPeerAddr().GetIid()));
135 SuccessOrExit(error = Tlv::Append<JoinerRouterLocatorTlv>(*message, Get<Mle::MleRouter>().GetRloc16()));
136
137 offsetRange.InitFromMessageOffsetToEnd(aMessage);
138
139 tlv.SetType(Tlv::kJoinerDtlsEncapsulation);
140 tlv.SetLength(offsetRange.GetLength());
141 SuccessOrExit(error = message->Append(tlv));
142 SuccessOrExit(error = message->AppendBytesFromMessage(aMessage, offsetRange));
143
144 messageInfo.SetSockAddrToRlocPeerAddrTo(borderAgentRloc);
145
146 SuccessOrExit(error = Get<Tmf::Agent>().SendMessage(*message, messageInfo));
147
148 LogInfo("Sent %s", UriToString<kUriRelayRx>());
149
150 exit:
151 FreeMessageOnError(message, error);
152 }
153
HandleTmf(Coap::Message & aMessage,const Ip6::MessageInfo & aMessageInfo)154 template <> void JoinerRouter::HandleTmf<kUriRelayTx>(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
155 {
156 OT_UNUSED_VARIABLE(aMessageInfo);
157
158 Error error;
159 uint16_t joinerPort;
160 Ip6::InterfaceIdentifier joinerIid;
161 Kek kek;
162 OffsetRange offsetRange;
163 Message *message = nullptr;
164 Message::Settings settings(kNoLinkSecurity, Message::kPriorityNet);
165 Ip6::MessageInfo messageInfo;
166
167 VerifyOrExit(aMessage.IsNonConfirmablePostRequest(), error = kErrorDrop);
168
169 LogInfo("Received %s", UriToString<kUriRelayTx>());
170
171 SuccessOrExit(error = Tlv::Find<JoinerUdpPortTlv>(aMessage, joinerPort));
172 SuccessOrExit(error = Tlv::Find<JoinerIidTlv>(aMessage, joinerIid));
173
174 SuccessOrExit(error = Tlv::FindTlvValueOffsetRange(aMessage, Tlv::kJoinerDtlsEncapsulation, offsetRange));
175
176 VerifyOrExit((message = mSocket.NewMessage(0, settings)) != nullptr, error = kErrorNoBufs);
177
178 SuccessOrExit(error = message->AppendBytesFromMessage(aMessage, offsetRange));
179
180 messageInfo.GetPeerAddr().SetToLinkLocalAddress(joinerIid);
181 messageInfo.SetPeerPort(joinerPort);
182
183 SuccessOrExit(error = mSocket.SendTo(*message, messageInfo));
184
185 if (Tlv::Find<JoinerRouterKekTlv>(aMessage, kek) == kErrorNone)
186 {
187 LogInfo("Received kek");
188
189 DelaySendingJoinerEntrust(messageInfo, kek);
190 }
191
192 exit:
193 FreeMessageOnError(message, error);
194 }
195
DelaySendingJoinerEntrust(const Ip6::MessageInfo & aMessageInfo,const Kek & aKek)196 void JoinerRouter::DelaySendingJoinerEntrust(const Ip6::MessageInfo &aMessageInfo, const Kek &aKek)
197 {
198 Error error = kErrorNone;
199 Message *message = Get<MessagePool>().Allocate(Message::kTypeOther);
200 JoinerEntrustMetadata metadata;
201
202 VerifyOrExit(message != nullptr, error = kErrorNoBufs);
203
204 metadata.mMessageInfo = aMessageInfo;
205 metadata.mMessageInfo.SetPeerPort(Tmf::kUdpPort);
206 metadata.mSendTime = TimerMilli::GetNow() + kJoinerEntrustTxDelay;
207 metadata.mKek = aKek;
208
209 SuccessOrExit(error = metadata.AppendTo(*message));
210
211 mDelayedJoinEnts.Enqueue(*message);
212
213 if (!mTimer.IsRunning())
214 {
215 mTimer.FireAt(metadata.mSendTime);
216 }
217
218 exit:
219 FreeMessageOnError(message, error);
220 LogWarnOnError(error, "schedule joiner entrust");
221 }
222
HandleTimer(void)223 void JoinerRouter::HandleTimer(void) { SendDelayedJoinerEntrust(); }
224
SendDelayedJoinerEntrust(void)225 void JoinerRouter::SendDelayedJoinerEntrust(void)
226 {
227 JoinerEntrustMetadata metadata;
228 Message *message = mDelayedJoinEnts.GetHead();
229
230 VerifyOrExit(message != nullptr);
231 VerifyOrExit(!mTimer.IsRunning());
232
233 metadata.ReadFrom(*message);
234
235 if (TimerMilli::GetNow() < metadata.mSendTime)
236 {
237 mTimer.FireAt(metadata.mSendTime);
238 }
239 else
240 {
241 mDelayedJoinEnts.DequeueAndFree(*message);
242
243 Get<KeyManager>().SetKek(metadata.mKek);
244
245 if (SendJoinerEntrust(metadata.mMessageInfo) != kErrorNone)
246 {
247 mTimer.Start(0);
248 }
249 }
250
251 exit:
252 return;
253 }
254
SendJoinerEntrust(const Ip6::MessageInfo & aMessageInfo)255 Error JoinerRouter::SendJoinerEntrust(const Ip6::MessageInfo &aMessageInfo)
256 {
257 Error error = kErrorNone;
258 Coap::Message *message;
259
260 message = PrepareJoinerEntrustMessage();
261 VerifyOrExit(message != nullptr, error = kErrorNoBufs);
262
263 IgnoreError(Get<Tmf::Agent>().AbortTransaction(&JoinerRouter::HandleJoinerEntrustResponse, this));
264
265 SuccessOrExit(error = Get<Tmf::Agent>().SendMessage(*message, aMessageInfo,
266 &JoinerRouter::HandleJoinerEntrustResponse, this));
267
268 LogInfo("Sent %s (len= %d)", UriToString<kUriJoinerEntrust>(), message->GetLength());
269 LogCert("[THCI] direction=send | type=JOIN_ENT.ntf");
270
271 exit:
272 FreeMessageOnError(message, error);
273 return error;
274 }
275
PrepareJoinerEntrustMessage(void)276 Coap::Message *JoinerRouter::PrepareJoinerEntrustMessage(void)
277 {
278 static const Tlv::Type kTlvTypes[] = {
279 Tlv::kNetworkKey, Tlv::kMeshLocalPrefix, Tlv::kExtendedPanId, Tlv::kNetworkName,
280 Tlv::kActiveTimestamp, Tlv::kChannelMask, Tlv::kPskc, Tlv::kSecurityPolicy,
281 };
282
283 Error error = kErrorNone;
284 Coap::Message *message = nullptr;
285 Dataset dataset;
286
287 message = Get<Tmf::Agent>().NewPriorityConfirmablePostMessage(kUriJoinerEntrust);
288 VerifyOrExit(message != nullptr, error = kErrorNoBufs);
289
290 message->SetSubType(Message::kSubTypeJoinerEntrust);
291
292 SuccessOrExit(error = Get<ActiveDatasetManager>().Read(dataset));
293
294 for (Tlv::Type tlvType : kTlvTypes)
295 {
296 const Tlv *tlv = dataset.FindTlv(tlvType);
297
298 VerifyOrExit(tlv != nullptr, error = kErrorInvalidState);
299 SuccessOrExit(error = tlv->AppendTo(*message));
300 }
301
302 SuccessOrExit(error = Tlv::Append<NetworkKeySequenceTlv>(*message, Get<KeyManager>().GetCurrentKeySequence()));
303
304 exit:
305 FreeAndNullMessageOnError(message, error);
306 return message;
307 }
308
HandleJoinerEntrustResponse(void * aContext,otMessage * aMessage,const otMessageInfo * aMessageInfo,otError aResult)309 void JoinerRouter::HandleJoinerEntrustResponse(void *aContext,
310 otMessage *aMessage,
311 const otMessageInfo *aMessageInfo,
312 otError aResult)
313 {
314 static_cast<JoinerRouter *>(aContext)->HandleJoinerEntrustResponse(AsCoapMessagePtr(aMessage),
315 AsCoreTypePtr(aMessageInfo), aResult);
316 }
317
HandleJoinerEntrustResponse(Coap::Message * aMessage,const Ip6::MessageInfo * aMessageInfo,Error aResult)318 void JoinerRouter::HandleJoinerEntrustResponse(Coap::Message *aMessage,
319 const Ip6::MessageInfo *aMessageInfo,
320 Error aResult)
321 {
322 OT_UNUSED_VARIABLE(aMessageInfo);
323
324 SendDelayedJoinerEntrust();
325
326 VerifyOrExit(aResult == kErrorNone && aMessage != nullptr);
327
328 VerifyOrExit(aMessage->GetCode() == Coap::kCodeChanged);
329
330 LogInfo("Receive %s response", UriToString<kUriJoinerEntrust>());
331 LogCert("[THCI] direction=recv | type=JOIN_ENT.rsp");
332
333 exit:
334 return;
335 }
336
337 } // namespace MeshCoP
338 } // namespace ot
339
340 #endif // OPENTHREAD_FTD
341