diff --git a/examples/network-manager-app/linux/main.cpp b/examples/network-manager-app/linux/main.cpp index ee6763a6d3d47d..6274be9a093268 100644 --- a/examples/network-manager-app/linux/main.cpp +++ b/examples/network-manager-app/linux/main.cpp @@ -16,10 +16,14 @@ */ #include +#include #include #include +#include #include +#include + using namespace chip; using namespace chip::app; using namespace chip::app::Clusters; @@ -32,6 +36,13 @@ ByteSpan ByteSpanFromCharSpan(CharSpan span) return ByteSpan(Uint8::from_const_char(span.data()), span.size()); } +std::optional gThreadNetworkDirectoryServer; +void emberAfThreadNetworkDirectoryClusterInitCallback(chip::EndpointId endpoint) +{ + VerifyOrDie(!gThreadNetworkDirectoryServer); + gThreadNetworkDirectoryServer.emplace(endpoint).Init(); +} + int main(int argc, char * argv[]) { if (ChipLinuxAppInit(argc, argv) != 0) diff --git a/examples/network-manager-app/network-manager-common/network-manager-app.matter b/examples/network-manager-app/network-manager-common/network-manager-app.matter index bee7b9d2df4c61..22fee8337e549e 100644 --- a/examples/network-manager-app/network-manager-common/network-manager-app.matter +++ b/examples/network-manager-app/network-manager-common/network-manager-app.matter @@ -1195,6 +1195,51 @@ cluster WiFiNetworkManagement = 1105 { command access(invoke: administer) NetworkPassphraseRequest(): NetworkPassphraseResponse = 0; } +/** Manages the names and credentials of Thread networks visible to the user. */ +cluster ThreadNetworkDirectory = 1107 { + revision 1; + + struct ThreadNetworkStruct { + octet_string<8> extendedPanID = 0; + char_string<16> networkName = 1; + int16u channel = 2; + int64u activeTimestamp = 3; + } + + attribute access(read: manage, write: manage) nullable octet_string<8> preferredExtendedPanID = 0; + readonly attribute access(read: operate) ThreadNetworkStruct threadNetworks[] = 1; + readonly attribute int8u threadNetworkTableSize = 2; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute event_id eventList[] = 65530; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; + + request struct AddNetworkRequest { + octet_string<254> operationalDataset = 0; + } + + request struct RemoveNetworkRequest { + octet_string<8> extendedPanID = 0; + } + + request struct GetOperationalDatasetRequest { + octet_string<8> extendedPanID = 0; + } + + response struct OperationalDatasetResponse = 3 { + octet_string<254> operationalDataset = 0; + } + + /** Adds an entry to the ThreadNetworks list. */ + timed command access(invoke: manage) AddNetwork(AddNetworkRequest): DefaultSuccess = 0; + /** Removes an entry from the ThreadNetworks list. */ + timed command access(invoke: manage) RemoveNetwork(RemoveNetworkRequest): DefaultSuccess = 1; + /** Retrieves a Thread Operational Dataset from the ThreadNetworks list. */ + timed command GetOperationalDataset(GetOperationalDatasetRequest): OperationalDatasetResponse = 2; +} + endpoint 0 { device type ma_rootdevice = 22, version 1; @@ -1473,6 +1518,23 @@ endpoint 1 { handle command NetworkPassphraseRequest; handle command NetworkPassphraseResponse; } + + server cluster ThreadNetworkDirectory { + callback attribute preferredExtendedPanID; + callback attribute threadNetworks; + callback attribute threadNetworkTableSize; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute eventList; + callback attribute attributeList; + ram attribute featureMap default = 0; + ram attribute clusterRevision default = 1; + + handle command AddNetwork; + handle command RemoveNetwork; + handle command GetOperationalDataset; + handle command OperationalDatasetResponse; + } } diff --git a/examples/network-manager-app/network-manager-common/network-manager-app.zap b/examples/network-manager-app/network-manager-common/network-manager-app.zap index 2e0180ebc27357..ec8316ce2ad3c0 100644 --- a/examples/network-manager-app/network-manager-common/network-manager-app.zap +++ b/examples/network-manager-app/network-manager-common/network-manager-app.zap @@ -3349,6 +3349,194 @@ "reportableChange": 0 } ] + }, + { + "name": "Thread Network Directory", + "code": 1107, + "mfgCode": null, + "define": "THREAD_NETWORK_DIRECTORY_CLUSTER", + "side": "server", + "enabled": 1, + "commands": [ + { + "name": "AddNetwork", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "RemoveNetwork", + "code": 1, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "GetOperationalDataset", + "code": 2, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "OperationalDatasetResponse", + "code": 3, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + } + ], + "attributes": [ + { + "name": "PreferredExtendedPanID", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "octet_string", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ThreadNetworks", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ThreadNetworkTableSize", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "EventList", + "code": 65530, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] } ] } diff --git a/scripts/rules.matterlint b/scripts/rules.matterlint index b4af613c584c29..f44681febd112d 100644 --- a/scripts/rules.matterlint +++ b/scripts/rules.matterlint @@ -94,6 +94,7 @@ load "../src/app/zap-templates/zcl/data-model/chip/thermostat-user-interface-con load "../src/app/zap-templates/zcl/data-model/chip/thermostat-cluster.xml"; load "../src/app/zap-templates/zcl/data-model/chip/thread-border-router-management-cluster.xml"; load "../src/app/zap-templates/zcl/data-model/chip/thread-network-diagnostics-cluster.xml"; +load "../src/app/zap-templates/zcl/data-model/chip/thread-network-directory-cluster.xml"; load "../src/app/zap-templates/zcl/data-model/chip/time-format-localization-cluster.xml"; load "../src/app/zap-templates/zcl/data-model/chip/time-synchronization-cluster.xml"; load "../src/app/zap-templates/zcl/data-model/chip/timer-cluster.xml"; diff --git a/src/app/AttributeAccessInterface.h b/src/app/AttributeAccessInterface.h index f92b5987684039..50e0812fb61c1a 100644 --- a/src/app/AttributeAccessInterface.h +++ b/src/app/AttributeAccessInterface.h @@ -149,6 +149,9 @@ class AttributeAccessInterface (!mEndpointId.HasValue() || !aOther.mEndpointId.HasValue() || mEndpointId.Value() == aOther.mEndpointId.Value()); } +protected: + Optional GetEndpointId() { return mEndpointId; } + private: Optional mEndpointId; ClusterId mClusterId; diff --git a/src/app/CommandHandlerInterface.h b/src/app/CommandHandlerInterface.h index d36a41e37f076c..6a0d8a4bc36e5c 100644 --- a/src/app/CommandHandlerInterface.h +++ b/src/app/CommandHandlerInterface.h @@ -226,6 +226,8 @@ class CommandHandlerInterface } } + Optional GetEndpointId() { return mEndpointId; } + private: Optional mEndpointId; ClusterId mClusterId; diff --git a/src/app/chip_data_model.gni b/src/app/chip_data_model.gni index a68d193d241541..6b37e857c6b2d8 100644 --- a/src/app/chip_data_model.gni +++ b/src/app/chip_data_model.gni @@ -390,6 +390,14 @@ template("chip_data_model") { "${_app_root}/clusters/${cluster}/thread-network-diagnostics-provider.cpp", "${_app_root}/clusters/${cluster}/thread-network-diagnostics-provider.h", ] + } else if (cluster == "thread-network-directory-server") { + sources += [ + "${_app_root}/clusters/${cluster}/${cluster}.cpp", + "${_app_root}/clusters/${cluster}/${cluster}.h", + "${_app_root}/clusters/${cluster}/DefaultThreadNetworkDirectoryStorage.cpp", + "${_app_root}/clusters/${cluster}/DefaultThreadNetworkDirectoryStorage.h", + "${_app_root}/clusters/${cluster}/ThreadNetworkDirectoryStorage.h", + ] } else { sources += [ "${_app_root}/clusters/${cluster}/${cluster}.cpp" ] } diff --git a/src/app/clusters/thread-network-directory-server/DefaultThreadNetworkDirectoryStorage.cpp b/src/app/clusters/thread-network-directory-server/DefaultThreadNetworkDirectoryStorage.cpp new file mode 100644 index 00000000000000..6daaffce9ce91c --- /dev/null +++ b/src/app/clusters/thread-network-directory-server/DefaultThreadNetworkDirectoryStorage.cpp @@ -0,0 +1,144 @@ +/** + * + * Copyright (c) 2024 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 "DefaultThreadNetworkDirectoryStorage.h" +#include +#include +#include + +namespace chip { +namespace app { + +void DefaultThreadNetworkDirectoryStorage::InitializedIfNeeded() +{ + VerifyOrReturn(!mInitialized); + mInitialized = true; + + CHIP_ERROR err; + StorageKeyName key = DefaultStorageKeyAllocator::ThreadNetworkDirectoryIndex(); + uint16_t size = sizeof(mExtendedPanIds); + SuccessOrExit(err = mStorage.SyncGetKeyValue(key.KeyName(), mExtendedPanIds, size)); + VerifyOrExit(size % ExtendedPanId::size() == 0, err = CHIP_ERROR_INTERNAL); + mCount = static_cast(size / ExtendedPanId::size()); + return; +exit: + if (err != CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND) + { + ChipLogError(Zcl, "Failed to load Thread Network Directory storage: %" CHIP_ERROR_FORMAT, err.Format()); + } +} + +CHIP_ERROR DefaultThreadNetworkDirectoryStorage::StoreIndex() +{ + VerifyOrDie(mInitialized); + StorageKeyName key = DefaultStorageKeyAllocator::ThreadNetworkDirectoryIndex(); + return mStorage.SyncSetKeyValue(key.KeyName(), mExtendedPanIds, mCount * ExtendedPanId::size()); +} + +bool DefaultThreadNetworkDirectoryStorage::FindNetwork(const ExtendedPanId & exPanId, index_t & outIndex) +{ + for (index_t idx = 0; idx < mCount; idx++) + { + if (mExtendedPanIds[idx] == exPanId) + { + outIndex = idx; + return true; + } + } + return false; +} + +ThreadNetworkDirectoryStorage::ExtendedPanIdIterator * DefaultThreadNetworkDirectoryStorage::IterateNetworkIds() +{ + InitializedIfNeeded(); + return mIterators.CreateObject(*this); +} + +bool DefaultThreadNetworkDirectoryStorage::ContainsNetwork(const ExtendedPanId & exPanId) +{ + InitializedIfNeeded(); + index_t unused; + return FindNetwork(exPanId, unused); +} + +CHIP_ERROR DefaultThreadNetworkDirectoryStorage::GetNetworkDataset(const ExtendedPanId & exPanId, MutableByteSpan & dataset) +{ + VerifyOrReturnError(ContainsNetwork(exPanId), CHIP_ERROR_NOT_FOUND); + uint16_t size = static_cast(CanCastTo(dataset.size()) ? dataset.size() : UINT16_MAX); + StorageKeyName key = DefaultStorageKeyAllocator::ThreadNetworkDirectoryDataset(exPanId.AsNumber()); + ReturnErrorOnFailure(mStorage.SyncGetKeyValue(key.KeyName(), dataset.data(), size)); + dataset.reduce_size(size); + return CHIP_NO_ERROR; +} + +CHIP_ERROR DefaultThreadNetworkDirectoryStorage::AddOrUpdateNetwork(const ExtendedPanId & exPanId, ByteSpan dataset) +{ + VerifyOrReturnError(0 < dataset.size() && dataset.size() <= kMaxThreadDatasetLen, CHIP_ERROR_INVALID_ARGUMENT); + bool update = ContainsNetwork(exPanId); + VerifyOrReturnError(update || mCount < kCapacity, CHIP_ERROR_NO_MEMORY); + + // Store the dataset first + StorageKeyName key = DefaultStorageKeyAllocator::ThreadNetworkDirectoryDataset(exPanId.AsNumber()); + ReturnErrorOnFailure(mStorage.SyncSetKeyValue(key.KeyName(), dataset.data(), static_cast(dataset.size()))); + + // Update the index if we're adding a new network, rolling back on failure. + if (!update) + { + mExtendedPanIds[mCount++] = exPanId; + CHIP_ERROR err = StoreIndex(); + if (err != CHIP_NO_ERROR) + { + mCount--; + mStorage.SyncDeleteKeyValue(key.KeyName()); + return err; + } + } + + return CHIP_NO_ERROR; +} + +CHIP_ERROR DefaultThreadNetworkDirectoryStorage::RemoveNetwork(const ExtendedPanId & exPanId) +{ + InitializedIfNeeded(); + index_t index; + VerifyOrReturnError(FindNetwork(exPanId, index), CHIP_ERROR_NOT_FOUND); + + // Move subsequent elements down to fill the deleted slot + static_assert(std::is_trivially_copyable_v); + size_t subsequentCount = mCount - (index + 1u); + auto * element = &mExtendedPanIds[index]; + memmove(element, element + 1, subsequentCount * sizeof(*element)); + mCount--; + + CHIP_ERROR err = StoreIndex(); + if (err != CHIP_NO_ERROR) + { + // Roll back the change to our in-memory state + memmove(element + 1, element, subsequentCount * sizeof(*element)); + mExtendedPanIds[index] = exPanId; + mCount++; + return err; + } + + // Delete the dataset itself. Ignore errors since we successfully updated the index. + StorageKeyName key = DefaultStorageKeyAllocator::ThreadNetworkDirectoryDataset(exPanId.AsNumber()); + mStorage.SyncDeleteKeyValue(key.KeyName()); + return CHIP_NO_ERROR; +} + +} // namespace app +} // namespace chip diff --git a/src/app/clusters/thread-network-directory-server/DefaultThreadNetworkDirectoryStorage.h b/src/app/clusters/thread-network-directory-server/DefaultThreadNetworkDirectoryStorage.h new file mode 100644 index 00000000000000..0cda5e3e188c7f --- /dev/null +++ b/src/app/clusters/thread-network-directory-server/DefaultThreadNetworkDirectoryStorage.h @@ -0,0 +1,80 @@ +/** + * + * Copyright (c) 2024 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 + +namespace chip { +namespace app { + +/** + * Stores Thread network information via a PersistentStorageDelegate. + */ +class DefaultThreadNetworkDirectoryStorage : public ThreadNetworkDirectoryStorage +{ +public: + DefaultThreadNetworkDirectoryStorage(PersistentStorageDelegate & storage) : mStorage(storage) {} + + uint8_t Capacity() override { return kCapacity; } + ExtendedPanIdIterator * IterateNetworkIds() override; + bool ContainsNetwork(const ExtendedPanId & exPanId) override; + CHIP_ERROR GetNetworkDataset(const ExtendedPanId & exPanId, MutableByteSpan & dataset) override; + CHIP_ERROR AddOrUpdateNetwork(const ExtendedPanId & exPanId, ByteSpan dataset) override; + CHIP_ERROR RemoveNetwork(const ExtendedPanId & exPanId) override; + +private: + using index_t = uint8_t; + static constexpr index_t kCapacity = CHIP_CONFIG_MAX_THREAD_NETWORK_DIRECTORY_STORAGE_CAPACITY; + static constexpr size_t kIteratorsMax = CHIP_CONFIG_MAX_THREAD_NETWORK_DIRECTORY_STORAGE_CONCURRENT_ITERATORS; + + void InitializedIfNeeded(); + CHIP_ERROR StoreIndex(); + bool FindNetwork(const ExtendedPanId & exPanId, index_t & outIndex); + + struct IteratorImpl final : public ExtendedPanIdIterator + { + IteratorImpl(DefaultThreadNetworkDirectoryStorage & storage) : mContainer(storage) {} + + size_t Count() override { return mContainer.mCount; } + + bool Next(ExtendedPanId & item) override + { + VerifyOrReturnValue(mIndex < Count(), false); + item = mContainer.mExtendedPanIds[mIndex++]; + return true; + } + + void Release() override { mContainer.mIterators.ReleaseObject(this); } + + DefaultThreadNetworkDirectoryStorage & mContainer; + index_t mIndex = 0; + }; + + PersistentStorageDelegate & mStorage; + ObjectPool mIterators; + ExtendedPanId mExtendedPanIds[kCapacity]; + index_t mCount = 0; + bool mInitialized = false; +}; + +} // namespace app +} // namespace chip diff --git a/src/app/clusters/thread-network-directory-server/ThreadNetworkDirectoryStorage.h b/src/app/clusters/thread-network-directory-server/ThreadNetworkDirectoryStorage.h new file mode 100644 index 00000000000000..b31d34e9778bd0 --- /dev/null +++ b/src/app/clusters/thread-network-directory-server/ThreadNetworkDirectoryStorage.h @@ -0,0 +1,127 @@ +/** + * + * Copyright (c) 2024 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 + +namespace chip { +namespace app { + +class ThreadNetworkDirectoryStorage +{ +public: + static constexpr size_t kMaxThreadDatasetLen = 254; + + /** + * A Thread Extended PAN ID is an opaque 8 byte value, + * and can optionally be interpreted as a big-endian number. + * + * ExtendedPanId structs or arrays thereof can be directly + * read from or written to storage and are byte-order independent. + */ + struct ExtendedPanId final + { + uint8_t bytes[8]; + static constexpr size_t size() { return sizeof(bytes); } + + constexpr ExtendedPanId() : bytes{} {} + explicit ExtendedPanId(ByteSpan source) + { + VerifyOrDie(source.size() == size()); + memcpy(bytes, source.data(), size()); + } + + explicit ExtendedPanId(uint64_t number) { Encoding::BigEndian::Put64(bytes, number); } + + constexpr ByteSpan AsSpan() const { return ByteSpan(bytes); } + uint64_t AsNumber() const { return Encoding::BigEndian::Get64(bytes); } + + bool operator==(const ExtendedPanId & other) const { return memcmp(bytes, other.bytes, size()) == 0; } + bool operator!=(const ExtendedPanId & other) const { return !(*this == other); } + }; + + static_assert(std::is_trivially_copyable_v && sizeof(ExtendedPanId) == sizeof(ExtendedPanId::bytes)); + + using ExtendedPanIdIterator = CommonIterator; + + virtual ~ThreadNetworkDirectoryStorage() = default; + + /** + * Returns the maximum number of networks that can be stored. + */ + virtual uint8_t Capacity() = 0; + + /** + * Creates an iterator over the list of stored networks. + * Release() must be called on the iterator after the iteration is finished. + * Adding or removing networks during the iteration is not supported. + * + * The iteration order of stored networks should remain stable as long as + * as no networks are added or removed. + * + * @retval An instance of ExtendedPanIdIterator on success + * @retval nullptr if no iterator instances are available. + */ + virtual ExtendedPanIdIterator * IterateNetworkIds() = 0; + + /** + * Retrieves the dataset associated with the specified Extended PAN ID. + * + * @retval CHIP_ERROR_NOT_FOUND if there is no matching network stored. + * @retval CHIP_ERROR_BUFFER_TOO_SMALL if the provided buffer buffer is too small. + * @retval CHIP_ERROR_* for other errors. + */ + virtual CHIP_ERROR GetNetworkDataset(const ExtendedPanId & exPanId, MutableByteSpan & dataset) = 0; + + /** + * Adds (or updates, if a matching network already exists) the network with the specified + * Extended PAN ID and dataset. Note that the dataset must be treated as an opaque blob; + * no validation of any kind is expected to be performed on the dataset contents. + * + * @retval CHIP_ERROR_INVALID_ARGUMENT if the dataset is empty or too long. + * @retval CHIP_ERROR_NO_MEMORY if adding the network would exceed the storage capacity. + * @retval CHIP_ERROR_* for other errors. + */ + virtual CHIP_ERROR AddOrUpdateNetwork(const ExtendedPanId & exPanId, ByteSpan dataset) = 0; + + /** + * Removes the network with the specified Extended PAN ID. + * + * @retval CHIP_ERROR_NOT_FOUND if there is no matching network stored. + * @retval CHIP_ERROR_* for other errors. + */ + virtual CHIP_ERROR RemoveNetwork(const ExtendedPanId & exPanId) = 0; + + /** + * Returns true if a network with the specified Extended PAN ID is stored, or false otherwise. + */ + virtual bool ContainsNetwork(const ExtendedPanId & exPanId) + { + MutableByteSpan empty; + return GetNetworkDataset(exPanId, empty) != CHIP_ERROR_NOT_FOUND; + } +}; + +} // namespace app +} // namespace chip diff --git a/src/app/clusters/thread-network-directory-server/thread-network-directory-server.cpp b/src/app/clusters/thread-network-directory-server/thread-network-directory-server.cpp new file mode 100644 index 00000000000000..888972b3075c33 --- /dev/null +++ b/src/app/clusters/thread-network-directory-server/thread-network-directory-server.cpp @@ -0,0 +1,288 @@ +/** + * + * Copyright (c) 2024 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 "thread-network-directory-server.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace chip; +using namespace chip::app; +using namespace chip::app::Clusters; +using namespace chip::app::Clusters::ThreadNetworkDirectory::Attributes; +using namespace chip::app::Clusters::ThreadNetworkDirectory::Commands; +using namespace chip::app::Clusters::ThreadNetworkDirectory::Structs; +using namespace chip::Thread; +using IMStatus = chip::Protocols::InteractionModel::Status; + +namespace chip { +namespace app { +namespace Clusters { + +ThreadNetworkDirectoryServer::ThreadNetworkDirectoryServer(EndpointId endpoint, ThreadNetworkDirectoryStorage & storage) : + AttributeAccessInterface(MakeOptional(endpoint), ThreadNetworkDirectory::Id), + CommandHandlerInterface(MakeOptional(endpoint), ThreadNetworkDirectory::Id), mStorage(storage) +{} + +ThreadNetworkDirectoryServer::~ThreadNetworkDirectoryServer() +{ + unregisterAttributeAccessOverride(this); + InteractionModelEngine::GetInstance()->UnregisterCommandHandler(this); +} + +CHIP_ERROR ThreadNetworkDirectoryServer::Init() +{ + VerifyOrReturnError(registerAttributeAccessOverride(this), CHIP_ERROR_INTERNAL); + ReturnErrorOnFailure(InteractionModelEngine::GetInstance()->RegisterCommandHandler(this)); + return CHIP_NO_ERROR; +} + +CHIP_ERROR ThreadNetworkDirectoryServer::Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder) +{ + switch (aPath.mAttributeId) + { + case PreferredExtendedPanID::Id: + return ReadPreferredExtendedPanId(aPath, aEncoder); + case ThreadNetworks::Id: + return ReadThreadNetworks(aPath, aEncoder); + case ThreadNetworkTableSize::Id: + return aEncoder.Encode(mStorage.Capacity()); + } + return CHIP_NO_ERROR; +} + +CHIP_ERROR ThreadNetworkDirectoryServer::Write(const ConcreteDataAttributePath & aPath, AttributeValueDecoder & aDecoder) +{ + switch (aPath.mAttributeId) + { + case PreferredExtendedPanID::Id: + return WritePreferredExtendedPanId(aPath, aDecoder); + } + return CHIP_NO_ERROR; +} + +CHIP_ERROR ThreadNetworkDirectoryServer::ReadExtendedPanId(const ConcreteDataAttributePath & aPath, + std::optional & outExPanId) +{ + MutableByteSpan value(outExPanId.emplace().bytes); + CHIP_ERROR err = GetSafeAttributePersistenceProvider()->SafeReadValue(aPath, value); + if (err == CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND) + { + outExPanId.reset(); // default to empty + return CHIP_NO_ERROR; + } + ReturnErrorOnFailure(err); + + if (value.size() == 0) + { + outExPanId.reset(); + return CHIP_NO_ERROR; + } + + VerifyOrReturnError(value.size() == ExtendedPanId::size(), CHIP_ERROR_INTERNAL); + return CHIP_NO_ERROR; +} + +CHIP_ERROR ThreadNetworkDirectoryServer::ReadPreferredExtendedPanId(const ConcreteDataAttributePath & aPath, + AttributeValueEncoder & aEncoder) +{ + std::optional value; + ReturnErrorOnFailure(ReadExtendedPanId(aPath, value)); + return (value.has_value()) ? aEncoder.Encode(value.value().AsSpan()) : aEncoder.EncodeNull(); +} + +CHIP_ERROR ThreadNetworkDirectoryServer::WritePreferredExtendedPanId(const ConcreteDataAttributePath & aPath, + AttributeValueDecoder & aDecoder) +{ + DataModel::Nullable nullableValue; + ReturnErrorOnFailure(aDecoder.Decode(nullableValue)); + + // "A zero-length value SHALL be allowed for nullable values ... and SHALL have the same semantics as the null value." + ByteSpan value = nullableValue.ValueOr(ByteSpan()); + // Ensure the provided value is valid (correct size) and refers to PAN from the list. + VerifyOrReturnError(value.empty() || (value.size() == ExtendedPanId::size() && mStorage.ContainsNetwork(ExtendedPanId(value))), + StatusIB(IMStatus::ConstraintError).ToChipError()); + + return GetSafeAttributePersistenceProvider()->SafeWriteValue(aPath, value); +} + +CHIP_ERROR ThreadNetworkDirectoryServer::ReadThreadNetworks(const ConcreteDataAttributePath &, AttributeValueEncoder & aEncoder) +{ + return aEncoder.EncodeList([this](const auto & encoder) -> CHIP_ERROR { + CHIP_ERROR err = CHIP_NO_ERROR; + ExtendedPanId exPanId; + auto * iterator = mStorage.IterateNetworkIds(); + while (iterator->Next(exPanId)) + { + uint8_t datasetBuffer[kSizeOperationalDataset]; + MutableByteSpan datasetSpan(datasetBuffer); + SuccessOrExit(err = mStorage.GetNetworkDataset(exPanId, datasetSpan)); + + OperationalDataset dataset; + char networkName[kSizeNetworkName + 1]; + ThreadNetworkStruct::Type network; + + dataset.Init(datasetSpan); + SuccessOrExit(err = dataset.GetExtendedPanIdAsByteSpan(network.extendedPanID)); + SuccessOrExit(err = dataset.GetNetworkName(networkName)); + network.networkName = CharSpan::fromCharString(networkName); + SuccessOrExit(err = dataset.GetChannel(network.channel)); + SuccessOrExit(err = dataset.GetActiveTimestamp(network.activeTimestamp)); + + SuccessOrExit(err = encoder.Encode(network)); + } + exit: + iterator->Release(); + return err; + }); +} + +void ThreadNetworkDirectoryServer::InvokeCommand(HandlerContext & ctx) +{ + switch (ctx.mRequestPath.mCommandId) + { + case AddNetwork::Id: + HandleCommand( + ctx, [this](HandlerContext & aCtx, const auto & req) { HandleAddNetworkRequest(aCtx, req); }); + return; + case RemoveNetwork::Id: + HandleCommand( + ctx, [this](HandlerContext & aCtx, const auto & req) { HandleRemoveNetworkRequest(aCtx, req); }); + return; + case GetOperationalDataset::Id: + HandleCommand( + ctx, [this](HandlerContext & aCtx, const auto & req) { HandleOperationalDatasetRequest(aCtx, req); }); + return; + } +} + +void ThreadNetworkDirectoryServer::HandleAddNetworkRequest(HandlerContext & ctx, + const ThreadNetworkDirectory::Commands::AddNetwork::DecodableType & req) +{ + OperationalDataset dataset; + ByteSpan extendedPanIdSpan; + union + { + uint64_t activeTimestamp; + uint16_t channel; + uint8_t masterKey[kSizeMasterKey]; + uint8_t meshLocalPrefix[kSizeMeshLocalPrefix]; + char networkName[kSizeNetworkName + 1]; + uint16_t panId; + uint8_t pksc[kSizePSKc]; + uint32_t securityPolicy; + } unused; + ByteSpan unusedSpan; + + // "It SHALL contain at least the following sub-TLVs: Active Timestamp, Channel, Channel Mask, + // Extended PAN ID, Network Key, Network Mesh-Local Prefix, Network Name, PAN ID, PKSc, and Security Policy." + CHIP_ERROR err; + auto status = IMStatus::ConstraintError; + const char * context = nullptr; + // TODO: An immutable OperationalDatasetView on top of a ByteSpan (without copying) would be useful here. + SuccessOrExitAction(err = dataset.Init(req.operationalDataset), context = "OperationalDataset"); + SuccessOrExitAction(err = dataset.GetExtendedPanIdAsByteSpan(extendedPanIdSpan), context = "ExtendedPanID"); + SuccessOrExitAction(err = dataset.GetActiveTimestamp(unused.activeTimestamp), context = "ActiveTimestamp"); + SuccessOrExitAction(err = dataset.GetChannel(unused.channel), context = "Channel"); + SuccessOrExitAction(err = dataset.GetChannelMask(unusedSpan), context = "ChannelMask"); + SuccessOrExitAction(err = dataset.GetMasterKey(unused.masterKey), context = "NetworkKey"); + SuccessOrExitAction(err = dataset.GetMeshLocalPrefix(unused.meshLocalPrefix), context = "MeshLocalPrefix"); + SuccessOrExitAction(err = dataset.GetNetworkName(unused.networkName), context = "NetworkName"); + SuccessOrExitAction(err = dataset.GetPanId(unused.panId), context = "PanID"); + SuccessOrExitAction(err = dataset.GetPSKc(unused.pksc), context = "PKSc"); + SuccessOrExitAction(err = dataset.GetSecurityPolicy(unused.securityPolicy), context = "SecurityContext"); + + status = IMStatus::Failure; + SuccessOrExit(err = mStorage.AddOrUpdateNetwork(ExtendedPanId(extendedPanIdSpan), req.operationalDataset)); + + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, IMStatus::Success); + MatterReportingAttributeChangeCallback(GetEndpointId(), ThreadNetworkDirectory::Id, ThreadNetworks::Id); + return; + +exit: + ChipLogError(Zcl, "AddNetwork: %" CHIP_ERROR_FORMAT, err.Format()); + ctx.mCommandHandler.AddStatus( + ctx.mRequestPath, (status == IMStatus::Failure && err == CHIP_ERROR_NO_MEMORY) ? IMStatus::ResourceExhausted : status, + context); +} + +void ThreadNetworkDirectoryServer::HandleRemoveNetworkRequest( + HandlerContext & ctx, const ThreadNetworkDirectory::Commands::RemoveNetwork::DecodableType & req) +{ + CHIP_ERROR err; + + if (req.extendedPanID.size() != ExtendedPanId::size()) + { + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, IMStatus::ConstraintError); + return; + } + ExtendedPanId exPanId(req.extendedPanID); + + std::optional preferredExPanId; + ConcreteReadAttributePath preferredExPanIdPath(GetEndpointId(), ThreadNetworkDirectory::Id, + ThreadNetworkDirectory::Attributes::PreferredExtendedPanID::Id); + SuccessOrExit(err = ReadExtendedPanId(preferredExPanIdPath, preferredExPanId)); + if (preferredExPanId.has_value() && preferredExPanId.value() == exPanId) + { + ChipLogError(Zcl, "RemoveNetwork: Rejecting removal of preferred PAN"); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, IMStatus::ConstraintError); + return; + } + + SuccessOrExit(err = mStorage.RemoveNetwork(exPanId)); + + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, IMStatus::Success); + MatterReportingAttributeChangeCallback(GetEndpointId(), ThreadNetworkDirectory::Id, ThreadNetworks::Id); + return; + +exit: + ChipLogError(Zcl, "RemoveNetwork: %" CHIP_ERROR_FORMAT, err.Format()); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, (err == CHIP_ERROR_NOT_FOUND) ? IMStatus::NotFound : IMStatus::Failure); +} + +void ThreadNetworkDirectoryServer::HandleOperationalDatasetRequest( + HandlerContext & ctx, const ThreadNetworkDirectory::Commands::GetOperationalDataset::DecodableType & req) +{ + CHIP_ERROR err; + + if (req.extendedPanID.size() != ExtendedPanId::size()) + { + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, IMStatus::ConstraintError); + return; + } + + uint8_t datasetBuffer[kSizeOperationalDataset]; + MutableByteSpan datasetSpan(datasetBuffer); + SuccessOrExit(err = mStorage.GetNetworkDataset(ExtendedPanId(req.extendedPanID), datasetSpan)); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, IMStatus::Success); + return; +exit: + ChipLogError(Zcl, "GetOperationalDataset: %" CHIP_ERROR_FORMAT, err.Format()); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, (err == CHIP_ERROR_NOT_FOUND) ? IMStatus::NotFound : IMStatus::Failure); +} + +} // namespace Clusters +} // namespace app +} // namespace chip + +void MatterThreadNetworkDirectoryPluginServerInitCallback() {} diff --git a/src/app/clusters/thread-network-directory-server/thread-network-directory-server.h b/src/app/clusters/thread-network-directory-server/thread-network-directory-server.h new file mode 100644 index 00000000000000..2f671bdd6b4e09 --- /dev/null +++ b/src/app/clusters/thread-network-directory-server/thread-network-directory-server.h @@ -0,0 +1,86 @@ +/** + * + * Copyright (c) 2024 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 + +#include + +namespace chip { +namespace app { +namespace Clusters { + +class ThreadNetworkDirectoryServer : private AttributeAccessInterface, private CommandHandlerInterface +{ +public: + ThreadNetworkDirectoryServer(EndpointId endpoint, ThreadNetworkDirectoryStorage & storage); + ~ThreadNetworkDirectoryServer(); + + CHIP_ERROR Init(); + + ThreadNetworkDirectoryServer(ThreadNetworkDirectoryServer const &) = delete; + ThreadNetworkDirectoryServer & operator=(ThreadNetworkDirectoryServer const &) = delete; + +private: + using ExtendedPanId = ThreadNetworkDirectoryStorage::ExtendedPanId; + + EndpointId GetEndpointId() { return AttributeAccessInterface::GetEndpointId().Value(); } + + CHIP_ERROR Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder) override; + CHIP_ERROR Write(const ConcreteDataAttributePath & aPath, AttributeValueDecoder & aDecoder) override; + void InvokeCommand(HandlerContext & handlerContext) override; + + CHIP_ERROR ReadExtendedPanId(const ConcreteDataAttributePath & aPath, std::optional & outExPanId); + CHIP_ERROR ReadPreferredExtendedPanId(const ConcreteDataAttributePath & aPath, AttributeValueEncoder & aEncoder); + CHIP_ERROR WritePreferredExtendedPanId(const ConcreteDataAttributePath & aPath, AttributeValueDecoder & aDecoder); + CHIP_ERROR ReadThreadNetworks(const ConcreteDataAttributePath & aPath, AttributeValueEncoder & aEncoder); + + void HandleAddNetworkRequest(HandlerContext & ctx, const ThreadNetworkDirectory::Commands::AddNetwork::DecodableType & req); + void HandleRemoveNetworkRequest(HandlerContext & ctx, + const ThreadNetworkDirectory::Commands::RemoveNetwork::DecodableType & req); + void HandleOperationalDatasetRequest(HandlerContext & ctx, + const ThreadNetworkDirectory::Commands::GetOperationalDataset::DecodableType & req); + + ThreadNetworkDirectoryStorage & mStorage; +}; + +/** + * A ThreadNetworkDirectoryServer using DefaultThreadNetworkDirectoryStorage. + */ +class DefaultThreadNetworkDirectoryServer final : public ThreadNetworkDirectoryServer +{ +public: + DefaultThreadNetworkDirectoryServer(EndpointId endpoint, + PersistentStorageDelegate & storage = Server::GetInstance().GetPersistentStorage()) : + ThreadNetworkDirectoryServer(endpoint, mStorage), + mStorage(storage) + {} + +private: + DefaultThreadNetworkDirectoryStorage mStorage; +}; + +} // namespace Clusters +} // namespace app +} // namespace chip diff --git a/src/app/common/templates/config-data.yaml b/src/app/common/templates/config-data.yaml index 83d1b682153ed7..e7121b2757e2f3 100644 --- a/src/app/common/templates/config-data.yaml +++ b/src/app/common/templates/config-data.yaml @@ -41,6 +41,7 @@ CommandHandlerInterfaceOnlyClusters: - Electrical Power Measurement - Electrical Energy Measurement - Wi-Fi Network Management + - Thread Network Directory # We need a more configurable way of deciding which clusters have which init functions.... # See https://github.com/project-chip/connectedhomeip/issues/4369 diff --git a/src/app/tests/BUILD.gn b/src/app/tests/BUILD.gn index c1826884923af4..3ca229a6751132 100644 --- a/src/app/tests/BUILD.gn +++ b/src/app/tests/BUILD.gn @@ -73,6 +73,19 @@ source_set("ota-requestor-test-srcs") { ] } +source_set("thread-network-directory-test-srcs") { + sources = [ + "${chip_root}/src/app/clusters/thread-network-directory-server/DefaultThreadNetworkDirectoryStorage.cpp", + "${chip_root}/src/app/clusters/thread-network-directory-server/DefaultThreadNetworkDirectoryStorage.h", + "${chip_root}/src/app/clusters/thread-network-directory-server/ThreadNetworkDirectoryStorage.h", + ] + + public_deps = [ + "${chip_root}/src/app/common:cluster-objects", + "${chip_root}/src/lib/core", + ] +} + source_set("time-sync-data-provider-test-srcs") { sources = [ "${chip_root}/src/app/clusters/time-synchronization-server/TimeSyncDataProvider.cpp" ] @@ -159,6 +172,7 @@ chip_test_suite("tests") { "TestConcreteAttributePath.cpp", "TestDataModelSerialization.cpp", "TestDefaultOTARequestorStorage.cpp", + "TestDefaultThreadNetworkDirectoryStorage.cpp", "TestEventLoggingNoUTCTime.cpp", "TestEventOverflow.cpp", "TestEventPathParams.cpp", @@ -189,6 +203,7 @@ chip_test_suite("tests") { ":operational-state-test-srcs", ":ota-requestor-test-srcs", ":power-cluster-test-srcs", + ":thread-network-directory-test-srcs", ":time-sync-data-provider-test-srcs", "${chip_root}/src/app", "${chip_root}/src/app/common:cluster-objects", diff --git a/src/app/tests/TestDefaultThreadNetworkDirectoryStorage.cpp b/src/app/tests/TestDefaultThreadNetworkDirectoryStorage.cpp new file mode 100644 index 00000000000000..761b78afad4ff9 --- /dev/null +++ b/src/app/tests/TestDefaultThreadNetworkDirectoryStorage.cpp @@ -0,0 +1,292 @@ +/* + * + * Copyright (c) 2024 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 +#include +#include +#include + +#include +#include +#include + +using namespace chip; +using namespace chip::app; + +namespace { + +class TestDefaultThreadNetworkDirectoryStorage : public ::testing::Test +{ +public: + static void SetUpTestSuite() { ASSERT_EQ(chip::Platform::MemoryInit(), CHIP_NO_ERROR); } + static void TearDownTestSuite() { chip::Platform::MemoryShutdown(); } + +protected: + TestPersistentStorageDelegate persistentStorageDelegate; + DefaultThreadNetworkDirectoryStorage storageImpl{ persistentStorageDelegate }; + ThreadNetworkDirectoryStorage & storage = storageImpl; +}; + +TEST_F(TestDefaultThreadNetworkDirectoryStorage, TestEmptyStorage) +{ + EXPECT_GE(storage.Capacity(), 2); // can't meaningfully test with less and spec requires 2 per fabric + + { + ThreadNetworkDirectoryStorage::ExtendedPanId exPanId; + auto * iterator = storage.IterateNetworkIds(); + EXPECT_TRUE(iterator != nullptr); + EXPECT_EQ(iterator->Count(), 0u); + EXPECT_FALSE(iterator->Next(exPanId)); + iterator->Release(); + } + + ThreadNetworkDirectoryStorage::ExtendedPanId exPanId(UINT64_C(0x1122334455667788)); + EXPECT_FALSE(storage.ContainsNetwork(exPanId)); + EXPECT_EQ(storage.RemoveNetwork(exPanId), CHIP_ERROR_NOT_FOUND); + MutableByteSpan mutableSpan; + EXPECT_EQ(storage.GetNetworkDataset(exPanId, mutableSpan), CHIP_ERROR_NOT_FOUND); +} + +TEST_F(TestDefaultThreadNetworkDirectoryStorage, TestAddEmptyDataset) +{ + ThreadNetworkDirectoryStorage::ExtendedPanId exPanId(UINT64_C(0xd00fd00fdeadbeef)); + EXPECT_EQ(storage.AddOrUpdateNetwork(exPanId, ByteSpan()), CHIP_ERROR_INVALID_ARGUMENT); +} + +TEST_F(TestDefaultThreadNetworkDirectoryStorage, TestAddDatasetTooLong) +{ + ThreadNetworkDirectoryStorage::ExtendedPanId exPanId(UINT64_C(0xd00fd00fdeadbeef)); + uint8_t dataset[ThreadNetworkDirectoryStorage::kMaxThreadDatasetLen + 1] = { 1, 2, 3 }; + EXPECT_EQ(storage.AddOrUpdateNetwork(exPanId, ByteSpan(dataset)), CHIP_ERROR_INVALID_ARGUMENT); +} + +TEST_F(TestDefaultThreadNetworkDirectoryStorage, TestAddRemoveNetworks) +{ + const ThreadNetworkDirectoryStorage::ExtendedPanId panA(UINT64_C(0xd00fd00fdeadbeef)); + const uint8_t datasetA[] = { 1 }; + const uint8_t updatedDatasetA[] = { 0x11, 0x11 }; + const ThreadNetworkDirectoryStorage::ExtendedPanId panB(UINT64_C(0xe475cafef00df00d)); + const uint8_t datasetB[] = { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 }; + uint8_t mutableBytes[ThreadNetworkDirectoryStorage::kMaxThreadDatasetLen]; + + // Add Pan A only + EXPECT_EQ(storage.AddOrUpdateNetwork(panA, ByteSpan(datasetA)), CHIP_NO_ERROR); + EXPECT_TRUE(storage.ContainsNetwork(panA)); + EXPECT_FALSE(storage.ContainsNetwork(panB)); + + { + MutableByteSpan retrievedDatasetA(mutableBytes); + EXPECT_EQ(storage.GetNetworkDataset(panA, retrievedDatasetA), CHIP_NO_ERROR); + EXPECT_TRUE(retrievedDatasetA.data_equal(ByteSpan(datasetA))); + } + { + MutableByteSpan emptyMutableSpan; + EXPECT_EQ(storage.GetNetworkDataset(panA, emptyMutableSpan), CHIP_ERROR_BUFFER_TOO_SMALL); + } + { + ThreadNetworkDirectoryStorage::ExtendedPanId exPanId; + auto * iterator = storage.IterateNetworkIds(); + EXPECT_TRUE(iterator != nullptr); + EXPECT_EQ(iterator->Count(), 1u); + EXPECT_TRUE(iterator->Next(exPanId)); + EXPECT_EQ(exPanId, panA); + EXPECT_NE(exPanId, panB); // just to ensure operator== is sane + EXPECT_FALSE(iterator->Next(exPanId)); + EXPECT_EQ(iterator->Count(), 1u); + iterator->Release(); + } + + // Update Pan A + EXPECT_EQ(storage.AddOrUpdateNetwork(panA, ByteSpan(updatedDatasetA)), CHIP_NO_ERROR); + EXPECT_TRUE(storage.ContainsNetwork(panA)); + EXPECT_FALSE(storage.ContainsNetwork(panB)); + + { + MutableByteSpan retrievedUpdatedDatasetA(mutableBytes); + EXPECT_EQ(storage.GetNetworkDataset(panA, retrievedUpdatedDatasetA), CHIP_NO_ERROR); + EXPECT_TRUE(retrievedUpdatedDatasetA.data_equal(ByteSpan(updatedDatasetA))); + } + { + auto * iterator = storage.IterateNetworkIds(); + EXPECT_TRUE(iterator != nullptr); + EXPECT_EQ(iterator->Count(), 1u); // still 1 + iterator->Release(); + } + + // Add Pan B + EXPECT_EQ(storage.AddOrUpdateNetwork(panB, ByteSpan(datasetB)), CHIP_NO_ERROR); + EXPECT_TRUE(storage.ContainsNetwork(panA)); + EXPECT_TRUE(storage.ContainsNetwork(panB)); + { + ThreadNetworkDirectoryStorage::ExtendedPanId exPanId1; + ThreadNetworkDirectoryStorage::ExtendedPanId exPanId2; + ThreadNetworkDirectoryStorage::ExtendedPanId unused; + auto * iterator = storage.IterateNetworkIds(); + EXPECT_TRUE(iterator != nullptr); + EXPECT_EQ(iterator->Count(), 2u); + EXPECT_TRUE(iterator->Next(exPanId1)); + EXPECT_TRUE(iterator->Next(exPanId2)); + EXPECT_TRUE((exPanId1 == panA && exPanId2 == panB) || (exPanId1 == panB && exPanId2 == panA)); + EXPECT_FALSE(iterator->Next(unused)); + EXPECT_EQ(iterator->Count(), 2u); + iterator->Release(); + } + { + MutableByteSpan retrievedDatasetB(mutableBytes); + EXPECT_EQ(storage.GetNetworkDataset(panB, retrievedDatasetB), CHIP_NO_ERROR); + EXPECT_TRUE(retrievedDatasetB.data_equal(ByteSpan(datasetB))); + } + + // Remove Pan A + EXPECT_EQ(storage.RemoveNetwork(panA), CHIP_NO_ERROR); + EXPECT_FALSE(storage.ContainsNetwork(panA)); + EXPECT_TRUE(storage.ContainsNetwork(panB)); + + { + MutableByteSpan mutableSpan; + EXPECT_EQ(storage.GetNetworkDataset(panA, mutableSpan), CHIP_ERROR_NOT_FOUND); + } + { + ThreadNetworkDirectoryStorage::ExtendedPanId exPanId; + auto * iterator = storage.IterateNetworkIds(); + EXPECT_TRUE(iterator != nullptr); + EXPECT_EQ(iterator->Count(), 1u); + EXPECT_TRUE(iterator->Next(exPanId)); + EXPECT_EQ(exPanId, panB); + EXPECT_FALSE(iterator->Next(exPanId)); + iterator->Release(); + } + + // Remove Pan B + EXPECT_EQ(storage.RemoveNetwork(panB), CHIP_NO_ERROR); + EXPECT_FALSE(storage.ContainsNetwork(panA)); + EXPECT_FALSE(storage.ContainsNetwork(panB)); + + { + MutableByteSpan mutableSpan; + EXPECT_EQ(storage.GetNetworkDataset(panB, mutableSpan), CHIP_ERROR_NOT_FOUND); + } + { + ThreadNetworkDirectoryStorage::ExtendedPanId exPanId; + auto * iterator = storage.IterateNetworkIds(); + EXPECT_TRUE(iterator != nullptr); + EXPECT_EQ(iterator->Count(), 0u); + EXPECT_FALSE(iterator->Next(exPanId)); + iterator->Release(); + } +} + +TEST_F(TestDefaultThreadNetworkDirectoryStorage, TestStorageOverflow) +{ + // Fill up the storage to capacity + uint8_t dataset[] = { 42 }; + for (uint64_t id = 0; id < storage.Capacity(); id++) + { + EXPECT_EQ(storage.AddOrUpdateNetwork(ThreadNetworkDirectoryStorage::ExtendedPanId(id), ByteSpan(dataset)), CHIP_NO_ERROR); + } + + // Capacity limit should be enforced + const ThreadNetworkDirectoryStorage::ExtendedPanId exPanId(UINT64_C(0xd00fd00fdeadbeef)); + EXPECT_EQ(storage.AddOrUpdateNetwork(exPanId, ByteSpan(dataset)), CHIP_ERROR_NO_MEMORY); + + // Updating an existing network is still possible + dataset[0] = 88; + EXPECT_EQ(storage.AddOrUpdateNetwork(ThreadNetworkDirectoryStorage::ExtendedPanId(0u), ByteSpan(dataset)), CHIP_NO_ERROR); +} + +TEST_F(TestDefaultThreadNetworkDirectoryStorage, TestAddNetworkStorageFailure) +{ + const ThreadNetworkDirectoryStorage::ExtendedPanId panA(UINT64_C(0xd00fd00fdeadbeef)); + const uint8_t datasetA[] = { 1 }; + const ThreadNetworkDirectoryStorage::ExtendedPanId panB(UINT64_C(0xe475cafef00df00d)); + uint8_t datasetB[] = { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 }; + + EXPECT_EQ(storage.AddOrUpdateNetwork(panA, ByteSpan(datasetA)), CHIP_NO_ERROR); + + // Make the storage delegate return CHIP_ERROR_PERSISTED_STORAGE_FAILED for writes. + // Attempting to add a network should fail and state should be unaffected. + persistentStorageDelegate.SetRejectWrites(true); + EXPECT_EQ(storage.AddOrUpdateNetwork(panB, ByteSpan(datasetB)), CHIP_ERROR_PERSISTED_STORAGE_FAILED); + EXPECT_TRUE(storage.ContainsNetwork(panA)); + EXPECT_FALSE(storage.ContainsNetwork(panB)); + { + auto * iterator = storage.IterateNetworkIds(); + EXPECT_EQ(iterator->Count(), 1u); + iterator->Release(); + } +} + +TEST_F(TestDefaultThreadNetworkDirectoryStorage, TestAddNetworkStorageWriteIndexFailure) +{ + const ThreadNetworkDirectoryStorage::ExtendedPanId panA(UINT64_C(0xd00fd00fdeadbeef)); + const uint8_t datasetA[] = { 1 }; + const ThreadNetworkDirectoryStorage::ExtendedPanId panB(UINT64_C(0xe475cafef00df00d)); + uint8_t datasetB[] = { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 }; + + EXPECT_EQ(storage.AddOrUpdateNetwork(panA, ByteSpan(datasetA)), CHIP_NO_ERROR); + + // White box test: Poison the index key specifically, so the dataset + // can be written but the subsequent update of the index fails. + // Attempting to add a network should fail and state should be unaffected. + StorageKeyName indexKey = DefaultStorageKeyAllocator::ThreadNetworkDirectoryIndex(); + persistentStorageDelegate.AddPoisonKey(indexKey.KeyName()); + EXPECT_EQ(storage.AddOrUpdateNetwork(panB, ByteSpan(datasetB)), CHIP_ERROR_PERSISTED_STORAGE_FAILED); + EXPECT_TRUE(storage.ContainsNetwork(panA)); + EXPECT_FALSE(storage.ContainsNetwork(panB)); + { + auto * iterator = storage.IterateNetworkIds(); + EXPECT_EQ(iterator->Count(), 1u); + iterator->Release(); + } +} + +TEST_F(TestDefaultThreadNetworkDirectoryStorage, TestRemoveNetworkStorageFailure) +{ + const ThreadNetworkDirectoryStorage::ExtendedPanId panA(UINT64_C(0xd00f0001)); + const ThreadNetworkDirectoryStorage::ExtendedPanId panB(UINT64_C(0xd00f0002)); + const ThreadNetworkDirectoryStorage::ExtendedPanId panC(UINT64_C(0xd00f0003)); + const uint8_t dataset[] = { 1 }; + + // Just in case the test is compiled with CHIP_CONFIG_MAX_FABRICS == 1 + bool canStorePanC = (storage.Capacity() >= 3); + + // Add Pans A, B, and C + EXPECT_EQ(storage.AddOrUpdateNetwork(panA, ByteSpan(dataset)), CHIP_NO_ERROR); + EXPECT_EQ(storage.AddOrUpdateNetwork(panB, ByteSpan(dataset)), CHIP_NO_ERROR); + if (canStorePanC) + { + EXPECT_EQ(storage.AddOrUpdateNetwork(panC, ByteSpan(dataset)), CHIP_NO_ERROR); + } + + // Make the storage delegate return CHIP_ERROR_PERSISTED_STORAGE_FAILED for writes. + // Attempting to remove a network should fail and state should be unaffected. + persistentStorageDelegate.SetRejectWrites(true); + EXPECT_EQ(storage.RemoveNetwork(panA), CHIP_ERROR_PERSISTED_STORAGE_FAILED); + EXPECT_TRUE(storage.ContainsNetwork(panA)); + EXPECT_TRUE(storage.ContainsNetwork(panB)); + if (canStorePanC) + { + EXPECT_TRUE(storage.ContainsNetwork(panC)); + } + { + auto * iterator = storage.IterateNetworkIds(); + EXPECT_EQ(iterator->Count(), canStorePanC ? 3u : 2u); + iterator->Release(); + } +} + +} // namespace diff --git a/src/app/zap-templates/zcl/data-model/chip/matter-devices.xml b/src/app/zap-templates/zcl/data-model/chip/matter-devices.xml index ce12fb58abb9f5..f0266fffecb872 100644 --- a/src/app/zap-templates/zcl/data-model/chip/matter-devices.xml +++ b/src/app/zap-templates/zcl/data-model/chip/matter-devices.xml @@ -2426,6 +2426,7 @@ limitations under the License. Endpoint + diff --git a/src/app/zap-templates/zcl/data-model/chip/thread-network-directory-cluster.xml b/src/app/zap-templates/zcl/data-model/chip/thread-network-directory-cluster.xml index f802b7ab4452c0..e97cbc931e6b0e 100644 --- a/src/app/zap-templates/zcl/data-model/chip/thread-network-directory-cluster.xml +++ b/src/app/zap-templates/zcl/data-model/chip/thread-network-directory-cluster.xml @@ -19,9 +19,10 @@ limitations under the License. - + + @@ -37,7 +38,7 @@ limitations under the License. - + PreferredExtendedPanID @@ -56,22 +57,16 @@ limitations under the License. Removes an entry from the ThreadNetworks list. - + Retrieves a Thread Operational Dataset from the ThreadNetworks list. - + This is the response to a GetOperationalDataset request. - - - This event SHALL be generated when an entry in ThreadNetworks is added, removed, or had its Operational Dataset changed. - - - diff --git a/src/app/zap-templates/zcl/zcl-with-test-extensions.json b/src/app/zap-templates/zcl/zcl-with-test-extensions.json index 3b11954f1582b0..1a76205be885f9 100644 --- a/src/app/zap-templates/zcl/zcl-with-test-extensions.json +++ b/src/app/zap-templates/zcl/zcl-with-test-extensions.json @@ -645,7 +645,12 @@ "Valve Configuration and Control": ["RemainingDuration"], "Boolean State Configuration": ["CurrentSensitivityLevel"], "Water Heater Mode": ["SupportedModes", "CurrentMode", "FeatureMap"], - "Wi-Fi Network Management": ["SSID"] + "Wi-Fi Network Management": ["SSID"], + "Thread Network Directory": [ + "PreferredExtendedPanID", + "ThreadNetworks", + "ThreadNetworkTableSize" + ] }, "defaultReportingPolicy": "mandatory", "ZCLDataTypes": ["ARRAY", "BITMAP", "ENUM", "NUMBER", "STRING", "STRUCT"], diff --git a/src/app/zap-templates/zcl/zcl.json b/src/app/zap-templates/zcl/zcl.json index b03da7bc7b1e67..5388a12156601a 100644 --- a/src/app/zap-templates/zcl/zcl.json +++ b/src/app/zap-templates/zcl/zcl.json @@ -643,7 +643,12 @@ "Valve Configuration and Control": ["RemainingDuration"], "Boolean State Configuration": ["CurrentSensitivityLevel"], "Water Heater Mode": ["SupportedModes", "CurrentMode", "FeatureMap"], - "Wi-Fi Network Management": ["SSID"] + "Wi-Fi Network Management": ["SSID"], + "Thread Network Directory": [ + "PreferredExtendedPanID", + "ThreadNetworks", + "ThreadNetworkTableSize" + ] }, "defaultReportingPolicy": "mandatory", "ZCLDataTypes": ["ARRAY", "BITMAP", "ENUM", "NUMBER", "STRING", "STRUCT"], diff --git a/src/app/zap_cluster_list.json b/src/app/zap_cluster_list.json index dc324968991adc..00bcb55adb90a7 100644 --- a/src/app/zap_cluster_list.json +++ b/src/app/zap_cluster_list.json @@ -117,6 +117,7 @@ "THERMOSTAT_USER_INTERFACE_CONFIGURATION_CLUSTER": [], "THREAD_BORDER_ROUTER_MANAGEMENT_CLUSTER": [], "THREAD_NETWORK_DIAGNOSTICS_CLUSTER": [], + "THREAD_NETWORK_DIRECTORY_CLUSTER": [], "TIME_CLUSTER": [], "TIME_FORMAT_LOCALIZATION_CLUSTER": [], "TIME_SYNCHRONIZATION_CLUSTER": [], @@ -293,7 +294,7 @@ "THREAD_NETWORK_DIAGNOSTICS_CLUSTER": [ "thread-network-diagnostics-server" ], - "THREAD_NETWORK_DIRECTORY_CLUSTER": [], + "THREAD_NETWORK_DIRECTORY_CLUSTER": ["thread-network-directory-server"], "TIME_CLUSTER": [], "TIME_FORMAT_LOCALIZATION_CLUSTER": ["time-format-localization-server"], "TIME_SYNCHRONIZATION_CLUSTER": ["time-synchronization-server"], diff --git a/src/controller/data_model/controller-clusters.matter b/src/controller/data_model/controller-clusters.matter index 066f34e20d2731..48e39baf07f5dc 100644 --- a/src/controller/data_model/controller-clusters.matter +++ b/src/controller/data_model/controller-clusters.matter @@ -8168,16 +8168,13 @@ cluster ThreadNetworkDirectory = 1107 { revision 1; struct ThreadNetworkStruct { - int64u extendedPanID = 0; + octet_string<8> extendedPanID = 0; char_string<16> networkName = 1; int16u channel = 2; + int64u activeTimestamp = 3; } - info event access(read: operate) NetworkChanged = 0 { - int64u extendedPanID = 0; - } - - attribute access(read: manage, write: manage) nullable int64u preferredExtendedPanID = 0; + attribute access(read: manage, write: manage) nullable octet_string<8> preferredExtendedPanID = 0; readonly attribute access(read: operate) ThreadNetworkStruct threadNetworks[] = 1; readonly attribute int8u threadNetworkTableSize = 2; readonly attribute command_id generatedCommandList[] = 65528; @@ -8192,11 +8189,11 @@ cluster ThreadNetworkDirectory = 1107 { } request struct RemoveNetworkRequest { - int64u extendedPanID = 0; + octet_string<8> extendedPanID = 0; } request struct GetOperationalDatasetRequest { - int64u extendedPanID = 0; + octet_string<8> extendedPanID = 0; } response struct OperationalDatasetResponse = 3 { diff --git a/src/controller/data_model/controller-clusters.zap b/src/controller/data_model/controller-clusters.zap index 3c95a3320ba91b..ec4af6eeec7e0a 100644 --- a/src/controller/data_model/controller-clusters.zap +++ b/src/controller/data_model/controller-clusters.zap @@ -4816,6 +4816,82 @@ } ] }, + { + "name": "Thread Network Directory", + "code": 1107, + "mfgCode": null, + "define": "THREAD_NETWORK_DIRECTORY_CLUSTER", + "side": "client", + "enabled": 1, + "commands": [ + { + "name": "AddNetwork", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "RemoveNetwork", + "code": 1, + "mfgCode": null, + "source": "client", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "GetOperationalDataset", + "code": 2, + "mfgCode": null, + "source": "client", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "OperationalDatasetResponse", + "code": 3, + "mfgCode": null, + "source": "server", + "isIncoming": 1, + "isEnabled": 1 + } + ], + "attributes": [ + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "client", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "client", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, { "name": "Wake on LAN", "code": 1283, diff --git a/src/controller/java/generated/java/chip/devicecontroller/ChipClusters.java b/src/controller/java/generated/java/chip/devicecontroller/ChipClusters.java index 98e208fd3815ee..5369a5c42d4a26 100644 --- a/src/controller/java/generated/java/chip/devicecontroller/ChipClusters.java +++ b/src/controller/java/generated/java/chip/devicecontroller/ChipClusters.java @@ -54867,12 +54867,12 @@ public void onResponse(StructType invokeStructValue) { } - public void removeNetwork(DefaultClusterCallback callback, Long extendedPanID, int timedInvokeTimeoutMs) { + public void removeNetwork(DefaultClusterCallback callback, byte[] extendedPanID, int timedInvokeTimeoutMs) { final long commandId = 1L; ArrayList elements = new ArrayList<>(); final long extendedPanIDFieldID = 0L; - BaseTLVType extendedPanIDtlvValue = new UIntType(extendedPanID); + BaseTLVType extendedPanIDtlvValue = new ByteArrayType(extendedPanID); elements.add(new StructElement(extendedPanIDFieldID, extendedPanIDtlvValue)); StructType commandArgs = new StructType(elements); @@ -54884,12 +54884,12 @@ public void onResponse(StructType invokeStructValue) { } - public void getOperationalDataset(OperationalDatasetResponseCallback callback, Long extendedPanID, int timedInvokeTimeoutMs) { + public void getOperationalDataset(OperationalDatasetResponseCallback callback, byte[] extendedPanID, int timedInvokeTimeoutMs) { final long commandId = 2L; ArrayList elements = new ArrayList<>(); final long extendedPanIDFieldID = 0L; - BaseTLVType extendedPanIDtlvValue = new UIntType(extendedPanID); + BaseTLVType extendedPanIDtlvValue = new ByteArrayType(extendedPanID); elements.add(new StructElement(extendedPanIDFieldID, extendedPanIDtlvValue)); StructType commandArgs = new StructType(elements); @@ -54915,7 +54915,7 @@ public interface OperationalDatasetResponseCallback extends BaseClusterCallback } public interface PreferredExtendedPanIDAttributeCallback extends BaseAttributeCallback { - void onSuccess(@Nullable Long value); + void onSuccess(@Nullable byte[] value); } public interface ThreadNetworksAttributeCallback extends BaseAttributeCallback { @@ -54945,18 +54945,18 @@ public void readPreferredExtendedPanIDAttribute( readAttribute(new ReportCallbackImpl(callback, path) { @Override public void onSuccess(byte[] tlv) { - @Nullable Long value = ChipTLVValueDecoder.decodeAttributeValue(path, tlv); + @Nullable byte[] value = ChipTLVValueDecoder.decodeAttributeValue(path, tlv); callback.onSuccess(value); } }, PREFERRED_EXTENDED_PAN_I_D_ATTRIBUTE_ID, true); } - public void writePreferredExtendedPanIDAttribute(DefaultClusterCallback callback, Long value) { + public void writePreferredExtendedPanIDAttribute(DefaultClusterCallback callback, byte[] value) { writePreferredExtendedPanIDAttribute(callback, value, 0); } - public void writePreferredExtendedPanIDAttribute(DefaultClusterCallback callback, Long value, int timedWriteTimeoutMs) { - BaseTLVType tlvValue = value != null ? new UIntType(value) : new NullType(); + public void writePreferredExtendedPanIDAttribute(DefaultClusterCallback callback, byte[] value, int timedWriteTimeoutMs) { + BaseTLVType tlvValue = value != null ? new ByteArrayType(value) : new NullType(); writeAttribute(new WriteAttributesCallbackImpl(callback), PREFERRED_EXTENDED_PAN_I_D_ATTRIBUTE_ID, tlvValue, timedWriteTimeoutMs); } @@ -54967,7 +54967,7 @@ public void subscribePreferredExtendedPanIDAttribute( subscribeAttribute(new ReportCallbackImpl(callback, path) { @Override public void onSuccess(byte[] tlv) { - @Nullable Long value = ChipTLVValueDecoder.decodeAttributeValue(path, tlv); + @Nullable byte[] value = ChipTLVValueDecoder.decodeAttributeValue(path, tlv); callback.onSuccess(value); } }, PREFERRED_EXTENDED_PAN_I_D_ATTRIBUTE_ID, minInterval, maxInterval); diff --git a/src/controller/java/generated/java/chip/devicecontroller/ChipEventStructs.java b/src/controller/java/generated/java/chip/devicecontroller/ChipEventStructs.java index d256c91c32d9ed..6ab2b64ce65000 100644 --- a/src/controller/java/generated/java/chip/devicecontroller/ChipEventStructs.java +++ b/src/controller/java/generated/java/chip/devicecontroller/ChipEventStructs.java @@ -5614,52 +5614,6 @@ public String toString() { return output.toString(); } } -public static class ThreadNetworkDirectoryClusterNetworkChangedEvent { - public Long extendedPanID; - private static final long EXTENDED_PAN_I_D_ID = 0L; - - public ThreadNetworkDirectoryClusterNetworkChangedEvent( - Long extendedPanID - ) { - this.extendedPanID = extendedPanID; - } - - public StructType encodeTlv() { - ArrayList values = new ArrayList<>(); - values.add(new StructElement(EXTENDED_PAN_I_D_ID, new UIntType(extendedPanID))); - - return new StructType(values); - } - - public static ThreadNetworkDirectoryClusterNetworkChangedEvent decodeTlv(BaseTLVType tlvValue) { - if (tlvValue == null || tlvValue.type() != TLVType.Struct) { - return null; - } - Long extendedPanID = null; - for (StructElement element: ((StructType)tlvValue).value()) { - if (element.contextTagNum() == EXTENDED_PAN_I_D_ID) { - if (element.value(BaseTLVType.class).type() == TLVType.UInt) { - UIntType castingValue = element.value(UIntType.class); - extendedPanID = castingValue.value(Long.class); - } - } - } - return new ThreadNetworkDirectoryClusterNetworkChangedEvent( - extendedPanID - ); - } - - @Override - public String toString() { - StringBuilder output = new StringBuilder(); - output.append("ThreadNetworkDirectoryClusterNetworkChangedEvent {\n"); - output.append("\textendedPanID: "); - output.append(extendedPanID); - output.append("\n"); - output.append("}\n"); - return output.toString(); - } -} public static class TargetNavigatorClusterTargetUpdatedEvent { public ArrayList targetList; public Integer currentTarget; diff --git a/src/controller/java/generated/java/chip/devicecontroller/ChipStructs.java b/src/controller/java/generated/java/chip/devicecontroller/ChipStructs.java index 94bd7622678351..11cba416fb733c 100644 --- a/src/controller/java/generated/java/chip/devicecontroller/ChipStructs.java +++ b/src/controller/java/generated/java/chip/devicecontroller/ChipStructs.java @@ -10067,28 +10067,33 @@ public String toString() { } } public static class ThreadNetworkDirectoryClusterThreadNetworkStruct { - public Long extendedPanID; + public byte[] extendedPanID; public String networkName; public Integer channel; + public Long activeTimestamp; private static final long EXTENDED_PAN_I_D_ID = 0L; private static final long NETWORK_NAME_ID = 1L; private static final long CHANNEL_ID = 2L; + private static final long ACTIVE_TIMESTAMP_ID = 3L; public ThreadNetworkDirectoryClusterThreadNetworkStruct( - Long extendedPanID, + byte[] extendedPanID, String networkName, - Integer channel + Integer channel, + Long activeTimestamp ) { this.extendedPanID = extendedPanID; this.networkName = networkName; this.channel = channel; + this.activeTimestamp = activeTimestamp; } public StructType encodeTlv() { ArrayList values = new ArrayList<>(); - values.add(new StructElement(EXTENDED_PAN_I_D_ID, new UIntType(extendedPanID))); + values.add(new StructElement(EXTENDED_PAN_I_D_ID, new ByteArrayType(extendedPanID))); values.add(new StructElement(NETWORK_NAME_ID, new StringType(networkName))); values.add(new StructElement(CHANNEL_ID, new UIntType(channel))); + values.add(new StructElement(ACTIVE_TIMESTAMP_ID, new UIntType(activeTimestamp))); return new StructType(values); } @@ -10097,14 +10102,15 @@ public static ThreadNetworkDirectoryClusterThreadNetworkStruct decodeTlv(BaseTLV if (tlvValue == null || tlvValue.type() != TLVType.Struct) { return null; } - Long extendedPanID = null; + byte[] extendedPanID = null; String networkName = null; Integer channel = null; + Long activeTimestamp = null; for (StructElement element: ((StructType)tlvValue).value()) { if (element.contextTagNum() == EXTENDED_PAN_I_D_ID) { - if (element.value(BaseTLVType.class).type() == TLVType.UInt) { - UIntType castingValue = element.value(UIntType.class); - extendedPanID = castingValue.value(Long.class); + if (element.value(BaseTLVType.class).type() == TLVType.ByteArray) { + ByteArrayType castingValue = element.value(ByteArrayType.class); + extendedPanID = castingValue.value(byte[].class); } } else if (element.contextTagNum() == NETWORK_NAME_ID) { if (element.value(BaseTLVType.class).type() == TLVType.String) { @@ -10116,12 +10122,18 @@ public static ThreadNetworkDirectoryClusterThreadNetworkStruct decodeTlv(BaseTLV UIntType castingValue = element.value(UIntType.class); channel = castingValue.value(Integer.class); } + } else if (element.contextTagNum() == ACTIVE_TIMESTAMP_ID) { + if (element.value(BaseTLVType.class).type() == TLVType.UInt) { + UIntType castingValue = element.value(UIntType.class); + activeTimestamp = castingValue.value(Long.class); + } } } return new ThreadNetworkDirectoryClusterThreadNetworkStruct( extendedPanID, networkName, - channel + channel, + activeTimestamp ); } @@ -10130,7 +10142,7 @@ public String toString() { StringBuilder output = new StringBuilder(); output.append("ThreadNetworkDirectoryClusterThreadNetworkStruct {\n"); output.append("\textendedPanID: "); - output.append(extendedPanID); + output.append(Arrays.toString(extendedPanID)); output.append("\n"); output.append("\tnetworkName: "); output.append(networkName); @@ -10138,6 +10150,9 @@ public String toString() { output.append("\tchannel: "); output.append(channel); output.append("\n"); + output.append("\tactiveTimestamp: "); + output.append(activeTimestamp); + output.append("\n"); output.append("}\n"); return output.toString(); } diff --git a/src/controller/java/generated/java/chip/devicecontroller/ClusterIDMapping.java b/src/controller/java/generated/java/chip/devicecontroller/ClusterIDMapping.java index b733ca22822c88..fc0a28a6d4eb0c 100644 --- a/src/controller/java/generated/java/chip/devicecontroller/ClusterIDMapping.java +++ b/src/controller/java/generated/java/chip/devicecontroller/ClusterIDMapping.java @@ -14988,8 +14988,7 @@ public static Attribute value(long id) throws NoSuchFieldError { } } - public enum Event { - NetworkChanged(0L),; + public enum Event {; private final long id; Event(long id) { this.id = id; diff --git a/src/controller/java/generated/java/chip/devicecontroller/ClusterInfoMapping.java b/src/controller/java/generated/java/chip/devicecontroller/ClusterInfoMapping.java index 23dc3048a5fb3d..1538d4f47415ad 100644 --- a/src/controller/java/generated/java/chip/devicecontroller/ClusterInfoMapping.java +++ b/src/controller/java/generated/java/chip/devicecontroller/ClusterInfoMapping.java @@ -18117,9 +18117,9 @@ public void setCallbackDelegate(ClusterCommandCallback callback) { } @Override - public void onSuccess(@Nullable Long value) { + public void onSuccess(@Nullable byte[] value) { Map responseValues = new LinkedHashMap<>(); - CommandResponseInfo commandResponseInfo = new CommandResponseInfo("value", "Long"); + CommandResponseInfo commandResponseInfo = new CommandResponseInfo("value", "byte[]"); responseValues.put(commandResponseInfo, value); callback.onSuccess(responseValues); } @@ -27690,13 +27690,13 @@ public Map> getCommandMap() { Map threadNetworkDirectoryremoveNetworkCommandParams = new LinkedHashMap(); - CommandParameterInfo threadNetworkDirectoryremoveNetworkextendedPanIDCommandParameterInfo = new CommandParameterInfo("extendedPanID", Long.class, Long.class); + CommandParameterInfo threadNetworkDirectoryremoveNetworkextendedPanIDCommandParameterInfo = new CommandParameterInfo("extendedPanID", byte[].class, byte[].class); threadNetworkDirectoryremoveNetworkCommandParams.put("extendedPanID",threadNetworkDirectoryremoveNetworkextendedPanIDCommandParameterInfo); InteractionInfo threadNetworkDirectoryremoveNetworkInteractionInfo = new InteractionInfo( (cluster, callback, commandArguments) -> { ((ChipClusters.ThreadNetworkDirectoryCluster) cluster) .removeNetwork((DefaultClusterCallback) callback - , (Long) + , (byte[]) commandArguments.get("extendedPanID"), 10000 ); }, @@ -27707,13 +27707,13 @@ public Map> getCommandMap() { Map threadNetworkDirectorygetOperationalDatasetCommandParams = new LinkedHashMap(); - CommandParameterInfo threadNetworkDirectorygetOperationalDatasetextendedPanIDCommandParameterInfo = new CommandParameterInfo("extendedPanID", Long.class, Long.class); + CommandParameterInfo threadNetworkDirectorygetOperationalDatasetextendedPanIDCommandParameterInfo = new CommandParameterInfo("extendedPanID", byte[].class, byte[].class); threadNetworkDirectorygetOperationalDatasetCommandParams.put("extendedPanID",threadNetworkDirectorygetOperationalDatasetextendedPanIDCommandParameterInfo); InteractionInfo threadNetworkDirectorygetOperationalDatasetInteractionInfo = new InteractionInfo( (cluster, callback, commandArguments) -> { ((ChipClusters.ThreadNetworkDirectoryCluster) cluster) .getOperationalDataset((ChipClusters.ThreadNetworkDirectoryCluster.OperationalDatasetResponseCallback) callback - , (Long) + , (byte[]) commandArguments.get("extendedPanID") , 10000); diff --git a/src/controller/java/generated/java/chip/devicecontroller/ClusterWriteMapping.java b/src/controller/java/generated/java/chip/devicecontroller/ClusterWriteMapping.java index 715cb477319345..28cba2abd728f8 100644 --- a/src/controller/java/generated/java/chip/devicecontroller/ClusterWriteMapping.java +++ b/src/controller/java/generated/java/chip/devicecontroller/ClusterWriteMapping.java @@ -3717,8 +3717,8 @@ public Map> getWriteAttributeMap() { CommandParameterInfo threadNetworkDirectorypreferredExtendedPanIDCommandParameterInfo = new CommandParameterInfo( "value", - Long.class, - Long.class + byte[].class, + byte[].class ); writeThreadNetworkDirectoryPreferredExtendedPanIDCommandParams.put( "value", @@ -3728,7 +3728,7 @@ public Map> getWriteAttributeMap() { (cluster, callback, commandArguments) -> { ((ChipClusters.ThreadNetworkDirectoryCluster) cluster).writePreferredExtendedPanIDAttribute( (DefaultClusterCallback) callback, - (Long) commandArguments.get("value") + (byte[]) commandArguments.get("value") ); }, () -> new ClusterInfoMapping.DelegatedDefaultClusterCallback(), diff --git a/src/controller/java/generated/java/chip/devicecontroller/cluster/eventstructs/ThreadNetworkDirectoryClusterNetworkChangedEvent.kt b/src/controller/java/generated/java/chip/devicecontroller/cluster/eventstructs/ThreadNetworkDirectoryClusterNetworkChangedEvent.kt deleted file mode 100644 index b90c6e8126260b..00000000000000 --- a/src/controller/java/generated/java/chip/devicecontroller/cluster/eventstructs/ThreadNetworkDirectoryClusterNetworkChangedEvent.kt +++ /dev/null @@ -1,55 +0,0 @@ -/* - * - * Copyright (c) 2023 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. - */ -package chip.devicecontroller.cluster.eventstructs - -import chip.devicecontroller.cluster.* -import matter.tlv.ContextSpecificTag -import matter.tlv.Tag -import matter.tlv.TlvReader -import matter.tlv.TlvWriter - -class ThreadNetworkDirectoryClusterNetworkChangedEvent(val extendedPanID: ULong) { - override fun toString(): String = buildString { - append("ThreadNetworkDirectoryClusterNetworkChangedEvent {\n") - append("\textendedPanID : $extendedPanID\n") - append("}\n") - } - - fun toTlv(tlvTag: Tag, tlvWriter: TlvWriter) { - tlvWriter.apply { - startStructure(tlvTag) - put(ContextSpecificTag(TAG_EXTENDED_PAN_I_D), extendedPanID) - endStructure() - } - } - - companion object { - private const val TAG_EXTENDED_PAN_I_D = 0 - - fun fromTlv( - tlvTag: Tag, - tlvReader: TlvReader, - ): ThreadNetworkDirectoryClusterNetworkChangedEvent { - tlvReader.enterStructure(tlvTag) - val extendedPanID = tlvReader.getULong(ContextSpecificTag(TAG_EXTENDED_PAN_I_D)) - - tlvReader.exitContainer() - - return ThreadNetworkDirectoryClusterNetworkChangedEvent(extendedPanID) - } - } -} diff --git a/src/controller/java/generated/java/chip/devicecontroller/cluster/files.gni b/src/controller/java/generated/java/chip/devicecontroller/cluster/files.gni index c15fb2a01efd80..5a29a90b27372b 100644 --- a/src/controller/java/generated/java/chip/devicecontroller/cluster/files.gni +++ b/src/controller/java/generated/java/chip/devicecontroller/cluster/files.gni @@ -222,7 +222,6 @@ eventstructs_sources = [ "${chip_root}/src/controller/java/generated/java/chip/devicecontroller/cluster/eventstructs/TargetNavigatorClusterTargetUpdatedEvent.kt", "${chip_root}/src/controller/java/generated/java/chip/devicecontroller/cluster/eventstructs/ThreadNetworkDiagnosticsClusterConnectionStatusEvent.kt", "${chip_root}/src/controller/java/generated/java/chip/devicecontroller/cluster/eventstructs/ThreadNetworkDiagnosticsClusterNetworkFaultChangeEvent.kt", - "${chip_root}/src/controller/java/generated/java/chip/devicecontroller/cluster/eventstructs/ThreadNetworkDirectoryClusterNetworkChangedEvent.kt", "${chip_root}/src/controller/java/generated/java/chip/devicecontroller/cluster/eventstructs/TimeSynchronizationClusterDSTStatusEvent.kt", "${chip_root}/src/controller/java/generated/java/chip/devicecontroller/cluster/eventstructs/TimeSynchronizationClusterTimeZoneStatusEvent.kt", "${chip_root}/src/controller/java/generated/java/chip/devicecontroller/cluster/eventstructs/UnitTestingClusterTestDifferentVendorMeiEventEvent.kt", diff --git a/src/controller/java/generated/java/chip/devicecontroller/cluster/structs/ThreadNetworkDirectoryClusterThreadNetworkStruct.kt b/src/controller/java/generated/java/chip/devicecontroller/cluster/structs/ThreadNetworkDirectoryClusterThreadNetworkStruct.kt index 2ba4a216410ef3..ae988738b7be34 100644 --- a/src/controller/java/generated/java/chip/devicecontroller/cluster/structs/ThreadNetworkDirectoryClusterThreadNetworkStruct.kt +++ b/src/controller/java/generated/java/chip/devicecontroller/cluster/structs/ThreadNetworkDirectoryClusterThreadNetworkStruct.kt @@ -23,15 +23,17 @@ import matter.tlv.TlvReader import matter.tlv.TlvWriter class ThreadNetworkDirectoryClusterThreadNetworkStruct( - val extendedPanID: ULong, + val extendedPanID: ByteArray, val networkName: String, val channel: UInt, + val activeTimestamp: ULong, ) { override fun toString(): String = buildString { append("ThreadNetworkDirectoryClusterThreadNetworkStruct {\n") append("\textendedPanID : $extendedPanID\n") append("\tnetworkName : $networkName\n") append("\tchannel : $channel\n") + append("\tactiveTimestamp : $activeTimestamp\n") append("}\n") } @@ -41,6 +43,7 @@ class ThreadNetworkDirectoryClusterThreadNetworkStruct( put(ContextSpecificTag(TAG_EXTENDED_PAN_I_D), extendedPanID) put(ContextSpecificTag(TAG_NETWORK_NAME), networkName) put(ContextSpecificTag(TAG_CHANNEL), channel) + put(ContextSpecificTag(TAG_ACTIVE_TIMESTAMP), activeTimestamp) endStructure() } } @@ -49,19 +52,26 @@ class ThreadNetworkDirectoryClusterThreadNetworkStruct( private const val TAG_EXTENDED_PAN_I_D = 0 private const val TAG_NETWORK_NAME = 1 private const val TAG_CHANNEL = 2 + private const val TAG_ACTIVE_TIMESTAMP = 3 fun fromTlv( tlvTag: Tag, tlvReader: TlvReader, ): ThreadNetworkDirectoryClusterThreadNetworkStruct { tlvReader.enterStructure(tlvTag) - val extendedPanID = tlvReader.getULong(ContextSpecificTag(TAG_EXTENDED_PAN_I_D)) + val extendedPanID = tlvReader.getByteArray(ContextSpecificTag(TAG_EXTENDED_PAN_I_D)) val networkName = tlvReader.getString(ContextSpecificTag(TAG_NETWORK_NAME)) val channel = tlvReader.getUInt(ContextSpecificTag(TAG_CHANNEL)) + val activeTimestamp = tlvReader.getULong(ContextSpecificTag(TAG_ACTIVE_TIMESTAMP)) tlvReader.exitContainer() - return ThreadNetworkDirectoryClusterThreadNetworkStruct(extendedPanID, networkName, channel) + return ThreadNetworkDirectoryClusterThreadNetworkStruct( + extendedPanID, + networkName, + channel, + activeTimestamp, + ) } } } diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/ThreadNetworkDirectoryCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/ThreadNetworkDirectoryCluster.kt index 6bbf6ffe4f813c..e479f0c79ef0f2 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/ThreadNetworkDirectoryCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/ThreadNetworkDirectoryCluster.kt @@ -49,10 +49,10 @@ class ThreadNetworkDirectoryCluster( ) { class OperationalDatasetResponse(val operationalDataset: ByteArray) - class PreferredExtendedPanIDAttribute(val value: ULong?) + class PreferredExtendedPanIDAttribute(val value: ByteArray?) sealed class PreferredExtendedPanIDAttributeSubscriptionState { - data class Success(val value: ULong?) : PreferredExtendedPanIDAttributeSubscriptionState() + data class Success(val value: ByteArray?) : PreferredExtendedPanIDAttributeSubscriptionState() data class Error(val exception: Exception) : PreferredExtendedPanIDAttributeSubscriptionState() @@ -131,7 +131,7 @@ class ThreadNetworkDirectoryCluster( logger.log(Level.FINE, "Invoke command succeeded: ${response}") } - suspend fun removeNetwork(extendedPanID: ULong, timedInvokeTimeout: Duration) { + suspend fun removeNetwork(extendedPanID: ByteArray, timedInvokeTimeout: Duration) { val commandId: UInt = 1u val tlvWriter = TlvWriter() @@ -153,7 +153,7 @@ class ThreadNetworkDirectoryCluster( } suspend fun getOperationalDataset( - extendedPanID: ULong, + extendedPanID: ByteArray, timedInvokeTimeout: Duration, ): OperationalDatasetResponse { val commandId: UInt = 2u @@ -225,9 +225,9 @@ class ThreadNetworkDirectoryCluster( // Decode the TLV data into the appropriate type val tlvReader = TlvReader(attributeData.data) - val decodedValue: ULong? = + val decodedValue: ByteArray? = if (!tlvReader.isNull()) { - tlvReader.getULong(AnonymousTag) + tlvReader.getByteArray(AnonymousTag) } else { tlvReader.getNull(AnonymousTag) null @@ -237,7 +237,7 @@ class ThreadNetworkDirectoryCluster( } suspend fun writePreferredExtendedPanIDAttribute( - value: ULong, + value: ByteArray, timedWriteTimeout: Duration? = null, ) { val ATTRIBUTE_ID: UInt = 0u @@ -320,9 +320,9 @@ class ThreadNetworkDirectoryCluster( // Decode the TLV data into the appropriate type val tlvReader = TlvReader(attributeData.data) - val decodedValue: ULong? = + val decodedValue: ByteArray? = if (!tlvReader.isNull()) { - tlvReader.getULong(AnonymousTag) + tlvReader.getByteArray(AnonymousTag) } else { tlvReader.getNull(AnonymousTag) null diff --git a/src/controller/java/generated/java/matter/controller/cluster/eventstructs/ThreadNetworkDirectoryClusterNetworkChangedEvent.kt b/src/controller/java/generated/java/matter/controller/cluster/eventstructs/ThreadNetworkDirectoryClusterNetworkChangedEvent.kt deleted file mode 100644 index a5b1f26621002e..00000000000000 --- a/src/controller/java/generated/java/matter/controller/cluster/eventstructs/ThreadNetworkDirectoryClusterNetworkChangedEvent.kt +++ /dev/null @@ -1,55 +0,0 @@ -/* - * - * Copyright (c) 2023 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. - */ -package matter.controller.cluster.eventstructs - -import matter.controller.cluster.* -import matter.tlv.ContextSpecificTag -import matter.tlv.Tag -import matter.tlv.TlvReader -import matter.tlv.TlvWriter - -class ThreadNetworkDirectoryClusterNetworkChangedEvent(val extendedPanID: ULong) { - override fun toString(): String = buildString { - append("ThreadNetworkDirectoryClusterNetworkChangedEvent {\n") - append("\textendedPanID : $extendedPanID\n") - append("}\n") - } - - fun toTlv(tlvTag: Tag, tlvWriter: TlvWriter) { - tlvWriter.apply { - startStructure(tlvTag) - put(ContextSpecificTag(TAG_EXTENDED_PAN_I_D), extendedPanID) - endStructure() - } - } - - companion object { - private const val TAG_EXTENDED_PAN_I_D = 0 - - fun fromTlv( - tlvTag: Tag, - tlvReader: TlvReader, - ): ThreadNetworkDirectoryClusterNetworkChangedEvent { - tlvReader.enterStructure(tlvTag) - val extendedPanID = tlvReader.getULong(ContextSpecificTag(TAG_EXTENDED_PAN_I_D)) - - tlvReader.exitContainer() - - return ThreadNetworkDirectoryClusterNetworkChangedEvent(extendedPanID) - } - } -} diff --git a/src/controller/java/generated/java/matter/controller/cluster/files.gni b/src/controller/java/generated/java/matter/controller/cluster/files.gni index bf7839d661528d..ddb25414b6304d 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/files.gni +++ b/src/controller/java/generated/java/matter/controller/cluster/files.gni @@ -222,7 +222,6 @@ matter_eventstructs_sources = [ "${chip_root}/src/controller/java/generated/java/matter/controller/cluster/eventstructs/TargetNavigatorClusterTargetUpdatedEvent.kt", "${chip_root}/src/controller/java/generated/java/matter/controller/cluster/eventstructs/ThreadNetworkDiagnosticsClusterConnectionStatusEvent.kt", "${chip_root}/src/controller/java/generated/java/matter/controller/cluster/eventstructs/ThreadNetworkDiagnosticsClusterNetworkFaultChangeEvent.kt", - "${chip_root}/src/controller/java/generated/java/matter/controller/cluster/eventstructs/ThreadNetworkDirectoryClusterNetworkChangedEvent.kt", "${chip_root}/src/controller/java/generated/java/matter/controller/cluster/eventstructs/TimeSynchronizationClusterDSTStatusEvent.kt", "${chip_root}/src/controller/java/generated/java/matter/controller/cluster/eventstructs/TimeSynchronizationClusterTimeZoneStatusEvent.kt", "${chip_root}/src/controller/java/generated/java/matter/controller/cluster/eventstructs/UnitTestingClusterTestDifferentVendorMeiEventEvent.kt", diff --git a/src/controller/java/generated/java/matter/controller/cluster/structs/ThreadNetworkDirectoryClusterThreadNetworkStruct.kt b/src/controller/java/generated/java/matter/controller/cluster/structs/ThreadNetworkDirectoryClusterThreadNetworkStruct.kt index db8dbbb0324745..bacfb457534ddd 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/structs/ThreadNetworkDirectoryClusterThreadNetworkStruct.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/structs/ThreadNetworkDirectoryClusterThreadNetworkStruct.kt @@ -23,15 +23,17 @@ import matter.tlv.TlvReader import matter.tlv.TlvWriter class ThreadNetworkDirectoryClusterThreadNetworkStruct( - val extendedPanID: ULong, + val extendedPanID: ByteArray, val networkName: String, val channel: UShort, + val activeTimestamp: ULong, ) { override fun toString(): String = buildString { append("ThreadNetworkDirectoryClusterThreadNetworkStruct {\n") append("\textendedPanID : $extendedPanID\n") append("\tnetworkName : $networkName\n") append("\tchannel : $channel\n") + append("\tactiveTimestamp : $activeTimestamp\n") append("}\n") } @@ -41,6 +43,7 @@ class ThreadNetworkDirectoryClusterThreadNetworkStruct( put(ContextSpecificTag(TAG_EXTENDED_PAN_I_D), extendedPanID) put(ContextSpecificTag(TAG_NETWORK_NAME), networkName) put(ContextSpecificTag(TAG_CHANNEL), channel) + put(ContextSpecificTag(TAG_ACTIVE_TIMESTAMP), activeTimestamp) endStructure() } } @@ -49,19 +52,26 @@ class ThreadNetworkDirectoryClusterThreadNetworkStruct( private const val TAG_EXTENDED_PAN_I_D = 0 private const val TAG_NETWORK_NAME = 1 private const val TAG_CHANNEL = 2 + private const val TAG_ACTIVE_TIMESTAMP = 3 fun fromTlv( tlvTag: Tag, tlvReader: TlvReader, ): ThreadNetworkDirectoryClusterThreadNetworkStruct { tlvReader.enterStructure(tlvTag) - val extendedPanID = tlvReader.getULong(ContextSpecificTag(TAG_EXTENDED_PAN_I_D)) + val extendedPanID = tlvReader.getByteArray(ContextSpecificTag(TAG_EXTENDED_PAN_I_D)) val networkName = tlvReader.getString(ContextSpecificTag(TAG_NETWORK_NAME)) val channel = tlvReader.getUShort(ContextSpecificTag(TAG_CHANNEL)) + val activeTimestamp = tlvReader.getULong(ContextSpecificTag(TAG_ACTIVE_TIMESTAMP)) tlvReader.exitContainer() - return ThreadNetworkDirectoryClusterThreadNetworkStruct(extendedPanID, networkName, channel) + return ThreadNetworkDirectoryClusterThreadNetworkStruct( + extendedPanID, + networkName, + channel, + activeTimestamp, + ) } } } diff --git a/src/controller/java/zap-generated/CHIPAttributeTLVValueDecoder.cpp b/src/controller/java/zap-generated/CHIPAttributeTLVValueDecoder.cpp index 9d1d0bd1bb65a3..cff767b424b59d 100644 --- a/src/controller/java/zap-generated/CHIPAttributeTLVValueDecoder.cpp +++ b/src/controller/java/zap-generated/CHIPAttributeTLVValueDecoder.cpp @@ -38832,11 +38832,10 @@ jobject DecodeAttributeValue(const app::ConcreteAttributePath & aPath, TLV::TLVR } else { - std::string valueClassName = "java/lang/Long"; - std::string valueCtorSignature = "(J)V"; - jlong jnivalue = static_cast(cppValue.Value()); - chip::JniReferences::GetInstance().CreateBoxedObject(valueClassName.c_str(), valueCtorSignature.c_str(), - jnivalue, value); + jbyteArray valueByteArray = env->NewByteArray(static_cast(cppValue.Value().size())); + env->SetByteArrayRegion(valueByteArray, 0, static_cast(cppValue.Value().size()), + reinterpret_cast(cppValue.Value().data())); + value = valueByteArray; } return value; } @@ -38857,12 +38856,11 @@ jobject DecodeAttributeValue(const app::ConcreteAttributePath & aPath, TLV::TLVR auto & entry_0 = iter_value_0.GetValue(); jobject newElement_0; jobject newElement_0_extendedPanID; - std::string newElement_0_extendedPanIDClassName = "java/lang/Long"; - std::string newElement_0_extendedPanIDCtorSignature = "(J)V"; - jlong jninewElement_0_extendedPanID = static_cast(entry_0.extendedPanID); - chip::JniReferences::GetInstance().CreateBoxedObject( - newElement_0_extendedPanIDClassName.c_str(), newElement_0_extendedPanIDCtorSignature.c_str(), - jninewElement_0_extendedPanID, newElement_0_extendedPanID); + jbyteArray newElement_0_extendedPanIDByteArray = + env->NewByteArray(static_cast(entry_0.extendedPanID.size())); + env->SetByteArrayRegion(newElement_0_extendedPanIDByteArray, 0, static_cast(entry_0.extendedPanID.size()), + reinterpret_cast(entry_0.extendedPanID.data())); + newElement_0_extendedPanID = newElement_0_extendedPanIDByteArray; jobject newElement_0_networkName; LogErrorOnFailure( chip::JniReferences::GetInstance().CharToStringUTF(entry_0.networkName, newElement_0_networkName)); @@ -38873,6 +38871,13 @@ jobject DecodeAttributeValue(const app::ConcreteAttributePath & aPath, TLV::TLVR chip::JniReferences::GetInstance().CreateBoxedObject(newElement_0_channelClassName.c_str(), newElement_0_channelCtorSignature.c_str(), jninewElement_0_channel, newElement_0_channel); + jobject newElement_0_activeTimestamp; + std::string newElement_0_activeTimestampClassName = "java/lang/Long"; + std::string newElement_0_activeTimestampCtorSignature = "(J)V"; + jlong jninewElement_0_activeTimestamp = static_cast(entry_0.activeTimestamp); + chip::JniReferences::GetInstance().CreateBoxedObject( + newElement_0_activeTimestampClassName.c_str(), newElement_0_activeTimestampCtorSignature.c_str(), + jninewElement_0_activeTimestamp, newElement_0_activeTimestamp); jclass threadNetworkStructStructClass_1; err = chip::JniReferences::GetInstance().GetLocalClassRef( @@ -38886,7 +38891,7 @@ jobject DecodeAttributeValue(const app::ConcreteAttributePath & aPath, TLV::TLVR jmethodID threadNetworkStructStructCtor_1; err = chip::JniReferences::GetInstance().FindMethod(env, threadNetworkStructStructClass_1, "", - "(Ljava/lang/Long;Ljava/lang/String;Ljava/lang/Integer;)V", + "([BLjava/lang/String;Ljava/lang/Integer;Ljava/lang/Long;)V", &threadNetworkStructStructCtor_1); if (err != CHIP_NO_ERROR || threadNetworkStructStructCtor_1 == nullptr) { @@ -38894,8 +38899,9 @@ jobject DecodeAttributeValue(const app::ConcreteAttributePath & aPath, TLV::TLVR return nullptr; } - newElement_0 = env->NewObject(threadNetworkStructStructClass_1, threadNetworkStructStructCtor_1, - newElement_0_extendedPanID, newElement_0_networkName, newElement_0_channel); + newElement_0 = + env->NewObject(threadNetworkStructStructClass_1, threadNetworkStructStructCtor_1, newElement_0_extendedPanID, + newElement_0_networkName, newElement_0_channel, newElement_0_activeTimestamp); chip::JniReferences::GetInstance().AddToList(value, newElement_0); } return value; diff --git a/src/controller/java/zap-generated/CHIPEventTLVValueDecoder.cpp b/src/controller/java/zap-generated/CHIPEventTLVValueDecoder.cpp index 789e3ea5f1310e..0dbed58b4b93d3 100644 --- a/src/controller/java/zap-generated/CHIPEventTLVValueDecoder.cpp +++ b/src/controller/java/zap-generated/CHIPEventTLVValueDecoder.cpp @@ -7481,44 +7481,6 @@ jobject DecodeEventValue(const app::ConcreteEventPath & aPath, TLV::TLVReader & using namespace app::Clusters::ThreadNetworkDirectory; switch (aPath.mEventId) { - case Events::NetworkChanged::Id: { - Events::NetworkChanged::DecodableType cppValue; - *aError = app::DataModel::Decode(aReader, cppValue); - if (*aError != CHIP_NO_ERROR) - { - return nullptr; - } - jobject value_extendedPanID; - std::string value_extendedPanIDClassName = "java/lang/Long"; - std::string value_extendedPanIDCtorSignature = "(J)V"; - jlong jnivalue_extendedPanID = static_cast(cppValue.extendedPanID); - chip::JniReferences::GetInstance().CreateBoxedObject(value_extendedPanIDClassName.c_str(), - value_extendedPanIDCtorSignature.c_str(), - jnivalue_extendedPanID, value_extendedPanID); - - jclass networkChangedStructClass; - err = chip::JniReferences::GetInstance().GetLocalClassRef( - env, "chip/devicecontroller/ChipEventStructs$ThreadNetworkDirectoryClusterNetworkChangedEvent", - networkChangedStructClass); - if (err != CHIP_NO_ERROR) - { - ChipLogError(Zcl, "Could not find class ChipEventStructs$ThreadNetworkDirectoryClusterNetworkChangedEvent"); - return nullptr; - } - - jmethodID networkChangedStructCtor; - err = chip::JniReferences::GetInstance().FindMethod(env, networkChangedStructClass, "", "(Ljava/lang/Long;)V", - &networkChangedStructCtor); - if (err != CHIP_NO_ERROR || networkChangedStructCtor == nullptr) - { - ChipLogError(Zcl, "Could not find ChipEventStructs$ThreadNetworkDirectoryClusterNetworkChangedEvent constructor"); - return nullptr; - } - - jobject value = env->NewObject(networkChangedStructClass, networkChangedStructCtor, value_extendedPanID); - - return value; - } default: *aError = CHIP_ERROR_IM_MALFORMED_EVENT_PATH_IB; break; diff --git a/src/controller/python/chip/clusters/CHIPClusters.py b/src/controller/python/chip/clusters/CHIPClusters.py index 1901351596228a..3b77856a4121d2 100644 --- a/src/controller/python/chip/clusters/CHIPClusters.py +++ b/src/controller/python/chip/clusters/CHIPClusters.py @@ -11989,14 +11989,14 @@ class ChipClusters: "commandId": 0x00000001, "commandName": "RemoveNetwork", "args": { - "extendedPanID": "int", + "extendedPanID": "bytes", }, }, 0x00000002: { "commandId": 0x00000002, "commandName": "GetOperationalDataset", "args": { - "extendedPanID": "int", + "extendedPanID": "bytes", }, }, }, @@ -12004,7 +12004,7 @@ class ChipClusters: 0x00000000: { "attributeName": "PreferredExtendedPanID", "attributeId": 0x00000000, - "type": "int", + "type": "bytes", "reportable": True, "writable": True, }, diff --git a/src/controller/python/chip/clusters/Objects.py b/src/controller/python/chip/clusters/Objects.py index 7b0c4a0cd6bc37..52e2be80aa74f5 100644 --- a/src/controller/python/chip/clusters/Objects.py +++ b/src/controller/python/chip/clusters/Objects.py @@ -42011,7 +42011,7 @@ class ThreadNetworkDirectory(Cluster): def descriptor(cls) -> ClusterObjectDescriptor: return ClusterObjectDescriptor( Fields=[ - ClusterObjectFieldDescriptor(Label="preferredExtendedPanID", Tag=0x00000000, Type=typing.Union[Nullable, uint]), + ClusterObjectFieldDescriptor(Label="preferredExtendedPanID", Tag=0x00000000, Type=typing.Union[Nullable, bytes]), ClusterObjectFieldDescriptor(Label="threadNetworks", Tag=0x00000001, Type=typing.List[ThreadNetworkDirectory.Structs.ThreadNetworkStruct]), ClusterObjectFieldDescriptor(Label="threadNetworkTableSize", Tag=0x00000002, Type=uint), ClusterObjectFieldDescriptor(Label="generatedCommandList", Tag=0x0000FFF8, Type=typing.List[uint]), @@ -42022,7 +42022,7 @@ def descriptor(cls) -> ClusterObjectDescriptor: ClusterObjectFieldDescriptor(Label="clusterRevision", Tag=0x0000FFFD, Type=uint), ]) - preferredExtendedPanID: 'typing.Union[Nullable, uint]' = None + preferredExtendedPanID: 'typing.Union[Nullable, bytes]' = None threadNetworks: 'typing.List[ThreadNetworkDirectory.Structs.ThreadNetworkStruct]' = None threadNetworkTableSize: 'uint' = None generatedCommandList: 'typing.List[uint]' = None @@ -42039,14 +42039,16 @@ class ThreadNetworkStruct(ClusterObject): def descriptor(cls) -> ClusterObjectDescriptor: return ClusterObjectDescriptor( Fields=[ - ClusterObjectFieldDescriptor(Label="extendedPanID", Tag=0, Type=uint), + ClusterObjectFieldDescriptor(Label="extendedPanID", Tag=0, Type=bytes), ClusterObjectFieldDescriptor(Label="networkName", Tag=1, Type=str), ClusterObjectFieldDescriptor(Label="channel", Tag=2, Type=uint), + ClusterObjectFieldDescriptor(Label="activeTimestamp", Tag=3, Type=uint), ]) - extendedPanID: 'uint' = 0 + extendedPanID: 'bytes' = b"" networkName: 'str' = "" channel: 'uint' = 0 + activeTimestamp: 'uint' = 0 class Commands: @dataclass @@ -42080,14 +42082,14 @@ class RemoveNetwork(ClusterCommand): def descriptor(cls) -> ClusterObjectDescriptor: return ClusterObjectDescriptor( Fields=[ - ClusterObjectFieldDescriptor(Label="extendedPanID", Tag=0, Type=uint), + ClusterObjectFieldDescriptor(Label="extendedPanID", Tag=0, Type=bytes), ]) @ChipUtility.classproperty def must_use_timed_invoke(cls) -> bool: return True - extendedPanID: 'uint' = 0 + extendedPanID: 'bytes' = b"" @dataclass class GetOperationalDataset(ClusterCommand): @@ -42100,14 +42102,14 @@ class GetOperationalDataset(ClusterCommand): def descriptor(cls) -> ClusterObjectDescriptor: return ClusterObjectDescriptor( Fields=[ - ClusterObjectFieldDescriptor(Label="extendedPanID", Tag=0, Type=uint), + ClusterObjectFieldDescriptor(Label="extendedPanID", Tag=0, Type=bytes), ]) @ChipUtility.classproperty def must_use_timed_invoke(cls) -> bool: return True - extendedPanID: 'uint' = 0 + extendedPanID: 'bytes' = b"" @dataclass class OperationalDatasetResponse(ClusterCommand): @@ -42138,9 +42140,9 @@ def attribute_id(cls) -> int: @ChipUtility.classproperty def attribute_type(cls) -> ClusterObjectFieldDescriptor: - return ClusterObjectFieldDescriptor(Type=typing.Union[Nullable, uint]) + return ClusterObjectFieldDescriptor(Type=typing.Union[Nullable, bytes]) - value: 'typing.Union[Nullable, uint]' = NullValue + value: 'typing.Union[Nullable, bytes]' = NullValue @dataclass class ThreadNetworks(ClusterAttributeDescriptor): @@ -42270,26 +42272,6 @@ def attribute_type(cls) -> ClusterObjectFieldDescriptor: value: 'uint' = 0 - class Events: - @dataclass - class NetworkChanged(ClusterEvent): - @ChipUtility.classproperty - def cluster_id(cls) -> int: - return 0x00000453 - - @ChipUtility.classproperty - def event_id(cls) -> int: - return 0x00000000 - - @ChipUtility.classproperty - def descriptor(cls) -> ClusterObjectDescriptor: - return ClusterObjectDescriptor( - Fields=[ - ClusterObjectFieldDescriptor(Label="extendedPanID", Tag=0, Type=uint), - ]) - - extendedPanID: 'uint' = 0 - @dataclass class WakeOnLan(Cluster): diff --git a/src/controller/python/chip/clusters/__init__.py b/src/controller/python/chip/clusters/__init__.py index 1aa2a61a8911d6..f633ca272a48a7 100644 --- a/src/controller/python/chip/clusters/__init__.py +++ b/src/controller/python/chip/clusters/__init__.py @@ -44,10 +44,10 @@ RefrigeratorAndTemperatureControlledCabinetMode, RelativeHumidityMeasurement, RvcCleanMode, RvcOperationalState, RvcRunMode, ScenesManagement, SmokeCoAlarm, SoftwareDiagnostics, Switch, TargetNavigator, TemperatureControl, TemperatureMeasurement, Thermostat, ThermostatUserInterfaceConfiguration, - ThreadBorderRouterManagement, ThreadNetworkDiagnostics, TimeFormatLocalization, TimeSynchronization, - TotalVolatileOrganicCompoundsConcentrationMeasurement, UnitLocalization, UnitTesting, UserLabel, - ValveConfigurationAndControl, WakeOnLan, WaterHeaterManagement, WaterHeaterMode, WiFiNetworkDiagnostics, - WindowCovering) + ThreadBorderRouterManagement, ThreadNetworkDiagnostics, ThreadNetworkDirectory, TimeFormatLocalization, + TimeSynchronization, TotalVolatileOrganicCompoundsConcentrationMeasurement, UnitLocalization, UnitTesting, + UserLabel, ValveConfigurationAndControl, WakeOnLan, WaterHeaterManagement, WaterHeaterMode, + WiFiNetworkDiagnostics, WindowCovering) __all__ = [Attribute, CHIPClusters, Command, AccessControl, AccountLogin, Actions, ActivatedCarbonFilterMonitoring, AdministratorCommissioning, AirQuality, ApplicationBasic, ApplicationLauncher, AudioOutput, BallastConfiguration, BarrierControl, BasicInformation, @@ -68,6 +68,6 @@ RefrigeratorAlarm, RefrigeratorAndTemperatureControlledCabinetMode, RelativeHumidityMeasurement, RvcCleanMode, RvcOperationalState, RvcRunMode, ScenesManagement, SmokeCoAlarm, SoftwareDiagnostics, Switch, TargetNavigator, TemperatureControl, TemperatureMeasurement, Thermostat, ThermostatUserInterfaceConfiguration, - ThreadBorderRouterManagement, ThreadNetworkDiagnostics, TimeFormatLocalization, TimeSynchronization, + ThreadBorderRouterManagement, ThreadNetworkDiagnostics, ThreadNetworkDirectory, TimeFormatLocalization, TimeSynchronization, TotalVolatileOrganicCompoundsConcentrationMeasurement, UnitLocalization, UnitTesting, UserLabel, ValveConfigurationAndControl, WakeOnLan, WaterHeaterManagement, WaterHeaterMode, WiFiNetworkDiagnostics, WindowCovering] diff --git a/src/darwin/Framework/CHIP/MTRDemuxingStorage.mm b/src/darwin/Framework/CHIP/MTRDemuxingStorage.mm index 4ce1a3a93a8f72..fff85f8eb4c3d2 100644 --- a/src/darwin/Framework/CHIP/MTRDemuxingStorage.mm +++ b/src/darwin/Framework/CHIP/MTRDemuxingStorage.mm @@ -167,6 +167,8 @@ static bool IsMemoryOnlyGlobalKey(NSString * key) // We do not expect to see the "g/icdfl" key; that's only used by // DefaultICDClientStorage, which Matter.framework does not use. + // We do not expect to see the "g/tnd/*" Thread Network Directory keys. + return false; } diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRAttributeTLVValueDecoder.mm b/src/darwin/Framework/CHIP/zap-generated/MTRAttributeTLVValueDecoder.mm index 96f5a211636050..26db9e819103af 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRAttributeTLVValueDecoder.mm +++ b/src/darwin/Framework/CHIP/zap-generated/MTRAttributeTLVValueDecoder.mm @@ -15779,11 +15779,11 @@ static id _Nullable DecodeAttributeValueForThreadNetworkDirectoryCluster(Attribu if (*aError != CHIP_NO_ERROR) { return nil; } - NSNumber * _Nullable value; + NSData * _Nullable value; if (cppValue.IsNull()) { value = nil; } else { - value = [NSNumber numberWithUnsignedLongLong:cppValue.Value()]; + value = AsData(cppValue.Value()); } return value; } @@ -15802,7 +15802,7 @@ static id _Nullable DecodeAttributeValueForThreadNetworkDirectoryCluster(Attribu auto & entry_0 = iter_0.GetValue(); MTRThreadNetworkDirectoryClusterThreadNetworkStruct * newElement_0; newElement_0 = [MTRThreadNetworkDirectoryClusterThreadNetworkStruct new]; - newElement_0.extendedPanID = [NSNumber numberWithUnsignedLongLong:entry_0.extendedPanID]; + newElement_0.extendedPanID = AsData(entry_0.extendedPanID); newElement_0.networkName = AsString(entry_0.networkName); if (newElement_0.networkName == nil) { CHIP_ERROR err = CHIP_ERROR_INVALID_ARGUMENT; @@ -15810,6 +15810,7 @@ static id _Nullable DecodeAttributeValueForThreadNetworkDirectoryCluster(Attribu return nil; } newElement_0.channel = [NSNumber numberWithUnsignedShort:entry_0.channel]; + newElement_0.activeTimestamp = [NSNumber numberWithUnsignedLongLong:entry_0.activeTimestamp]; [array_0 addObject:newElement_0]; } CHIP_ERROR err = iter_0.GetStatus(); diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.h b/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.h index 181d0c70408b24..91b6e9a65a2fc6 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.h +++ b/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.h @@ -13547,13 +13547,13 @@ MTR_PROVISIONALLY_AVAILABLE */ - (void)getOperationalDatasetWithParams:(MTRThreadNetworkDirectoryClusterGetOperationalDatasetParams *)params completion:(void (^)(MTRThreadNetworkDirectoryClusterOperationalDatasetResponseParams * _Nullable data, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; -- (void)readAttributePreferredExtendedPanIDWithCompletion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; -- (void)writeAttributePreferredExtendedPanIDWithValue:(NSNumber * _Nullable)value completion:(MTRStatusCompletion)completion MTR_PROVISIONALLY_AVAILABLE; -- (void)writeAttributePreferredExtendedPanIDWithValue:(NSNumber * _Nullable)value params:(MTRWriteParams * _Nullable)params completion:(MTRStatusCompletion)completion MTR_PROVISIONALLY_AVAILABLE; +- (void)readAttributePreferredExtendedPanIDWithCompletion:(void (^)(NSData * _Nullable value, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; +- (void)writeAttributePreferredExtendedPanIDWithValue:(NSData * _Nullable)value completion:(MTRStatusCompletion)completion MTR_PROVISIONALLY_AVAILABLE; +- (void)writeAttributePreferredExtendedPanIDWithValue:(NSData * _Nullable)value params:(MTRWriteParams * _Nullable)params completion:(MTRStatusCompletion)completion MTR_PROVISIONALLY_AVAILABLE; - (void)subscribeAttributePreferredExtendedPanIDWithParams:(MTRSubscribeParams *)params subscriptionEstablished:(MTRSubscriptionEstablishedHandler _Nullable)subscriptionEstablished - reportHandler:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))reportHandler MTR_PROVISIONALLY_AVAILABLE; -+ (void)readAttributePreferredExtendedPanIDWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer endpoint:(NSNumber *)endpoint queue:(dispatch_queue_t)queue completion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; + reportHandler:(void (^)(NSData * _Nullable value, NSError * _Nullable error))reportHandler MTR_PROVISIONALLY_AVAILABLE; ++ (void)readAttributePreferredExtendedPanIDWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer endpoint:(NSNumber *)endpoint queue:(dispatch_queue_t)queue completion:(void (^)(NSData * _Nullable value, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; - (void)readAttributeThreadNetworksWithCompletion:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; - (void)subscribeAttributeThreadNetworksWithParams:(MTRSubscribeParams *)params diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.mm b/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.mm index 6a15e501af9a7d..9aa9dbfab3dec4 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.mm +++ b/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.mm @@ -95301,7 +95301,7 @@ - (void)getOperationalDatasetWithParams:(MTRThreadNetworkDirectoryClusterGetOper completion:responseHandler]; } -- (void)readAttributePreferredExtendedPanIDWithCompletion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion +- (void)readAttributePreferredExtendedPanIDWithCompletion:(void (^)(NSData * _Nullable value, NSError * _Nullable error))completion { using TypeInfo = ThreadNetworkDirectory::Attributes::PreferredExtendedPanID::TypeInfo; [self.device _readKnownAttributeWithEndpointID:self.endpointID @@ -95312,11 +95312,11 @@ - (void)readAttributePreferredExtendedPanIDWithCompletion:(void (^)(NSNumber * _ completion:completion]; } -- (void)writeAttributePreferredExtendedPanIDWithValue:(NSNumber * _Nullable)value completion:(MTRStatusCompletion)completion +- (void)writeAttributePreferredExtendedPanIDWithValue:(NSData * _Nullable)value completion:(MTRStatusCompletion)completion { - [self writeAttributePreferredExtendedPanIDWithValue:(NSNumber * _Nullable) value params:nil completion:completion]; + [self writeAttributePreferredExtendedPanIDWithValue:(NSData * _Nullable) value params:nil completion:completion]; } -- (void)writeAttributePreferredExtendedPanIDWithValue:(NSNumber * _Nullable)value params:(MTRWriteParams * _Nullable)params completion:(MTRStatusCompletion)completion +- (void)writeAttributePreferredExtendedPanIDWithValue:(NSData * _Nullable)value params:(MTRWriteParams * _Nullable)params completion:(MTRStatusCompletion)completion { // Make a copy of params before we go async. params = [params copy]; @@ -95337,8 +95337,8 @@ - (void)writeAttributePreferredExtendedPanIDWithValue:(NSNumber * _Nullable)valu cppValue.SetNull(); } else { auto & nonNullValue_0 = cppValue.SetNonNull(); - nonNullValue_0 = value.unsignedLongLongValue; - } + nonNullValue_0 = AsByteSpan(value); + } chip::Controller::ClusterBase cppCluster(exchangeManager, session, self.endpointID.unsignedShortValue); return cppCluster.WriteAttribute(cppValue, bridge, successCb, failureCb, timedWriteTimeout); }); @@ -95347,7 +95347,7 @@ - (void)writeAttributePreferredExtendedPanIDWithValue:(NSNumber * _Nullable)valu - (void)subscribeAttributePreferredExtendedPanIDWithParams:(MTRSubscribeParams * _Nonnull)params subscriptionEstablished:(MTRSubscriptionEstablishedHandler _Nullable)subscriptionEstablished - reportHandler:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))reportHandler + reportHandler:(void (^)(NSData * _Nullable value, NSError * _Nullable error))reportHandler { using TypeInfo = ThreadNetworkDirectory::Attributes::PreferredExtendedPanID::TypeInfo; [self.device _subscribeToKnownAttributeWithEndpointID:self.endpointID @@ -95359,7 +95359,7 @@ - (void)subscribeAttributePreferredExtendedPanIDWithParams:(MTRSubscribeParams * subscriptionEstablished:subscriptionEstablished]; } -+ (void)readAttributePreferredExtendedPanIDWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer endpoint:(NSNumber *)endpoint queue:(dispatch_queue_t)queue completion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion ++ (void)readAttributePreferredExtendedPanIDWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer endpoint:(NSNumber *)endpoint queue:(dispatch_queue_t)queue completion:(void (^)(NSData * _Nullable value, NSError * _Nullable error))completion { using TypeInfo = ThreadNetworkDirectory::Attributes::PreferredExtendedPanID::TypeInfo; [clusterStateCacheContainer diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRClusterConstants.h b/src/darwin/Framework/CHIP/zap-generated/MTRClusterConstants.h index 445404818a9573..6c2978795cdafd 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRClusterConstants.h +++ b/src/darwin/Framework/CHIP/zap-generated/MTRClusterConstants.h @@ -7452,9 +7452,6 @@ typedef NS_ENUM(uint32_t, MTREventIDType) { MTREventIDTypeClusterPumpConfigurationAndControlEventAirDetectionID MTR_AVAILABLE(ios(16.4), macos(13.3), watchos(9.4), tvos(16.4)) = 0x0000000F, MTREventIDTypeClusterPumpConfigurationAndControlEventTurbineOperationID MTR_AVAILABLE(ios(16.4), macos(13.3), watchos(9.4), tvos(16.4)) = 0x00000010, - // Cluster ThreadNetworkDirectory events - MTREventIDTypeClusterThreadNetworkDirectoryEventNetworkChangedID MTR_PROVISIONALLY_AVAILABLE = 0x00000000, - // Cluster TargetNavigator deprecated event names // Cluster TargetNavigator events diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.h b/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.h index 7c30f13fbe7044..4bdab512cd6d77 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.h +++ b/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.h @@ -8950,7 +8950,7 @@ MTR_PROVISIONALLY_AVAILABLE MTR_PROVISIONALLY_AVAILABLE @interface MTRThreadNetworkDirectoryClusterRemoveNetworkParams : NSObject -@property (nonatomic, copy) NSNumber * _Nonnull extendedPanID MTR_PROVISIONALLY_AVAILABLE; +@property (nonatomic, copy) NSData * _Nonnull extendedPanID MTR_PROVISIONALLY_AVAILABLE; /** * Controls whether the command is a timed command (using Timed Invoke). * @@ -8980,7 +8980,7 @@ MTR_PROVISIONALLY_AVAILABLE MTR_PROVISIONALLY_AVAILABLE @interface MTRThreadNetworkDirectoryClusterGetOperationalDatasetParams : NSObject -@property (nonatomic, copy) NSNumber * _Nonnull extendedPanID MTR_PROVISIONALLY_AVAILABLE; +@property (nonatomic, copy) NSData * _Nonnull extendedPanID MTR_PROVISIONALLY_AVAILABLE; /** * Controls whether the command is a timed command (using Timed Invoke). * diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.mm b/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.mm index 441fc5cb8361cf..9f7ffd3a16b328 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.mm +++ b/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.mm @@ -25408,7 +25408,7 @@ - (instancetype)init { if (self = [super init]) { - _extendedPanID = @(0); + _extendedPanID = [NSData data]; _timedInvokeTimeoutMs = nil; _serverSideProcessingTimeout = nil; } @@ -25428,7 +25428,7 @@ - (id)copyWithZone:(NSZone * _Nullable)zone; - (NSString *)description { - NSString * descriptionString = [NSString stringWithFormat:@"<%@: extendedPanID:%@; >", NSStringFromClass([self class]), _extendedPanID]; + NSString * descriptionString = [NSString stringWithFormat:@"<%@: extendedPanID:%@; >", NSStringFromClass([self class]), [_extendedPanID base64EncodedStringWithOptions:0]]; return descriptionString; } @@ -25441,7 +25441,7 @@ - (CHIP_ERROR)_encodeToTLVReader:(chip::System::PacketBufferTLVReader &)reader chip::app::Clusters::ThreadNetworkDirectory::Commands::RemoveNetwork::Type encodableStruct; ListFreer listFreer; { - encodableStruct.extendedPanID = self.extendedPanID.unsignedLongLongValue; + encodableStruct.extendedPanID = AsByteSpan(self.extendedPanID); } auto buffer = chip::System::PacketBufferHandle::New(chip::System::PacketBuffer::kMaxSizeWithoutReserve, 0); @@ -25487,7 +25487,7 @@ - (instancetype)init { if (self = [super init]) { - _extendedPanID = @(0); + _extendedPanID = [NSData data]; _timedInvokeTimeoutMs = nil; _serverSideProcessingTimeout = nil; } @@ -25507,7 +25507,7 @@ - (id)copyWithZone:(NSZone * _Nullable)zone; - (NSString *)description { - NSString * descriptionString = [NSString stringWithFormat:@"<%@: extendedPanID:%@; >", NSStringFromClass([self class]), _extendedPanID]; + NSString * descriptionString = [NSString stringWithFormat:@"<%@: extendedPanID:%@; >", NSStringFromClass([self class]), [_extendedPanID base64EncodedStringWithOptions:0]]; return descriptionString; } @@ -25520,7 +25520,7 @@ - (CHIP_ERROR)_encodeToTLVReader:(chip::System::PacketBufferTLVReader &)reader chip::app::Clusters::ThreadNetworkDirectory::Commands::GetOperationalDataset::Type encodableStruct; ListFreer listFreer; { - encodableStruct.extendedPanID = self.extendedPanID.unsignedLongLongValue; + encodableStruct.extendedPanID = AsByteSpan(self.extendedPanID); } auto buffer = chip::System::PacketBufferHandle::New(chip::System::PacketBuffer::kMaxSizeWithoutReserve, 0); diff --git a/src/darwin/Framework/CHIP/zap-generated/MTREventTLVValueDecoder.mm b/src/darwin/Framework/CHIP/zap-generated/MTREventTLVValueDecoder.mm index 445807b9902bd8..e2fc7e70cba67b 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTREventTLVValueDecoder.mm +++ b/src/darwin/Framework/CHIP/zap-generated/MTREventTLVValueDecoder.mm @@ -4117,23 +4117,6 @@ static id _Nullable DecodeEventPayloadForThreadNetworkDirectoryCluster(EventId a { using namespace Clusters::ThreadNetworkDirectory; switch (aEventId) { - case Events::NetworkChanged::Id: { - Events::NetworkChanged::DecodableType cppValue; - *aError = DataModel::Decode(aReader, cppValue); - if (*aError != CHIP_NO_ERROR) { - return nil; - } - - __auto_type * value = [MTRThreadNetworkDirectoryClusterNetworkChangedEvent new]; - - do { - NSNumber * _Nonnull memberValue; - memberValue = [NSNumber numberWithUnsignedLongLong:cppValue.extendedPanID]; - value.extendedPanID = memberValue; - } while (0); - - return value; - } default: { break; } diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRStructsObjc.h b/src/darwin/Framework/CHIP/zap-generated/MTRStructsObjc.h index dd93b4322ad447..92f82f3496fca9 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRStructsObjc.h +++ b/src/darwin/Framework/CHIP/zap-generated/MTRStructsObjc.h @@ -1711,14 +1711,10 @@ MTR_PROVISIONALLY_AVAILABLE MTR_PROVISIONALLY_AVAILABLE @interface MTRThreadNetworkDirectoryClusterThreadNetworkStruct : NSObject -@property (nonatomic, copy) NSNumber * _Nonnull extendedPanID MTR_PROVISIONALLY_AVAILABLE; +@property (nonatomic, copy) NSData * _Nonnull extendedPanID MTR_PROVISIONALLY_AVAILABLE; @property (nonatomic, copy) NSString * _Nonnull networkName MTR_PROVISIONALLY_AVAILABLE; @property (nonatomic, copy) NSNumber * _Nonnull channel MTR_PROVISIONALLY_AVAILABLE; -@end - -MTR_PROVISIONALLY_AVAILABLE -@interface MTRThreadNetworkDirectoryClusterNetworkChangedEvent : NSObject -@property (nonatomic, copy) NSNumber * _Nonnull extendedPanID MTR_PROVISIONALLY_AVAILABLE; +@property (nonatomic, copy) NSNumber * _Nonnull activeTimestamp MTR_PROVISIONALLY_AVAILABLE; @end MTR_PROVISIONALLY_AVAILABLE diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRStructsObjc.mm b/src/darwin/Framework/CHIP/zap-generated/MTRStructsObjc.mm index 6fe345c0621baf..f0869bd61918fb 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRStructsObjc.mm +++ b/src/darwin/Framework/CHIP/zap-generated/MTRStructsObjc.mm @@ -7213,11 +7213,13 @@ - (instancetype)init { if (self = [super init]) { - _extendedPanID = @(0); + _extendedPanID = [NSData data]; _networkName = @""; _channel = @(0); + + _activeTimestamp = @(0); } return self; } @@ -7229,40 +7231,14 @@ - (id)copyWithZone:(NSZone * _Nullable)zone other.extendedPanID = self.extendedPanID; other.networkName = self.networkName; other.channel = self.channel; + other.activeTimestamp = self.activeTimestamp; return other; } - (NSString *)description { - NSString * descriptionString = [NSString stringWithFormat:@"<%@: extendedPanID:%@; networkName:%@; channel:%@; >", NSStringFromClass([self class]), _extendedPanID, _networkName, _channel]; - return descriptionString; -} - -@end - -@implementation MTRThreadNetworkDirectoryClusterNetworkChangedEvent -- (instancetype)init -{ - if (self = [super init]) { - - _extendedPanID = @(0); - } - return self; -} - -- (id)copyWithZone:(NSZone * _Nullable)zone -{ - auto other = [[MTRThreadNetworkDirectoryClusterNetworkChangedEvent alloc] init]; - - other.extendedPanID = self.extendedPanID; - - return other; -} - -- (NSString *)description -{ - NSString * descriptionString = [NSString stringWithFormat:@"<%@: extendedPanID:%@; >", NSStringFromClass([self class]), _extendedPanID]; + NSString * descriptionString = [NSString stringWithFormat:@"<%@: extendedPanID:%@; networkName:%@; channel:%@; activeTimestamp:%@; >", NSStringFromClass([self class]), [_extendedPanID base64EncodedStringWithOptions:0], _networkName, _channel, _activeTimestamp]; return descriptionString; } diff --git a/src/lib/core/CHIPConfig.h b/src/lib/core/CHIPConfig.h index 2de6a662ee8c4d..32e49ab2e3d45f 100644 --- a/src/lib/core/CHIPConfig.h +++ b/src/lib/core/CHIPConfig.h @@ -1702,6 +1702,24 @@ extern const char CHIP_NON_PRODUCTION_MARKER[]; #define CHIP_CONFIG_MAX_ICD_CLIENTS_INFO_STORAGE_CONCURRENT_ITERATORS 1 #endif +/** + * @def CHIP_CONFIG_MAX_THREAD_NETWORK_DIRECTORY_STORAGE_CAPACITY + * + * Defines the number of networks the default ThreadNetworkDirectoryStorage implementation will store. + */ +#ifndef CHIP_CONFIG_MAX_THREAD_NETWORK_DIRECTORY_STORAGE_CAPACITY +#define CHIP_CONFIG_MAX_THREAD_NETWORK_DIRECTORY_STORAGE_CAPACITY (CHIP_CONFIG_MAX_FABRICS * 2) +#endif + +/** + * @def CHIP_CONFIG_MAX_THREAD_NETWORK_DIRECTORY_STORAGE_CONCURRENT_ITERATORS + * + * Defines the number of ThreadNetworkDirectoryStorage iterators that can be allocated at any one time. + */ +#ifndef CHIP_CONFIG_MAX_THREAD_NETWORK_DIRECTORY_STORAGE_CONCURRENT_ITERATORS +#define CHIP_CONFIG_MAX_THREAD_NETWORK_DIRECTORY_STORAGE_CONCURRENT_ITERATORS 1 +#endif + /** * @def CHIP_CONFIG_COMMAND_SENDER_BUILTIN_SUPPORT_FOR_BATCHED_COMMANDS * diff --git a/src/lib/support/CodeUtils.h b/src/lib/support/CodeUtils.h index 500804bc94912d..800123aa456851 100644 --- a/src/lib/support/CodeUtils.h +++ b/src/lib/support/CodeUtils.h @@ -392,6 +392,19 @@ constexpr inline const _T & max(const _T & a, const _T & b) */ #define SuccessOrExit(error) nlEXPECT(::chip::ChipError::IsSuccess((error)), exit) +/** + * @def SuccessOrExitAction(error, anAction) + * + * @brief + * This checks for the specified error, which is expected to + * commonly be successful (CHIP_NO_ERROR), and both executes + * @a anAction and branches to the local label 'exit' if the + * status is unsuccessful. + * + * @param[in] error A ChipError object to be evaluated against success (CHIP_NO_ERROR). + */ +#define SuccessOrExitAction(error, action) nlEXPECT_ACTION(::chip::ChipError::IsSuccess((error)), exit, action) + /** * @def VerifyOrExit(aCondition, anAction) * diff --git a/src/lib/support/CommonIterator.h b/src/lib/support/CommonIterator.h index fc799c33b233eb..0eec391a40e777 100644 --- a/src/lib/support/CommonIterator.h +++ b/src/lib/support/CommonIterator.h @@ -46,7 +46,7 @@ class CommonIterator virtual bool Next(T & item) = 0; /** * Release the memory allocated by this iterator. - * Must be called before the iterator goes out of scope in the iterator was dynamically allocated. + * Must be called before the iterator goes out of scope if the iterator was dynamically allocated. */ virtual void Release() = 0; diff --git a/src/lib/support/DefaultStorageKeyAllocator.h b/src/lib/support/DefaultStorageKeyAllocator.h index 04825c9ca4d719..9ed8a2f56cfd77 100644 --- a/src/lib/support/DefaultStorageKeyAllocator.h +++ b/src/lib/support/DefaultStorageKeyAllocator.h @@ -193,6 +193,17 @@ class DefaultStorageKeyAllocator return StorageKeyName::Formatted("f/%x/icd/%x", fabric, index); } + // Thread Network Directory + + static StorageKeyName ThreadNetworkDirectoryIndex() { return StorageKeyName::FromConst("g/tnd/i"); } + static StorageKeyName ThreadNetworkDirectoryDataset(uint64_t extendedPanId) + { + return StorageKeyName::Formatted("g/tnd/n/%08" PRIx32 "%08" PRIx32, // some platforms can't format uint64 + static_cast(extendedPanId >> 32), static_cast(extendedPanId)); + } + + // OTA + static StorageKeyName OTADefaultProviders() { return StorageKeyName::FromConst("g/o/dp"); } static StorageKeyName OTACurrentProvider() { return StorageKeyName::FromConst("g/o/cp"); } static StorageKeyName OTAUpdateToken() { return StorageKeyName::FromConst("g/o/ut"); } diff --git a/src/lib/support/Span.h b/src/lib/support/Span.h index a6f63c7c59f33e..2e6627d937e560 100644 --- a/src/lib/support/Span.h +++ b/src/lib/support/Span.h @@ -364,6 +364,8 @@ using ByteSpan = Span; using MutableByteSpan = Span; template using FixedByteSpan = FixedSpan; +template +using MutableFixedByteSpan = FixedSpan; using CharSpan = Span; using MutableCharSpan = Span; diff --git a/src/lib/support/TestPersistentStorageDelegate.h b/src/lib/support/TestPersistentStorageDelegate.h index 8d3bfd63e11bb2..7dc1c06008c77c 100644 --- a/src/lib/support/TestPersistentStorageDelegate.h +++ b/src/lib/support/TestPersistentStorageDelegate.h @@ -134,6 +134,11 @@ class TestPersistentStorageDelegate : public PersistentStorageDelegate */ virtual void AddPoisonKey(const std::string & key) { mPoisonKeys.insert(key); } + /** + * Allows subsequent writes to be rejected for unit testing purposes. + */ + virtual void SetRejectWrites(bool rejectWrites) { mRejectWrites = rejectWrites; } + /** * @brief Clear all "poison keys" * @@ -233,8 +238,8 @@ class TestPersistentStorageDelegate : public PersistentStorageDelegate virtual CHIP_ERROR SyncSetKeyValueInternal(const char * key, const void * value, uint16_t size) { - // Make sure poison keys are not accessed - if (mPoisonKeys.find(std::string(key)) != mPoisonKeys.end()) + // Make sure writes are allowed and poison keys are not accessed + if (mRejectWrites || mPoisonKeys.find(std::string(key)) != mPoisonKeys.end()) { return CHIP_ERROR_PERSISTED_STORAGE_FAILED; } @@ -259,8 +264,8 @@ class TestPersistentStorageDelegate : public PersistentStorageDelegate virtual CHIP_ERROR SyncDeleteKeyValueInternal(const char * key) { - // Make sure poison keys are not accessed - if (mPoisonKeys.find(std::string(key)) != mPoisonKeys.end()) + // Make sure writes are allowed and poison keys are not accessed + if (mRejectWrites || mPoisonKeys.find(std::string(key)) != mPoisonKeys.end()) { return CHIP_ERROR_PERSISTED_STORAGE_FAILED; } @@ -273,6 +278,7 @@ class TestPersistentStorageDelegate : public PersistentStorageDelegate std::map> mStorage; std::set mPoisonKeys; + bool mRejectWrites = false; LoggingLevel mLoggingLevel = LoggingLevel::kDisabled; }; diff --git a/src/lib/support/ThreadOperationalDataset.cpp b/src/lib/support/ThreadOperationalDataset.cpp index 9f2ae6a1b1a8ec..1c11712166cfa4 100644 --- a/src/lib/support/ThreadOperationalDataset.cpp +++ b/src/lib/support/ThreadOperationalDataset.cpp @@ -39,9 +39,11 @@ namespace Thread { class ThreadTLV final { static constexpr uint8_t kLengthEscape = 0xff; ///< This length value indicates the actual length is of two-bytes length, which - ///< not allowed in Thread Operational Dataset TLVs. + ///< is not allowed in Thread Operational Dataset TLVs. public: + static constexpr uint8_t kMaxLength = kLengthEscape - 1; + enum : uint8_t { kChannel = 0, @@ -51,7 +53,9 @@ class ThreadTLV final kPSKc = 4, kMasterKey = 5, kMeshLocalPrefix = 7, + kSecurityPolicy = 12, kActiveTimestamp = 14, + kChannelMask = 53, }; uint8_t GetSize() const { return static_cast(sizeof(*this) + GetLength()); } @@ -127,6 +131,8 @@ class ThreadTLV final memcpy(GetValue(), aValue, aLength); } + void SetValue(const ByteSpan & aValue) { SetValue(aValue.data(), static_cast(aValue.size())); } + const ThreadTLV * GetNext() const { static_assert(alignof(ThreadTLV) == 1, "Wrong alignment for ThreadTLV header"); @@ -239,12 +245,21 @@ CHIP_ERROR OperationalDataset::GetExtendedPanId(uint8_t (&aExtendedPanId)[kSizeE return CHIP_NO_ERROR; } +CHIP_ERROR OperationalDataset::GetExtendedPanId(uint64_t & extendedPanId) const +{ + ByteSpan extPanIdSpan; + ReturnErrorOnFailure(GetExtendedPanIdAsByteSpan(extPanIdSpan)); + VerifyOrDie(extPanIdSpan.size() == sizeof(extendedPanId)); + extendedPanId = Encoding::BigEndian::Get64(extPanIdSpan.data()); + return CHIP_NO_ERROR; +} + CHIP_ERROR OperationalDataset::GetExtendedPanIdAsByteSpan(ByteSpan & span) const { const ThreadTLV * tlv = Locate(ThreadTLV::kExtendedPanId); VerifyOrReturnError(tlv != nullptr, CHIP_ERROR_TLV_TAG_NOT_FOUND); VerifyOrReturnError(tlv->GetLength() == kSizeExtendedPanId, CHIP_ERROR_INVALID_TLV_ELEMENT); - span = ByteSpan(static_cast(tlv->GetValue()), tlv->GetLength()); + span = tlv->GetValueAsSpan(); return CHIP_NO_ERROR; } @@ -374,6 +389,43 @@ CHIP_ERROR OperationalDataset::SetPSKc(const uint8_t (&aPSKc)[kSizePSKc]) return CHIP_NO_ERROR; } +CHIP_ERROR OperationalDataset::GetChannelMask(ByteSpan & aChannelMask) const +{ + const ThreadTLV * tlv = Locate(ThreadTLV::kChannelMask); + VerifyOrReturnError(tlv != nullptr, CHIP_ERROR_TLV_TAG_NOT_FOUND); + VerifyOrReturnError(tlv->GetLength() > 0, CHIP_ERROR_INVALID_TLV_ELEMENT); + aChannelMask = tlv->GetValueAsSpan(); + return CHIP_NO_ERROR; +} + +CHIP_ERROR OperationalDataset::SetChannelMask(ByteSpan aChannelMask) +{ + VerifyOrReturnError(0 < aChannelMask.size() && aChannelMask.size() < ThreadTLV::kMaxLength, CHIP_ERROR_INVALID_ARGUMENT); + ThreadTLV * tlv = MakeRoom(ThreadTLV::kChannelMask, sizeof(*tlv) + aChannelMask.size()); + VerifyOrReturnError(tlv != nullptr, CHIP_ERROR_NO_MEMORY); + tlv->SetValue(aChannelMask); + mLength = static_cast(mLength + tlv->GetSize()); + return CHIP_NO_ERROR; +} + +CHIP_ERROR OperationalDataset::GetSecurityPolicy(uint32_t & aSecurityPolicy) const +{ + const ThreadTLV * tlv = Locate(ThreadTLV::kSecurityPolicy); + VerifyOrReturnError(tlv != nullptr, CHIP_ERROR_TLV_TAG_NOT_FOUND); + VerifyOrReturnError(tlv->GetLength() == sizeof(aSecurityPolicy), CHIP_ERROR_INVALID_TLV_ELEMENT); + tlv->Get32(aSecurityPolicy); + return CHIP_NO_ERROR; +} + +CHIP_ERROR OperationalDataset::SetSecurityPolicy(uint32_t aSecurityPolicy) +{ + ThreadTLV * tlv = MakeRoom(ThreadTLV::kSecurityPolicy, sizeof(*tlv) + sizeof(aSecurityPolicy)); + VerifyOrReturnError(tlv != nullptr, CHIP_ERROR_NO_MEMORY); + tlv->Set32(aSecurityPolicy); + mLength = static_cast(mLength + tlv->GetSize()); + return CHIP_NO_ERROR; +} + void OperationalDataset::UnsetMasterKey() { Remove(ThreadTLV::kMasterKey); diff --git a/src/lib/support/ThreadOperationalDataset.h b/src/lib/support/ThreadOperationalDataset.h index 7bb528d691c193..5cd57df6a79db6 100644 --- a/src/lib/support/ThreadOperationalDataset.h +++ b/src/lib/support/ThreadOperationalDataset.h @@ -110,10 +110,20 @@ class OperationalDataset */ CHIP_ERROR GetExtendedPanId(uint8_t (&aExtendedPanId)[kSizeExtendedPanId]) const; + /** + * This method retrieves the Thread extended PAN ID from the dataset, interpreted as a big endian number. + * @retval CHIP_NO_ERROR Successfully retrieved the extended PAN ID. + * @retval CHIP_ERROR_TLV_TAG_NOT_FOUND Thread extended PAN ID is not present in the dataset. + */ + CHIP_ERROR GetExtendedPanId(uint64_t & extendedPanId) const; + /** * This method returns a const ByteSpan to the extended PAN ID in the dataset. * This can be used to pass the extended PAN ID to a cluster command without the use of external memory. * + * Note: The returned span points into storage managed by this class, + * and must not be dereferenced beyond the lifetime of this object. + * * @param[out] span A reference to receive the location of the extended PAN ID. * * @retval CHIP_NO_ERROR Successfully retrieved the extended PAN ID. @@ -247,6 +257,43 @@ class OperationalDataset */ void UnsetPSKc(void); + /** + * Returns ByteSpan pointing to the channel mask within the dataset. + * + * Note: The returned span points into storage managed by this class, + * and must not be dereferenced beyond the lifetime of this object. + * + * @retval CHIP_NO_ERROR on success. + * @retval CHIP_ERROR_TLV_TAG_NOT_FOUND if the channel mask is not present in the dataset. + * @retval CHIP_ERROR_INVALID_TLV_ELEMENT if the TLV element is invalid. + */ + CHIP_ERROR GetChannelMask(ByteSpan & aChannelMask) const; + + /** + * This method sets the channel mask within the dataset. + * + * @retval CHIP_NO_ERROR on success. + * @retval CHIP_ERROR_NO_MEMORY if there is insufficient space within the dataset. + */ + CHIP_ERROR SetChannelMask(ByteSpan aChannelMask); + + /** + * Retrieves the security policy from the dataset. + * + * @retval CHIP_NO_ERROR on success. + * @retval CHIP_ERROR_TLV_TAG_NOT_FOUND if no security policy is present in the dataset. + * @retval CHIP_ERROR_INVALID_TLV_ELEMENT if the TLV element is invalid. + */ + CHIP_ERROR GetSecurityPolicy(uint32_t & aSecurityPolicy) const; + + /** + * This method sets the security policy within the dataset. + * + * @retval CHIP_NO_ERROR on success. + * @retval CHIP_ERROR_NO_MEMORY if there is insufficient space within the dataset. + */ + CHIP_ERROR SetSecurityPolicy(uint32_t aSecurityPolicy); + /** * This method clears all data stored in the dataset. */ @@ -254,7 +301,6 @@ class OperationalDataset /** * This method checks if the dataset is ready for creating Thread network. - * */ bool IsCommissioned(void) const; @@ -267,7 +313,6 @@ class OperationalDataset * This method checks whether @p aData is formatted as ThreadTLVs. * * @note This method doesn't verify ThreadTLV values are valid. - * */ static bool IsValid(ByteSpan aData); diff --git a/src/lib/support/tests/TestThreadOperationalDataset.cpp b/src/lib/support/tests/TestThreadOperationalDataset.cpp index 3c60230a573a2a..2ea4d3c99eba30 100644 --- a/src/lib/support/tests/TestThreadOperationalDataset.cpp +++ b/src/lib/support/tests/TestThreadOperationalDataset.cpp @@ -276,6 +276,15 @@ TEST_F(TestThreadOperationalDataset, TestExampleDataset) 0x3c, 0xa6, 0x7c, 0x96, 0x9e, 0xfb, 0x0d, 0x0c, 0x74, 0xa4, 0xd8, 0xee, 0x92, 0x3b, 0x57, 0x6c }; EXPECT_TRUE(ByteSpan(pksc).data_equal(ByteSpan(expectedPksc))); + + ByteSpan channelMask; + EXPECT_EQ(dataset.GetChannelMask(channelMask), CHIP_NO_ERROR); + const uint8_t expectedChannelMask[] = { 0x07, 0xff, 0xf8, 0x00 }; + EXPECT_TRUE(channelMask.data_equal(ByteSpan(expectedChannelMask))); + + uint32_t securityPolicy; + EXPECT_EQ(dataset.GetSecurityPolicy(securityPolicy), CHIP_NO_ERROR); + EXPECT_EQ(securityPolicy, 0x02a0f7f8u); } TEST_F(TestThreadOperationalDataset, TestInvalidExampleDataset) @@ -319,6 +328,12 @@ TEST_F(TestThreadOperationalDataset, TestInvalidExampleDataset) uint8_t pksc[Thread::kSizePSKc]; EXPECT_EQ(dataset.GetPSKc(pksc), CHIP_ERROR_INVALID_TLV_ELEMENT); + + ByteSpan channelMask; + EXPECT_EQ(dataset.GetChannelMask(channelMask), CHIP_ERROR_INVALID_TLV_ELEMENT); + + uint32_t securityPolicy; + EXPECT_EQ(dataset.GetSecurityPolicy(securityPolicy), CHIP_ERROR_INVALID_TLV_ELEMENT); } } // namespace diff --git a/zzz_generated/app-common/app-common/zap-generated/attributes/Accessors.cpp b/zzz_generated/app-common/app-common/zap-generated/attributes/Accessors.cpp index a7fef6deeee4df..0e519739bea690 100644 --- a/zzz_generated/app-common/app-common/zap-generated/attributes/Accessors.cpp +++ b/zzz_generated/app-common/app-common/zap-generated/attributes/Accessors.cpp @@ -35989,142 +35989,6 @@ Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, uint16_t valu namespace ThreadNetworkDirectory { namespace Attributes { -namespace PreferredExtendedPanID { - -Protocols::InteractionModel::Status Get(chip::EndpointId endpoint, DataModel::Nullable & value) -{ - using Traits = NumericAttributeTraits; - Traits::StorageType temp; - uint8_t * readable = Traits::ToAttributeStoreRepresentation(temp); - Protocols::InteractionModel::Status status = - emberAfReadAttribute(endpoint, Clusters::ThreadNetworkDirectory::Id, Id, readable, sizeof(temp)); - VerifyOrReturnError(Protocols::InteractionModel::Status::Success == status, status); - if (Traits::IsNullValue(temp)) - { - value.SetNull(); - } - else - { - value.SetNonNull() = Traits::StorageToWorking(temp); - } - return status; -} - -Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, uint64_t value, MarkAttributeDirty markDirty) -{ - using Traits = NumericAttributeTraits; - if (!Traits::CanRepresentValue(/* isNullable = */ true, value)) - { - return Protocols::InteractionModel::Status::ConstraintError; - } - Traits::StorageType storageValue; - Traits::WorkingToStorage(value, storageValue); - uint8_t * writable = Traits::ToAttributeStoreRepresentation(storageValue); - return emberAfWriteAttribute(endpoint, Clusters::ThreadNetworkDirectory::Id, Id, writable, ZCL_INT64U_ATTRIBUTE_TYPE, - markDirty); -} - -Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, uint64_t value) -{ - using Traits = NumericAttributeTraits; - if (!Traits::CanRepresentValue(/* isNullable = */ true, value)) - { - return Protocols::InteractionModel::Status::ConstraintError; - } - Traits::StorageType storageValue; - Traits::WorkingToStorage(value, storageValue); - uint8_t * writable = Traits::ToAttributeStoreRepresentation(storageValue); - return emberAfWriteAttribute(endpoint, Clusters::ThreadNetworkDirectory::Id, Id, writable, ZCL_INT64U_ATTRIBUTE_TYPE); -} - -Protocols::InteractionModel::Status SetNull(chip::EndpointId endpoint, MarkAttributeDirty markDirty) -{ - using Traits = NumericAttributeTraits; - Traits::StorageType value; - Traits::SetNull(value); - uint8_t * writable = Traits::ToAttributeStoreRepresentation(value); - return emberAfWriteAttribute(endpoint, Clusters::ThreadNetworkDirectory::Id, Id, writable, ZCL_INT64U_ATTRIBUTE_TYPE, - markDirty); -} - -Protocols::InteractionModel::Status SetNull(chip::EndpointId endpoint) -{ - using Traits = NumericAttributeTraits; - Traits::StorageType value; - Traits::SetNull(value); - uint8_t * writable = Traits::ToAttributeStoreRepresentation(value); - return emberAfWriteAttribute(endpoint, Clusters::ThreadNetworkDirectory::Id, Id, writable, ZCL_INT64U_ATTRIBUTE_TYPE); -} - -Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, const chip::app::DataModel::Nullable & value, - MarkAttributeDirty markDirty) -{ - if (value.IsNull()) - { - return SetNull(endpoint, markDirty); - } - - return Set(endpoint, value.Value(), markDirty); -} - -Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, const chip::app::DataModel::Nullable & value) -{ - if (value.IsNull()) - { - return SetNull(endpoint); - } - - return Set(endpoint, value.Value()); -} - -} // namespace PreferredExtendedPanID - -namespace ThreadNetworkTableSize { - -Protocols::InteractionModel::Status Get(chip::EndpointId endpoint, uint8_t * value) -{ - using Traits = NumericAttributeTraits; - Traits::StorageType temp; - uint8_t * readable = Traits::ToAttributeStoreRepresentation(temp); - Protocols::InteractionModel::Status status = - emberAfReadAttribute(endpoint, Clusters::ThreadNetworkDirectory::Id, Id, readable, sizeof(temp)); - VerifyOrReturnError(Protocols::InteractionModel::Status::Success == status, status); - if (!Traits::CanRepresentValue(/* isNullable = */ false, temp)) - { - return Protocols::InteractionModel::Status::ConstraintError; - } - *value = Traits::StorageToWorking(temp); - return status; -} - -Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, uint8_t value, MarkAttributeDirty markDirty) -{ - using Traits = NumericAttributeTraits; - if (!Traits::CanRepresentValue(/* isNullable = */ false, value)) - { - return Protocols::InteractionModel::Status::ConstraintError; - } - Traits::StorageType storageValue; - Traits::WorkingToStorage(value, storageValue); - uint8_t * writable = Traits::ToAttributeStoreRepresentation(storageValue); - return emberAfWriteAttribute(endpoint, Clusters::ThreadNetworkDirectory::Id, Id, writable, ZCL_INT8U_ATTRIBUTE_TYPE, markDirty); -} - -Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, uint8_t value) -{ - using Traits = NumericAttributeTraits; - if (!Traits::CanRepresentValue(/* isNullable = */ false, value)) - { - return Protocols::InteractionModel::Status::ConstraintError; - } - Traits::StorageType storageValue; - Traits::WorkingToStorage(value, storageValue); - uint8_t * writable = Traits::ToAttributeStoreRepresentation(storageValue); - return emberAfWriteAttribute(endpoint, Clusters::ThreadNetworkDirectory::Id, Id, writable, ZCL_INT8U_ATTRIBUTE_TYPE); -} - -} // namespace ThreadNetworkTableSize - namespace FeatureMap { Protocols::InteractionModel::Status Get(chip::EndpointId endpoint, uint32_t * value) diff --git a/zzz_generated/app-common/app-common/zap-generated/attributes/Accessors.h b/zzz_generated/app-common/app-common/zap-generated/attributes/Accessors.h index 63493b3f90551d..3fed44373526df 100644 --- a/zzz_generated/app-common/app-common/zap-generated/attributes/Accessors.h +++ b/zzz_generated/app-common/app-common/zap-generated/attributes/Accessors.h @@ -5537,23 +5537,6 @@ Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, uint16_t valu namespace ThreadNetworkDirectory { namespace Attributes { -namespace PreferredExtendedPanID { -Protocols::InteractionModel::Status Get(chip::EndpointId endpoint, DataModel::Nullable & value); // int64u -Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, uint64_t value); -Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, uint64_t value, MarkAttributeDirty markDirty); -Protocols::InteractionModel::Status SetNull(chip::EndpointId endpoint); -Protocols::InteractionModel::Status SetNull(chip::EndpointId endpoint, MarkAttributeDirty markDirty); -Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, const chip::app::DataModel::Nullable & value); -Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, const chip::app::DataModel::Nullable & value, - MarkAttributeDirty markDirty); -} // namespace PreferredExtendedPanID - -namespace ThreadNetworkTableSize { -Protocols::InteractionModel::Status Get(chip::EndpointId endpoint, uint8_t * value); // int8u -Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, uint8_t value); -Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, uint8_t value, MarkAttributeDirty markDirty); -} // namespace ThreadNetworkTableSize - namespace FeatureMap { Protocols::InteractionModel::Status Get(chip::EndpointId endpoint, uint32_t * value); // bitmap32 Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, uint32_t value); diff --git a/zzz_generated/app-common/app-common/zap-generated/callback.h b/zzz_generated/app-common/app-common/zap-generated/callback.h index 6e78fd6c09a8bf..ab6514fdf02103 100644 --- a/zzz_generated/app-common/app-common/zap-generated/callback.h +++ b/zzz_generated/app-common/app-common/zap-generated/callback.h @@ -6473,24 +6473,6 @@ bool emberAfThreadBorderRouterManagementClusterSetActiveDatasetRequestCallback( bool emberAfThreadBorderRouterManagementClusterSetPendingDatasetRequestCallback( chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, const chip::app::Clusters::ThreadBorderRouterManagement::Commands::SetPendingDatasetRequest::DecodableType & commandData); -/** - * @brief Thread Network Directory Cluster AddNetwork Command callback (from client) - */ -bool emberAfThreadNetworkDirectoryClusterAddNetworkCallback( - chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, - const chip::app::Clusters::ThreadNetworkDirectory::Commands::AddNetwork::DecodableType & commandData); -/** - * @brief Thread Network Directory Cluster RemoveNetwork Command callback (from client) - */ -bool emberAfThreadNetworkDirectoryClusterRemoveNetworkCallback( - chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, - const chip::app::Clusters::ThreadNetworkDirectory::Commands::RemoveNetwork::DecodableType & commandData); -/** - * @brief Thread Network Directory Cluster GetOperationalDataset Command callback (from client) - */ -bool emberAfThreadNetworkDirectoryClusterGetOperationalDatasetCallback( - chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, - const chip::app::Clusters::ThreadNetworkDirectory::Commands::GetOperationalDataset::DecodableType & commandData); /** * @brief Channel Cluster ChangeChannel Command callback (from client) */ diff --git a/zzz_generated/app-common/app-common/zap-generated/cluster-objects.cpp b/zzz_generated/app-common/app-common/zap-generated/cluster-objects.cpp index fcae2110b2ce53..3244826b526af4 100644 --- a/zzz_generated/app-common/app-common/zap-generated/cluster-objects.cpp +++ b/zzz_generated/app-common/app-common/zap-generated/cluster-objects.cpp @@ -23948,6 +23948,7 @@ CHIP_ERROR Type::Encode(TLV::TLVWriter & aWriter, TLV::Tag aTag) const encoder.Encode(to_underlying(Fields::kExtendedPanID), extendedPanID); encoder.Encode(to_underlying(Fields::kNetworkName), networkName); encoder.Encode(to_underlying(Fields::kChannel), channel); + encoder.Encode(to_underlying(Fields::kActiveTimestamp), activeTimestamp); return encoder.Finalize(); } @@ -23977,6 +23978,10 @@ CHIP_ERROR DecodableType::Decode(TLV::TLVReader & reader) { err = DataModel::Decode(reader, channel); } + else if (__context_tag == to_underlying(Fields::kActiveTimestamp)) + { + err = DataModel::Decode(reader, activeTimestamp); + } else { } @@ -24156,43 +24161,7 @@ CHIP_ERROR TypeInfo::DecodableType::Decode(TLV::TLVReader & reader, const Concre } } // namespace Attributes -namespace Events { -namespace NetworkChanged { -CHIP_ERROR Type::Encode(TLV::TLVWriter & aWriter, TLV::Tag aTag) const -{ - TLV::TLVType outer; - ReturnErrorOnFailure(aWriter.StartContainer(aTag, TLV::kTLVType_Structure, outer)); - ReturnErrorOnFailure(DataModel::Encode(aWriter, TLV::ContextTag(Fields::kExtendedPanID), extendedPanID)); - return aWriter.EndContainer(outer); -} - -CHIP_ERROR DecodableType::Decode(TLV::TLVReader & reader) -{ - detail::StructDecodeIterator __iterator(reader); - while (true) - { - auto __element = __iterator.Next(); - if (std::holds_alternative(__element)) - { - return std::get(__element); - } - - CHIP_ERROR err = CHIP_NO_ERROR; - const uint8_t __context_tag = std::get(__element); - - if (__context_tag == to_underlying(Fields::kExtendedPanID)) - { - err = DataModel::Decode(reader, extendedPanID); - } - else - { - } - - ReturnErrorOnFailure(err); - } -} -} // namespace NetworkChanged. -} // namespace Events +namespace Events {} // namespace Events } // namespace ThreadNetworkDirectory namespace WakeOnLan { diff --git a/zzz_generated/app-common/app-common/zap-generated/cluster-objects.h b/zzz_generated/app-common/app-common/zap-generated/cluster-objects.h index 9377e6e1739a75..2e3dddde6d0fc0 100644 --- a/zzz_generated/app-common/app-common/zap-generated/cluster-objects.h +++ b/zzz_generated/app-common/app-common/zap-generated/cluster-objects.h @@ -36291,17 +36291,19 @@ namespace Structs { namespace ThreadNetworkStruct { enum class Fields : uint8_t { - kExtendedPanID = 0, - kNetworkName = 1, - kChannel = 2, + kExtendedPanID = 0, + kNetworkName = 1, + kChannel = 2, + kActiveTimestamp = 3, }; struct Type { public: - uint64_t extendedPanID = static_cast(0); + chip::ByteSpan extendedPanID; chip::CharSpan networkName; - uint16_t channel = static_cast(0); + uint16_t channel = static_cast(0); + uint64_t activeTimestamp = static_cast(0); CHIP_ERROR Decode(TLV::TLVReader & reader); @@ -36386,7 +36388,7 @@ struct Type static constexpr CommandId GetCommandId() { return Commands::RemoveNetwork::Id; } static constexpr ClusterId GetClusterId() { return Clusters::ThreadNetworkDirectory::Id; } - uint64_t extendedPanID = static_cast(0); + chip::ByteSpan extendedPanID; CHIP_ERROR Encode(TLV::TLVWriter & aWriter, TLV::Tag aTag) const; @@ -36401,7 +36403,7 @@ struct DecodableType static constexpr CommandId GetCommandId() { return Commands::RemoveNetwork::Id; } static constexpr ClusterId GetClusterId() { return Clusters::ThreadNetworkDirectory::Id; } - uint64_t extendedPanID = static_cast(0); + chip::ByteSpan extendedPanID; CHIP_ERROR Decode(TLV::TLVReader & reader); }; }; // namespace RemoveNetwork @@ -36418,7 +36420,7 @@ struct Type static constexpr CommandId GetCommandId() { return Commands::GetOperationalDataset::Id; } static constexpr ClusterId GetClusterId() { return Clusters::ThreadNetworkDirectory::Id; } - uint64_t extendedPanID = static_cast(0); + chip::ByteSpan extendedPanID; CHIP_ERROR Encode(TLV::TLVWriter & aWriter, TLV::Tag aTag) const; @@ -36433,7 +36435,7 @@ struct DecodableType static constexpr CommandId GetCommandId() { return Commands::GetOperationalDataset::Id; } static constexpr ClusterId GetClusterId() { return Clusters::ThreadNetworkDirectory::Id; } - uint64_t extendedPanID = static_cast(0); + chip::ByteSpan extendedPanID; CHIP_ERROR Decode(TLV::TLVReader & reader); }; }; // namespace GetOperationalDataset @@ -36476,13 +36478,14 @@ namespace Attributes { namespace PreferredExtendedPanID { struct TypeInfo { - using Type = chip::app::DataModel::Nullable; - using DecodableType = chip::app::DataModel::Nullable; - using DecodableArgType = const chip::app::DataModel::Nullable &; + using Type = chip::app::DataModel::Nullable; + using DecodableType = chip::app::DataModel::Nullable; + using DecodableArgType = const chip::app::DataModel::Nullable &; static constexpr ClusterId GetClusterId() { return Clusters::ThreadNetworkDirectory::Id; } static constexpr AttributeId GetAttributeId() { return Attributes::PreferredExtendedPanID::Id; } static constexpr bool MustUseTimedWrite() { return false; } + static constexpr size_t MaxLength() { return 8; } }; } // namespace PreferredExtendedPanID namespace ThreadNetworks { @@ -36568,41 +36571,6 @@ struct TypeInfo }; }; } // namespace Attributes -namespace Events { -namespace NetworkChanged { -static constexpr PriorityLevel kPriorityLevel = PriorityLevel::Info; - -enum class Fields : uint8_t -{ - kExtendedPanID = 0, -}; - -struct Type -{ -public: - static constexpr PriorityLevel GetPriorityLevel() { return kPriorityLevel; } - static constexpr EventId GetEventId() { return Events::NetworkChanged::Id; } - static constexpr ClusterId GetClusterId() { return Clusters::ThreadNetworkDirectory::Id; } - static constexpr bool kIsFabricScoped = false; - - uint64_t extendedPanID = static_cast(0); - - CHIP_ERROR Encode(TLV::TLVWriter & aWriter, TLV::Tag aTag) const; -}; - -struct DecodableType -{ -public: - static constexpr PriorityLevel GetPriorityLevel() { return kPriorityLevel; } - static constexpr EventId GetEventId() { return Events::NetworkChanged::Id; } - static constexpr ClusterId GetClusterId() { return Clusters::ThreadNetworkDirectory::Id; } - - uint64_t extendedPanID = static_cast(0); - - CHIP_ERROR Decode(TLV::TLVReader & reader); -}; -} // namespace NetworkChanged -} // namespace Events } // namespace ThreadNetworkDirectory namespace WakeOnLan { diff --git a/zzz_generated/app-common/app-common/zap-generated/ids/Events.h b/zzz_generated/app-common/app-common/zap-generated/ids/Events.h index cc619b581dc3e6..6e6191fe45c21c 100644 --- a/zzz_generated/app-common/app-common/zap-generated/ids/Events.h +++ b/zzz_generated/app-common/app-common/zap-generated/ids/Events.h @@ -611,16 +611,6 @@ static constexpr EventId Id = 0x00000010; } // namespace Events } // namespace PumpConfigurationAndControl -namespace ThreadNetworkDirectory { -namespace Events { - -namespace NetworkChanged { -static constexpr EventId Id = 0x00000000; -} // namespace NetworkChanged - -} // namespace Events -} // namespace ThreadNetworkDirectory - namespace TargetNavigator { namespace Events { diff --git a/zzz_generated/chip-tool/zap-generated/cluster/Commands.h b/zzz_generated/chip-tool/zap-generated/cluster/Commands.h index c5971984fed334..6bc2808777acad 100644 --- a/zzz_generated/chip-tool/zap-generated/cluster/Commands.h +++ b/zzz_generated/chip-tool/zap-generated/cluster/Commands.h @@ -11547,7 +11547,6 @@ class ThreadBorderRouterManagementSetPendingDatasetRequest : public ClusterComma | * ClusterRevision | 0xFFFD | |------------------------------------------------------------------------------| | Events: | | -| * NetworkChanged | 0x0000 | \*----------------------------------------------------------------------------*/ /* @@ -11597,7 +11596,7 @@ class ThreadNetworkDirectoryRemoveNetwork : public ClusterCommand ThreadNetworkDirectoryRemoveNetwork(CredentialIssuerCommands * credsIssuerConfig) : ClusterCommand("remove-network", credsIssuerConfig) { - AddArgument("ExtendedPanID", 0, UINT64_MAX, &mRequest.extendedPanID); + AddArgument("ExtendedPanID", &mRequest.extendedPanID); ClusterCommand::AddArguments(); } @@ -11635,7 +11634,7 @@ class ThreadNetworkDirectoryGetOperationalDataset : public ClusterCommand ThreadNetworkDirectoryGetOperationalDataset(CredentialIssuerCommands * credsIssuerConfig) : ClusterCommand("get-operational-dataset", credsIssuerConfig) { - AddArgument("ExtendedPanID", 0, UINT64_MAX, &mRequest.extendedPanID); + AddArgument("ExtendedPanID", &mRequest.extendedPanID); ClusterCommand::AddArguments(); } @@ -25693,9 +25692,9 @@ void registerClusterThreadNetworkDirectory(Commands & commands, CredentialIssuer make_unique(Id, "feature-map", Attributes::FeatureMap::Id, credsIssuerConfig), // make_unique(Id, "cluster-revision", Attributes::ClusterRevision::Id, credsIssuerConfig), // make_unique>(Id, credsIssuerConfig), // - make_unique>>(Id, "preferred-extended-pan-id", 0, UINT64_MAX, - Attributes::PreferredExtendedPanID::Id, - WriteCommandType::kWrite, credsIssuerConfig), // + make_unique>>(Id, "preferred-extended-pan-id", + Attributes::PreferredExtendedPanID::Id, + WriteCommandType::kWrite, credsIssuerConfig), // make_unique>>( Id, "thread-networks", Attributes::ThreadNetworks::Id, WriteCommandType::kForceWrite, credsIssuerConfig), // @@ -25729,10 +25728,8 @@ void registerClusterThreadNetworkDirectory(Commands & commands, CredentialIssuer // // Events // - make_unique(Id, credsIssuerConfig), // - make_unique(Id, "network-changed", Events::NetworkChanged::Id, credsIssuerConfig), // - make_unique(Id, credsIssuerConfig), // - make_unique(Id, "network-changed", Events::NetworkChanged::Id, credsIssuerConfig), // + make_unique(Id, credsIssuerConfig), // + make_unique(Id, credsIssuerConfig), // }; commands.RegisterCluster(clusterName, clusterCommands); diff --git a/zzz_generated/chip-tool/zap-generated/cluster/ComplexArgumentParser.cpp b/zzz_generated/chip-tool/zap-generated/cluster/ComplexArgumentParser.cpp index 035f26c348a135..624acd23feb594 100644 --- a/zzz_generated/chip-tool/zap-generated/cluster/ComplexArgumentParser.cpp +++ b/zzz_generated/chip-tool/zap-generated/cluster/ComplexArgumentParser.cpp @@ -4340,6 +4340,8 @@ CHIP_ERROR ComplexArgumentParser::Setup(const char * label, ComplexArgumentParser::EnsureMemberExist("ThreadNetworkStruct.networkName", "networkName", value.isMember("networkName"))); ReturnErrorOnFailure( ComplexArgumentParser::EnsureMemberExist("ThreadNetworkStruct.channel", "channel", value.isMember("channel"))); + ReturnErrorOnFailure(ComplexArgumentParser::EnsureMemberExist("ThreadNetworkStruct.activeTimestamp", "activeTimestamp", + value.isMember("activeTimestamp"))); char labelWithMember[kMaxLabelLength]; snprintf(labelWithMember, sizeof(labelWithMember), "%s.%s", label, "extendedPanID"); @@ -4354,6 +4356,10 @@ CHIP_ERROR ComplexArgumentParser::Setup(const char * label, ReturnErrorOnFailure(ComplexArgumentParser::Setup(labelWithMember, request.channel, value["channel"])); valueCopy.removeMember("channel"); + snprintf(labelWithMember, sizeof(labelWithMember), "%s.%s", label, "activeTimestamp"); + ReturnErrorOnFailure(ComplexArgumentParser::Setup(labelWithMember, request.activeTimestamp, value["activeTimestamp"])); + valueCopy.removeMember("activeTimestamp"); + return ComplexArgumentParser::EnsureNoMembersRemaining(label, valueCopy); } @@ -4362,6 +4368,7 @@ void ComplexArgumentParser::Finalize(chip::app::Clusters::ThreadNetworkDirectory ComplexArgumentParser::Finalize(request.extendedPanID); ComplexArgumentParser::Finalize(request.networkName); ComplexArgumentParser::Finalize(request.channel); + ComplexArgumentParser::Finalize(request.activeTimestamp); } CHIP_ERROR ComplexArgumentParser::Setup(const char * label, diff --git a/zzz_generated/chip-tool/zap-generated/cluster/logging/DataModelLogger.cpp b/zzz_generated/chip-tool/zap-generated/cluster/logging/DataModelLogger.cpp index 9de841aaaa4af3..d0fba2b8f0e0f3 100644 --- a/zzz_generated/chip-tool/zap-generated/cluster/logging/DataModelLogger.cpp +++ b/zzz_generated/chip-tool/zap-generated/cluster/logging/DataModelLogger.cpp @@ -3854,6 +3854,14 @@ DataModelLogger::LogValue(const char * label, size_t indent, return err; } } + { + CHIP_ERROR err = LogValue("ActiveTimestamp", indent + 1, value.activeTimestamp); + if (err != CHIP_NO_ERROR) + { + DataModelLogger::LogString(indent + 1, "Struct truncated due to invalid value for 'ActiveTimestamp'"); + return err; + } + } DataModelLogger::LogString(indent, "}"); return CHIP_NO_ERROR; @@ -7316,22 +7324,6 @@ CHIP_ERROR DataModelLogger::LogValue(const char * label, size_t indent, return CHIP_NO_ERROR; } -CHIP_ERROR DataModelLogger::LogValue(const char * label, size_t indent, - const ThreadNetworkDirectory::Events::NetworkChanged::DecodableType & value) -{ - DataModelLogger::LogString(label, indent, "{"); - { - CHIP_ERROR err = DataModelLogger::LogValue("ExtendedPanID", indent + 1, value.extendedPanID); - if (err != CHIP_NO_ERROR) - { - DataModelLogger::LogString(indent + 1, "Event truncated due to invalid value for 'ExtendedPanID'"); - return err; - } - } - DataModelLogger::LogString(indent, "}"); - - return CHIP_NO_ERROR; -} CHIP_ERROR DataModelLogger::LogValue(const char * label, size_t indent, const TargetNavigator::Events::TargetUpdated::DecodableType & value) { @@ -16872,7 +16864,7 @@ CHIP_ERROR DataModelLogger::LogAttribute(const chip::app::ConcreteDataAttributeP switch (path.mAttributeId) { case ThreadNetworkDirectory::Attributes::PreferredExtendedPanID::Id: { - chip::app::DataModel::Nullable value; + chip::app::DataModel::Nullable value; ReturnErrorOnFailure(chip::app::DataModel::Decode(*data, value)); return DataModelLogger::LogValue("PreferredExtendedPanID", 1, value); } @@ -20318,17 +20310,6 @@ CHIP_ERROR DataModelLogger::LogEvent(const chip::app::EventHeader & header, chip } break; } - case ThreadNetworkDirectory::Id: { - switch (header.mPath.mEventId) - { - case ThreadNetworkDirectory::Events::NetworkChanged::Id: { - chip::app::Clusters::ThreadNetworkDirectory::Events::NetworkChanged::DecodableType value; - ReturnErrorOnFailure(chip::app::DataModel::Decode(*data, value)); - return DataModelLogger::LogValue("NetworkChanged", 1, value); - } - } - break; - } case TargetNavigator::Id: { switch (header.mPath.mEventId) { diff --git a/zzz_generated/chip-tool/zap-generated/cluster/logging/DataModelLogger.h b/zzz_generated/chip-tool/zap-generated/cluster/logging/DataModelLogger.h index 8ca6e2ef3904d6..7ee50893968ccd 100644 --- a/zzz_generated/chip-tool/zap-generated/cluster/logging/DataModelLogger.h +++ b/zzz_generated/chip-tool/zap-generated/cluster/logging/DataModelLogger.h @@ -627,8 +627,6 @@ static CHIP_ERROR LogValue(const char * label, size_t indent, const chip::app::Clusters::PumpConfigurationAndControl::Events::AirDetection::DecodableType & value); static CHIP_ERROR LogValue(const char * label, size_t indent, const chip::app::Clusters::PumpConfigurationAndControl::Events::TurbineOperation::DecodableType & value); -static CHIP_ERROR LogValue(const char * label, size_t indent, - const chip::app::Clusters::ThreadNetworkDirectory::Events::NetworkChanged::DecodableType & value); static CHIP_ERROR LogValue(const char * label, size_t indent, const chip::app::Clusters::TargetNavigator::Events::TargetUpdated::DecodableType & value); static CHIP_ERROR LogValue(const char * label, size_t indent, diff --git a/zzz_generated/darwin-framework-tool/zap-generated/cluster/Commands.h b/zzz_generated/darwin-framework-tool/zap-generated/cluster/Commands.h index c9386dc42a6a7b..0319e41eeaec91 100644 --- a/zzz_generated/darwin-framework-tool/zap-generated/cluster/Commands.h +++ b/zzz_generated/darwin-framework-tool/zap-generated/cluster/Commands.h @@ -148571,7 +148571,6 @@ class SubscribeAttributeThreadBorderRouterManagementClusterRevision : public Sub | * ClusterRevision | 0xFFFD | |------------------------------------------------------------------------------| | Events: | | -| * NetworkChanged | 0x0000 | \*----------------------------------------------------------------------------*/ #if MTR_ENABLE_PROVISIONAL @@ -148637,7 +148636,7 @@ class ThreadNetworkDirectoryRemoveNetwork : public ClusterCommand { : ClusterCommand("remove-network") { #if MTR_ENABLE_PROVISIONAL - AddArgument("ExtendedPanID", 0, UINT64_MAX, &mRequest.extendedPanID); + AddArgument("ExtendedPanID", &mRequest.extendedPanID); #endif // MTR_ENABLE_PROVISIONAL ClusterCommand::AddArguments(); } @@ -148654,7 +148653,7 @@ class ThreadNetworkDirectoryRemoveNetwork : public ClusterCommand { __auto_type * params = [[MTRThreadNetworkDirectoryClusterRemoveNetworkParams alloc] init]; params.timedInvokeTimeoutMs = mTimedInteractionTimeoutMs.HasValue() ? [NSNumber numberWithUnsignedShort:mTimedInteractionTimeoutMs.Value()] : nil; #if MTR_ENABLE_PROVISIONAL - params.extendedPanID = [NSNumber numberWithUnsignedLongLong:mRequest.extendedPanID]; + params.extendedPanID = [NSData dataWithBytes:mRequest.extendedPanID.data() length:mRequest.extendedPanID.size()]; #endif // MTR_ENABLE_PROVISIONAL uint16_t repeatCount = mRepeatCount.ValueOr(1); uint16_t __block responsesNeeded = repeatCount; @@ -148690,7 +148689,7 @@ class ThreadNetworkDirectoryGetOperationalDataset : public ClusterCommand { : ClusterCommand("get-operational-dataset") { #if MTR_ENABLE_PROVISIONAL - AddArgument("ExtendedPanID", 0, UINT64_MAX, &mRequest.extendedPanID); + AddArgument("ExtendedPanID", &mRequest.extendedPanID); #endif // MTR_ENABLE_PROVISIONAL ClusterCommand::AddArguments(); } @@ -148707,7 +148706,7 @@ class ThreadNetworkDirectoryGetOperationalDataset : public ClusterCommand { __auto_type * params = [[MTRThreadNetworkDirectoryClusterGetOperationalDatasetParams alloc] init]; params.timedInvokeTimeoutMs = mTimedInteractionTimeoutMs.HasValue() ? [NSNumber numberWithUnsignedShort:mTimedInteractionTimeoutMs.Value()] : nil; #if MTR_ENABLE_PROVISIONAL - params.extendedPanID = [NSNumber numberWithUnsignedLongLong:mRequest.extendedPanID]; + params.extendedPanID = [NSData dataWithBytes:mRequest.extendedPanID.data() length:mRequest.extendedPanID.size()]; #endif // MTR_ENABLE_PROVISIONAL uint16_t repeatCount = mRepeatCount.ValueOr(1); uint16_t __block responsesNeeded = repeatCount; @@ -148765,7 +148764,7 @@ class ReadThreadNetworkDirectoryPreferredExtendedPanID : public ReadAttribute { dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); __auto_type * cluster = [[MTRBaseClusterThreadNetworkDirectory alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; - [cluster readAttributePreferredExtendedPanIDWithCompletion:^(NSNumber * _Nullable value, NSError * _Nullable error) { + [cluster readAttributePreferredExtendedPanIDWithCompletion:^(NSData * _Nullable value, NSError * _Nullable error) { NSLog(@"ThreadNetworkDirectory.PreferredExtendedPanID response %@", [value description]); if (error == nil) { RemoteDataModelLogger::LogAttributeAsJSON(@(endpointId), @(clusterId), @(attributeId), value); @@ -148785,7 +148784,7 @@ class WriteThreadNetworkDirectoryPreferredExtendedPanID : public WriteAttribute : WriteAttribute("preferred-extended-pan-id") { AddArgument("attr-name", "preferred-extended-pan-id"); - AddArgument("attr-value", 0, UINT64_MAX, &mValue); + AddArgument("attr-value", &mValue); WriteAttribute::AddArguments(); } @@ -148804,9 +148803,9 @@ class WriteThreadNetworkDirectoryPreferredExtendedPanID : public WriteAttribute __auto_type * params = [[MTRWriteParams alloc] init]; params.timedWriteTimeout = mTimedInteractionTimeoutMs.HasValue() ? [NSNumber numberWithUnsignedShort:mTimedInteractionTimeoutMs.Value()] : nil; params.dataVersion = mDataVersion.HasValue() ? [NSNumber numberWithUnsignedInt:mDataVersion.Value()] : nil; - NSNumber * _Nullable value = nil; + NSData * _Nullable value = nil; if (!mValue.IsNull()) { - value = [NSNumber numberWithUnsignedLongLong:mValue.Value()]; + value = [[NSData alloc] initWithBytes:mValue.Value().data() length:mValue.Value().size()]; } [cluster writeAttributePreferredExtendedPanIDWithValue:value params:params completion:^(NSError * _Nullable error) { @@ -148820,7 +148819,7 @@ class WriteThreadNetworkDirectoryPreferredExtendedPanID : public WriteAttribute } private: - chip::app::DataModel::Nullable mValue; + chip::app::DataModel::Nullable mValue; }; class SubscribeAttributeThreadNetworkDirectoryPreferredExtendedPanID : public SubscribeAttribute { @@ -148854,7 +148853,7 @@ class SubscribeAttributeThreadNetworkDirectoryPreferredExtendedPanID : public Su } [cluster subscribeAttributePreferredExtendedPanIDWithParams:params subscriptionEstablished:^() { mSubscriptionEstablished = YES; } - reportHandler:^(NSNumber * _Nullable value, NSError * _Nullable error) { + reportHandler:^(NSData * _Nullable value, NSError * _Nullable error) { NSLog(@"ThreadNetworkDirectory.PreferredExtendedPanID response %@", [value description]); if (error == nil) { RemoteDataModelLogger::LogAttributeAsJSON(@(endpointId), @(clusterId), @(attributeId), value); @@ -195631,8 +195630,6 @@ void registerClusterThreadNetworkDirectory(Commands & commands) make_unique(), // make_unique(), // #endif // MTR_ENABLE_PROVISIONAL - make_unique(Id), // - make_unique(Id), // }; commands.RegisterCluster(clusterName, clusterCommands);