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