diff --git a/src/core/meshcop/border_agent.cpp b/src/core/meshcop/border_agent.cpp index f2c013d5c..44006eedb 100644 --- a/src/core/meshcop/border_agent.cpp +++ b/src/core/meshcop/border_agent.cpp @@ -42,116 +42,337 @@ namespace MeshCoP { RegisterLogModule("BorderAgent"); -//---------------------------------------------------------------------------------------------------------------------- -// `BorderAgent::ForwardContext` - -Error 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); - - return kErrorNone; -} - -Error BorderAgent::ForwardContext::ToHeader(Coap::Message &aMessage, uint8_t aCode) const -{ - if ((mType == Coap::kTypeNonConfirmable) || mSeparate) - { - aMessage.Init(Coap::kTypeNonConfirmable, static_cast(aCode)); - } - else - { - aMessage.Init(Coap::kTypeAck, static_cast(aCode)); - } - - if (!mSeparate) - { - aMessage.SetMessageId(mMessageId); - } - - return aMessage.SetToken(mToken, mTokenLength); -} - //---------------------------------------------------------------------------------------------------------------------- // `BorderAgent` -Coap::Message::Code BorderAgent::CoapCodeFromError(Error aError) +BorderAgent::BorderAgent(Instance &aInstance) + : InstanceLocator(aInstance) + , mState(kStateStopped) + , mUdpProxyPort(0) + , mUdpReceiver(BorderAgent::HandleUdpReceive, this) + , mTimer(aInstance) +#if OPENTHREAD_CONFIG_BORDER_AGENT_ID_ENABLE + , mIdInitialized(false) +#endif +#if OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE + , mUsingEphemeralKey(false) + , mOldUdpPort(0) + , mEphemeralKeyTimer(aInstance) + , mEphemeralKeyTask(aInstance) +#endif { - Coap::Message::Code code; + mCommissionerAloc.InitAsThreadOriginMeshLocal(); + ClearAllBytes(mCounters); +} - switch (aError) +#if OPENTHREAD_CONFIG_BORDER_AGENT_ID_ENABLE +Error BorderAgent::GetId(Id &aId) +{ + Error error = kErrorNone; + + if (mIdInitialized) { - case kErrorNone: - code = Coap::kCodeChanged; - break; - - case kErrorParse: - code = Coap::kCodeBadRequest; - break; - - default: - code = Coap::kCodeInternalError; - break; + aId = mId; + ExitNow(); } - return code; -} + if (Get().Read(mId) != kErrorNone) + { + Random::NonCrypto::Fill(mId); + SuccessOrExit(error = Get().Save(mId)); + } -void BorderAgent::SendErrorMessage(const ForwardContext &aForwardContext, Error aError) -{ - Error error = kErrorNone; - Coap::Message *message = nullptr; - - VerifyOrExit((message = Get().NewPriorityMessage()) != nullptr, error = kErrorNoBufs); - SuccessOrExit(error = aForwardContext.ToHeader(*message, CoapCodeFromError(aError))); - SuccessOrExit(error = SendMessage(*message)); + mIdInitialized = true; + aId = mId; exit: - FreeMessageOnError(message, error); - LogWarnOnError(error, "send error CoAP message"); + return error; } -void BorderAgent::SendErrorMessage(const Coap::Message &aRequest, bool aSeparate, Error aError) +Error BorderAgent::SetId(const Id &aId) { - Error error = kErrorNone; - Coap::Message *message = nullptr; + Error error = kErrorNone; - VerifyOrExit((message = Get().NewPriorityMessage()) != nullptr, error = kErrorNoBufs); + SuccessOrExit(error = Get().Save(aId)); + mId = aId; + mIdInitialized = true; - if (aRequest.IsNonConfirmable() || aSeparate) +exit: + return error; +} +#endif // OPENTHREAD_CONFIG_BORDER_AGENT_ID_ENABLE + +Error BorderAgent::Start(uint16_t aUdpPort) +{ + Error error; + Pskc pskc; + + Get().GetPskc(pskc); + error = Start(aUdpPort, pskc.m8, Pskc::kSize); + pskc.Clear(); + + return error; +} + +Error BorderAgent::Start(uint16_t aUdpPort, const uint8_t *aPsk, uint8_t aPskLength) +{ + Error error = kErrorNone; + + VerifyOrExit(mState == kStateStopped); + +#if OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE + if (mUsingEphemeralKey) { - message->Init(Coap::kTypeNonConfirmable, CoapCodeFromError(aError)); + SuccessOrExit(error = Get().Start(aUdpPort, kMaxEphemeralKeyConnectionAttempts, + HandleSecureAgentStopped, this)); + } + else +#endif + { + SuccessOrExit(error = Get().Start(aUdpPort)); + } + + SuccessOrExit(error = Get().SetPsk(aPsk, aPskLength)); + + Get().SetConnectCallback(HandleConnected, this); + + mState = kStateStarted; + mUdpProxyPort = 0; + + LogInfo("Border Agent start listening on port %u", GetUdpPort()); + +exit: + LogWarnOnError(error, "start agent"); + return error; +} + +void BorderAgent::Stop(void) +{ + VerifyOrExit(mState != kStateStopped); + +#if OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE + if (mUsingEphemeralKey) + { + mUsingEphemeralKey = false; + mEphemeralKeyTimer.Stop(); + mEphemeralKeyTask.Post(); + } +#endif + + mTimer.Stop(); + Get().Stop(); + + mState = kStateStopped; + mUdpProxyPort = 0; + LogInfo("Border Agent stopped"); + +exit: + return; +} + +void BorderAgent::Disconnect(void) +{ + VerifyOrExit(mState == kStateConnected || mState == kStateAccepted); + + Get().Disconnect(); + +exit: + return; +} + +uint16_t BorderAgent::GetUdpPort(void) const { return Get().GetUdpPort(); } + +void BorderAgent::HandleNotifierEvents(Events aEvents) +{ + if ((aEvents.ContainsAny(kEventThreadRoleChanged | kEventCommissionerStateChanged))) + { +#if OPENTHREAD_CONFIG_COMMISSIONER_ENABLE && OPENTHREAD_FTD + VerifyOrExit(Get().IsDisabled()); +#endif + + if (Get().IsAttached()) + { + Start(); + } + else + { + Stop(); + } + } + + if (aEvents.ContainsAny(kEventPskcChanged)) + { + VerifyOrExit(mState != kStateStopped); + +#if OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE + // No-op if Ephemeralkey mode is activated, new pskc will be applied + // when Ephemeralkey mode is deactivated. + VerifyOrExit(!mUsingEphemeralKey); +#endif + + { + Pskc pskc; + Get().GetPskc(pskc); + + // If there is secure session already established, it won't be impacted, + // new pskc will be applied for next connection. + SuccessOrExit(Get().SetPsk(pskc.m8, Pskc::kSize)); + pskc.Clear(); + } + } + +exit: + return; +} + +void BorderAgent::HandleTimeout(void) +{ + if (Get().IsConnected()) + { + Get().Disconnect(); + LogWarn("Reset secure session"); + } +} + +void BorderAgent::HandleConnected(Dtls::ConnectEvent aEvent, void *aContext) +{ + static_cast(aContext)->HandleConnected(aEvent); +} + +void BorderAgent::HandleConnected(Dtls::ConnectEvent aEvent) +{ + if (aEvent == Dtls::kConnected) + { + LogInfo("SecureSession connected"); + mState = kStateConnected; + mTimer.Start(kKeepAliveTimeout); +#if OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE + if (mUsingEphemeralKey) + { + mCounters.mEpskcSecureSessionSuccesses++; + mEphemeralKeyTask.Post(); + } + else +#endif + { + mCounters.mPskcSecureSessionSuccesses++; + } } else { - message->Init(Coap::kTypeAck, CoapCodeFromError(aError)); + LogInfo("SecureSession disconnected"); + IgnoreError(Get().RemoveReceiver(mUdpReceiver)); + Get().RemoveUnicastAddress(mCommissionerAloc); + +#if OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE + if (mUsingEphemeralKey) + { + RestartAfterRemovingEphemeralKey(); + + if (aEvent == Dtls::kDisconnectedError) + { + mCounters.mEpskcSecureSessionFailures++; + } + else if (aEvent == Dtls::kDisconnectedPeerClosed) + { + mCounters.mEpskcDeactivationDisconnects++; + } + } + else +#endif + { + mState = kStateStarted; + mUdpProxyPort = 0; + + if (aEvent == Dtls::kDisconnectedError) + { + mCounters.mPskcSecureSessionFailures++; + } + } } - - if (!aSeparate) - { - message->SetMessageId(aRequest.GetMessageId()); - } - - SuccessOrExit(error = message->SetTokenFromMessage(aRequest)); - - SuccessOrExit(error = SendMessage(*message)); - -exit: - FreeMessageOnError(message, error); - LogWarnOnError(error, "send error CoAP message"); } -Error BorderAgent::SendMessage(Coap::Message &aMessage) +template <> +void BorderAgent::HandleTmf(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo) { - return Get().SendMessage(aMessage, Get().GetMessageInfo()); + IgnoreError(ForwardToLeader(aMessage, aMessageInfo, kUriLeaderPetition)); +} + +template <> +void BorderAgent::HandleTmf(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo) +{ + VerifyOrExit(mState == kStateAccepted); + + SuccessOrExit(ForwardToLeader(aMessage, aMessageInfo, kUriLeaderKeepAlive)); + mTimer.Start(kKeepAliveTimeout); + +exit: + return; +} + +Error BorderAgent::ForwardToLeader(const Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo, Uri aUri) +{ + Error error = kErrorNone; + OwnedPtr forwardContext; + Tmf::MessageInfo messageInfo(GetInstance()); + Coap::Message *message = nullptr; + bool petition = false; + bool separate = false; + OffsetRange offsetRange; + + VerifyOrExit(mState != kStateStopped); + + switch (aUri) + { + case kUriLeaderPetition: + petition = true; + separate = true; + break; + case kUriLeaderKeepAlive: + separate = true; + break; + default: + break; + } + + if (separate) + { + SuccessOrExit(error = Get().SendAck(aMessage, aMessageInfo)); + } + + forwardContext.Reset(ForwardContext::AllocateAndInit(GetInstance(), aMessage, petition, separate)); + VerifyOrExit(!forwardContext.IsNull(), error = kErrorNoBufs); + + message = Get().NewPriorityConfirmablePostMessage(aUri); + VerifyOrExit(message != nullptr, error = kErrorNoBufs); + + offsetRange.InitFromMessageOffsetToEnd(aMessage); + SuccessOrExit(error = message->AppendBytesFromMessage(aMessage, offsetRange)); + + messageInfo.SetSockAddrToRlocPeerAddrToLeaderAloc(); + messageInfo.SetSockPortToTmf(); + + SuccessOrExit(error = + Get().SendMessage(*message, messageInfo, HandleCoapResponse, forwardContext.Get())); + + // Release the ownership of `forwardContext` since `SendMessage()` + // will own it. We take back ownership from `HandleCoapResponse()` + // callback. + + forwardContext.Release(); + + LogInfo("Forwarded request to leader on %s", PathForUri(aUri)); + +exit: + LogWarnOnError(error, "forward to leader"); + + if (error != kErrorNone) + { + FreeMessage(message); + SendErrorMessage(aMessage, separate, error); + } + + return error; } void BorderAgent::HandleCoapResponse(void *aContext, @@ -234,144 +455,6 @@ exit: } } -BorderAgent::BorderAgent(Instance &aInstance) - : InstanceLocator(aInstance) - , mState(kStateStopped) - , mUdpProxyPort(0) - , mUdpReceiver(BorderAgent::HandleUdpReceive, this) - , mTimer(aInstance) -#if OPENTHREAD_CONFIG_BORDER_AGENT_ID_ENABLE - , mIdInitialized(false) -#endif -#if OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE - , mUsingEphemeralKey(false) - , mOldUdpPort(0) - , mEphemeralKeyTimer(aInstance) - , mEphemeralKeyTask(aInstance) -#endif -{ - mCommissionerAloc.InitAsThreadOriginMeshLocal(); - ClearAllBytes(mCounters); -} - -#if OPENTHREAD_CONFIG_BORDER_AGENT_ID_ENABLE -Error BorderAgent::GetId(Id &aId) -{ - Error error = kErrorNone; - - if (mIdInitialized) - { - aId = mId; - ExitNow(); - } - - if (Get().Read(mId) != kErrorNone) - { - Random::NonCrypto::Fill(mId); - SuccessOrExit(error = Get().Save(mId)); - } - - mIdInitialized = true; - aId = mId; - -exit: - return error; -} - -Error BorderAgent::SetId(const Id &aId) -{ - Error error = kErrorNone; - - SuccessOrExit(error = Get().Save(aId)); - mId = aId; - mIdInitialized = true; - -exit: - return error; -} -#endif // OPENTHREAD_CONFIG_BORDER_AGENT_ID_ENABLE - -void BorderAgent::HandleNotifierEvents(Events aEvents) -{ - if ((aEvents.ContainsAny(kEventThreadRoleChanged | kEventCommissionerStateChanged))) - { -#if OPENTHREAD_CONFIG_COMMISSIONER_ENABLE && OPENTHREAD_FTD - VerifyOrExit(Get().IsDisabled()); -#endif - - if (Get().IsAttached()) - { - Start(); - } - else - { - Stop(); - } - } - - if (aEvents.ContainsAny(kEventPskcChanged)) - { - VerifyOrExit(mState != kStateStopped); - -#if OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE - // No-op if Ephemeralkey mode is activated, new pskc will be applied - // when Ephemeralkey mode is deactivated. - VerifyOrExit(!mUsingEphemeralKey); -#endif - - { - Pskc pskc; - Get().GetPskc(pskc); - - // If there is secure session already established, it won't be impacted, - // new pskc will be applied for next connection. - SuccessOrExit(Get().SetPsk(pskc.m8, Pskc::kSize)); - pskc.Clear(); - } - } - -exit: - return; -} - -template <> void BorderAgent::HandleTmf(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo) -{ - OT_UNUSED_VARIABLE(aMessageInfo); - - Error error = kErrorNone; - Message *message = nullptr; - Ip6::MessageInfo messageInfo; - OffsetRange offsetRange; - UdpEncapsulationTlvHeader udpEncapHeader; - - VerifyOrExit(mState != kStateStopped); - - SuccessOrExit(error = Tlv::FindTlvValueOffsetRange(aMessage, Tlv::kUdpEncapsulation, offsetRange)); - - SuccessOrExit(error = aMessage.Read(offsetRange, udpEncapHeader)); - offsetRange.AdvanceOffset(sizeof(UdpEncapsulationTlvHeader)); - - VerifyOrExit(udpEncapHeader.GetSourcePort() > 0 && udpEncapHeader.GetDestinationPort() > 0, error = kErrorDrop); - - VerifyOrExit((message = Get().NewMessage()) != nullptr, error = kErrorNoBufs); - SuccessOrExit(error = message->AppendBytesFromMessage(aMessage, offsetRange)); - - messageInfo.SetSockPort(udpEncapHeader.GetSourcePort()); - messageInfo.SetSockAddr(mCommissionerAloc.GetAddress()); - messageInfo.SetPeerPort(udpEncapHeader.GetDestinationPort()); - - SuccessOrExit(error = Tlv::Find(aMessage, messageInfo.GetPeerAddr())); - - SuccessOrExit(error = Get().SendDatagram(*message, messageInfo)); - mUdpProxyPort = udpEncapHeader.GetSourcePort(); - - LogInfo("Proxy transmit sent to %s", messageInfo.GetPeerAddr().ToString().AsCString()); - -exit: - FreeMessageOnError(message, error); - LogWarnOnError(error, "send proxy stream"); -} - bool BorderAgent::HandleUdpReceive(void *aContext, const otMessage *aMessage, const otMessageInfo *aMessageInfo) { return static_cast(aContext)->HandleUdpReceive(AsCoreType(aMessage), AsCoreType(aMessageInfo)); @@ -428,8 +511,98 @@ exit: return error != kErrorDestinationAddressFiltered; } +Error BorderAgent::ForwardToCommissioner(Coap::Message &aForwardMessage, const Message &aMessage) +{ + Error error; + OffsetRange offsetRange; + + offsetRange.InitFromMessageOffsetToEnd(aMessage); + SuccessOrExit(error = aForwardMessage.AppendBytesFromMessage(aMessage, offsetRange)); + + SuccessOrExit(error = SendMessage(aForwardMessage)); + + LogInfo("Sent to commissioner"); + +exit: + LogWarnOnError(error, "send to commissioner"); + return error; +} + +Error BorderAgent::SendMessage(Coap::Message &aMessage) +{ + return Get().SendMessage(aMessage, Get().GetMessageInfo()); +} + +void BorderAgent::SendErrorMessage(const ForwardContext &aForwardContext, Error aError) +{ + Error error = kErrorNone; + Coap::Message *message = nullptr; + + VerifyOrExit((message = Get().NewPriorityMessage()) != nullptr, error = kErrorNoBufs); + SuccessOrExit(error = aForwardContext.ToHeader(*message, CoapCodeFromError(aError))); + SuccessOrExit(error = SendMessage(*message)); + +exit: + FreeMessageOnError(message, error); + LogWarnOnError(error, "send error CoAP message"); +} + +void BorderAgent::SendErrorMessage(const Coap::Message &aRequest, bool aSeparate, Error aError) +{ + Error error = kErrorNone; + Coap::Message *message = nullptr; + + VerifyOrExit((message = Get().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 = SendMessage(*message)); + +exit: + FreeMessageOnError(message, error); + LogWarnOnError(error, "send error CoAP message"); +} + +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; +} + template <> void BorderAgent::HandleTmf(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo) { + // This is from TMF agent. + OT_UNUSED_VARIABLE(aMessageInfo); Coap::Message *message = nullptr; @@ -449,27 +622,42 @@ exit: FreeMessageOnError(message, error); } -Error BorderAgent::ForwardToCommissioner(Coap::Message &aForwardMessage, const Message &aMessage) +template <> void BorderAgent::HandleTmf(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo) { - Error error; - OffsetRange offsetRange; + OT_UNUSED_VARIABLE(aMessageInfo); - offsetRange.InitFromMessageOffsetToEnd(aMessage); - SuccessOrExit(error = aForwardMessage.AppendBytesFromMessage(aMessage, offsetRange)); + Error error = kErrorNone; + Message *message = nullptr; + Ip6::MessageInfo messageInfo; + OffsetRange offsetRange; + UdpEncapsulationTlvHeader udpEncapHeader; - SuccessOrExit(error = SendMessage(aForwardMessage)); + VerifyOrExit(mState != kStateStopped); - LogInfo("Sent to commissioner"); + SuccessOrExit(error = Tlv::FindTlvValueOffsetRange(aMessage, Tlv::kUdpEncapsulation, offsetRange)); + + SuccessOrExit(error = aMessage.Read(offsetRange, udpEncapHeader)); + offsetRange.AdvanceOffset(sizeof(UdpEncapsulationTlvHeader)); + + VerifyOrExit(udpEncapHeader.GetSourcePort() > 0 && udpEncapHeader.GetDestinationPort() > 0, error = kErrorDrop); + + VerifyOrExit((message = Get().NewMessage()) != nullptr, error = kErrorNoBufs); + SuccessOrExit(error = message->AppendBytesFromMessage(aMessage, offsetRange)); + + messageInfo.SetSockPort(udpEncapHeader.GetSourcePort()); + messageInfo.SetSockAddr(mCommissionerAloc.GetAddress()); + messageInfo.SetPeerPort(udpEncapHeader.GetDestinationPort()); + + SuccessOrExit(error = Tlv::Find(aMessage, messageInfo.GetPeerAddr())); + + SuccessOrExit(error = Get().SendDatagram(*message, messageInfo)); + mUdpProxyPort = udpEncapHeader.GetSourcePort(); + + LogInfo("Proxy transmit sent to %s", messageInfo.GetPeerAddr().ToString().AsCString()); exit: - LogWarnOnError(error, "send to commissioner"); - return error; -} - -template <> -void BorderAgent::HandleTmf(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo) -{ - IgnoreError(ForwardToLeader(aMessage, aMessageInfo, kUriLeaderPetition)); + FreeMessageOnError(message, error); + LogWarnOnError(error, "send proxy stream"); } template <> @@ -490,18 +678,6 @@ template <> void BorderAgent::HandleTmf(Coap::Message &aMessage, mCounters.mMgmtPendingGets++; } -template <> -void BorderAgent::HandleTmf(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo) -{ - VerifyOrExit(mState == kStateAccepted); - - SuccessOrExit(ForwardToLeader(aMessage, aMessageInfo, kUriLeaderKeepAlive)); - mTimer.Start(kKeepAliveTimeout); - -exit: - return; -} - template <> void BorderAgent::HandleTmf(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo) { OT_UNUSED_VARIABLE(aMessageInfo); @@ -536,78 +712,13 @@ exit: LogWarnOnError(error, "send to joiner router request RelayTx (c/tx)"); } -Error BorderAgent::ForwardToLeader(const Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo, Uri aUri) -{ - Error error = kErrorNone; - OwnedPtr forwardContext; - Tmf::MessageInfo messageInfo(GetInstance()); - Coap::Message *message = nullptr; - bool petition = false; - bool separate = false; - OffsetRange offsetRange; - - VerifyOrExit(mState != kStateStopped); - - switch (aUri) - { - case kUriLeaderPetition: - petition = true; - separate = true; - break; - case kUriLeaderKeepAlive: - separate = true; - break; - default: - break; - } - - if (separate) - { - SuccessOrExit(error = Get().SendAck(aMessage, aMessageInfo)); - } - - forwardContext.Reset(ForwardContext::AllocateAndInit(GetInstance(), aMessage, petition, separate)); - VerifyOrExit(!forwardContext.IsNull(), error = kErrorNoBufs); - - message = Get().NewPriorityConfirmablePostMessage(aUri); - VerifyOrExit(message != nullptr, error = kErrorNoBufs); - - offsetRange.InitFromMessageOffsetToEnd(aMessage); - SuccessOrExit(error = message->AppendBytesFromMessage(aMessage, offsetRange)); - - messageInfo.SetSockAddrToRlocPeerAddrToLeaderAloc(); - messageInfo.SetSockPortToTmf(); - - SuccessOrExit(error = - Get().SendMessage(*message, messageInfo, HandleCoapResponse, forwardContext.Get())); - - // Release the ownership of `forwardContext` since `SendMessage()` - // will own it. We take back ownership from `HandleCoapResponse()` - // callback. - - forwardContext.Release(); - - LogInfo("Forwarded request to leader on %s", PathForUri(aUri)); - -exit: - LogWarnOnError(error, "forward to leader"); - - if (error != kErrorNone) - { - FreeMessage(message); - SendErrorMessage(aMessage, separate, error); - } - - return error; -} - void BorderAgent::HandleTmfDatasetGet(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo, Uri aUri) { Error error = kErrorNone; Coap::Message *response = nullptr; // When processing `MGMT_GET` request directly on Border Agent, - // the Security Policy flags (O-bit) should be ignore to allow + // the Security Policy flags (O-bit) should be ignored to allow // the commissioner candidate to get the full Operational Dataset. switch (aUri) @@ -639,152 +750,8 @@ exit: FreeMessageOnError(response, error); } -void BorderAgent::HandleConnected(Dtls::ConnectEvent aEvent, void *aContext) -{ - static_cast(aContext)->HandleConnected(aEvent); -} - -void BorderAgent::HandleConnected(Dtls::ConnectEvent aEvent) -{ - if (aEvent == Dtls::kConnected) - { - LogInfo("SecureSession connected"); - mState = kStateConnected; - mTimer.Start(kKeepAliveTimeout); -#if OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE - if (mUsingEphemeralKey) - { - mCounters.mEpskcSecureSessionSuccesses++; - mEphemeralKeyTask.Post(); - } - else -#endif - { - mCounters.mPskcSecureSessionSuccesses++; - } - } - else - { - LogInfo("SecureSession disconnected"); - IgnoreError(Get().RemoveReceiver(mUdpReceiver)); - Get().RemoveUnicastAddress(mCommissionerAloc); - -#if OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE - if (mUsingEphemeralKey) - { - RestartAfterRemovingEphemeralKey(); - - if (aEvent == Dtls::kDisconnectedError) - { - mCounters.mEpskcSecureSessionFailures++; - } - else if (aEvent == Dtls::kDisconnectedPeerClosed) - { - mCounters.mEpskcDeactivationDisconnects++; - } - } - else -#endif - { - mState = kStateStarted; - mUdpProxyPort = 0; - - if (aEvent == Dtls::kDisconnectedError) - { - mCounters.mPskcSecureSessionFailures++; - } - } - } -} - -uint16_t BorderAgent::GetUdpPort(void) const { return Get().GetUdpPort(); } - -Error BorderAgent::Start(uint16_t aUdpPort) -{ - Error error; - Pskc pskc; - - Get().GetPskc(pskc); - error = Start(aUdpPort, pskc.m8, Pskc::kSize); - pskc.Clear(); - - return error; -} - -Error BorderAgent::Start(uint16_t aUdpPort, const uint8_t *aPsk, uint8_t aPskLength) -{ - Error error = kErrorNone; - - VerifyOrExit(mState == kStateStopped); - -#if OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE - if (mUsingEphemeralKey) - { - SuccessOrExit(error = Get().Start(aUdpPort, kMaxEphemeralKeyConnectionAttempts, - HandleSecureAgentStopped, this)); - } - else -#endif - { - SuccessOrExit(error = Get().Start(aUdpPort)); - } - - SuccessOrExit(error = Get().SetPsk(aPsk, aPskLength)); - - Get().SetConnectCallback(HandleConnected, this); - - mState = kStateStarted; - mUdpProxyPort = 0; - - LogInfo("Border Agent start listening on port %u", GetUdpPort()); - -exit: - LogWarnOnError(error, "start agent"); - return error; -} - -void BorderAgent::HandleTimeout(void) -{ - if (Get().IsConnected()) - { - Get().Disconnect(); - LogWarn("Reset secure session"); - } -} - -void BorderAgent::Stop(void) -{ - VerifyOrExit(mState != kStateStopped); - -#if OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE - if (mUsingEphemeralKey) - { - mUsingEphemeralKey = false; - mEphemeralKeyTimer.Stop(); - mEphemeralKeyTask.Post(); - } -#endif - - mTimer.Stop(); - Get().Stop(); - - mState = kStateStopped; - mUdpProxyPort = 0; - LogInfo("Border Agent stopped"); - -exit: - return; -} - -void BorderAgent::Disconnect(void) -{ - VerifyOrExit(mState == kStateConnected || mState == kStateAccepted); - - Get().Disconnect(); - -exit: - return; -} +//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// Ephemeral Key #if OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE @@ -908,6 +875,44 @@ void BorderAgent::HandleSecureAgentStopped(void) #endif // OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE +//---------------------------------------------------------------------------------------------------------------------- +// `BorderAgent::ForwardContext` + +Error 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); + + return kErrorNone; +} + +Error BorderAgent::ForwardContext::ToHeader(Coap::Message &aMessage, uint8_t aCode) const +{ + if ((mType == Coap::kTypeNonConfirmable) || mSeparate) + { + aMessage.Init(Coap::kTypeNonConfirmable, static_cast(aCode)); + } + else + { + aMessage.Init(Coap::kTypeAck, static_cast(aCode)); + } + + if (!mSeparate) + { + aMessage.SetMessageId(mMessageId); + } + + return aMessage.SetToken(mToken, mTokenLength); +} + } // namespace MeshCoP } // namespace ot diff --git a/src/core/meshcop/border_agent.hpp b/src/core/meshcop/border_agent.hpp index f7b93ec14..864edde03 100644 --- a/src/core/meshcop/border_agent.hpp +++ b/src/core/meshcop/border_agent.hpp @@ -280,21 +280,28 @@ private: Error Start(uint16_t aUdpPort); Error Start(uint16_t aUdpPort, const uint8_t *aPsk, uint8_t aPskLength); - - void HandleNotifierEvents(Events aEvents); - - Coap::Message::Code CoapCodeFromError(Error aError); - Error SendMessage(Coap::Message &aMessage); - void SendErrorMessage(const ForwardContext &aForwardContext, Error aError); - void SendErrorMessage(const Coap::Message &aRequest, bool aSeparate, Error aError); - - static void HandleConnected(Dtls::ConnectEvent aEvent, void *aContext); - void HandleConnected(Dtls::ConnectEvent aEvent); + void HandleNotifierEvents(Events aEvents); + void HandleTimeout(void); + Error ForwardToLeader(const Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo, Uri aUri); + Error ForwardToCommissioner(Coap::Message &aForwardMessage, const Message &aMessage); + Error SendMessage(Coap::Message &aMessage); + void SendErrorMessage(const ForwardContext &aForwardContext, Error aError); + void SendErrorMessage(const Coap::Message &aRequest, bool aSeparate, Error aError); + void HandleTmfDatasetGet(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo, Uri aUri); template void HandleTmf(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo); - void HandleTmfDatasetGet(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo, Uri aUri); - void HandleTimeout(void); + static void HandleConnected(Dtls::ConnectEvent aEvent, void *aContext); + void HandleConnected(Dtls::ConnectEvent aEvent); + static void HandleCoapResponse(void *aContext, + otMessage *aMessage, + const otMessageInfo *aMessageInfo, + Error aResult); + void HandleCoapResponse(const ForwardContext &aForwardContext, const Coap::Message *aResponse, Error aResult); + static bool HandleUdpReceive(void *aContext, const otMessage *aMessage, const otMessageInfo *aMessageInfo); + bool HandleUdpReceive(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo); + + static Coap::Message::Code CoapCodeFromError(Error aError); #if OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE void RestartAfterRemovingEphemeralKey(void); @@ -304,16 +311,6 @@ private: void HandleSecureAgentStopped(void); #endif - static void HandleCoapResponse(void *aContext, - otMessage *aMessage, - const otMessageInfo *aMessageInfo, - Error aResult); - void HandleCoapResponse(const ForwardContext &aForwardContext, const Coap::Message *aResponse, Error aResult); - Error ForwardToLeader(const Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo, Uri aUri); - Error ForwardToCommissioner(Coap::Message &aForwardMessage, const Message &aMessage); - static bool HandleUdpReceive(void *aContext, const otMessage *aMessage, const otMessageInfo *aMessageInfo); - bool HandleUdpReceive(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo); - using TimeoutTimer = TimerMilliIn; #if OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE using EphemeralKeyTimer = TimerMilliIn;