mirror of
https://github.com/espressif/openthread.git
synced 2026-09-09 02:30:11 +00:00
[joiner-router] prepare Joiner Entrust msg after the delay (#4657)
This commit simplifies the `JoinerRouter` implementation. It moves `JoinerEntrustMetadata` as a private inner type of `JoinerRouter`. It also changes how the tx of Joiner Entrust is delayed. Instead of preparing the message (and appending metadata to it) and enqueuing it to be sent later after a delay, only the metadata is saved and the Joiner Entrust message is prepared after the delay (when it is being sent).
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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<MessagePool>().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<JoinerRouter>().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<KeyManager>().GetKek(), metadata.mKek, KeyManager::kMaxKeyLength) == 0);
|
||||
|
||||
if (TimerMilli::GetNow() < metadata.mSendTime)
|
||||
{
|
||||
mTimer.FireAt(metadata.mSendTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
mDelayedJoinEnts.Dequeue(*message);
|
||||
message->Free();
|
||||
|
||||
Get<KeyManager>().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<Coap::Coap>().AbortTransaction(&JoinerRouter::HandleJoinerEntrustResponse, this);
|
||||
|
||||
otLogInfoMeshCoP("Sending JOIN_ENT.ntf");
|
||||
SuccessOrExit(error = Get<Coap::Coap>().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<Coap::Coap>())) != 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<KeyManager>().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<JoinerRouter>().HandleTimer();
|
||||
}
|
||||
|
||||
void JoinerRouter::HandleTimer(void)
|
||||
{
|
||||
SendDelayedJoinerEntrust();
|
||||
}
|
||||
|
||||
void JoinerRouter::SendDelayedJoinerEntrust(void)
|
||||
{
|
||||
DelayedJoinEntHeader delayedJoinEnt;
|
||||
Coap::Message * message = static_cast<Coap::Message *>(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<KeyManager>().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<KeyManager>().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<Coap::Coap>().AbortTransaction(&JoinerRouter::HandleJoinerEntrustResponse, this);
|
||||
|
||||
otLogInfoMeshCoP("Sending JOIN_ENT.ntf");
|
||||
SuccessOrExit(error = Get<Coap::Coap>().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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user