[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:
Abtin Keshavarzian
2020-03-10 19:15:35 -07:00
committed by GitHub
parent 27ec1a7648
commit e81562f182
3 changed files with 137 additions and 185 deletions
+1
View File
@@ -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
+121 -92
View File
@@ -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
+15 -93
View File
@@ -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