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 implements the BorderAgent service.
32 */
33
34 #include "border_agent.hpp"
35
36 #if OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE
37
38 #include "coap/coap_message.hpp"
39 #include "common/as_core_type.hpp"
40 #include "common/heap.hpp"
41 #include "common/locator_getters.hpp"
42 #include "common/log.hpp"
43 #include "common/owned_ptr.hpp"
44 #include "common/settings.hpp"
45 #include "instance/instance.hpp"
46 #include "meshcop/meshcop.hpp"
47 #include "meshcop/meshcop_tlvs.hpp"
48 #include "thread/thread_netif.hpp"
49 #include "thread/thread_tlvs.hpp"
50 #include "thread/uri_paths.hpp"
51
52 namespace ot {
53 namespace MeshCoP {
54
55 RegisterLogModule("BorderAgent");
56
57 //----------------------------------------------------------------------------------------------------------------------
58 // `BorderAgent::ForwardContext`
59
Init(Instance & aInstance,const Coap::Message & aMessage,bool aPetition,bool aSeparate)60 Error BorderAgent::ForwardContext::Init(Instance &aInstance,
61 const Coap::Message &aMessage,
62 bool aPetition,
63 bool aSeparate)
64 {
65 InstanceLocatorInit::Init(aInstance);
66 mMessageId = aMessage.GetMessageId();
67 mPetition = aPetition;
68 mSeparate = aSeparate;
69 mType = aMessage.GetType();
70 mTokenLength = aMessage.GetTokenLength();
71 memcpy(mToken, aMessage.GetToken(), mTokenLength);
72
73 return kErrorNone;
74 }
75
ToHeader(Coap::Message & aMessage,uint8_t aCode) const76 Error BorderAgent::ForwardContext::ToHeader(Coap::Message &aMessage, uint8_t aCode) const
77 {
78 if ((mType == Coap::kTypeNonConfirmable) || mSeparate)
79 {
80 aMessage.Init(Coap::kTypeNonConfirmable, static_cast<Coap::Code>(aCode));
81 }
82 else
83 {
84 aMessage.Init(Coap::kTypeAck, static_cast<Coap::Code>(aCode));
85 }
86
87 if (!mSeparate)
88 {
89 aMessage.SetMessageId(mMessageId);
90 }
91
92 return aMessage.SetToken(mToken, mTokenLength);
93 }
94
95 //----------------------------------------------------------------------------------------------------------------------
96 // `BorderAgent`
97
CoapCodeFromError(Error aError)98 Coap::Message::Code BorderAgent::CoapCodeFromError(Error aError)
99 {
100 Coap::Message::Code code;
101
102 switch (aError)
103 {
104 case kErrorNone:
105 code = Coap::kCodeChanged;
106 break;
107
108 case kErrorParse:
109 code = Coap::kCodeBadRequest;
110 break;
111
112 default:
113 code = Coap::kCodeInternalError;
114 break;
115 }
116
117 return code;
118 }
119
SendErrorMessage(const ForwardContext & aForwardContext,Error aError)120 void BorderAgent::SendErrorMessage(const ForwardContext &aForwardContext, Error aError)
121 {
122 Error error = kErrorNone;
123 Coap::Message *message = nullptr;
124
125 VerifyOrExit((message = Get<Tmf::SecureAgent>().NewPriorityMessage()) != nullptr, error = kErrorNoBufs);
126 SuccessOrExit(error = aForwardContext.ToHeader(*message, CoapCodeFromError(aError)));
127 SuccessOrExit(error = SendMessage(*message));
128
129 exit:
130 FreeMessageOnError(message, error);
131 LogError("send error CoAP message", error);
132 }
133
SendErrorMessage(const Coap::Message & aRequest,bool aSeparate,Error aError)134 void BorderAgent::SendErrorMessage(const Coap::Message &aRequest, bool aSeparate, Error aError)
135 {
136 Error error = kErrorNone;
137 Coap::Message *message = nullptr;
138
139 VerifyOrExit((message = Get<Tmf::SecureAgent>().NewPriorityMessage()) != nullptr, error = kErrorNoBufs);
140
141 if (aRequest.IsNonConfirmable() || aSeparate)
142 {
143 message->Init(Coap::kTypeNonConfirmable, CoapCodeFromError(aError));
144 }
145 else
146 {
147 message->Init(Coap::kTypeAck, CoapCodeFromError(aError));
148 }
149
150 if (!aSeparate)
151 {
152 message->SetMessageId(aRequest.GetMessageId());
153 }
154
155 SuccessOrExit(error = message->SetTokenFromMessage(aRequest));
156
157 SuccessOrExit(error = SendMessage(*message));
158
159 exit:
160 FreeMessageOnError(message, error);
161 LogError("send error CoAP message", error);
162 }
163
SendMessage(Coap::Message & aMessage)164 Error BorderAgent::SendMessage(Coap::Message &aMessage)
165 {
166 return Get<Tmf::SecureAgent>().SendMessage(aMessage, Get<Tmf::SecureAgent>().GetMessageInfo());
167 }
168
HandleCoapResponse(void * aContext,otMessage * aMessage,const otMessageInfo * aMessageInfo,Error aResult)169 void BorderAgent::HandleCoapResponse(void *aContext,
170 otMessage *aMessage,
171 const otMessageInfo *aMessageInfo,
172 Error aResult)
173 {
174 OT_UNUSED_VARIABLE(aMessageInfo);
175
176 OwnedPtr<ForwardContext> forwardContext(static_cast<ForwardContext *>(aContext));
177
178 forwardContext->Get<BorderAgent>().HandleCoapResponse(*forwardContext.Get(), AsCoapMessagePtr(aMessage), aResult);
179 }
180
HandleCoapResponse(const ForwardContext & aForwardContext,const Coap::Message * aResponse,Error aResult)181 void BorderAgent::HandleCoapResponse(const ForwardContext &aForwardContext,
182 const Coap::Message *aResponse,
183 Error aResult)
184 {
185 Coap::Message *message = nullptr;
186 Error error;
187
188 SuccessOrExit(error = aResult);
189 VerifyOrExit((message = Get<Tmf::SecureAgent>().NewPriorityMessage()) != nullptr, error = kErrorNoBufs);
190
191 if (aForwardContext.IsPetition() && aResponse->GetCode() == Coap::kCodeChanged)
192 {
193 uint8_t state;
194
195 SuccessOrExit(error = Tlv::Find<StateTlv>(*aResponse, state));
196
197 if (state == StateTlv::kAccept)
198 {
199 uint16_t sessionId;
200
201 SuccessOrExit(error = Tlv::Find<CommissionerSessionIdTlv>(*aResponse, sessionId));
202
203 IgnoreError(Get<Mle::MleRouter>().GetCommissionerAloc(mCommissionerAloc.GetAddress(), sessionId));
204 Get<ThreadNetif>().AddUnicastAddress(mCommissionerAloc);
205 IgnoreError(Get<Ip6::Udp>().AddReceiver(mUdpReceiver));
206
207 LogInfo("Commissioner accepted - SessionId:%u ALOC:%s", sessionId,
208 mCommissionerAloc.GetAddress().ToString().AsCString());
209 }
210 }
211
212 SuccessOrExit(error = aForwardContext.ToHeader(*message, aResponse->GetCode()));
213
214 if (aResponse->GetLength() > aResponse->GetOffset())
215 {
216 SuccessOrExit(error = message->SetPayloadMarker());
217 }
218
219 SuccessOrExit(error = ForwardToCommissioner(*message, *aResponse));
220
221 exit:
222
223 if (error != kErrorNone)
224 {
225 FreeMessage(message);
226
227 LogWarn("Commissioner request[%u] failed: %s", aForwardContext.GetMessageId(), ErrorToString(error));
228
229 SendErrorMessage(aForwardContext, error);
230 }
231 }
232
BorderAgent(Instance & aInstance)233 BorderAgent::BorderAgent(Instance &aInstance)
234 : InstanceLocator(aInstance)
235 , mState(kStateStopped)
236 , mUdpProxyPort(0)
237 , mUdpReceiver(BorderAgent::HandleUdpReceive, this)
238 , mTimer(aInstance)
239 #if OPENTHREAD_CONFIG_BORDER_AGENT_ID_ENABLE
240 , mIdInitialized(false)
241 #endif
242 {
243 mCommissionerAloc.InitAsThreadOriginMeshLocal();
244 }
245
246 #if OPENTHREAD_CONFIG_BORDER_AGENT_ID_ENABLE
GetId(Id & aId)247 Error BorderAgent::GetId(Id &aId)
248 {
249 Error error = kErrorNone;
250 Settings::BorderAgentId id;
251
252 VerifyOrExit(!mIdInitialized, error = kErrorNone);
253
254 if (Get<Settings>().Read(id) != kErrorNone)
255 {
256 Random::NonCrypto::Fill(id.GetId());
257 SuccessOrExit(error = Get<Settings>().Save(id));
258 }
259
260 mId = id.GetId();
261 mIdInitialized = true;
262
263 exit:
264 if (error == kErrorNone)
265 {
266 aId = mId;
267 }
268 return error;
269 }
270
SetId(const Id & aId)271 Error BorderAgent::SetId(const Id &aId)
272 {
273 Error error = kErrorNone;
274 Settings::BorderAgentId id;
275
276 id.SetId(aId);
277 SuccessOrExit(error = Get<Settings>().Save(id));
278 mId = aId;
279 mIdInitialized = true;
280
281 exit:
282 return error;
283 }
284 #endif // OPENTHREAD_CONFIG_BORDER_AGENT_ID_ENABLE
285
HandleNotifierEvents(Events aEvents)286 void BorderAgent::HandleNotifierEvents(Events aEvents)
287 {
288 VerifyOrExit(aEvents.ContainsAny(kEventThreadRoleChanged | kEventCommissionerStateChanged));
289
290 #if OPENTHREAD_CONFIG_COMMISSIONER_ENABLE && OPENTHREAD_FTD
291 VerifyOrExit(Get<Commissioner>().IsDisabled());
292 #endif
293
294 if (Get<Mle::MleRouter>().IsAttached())
295 {
296 Start();
297 }
298 else
299 {
300 Stop();
301 }
302
303 exit:
304 return;
305 }
306
HandleTmf(Coap::Message & aMessage,const Ip6::MessageInfo & aMessageInfo)307 template <> void BorderAgent::HandleTmf<kUriProxyTx>(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
308 {
309 OT_UNUSED_VARIABLE(aMessageInfo);
310
311 Error error = kErrorNone;
312 Message *message = nullptr;
313 Ip6::MessageInfo messageInfo;
314 uint16_t offset;
315 uint16_t length;
316 UdpEncapsulationTlvHeader udpEncapHeader;
317
318 VerifyOrExit(mState != kStateStopped);
319
320 SuccessOrExit(error = Tlv::FindTlvValueOffset(aMessage, Tlv::kUdpEncapsulation, offset, length));
321
322 SuccessOrExit(error = aMessage.Read(offset, udpEncapHeader));
323 offset += sizeof(UdpEncapsulationTlvHeader);
324 length -= sizeof(UdpEncapsulationTlvHeader);
325
326 VerifyOrExit(udpEncapHeader.GetSourcePort() > 0 && udpEncapHeader.GetDestinationPort() > 0, error = kErrorDrop);
327
328 VerifyOrExit((message = Get<Ip6::Udp>().NewMessage()) != nullptr, error = kErrorNoBufs);
329 SuccessOrExit(error = message->AppendBytesFromMessage(aMessage, offset, length));
330
331 messageInfo.SetSockPort(udpEncapHeader.GetSourcePort());
332 messageInfo.SetSockAddr(mCommissionerAloc.GetAddress());
333 messageInfo.SetPeerPort(udpEncapHeader.GetDestinationPort());
334
335 SuccessOrExit(error = Tlv::Find<Ip6AddressTlv>(aMessage, messageInfo.GetPeerAddr()));
336
337 SuccessOrExit(error = Get<Ip6::Udp>().SendDatagram(*message, messageInfo));
338 mUdpProxyPort = udpEncapHeader.GetSourcePort();
339
340 LogInfo("Proxy transmit sent to %s", messageInfo.GetPeerAddr().ToString().AsCString());
341
342 exit:
343 FreeMessageOnError(message, error);
344 LogError("send proxy stream", error);
345 }
346
HandleUdpReceive(void * aContext,const otMessage * aMessage,const otMessageInfo * aMessageInfo)347 bool BorderAgent::HandleUdpReceive(void *aContext, const otMessage *aMessage, const otMessageInfo *aMessageInfo)
348 {
349 return static_cast<BorderAgent *>(aContext)->HandleUdpReceive(AsCoreType(aMessage), AsCoreType(aMessageInfo));
350 }
351
HandleUdpReceive(const Message & aMessage,const Ip6::MessageInfo & aMessageInfo)352 bool BorderAgent::HandleUdpReceive(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
353 {
354 Error error;
355 Coap::Message *message = nullptr;
356
357 if (aMessageInfo.GetSockAddr() != mCommissionerAloc.GetAddress())
358 {
359 LogDebg("Filtered out message for commissioner: dest %s != %s (ALOC)",
360 aMessageInfo.GetSockAddr().ToString().AsCString(),
361 mCommissionerAloc.GetAddress().ToString().AsCString());
362 ExitNow(error = kErrorDestinationAddressFiltered);
363 }
364
365 VerifyOrExit(aMessage.GetLength() > 0, error = kErrorNone);
366
367 message = Get<Tmf::SecureAgent>().NewPriorityNonConfirmablePostMessage(kUriProxyRx);
368 VerifyOrExit(message != nullptr, error = kErrorNoBufs);
369
370 {
371 ExtendedTlv extTlv;
372 UdpEncapsulationTlvHeader udpEncapHeader;
373 uint16_t udpLength = aMessage.GetLength() - aMessage.GetOffset();
374
375 extTlv.SetType(Tlv::kUdpEncapsulation);
376 extTlv.SetLength(sizeof(UdpEncapsulationTlvHeader) + udpLength);
377 SuccessOrExit(error = message->Append(extTlv));
378
379 udpEncapHeader.SetSourcePort(aMessageInfo.GetPeerPort());
380 udpEncapHeader.SetDestinationPort(aMessageInfo.GetSockPort());
381 SuccessOrExit(error = message->Append(udpEncapHeader));
382 SuccessOrExit(error = message->AppendBytesFromMessage(aMessage, aMessage.GetOffset(), udpLength));
383 }
384
385 SuccessOrExit(error = Tlv::Append<Ip6AddressTlv>(*message, aMessageInfo.GetPeerAddr()));
386
387 SuccessOrExit(error = SendMessage(*message));
388
389 LogInfo("Sent to commissioner on ProxyRx (c/ur)");
390
391 exit:
392 FreeMessageOnError(message, error);
393 if (error != kErrorDestinationAddressFiltered)
394 {
395 LogError("notify commissioner on ProxyRx (c/ur)", error);
396 }
397
398 return error != kErrorDestinationAddressFiltered;
399 }
400
HandleTmf(Coap::Message & aMessage,const Ip6::MessageInfo & aMessageInfo)401 template <> void BorderAgent::HandleTmf<kUriRelayRx>(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
402 {
403 OT_UNUSED_VARIABLE(aMessageInfo);
404
405 Coap::Message *message = nullptr;
406 Error error = kErrorNone;
407
408 VerifyOrExit(mState != kStateStopped);
409
410 VerifyOrExit(aMessage.IsNonConfirmablePostRequest(), error = kErrorDrop);
411
412 message = Get<Tmf::SecureAgent>().NewPriorityNonConfirmablePostMessage(kUriRelayRx);
413 VerifyOrExit(message != nullptr, error = kErrorNoBufs);
414
415 SuccessOrExit(error = ForwardToCommissioner(*message, aMessage));
416 LogInfo("Sent to commissioner on RelayRx (c/rx)");
417
418 exit:
419 FreeMessageOnError(message, error);
420 }
421
ForwardToCommissioner(Coap::Message & aForwardMessage,const Message & aMessage)422 Error BorderAgent::ForwardToCommissioner(Coap::Message &aForwardMessage, const Message &aMessage)
423 {
424 Error error;
425
426 SuccessOrExit(error = aForwardMessage.AppendBytesFromMessage(aMessage, aMessage.GetOffset(),
427 aMessage.GetLength() - aMessage.GetOffset()));
428 SuccessOrExit(error = SendMessage(aForwardMessage));
429
430 LogInfo("Sent to commissioner");
431
432 exit:
433 LogError("send to commissioner", error);
434 return error;
435 }
436
437 template <>
HandleTmf(Coap::Message & aMessage,const Ip6::MessageInfo & aMessageInfo)438 void BorderAgent::HandleTmf<kUriCommissionerPetition>(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
439 {
440 IgnoreError(ForwardToLeader(aMessage, aMessageInfo, kUriLeaderPetition));
441 }
442
443 template <>
HandleTmf(Coap::Message & aMessage,const Ip6::MessageInfo & aMessageInfo)444 void BorderAgent::HandleTmf<kUriCommissionerGet>(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
445 {
446 IgnoreError(ForwardToLeader(aMessage, aMessageInfo, kUriCommissionerGet));
447 }
448
449 template <>
HandleTmf(Coap::Message & aMessage,const Ip6::MessageInfo & aMessageInfo)450 void BorderAgent::HandleTmf<kUriCommissionerSet>(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
451 {
452 IgnoreError(ForwardToLeader(aMessage, aMessageInfo, kUriCommissionerSet));
453 }
454
HandleTmf(Coap::Message & aMessage,const Ip6::MessageInfo & aMessageInfo)455 template <> void BorderAgent::HandleTmf<kUriActiveGet>(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
456 {
457 IgnoreError(ForwardToLeader(aMessage, aMessageInfo, kUriActiveGet));
458 }
459
HandleTmf(Coap::Message & aMessage,const Ip6::MessageInfo & aMessageInfo)460 template <> void BorderAgent::HandleTmf<kUriActiveSet>(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
461 {
462 IgnoreError(ForwardToLeader(aMessage, aMessageInfo, kUriActiveSet));
463 }
464
HandleTmf(Coap::Message & aMessage,const Ip6::MessageInfo & aMessageInfo)465 template <> void BorderAgent::HandleTmf<kUriPendingGet>(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
466 {
467 IgnoreError(ForwardToLeader(aMessage, aMessageInfo, kUriPendingGet));
468 }
469
HandleTmf(Coap::Message & aMessage,const Ip6::MessageInfo & aMessageInfo)470 template <> void BorderAgent::HandleTmf<kUriPendingSet>(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
471 {
472 IgnoreError(ForwardToLeader(aMessage, aMessageInfo, kUriPendingSet));
473 }
474
475 template <>
HandleTmf(Coap::Message & aMessage,const Ip6::MessageInfo & aMessageInfo)476 void BorderAgent::HandleTmf<kUriCommissionerKeepAlive>(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
477 {
478 VerifyOrExit(mState != kStateStopped);
479
480 SuccessOrExit(ForwardToLeader(aMessage, aMessageInfo, kUriLeaderKeepAlive));
481 mTimer.Start(kKeepAliveTimeout);
482
483 exit:
484 return;
485 }
486
HandleTmf(Coap::Message & aMessage,const Ip6::MessageInfo & aMessageInfo)487 template <> void BorderAgent::HandleTmf<kUriRelayTx>(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
488 {
489 OT_UNUSED_VARIABLE(aMessageInfo);
490
491 Error error = kErrorNone;
492 uint16_t joinerRouterRloc;
493 Coap::Message *message = nullptr;
494 Tmf::MessageInfo messageInfo(GetInstance());
495
496 VerifyOrExit(mState != kStateStopped);
497
498 VerifyOrExit(aMessage.IsNonConfirmablePostRequest());
499
500 SuccessOrExit(error = Tlv::Find<JoinerRouterLocatorTlv>(aMessage, joinerRouterRloc));
501
502 message = Get<Tmf::Agent>().NewPriorityNonConfirmablePostMessage(kUriRelayTx);
503 VerifyOrExit(message != nullptr, error = kErrorNoBufs);
504
505 SuccessOrExit(error = message->AppendBytesFromMessage(aMessage, aMessage.GetOffset(),
506 aMessage.GetLength() - aMessage.GetOffset()));
507
508 messageInfo.SetSockAddrToRlocPeerAddrTo(joinerRouterRloc);
509 messageInfo.SetSockPortToTmf();
510
511 SuccessOrExit(error = Get<Tmf::Agent>().SendMessage(*message, messageInfo));
512
513 LogInfo("Sent to joiner router request on RelayTx (c/tx)");
514
515 exit:
516 FreeMessageOnError(message, error);
517 LogError("send to joiner router request RelayTx (c/tx)", error);
518 }
519
ForwardToLeader(const Coap::Message & aMessage,const Ip6::MessageInfo & aMessageInfo,Uri aUri)520 Error BorderAgent::ForwardToLeader(const Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo, Uri aUri)
521 {
522 Error error = kErrorNone;
523 OwnedPtr<ForwardContext> forwardContext;
524 Tmf::MessageInfo messageInfo(GetInstance());
525 Coap::Message *message = nullptr;
526 bool petition = false;
527 bool separate = false;
528
529 VerifyOrExit(mState != kStateStopped);
530
531 switch (aUri)
532 {
533 case kUriLeaderPetition:
534 petition = true;
535 separate = true;
536 break;
537 case kUriLeaderKeepAlive:
538 separate = true;
539 break;
540 default:
541 break;
542 }
543
544 if (separate)
545 {
546 SuccessOrExit(error = Get<Tmf::SecureAgent>().SendAck(aMessage, aMessageInfo));
547 }
548
549 forwardContext.Reset(ForwardContext::AllocateAndInit(GetInstance(), aMessage, petition, separate));
550 VerifyOrExit(!forwardContext.IsNull(), error = kErrorNoBufs);
551
552 message = Get<Tmf::Agent>().NewPriorityConfirmablePostMessage(aUri);
553 VerifyOrExit(message != nullptr, error = kErrorNoBufs);
554
555 SuccessOrExit(error = message->AppendBytesFromMessage(aMessage, aMessage.GetOffset(),
556 aMessage.GetLength() - aMessage.GetOffset()));
557
558 SuccessOrExit(error = messageInfo.SetSockAddrToRlocPeerAddrToLeaderAloc());
559 messageInfo.SetSockPortToTmf();
560
561 SuccessOrExit(error =
562 Get<Tmf::Agent>().SendMessage(*message, messageInfo, HandleCoapResponse, forwardContext.Get()));
563
564 // Release the ownership of `forwardContext` since `SendMessage()`
565 // will own it. We take back ownership from `HandleCoapResponse()`
566 // callback.
567
568 forwardContext.Release();
569
570 LogInfo("Forwarded request to leader on %s", PathForUri(aUri));
571
572 exit:
573 LogError("forward to leader", error);
574
575 if (error != kErrorNone)
576 {
577 FreeMessage(message);
578 SendErrorMessage(aMessage, separate, error);
579 }
580
581 return error;
582 }
583
HandleConnected(bool aConnected,void * aContext)584 void BorderAgent::HandleConnected(bool aConnected, void *aContext)
585 {
586 static_cast<BorderAgent *>(aContext)->HandleConnected(aConnected);
587 }
588
HandleConnected(bool aConnected)589 void BorderAgent::HandleConnected(bool aConnected)
590 {
591 if (aConnected)
592 {
593 LogInfo("Commissioner connected");
594 mState = kStateActive;
595 mTimer.Start(kKeepAliveTimeout);
596 }
597 else
598 {
599 LogInfo("Commissioner disconnected");
600 IgnoreError(Get<Ip6::Udp>().RemoveReceiver(mUdpReceiver));
601 Get<ThreadNetif>().RemoveUnicastAddress(mCommissionerAloc);
602 mState = kStateStarted;
603 mUdpProxyPort = 0;
604 }
605 }
606
GetUdpPort(void) const607 uint16_t BorderAgent::GetUdpPort(void) const { return Get<Tmf::SecureAgent>().GetUdpPort(); }
608
Start(void)609 void BorderAgent::Start(void)
610 {
611 Error error;
612 Pskc pskc;
613
614 VerifyOrExit(mState == kStateStopped, error = kErrorNone);
615
616 Get<KeyManager>().GetPskc(pskc);
617 SuccessOrExit(error = Get<Tmf::SecureAgent>().Start(kUdpPort));
618 SuccessOrExit(error = Get<Tmf::SecureAgent>().SetPsk(pskc.m8, Pskc::kSize));
619
620 pskc.Clear();
621 Get<Tmf::SecureAgent>().SetConnectedCallback(HandleConnected, this);
622
623 mState = kStateStarted;
624 mUdpProxyPort = 0;
625
626 LogInfo("Border Agent start listening on port %u", GetUdpPort());
627
628 exit:
629 LogError("start agent", error);
630 }
631
HandleTimeout(void)632 void BorderAgent::HandleTimeout(void)
633 {
634 if (Get<Tmf::SecureAgent>().IsConnected())
635 {
636 Get<Tmf::SecureAgent>().Disconnect();
637 LogWarn("Reset commissioner session");
638 }
639 }
640
Stop(void)641 void BorderAgent::Stop(void)
642 {
643 VerifyOrExit(mState != kStateStopped);
644
645 mTimer.Stop();
646 Get<Tmf::SecureAgent>().Stop();
647
648 mState = kStateStopped;
649 mUdpProxyPort = 0;
650
651 LogInfo("Border Agent stopped");
652
653 exit:
654 return;
655 }
656
657 #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_WARN)
LogError(const char * aActionText,Error aError)658 void BorderAgent::LogError(const char *aActionText, Error aError)
659 {
660 if (aError != kErrorNone)
661 {
662 LogWarn("Failed to %s: %s", aActionText, ErrorToString(aError));
663 }
664 }
665 #endif
666
667 } // namespace MeshCoP
668 } // namespace ot
669
670 #endif // OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE
671