mirror of
https://github.com/espressif/openthread.git
synced 2026-08-25 19:59:51 +00:00
[coap] introduce otCoapToken to improve token handling (#12273)
This commit introduces a new `otCoapToken` struct and a corresponding `Coap::Token` class to provide a clear and type-safe representation of a CoAP message token. The CoAP APIs are updated to use these new types, replacing the use of raw `uint8_t` pointers and separate length parameters. This encapsulation enhances robustness and reduces the potential for errors in token handling. The following new APIs are added: - `otCoapMessageReadToken()` - `otCoapMessageWriteToken()` - `otCoapMessageAreTokensEqual()` Importantly, several older APIs are now marked as deprecated (some returned pointers directly into `otMessage` data which is unsafe). While these APIs remain supported for now, their use is discouraged, and applications should migrate to the new APIs. Deprecated APIs: - `otCoapMessageGetTokenLength()` - `otCoapMessageGetToken()` - `otCoapMessageSetToken()` The internal implementation is updated to utilize the new `Token` class, and the CLI implementation is updated to use the new public APIs. Additionally, Doxygen documentations are updated for the new and updated APIs.
This commit is contained in:
+70
-17
@@ -255,6 +255,15 @@ typedef void (*otCoapRequestHandler)(void *aContext, otMessage *aMessage, const
|
||||
*/
|
||||
typedef bool (*otCoapResponseFallback)(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo);
|
||||
|
||||
/**
|
||||
* Represents a CoAP message token.
|
||||
*/
|
||||
typedef struct otCoapToken
|
||||
{
|
||||
uint8_t m8[OT_COAP_MAX_TOKEN_LENGTH]; ///< The token bytes.
|
||||
uint8_t mLength; ///< The token length in bytes.
|
||||
} otCoapToken;
|
||||
|
||||
/**
|
||||
* Represents a CoAP resource.
|
||||
*/
|
||||
@@ -327,22 +336,21 @@ void otCoapMessageInit(otMessage *aMessage, otCoapType aType, otCoapCode aCode);
|
||||
otError otCoapMessageInitResponse(otMessage *aResponse, const otMessage *aRequest, otCoapType aType, otCoapCode aCode);
|
||||
|
||||
/**
|
||||
* Sets the Token value and length in a header.
|
||||
* Writes the Token in the CoAP message.
|
||||
*
|
||||
* @param[in,out] aMessage A pointer to the CoAP message.
|
||||
* @param[in] aToken A pointer to the Token value.
|
||||
* @param[in] aTokenLength The Length of @p aToken.
|
||||
* @param[in,out] aMessage The CoAP message.
|
||||
* @param[in] aToken The Token to write.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully set the Token value.
|
||||
* @retval OT_ERROR_NONE Successfully wrote the Token.
|
||||
* @retval OT_ERROR_NO_BUFS Insufficient buffers to set the Token value.
|
||||
*/
|
||||
otError otCoapMessageSetToken(otMessage *aMessage, const uint8_t *aToken, uint8_t aTokenLength);
|
||||
otError otCoapMessageWriteToken(otMessage *aMessage, const otCoapToken *aToken);
|
||||
|
||||
/**
|
||||
* Sets the Token length and randomizes its value.
|
||||
* Writes a randomly generated Token of a given length in the CoAP message.
|
||||
*
|
||||
* @param[in,out] aMessage A pointer to the CoAP message.
|
||||
* @param[in] aTokenLength The Length of a Token to set.
|
||||
* @param[in,out] aMessage The CoAP message.
|
||||
* @param[in] aTokenLength The Length of a Token (in bytes).
|
||||
*/
|
||||
void otCoapMessageGenerateToken(otMessage *aMessage, uint8_t aTokenLength);
|
||||
|
||||
@@ -560,22 +568,26 @@ const char *otCoapMessageCodeToString(const otMessage *aMessage);
|
||||
uint16_t otCoapMessageGetMessageId(const otMessage *aMessage);
|
||||
|
||||
/**
|
||||
* Returns the Token length.
|
||||
* Reads the Token from the CoAP message.
|
||||
*
|
||||
* @param[in] aMessage A pointer to the CoAP message.
|
||||
* @param[in] aMessage The CoAP message.
|
||||
* @param[out] aToken A pointer to a `otCoapToken` to output the read Token.
|
||||
*
|
||||
* @returns The Token length.
|
||||
* @retval OT_ERROR_NONE Successfully read the Token. @p aToken is updated.
|
||||
* @retval OT_ERROR_PARSE Failed to parse the header.
|
||||
*/
|
||||
uint8_t otCoapMessageGetTokenLength(const otMessage *aMessage);
|
||||
otError otCoapMessageReadToken(const otMessage *aMessage, otCoapToken *aToken);
|
||||
|
||||
/**
|
||||
* Returns a pointer to the Token value.
|
||||
* Indicates whether two given CoAP Tokens are equal.
|
||||
*
|
||||
* @param[in] aMessage A pointer to the CoAP message.
|
||||
* @param[in] aFirstToken The first Token to compare.
|
||||
* @param[in] aSecondToken The second Token to compare.
|
||||
*
|
||||
* @returns A pointer to the Token value.
|
||||
* @retval TRUE If the two Tokens are equal.
|
||||
* @retval FALSE If the two Tokens are not equal.
|
||||
*/
|
||||
const uint8_t *otCoapMessageGetToken(const otMessage *aMessage);
|
||||
bool otCoapMessageAreTokensEqual(const otCoapToken *aFirstToken, const otCoapToken *aSecondToken);
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
// `otCoapOptionIterator*` APIs - Iterating over CoAP Options in a CoAP message.
|
||||
@@ -1005,6 +1017,47 @@ otError otCoapSendResponseBlockWise(otInstance *aInstance,
|
||||
void *aContext,
|
||||
otCoapBlockwiseTransmitHook aTransmitHook);
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
// Deprecated APIs
|
||||
|
||||
/**
|
||||
* Sets the Token value and length in a CoAP message.
|
||||
*
|
||||
* @deprecated This function is deprecated. Use `otCoapMessageWriteToken()` instead.
|
||||
*
|
||||
* @param[in,out] aMessage A pointer to the CoAP message.
|
||||
* @param[in] aToken A pointer to the Token value.
|
||||
* @param[in] aTokenLength The Length of @p aToken.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully set the Token value.
|
||||
* @retval OT_ERROR_NO_BUFS Insufficient buffers to set the Token value.
|
||||
*/
|
||||
otError otCoapMessageSetToken(otMessage *aMessage, const uint8_t *aToken, uint8_t aTokenLength);
|
||||
|
||||
/**
|
||||
* Returns the Token length.
|
||||
*
|
||||
* @deprecated This function is deprecated. Use `otCoapMessageReadToken()` instead.
|
||||
*
|
||||
* @param[in] aMessage A pointer to the CoAP message.
|
||||
*
|
||||
* @returns The Token length.
|
||||
*/
|
||||
uint8_t otCoapMessageGetTokenLength(const otMessage *aMessage);
|
||||
|
||||
/**
|
||||
* Returns a pointer to the Token value.
|
||||
*
|
||||
* @deprecated This function is deprecated. Use `otCoapMessageReadToken()` instead.
|
||||
*
|
||||
* @note A previously returned pointer (`const uint8_t *`) will be invalidated upon the next call to this function.
|
||||
*
|
||||
* @param[in] aMessage A pointer to the CoAP message.
|
||||
*
|
||||
* @returns A pointer to the Token value.
|
||||
*/
|
||||
const uint8_t *otCoapMessageGetToken(const otMessage *aMessage);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
@@ -52,7 +52,7 @@ extern "C" {
|
||||
*
|
||||
* @note This number versions both OpenThread platform and user APIs.
|
||||
*/
|
||||
#define OPENTHREAD_API_VERSION (568)
|
||||
#define OPENTHREAD_API_VERSION (569)
|
||||
|
||||
/**
|
||||
* @addtogroup api-instance
|
||||
|
||||
+17
-17
@@ -50,8 +50,6 @@ Coap::Coap(otInstance *aInstance, OutputImplementer &aOutputImplementer)
|
||||
, mUseDefaultResponseTxParameters(true)
|
||||
#if OPENTHREAD_CONFIG_COAP_OBSERVE_API_ENABLE
|
||||
, mObserveSerial(0)
|
||||
, mRequestTokenLength(0)
|
||||
, mSubscriberTokenLength(0)
|
||||
, mSubscriberConfirmableNotifications(false)
|
||||
, mValidateObserveClient(false)
|
||||
, mNotificationSeriesCount(0)
|
||||
@@ -84,7 +82,7 @@ otError Coap::CancelResourceSubscription(bool aSendCancelMessage)
|
||||
messageInfo.mPeerAddr = mRequestAddr;
|
||||
messageInfo.mPeerPort = OT_DEFAULT_COAP_PORT;
|
||||
|
||||
VerifyOrExit(mRequestTokenLength != 0, error = OT_ERROR_INVALID_STATE);
|
||||
VerifyOrExit(mRequestToken.mLength != 0, error = OT_ERROR_INVALID_STATE);
|
||||
|
||||
if (aSendCancelMessage)
|
||||
{
|
||||
@@ -93,7 +91,7 @@ otError Coap::CancelResourceSubscription(bool aSendCancelMessage)
|
||||
|
||||
otCoapMessageInit(message, OT_COAP_TYPE_CONFIRMABLE, OT_COAP_CODE_GET);
|
||||
|
||||
SuccessOrExit(error = otCoapMessageSetToken(message, mRequestToken, mRequestTokenLength));
|
||||
SuccessOrExit(error = otCoapMessageWriteToken(message, &mRequestToken));
|
||||
SuccessOrExit(error = otCoapMessageAppendObserveOption(message, 1));
|
||||
SuccessOrExit(error = otCoapMessageAppendUriPathOptions(message, mRequestUri));
|
||||
SuccessOrExit(error = otCoapSendRequest(GetInstancePtr(), message, &messageInfo, &Coap::HandleResponse, this));
|
||||
@@ -101,7 +99,7 @@ otError Coap::CancelResourceSubscription(bool aSendCancelMessage)
|
||||
|
||||
ClearAllBytes(mRequestAddr);
|
||||
ClearAllBytes(mRequestUri);
|
||||
mRequestTokenLength = 0;
|
||||
ClearAllBytes(mRequestToken);
|
||||
|
||||
exit:
|
||||
|
||||
@@ -118,7 +116,7 @@ void Coap::CancelSubscriber(void)
|
||||
OutputFormat("Removed subscriber ");
|
||||
OutputIp6AddressLine(mSubscriberSock.mAddress);
|
||||
ClearAllBytes(mSubscriberSock);
|
||||
mSubscriberTokenLength = 0;
|
||||
ClearAllBytes(mSubscriberToken);
|
||||
}
|
||||
#endif // OPENTHREAD_CONFIG_COAP_OBSERVE_API_ENABLE
|
||||
|
||||
@@ -253,7 +251,7 @@ template <> otError Coap::Process<Cmd("set")>(Arg aArgs[])
|
||||
mResourceContent[sizeof(mResourceContent) - 1] = '\0';
|
||||
|
||||
#if OPENTHREAD_CONFIG_COAP_OBSERVE_API_ENABLE
|
||||
if (mSubscriberTokenLength > 0)
|
||||
if (mSubscriberToken.mLength > 0)
|
||||
{
|
||||
// determine the type of notification to send
|
||||
const bool isConNotification = mSubscriberConfirmableNotifications || mValidateObserveClient;
|
||||
@@ -274,7 +272,7 @@ template <> otError Coap::Process<Cmd("set")>(Arg aArgs[])
|
||||
(isConNotification ? OT_COAP_TYPE_CONFIRMABLE : OT_COAP_TYPE_NON_CONFIRMABLE),
|
||||
OT_COAP_CODE_CONTENT);
|
||||
|
||||
SuccessOrExit(error = otCoapMessageSetToken(notificationMessage, mSubscriberToken, mSubscriberTokenLength));
|
||||
SuccessOrExit(error = otCoapMessageWriteToken(notificationMessage, &mSubscriberToken));
|
||||
SuccessOrExit(error = otCoapMessageAppendObserveOption(notificationMessage, mObserveSerial++));
|
||||
SuccessOrExit(error = otCoapMessageSetPayloadMarker(notificationMessage));
|
||||
SuccessOrExit(error = otMessageAppend(notificationMessage, mResourceContent,
|
||||
@@ -695,7 +693,7 @@ otError Coap::ProcessRequest(Arg aArgs[], otCoapCode aCoapCode)
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_COAP_OBSERVE_API_ENABLE
|
||||
if (aCoapObserve && mRequestTokenLength)
|
||||
if (aCoapObserve && mRequestToken.mLength)
|
||||
{
|
||||
// New observe request: cancel the existing observation silently, without sending an explicit cancel message.
|
||||
// Note: explicit cancellation MAY be sent by the user using 'coap cancel' per Section 3.6 of RFC7641.
|
||||
@@ -781,8 +779,8 @@ otError Coap::ProcessRequest(Arg aArgs[], otCoapCode aCoapCode)
|
||||
{
|
||||
// Make a note of the message details for later so we can cancel it later.
|
||||
memcpy(&mRequestAddr, &coapDestinationIp, sizeof(mRequestAddr));
|
||||
mRequestTokenLength = otCoapMessageGetTokenLength(message);
|
||||
memcpy(mRequestToken, otCoapMessageGetToken(message), mRequestTokenLength);
|
||||
SuccessOrExit(error = otCoapMessageReadToken(message, &mRequestToken));
|
||||
|
||||
// Use `memcpy` instead of `strncpy` here because GCC will give warnings for `strncpy` when the dest's length is
|
||||
// not bigger than the src's length.
|
||||
memcpy(mRequestUri, coapUri, sizeof(mRequestUri) - 1);
|
||||
@@ -940,7 +938,7 @@ void Coap::HandleRequest(otMessage *aMessage, const otMessageInfo *aMessageInfo)
|
||||
otCoapMessageGetCode(aMessage) == OT_COAP_CODE_GET)
|
||||
{
|
||||
#if OPENTHREAD_CONFIG_COAP_OBSERVE_API_ENABLE
|
||||
if (observePresent && (mSubscriberTokenLength > 0) && (observe == 0))
|
||||
if (observePresent && (mSubscriberToken.mLength > 0) && (observe == 0))
|
||||
{
|
||||
// There is already a subscriber: ignore the Observe option per Section 4.1 of RFC7641.
|
||||
observePresent = false;
|
||||
@@ -959,10 +957,9 @@ void Coap::HandleRequest(otMessage *aMessage, const otMessageInfo *aMessageInfo)
|
||||
OutputLine("Subscribing client");
|
||||
mSubscriberSock.mAddress = aMessageInfo->mPeerAddr;
|
||||
mSubscriberSock.mPort = aMessageInfo->mPeerPort;
|
||||
mSubscriberTokenLength = otCoapMessageGetTokenLength(aMessage);
|
||||
mValidateObserveClient = false;
|
||||
mNotificationSeriesCount = 0;
|
||||
memcpy(mSubscriberToken, otCoapMessageGetToken(aMessage), mSubscriberTokenLength);
|
||||
SuccessOrExit(error = otCoapMessageReadToken(aMessage, &mSubscriberToken));
|
||||
|
||||
/*
|
||||
* Implementer note.
|
||||
@@ -977,10 +974,13 @@ void Coap::HandleRequest(otMessage *aMessage, const otMessageInfo *aMessageInfo)
|
||||
else if (observe == 1)
|
||||
{
|
||||
// See if it matches our subscriber token
|
||||
if ((otCoapMessageGetTokenLength(aMessage) == mSubscriberTokenLength) &&
|
||||
(memcmp(otCoapMessageGetToken(aMessage), mSubscriberToken, mSubscriberTokenLength) == 0))
|
||||
|
||||
otCoapToken token;
|
||||
|
||||
SuccessOrExit(error = otCoapMessageReadToken(aMessage, &token));
|
||||
|
||||
if (otCoapMessageAreTokensEqual(&token, &mSubscriberToken))
|
||||
{
|
||||
// Unsubscribe request
|
||||
CancelSubscriber();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -166,15 +166,13 @@ private:
|
||||
otIp6Address mRequestAddr;
|
||||
otSockAddr mSubscriberSock;
|
||||
char mRequestUri[kMaxUriLength];
|
||||
uint8_t mRequestToken[OT_COAP_MAX_TOKEN_LENGTH];
|
||||
uint8_t mSubscriberToken[OT_COAP_MAX_TOKEN_LENGTH];
|
||||
otCoapToken mRequestToken;
|
||||
otCoapToken mSubscriberToken;
|
||||
#endif
|
||||
char mUriPath[kMaxUriLength];
|
||||
char mResourceContent[kMaxBufferSize];
|
||||
#if OPENTHREAD_CONFIG_COAP_OBSERVE_API_ENABLE
|
||||
uint32_t mObserveSerial;
|
||||
uint8_t mRequestTokenLength;
|
||||
uint8_t mSubscriberTokenLength;
|
||||
bool mSubscriberConfirmableNotifications;
|
||||
bool mValidateObserveClient;
|
||||
uint8_t mNotificationSeriesCount;
|
||||
|
||||
@@ -57,17 +57,29 @@ otError otCoapMessageInitResponse(otMessage *aResponse, const otMessage *aReques
|
||||
response.Init(MapEnum(aType), MapEnum(aCode));
|
||||
response.SetMessageId(request.GetMessageId());
|
||||
|
||||
return response.SetTokenFromMessage(request);
|
||||
return response.WriteTokenFromMessage(request);
|
||||
}
|
||||
|
||||
otError otCoapMessageWriteToken(otMessage *aMessage, const otCoapToken *aToken)
|
||||
{
|
||||
return AsCoapMessage(aMessage).WriteToken(AsCoreType(aToken));
|
||||
}
|
||||
|
||||
otError otCoapMessageSetToken(otMessage *aMessage, const uint8_t *aToken, uint8_t aTokenLength)
|
||||
{
|
||||
return AsCoapMessage(aMessage).SetToken(aToken, aTokenLength);
|
||||
Error error;
|
||||
Coap::Token token;
|
||||
|
||||
SuccessOrExit(error = token.SetToken(aToken, aTokenLength));
|
||||
error = AsCoapMessage(aMessage).WriteToken(token);
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
void otCoapMessageGenerateToken(otMessage *aMessage, uint8_t aTokenLength)
|
||||
{
|
||||
IgnoreError(AsCoapMessage(aMessage).GenerateRandomToken(aTokenLength));
|
||||
IgnoreError(AsCoapMessage(aMessage).WriteRandomToken(aTokenLength));
|
||||
}
|
||||
|
||||
otError otCoapMessageAppendContentFormatOption(otMessage *aMessage, otCoapOptionContentFormat aContentFormat)
|
||||
@@ -157,9 +169,39 @@ const char *otCoapMessageCodeToString(const otMessage *aMessage) { return AsCoap
|
||||
|
||||
uint16_t otCoapMessageGetMessageId(const otMessage *aMessage) { return AsCoapMessage(aMessage).GetMessageId(); }
|
||||
|
||||
uint8_t otCoapMessageGetTokenLength(const otMessage *aMessage) { return AsCoapMessage(aMessage).GetTokenLength(); }
|
||||
otError otCoapMessageReadToken(const otMessage *aMessage, otCoapToken *aToken)
|
||||
{
|
||||
return AsCoapMessage(aMessage).ReadToken(AsCoreType(aToken));
|
||||
}
|
||||
|
||||
const uint8_t *otCoapMessageGetToken(const otMessage *aMessage) { return AsCoapMessage(aMessage).GetToken(); }
|
||||
bool otCoapMessageAreTokensEqual(const otCoapToken *aFirstToken, const otCoapToken *aSecondToken)
|
||||
{
|
||||
return AsCoreType(aFirstToken) == AsCoreType(aSecondToken);
|
||||
}
|
||||
|
||||
uint8_t otCoapMessageGetTokenLength(const otMessage *aMessage)
|
||||
{
|
||||
uint8_t length;
|
||||
|
||||
if (AsCoapMessage(aMessage).ReadTokenLength(length) != kErrorNone)
|
||||
{
|
||||
length = 0;
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
const uint8_t *otCoapMessageGetToken(const otMessage *aMessage)
|
||||
{
|
||||
static Coap::Token token;
|
||||
|
||||
if (AsCoapMessage(aMessage).ReadToken(token) != kErrorNone)
|
||||
{
|
||||
token.Clear();
|
||||
}
|
||||
|
||||
return token.GetBytes();
|
||||
}
|
||||
|
||||
otError otCoapOptionIteratorInit(otCoapOptionIterator *aIterator, const otMessage *aMessage)
|
||||
{
|
||||
|
||||
@@ -400,7 +400,7 @@ Error CoapBase::SendHeaderResponse(Message::Code aCode, const Message &aRequest,
|
||||
ExitNow(error = kErrorInvalidArgs);
|
||||
}
|
||||
|
||||
SuccessOrExit(error = message->SetTokenFromMessage(aRequest));
|
||||
SuccessOrExit(error = message->WriteTokenFromMessage(aRequest));
|
||||
|
||||
SuccessOrExit(error = SendMessage(*message, aMessageInfo));
|
||||
|
||||
@@ -604,7 +604,7 @@ Message *CoapBase::FindRelatedRequest(const Message &aResponse,
|
||||
|
||||
case kTypeConfirmable:
|
||||
case kTypeNonConfirmable:
|
||||
if (aResponse.IsTokenEqual(message))
|
||||
if (aResponse.HasSameTokenAs(message))
|
||||
{
|
||||
request = &message;
|
||||
ExitNow();
|
||||
@@ -717,7 +717,7 @@ void CoapBase::ProcessReceivedResponse(Message &aMessage, const Ip6::MessageInfo
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (aMessage.IsResponse() && aMessage.IsTokenEqual(*request))
|
||||
else if (aMessage.IsResponse() && aMessage.HasSameTokenAs(*request))
|
||||
{
|
||||
// Piggybacked response.
|
||||
|
||||
@@ -1198,7 +1198,7 @@ Error CoapBase::PrepareNextBlockRequest(uint16_t aBlockOptionNumber,
|
||||
|
||||
// Per RFC 7959, all requests in a block-wise transfer MUST use the
|
||||
// same token.
|
||||
IgnoreError(aRequest.SetTokenFromMessage(aRequestOld));
|
||||
IgnoreError(aRequest.WriteTokenFromMessage(aRequestOld));
|
||||
|
||||
// Copy options from last response to next message
|
||||
|
||||
@@ -1384,7 +1384,7 @@ Error CoapBase::ProcessBlock1Request(Message &aMessage,
|
||||
VerifyOrExit((response = NewMessage()) != nullptr, error = kErrorFailed);
|
||||
response->Init(kTypeAck, kCodeContinue);
|
||||
response->SetMessageId(aMessage.GetMessageId());
|
||||
IgnoreError(response->SetToken(AsConst(aMessage).GetToken(), aMessage.GetTokenLength()));
|
||||
SuccessOrExit(error = response->WriteTokenFromMessage(aMessage));
|
||||
|
||||
SuccessOrExit(error = response->AppendBlockOption(kOptionBlock1, msgBlockInfo));
|
||||
|
||||
@@ -1440,7 +1440,7 @@ Error CoapBase::ProcessBlock2Request(Message &aMessage,
|
||||
response->Init(kTypeAck, kCodeContent);
|
||||
response->SetMessageId(aMessage.GetMessageId());
|
||||
|
||||
SuccessOrExit(error = response->SetTokenFromMessage(aMessage));
|
||||
SuccessOrExit(error = response->WriteTokenFromMessage(aMessage));
|
||||
|
||||
responseBlockInfo.mMoreBlocks = false;
|
||||
|
||||
|
||||
@@ -45,6 +45,47 @@ uint16_t BlockSizeFromExponent(BlockSzx aBlockSzxq)
|
||||
return static_cast<uint16_t>(1 << (static_cast<uint8_t>(aBlockSzxq) + kBlockSzxBase));
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
// `Token`
|
||||
|
||||
Error Token::SetToken(const uint8_t *aBytes, uint8_t aLength)
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
|
||||
VerifyOrExit(aLength <= kMaxLength, error = kErrorInvalidArgs);
|
||||
|
||||
mLength = aLength;
|
||||
memcpy(m8, aBytes, aLength);
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
bool Token::operator==(const Token &aOther) const
|
||||
{
|
||||
bool isEqual = false;
|
||||
|
||||
VerifyOrExit(IsValid());
|
||||
VerifyOrExit(mLength == aOther.mLength);
|
||||
|
||||
isEqual = (memcmp(m8, aOther.m8, mLength) == 0);
|
||||
|
||||
exit:
|
||||
return isEqual;
|
||||
}
|
||||
|
||||
Error Token::GenerateRandom(uint8_t aLength)
|
||||
{
|
||||
Error error;
|
||||
|
||||
VerifyOrExit(aLength <= kMaxLength, error = kErrorInvalidArgs);
|
||||
mLength = aLength;
|
||||
error = Random::Crypto::FillBuffer(m8, mLength);
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
// `Message`
|
||||
|
||||
@@ -70,7 +111,7 @@ Error Message::Init(Type aType, Code aCode, Uri aUri)
|
||||
Error error;
|
||||
|
||||
Init(aType, aCode);
|
||||
SuccessOrExit(error = GenerateRandomToken(kDefaultTokenLength));
|
||||
SuccessOrExit(error = WriteRandomToken(Token::kDefaultLength));
|
||||
SuccessOrExit(error = AppendUriPathOptions(PathForUri(aUri)));
|
||||
|
||||
exit:
|
||||
@@ -412,42 +453,70 @@ exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
Error Message::SetToken(const uint8_t *aToken, uint8_t aTokenLength)
|
||||
Error Message::ReadTokenLength(uint8_t &aLength) const
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
|
||||
VerifyOrExit(GetHelpData().mHeader.IsValid(), error = kErrorParse);
|
||||
aLength = GetHelpData().mHeader.GetTokenLength();
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
Error Message::ReadToken(Token &aToken) const
|
||||
{
|
||||
return aToken.SetToken(GetHelpData().mHeader.GetToken(), GetHelpData().mHeader.GetTokenLength());
|
||||
}
|
||||
|
||||
Error Message::WriteToken(const Token &aToken)
|
||||
{
|
||||
Error error;
|
||||
|
||||
SuccessOrExit(error = GetHelpData().mHeader.SetToken(aToken, aTokenLength));
|
||||
GetHelpData().mHeaderLength += aTokenLength;
|
||||
SuccessOrExit(error = GetHelpData().mHeader.SetToken(aToken));
|
||||
GetHelpData().mHeaderLength += aToken.GetLength();
|
||||
error = SetLength(GetHelpData().mHeaderLength);
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
Error Message::GenerateRandomToken(uint8_t aTokenLength)
|
||||
Error Message::WriteRandomToken(uint8_t aTokenLength)
|
||||
{
|
||||
Error error;
|
||||
uint8_t token[kMaxTokenLength];
|
||||
Error error;
|
||||
Token token;
|
||||
|
||||
VerifyOrExit(aTokenLength <= kMaxTokenLength, error = kErrorInvalidArgs);
|
||||
|
||||
SuccessOrExit(error = Random::Crypto::FillBuffer(token, aTokenLength));
|
||||
error = SetToken(token, aTokenLength);
|
||||
SuccessOrExit(error = token.GenerateRandom(aTokenLength));
|
||||
error = WriteToken(token);
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
Error Message::SetTokenFromMessage(const Message &aMessage)
|
||||
Error Message::WriteTokenFromMessage(const Message &aMessage)
|
||||
{
|
||||
return SetToken(aMessage.GetToken(), aMessage.GetTokenLength());
|
||||
Error error;
|
||||
Token token;
|
||||
|
||||
SuccessOrExit(error = aMessage.ReadToken(token));
|
||||
error = WriteToken(token);
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
bool Message::IsTokenEqual(const Message &aMessage) const
|
||||
bool Message::HasSameTokenAs(const Message &aMessage) const
|
||||
{
|
||||
uint8_t tokenLength = GetTokenLength();
|
||||
bool hasSame = false;
|
||||
Token token;
|
||||
Token msgToken;
|
||||
|
||||
return ((tokenLength == aMessage.GetTokenLength()) && (memcmp(GetToken(), aMessage.GetToken(), tokenLength) == 0));
|
||||
SuccessOrExit(ReadToken(token));
|
||||
SuccessOrExit(aMessage.ReadToken(msgToken));
|
||||
hasSame = (token == msgToken);
|
||||
|
||||
exit:
|
||||
return hasSame;
|
||||
}
|
||||
|
||||
Error Message::SetDefaultResponseHeader(const Message &aRequest)
|
||||
@@ -456,7 +525,7 @@ Error Message::SetDefaultResponseHeader(const Message &aRequest)
|
||||
|
||||
SetMessageId(aRequest.GetMessageId());
|
||||
|
||||
return SetTokenFromMessage(aRequest);
|
||||
return WriteTokenFromMessage(aRequest);
|
||||
}
|
||||
|
||||
Message *Message::Clone(uint16_t aLength) const
|
||||
@@ -514,15 +583,18 @@ const char *Message::CodeToString(void) const
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
// `Message::Header`
|
||||
|
||||
bool Message::Header::IsValid(void) const
|
||||
{
|
||||
return (GetVersion() == kVersion1) && (GetTokenLength() <= Token::kMaxLength);
|
||||
}
|
||||
|
||||
Error Message::Header::ParseFrom(const Message &aMessage)
|
||||
{
|
||||
Error error;
|
||||
uint16_t offset = aMessage.GetOffset();
|
||||
|
||||
SuccessOrExit(error = aMessage.Read(offset, this, kMinSize));
|
||||
|
||||
VerifyOrExit(GetVersion() == kVersion1, error = kErrorParse);
|
||||
VerifyOrExit(GetTokenLength() <= kMaxTokenLength, error = kErrorParse);
|
||||
VerifyOrExit(IsValid(), error = kErrorParse);
|
||||
|
||||
SuccessOrExit(error = aMessage.Read(offset + kMinSize, mToken, GetTokenLength()));
|
||||
|
||||
@@ -530,14 +602,14 @@ exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
Error Message::Header::SetToken(const uint8_t *aToken, uint8_t aTokenLength)
|
||||
Error Message::Header::SetToken(const Token &aToken)
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
|
||||
VerifyOrExit(aTokenLength <= kMaxTokenLength, error = kErrorInvalidArgs);
|
||||
VerifyOrExit(aToken.IsValid(), error = kErrorInvalidArgs);
|
||||
|
||||
SetTokenLength(aTokenLength);
|
||||
memcpy(mToken, aToken, aTokenLength);
|
||||
SetTokenLength(aToken.mLength);
|
||||
memcpy(mToken, aToken.GetBytes(), aToken.GetLength());
|
||||
|
||||
exit:
|
||||
return error;
|
||||
|
||||
+101
-30
@@ -44,6 +44,7 @@
|
||||
#include "common/code_utils.hpp"
|
||||
#include "common/const_cast.hpp"
|
||||
#include "common/encoding.hpp"
|
||||
#include "common/equatable.hpp"
|
||||
#include "common/message.hpp"
|
||||
#include "net/ip6.hpp"
|
||||
#include "net/ip6_address.hpp"
|
||||
@@ -68,6 +69,7 @@ namespace Coap {
|
||||
* @{
|
||||
*/
|
||||
|
||||
class Message;
|
||||
class Option;
|
||||
|
||||
/**
|
||||
@@ -201,6 +203,66 @@ struct BlockInfo
|
||||
bool mMoreBlocks; ///< Whether more blocks are following (`M` flag).
|
||||
};
|
||||
|
||||
/**
|
||||
* Represents a CoAP message Token.
|
||||
*/
|
||||
class Token : public otCoapToken, public Clearable<Token>, public Unequatable<Token>
|
||||
{
|
||||
friend class Message;
|
||||
|
||||
public:
|
||||
static const uint8_t kMaxLength = OT_COAP_MAX_TOKEN_LENGTH; ///< Maximum token length.
|
||||
static const uint8_t kDefaultLength = OT_COAP_DEFAULT_TOKEN_LENGTH; ///< Default token length.
|
||||
|
||||
/**
|
||||
* Indicates whether the Token is valid.
|
||||
*
|
||||
* A Token is valid if its length is less than or equal to `kMaxLength`.
|
||||
*
|
||||
* @retval TRUE If the Token is valid.
|
||||
* @retval FALSE If the Token is not valid.
|
||||
*/
|
||||
bool IsValid(void) const { return mLength <= kMaxLength; }
|
||||
|
||||
/**
|
||||
* Returns a pointer to the Token bytes.
|
||||
*
|
||||
* @returns A pointer to the Token bytes.
|
||||
*/
|
||||
const uint8_t *GetBytes(void) const { return m8; }
|
||||
|
||||
/**
|
||||
* Returns the Token length in bytes.
|
||||
*
|
||||
* @returns The Token length in bytes.
|
||||
*/
|
||||
uint8_t GetLength(void) const { return mLength; }
|
||||
|
||||
/**
|
||||
* Sets the Token bytes and length.
|
||||
*
|
||||
* @param[in] aBytes A pointer to the Token bytes.
|
||||
* @param[in] aLength The Token length in bytes.
|
||||
*
|
||||
* @retval kErrorNone Successfully set the Token.
|
||||
* @retval kErrorInvalidArgs The specified length @p aLength is greater than `kMaxLength`.
|
||||
*/
|
||||
Error SetToken(const uint8_t *aBytes, uint8_t aLength);
|
||||
|
||||
/**
|
||||
* Overloads the `==` operator to compare two CoAP Tokens.
|
||||
*
|
||||
* @param[in] aOther The other Token to compare with.
|
||||
*
|
||||
* @retval TRUE If the two Tokens are equal.
|
||||
* @retval FALSE If the two Tokens are not equal.
|
||||
*/
|
||||
bool operator==(const Token &aOther) const;
|
||||
|
||||
private:
|
||||
Error GenerateRandom(uint8_t aLength);
|
||||
};
|
||||
|
||||
/**
|
||||
* Implements CoAP message generation and parsing.
|
||||
*/
|
||||
@@ -313,7 +375,7 @@ public:
|
||||
* @ returns The CoAP Code as string.
|
||||
*/
|
||||
const char *CodeToString(void) const;
|
||||
#endif // OPENTHREAD_CONFIG_COAP_API_ENABLE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Returns the Message ID value.
|
||||
@@ -330,59 +392,66 @@ public:
|
||||
void SetMessageId(uint16_t aMessageId) { GetHelpData().mHeader.SetMessageId(aMessageId); }
|
||||
|
||||
/**
|
||||
* Returns the Token length.
|
||||
* Reads the Token length from the message
|
||||
*
|
||||
* @returns The Token length.
|
||||
* @param[out] aLength A reference to a `uint8_t` to return the read token length (in bytes).
|
||||
*
|
||||
* @retval kErrorNone Successfully parsed the CoaP header and read the Token length.
|
||||
* @retval kErrorParse Failed to parse the CoAP header.
|
||||
*/
|
||||
uint8_t GetTokenLength(void) const { return GetHelpData().mHeader.GetTokenLength(); }
|
||||
Error ReadTokenLength(uint8_t &aLength) const;
|
||||
|
||||
/**
|
||||
* Returns a pointer to the Token value.
|
||||
* Reads the Token from the message
|
||||
*
|
||||
* @returns A pointer to the Token value.
|
||||
* @param[out] aToken A reference to return the read `Token`.
|
||||
*
|
||||
* @retval kErrorNone Successfully parsed the CoaP header and read the Token. @p aToken is updated.
|
||||
* @retval kErrorParse Failed to parse the CoAP header.
|
||||
*/
|
||||
const uint8_t *GetToken(void) const { return GetHelpData().mHeader.GetToken(); }
|
||||
Error ReadToken(Token &aToken) const;
|
||||
|
||||
/**
|
||||
* Sets the Token value and length.
|
||||
* Writes the Token in the message.
|
||||
*
|
||||
* @param[in] aToken A pointer to the Token value.
|
||||
* @param[in] aTokenLength The Length of @p aToken.
|
||||
* @param[in] aToken The new token.
|
||||
*
|
||||
* @retval kErrorNone Successfully set the token value.
|
||||
* @retval kErrorNoBufs Insufficient message buffers available to set the token value.
|
||||
* @retval kErrorNone Successfully wrote the Token.
|
||||
* @retval kErrorNoBufs Insufficient message buffers available to write.
|
||||
*/
|
||||
Error SetToken(const uint8_t *aToken, uint8_t aTokenLength);
|
||||
Error WriteToken(const Token &aToken);
|
||||
|
||||
/**
|
||||
* Sets the Token value and length by copying it from another given message.
|
||||
* Writes the Token by copying it from another given message.
|
||||
*
|
||||
* @param[in] aMessage The message to copy the Token from.
|
||||
* @param[in] aMessage The message to copy the Token from.
|
||||
*
|
||||
* @retval kErrorNone Successfully set the token value.
|
||||
* @retval kErrorNoBufs Insufficient message buffers available to set the token value.
|
||||
* @retval kErrorNone Successfully wrote the Token.
|
||||
* @retval kErrorNoBufs Insufficient message buffers available to write.
|
||||
*/
|
||||
Error SetTokenFromMessage(const Message &aMessage);
|
||||
Error WriteTokenFromMessage(const Message &aMessage);
|
||||
|
||||
/**
|
||||
* Sets the Token length and randomizes its value.
|
||||
* Writes a randomly generated Token of a given length in the message.
|
||||
*
|
||||
* @param[in] aTokenLength The Length of a Token to set.
|
||||
* @param[in] aTokenLength The Token length (in bytes).
|
||||
*
|
||||
* @retval kErrorNone Successfully set the token value.
|
||||
* @retval kErrorNoBufs Insufficient message buffers available to set the token value.
|
||||
* @retval kErrorNone Successfully wrote the Token.
|
||||
* @retval kErrorNoBufs Insufficient message buffers available to write.
|
||||
*/
|
||||
Error GenerateRandomToken(uint8_t aTokenLength);
|
||||
Error WriteRandomToken(uint8_t aTokenLength);
|
||||
|
||||
/**
|
||||
* Checks if Tokens in two CoAP headers are equal.
|
||||
* Checks whether the Token in the message is the same as the one from another message.
|
||||
*
|
||||
* @param[in] aMessage A header to compare.
|
||||
* If parsing/reading the Token fails for either message, the Tokens are considered unequal.
|
||||
*
|
||||
* @retval TRUE If two Tokens are equal.
|
||||
* @retval FALSE If Tokens differ in length or value.
|
||||
* @param[in] aMessage The other message.
|
||||
*
|
||||
* @retval TRUE If the two Tokens are equal.
|
||||
* @retval FALSE If the two Tokens are not equal.
|
||||
*/
|
||||
bool IsTokenEqual(const Message &aMessage) const;
|
||||
bool HasSameTokenAs(const Message &aMessage) const;
|
||||
|
||||
/**
|
||||
* Appends a CoAP option.
|
||||
@@ -576,7 +645,7 @@ public:
|
||||
*
|
||||
* @returns The offset of the first CoAP option.
|
||||
*/
|
||||
uint16_t GetOptionStart(void) const { return kMinHeaderLength + GetTokenLength(); }
|
||||
uint16_t GetOptionStart(void) const { return kMinHeaderLength + GetHelpData().mHeader.GetTokenLength(); }
|
||||
|
||||
/**
|
||||
* Parses CoAP header and moves offset end of CoAP header.
|
||||
@@ -815,6 +884,7 @@ private:
|
||||
static constexpr uint8_t kVersion1 = 1;
|
||||
|
||||
uint8_t GetSize(void) const { return kMinSize + GetTokenLength(); }
|
||||
bool IsValid(void) const;
|
||||
Error ParseFrom(const Message &aMessage);
|
||||
uint8_t GetVersion(void) const { return ReadBits<uint8_t, kVersionMask>(mVersionTypeToken); }
|
||||
void SetVersion(uint8_t aVersion) { WriteBits<uint8_t, kVersionMask>(mVersionTypeToken, aVersion); }
|
||||
@@ -826,7 +896,7 @@ private:
|
||||
void SetMessageId(uint16_t aMessageId) { mMessageId = BigEndian::HostSwap16(aMessageId); }
|
||||
const uint8_t *GetToken(void) const { return mToken; }
|
||||
uint8_t GetTokenLength(void) const { return ReadBits<uint8_t, kTokenLengthMask>(mVersionTypeToken); }
|
||||
Error SetToken(const uint8_t *aToken, uint8_t aTokenLength);
|
||||
Error SetToken(const Token &aToken);
|
||||
|
||||
private:
|
||||
/*
|
||||
@@ -1147,6 +1217,7 @@ public:
|
||||
|
||||
DefineCoreType(otCoapOption, Coap::Option);
|
||||
DefineCoreType(otCoapOptionIterator, Coap::Option::Iterator);
|
||||
DefineCoreType(otCoapToken, Coap::Token);
|
||||
DefineMapEnum(otCoapType, Coap::Type);
|
||||
DefineMapEnum(otCoapCode, Coap::Code);
|
||||
DefineMapEnum(otCoapBlockSzx, Coap::BlockSzx);
|
||||
|
||||
@@ -670,6 +670,7 @@ Error Manager::CoapDtlsSession::ForwardToLeader(const Coap::Message &aMessage
|
||||
Tmf::MessageInfo messageInfo(GetInstance());
|
||||
OwnedPtr<Coap::Message> message;
|
||||
OffsetRange offsetRange;
|
||||
Coap::Token token;
|
||||
|
||||
switch (aUri)
|
||||
{
|
||||
@@ -718,9 +719,9 @@ Error Manager::CoapDtlsSession::ForwardToLeader(const Coap::Message &aMessage
|
||||
exit:
|
||||
LogWarnOnError(error, "forward to leader");
|
||||
|
||||
if (error != kErrorNone)
|
||||
if ((error != kErrorNone) && (aMessage.ReadToken(token) == kErrorNone))
|
||||
{
|
||||
SendErrorMessage(error, aMessage.GetToken(), aMessage.GetTokenLength());
|
||||
SendErrorMessage(error, token);
|
||||
}
|
||||
|
||||
return error;
|
||||
@@ -794,7 +795,7 @@ void Manager::CoapDtlsSession::HandleLeaderResponseToFwdTmf(const ForwardContext
|
||||
|
||||
forwardMessage->Init(Coap::kTypeNonConfirmable, static_cast<Coap::Code>(aResponse->GetCode()));
|
||||
|
||||
SuccessOrExit(error = forwardMessage->SetToken(aForwardContext.mToken, aForwardContext.mTokenLength));
|
||||
SuccessOrExit(error = forwardMessage->WriteToken(aForwardContext.mToken));
|
||||
|
||||
if (aResponse->GetLength() > aResponse->GetOffset())
|
||||
{
|
||||
@@ -824,7 +825,7 @@ exit:
|
||||
LogWarn("Forwarded %s failed - session %u, error:%s", uriString, mIndex, ErrorToString(error));
|
||||
#endif
|
||||
|
||||
SendErrorMessage(error, aForwardContext.mToken, aForwardContext.mTokenLength);
|
||||
SendErrorMessage(error, aForwardContext.mToken);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -894,7 +895,7 @@ exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
void Manager::CoapDtlsSession::SendErrorMessage(Error aError, const uint8_t *aToken, uint8_t aTokenLength)
|
||||
void Manager::CoapDtlsSession::SendErrorMessage(Error aError, const Coap::Token &aToken)
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
OwnedPtr<Coap::Message> message;
|
||||
@@ -906,7 +907,7 @@ void Manager::CoapDtlsSession::SendErrorMessage(Error aError, const uint8_t *aTo
|
||||
code = (aError == kErrorParse) ? Coap::kCodeBadRequest : Coap::kCodeInternalError;
|
||||
|
||||
message->Init(Coap::kTypeNonConfirmable, code);
|
||||
SuccessOrExit(error = message->SetToken(aToken, aTokenLength));
|
||||
SuccessOrExit(error = message->WriteToken(aToken));
|
||||
|
||||
SuccessOrExit(error = SendMessage(message.PassOwnership()));
|
||||
|
||||
@@ -1094,9 +1095,11 @@ Manager::CoapDtlsSession::ForwardContext::ForwardContext(CoapDtlsSession &aS
|
||||
Uri aUri)
|
||||
: mSession(aSession)
|
||||
, mUri(aUri)
|
||||
, mTokenLength(aMessage.GetTokenLength())
|
||||
{
|
||||
memcpy(mToken, aMessage.GetToken(), mTokenLength);
|
||||
if (aMessage.ReadToken(mToken) != kErrorNone)
|
||||
{
|
||||
mToken.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace BorderAgent
|
||||
|
||||
@@ -297,8 +297,7 @@ private:
|
||||
CoapDtlsSession &mSession;
|
||||
ForwardContext *mNext;
|
||||
Uri mUri;
|
||||
uint8_t mTokenLength;
|
||||
uint8_t mToken[Coap::Message::kMaxTokenLength];
|
||||
Coap::Token mToken;
|
||||
};
|
||||
|
||||
CoapDtlsSession(Instance &aInstance, Dtls::Transport &aDtlsTransport);
|
||||
@@ -309,7 +308,7 @@ private:
|
||||
void HandleTmfProxyTx(Coap::Message &aMessage);
|
||||
void HandleTmfDatasetGet(Coap::Message &aMessage, Uri aUri);
|
||||
Error ForwardToLeader(const Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo, Uri aUri);
|
||||
void SendErrorMessage(Error aError, const uint8_t *aToken, uint8_t aTokenLength);
|
||||
void SendErrorMessage(Error aError, const Coap::Token &aToken);
|
||||
|
||||
static void HandleConnected(ConnectEvent aEvent, void *aContext);
|
||||
void HandleConnected(ConnectEvent aEvent);
|
||||
|
||||
Reference in New Issue
Block a user