diff --git a/src/core/common/message.hpp b/src/core/common/message.hpp index 089fd7cb2..5780e3277 100644 --- a/src/core/common/message.hpp +++ b/src/core/common/message.hpp @@ -206,6 +206,7 @@ public: kTypeIp6 = 0, ///< A full uncompressed IPv6 packet kType6lowpan = 1, ///< A 6lowpan frame kTypeSupervision = 2, ///< A child supervision frame. + kTypeOther = 3, ///< Other (data) message. }; enum diff --git a/src/core/meshcop/joiner_router.cpp b/src/core/meshcop/joiner_router.cpp index c9f4acc55..211476c30 100644 --- a/src/core/meshcop/joiner_router.cpp +++ b/src/core/meshcop/joiner_router.cpp @@ -234,16 +234,121 @@ exit: otError JoinerRouter::DelaySendingJoinerEntrust(const Ip6::MessageInfo &aMessageInfo, const uint8_t *aKek) { - otError error; - Coap::Message * message = NULL; - Ip6::MessageInfo messageInfo; - Dataset dataset(MeshCoP::Tlv::kActiveTimestamp); + otError error = OT_ERROR_NONE; + Message * message = Get().New(Message::kTypeOther, 0); + JoinerEntrustMetadata metadata; + + VerifyOrExit(message != NULL, error = OT_ERROR_NO_BUFS); + + metadata.mMessageInfo = aMessageInfo; + metadata.mMessageInfo.SetPeerPort(kCoapUdpPort); + metadata.mSendTime = TimerMilli::GetNow() + kJoinerEntrustTxDelay; + memcpy(metadata.mKek, aKek, sizeof(metadata.mKek)); + + SuccessOrExit(error = metadata.AppendTo(*message)); + + mDelayedJoinEnts.Enqueue(*message); + + if (!mTimer.IsRunning()) + { + mTimer.FireAt(metadata.mSendTime); + } + +exit: + + if (error != OT_ERROR_NONE && message != NULL) + { + message->Free(); + } + + return error; +} + +void JoinerRouter::HandleTimer(Timer &aTimer) +{ + aTimer.GetOwner().HandleTimer(); +} + +void JoinerRouter::HandleTimer(void) +{ + SendDelayedJoinerEntrust(); +} + +void JoinerRouter::SendDelayedJoinerEntrust(void) +{ + JoinerEntrustMetadata metadata; + Message * message = mDelayedJoinEnts.GetHead(); + + VerifyOrExit(message != NULL); + VerifyOrExit(!mTimer.IsRunning()); + + metadata.ReadFrom(*message); + + // The message can be sent during CoAP transaction if KEK did not + // change (i.e., retransmission). Otherweise, we wait for Joiner + // Entrust Response before handling any other pending delayed + // Jointer Entrust message. + VerifyOrExit(!mExpectJoinEntRsp || + memcmp(Get().GetKek(), metadata.mKek, KeyManager::kMaxKeyLength) == 0); + + if (TimerMilli::GetNow() < metadata.mSendTime) + { + mTimer.FireAt(metadata.mSendTime); + } + else + { + mDelayedJoinEnts.Dequeue(*message); + message->Free(); + + Get().SetKek(metadata.mKek); + + if (SendJoinerEntrust(metadata.mMessageInfo) != OT_ERROR_NONE) + { + mTimer.Start(0); + } + } + +exit: + return; +} + +otError JoinerRouter::SendJoinerEntrust(const Ip6::MessageInfo &aMessageInfo) +{ + otError error = OT_ERROR_NONE; + Coap::Message *message; + + message = PrepareJoinerEntrustMessage(); + VerifyOrExit(message != NULL, error = OT_ERROR_NO_BUFS); + + Get().AbortTransaction(&JoinerRouter::HandleJoinerEntrustResponse, this); + + otLogInfoMeshCoP("Sending JOIN_ENT.ntf"); + SuccessOrExit(error = Get().SendMessage(*message, aMessageInfo, + &JoinerRouter::HandleJoinerEntrustResponse, this)); + + otLogInfoMeshCoP("Sent joiner entrust length = %d", message->GetLength()); + otLogCertMeshCoP("[THCI] direction=send | type=JOIN_ENT.ntf"); + + mExpectJoinEntRsp = true; + +exit: + if (error != OT_ERROR_NONE && message != NULL) + { + message->Free(); + } + + return error; +} + +Coap::Message *JoinerRouter::PrepareJoinerEntrustMessage(void) +{ + otError error; + Coap::Message *message = NULL; + Dataset dataset(MeshCoP::Tlv::kActiveTimestamp); NetworkNameTlv networkName; const Tlv * tlv; - DelayedJoinEntHeader delayedMessage; - VerifyOrExit((message = NewMeshCoPMessage(Get())) != NULL, error = OT_ERROR_NO_BUFS); message->Init(OT_COAP_TYPE_CONFIRMABLE, OT_COAP_CODE_POST); @@ -313,99 +418,15 @@ otError JoinerRouter::DelaySendingJoinerEntrust(const Ip6::MessageInfo &aMessage SuccessOrExit( error = Tlv::AppendUint32Tlv(*message, Tlv::kNetworkKeySequence, Get().GetCurrentKeySequence())); - messageInfo = aMessageInfo; - messageInfo.SetPeerPort(kCoapUdpPort); - - delayedMessage.Init(TimerMilli::GetNow() + kDelayJoinEnt, messageInfo, aKek); - SuccessOrExit(error = delayedMessage.AppendTo(*message)); - - mDelayedJoinEnts.Enqueue(*message); - - if (!mTimer.IsRunning()) - { - mTimer.Start(kDelayJoinEnt); - } - exit: if (error != OT_ERROR_NONE && message != NULL) { message->Free(); + message = NULL; } - return error; -} - -void JoinerRouter::HandleTimer(Timer &aTimer) -{ - aTimer.GetOwner().HandleTimer(); -} - -void JoinerRouter::HandleTimer(void) -{ - SendDelayedJoinerEntrust(); -} - -void JoinerRouter::SendDelayedJoinerEntrust(void) -{ - DelayedJoinEntHeader delayedJoinEnt; - Coap::Message * message = static_cast(mDelayedJoinEnts.GetHead()); - Ip6::MessageInfo messageInfo; - - VerifyOrExit(message != NULL); - VerifyOrExit(!mTimer.IsRunning()); - - delayedJoinEnt.ReadFrom(*message); - - // The message can be sent during CoAP transaction if KEK did not change (i.e. retransmission). - VerifyOrExit(!mExpectJoinEntRsp || - memcmp(Get().GetKek(), delayedJoinEnt.GetKek(), KeyManager::kMaxKeyLength) == 0); - - if (TimerMilli::GetNow() < delayedJoinEnt.GetSendTime()) - { - mTimer.FireAt(delayedJoinEnt.GetSendTime()); - } - else - { - mDelayedJoinEnts.Dequeue(*message); - - // Remove the DelayedJoinEntHeader from the message. - DelayedJoinEntHeader::RemoveFrom(*message); - - // Set KEK to one used for this message. - Get().SetKek(delayedJoinEnt.GetKek()); - - // Send the message. - memcpy(&messageInfo, delayedJoinEnt.GetMessageInfo(), sizeof(messageInfo)); - - if (SendJoinerEntrust(*message, messageInfo) != OT_ERROR_NONE) - { - message->Free(); - mTimer.Start(0); - } - } - -exit: - return; -} - -otError JoinerRouter::SendJoinerEntrust(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo) -{ - otError error; - - Get().AbortTransaction(&JoinerRouter::HandleJoinerEntrustResponse, this); - - otLogInfoMeshCoP("Sending JOIN_ENT.ntf"); - SuccessOrExit(error = Get().SendMessage(aMessage, aMessageInfo, - &JoinerRouter::HandleJoinerEntrustResponse, this)); - - otLogInfoMeshCoP("Sent joiner entrust length = %d", aMessage.GetLength()); - otLogCertMeshCoP("[THCI] direction=send | type=JOIN_ENT.ntf"); - - mExpectJoinEntRsp = true; - -exit: - return error; + return message; } void JoinerRouter::HandleJoinerEntrustResponse(void * aContext, @@ -437,6 +458,14 @@ exit: return; } +void JoinerRouter::JoinerEntrustMetadata::ReadFrom(const Message &aMessage) +{ + uint16_t length = aMessage.GetLength(); + + assert(length >= sizeof(*this)); + aMessage.Read(length - sizeof(*this), sizeof(*this), this); +} + } // namespace MeshCoP } // namespace ot diff --git a/src/core/meshcop/joiner_router.hpp b/src/core/meshcop/joiner_router.hpp index 2680f3ba8..27c03bf80 100644 --- a/src/core/meshcop/joiner_router.hpp +++ b/src/core/meshcop/joiner_router.hpp @@ -81,7 +81,17 @@ public: private: enum { - kDelayJoinEnt = 50, ///< milliseconds + kJoinerEntrustTxDelay = 50, ///< milliseconds + }; + + struct JoinerEntrustMetadata + { + otError AppendTo(Message &aMessage) { return aMessage.Append(this, sizeof(*this)); } + void ReadFrom(const Message &aMessage); + + Ip6::MessageInfo mMessageInfo; // Message info of the message to send. + TimeMilli mSendTime; // Time when the message shall be sent. + uint8_t mKek[KeyManager::kMaxKeyLength]; // KEK used by MAC layer to encode this message. }; static void HandleStateChanged(Notifier::Callback &aCallback, otChangedFlags aFlags); @@ -102,9 +112,10 @@ private: static void HandleTimer(Timer &aTimer); void HandleTimer(void); - otError DelaySendingJoinerEntrust(const Ip6::MessageInfo &aMessageInfo, const uint8_t *aKek); - void SendDelayedJoinerEntrust(void); - otError SendJoinerEntrust(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo); + otError DelaySendingJoinerEntrust(const Ip6::MessageInfo &aMessageInfo, const uint8_t *aKek); + void SendDelayedJoinerEntrust(void); + otError SendJoinerEntrust(const Ip6::MessageInfo &aMessageInfo); + Coap::Message *PrepareJoinerEntrustMessage(void); Ip6::UdpSocket mSocket; Coap::Resource mRelayTransmit; @@ -120,95 +131,6 @@ private: bool mExpectJoinEntRsp : 1; }; -/** - * This class implements functionality required for delaying JOIN_ENT.ntf messages. - * - */ -class DelayedJoinEntHeader -{ -public: - /** - * This method initializes the object with specific values. - * - * @param[in] aSendTime Time when the message shall be sent. - * @param[in] aMessageInfo IPv6 address of the message destination. - * @param[in] aKek A pointer to the KEK. - * - */ - void Init(TimeMilli aSendTime, Ip6::MessageInfo &aMessageInfo, const uint8_t *aKek) - { - mSendTime = aSendTime; - mMessageInfo = aMessageInfo; - memcpy(&mKek, aKek, sizeof(mKek)); - } - - /** - * This method appends delayed response header to the message. - * - * @param[in] aMessage A reference to the message. - * - * @retval OT_ERROR_NONE Successfully appended the bytes. - * @retval OT_ERROR_NO_BUFS Insufficient available buffers to grow the message. - * - */ - otError AppendTo(Message &aMessage) { return aMessage.Append(this, sizeof(*this)); } - - /** - * This method reads delayed response header from the message. - * - * @param[in] aMessage A reference to the message. - * - */ - void ReadFrom(const Message &aMessage) - { - uint16_t length = aMessage.Read(aMessage.GetLength() - sizeof(*this), sizeof(*this), this); - assert(length == sizeof(*this)); - OT_UNUSED_VARIABLE(length); - } - - /** - * This method removes delayed response header from the message. - * - * @param[in] aMessage A reference to the message. - * - */ - static void RemoveFrom(Message &aMessage) - { - otError error = aMessage.SetLength(aMessage.GetLength() - sizeof(DelayedJoinEntHeader)); - assert(error == OT_ERROR_NONE); - OT_UNUSED_VARIABLE(error); - } - - /** - * This method returns a time when the message shall be sent. - * - * @returns A time when the message shall be sent. - * - */ - TimeMilli GetSendTime(void) const { return mSendTime; } - - /** - * This method returns a destination of the delayed message. - * - * @returns A destination of the delayed message. - * - */ - const Ip6::MessageInfo *GetMessageInfo(void) const { return &mMessageInfo; } - - /** - * This method returns a pointer to the KEK that should be used to send the delayed message. - * - * @returns A pointer to the KEK. - * - */ - const uint8_t *GetKek(void) const { return mKek; } - -private: - Ip6::MessageInfo mMessageInfo; ///< Message info of the message to send. - TimeMilli mSendTime; ///< Time when the message shall be sent. - uint8_t mKek[KeyManager::kMaxKeyLength]; ///< KEK used by MAC layer to encode this message. -}; - } // namespace MeshCoP } // namespace ot