[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:
Abtin Keshavarzian
2026-01-09 16:45:14 -08:00
committed by GitHub
parent 6a9d92545b
commit 7354c57adb
10 changed files with 353 additions and 115 deletions
+70 -17
View File
@@ -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);
/**
* @}
*/
+1 -1
View File
@@ -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
View File
@@ -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();
}
}
+2 -4
View File
@@ -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;
+47 -5
View File
@@ -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)
{
+6 -6
View File
@@ -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;
+96 -24
View File
@@ -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
View File
@@ -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);
+11 -8
View File
@@ -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
+2 -3
View File
@@ -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);