From c7500514590a575bced08d74d4bc08bf81ceb64c Mon Sep 17 00:00:00 2001 From: yunhanw-google Date: Mon, 6 Dec 2021 13:32:40 -0800 Subject: [PATCH] Add IM DataVersionFilter encoding support for read/subscribe request (#12569) --- src/app/BUILD.gn | 8 +- .../MessageDef/AttributeDataVersionList.cpp | 164 ------------- src/app/MessageDef/ClusterPathIB.cpp | 169 ++++++++++++++ src/app/MessageDef/ClusterPathIB.h | 133 +++++++++++ src/app/MessageDef/DataVersionFilterIB.cpp | 142 ++++++++++++ ...ataVersionList.h => DataVersionFilterIB.h} | 68 +++--- src/app/MessageDef/DataVersionFilterIBs.cpp | 85 +++++++ src/app/MessageDef/DataVersionFilterIBs.h | 82 +++++++ src/app/MessageDef/ReadRequestMessage.cpp | 30 +++ src/app/MessageDef/ReadRequestMessage.h | 24 +- .../MessageDef/SubscribeRequestMessage.cpp | 66 ++++-- src/app/MessageDef/SubscribeRequestMessage.h | 12 +- src/app/MessageDef/WriteRequestMessage.h | 1 - src/app/tests/TestMessageDef.cpp | 219 ++++++++++++++---- src/lib/core/CHIPError.cpp | 6 + src/lib/core/CHIPError.h | 17 ++ 16 files changed, 956 insertions(+), 270 deletions(-) delete mode 100644 src/app/MessageDef/AttributeDataVersionList.cpp create mode 100644 src/app/MessageDef/ClusterPathIB.cpp create mode 100644 src/app/MessageDef/ClusterPathIB.h create mode 100644 src/app/MessageDef/DataVersionFilterIB.cpp rename src/app/MessageDef/{AttributeDataVersionList.h => DataVersionFilterIB.h} (58%) create mode 100644 src/app/MessageDef/DataVersionFilterIBs.cpp create mode 100644 src/app/MessageDef/DataVersionFilterIBs.h diff --git a/src/app/BUILD.gn b/src/app/BUILD.gn index 8024abcd1459ce..ace6654950b710 100644 --- a/src/app/BUILD.gn +++ b/src/app/BUILD.gn @@ -57,8 +57,6 @@ static_library("app") { "MessageDef/AttributeDataIB.h", "MessageDef/AttributeDataIBs.cpp", "MessageDef/AttributeDataIBs.h", - "MessageDef/AttributeDataVersionList.cpp", - "MessageDef/AttributeDataVersionList.h", "MessageDef/AttributePathIB.cpp", "MessageDef/AttributePathIB.h", "MessageDef/AttributePathIBs.cpp", @@ -73,9 +71,15 @@ static_library("app") { "MessageDef/AttributeStatusIBs.h", "MessageDef/Builder.cpp", "MessageDef/Builder.h", + "MessageDef/ClusterPathIB.cpp", + "MessageDef/ClusterPathIB.h", "MessageDef/CommandDataIB.cpp", "MessageDef/CommandPathIB.cpp", "MessageDef/CommandStatusIB.cpp", + "MessageDef/DataVersionFilterIB.cpp", + "MessageDef/DataVersionFilterIB.h", + "MessageDef/DataVersionFilterIBs.cpp", + "MessageDef/DataVersionFilterIBs.h", "MessageDef/EventDataIB.cpp", "MessageDef/EventDataIB.h", "MessageDef/EventFilterIB.cpp", diff --git a/src/app/MessageDef/AttributeDataVersionList.cpp b/src/app/MessageDef/AttributeDataVersionList.cpp deleted file mode 100644 index 0de5fe74412660..00000000000000 --- a/src/app/MessageDef/AttributeDataVersionList.cpp +++ /dev/null @@ -1,164 +0,0 @@ -/** - * - * Copyright (c) 2020 Project CHIP Authors - * Copyright (c) 2018 Google LLC. - * Copyright (c) 2016-2017 Nest Labs, Inc. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * @file - * This file defines AttributeDataVersionList parser and builder in CHIP interaction model - * - */ - -#include "AttributeDataVersionList.h" - -#include "MessageDefHelper.h" - -#include -#include -#include - -#include - -using namespace chip; -using namespace chip::TLV; - -namespace chip { -namespace app { -#if CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK -CHIP_ERROR AttributeDataVersionList::Parser::CheckSchemaValidity() const -{ - CHIP_ERROR err = CHIP_NO_ERROR; - chip::TLV::TLVReader reader; - chip::DataVersion version; - size_t index = 0; - - PRETTY_PRINT("AttributeDataVersionList = "); - PRETTY_PRINT("["); - - reader.Init(mReader); - - while (CHIP_NO_ERROR == (err = reader.Next())) - { - VerifyOrExit(chip::TLV::AnonymousTag == reader.GetTag(), err = CHIP_ERROR_INVALID_TLV_TAG); - - switch (reader.GetType()) - { - case chip::TLV::kTLVType_Null: - PRETTY_PRINT("\tNull,"); - break; - - case chip::TLV::kTLVType_UnsignedInteger: - err = reader.Get(version); - SuccessOrExit(err); - - PRETTY_PRINT("\t0x%" PRIx64 ",", version); - break; - - default: - ExitNow(err = CHIP_ERROR_WRONG_TLV_TYPE); - break; - } - - ++index; - } - - PRETTY_PRINT("],"); - - if (CHIP_END_OF_TLV == err) - { - err = CHIP_NO_ERROR; - } - SuccessOrExit(err); - err = reader.ExitContainer(mOuterContainerType); - -exit: - - return err; -} -#endif // CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK - -// 1) current element is anonymous -// 2) current element is either unsigned integer or NULL -bool AttributeDataVersionList::Parser::IsElementValid(void) -{ - CHIP_ERROR err = CHIP_NO_ERROR; - bool result = false; - - VerifyOrExit(chip::TLV::AnonymousTag == mReader.GetTag(), err = CHIP_ERROR_INVALID_TLV_TAG); - - switch (mReader.GetType()) - { - case chip::TLV::kTLVType_Null: - case chip::TLV::kTLVType_UnsignedInteger: - result = true; - break; - default: - ExitNow(); - break; - } - -exit: - - return result; -} - -bool AttributeDataVersionList::Parser::IsNull(void) -{ - return (chip::TLV::kTLVType_Null == mReader.GetType()); -} - -CHIP_ERROR AttributeDataVersionList::Parser::GetVersion(chip::DataVersion * const apVersion) -{ - CHIP_ERROR err = CHIP_NO_ERROR; - if (mReader.GetType() == kTLVType_Null) - { - *apVersion = 0; - ChipLogDetail(DataManagement, "Version is null in GetVersion"); - } - else - { - err = mReader.Get(*apVersion); - } - return err; -} - -AttributeDataVersionList::Builder & AttributeDataVersionList::Builder::AddVersion(const uint64_t aVersion) -{ - // skip if error has already been set - if (mError == CHIP_NO_ERROR) - { - mError = mpWriter->Put(chip::TLV::AnonymousTag, aVersion); - } - return *this; -} - -AttributeDataVersionList::Builder & AttributeDataVersionList::Builder::AddNull(void) -{ - // skip if error has already been set - if (mError == CHIP_NO_ERROR) - { - mError = mpWriter->PutNull(chip::TLV::AnonymousTag); - } - return *this; -} - -// Mark the end of this array and recover the type for outer container -AttributeDataVersionList::Builder & AttributeDataVersionList::Builder::EndOfAttributeDataVersionList(void) -{ - EndOfContainer(); - return *this; -} -}; // namespace app -}; // namespace chip diff --git a/src/app/MessageDef/ClusterPathIB.cpp b/src/app/MessageDef/ClusterPathIB.cpp new file mode 100644 index 00000000000000..c9ef017d747903 --- /dev/null +++ b/src/app/MessageDef/ClusterPathIB.cpp @@ -0,0 +1,169 @@ +/** + * + * Copyright (c) 2021 Project CHIP Authors + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ClusterPathIB.h" +#include "MessageDefHelper.h" + +#include +#include +#include + +#include + +namespace chip { +namespace app { +#if CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK +CHIP_ERROR ClusterPathIB::Parser::CheckSchemaValidity() const +{ + CHIP_ERROR err = CHIP_NO_ERROR; + int tagPresenceMask = 0; + TLV::TLVReader reader; + + PRETTY_PRINT("ClusterPathIB ="); + PRETTY_PRINT("{"); + + // make a copy of the Path reader + reader.Init(mReader); + + while (CHIP_NO_ERROR == (err = reader.Next())) + { + VerifyOrReturnError(TLV::IsContextTag(reader.GetTag()), CHIP_ERROR_INVALID_TLV_TAG); + uint32_t tagNum = TLV::TagNumFromTag(reader.GetTag()); + switch (tagNum) + { + case to_underlying(Tag::kNode): + // check if this tag has appeared before + + VerifyOrReturnError(!(tagPresenceMask & (1 << to_underlying(Tag::kNode))), err = CHIP_ERROR_INVALID_TLV_TAG); + tagPresenceMask |= (1 << to_underlying(Tag::kNode)); + VerifyOrReturnError(TLV::kTLVType_UnsignedInteger == reader.GetType(), err = CHIP_ERROR_WRONG_TLV_TYPE); + +#if CHIP_DETAIL_LOGGING + { + NodeId node; + reader.Get(node); + PRETTY_PRINT("\tNode = 0x%" PRIx64 ",", node); + } +#endif // CHIP_DETAIL_LOGGING + break; + case to_underlying(Tag::kEndpoint): + // check if this tag has appeared before + VerifyOrReturnError(!(tagPresenceMask & (1 << to_underlying(Tag::kEndpoint))), CHIP_ERROR_INVALID_TLV_TAG); + tagPresenceMask |= (1 << to_underlying(Tag::kEndpoint)); + VerifyOrReturnError(TLV::kTLVType_UnsignedInteger == reader.GetType(), CHIP_ERROR_WRONG_TLV_TYPE); +#if CHIP_DETAIL_LOGGING + { + EndpointId endpoint; + reader.Get(endpoint); + PRETTY_PRINT("\tEndpoint = 0x%" PRIx16 ",", endpoint); + } +#endif // CHIP_DETAIL_LOGGING + break; + case to_underlying(Tag::kCluster): + // check if this tag has appeared before + VerifyOrReturnError(!(tagPresenceMask & (1 << to_underlying(Tag::kCluster))), err = CHIP_ERROR_INVALID_TLV_TAG); + tagPresenceMask |= (1 << to_underlying(Tag::kCluster)); + VerifyOrReturnError(TLV::kTLVType_UnsignedInteger == reader.GetType(), err = CHIP_ERROR_WRONG_TLV_TYPE); + +#if CHIP_DETAIL_LOGGING + { + ClusterId cluster; + ReturnErrorOnFailure(reader.Get(cluster)); + PRETTY_PRINT("\tCluster = 0x%" PRIx32 ",", cluster); + } +#endif // CHIP_DETAIL_LOGGING + break; + default: + PRETTY_PRINT("Unknown tag num %" PRIu32, tagNum); + break; + } + } + + PRETTY_PRINT("}"); + PRETTY_PRINT("\t"); + // if we have exhausted this container + if (CHIP_END_OF_TLV == err) + { + // check for required fields: + const int RequiredFields = (1 << to_underlying(Tag::kCluster)); + + if ((tagPresenceMask & RequiredFields) == RequiredFields) + { + err = CHIP_NO_ERROR; + } + else + { + err = CHIP_ERROR_IM_MALFORMED_CLUSTER_PATH_IB; + } + } + + ReturnErrorOnFailure(err); + return reader.ExitContainer(mOuterContainerType); +} +#endif // CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK + +CHIP_ERROR ClusterPathIB::Parser::GetNode(NodeId * const apNode) const +{ + return GetUnsignedInteger(to_underlying(Tag::kNode), apNode); +} + +CHIP_ERROR ClusterPathIB::Parser::GetEndpoint(EndpointId * const apEndpoint) const +{ + return GetUnsignedInteger(to_underlying(Tag::kEndpoint), apEndpoint); +} + +CHIP_ERROR ClusterPathIB::Parser::GetCluster(ClusterId * const apCluster) const +{ + return GetUnsignedInteger(to_underlying(Tag::kCluster), apCluster); +} + +ClusterPathIB::Builder & ClusterPathIB::Builder::Node(const NodeId aNode) +{ + // skip if error has already been set + if (mError == CHIP_NO_ERROR) + { + mError = mpWriter->Put(TLV::ContextTag(to_underlying(Tag::kNode)), aNode); + } + return *this; +} + +ClusterPathIB::Builder & ClusterPathIB::Builder::Endpoint(const EndpointId aEndpoint) +{ + // skip if error has already been set + if (mError == CHIP_NO_ERROR) + { + mError = mpWriter->Put(TLV::ContextTag(to_underlying(Tag::kEndpoint)), aEndpoint); + } + return *this; +} + +ClusterPathIB::Builder & ClusterPathIB::Builder::Cluster(const ClusterId aCluster) +{ + // skip if error has already been set + if (mError == CHIP_NO_ERROR) + { + mError = mpWriter->Put(TLV::ContextTag(to_underlying(Tag::kCluster)), aCluster); + } + return *this; +} + +ClusterPathIB::Builder & ClusterPathIB::Builder::EndOfClusterPathIB() +{ + EndOfContainer(); + return *this; +} +} // namespace app +} // namespace chip diff --git a/src/app/MessageDef/ClusterPathIB.h b/src/app/MessageDef/ClusterPathIB.h new file mode 100644 index 00000000000000..87cf4d2fa892a5 --- /dev/null +++ b/src/app/MessageDef/ClusterPathIB.h @@ -0,0 +1,133 @@ +/** + * + * Copyright (c) 2021 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "ListBuilder.h" +#include "ListParser.h" + +#include +#include +#include +#include +#include +#include + +namespace chip { +namespace app { +namespace ClusterPathIB { +enum class Tag : uint8_t +{ + kNode = 0, + kEndpoint = 1, + kCluster = 2, +}; + +class Parser : public ListParser +{ +public: +#if CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK + /** + * @brief Roughly verify the message is correctly formed + * 1) all mandatory tags are present + * 2) all elements have expected data type + * 3) any tag can only appear once + * 4) At the top level of the structure, unknown tags are ignored for forward compatibility + * @note The main use of this function is to print out what we're + * receiving during protocol development and debugging. + * The encoding rule has changed in IM encoding spec so this + * check is only "roughly" conformant now. + * + * @return #CHIP_NO_ERROR on success + */ + CHIP_ERROR CheckSchemaValidity() const; +#endif + + /** + * @brief Get the NodeId + * + * @param [in] apNodeId A pointer to apNodeId + * + * @return #CHIP_NO_ERROR on success + * #CHIP_ERROR_WRONG_TLV_TYPE if there is such element but it's not any of the defined unsigned integer types + * #CHIP_END_OF_TLV if there is no such element + */ + CHIP_ERROR GetNode(NodeId * const apNodeId) const; + + /** + * @brief Get the Endpoint. + * + * @param [in] apEndpoint A pointer to apEndpoint + * + * @return #CHIP_NO_ERROR on success + * #CHIP_ERROR_WRONG_TLV_TYPE if there is such element but it's not any of the defined unsigned integer types + * #CHIP_END_OF_TLV if there is no such element + */ + CHIP_ERROR GetEndpoint(EndpointId * const apEndpoint) const; + + /** + * @brief Get the Cluster. + * + * @param [in] apCluster A pointer to apCluster + * + * @return #CHIP_NO_ERROR on success + * #CHIP_ERROR_WRONG_TLV_TYPE if there is such element but it's not any of the defined unsigned integer types + * #CHIP_END_OF_TLV if there is no such element + */ + CHIP_ERROR GetCluster(ClusterId * const apCluster) const; +}; + +class Builder : public ListBuilder +{ +public: + /** + * @brief Inject Node into the TLV stream. + * + * @param [in] aNode Node for this cluster path + * + * @return A reference to *this + */ + ClusterPathIB::Builder & Node(const NodeId aNode); + + /** + * @brief Inject Endpoint into the TLV stream. + * + * @param [in] aEndpoint Endpoint for this cluster path + * + * @return A reference to *this + */ + ClusterPathIB::Builder & Endpoint(const EndpointId aEndpoint); + + /** + * @brief Inject Cluster into the TLV stream. + * + * @param [in] aCluster Cluster for this cluster path + * + * @return A reference to *this + */ + ClusterPathIB::Builder & Cluster(const ClusterId aCluster); + + /** + * @brief Mark the end of this ClusterPathIB + * + * @return A reference to *this + */ + ClusterPathIB::Builder & EndOfClusterPathIB(); +}; +} // namespace ClusterPathIB +} // namespace app +} // namespace chip diff --git a/src/app/MessageDef/DataVersionFilterIB.cpp b/src/app/MessageDef/DataVersionFilterIB.cpp new file mode 100644 index 00000000000000..f7826c7d52f73c --- /dev/null +++ b/src/app/MessageDef/DataVersionFilterIB.cpp @@ -0,0 +1,142 @@ +/** + * + * Copyright (c) 2021 Project CHIP Authors + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file + * This file defines DataVersionFilter parser and builder in CHIP interaction model + * + */ + +#include "DataVersionFilterIB.h" + +#include "MessageDefHelper.h" + +#include +#include +#include + +#include + +namespace chip { +namespace app { +#if CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK +CHIP_ERROR DataVersionFilterIB::Parser::CheckSchemaValidity() const +{ + CHIP_ERROR err = CHIP_NO_ERROR; + int tagPresenceMask = 0; + TLV::TLVReader reader; + + PRETTY_PRINT("DataVersionFilterIB ="); + PRETTY_PRINT("{"); + + // make a copy of the Path reader + reader.Init(mReader); + + while (CHIP_NO_ERROR == (err = reader.Next())) + { + VerifyOrReturnError(TLV::IsContextTag(reader.GetTag()), CHIP_ERROR_INVALID_TLV_TAG); + uint32_t tagNum = TLV::TagNumFromTag(reader.GetTag()); + switch (tagNum) + { + case to_underlying(Tag::kPath): + // check if this tag has appeared before + VerifyOrReturnError(!(tagPresenceMask & (1 << to_underlying(Tag::kPath))), CHIP_ERROR_INVALID_TLV_TAG); + tagPresenceMask |= (1 << to_underlying(Tag::kPath)); + { + ClusterPathIB::Parser path; + ReturnErrorOnFailure(path.Init(reader)); + + PRETTY_PRINT_INCDEPTH(); + ReturnErrorOnFailure(path.CheckSchemaValidity()); + PRETTY_PRINT_DECDEPTH(); + } + break; + case to_underlying(Tag::kDataVersion): + // check if this tag has appeared before + VerifyOrReturnError(!(tagPresenceMask & (1 << to_underlying(Tag::kDataVersion))), CHIP_ERROR_INVALID_TLV_TAG); + tagPresenceMask |= (1 << to_underlying(Tag::kDataVersion)); + VerifyOrReturnError(TLV::kTLVType_UnsignedInteger == reader.GetType(), CHIP_ERROR_WRONG_TLV_TYPE); + +#if CHIP_DETAIL_LOGGING + { + chip::DataVersion version; + ReturnErrorOnFailure(reader.Get(version)); + PRETTY_PRINT("\tDataVersion = 0x%" PRIx32 ",", version); + } +#endif // CHIP_DETAIL_LOGGING + break; + } + } + PRETTY_PRINT("},"); + PRETTY_PRINT(""); + + // if we have exhausted this container + if (CHIP_END_OF_TLV == err) + { + // check for required fields: + const int RequiredFields = (1 << to_underlying(Tag::kPath)) | (1 << to_underlying(Tag::kDataVersion)); + + if ((tagPresenceMask & RequiredFields) == RequiredFields) + { + err = CHIP_NO_ERROR; + } + else + { + err = CHIP_ERROR_IM_MALFORMED_DATA_VERSION_FILTER_IB; + } + } + ReturnErrorOnFailure(err); + return reader.ExitContainer(mOuterContainerType); +} +#endif // CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK + +CHIP_ERROR DataVersionFilterIB::Parser::GetPath(ClusterPathIB::Parser * const apPath) const +{ + TLV::TLVReader reader; + ReturnErrorOnFailure(mReader.FindElementWithTag(TLV::ContextTag(to_underlying(Tag::kPath)), reader)); + return apPath->Init(reader); +} + +CHIP_ERROR DataVersionFilterIB::Parser::GetDataVersion(chip::DataVersion * const apVersion) const +{ + return GetUnsignedInteger(to_underlying(Tag::kDataVersion), apVersion); +} + +ClusterPathIB::Builder & DataVersionFilterIB::Builder::CreatePath() +{ + if (mError == CHIP_NO_ERROR) + { + mError = mPath.Init(mpWriter, to_underlying(Tag::kPath)); + } + return mPath; +} + +DataVersionFilterIB::Builder & DataVersionFilterIB::Builder::DataVersion(const chip::DataVersion aDataVersion) +{ + // skip if error has already been set + if (mError == CHIP_NO_ERROR) + { + mError = mpWriter->Put(TLV::ContextTag(to_underlying(Tag::kDataVersion)), aDataVersion); + } + return *this; +} + +DataVersionFilterIB::Builder & DataVersionFilterIB::Builder::EndOfDataVersionFilterIB() +{ + EndOfContainer(); + return *this; +} +} // namespace app +} // namespace chip diff --git a/src/app/MessageDef/AttributeDataVersionList.h b/src/app/MessageDef/DataVersionFilterIB.h similarity index 58% rename from src/app/MessageDef/AttributeDataVersionList.h rename to src/app/MessageDef/DataVersionFilterIB.h index a5b807c7aede39..761b21ac8be67c 100644 --- a/src/app/MessageDef/AttributeDataVersionList.h +++ b/src/app/MessageDef/DataVersionFilterIB.h @@ -1,7 +1,6 @@ /** * - * Copyright (c) 2020 Project CHIP Authors - * Copyright (c) 2016-2017 Nest Labs, Inc. + * Copyright (c) 2021 Project CHIP Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,18 +14,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/** - * @file - * This file defines AttributeDataVersionList parser and builder in CHIP interaction model - * - */ #pragma once -#include "ArrayBuilder.h" -#include "ArrayParser.h" -#include "AttributeDataIB.h" - +#include "ClusterPathIB.h" +#include "StructBuilder.h" +#include "StructParser.h" #include #include #include @@ -36,8 +29,14 @@ namespace chip { namespace app { -namespace AttributeDataVersionList { -class Parser : public ArrayParser +namespace DataVersionFilterIB { +enum class Tag : uint8_t +{ + kPath = 0, + kDataVersion = 1, +}; + +class Parser : public StructParser { public: #if CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK @@ -58,21 +57,18 @@ class Parser : public ArrayParser #endif /** - * @brief Check if this element is valid + * @brief Get a TLVReader for the AttributePathIB. Next() must be called before accessing them. * - * @return A Boolean - */ - bool IsElementValid(void); - - /** - * @brief Check if this element is NULL + * @param [in] apClusterPath A pointer to apClusterPath * - * @return A Boolean + * @return #CHIP_NO_ERROR on success + * #CHIP_ERROR_WRONG_TLV_TYPE if there is such element but it's not a Path + * #CHIP_END_OF_TLV if there is no such element */ - bool IsNull(void); + CHIP_ERROR GetPath(ClusterPathIB::Parser * const apPath) const; /** - * @brief Get a value for the DataVersion. Next() must be called before accessing them. + * @brief Get the DataVersion. * * @param [in] apVersion A pointer to apVersion * @@ -80,35 +76,39 @@ class Parser : public ArrayParser * #CHIP_ERROR_WRONG_TLV_TYPE if there is such element but it's not any of the defined unsigned integer types * #CHIP_END_OF_TLV if there is no such element */ - CHIP_ERROR GetVersion(chip::DataVersion * const apVersion); + CHIP_ERROR GetDataVersion(chip::DataVersion * const apVersion) const; }; -class Builder : public ArrayBuilder +class Builder : public StructBuilder { public: /** - * @brief Add version in AttributeDataVersionList + * @brief Initialize a ClusterPathIB::Builder for writing into the TLV stream * - * @return A reference to AttributeDataVersionList::Builder + * @return A reference to ClusterPathIB::Builder */ - AttributeDataVersionList::Builder & AddVersion(const uint64_t aVersion); + ClusterPathIB::Builder & CreatePath(); /** - * @brief Add Null in version list + * @brief Inject DataVersion into the TLV stream to indicate the numerical data version associated with + * the cluster that is referenced by the path. + * + * @param [in] aDataVersion The unsigned integer variable * * @return A reference to *this */ - AttributeDataVersionList::Builder & AddNull(void); + DataVersionFilterIB::Builder & DataVersion(const chip::DataVersion aDataVersion); + /** - * @brief Mark the end of this AttributeDataVersionList + * @brief Mark the end of this DataVersionFilterIB * * @return A reference to *this */ - AttributeDataVersionList::Builder & EndOfAttributeDataVersionList(); + DataVersionFilterIB::Builder & EndOfDataVersionFilterIB(); private: - AttributeDataIB::Builder mAttributeDataIBBuilder; + ClusterPathIB::Builder mPath; }; -}; // namespace AttributeDataVersionList +}; // namespace DataVersionFilterIB }; // namespace app }; // namespace chip diff --git a/src/app/MessageDef/DataVersionFilterIBs.cpp b/src/app/MessageDef/DataVersionFilterIBs.cpp new file mode 100644 index 00000000000000..dcce8afe403cf4 --- /dev/null +++ b/src/app/MessageDef/DataVersionFilterIBs.cpp @@ -0,0 +1,85 @@ +/** + * + * Copyright (c) 2021 Project CHIP Authors + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "DataVersionFilterIBs.h" + +#include "MessageDefHelper.h" + +#include +#include +#include + +#include + +namespace chip { +namespace app { +#if CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK +CHIP_ERROR DataVersionFilterIBs::Parser::CheckSchemaValidity() const +{ + CHIP_ERROR err = CHIP_NO_ERROR; + size_t numDataVersionFilters = 0; + TLV::TLVReader reader; + + PRETTY_PRINT("DataVersionFilterIBs ="); + PRETTY_PRINT("["); + + // make a copy of the reader + reader.Init(mReader); + + while (CHIP_NO_ERROR == (err = reader.Next())) + { + VerifyOrReturnError(TLV::AnonymousTag == reader.GetTag(), CHIP_ERROR_INVALID_TLV_TAG); + { + DataVersionFilterIB::Parser DataVersionFilter; + ReturnErrorOnFailure(DataVersionFilter.Init(reader)); + PRETTY_PRINT_INCDEPTH(); + ReturnErrorOnFailure(DataVersionFilter.CheckSchemaValidity()); + PRETTY_PRINT_DECDEPTH(); + } + + ++numDataVersionFilters; + } + + PRETTY_PRINT("],"); + PRETTY_PRINT(""); + + // if we have exhausted this container + if (CHIP_END_OF_TLV == err) + { + // if we have at least one event filter + if (numDataVersionFilters > 0) + { + err = CHIP_NO_ERROR; + } + } + ReturnErrorOnFailure(err); + return reader.ExitContainer(mOuterContainerType); +} +#endif // CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK + +DataVersionFilterIB::Builder & DataVersionFilterIBs::Builder::CreateDataVersionFilter() +{ + mError = mDataVersionFilter.Init(mpWriter); + return mDataVersionFilter; +} + +DataVersionFilterIBs::Builder & DataVersionFilterIBs::Builder::EndOfDataVersionFilterIBs() +{ + EndOfContainer(); + return *this; +} +} // namespace app +} // namespace chip diff --git a/src/app/MessageDef/DataVersionFilterIBs.h b/src/app/MessageDef/DataVersionFilterIBs.h new file mode 100644 index 00000000000000..8c7ae021f6899f --- /dev/null +++ b/src/app/MessageDef/DataVersionFilterIBs.h @@ -0,0 +1,82 @@ +/** + * + * Copyright (c) 2021 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include + +#include "ArrayBuilder.h" +#include "ArrayParser.h" +#include "DataVersionFilterIB.h" + +namespace chip { +namespace app { +namespace DataVersionFilterIBs { +class Parser : public ArrayParser +{ +public: +#if CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK + /** + * @brief Roughly verify the message is correctly formed + * 1) all mandatory tags are present + * 2) all elements have expected data type + * 3) any tag can only appear once + * 4) At the top level of the structure, unknown tags are ignored for forward compatibility + * @note The main use of this function is to print out what we're + * receiving during protocol development and debugging. + * The encoding rule has changed in IM encoding spec so this + * check is only "roughly" conformant now. + * + * @return #CHIP_NO_ERROR on success + */ + CHIP_ERROR CheckSchemaValidity() const; +#endif +}; + +class Builder : public ArrayBuilder +{ +public: + /** + * @brief Initialize a DataVersionFilterIB::Builder for writing into the TLV stream + * + * @return A reference to DataVersionFilterIB::Builder + */ + DataVersionFilterIB::Builder & CreateDataVersionFilter(); + + /** + * @return A reference to DataVersionFilterIB::Builder + */ + DataVersionFilterIB::Builder & GetDataVersionFilter() { return mDataVersionFilter; }; + + /** + * @brief Mark the end of this DataVersionFilterIBs + * + * @return A reference to *this + */ + DataVersionFilterIBs::Builder & EndOfDataVersionFilterIBs(); + +private: + DataVersionFilterIB::Builder mDataVersionFilter; +}; +} // namespace DataVersionFilterIBs +} // namespace app +} // namespace chip diff --git a/src/app/MessageDef/ReadRequestMessage.cpp b/src/app/MessageDef/ReadRequestMessage.cpp index 626a6e33b335b2..0c80dcb3572a4c 100644 --- a/src/app/MessageDef/ReadRequestMessage.cpp +++ b/src/app/MessageDef/ReadRequestMessage.cpp @@ -57,6 +57,19 @@ CHIP_ERROR ReadRequestMessage::Parser::CheckSchemaValidity() const PRETTY_PRINT_DECDEPTH(); } break; + case to_underlying(Tag::kDataVersionFilters): + // check if this tag has appeared before + VerifyOrReturnError(!(TagPresenceMask & (1 << to_underlying(Tag::kEventFilters))), CHIP_ERROR_INVALID_TLV_TAG); + TagPresenceMask |= (1 << to_underlying(Tag::kDataVersionFilters)); + { + DataVersionFilterIBs::Parser dataVersionFilters; + ReturnErrorOnFailure(dataVersionFilters.Init(reader)); + + PRETTY_PRINT_INCDEPTH(); + ReturnErrorOnFailure(dataVersionFilters.CheckSchemaValidity()); + PRETTY_PRINT_DECDEPTH(); + } + break; case to_underlying(Tag::kEventRequests): // check if this tag has appeared before VerifyOrReturnError(!(TagPresenceMask & (1 << to_underlying(Tag::kEventRequests))), CHIP_ERROR_INVALID_TLV_TAG); @@ -130,6 +143,13 @@ CHIP_ERROR ReadRequestMessage::Parser::GetAttributeRequests(AttributePathIBs::Pa return apAttributeRequests->Init(reader); } +CHIP_ERROR ReadRequestMessage::Parser::GetDataVersionFilters(DataVersionFilterIBs::Parser * const apDataVersionFilters) const +{ + TLV::TLVReader reader; + ReturnErrorOnFailure(mReader.FindElementWithTag(TLV::ContextTag(to_underlying(Tag::kDataVersionFilters)), reader)); + return apDataVersionFilters->Init(reader); +} + CHIP_ERROR ReadRequestMessage::Parser::GetEventRequests(EventPathIBs::Parser * const apEventRequests) const { TLV::TLVReader reader; @@ -159,6 +179,16 @@ AttributePathIBs::Builder & ReadRequestMessage::Builder::CreateAttributeRequests return mAttributeRequests; } +DataVersionFilterIBs::Builder & ReadRequestMessage::Builder::CreateDataVersionFilters() +{ + // skip if error has already been set + if (mError == CHIP_NO_ERROR) + { + mError = mDataVersionFilters.Init(mpWriter, to_underlying(Tag::kDataVersionFilters)); + } + return mDataVersionFilters; +} + EventPathIBs::Builder & ReadRequestMessage::Builder::CreateEventRequests() { // skip if error has already been set diff --git a/src/app/MessageDef/ReadRequestMessage.h b/src/app/MessageDef/ReadRequestMessage.h index 8e5e3a06524b85..1db10868db8d67 100644 --- a/src/app/MessageDef/ReadRequestMessage.h +++ b/src/app/MessageDef/ReadRequestMessage.h @@ -1,7 +1,6 @@ /** * - * Copyright (c) 2020 Project CHIP Authors - * Copyright (c) 2016-2017 Nest Labs, Inc. + * Copyright (c) 2020-2021 Project CHIP Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,6 +18,7 @@ #pragma once #include "AttributePathIBs.h" +#include "DataVersionFilterIBs.h" #include "EventFilterIBs.h" #include "EventPathIBs.h" @@ -35,8 +35,8 @@ namespace ReadRequestMessage { enum class Tag : uint8_t { kAttributeRequests = 0, - kEventRequests = 1, - kDataVersionFilters = 2, + kDataVersionFilters = 1, + kEventRequests = 2, kEventFilters = 3, kIsFabricFiltered = 4, }; @@ -71,6 +71,14 @@ class Parser : public StructParser */ CHIP_ERROR GetAttributeRequests(AttributePathIBs::Parser * const apAttributeRequests) const; + /** + * @brief Get a TLVReader for the DataVersionFilterIBs. Next() must be called before accessing them. + * + * @return #CHIP_NO_ERROR on success + * #CHIP_END_OF_TLV if there is no such element + */ + CHIP_ERROR GetDataVersionFilters(DataVersionFilterIBs::Parser * const apDataVersionFilters) const; + /** * @brief Get a TLVReader for the EventRequests. Next() must be called before accessing them. * @@ -110,6 +118,13 @@ class Builder : public StructBuilder */ AttributePathIBs::Builder & CreateAttributeRequests(); + /** + * @brief Initialize a DataVersionFilterIBs::Builder for writing into the TLV stream + * + * @return A reference to DataVersionFilterIBs::Builder + */ + DataVersionFilterIBs::Builder & CreateDataVersionFilters(); + /** * @brief Initialize a EventPathIBs::Builder for writing into the TLV stream * @@ -139,6 +154,7 @@ class Builder : public StructBuilder private: AttributePathIBs::Builder mAttributeRequests; + DataVersionFilterIBs::Builder mDataVersionFilters; EventPathIBs::Builder mEventRequests; EventFilterIBs::Builder mEventFilters; }; diff --git a/src/app/MessageDef/SubscribeRequestMessage.cpp b/src/app/MessageDef/SubscribeRequestMessage.cpp index e01892f8b30db4..4b73a34bae571c 100644 --- a/src/app/MessageDef/SubscribeRequestMessage.cpp +++ b/src/app/MessageDef/SubscribeRequestMessage.cpp @@ -23,7 +23,7 @@ namespace app { CHIP_ERROR SubscribeRequestMessage::Parser::CheckSchemaValidity() const { CHIP_ERROR err = CHIP_NO_ERROR; - int TagPresenceMask = 0; + int tagPresenceMask = 0; TLV::TLVReader reader; PRETTY_PRINT("SubscribeRequestMessage ="); @@ -39,8 +39,8 @@ CHIP_ERROR SubscribeRequestMessage::Parser::CheckSchemaValidity() const switch (tagNum) { case to_underlying(Tag::kKeepSubscriptions): - VerifyOrReturnError(!(TagPresenceMask & (1 << to_underlying(Tag::kKeepSubscriptions))), CHIP_ERROR_INVALID_TLV_TAG); - TagPresenceMask |= (1 << to_underlying(Tag::kKeepSubscriptions)); + VerifyOrReturnError(!(tagPresenceMask & (1 << to_underlying(Tag::kKeepSubscriptions))), CHIP_ERROR_INVALID_TLV_TAG); + tagPresenceMask |= (1 << to_underlying(Tag::kKeepSubscriptions)); VerifyOrReturnError(TLV::kTLVType_Boolean == reader.GetType(), CHIP_ERROR_WRONG_TLV_TYPE); #if CHIP_DETAIL_LOGGING { @@ -51,9 +51,9 @@ CHIP_ERROR SubscribeRequestMessage::Parser::CheckSchemaValidity() const #endif // CHIP_DETAIL_LOGGING break; case to_underlying(Tag::kMinIntervalFloorSeconds): - VerifyOrReturnError(!(TagPresenceMask & (1 << to_underlying(Tag::kMinIntervalFloorSeconds))), + VerifyOrReturnError(!(tagPresenceMask & (1 << to_underlying(Tag::kMinIntervalFloorSeconds))), CHIP_ERROR_INVALID_TLV_TAG); - TagPresenceMask |= (1 << to_underlying(Tag::kMinIntervalFloorSeconds)); + tagPresenceMask |= (1 << to_underlying(Tag::kMinIntervalFloorSeconds)); VerifyOrReturnError(TLV::kTLVType_UnsignedInteger == reader.GetType(), CHIP_ERROR_WRONG_TLV_TYPE); #if CHIP_DETAIL_LOGGING { @@ -64,9 +64,9 @@ CHIP_ERROR SubscribeRequestMessage::Parser::CheckSchemaValidity() const #endif // CHIP_DETAIL_LOGGING break; case to_underlying(Tag::kMaxIntervalCeilingSeconds): - VerifyOrReturnError(!(TagPresenceMask & (1 << to_underlying(Tag::kMaxIntervalCeilingSeconds))), + VerifyOrReturnError(!(tagPresenceMask & (1 << to_underlying(Tag::kMaxIntervalCeilingSeconds))), CHIP_ERROR_INVALID_TLV_TAG); - TagPresenceMask |= (1 << to_underlying(Tag::kMaxIntervalCeilingSeconds)); + tagPresenceMask |= (1 << to_underlying(Tag::kMaxIntervalCeilingSeconds)); VerifyOrReturnError(TLV::kTLVType_UnsignedInteger == reader.GetType(), CHIP_ERROR_WRONG_TLV_TYPE); #if CHIP_DETAIL_LOGGING { @@ -78,8 +78,8 @@ CHIP_ERROR SubscribeRequestMessage::Parser::CheckSchemaValidity() const break; case to_underlying(Tag::kAttributeRequests): // check if this tag has appeared before - VerifyOrReturnError(!(TagPresenceMask & (1 << to_underlying(Tag::kAttributeRequests))), CHIP_ERROR_INVALID_TLV_TAG); - TagPresenceMask |= (1 << to_underlying(Tag::kAttributeRequests)); + VerifyOrReturnError(!(tagPresenceMask & (1 << to_underlying(Tag::kAttributeRequests))), CHIP_ERROR_INVALID_TLV_TAG); + tagPresenceMask |= (1 << to_underlying(Tag::kAttributeRequests)); { AttributePathIBs::Parser attributeRequests; ReturnErrorOnFailure(attributeRequests.Init(reader)); @@ -89,10 +89,23 @@ CHIP_ERROR SubscribeRequestMessage::Parser::CheckSchemaValidity() const PRETTY_PRINT_DECDEPTH(); } break; + case to_underlying(Tag::kDataVersionFilters): + // check if this tag has appeared before + VerifyOrReturnError(!(tagPresenceMask & (1 << to_underlying(Tag::kEventFilters))), CHIP_ERROR_INVALID_TLV_TAG); + tagPresenceMask |= (1 << to_underlying(Tag::kDataVersionFilters)); + { + DataVersionFilterIBs::Parser dataVersionFilters; + ReturnErrorOnFailure(dataVersionFilters.Init(reader)); + + PRETTY_PRINT_INCDEPTH(); + ReturnErrorOnFailure(dataVersionFilters.CheckSchemaValidity()); + PRETTY_PRINT_DECDEPTH(); + } + break; case to_underlying(Tag::kEventRequests): // check if this tag has appeared before - VerifyOrReturnError(!(TagPresenceMask & (1 << to_underlying(Tag::kEventRequests))), CHIP_ERROR_INVALID_TLV_TAG); - TagPresenceMask |= (1 << to_underlying(Tag::kEventRequests)); + VerifyOrReturnError(!(tagPresenceMask & (1 << to_underlying(Tag::kEventRequests))), CHIP_ERROR_INVALID_TLV_TAG); + tagPresenceMask |= (1 << to_underlying(Tag::kEventRequests)); { EventPathIBs::Parser eventRequests; ReturnErrorOnFailure(eventRequests.Init(reader)); @@ -104,8 +117,8 @@ CHIP_ERROR SubscribeRequestMessage::Parser::CheckSchemaValidity() const break; case to_underlying(Tag::kEventFilters): // check if this tag has appeared before - VerifyOrReturnError(!(TagPresenceMask & (1 << to_underlying(Tag::kEventFilters))), CHIP_ERROR_INVALID_TLV_TAG); - TagPresenceMask |= (1 << to_underlying(Tag::kEventFilters)); + VerifyOrReturnError(!(tagPresenceMask & (1 << to_underlying(Tag::kEventFilters))), CHIP_ERROR_INVALID_TLV_TAG); + tagPresenceMask |= (1 << to_underlying(Tag::kEventFilters)); { EventFilterIBs::Parser eventFilters; ReturnErrorOnFailure(eventFilters.Init(reader)); @@ -116,8 +129,8 @@ CHIP_ERROR SubscribeRequestMessage::Parser::CheckSchemaValidity() const } break; case to_underlying(Tag::kIsProxy): - VerifyOrReturnError(!(TagPresenceMask & (1 << to_underlying(Tag::kIsProxy))), CHIP_ERROR_INVALID_TLV_TAG); - TagPresenceMask |= (1 << to_underlying(Tag::kIsProxy)); + VerifyOrReturnError(!(tagPresenceMask & (1 << to_underlying(Tag::kIsProxy))), CHIP_ERROR_INVALID_TLV_TAG); + tagPresenceMask |= (1 << to_underlying(Tag::kIsProxy)); VerifyOrReturnError(TLV::kTLVType_Boolean == reader.GetType(), CHIP_ERROR_WRONG_TLV_TYPE); #if CHIP_DETAIL_LOGGING { @@ -129,8 +142,8 @@ CHIP_ERROR SubscribeRequestMessage::Parser::CheckSchemaValidity() const break; case to_underlying(Tag::kIsFabricFiltered): // check if this tag has appeared before - VerifyOrReturnError(!(TagPresenceMask & (1 << to_underlying(Tag::kIsFabricFiltered))), CHIP_ERROR_INVALID_TLV_TAG); - TagPresenceMask |= (1 << to_underlying(Tag::kIsFabricFiltered)); + VerifyOrReturnError(!(tagPresenceMask & (1 << to_underlying(Tag::kIsFabricFiltered))), CHIP_ERROR_INVALID_TLV_TAG); + tagPresenceMask |= (1 << to_underlying(Tag::kIsFabricFiltered)); #if CHIP_DETAIL_LOGGING { bool isFabricFiltered; @@ -153,7 +166,7 @@ CHIP_ERROR SubscribeRequestMessage::Parser::CheckSchemaValidity() const const int RequiredFields = (1 << to_underlying(Tag::kIsFabricFiltered)) | (1 << to_underlying(Tag::kMinIntervalFloorSeconds)) | (1 << to_underlying(Tag::kMaxIntervalCeilingSeconds)); - if ((TagPresenceMask & RequiredFields) == RequiredFields) + if ((tagPresenceMask & RequiredFields) == RequiredFields) { err = CHIP_NO_ERROR; } @@ -190,6 +203,13 @@ CHIP_ERROR SubscribeRequestMessage::Parser::GetAttributeRequests(AttributePathIB return apAttributeRequests->Init(reader); } +CHIP_ERROR SubscribeRequestMessage::Parser::GetDataVersionFilters(DataVersionFilterIBs::Parser * const apDataVersionFilters) const +{ + TLV::TLVReader reader; + ReturnErrorOnFailure(mReader.FindElementWithTag(TLV::ContextTag(to_underlying(Tag::kDataVersionFilters)), reader)); + return apDataVersionFilters->Init(reader); +} + CHIP_ERROR SubscribeRequestMessage::Parser::GetEventRequests(EventPathIBs::Parser * const apEventRequests) const { TLV::TLVReader reader; @@ -252,6 +272,16 @@ AttributePathIBs::Builder & SubscribeRequestMessage::Builder::CreateAttributeReq return mAttributeRequests; } +DataVersionFilterIBs::Builder & SubscribeRequestMessage::Builder::CreateDataVersionFilters() +{ + // skip if error has already been set + if (mError == CHIP_NO_ERROR) + { + mError = mDataVersionFilters.Init(mpWriter, to_underlying(Tag::kDataVersionFilters)); + } + return mDataVersionFilters; +} + EventPathIBs::Builder & SubscribeRequestMessage::Builder::CreateEventRequests() { if (mError == CHIP_NO_ERROR) diff --git a/src/app/MessageDef/SubscribeRequestMessage.h b/src/app/MessageDef/SubscribeRequestMessage.h index b86ae5c59f16fb..acb8a4187fcd8a 100644 --- a/src/app/MessageDef/SubscribeRequestMessage.h +++ b/src/app/MessageDef/SubscribeRequestMessage.h @@ -17,8 +17,8 @@ #pragma once -#include "AttributeDataVersionList.h" #include "AttributePathIBs.h" +#include "DataVersionFilterIBs.h" #include "EventFilterIBs.h" #include "EventPathIBs.h" #include "StructBuilder.h" @@ -94,6 +94,14 @@ class Parser : public StructParser */ CHIP_ERROR GetAttributeRequests(AttributePathIBs::Parser * const apAttributeRequests) const; + /** + * @brief Get a TLVReader for the DataVersionFilterIBs. Next() must be called before accessing them. + * + * @return #CHIP_NO_ERROR on success + * #CHIP_END_OF_TLV if there is no such element + */ + CHIP_ERROR GetDataVersionFilters(DataVersionFilterIBs::Parser * const apDataVersionFilters) const; + /** * @brief Get a TLVReader for the EventPathIBs. Next() must be called before accessing them. * @@ -139,6 +147,7 @@ class Builder : public StructBuilder SubscribeRequestMessage::Builder & MinIntervalFloorSeconds(const uint16_t aMinIntervalFloorSeconds); SubscribeRequestMessage::Builder & MaxIntervalCeilingSeconds(const uint16_t aMinIntervalFloorSeconds); AttributePathIBs::Builder & CreateAttributeRequests(); + DataVersionFilterIBs::Builder & CreateDataVersionFilters(); EventPathIBs::Builder & CreateEventRequests(); EventFilterIBs::Builder & CreateEventFilters(); @@ -162,6 +171,7 @@ class Builder : public StructBuilder private: AttributePathIBs::Builder mAttributeRequests; + DataVersionFilterIBs::Builder mDataVersionFilters; EventPathIBs::Builder mEventRequests; EventFilterIBs::Builder mEventFilters; }; diff --git a/src/app/MessageDef/WriteRequestMessage.h b/src/app/MessageDef/WriteRequestMessage.h index 53b4b2d63ad9f9..6af673a8342920 100644 --- a/src/app/MessageDef/WriteRequestMessage.h +++ b/src/app/MessageDef/WriteRequestMessage.h @@ -23,7 +23,6 @@ #pragma once #include "AttributeDataIBs.h" -#include "AttributeDataVersionList.h" #include "StructBuilder.h" #include "StructParser.h" #include diff --git a/src/app/tests/TestMessageDef.cpp b/src/app/tests/TestMessageDef.cpp index cef68604872580..eedc42f664ca56 100644 --- a/src/app/tests/TestMessageDef.cpp +++ b/src/app/tests/TestMessageDef.cpp @@ -100,6 +100,91 @@ void ParseStatusIB(nlTestSuite * apSuite, StatusIB::Parser & aStatusIBParser) !statusIB.mClusterStatus.HasValue()); } +void BuildClusterPathIB(nlTestSuite * apSuite, ClusterPathIB::Builder & aClusterPathBuilder) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + aClusterPathBuilder.Node(1).Endpoint(2).Cluster(3).EndOfClusterPathIB(); + err = aClusterPathBuilder.GetError(); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); +} + +void ParseClusterPathIB(nlTestSuite * apSuite, chip::TLV::TLVReader & aReader) +{ + ClusterPathIB::Parser clusterPathParser; + CHIP_ERROR err = CHIP_NO_ERROR; + chip::NodeId node = 0; + chip::EndpointId endpoint = 0; + chip::ClusterId cluster = 0; + + err = clusterPathParser.Init(aReader); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); +#if CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK + err = clusterPathParser.CheckSchemaValidity(); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); +#endif + + err = clusterPathParser.GetNode(&node); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR && node == 1); + + err = clusterPathParser.GetEndpoint(&endpoint); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR && endpoint == 2); + + err = clusterPathParser.GetCluster(&cluster); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR && cluster == 3); +} + +void BuildDataVersionFilterIB(nlTestSuite * apSuite, DataVersionFilterIB::Builder & aDataVersionFilterIBBuilder) +{ + ClusterPathIB::Builder clusterPathBuilder = aDataVersionFilterIBBuilder.CreatePath(); + NL_TEST_ASSERT(apSuite, clusterPathBuilder.GetError() == CHIP_NO_ERROR); + BuildClusterPathIB(apSuite, clusterPathBuilder); + aDataVersionFilterIBBuilder.DataVersion(2).EndOfDataVersionFilterIB(); + NL_TEST_ASSERT(apSuite, aDataVersionFilterIBBuilder.GetError() == CHIP_NO_ERROR); +} + +void ParseDataVersionFilterIB(nlTestSuite * apSuite, chip::TLV::TLVReader & aReader) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + DataVersionFilterIB::Parser dataVersionFilterIBParser; + ClusterPathIB::Parser clusterPath; + chip::DataVersion dataVersion = 2; + + err = dataVersionFilterIBParser.Init(aReader); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); +#if CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK + err = dataVersionFilterIBParser.CheckSchemaValidity(); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); +#endif + + err = dataVersionFilterIBParser.GetPath(&clusterPath); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); + + err = dataVersionFilterIBParser.GetDataVersion(&dataVersion); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR && dataVersion == 2); +} + +void BuildDataVersionFilterIBs(nlTestSuite * apSuite, DataVersionFilterIBs::Builder & aDataVersionFilterIBsBuilder) +{ + DataVersionFilterIB::Builder & dataVersionFilterIBBuilder = aDataVersionFilterIBsBuilder.CreateDataVersionFilter(); + NL_TEST_ASSERT(apSuite, aDataVersionFilterIBsBuilder.GetError() == CHIP_NO_ERROR); + BuildDataVersionFilterIB(apSuite, dataVersionFilterIBBuilder); + aDataVersionFilterIBsBuilder.EndOfDataVersionFilterIBs(); + NL_TEST_ASSERT(apSuite, aDataVersionFilterIBsBuilder.GetError() == CHIP_NO_ERROR); +} + +void ParseDataVersionFilterIBs(nlTestSuite * apSuite, chip::TLV::TLVReader & aReader) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + DataVersionFilterIBs::Parser dataVersionFilterIBsParser; + + err = dataVersionFilterIBsParser.Init(aReader); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); +#if CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK + err = dataVersionFilterIBsParser.CheckSchemaValidity(); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); +#endif +} + void BuildEventFilterIB(nlTestSuite * apSuite, EventFilterIB::Builder & aEventFilterIBBuilder) { aEventFilterIBBuilder.Node(1).EventMin(2).EndOfEventFilterIB(); @@ -665,30 +750,6 @@ void ParseAttributeReportIBs(nlTestSuite * apSuite, chip::TLV::TLVReader & aRead #endif } -void BuildAttributeDataVersionList(nlTestSuite * apSuite, AttributeDataVersionList::Builder & aAttributeDataVersionListBuilder) -{ - aAttributeDataVersionListBuilder.AddVersion(1); - - aAttributeDataVersionListBuilder.EndOfAttributeDataVersionList(); - NL_TEST_ASSERT(apSuite, aAttributeDataVersionListBuilder.GetError() == CHIP_NO_ERROR); -} - -void ParseAttributeDataVersionList(nlTestSuite * apSuite, chip::TLV::TLVReader & aReader) -{ - CHIP_ERROR err = CHIP_NO_ERROR; - chip::DataVersion version; - AttributeDataVersionList::Parser attributeDataVersionListParser; - - err = attributeDataVersionListParser.Init(aReader); - NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); - -#if CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK - err = attributeDataVersionListParser.CheckSchemaValidity(); - NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); -#endif - attributeDataVersionListParser.GetVersion(&version); -} - void BuildCommandDataIB(nlTestSuite * apSuite, CommandDataIB::Builder & aCommandDataIBBuilder) { CHIP_ERROR err = CHIP_NO_ERROR; @@ -1026,7 +1087,12 @@ void BuildReadRequestMessage(nlTestSuite * apSuite, chip::TLV::TLVWriter & aWrit NL_TEST_ASSERT(apSuite, readRequestBuilder.GetError() == CHIP_NO_ERROR); BuildAttributePathList(apSuite, attributePathIBs); + DataVersionFilterIBs::Builder & dataVersionFilters = readRequestBuilder.CreateDataVersionFilters(); + NL_TEST_ASSERT(apSuite, readRequestBuilder.GetError() == CHIP_NO_ERROR); + BuildDataVersionFilterIBs(apSuite, dataVersionFilters); + EventPathIBs::Builder & eventPathList = readRequestBuilder.CreateEventRequests(); + NL_TEST_ASSERT(apSuite, readRequestBuilder.GetError() == CHIP_NO_ERROR); BuildEventPaths(apSuite, eventPathList); @@ -1047,6 +1113,7 @@ void ParseReadRequestMessage(nlTestSuite * apSuite, chip::TLV::TLVReader & aRead ReadRequestMessage::Parser readRequestParser; AttributePathIBs::Parser attributePathListParser; + DataVersionFilterIBs::Parser dataVersionFilterIBsParser; EventPathIBs::Parser eventPathListParser; EventFilterIBs::Parser eventFiltersParser; bool isFabricFiltered = false; @@ -1060,6 +1127,9 @@ void ParseReadRequestMessage(nlTestSuite * apSuite, chip::TLV::TLVReader & aRead err = readRequestParser.GetAttributeRequests(&attributePathListParser); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); + err = readRequestParser.GetDataVersionFilters(&dataVersionFilterIBsParser); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); + err = readRequestParser.GetEventRequests(&eventPathListParser); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); @@ -1184,7 +1254,12 @@ void BuildSubscribeRequestMessage(nlTestSuite * apSuite, chip::TLV::TLVWriter & NL_TEST_ASSERT(apSuite, subscribeRequestBuilder.GetError() == CHIP_NO_ERROR); BuildAttributePathList(apSuite, attributePathIBs); + DataVersionFilterIBs::Builder & dataVersionFilters = subscribeRequestBuilder.CreateDataVersionFilters(); + NL_TEST_ASSERT(apSuite, subscribeRequestBuilder.GetError() == CHIP_NO_ERROR); + BuildDataVersionFilterIBs(apSuite, dataVersionFilters); + EventPathIBs::Builder & eventPathList = subscribeRequestBuilder.CreateEventRequests(); + NL_TEST_ASSERT(apSuite, subscribeRequestBuilder.GetError() == CHIP_NO_ERROR); BuildEventPaths(apSuite, eventPathList); @@ -1208,6 +1283,7 @@ void ParseSubscribeRequestMessage(nlTestSuite * apSuite, chip::TLV::TLVReader & SubscribeRequestMessage::Parser subscribeRequestParser; AttributePathIBs::Parser attributePathListParser; + DataVersionFilterIBs::Parser dataVersionFilterIBsParser; EventPathIBs::Parser eventPathListParser; EventFilterIBs::Parser eventFiltersParser; uint16_t MinIntervalFloorSeconds = 0; @@ -1225,6 +1301,9 @@ void ParseSubscribeRequestMessage(nlTestSuite * apSuite, chip::TLV::TLVReader & err = subscribeRequestParser.GetAttributeRequests(&attributePathListParser); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); + err = subscribeRequestParser.GetDataVersionFilters(&dataVersionFilterIBsParser); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); + err = subscribeRequestParser.GetEventRequests(&eventPathListParser); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); @@ -1321,6 +1400,51 @@ void ParseTimedRequestMessage(nlTestSuite * apSuite, chip::TLV::TLVReader & aRea NL_TEST_ASSERT(apSuite, timeout == 1 && err == CHIP_NO_ERROR); } +void DataVersionFilterIBTest(nlTestSuite * apSuite, void * apContext) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + DataVersionFilterIB::Builder dataVersionFilterIBBuilder; + chip::System::PacketBufferTLVWriter writer; + chip::System::PacketBufferTLVReader reader; + writer.Init(chip::System::PacketBufferHandle::New(chip::System::PacketBuffer::kMaxSize)); + dataVersionFilterIBBuilder.Init(&writer); + BuildDataVersionFilterIB(apSuite, dataVersionFilterIBBuilder); + chip::System::PacketBufferHandle buf; + err = writer.Finalize(&buf); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); + + DebugPrettyPrint(buf); + + reader.Init(std::move(buf)); + err = reader.Next(); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); + ParseDataVersionFilterIB(apSuite, reader); +} + +void DataVersionFilterIBsTest(nlTestSuite * apSuite, void * apContext) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + chip::System::PacketBufferTLVWriter writer; + chip::System::PacketBufferTLVReader reader; + DataVersionFilterIBs::Builder dataVersionFilterIBsBuilder; + writer.Init(chip::System::PacketBufferHandle::New(chip::System::PacketBuffer::kMaxSize)); + + err = dataVersionFilterIBsBuilder.Init(&writer); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); + + BuildDataVersionFilterIBs(apSuite, dataVersionFilterIBsBuilder); + chip::System::PacketBufferHandle buf; + err = writer.Finalize(&buf); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); + + DebugPrettyPrint(buf); + + reader.Init(std::move(buf)); + err = reader.Next(); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); + ParseDataVersionFilterIBs(apSuite, reader); +} + void EventFilterTest(nlTestSuite * apSuite, void * apContext) { CHIP_ERROR err = CHIP_NO_ERROR; @@ -1367,6 +1491,28 @@ void EventFiltersTest(nlTestSuite * apSuite, void * apContext) ParseEventFilters(apSuite, reader); } +void ClusterPathIBTest(nlTestSuite * apSuite, void * apContext) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + ClusterPathIB::Builder clusterPathBuilder; + chip::System::PacketBufferTLVWriter writer; + chip::System::PacketBufferTLVReader reader; + writer.Init(chip::System::PacketBufferHandle::New(chip::System::PacketBuffer::kMaxSize)); + clusterPathBuilder.Init(&writer); + BuildClusterPathIB(apSuite, clusterPathBuilder); + chip::System::PacketBufferHandle buf; + err = writer.Finalize(&buf); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); + + DebugPrettyPrint(buf); + + reader.Init(std::move(buf)); + err = reader.Next(); + NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); + + ParseClusterPathIB(apSuite, reader); +} + void AttributePathTest(nlTestSuite * apSuite, void * apContext) { CHIP_ERROR err = CHIP_NO_ERROR; @@ -1741,27 +1887,6 @@ void AttributeDataIBsTest(nlTestSuite * apSuite, void * apContext) ParseAttributeDataIBs(apSuite, reader); } -void AttributeDataVersionListTest(nlTestSuite * apSuite, void * apContext) -{ - CHIP_ERROR err = CHIP_NO_ERROR; - chip::System::PacketBufferTLVWriter writer; - chip::System::PacketBufferTLVReader reader; - writer.Init(chip::System::PacketBufferHandle::New(chip::System::PacketBuffer::kMaxSize)); - AttributeDataVersionList::Builder attributeDataVersionListBuilder; - attributeDataVersionListBuilder.Init(&writer); - BuildAttributeDataVersionList(apSuite, attributeDataVersionListBuilder); - chip::System::PacketBufferHandle buf; - err = writer.Finalize(&buf); - NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); - - DebugPrettyPrint(buf); - - reader.Init(std::move(buf)); - err = reader.Next(); - NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); - ParseAttributeDataVersionList(apSuite, reader); -} - void CommandDataIBTest(nlTestSuite * apSuite, void * apContext) { CHIP_ERROR err = CHIP_NO_ERROR; @@ -2155,6 +2280,9 @@ void CheckPointRollbackTest(nlTestSuite * apSuite, void * apContext) // clang-format off const nlTest sTests[] = { + NL_TEST_DEF("ClusterPathIBTest", ClusterPathIBTest), + NL_TEST_DEF("DataVersionFilterIBTest", DataVersionFilterIBTest), + NL_TEST_DEF("DataVersionFilterIBsTest", DataVersionFilterIBsTest), NL_TEST_DEF("EventFilterTest", EventFilterTest), NL_TEST_DEF("EventFiltersTest", EventFiltersTest), NL_TEST_DEF("AttributePathTest", AttributePathTest), @@ -2172,7 +2300,6 @@ const nlTest sTests[] = NL_TEST_DEF("EventReportsTest", EventReportsTest), NL_TEST_DEF("StatusIBTest", StatusIBTest), NL_TEST_DEF("EventStatusIBTest", EventStatusIBTest), - NL_TEST_DEF("AttributeDataVersionListTest", AttributeDataVersionListTest), NL_TEST_DEF("CommandPathIBTest", CommandPathIBTest), NL_TEST_DEF("CommandDataIBTest", CommandDataIBTest), NL_TEST_DEF("CommandStatusIBTest", CommandStatusIBTest), diff --git a/src/lib/core/CHIPError.cpp b/src/lib/core/CHIPError.cpp index fbb0b04dc5e426..cfe76b2492d568 100644 --- a/src/lib/core/CHIPError.cpp +++ b/src/lib/core/CHIPError.cpp @@ -686,6 +686,12 @@ bool FormatCHIPError(char * buf, uint16_t bufSize, CHIP_ERROR err) case CHIP_ERROR_IM_MALFORMED_EVENT_REPORT_IB.AsInteger(): desc = "Malformed Interaction Model Event Report IB"; break; + case CHIP_ERROR_IM_MALFORMED_CLUSTER_PATH_IB.AsInteger(): + desc = "Malformed Interaction Model Cluster Path IB"; + break; + case CHIP_ERROR_IM_MALFORMED_DATA_VERSION_FILTER_IB.AsInteger(): + desc = "Malformed Interaction Model Data Version Filter IB"; + break; } #endif // !CHIP_CONFIG_SHORT_ERROR_STR diff --git a/src/lib/core/CHIPError.h b/src/lib/core/CHIPError.h index d26b5a10170847..656d8a505ebad8 100644 --- a/src/lib/core/CHIPError.h +++ b/src/lib/core/CHIPError.h @@ -2315,6 +2315,23 @@ using CHIP_ERROR = ::chip::ChipError; */ #define CHIP_ERROR_ANOTHER_COMMISSIONING_IN_PROGRESS CHIP_CORE_ERROR(0xd6) +/** + * @def CHIP_ERROR_IM_MALFORMED_CLUSTER_PATH_IB + * + * @brief + * The ClusterPathIB is malformed: it either does not contain + * the required elements + */ +#define CHIP_ERROR_IM_MALFORMED_CLUSTER_PATH_IB CHIP_CORE_ERROR(0xd6) + +/** + * @def CHIP_ERROR_IM_MALFORMED_DATA_VERSION_FILTER_IB + * + * @brief + * The DataVersionFilterIB is malformed: it either does not contain + * the required elements + */ +#define CHIP_ERROR_IM_MALFORMED_DATA_VERSION_FILTER_IB CHIP_CORE_ERROR(0xd7) /** * @} */