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