diff --git a/include/openthread/coap.h b/include/openthread/coap.h index f4eb8122e..15adca24d 100644 --- a/include/openthread/coap.h +++ b/include/openthread/coap.h @@ -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); + /** * @} */ diff --git a/include/openthread/instance.h b/include/openthread/instance.h index 12170deb2..b52977f01 100644 --- a/include/openthread/instance.h +++ b/include/openthread/instance.h @@ -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 diff --git a/src/cli/cli_coap.cpp b/src/cli/cli_coap.cpp index 9a6547dc2..5aba2116e 100644 --- a/src/cli/cli_coap.cpp +++ b/src/cli/cli_coap.cpp @@ -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(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(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(); } } diff --git a/src/cli/cli_coap.hpp b/src/cli/cli_coap.hpp index f81ae2fa8..3df362c9f 100644 --- a/src/cli/cli_coap.hpp +++ b/src/cli/cli_coap.hpp @@ -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; diff --git a/src/core/api/coap_api.cpp b/src/core/api/coap_api.cpp index 4a210125d..2322c31fa 100644 --- a/src/core/api/coap_api.cpp +++ b/src/core/api/coap_api.cpp @@ -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) { diff --git a/src/core/coap/coap.cpp b/src/core/coap/coap.cpp index c9a69352d..cbf01d481 100644 --- a/src/core/coap/coap.cpp +++ b/src/core/coap/coap.cpp @@ -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; diff --git a/src/core/coap/coap_message.cpp b/src/core/coap/coap_message.cpp index bf4279e10..41bab3ce2 100644 --- a/src/core/coap/coap_message.cpp +++ b/src/core/coap/coap_message.cpp @@ -45,6 +45,47 @@ uint16_t BlockSizeFromExponent(BlockSzx aBlockSzxq) return static_cast(1 << (static_cast(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; diff --git a/src/core/coap/coap_message.hpp b/src/core/coap/coap_message.hpp index d44c25d2a..305766b45 100644 --- a/src/core/coap/coap_message.hpp +++ b/src/core/coap/coap_message.hpp @@ -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, public Unequatable +{ + 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(mVersionTypeToken); } void SetVersion(uint8_t aVersion) { WriteBits(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(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); diff --git a/src/core/meshcop/border_agent.cpp b/src/core/meshcop/border_agent.cpp index 7a13d0c70..fea02bd2c 100644 --- a/src/core/meshcop/border_agent.cpp +++ b/src/core/meshcop/border_agent.cpp @@ -670,6 +670,7 @@ Error Manager::CoapDtlsSession::ForwardToLeader(const Coap::Message &aMessage Tmf::MessageInfo messageInfo(GetInstance()); OwnedPtr 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(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 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 diff --git a/src/core/meshcop/border_agent.hpp b/src/core/meshcop/border_agent.hpp index dbdd5ba34..a85d6d4a3 100644 --- a/src/core/meshcop/border_agent.hpp +++ b/src/core/meshcop/border_agent.hpp @@ -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);