665 lines
22 KiB
C++
665 lines
22 KiB
C++
/*
|
|
* Copyright (c) 2018, The OpenThread Authors.
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* 3. Neither the name of the copyright holder nor the
|
|
* names of its contributors may be used to endorse or promote products
|
|
* derived from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
/**
|
|
* @file
|
|
* This file implements the BorderAgent service.
|
|
*/
|
|
|
|
#include "border_agent.hpp"
|
|
|
|
#if OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE
|
|
|
|
#include "coap/coap_message.hpp"
|
|
#include "common/as_core_type.hpp"
|
|
#include "common/heap.hpp"
|
|
#include "common/instance.hpp"
|
|
#include "common/locator_getters.hpp"
|
|
#include "common/log.hpp"
|
|
#include "meshcop/meshcop.hpp"
|
|
#include "meshcop/meshcop_tlvs.hpp"
|
|
#include "thread/thread_netif.hpp"
|
|
#include "thread/thread_tlvs.hpp"
|
|
#include "thread/uri_paths.hpp"
|
|
|
|
namespace ot {
|
|
namespace MeshCoP {
|
|
|
|
RegisterLogModule("BorderAgent");
|
|
|
|
namespace {
|
|
constexpr uint16_t kBorderAgentUdpPort = OPENTHREAD_CONFIG_BORDER_AGENT_UDP_PORT; ///< UDP port of border agent service.
|
|
}
|
|
|
|
void BorderAgent::ForwardContext::Init(Instance & aInstance,
|
|
const Coap::Message &aMessage,
|
|
bool aPetition,
|
|
bool aSeparate)
|
|
{
|
|
InstanceLocatorInit::Init(aInstance);
|
|
mMessageId = aMessage.GetMessageId();
|
|
mPetition = aPetition;
|
|
mSeparate = aSeparate;
|
|
mType = aMessage.GetType();
|
|
mTokenLength = aMessage.GetTokenLength();
|
|
memcpy(mToken, aMessage.GetToken(), mTokenLength);
|
|
}
|
|
|
|
Error BorderAgent::ForwardContext::ToHeader(Coap::Message &aMessage, uint8_t aCode)
|
|
{
|
|
if ((mType == Coap::kTypeNonConfirmable) || mSeparate)
|
|
{
|
|
aMessage.Init(Coap::kTypeNonConfirmable, static_cast<Coap::Code>(aCode));
|
|
}
|
|
else
|
|
{
|
|
aMessage.Init(Coap::kTypeAck, static_cast<Coap::Code>(aCode));
|
|
}
|
|
|
|
if (!mSeparate)
|
|
{
|
|
aMessage.SetMessageId(mMessageId);
|
|
}
|
|
|
|
return aMessage.SetToken(mToken, mTokenLength);
|
|
}
|
|
|
|
Coap::Message::Code BorderAgent::CoapCodeFromError(Error aError)
|
|
{
|
|
Coap::Message::Code code;
|
|
|
|
switch (aError)
|
|
{
|
|
case kErrorNone:
|
|
code = Coap::kCodeChanged;
|
|
break;
|
|
|
|
case kErrorParse:
|
|
code = Coap::kCodeBadRequest;
|
|
break;
|
|
|
|
default:
|
|
code = Coap::kCodeInternalError;
|
|
break;
|
|
}
|
|
|
|
return code;
|
|
}
|
|
|
|
void BorderAgent::SendErrorMessage(ForwardContext &aForwardContext, Error aError)
|
|
{
|
|
Error error = kErrorNone;
|
|
Coap::CoapSecure &coaps = Get<Coap::CoapSecure>();
|
|
Coap::Message * message = nullptr;
|
|
|
|
VerifyOrExit((message = coaps.NewPriorityMessage()) != nullptr, error = kErrorNoBufs);
|
|
SuccessOrExit(error = aForwardContext.ToHeader(*message, CoapCodeFromError(aError)));
|
|
SuccessOrExit(error = coaps.SendMessage(*message, coaps.GetMessageInfo()));
|
|
|
|
exit:
|
|
FreeMessageOnError(message, error);
|
|
LogError("send error CoAP message", error);
|
|
}
|
|
|
|
void BorderAgent::SendErrorMessage(const Coap::Message &aRequest, bool aSeparate, Error aError)
|
|
{
|
|
Error error = kErrorNone;
|
|
Coap::CoapSecure &coaps = Get<Coap::CoapSecure>();
|
|
Coap::Message * message = nullptr;
|
|
|
|
VerifyOrExit((message = coaps.NewPriorityMessage()) != nullptr, error = kErrorNoBufs);
|
|
|
|
if (aRequest.IsNonConfirmable() || aSeparate)
|
|
{
|
|
message->Init(Coap::kTypeNonConfirmable, CoapCodeFromError(aError));
|
|
}
|
|
else
|
|
{
|
|
message->Init(Coap::kTypeAck, CoapCodeFromError(aError));
|
|
}
|
|
|
|
if (!aSeparate)
|
|
{
|
|
message->SetMessageId(aRequest.GetMessageId());
|
|
}
|
|
|
|
SuccessOrExit(error = message->SetTokenFromMessage(aRequest));
|
|
|
|
SuccessOrExit(error = coaps.SendMessage(*message, coaps.GetMessageInfo()));
|
|
|
|
exit:
|
|
FreeMessageOnError(message, error);
|
|
LogError("send error CoAP message", error);
|
|
}
|
|
|
|
void BorderAgent::HandleCoapResponse(void * aContext,
|
|
otMessage * aMessage,
|
|
const otMessageInfo *aMessageInfo,
|
|
Error aResult)
|
|
{
|
|
OT_UNUSED_VARIABLE(aMessageInfo);
|
|
|
|
ForwardContext &forwardContext = *static_cast<ForwardContext *>(aContext);
|
|
|
|
forwardContext.Get<BorderAgent>().HandleCoapResponse(forwardContext, AsCoapMessagePtr(aMessage), aResult);
|
|
}
|
|
|
|
void BorderAgent::HandleCoapResponse(ForwardContext &aForwardContext, const Coap::Message *aResponse, Error aResult)
|
|
{
|
|
Coap::Message *message = nullptr;
|
|
Error error;
|
|
|
|
SuccessOrExit(error = aResult);
|
|
VerifyOrExit((message = Get<Coap::CoapSecure>().NewPriorityMessage()) != nullptr, error = kErrorNoBufs);
|
|
|
|
if (aForwardContext.IsPetition() && aResponse->GetCode() == Coap::kCodeChanged)
|
|
{
|
|
uint8_t state;
|
|
|
|
SuccessOrExit(error = Tlv::Find<StateTlv>(*aResponse, state));
|
|
|
|
if (state == StateTlv::kAccept)
|
|
{
|
|
uint16_t sessionId;
|
|
|
|
SuccessOrExit(error = Tlv::Find<CommissionerSessionIdTlv>(*aResponse, sessionId));
|
|
|
|
IgnoreError(Get<Mle::MleRouter>().GetCommissionerAloc(mCommissionerAloc.GetAddress(), sessionId));
|
|
Get<ThreadNetif>().AddUnicastAddress(mCommissionerAloc);
|
|
IgnoreError(Get<Ip6::Udp>().AddReceiver(mUdpReceiver));
|
|
|
|
LogInfo("commissioner accepted: session ID=%d, ALOC=%s", sessionId,
|
|
mCommissionerAloc.GetAddress().ToString().AsCString());
|
|
}
|
|
}
|
|
|
|
SuccessOrExit(error = aForwardContext.ToHeader(*message, aResponse->GetCode()));
|
|
|
|
if (aResponse->GetLength() > aResponse->GetOffset())
|
|
{
|
|
SuccessOrExit(error = message->SetPayloadMarker());
|
|
}
|
|
|
|
SuccessOrExit(error = ForwardToCommissioner(*message, *aResponse));
|
|
|
|
exit:
|
|
|
|
if (error != kErrorNone)
|
|
{
|
|
FreeMessage(message);
|
|
|
|
LogWarn("Commissioner request[%hu] failed: %s", aForwardContext.GetMessageId(), ErrorToString(error));
|
|
|
|
SendErrorMessage(aForwardContext, error);
|
|
}
|
|
|
|
Heap::Free(&aForwardContext);
|
|
}
|
|
|
|
template <Coap::Resource BorderAgent::*aResource>
|
|
void BorderAgent::HandleRequest(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo)
|
|
{
|
|
IgnoreError(static_cast<BorderAgent *>(aContext)->ForwardToLeader(
|
|
AsCoapMessage(aMessage), AsCoreType(aMessageInfo),
|
|
(static_cast<BorderAgent *>(aContext)->*aResource).GetUriPath(), false, false));
|
|
}
|
|
|
|
template <>
|
|
void BorderAgent::HandleRequest<&BorderAgent::mCommissionerPetition>(void * aContext,
|
|
otMessage * aMessage,
|
|
const otMessageInfo *aMessageInfo)
|
|
{
|
|
IgnoreError(static_cast<BorderAgent *>(aContext)->ForwardToLeader(AsCoapMessage(aMessage), AsCoreType(aMessageInfo),
|
|
UriPath::kLeaderPetition, true, true));
|
|
}
|
|
|
|
template <>
|
|
void BorderAgent::HandleRequest<&BorderAgent::mCommissionerKeepAlive>(void * aContext,
|
|
otMessage * aMessage,
|
|
const otMessageInfo *aMessageInfo)
|
|
{
|
|
static_cast<BorderAgent *>(aContext)->HandleKeepAlive(AsCoapMessage(aMessage), AsCoreType(aMessageInfo));
|
|
}
|
|
|
|
template <>
|
|
void BorderAgent::HandleRequest<&BorderAgent::mRelayTransmit>(void * aContext,
|
|
otMessage * aMessage,
|
|
const otMessageInfo *aMessageInfo)
|
|
{
|
|
OT_UNUSED_VARIABLE(aMessageInfo);
|
|
static_cast<BorderAgent *>(aContext)->HandleRelayTransmit(AsCoapMessage(aMessage));
|
|
}
|
|
|
|
template <>
|
|
void BorderAgent::HandleRequest<&BorderAgent::mRelayReceive>(void * aContext,
|
|
otMessage * aMessage,
|
|
const otMessageInfo *aMessageInfo)
|
|
{
|
|
OT_UNUSED_VARIABLE(aMessageInfo);
|
|
static_cast<BorderAgent *>(aContext)->HandleRelayReceive(AsCoapMessage(aMessage));
|
|
}
|
|
|
|
template <>
|
|
void BorderAgent::HandleRequest<&BorderAgent::mProxyTransmit>(void * aContext,
|
|
otMessage * aMessage,
|
|
const otMessageInfo *aMessageInfo)
|
|
{
|
|
OT_UNUSED_VARIABLE(aMessageInfo);
|
|
static_cast<BorderAgent *>(aContext)->HandleProxyTransmit(AsCoapMessage(aMessage));
|
|
}
|
|
|
|
BorderAgent::BorderAgent(Instance &aInstance)
|
|
: InstanceLocator(aInstance)
|
|
, mCommissionerPetition(UriPath::kCommissionerPetition,
|
|
BorderAgent::HandleRequest<&BorderAgent::mCommissionerPetition>,
|
|
this)
|
|
, mCommissionerKeepAlive(UriPath::kCommissionerKeepAlive,
|
|
BorderAgent::HandleRequest<&BorderAgent::mCommissionerKeepAlive>,
|
|
this)
|
|
, mRelayTransmit(UriPath::kRelayTx, BorderAgent::HandleRequest<&BorderAgent::mRelayTransmit>, this)
|
|
, mRelayReceive(UriPath::kRelayRx, BorderAgent::HandleRequest<&BorderAgent::mRelayReceive>, this)
|
|
, mCommissionerGet(UriPath::kCommissionerGet, BorderAgent::HandleRequest<&BorderAgent::mCommissionerGet>, this)
|
|
, mCommissionerSet(UriPath::kCommissionerSet, BorderAgent::HandleRequest<&BorderAgent::mCommissionerSet>, this)
|
|
, mActiveGet(UriPath::kActiveGet, BorderAgent::HandleRequest<&BorderAgent::mActiveGet>, this)
|
|
, mActiveSet(UriPath::kActiveSet, BorderAgent::HandleRequest<&BorderAgent::mActiveSet>, this)
|
|
, mPendingGet(UriPath::kPendingGet, BorderAgent::HandleRequest<&BorderAgent::mPendingGet>, this)
|
|
, mPendingSet(UriPath::kPendingSet, BorderAgent::HandleRequest<&BorderAgent::mPendingSet>, this)
|
|
, mProxyTransmit(UriPath::kProxyTx, BorderAgent::HandleRequest<&BorderAgent::mProxyTransmit>, this)
|
|
, mUdpReceiver(BorderAgent::HandleUdpReceive, this)
|
|
, mTimer(aInstance, HandleTimeout)
|
|
, mState(kStateStopped)
|
|
, mUdpProxyPort(0)
|
|
{
|
|
mCommissionerAloc.InitAsThreadOriginRealmLocalScope();
|
|
}
|
|
|
|
void BorderAgent::HandleNotifierEvents(Events aEvents)
|
|
{
|
|
VerifyOrExit(aEvents.ContainsAny(kEventThreadRoleChanged | kEventCommissionerStateChanged));
|
|
|
|
#if OPENTHREAD_CONFIG_COMMISSIONER_ENABLE && OPENTHREAD_FTD
|
|
VerifyOrExit(Get<Commissioner>().IsDisabled());
|
|
#endif
|
|
|
|
if (Get<Mle::MleRouter>().IsAttached())
|
|
{
|
|
Start();
|
|
}
|
|
else
|
|
{
|
|
Stop();
|
|
}
|
|
|
|
exit:
|
|
return;
|
|
}
|
|
|
|
void BorderAgent::HandleProxyTransmit(const Coap::Message &aMessage)
|
|
{
|
|
Message * message = nullptr;
|
|
Ip6::MessageInfo messageInfo;
|
|
uint16_t offset;
|
|
Error error;
|
|
UdpEncapsulationTlv tlv;
|
|
|
|
SuccessOrExit(error = Tlv::FindTlvOffset(aMessage, Tlv::kUdpEncapsulation, offset));
|
|
SuccessOrExit(error = aMessage.Read(offset, tlv));
|
|
|
|
VerifyOrExit((message = Get<Ip6::Udp>().NewMessage(0)) != nullptr, error = kErrorNoBufs);
|
|
SuccessOrExit(error = message->SetLength(tlv.GetUdpLength()));
|
|
aMessage.CopyTo(offset + sizeof(tlv), 0, tlv.GetUdpLength(), *message);
|
|
|
|
VerifyOrExit(tlv.GetSourcePort() > 0 && tlv.GetDestinationPort() > 0, error = kErrorDrop);
|
|
|
|
messageInfo.SetSockPort(tlv.GetSourcePort());
|
|
messageInfo.SetSockAddr(mCommissionerAloc.GetAddress());
|
|
messageInfo.SetPeerPort(tlv.GetDestinationPort());
|
|
|
|
SuccessOrExit(error = Tlv::Find<Ip6AddressTlv>(aMessage, messageInfo.GetPeerAddr()));
|
|
|
|
SuccessOrExit(error = Get<Ip6::Udp>().SendDatagram(*message, messageInfo, Ip6::kProtoUdp));
|
|
mUdpProxyPort = tlv.GetSourcePort();
|
|
|
|
LogInfo("Proxy transmit sent to %s", messageInfo.GetPeerAddr().ToString().AsCString());
|
|
|
|
exit:
|
|
FreeMessageOnError(message, error);
|
|
LogError("send proxy stream", error);
|
|
}
|
|
|
|
bool BorderAgent::HandleUdpReceive(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
|
|
{
|
|
Error error;
|
|
Coap::Message *message = nullptr;
|
|
|
|
VerifyOrExit(aMessageInfo.GetSockAddr() == mCommissionerAloc.GetAddress(),
|
|
error = kErrorDestinationAddressFiltered);
|
|
|
|
VerifyOrExit(aMessage.GetLength() > 0, error = kErrorNone);
|
|
|
|
message = Get<Coap::CoapSecure>().NewPriorityNonConfirmablePostMessage(UriPath::kProxyRx);
|
|
VerifyOrExit(message != nullptr, error = kErrorNoBufs);
|
|
|
|
{
|
|
UdpEncapsulationTlv tlv;
|
|
uint16_t offset;
|
|
uint16_t udpLength = aMessage.GetLength() - aMessage.GetOffset();
|
|
|
|
tlv.Init();
|
|
tlv.SetSourcePort(aMessageInfo.GetPeerPort());
|
|
tlv.SetDestinationPort(aMessageInfo.GetSockPort());
|
|
tlv.SetUdpLength(udpLength);
|
|
SuccessOrExit(error = message->Append(tlv));
|
|
|
|
offset = message->GetLength();
|
|
SuccessOrExit(error = message->SetLength(offset + udpLength));
|
|
aMessage.CopyTo(aMessage.GetOffset(), offset, udpLength, *message);
|
|
}
|
|
|
|
SuccessOrExit(error = Tlv::Append<Ip6AddressTlv>(*message, aMessageInfo.GetPeerAddr()));
|
|
|
|
SuccessOrExit(error = Get<Coap::CoapSecure>().SendMessage(*message, Get<Coap::CoapSecure>().GetMessageInfo()));
|
|
|
|
LogInfo("Sent to commissioner on %s", UriPath::kProxyRx);
|
|
|
|
exit:
|
|
FreeMessageOnError(message, error);
|
|
LogError("notify commissioner on ProxyRx (c/ur)", error);
|
|
|
|
return error != kErrorDestinationAddressFiltered;
|
|
}
|
|
|
|
void BorderAgent::HandleRelayReceive(const Coap::Message &aMessage)
|
|
{
|
|
Coap::Message *message = nullptr;
|
|
Error error;
|
|
|
|
VerifyOrExit(aMessage.IsNonConfirmablePostRequest(), error = kErrorDrop);
|
|
|
|
message = Get<Coap::CoapSecure>().NewPriorityNonConfirmablePostMessage(UriPath::kRelayRx);
|
|
VerifyOrExit(message != nullptr, error = kErrorNoBufs);
|
|
|
|
SuccessOrExit(error = ForwardToCommissioner(*message, aMessage));
|
|
LogInfo("Sent to commissioner on %s", UriPath::kRelayRx);
|
|
|
|
exit:
|
|
FreeMessageOnError(message, error);
|
|
}
|
|
|
|
Error BorderAgent::ForwardToCommissioner(Coap::Message &aForwardMessage, const Message &aMessage)
|
|
{
|
|
Error error = kErrorNone;
|
|
uint16_t offset = 0;
|
|
|
|
offset = aForwardMessage.GetLength();
|
|
SuccessOrExit(error = aForwardMessage.SetLength(offset + aMessage.GetLength() - aMessage.GetOffset()));
|
|
aMessage.CopyTo(aMessage.GetOffset(), offset, aMessage.GetLength() - aMessage.GetOffset(), aForwardMessage);
|
|
|
|
SuccessOrExit(error =
|
|
Get<Coap::CoapSecure>().SendMessage(aForwardMessage, Get<Coap::CoapSecure>().GetMessageInfo()));
|
|
|
|
LogInfo("Sent to commissioner");
|
|
|
|
exit:
|
|
LogError("send to commissioner", error);
|
|
return error;
|
|
}
|
|
|
|
void BorderAgent::HandleKeepAlive(const Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
|
|
{
|
|
Error error;
|
|
|
|
error = ForwardToLeader(aMessage, aMessageInfo, UriPath::kLeaderKeepAlive, false, true);
|
|
|
|
if (error == kErrorNone)
|
|
{
|
|
mTimer.Start(kKeepAliveTimeout);
|
|
}
|
|
}
|
|
|
|
void BorderAgent::HandleRelayTransmit(const Coap::Message &aMessage)
|
|
{
|
|
Error error = kErrorNone;
|
|
uint16_t joinerRouterRloc;
|
|
Coap::Message * message = nullptr;
|
|
Tmf::MessageInfo messageInfo(GetInstance());
|
|
uint16_t offset = 0;
|
|
|
|
VerifyOrExit(aMessage.IsNonConfirmablePostRequest());
|
|
|
|
SuccessOrExit(error = Tlv::Find<JoinerRouterLocatorTlv>(aMessage, joinerRouterRloc));
|
|
|
|
message = Get<Tmf::Agent>().NewPriorityNonConfirmablePostMessage(UriPath::kRelayTx);
|
|
VerifyOrExit(message != nullptr, error = kErrorNoBufs);
|
|
|
|
offset = message->GetLength();
|
|
SuccessOrExit(error = message->SetLength(offset + aMessage.GetLength() - aMessage.GetOffset()));
|
|
aMessage.CopyTo(aMessage.GetOffset(), offset, aMessage.GetLength() - aMessage.GetOffset(), *message);
|
|
|
|
messageInfo.SetSockAddrToRlocPeerAddrTo(joinerRouterRloc);
|
|
messageInfo.SetSockPortToTmf();
|
|
|
|
SuccessOrExit(error = Get<Tmf::Agent>().SendMessage(*message, messageInfo));
|
|
|
|
LogInfo("Sent to joiner router request on %s", UriPath::kRelayTx);
|
|
|
|
exit:
|
|
FreeMessageOnError(message, error);
|
|
LogError("send to joiner router request RelayTx (c/tx)", error);
|
|
}
|
|
|
|
Error BorderAgent::ForwardToLeader(const Coap::Message & aMessage,
|
|
const Ip6::MessageInfo &aMessageInfo,
|
|
const char * aPath,
|
|
bool aPetition,
|
|
bool aSeparate)
|
|
{
|
|
Error error = kErrorNone;
|
|
ForwardContext * forwardContext = nullptr;
|
|
Tmf::MessageInfo messageInfo(GetInstance());
|
|
Coap::Message * message = nullptr;
|
|
uint16_t offset = 0;
|
|
|
|
if (aSeparate)
|
|
{
|
|
SuccessOrExit(error = Get<Coap::CoapSecure>().SendAck(aMessage, aMessageInfo));
|
|
}
|
|
|
|
forwardContext = static_cast<ForwardContext *>(Heap::CAlloc(1, sizeof(ForwardContext)));
|
|
VerifyOrExit(forwardContext != nullptr, error = kErrorNoBufs);
|
|
|
|
forwardContext->Init(GetInstance(), aMessage, aPetition, aSeparate);
|
|
|
|
message = Get<Tmf::Agent>().NewPriorityConfirmablePostMessage(aPath);
|
|
VerifyOrExit(message != nullptr, error = kErrorNoBufs);
|
|
|
|
offset = message->GetLength();
|
|
SuccessOrExit(error = message->SetLength(offset + aMessage.GetLength() - aMessage.GetOffset()));
|
|
aMessage.CopyTo(aMessage.GetOffset(), offset, aMessage.GetLength() - aMessage.GetOffset(), *message);
|
|
|
|
SuccessOrExit(error = messageInfo.SetSockAddrToRlocPeerAddrToLeaderAloc());
|
|
messageInfo.SetSockPortToTmf();
|
|
|
|
SuccessOrExit(error = Get<Tmf::Agent>().SendMessage(*message, messageInfo, HandleCoapResponse, forwardContext));
|
|
|
|
// HandleCoapResponse is responsible to free this forward context.
|
|
forwardContext = nullptr;
|
|
|
|
LogInfo("Forwarded request to leader on %s", aPath);
|
|
|
|
exit:
|
|
LogError("forward to leader", error);
|
|
|
|
if (error != kErrorNone)
|
|
{
|
|
if (forwardContext != nullptr)
|
|
{
|
|
Heap::Free(forwardContext);
|
|
}
|
|
|
|
FreeMessage(message);
|
|
SendErrorMessage(aMessage, aSeparate, error);
|
|
}
|
|
|
|
return error;
|
|
}
|
|
|
|
void BorderAgent::HandleConnected(bool aConnected, void *aContext)
|
|
{
|
|
static_cast<BorderAgent *>(aContext)->HandleConnected(aConnected);
|
|
}
|
|
|
|
void BorderAgent::HandleConnected(bool aConnected)
|
|
{
|
|
if (aConnected)
|
|
{
|
|
LogInfo("Commissioner connected");
|
|
mState = kStateActive;
|
|
mTimer.Start(kKeepAliveTimeout);
|
|
}
|
|
else
|
|
{
|
|
LogInfo("Commissioner disconnected");
|
|
IgnoreError(Get<Ip6::Udp>().RemoveReceiver(mUdpReceiver));
|
|
Get<ThreadNetif>().RemoveUnicastAddress(mCommissionerAloc);
|
|
mState = kStateStarted;
|
|
mUdpProxyPort = 0;
|
|
}
|
|
}
|
|
|
|
uint16_t BorderAgent::GetUdpPort(void) const
|
|
{
|
|
return Get<Coap::CoapSecure>().GetUdpPort();
|
|
}
|
|
|
|
void BorderAgent::Start(void)
|
|
{
|
|
Error error;
|
|
Coap::CoapSecure &coaps = Get<Coap::CoapSecure>();
|
|
Pskc pskc;
|
|
|
|
VerifyOrExit(mState == kStateStopped, error = kErrorNone);
|
|
|
|
Get<KeyManager>().GetPskc(pskc);
|
|
SuccessOrExit(error = coaps.Start(kBorderAgentUdpPort));
|
|
SuccessOrExit(error = coaps.SetPsk(pskc.m8, Pskc::kSize));
|
|
|
|
pskc.Clear();
|
|
coaps.SetConnectedCallback(HandleConnected, this);
|
|
|
|
coaps.AddResource(mActiveGet);
|
|
coaps.AddResource(mActiveSet);
|
|
coaps.AddResource(mPendingGet);
|
|
coaps.AddResource(mPendingSet);
|
|
coaps.AddResource(mCommissionerPetition);
|
|
coaps.AddResource(mCommissionerKeepAlive);
|
|
coaps.AddResource(mCommissionerSet);
|
|
coaps.AddResource(mCommissionerGet);
|
|
coaps.AddResource(mProxyTransmit);
|
|
coaps.AddResource(mRelayTransmit);
|
|
|
|
Get<Tmf::Agent>().AddResource(mRelayReceive);
|
|
|
|
mState = kStateStarted;
|
|
mUdpProxyPort = 0;
|
|
|
|
LogInfo("Border Agent start listening on port %u", GetUdpPort());
|
|
|
|
exit:
|
|
if (error != kErrorNone)
|
|
{
|
|
LogWarn("failed to start Border Agent on port %d: %s", kBorderAgentUdpPort, ErrorToString(error));
|
|
}
|
|
}
|
|
|
|
void BorderAgent::HandleTimeout(Timer &aTimer)
|
|
{
|
|
aTimer.Get<BorderAgent>().HandleTimeout();
|
|
}
|
|
|
|
void BorderAgent::HandleTimeout(void)
|
|
{
|
|
if (Get<Coap::CoapSecure>().IsConnected())
|
|
{
|
|
Get<Coap::CoapSecure>().Disconnect();
|
|
LogWarn("Reset commissioner session");
|
|
}
|
|
}
|
|
|
|
void BorderAgent::Stop(void)
|
|
{
|
|
Coap::CoapSecure &coaps = Get<Coap::CoapSecure>();
|
|
|
|
VerifyOrExit(mState != kStateStopped);
|
|
|
|
mTimer.Stop();
|
|
|
|
coaps.RemoveResource(mCommissionerPetition);
|
|
coaps.RemoveResource(mCommissionerKeepAlive);
|
|
coaps.RemoveResource(mCommissionerSet);
|
|
coaps.RemoveResource(mCommissionerGet);
|
|
coaps.RemoveResource(mActiveGet);
|
|
coaps.RemoveResource(mActiveSet);
|
|
coaps.RemoveResource(mPendingGet);
|
|
coaps.RemoveResource(mPendingSet);
|
|
coaps.RemoveResource(mProxyTransmit);
|
|
coaps.RemoveResource(mRelayTransmit);
|
|
|
|
Get<Tmf::Agent>().RemoveResource(mRelayReceive);
|
|
|
|
coaps.Stop();
|
|
|
|
mState = kStateStopped;
|
|
mUdpProxyPort = 0;
|
|
|
|
LogInfo("Border Agent stopped");
|
|
|
|
exit:
|
|
return;
|
|
}
|
|
|
|
void BorderAgent::ApplyMeshLocalPrefix(void)
|
|
{
|
|
VerifyOrExit(mState == kStateActive);
|
|
|
|
if (Get<ThreadNetif>().HasUnicastAddress(mCommissionerAloc))
|
|
{
|
|
Get<ThreadNetif>().RemoveUnicastAddress(mCommissionerAloc);
|
|
mCommissionerAloc.GetAddress().SetPrefix(Get<Mle::MleRouter>().GetMeshLocalPrefix());
|
|
Get<ThreadNetif>().AddUnicastAddress(mCommissionerAloc);
|
|
}
|
|
|
|
exit:
|
|
return;
|
|
}
|
|
|
|
} // namespace MeshCoP
|
|
} // namespace ot
|
|
|
|
#endif // OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE
|