diff --git a/examples/chip-tool/config/PersistentStorage.h b/examples/chip-tool/config/PersistentStorage.h index 4f2a3b6297e554..edef1cdf94678c 100644 --- a/examples/chip-tool/config/PersistentStorage.h +++ b/examples/chip-tool/config/PersistentStorage.h @@ -22,13 +22,13 @@ #include #include -class PersistentStorage : public chip::Controller::PersistentStorageDelegate +class PersistentStorage : public chip::PersistentStorageDelegate { public: CHIP_ERROR Init(); /////////// PersistentStorageDelegate Interface ///////// - void SetDelegate(chip::Controller::PersistentStorageResultDelegate * delegate) override; + void SetDelegate(chip::PersistentStorageResultDelegate * delegate) override; void GetKeyValue(const char * key) override; CHIP_ERROR GetKeyValue(const char * key, char * value, uint16_t & size) override; void SetKeyValue(const char * key, const char * value) override; diff --git a/src/app/server/RendezvousServer.cpp b/src/app/server/RendezvousServer.cpp index 1fed68bcb8446e..3c3b32010e22f6 100644 --- a/src/app/server/RendezvousServer.cpp +++ b/src/app/server/RendezvousServer.cpp @@ -20,7 +20,10 @@ #include #include #include +#include +#include #include +#include #if CHIP_ENABLE_OPENTHREAD #include @@ -35,8 +38,8 @@ namespace chip { RendezvousServer::RendezvousServer() : mRendezvousSession(this) {} -CHIP_ERROR RendezvousServer::Init(const RendezvousParameters & params, TransportMgrBase * transportMgr, - SecureSessionMgr * sessionMgr, Transport::AdminPairingInfo * admin) +CHIP_ERROR RendezvousServer::WaitForPairing(const RendezvousParameters & params, TransportMgrBase * transportMgr, + SecureSessionMgr * sessionMgr, Transport::AdminPairingInfo * admin) { return mRendezvousSession.Init(params, transportMgr, sessionMgr, admin); } @@ -63,6 +66,17 @@ void RendezvousServer::OnRendezvousMessageReceived(const PacketHeader & packetHe void RendezvousServer::OnRendezvousComplete() { ChipLogProgress(AppServer, "Device completed Rendezvous process"); + StorablePeerConnection connection(mRendezvousSession.GetPairingSession(), mRendezvousSession.GetAdminId()); + + VerifyOrReturn(mStorage != nullptr, + ChipLogError(AppServer, "Storage delegate is not available. Cannot store the connection state")); + VerifyOrReturn(connection.StoreIntoKVS(*mStorage) == CHIP_NO_ERROR, + ChipLogError(AppServer, "Failed to store the connection state")); + + uint16_t nextKeyId = mRendezvousSession.GetNextKeyId(); + VerifyOrReturn(CanCastTo(sizeof(nextKeyId)), ChipLogError(AppServer, "Cannot cast the KeyID to uint16_t type")); + uint16_t size = static_cast(sizeof(nextKeyId)); + mStorage->SetKeyValue(kStorablePeerConnectionCountKey, &nextKeyId, size); } void RendezvousServer::OnRendezvousStatusUpdate(Status status, CHIP_ERROR err) diff --git a/src/app/server/RendezvousServer.h b/src/app/server/RendezvousServer.h index 147ef7a52a62f1..b3c493613de036 100644 --- a/src/app/server/RendezvousServer.h +++ b/src/app/server/RendezvousServer.h @@ -18,7 +18,9 @@ #pragma once #include +#include #include +#include #include namespace chip { @@ -28,9 +30,16 @@ class RendezvousServer : public RendezvousSessionDelegate public: RendezvousServer(); - CHIP_ERROR Init(const RendezvousParameters & params, TransportMgrBase * transportMgr, SecureSessionMgr * sessionMgr, - Transport::AdminPairingInfo * admin); - void SetDelegate(AppDelegate * delegate) { mDelegate = delegate; }; + CHIP_ERROR WaitForPairing(const RendezvousParameters & params, TransportMgrBase * transportMgr, SecureSessionMgr * sessionMgr, + Transport::AdminPairingInfo * admin); + + CHIP_ERROR Init(AppDelegate * delegate, PersistentStorageDelegate * storage) + { + VerifyOrReturnError(storage != nullptr, CHIP_ERROR_INVALID_ARGUMENT); + mDelegate = delegate; + mStorage = storage; + return CHIP_NO_ERROR; + } //////////////// RendezvousSessionDelegate Implementation /////////////////// @@ -46,6 +55,7 @@ class RendezvousServer : public RendezvousSessionDelegate private: RendezvousSession mRendezvousSession; AppDelegate * mDelegate; + PersistentStorageDelegate * mStorage = nullptr; }; } // namespace chip diff --git a/src/app/server/Server.cpp b/src/app/server/Server.cpp index a807fd0674359d..6128739871c53d 100644 --- a/src/app/server/Server.cpp +++ b/src/app/server/Server.cpp @@ -23,12 +23,14 @@ #include #include +#include #include #include #include #include #include #include +#include #include #include #include @@ -39,6 +41,7 @@ #include #include #include +#include using namespace ::chip; using namespace ::chip::Inet; @@ -70,6 +73,133 @@ constexpr bool useTestPairing() #endif } +class ServerStorageDelegate : public PersistentStorageDelegate +{ + void SetDelegate(PersistentStorageResultDelegate * delegate) override + { + ChipLogError(AppServer, "ServerStorageDelegate does not support async operations"); + chipDie(); + } + + void GetKeyValue(const char * key) override + { + ChipLogError(AppServer, "ServerStorageDelegate does not support async operations"); + chipDie(); + } + + void SetKeyValue(const char * key, const char * value) override + { + ChipLogError(AppServer, "ServerStorageDelegate does not support async operations"); + chipDie(); + } + + CHIP_ERROR GetKeyValue(const char * key, void * buffer, uint16_t & size) override + { + return PersistedStorage::KeyValueStoreMgr().Get(key, buffer, size); + } + + CHIP_ERROR SetKeyValue(const char * key, const void * value, uint16_t size) override + { + return PersistedStorage::KeyValueStoreMgr().Put(key, value, size); + } + + void DeleteKeyValue(const char * key) override { PersistedStorage::KeyValueStoreMgr().Delete(key); } +}; + +ServerStorageDelegate gServerStorage; + +CHIP_ERROR PersistAdminPairingToKVS(AdminPairingInfo * admin, AdminId nextAvailableId) +{ + ReturnErrorCodeIf(admin == nullptr, CHIP_ERROR_INVALID_ARGUMENT); + ChipLogProgress(AppServer, "Persisting admin ID %d, next available %d", admin->GetAdminId(), nextAvailableId); + + ReturnErrorOnFailure(admin->StoreIntoKVS(gServerStorage)); + ReturnErrorOnFailure(PersistedStorage::KeyValueStoreMgr().Put(kAdminTableCountKey, &nextAvailableId, sizeof(nextAvailableId))); + + ChipLogProgress(AppServer, "Persisting admin ID successfully"); + return CHIP_NO_ERROR; +} + +CHIP_ERROR RestoreAllAdminPairingsFromKVS(AdminPairingTable & adminPairings, AdminId & nextAvailableId) +{ + // It's not an error if the key doesn't exist. Just return right away. + VerifyOrReturnError(PersistedStorage::KeyValueStoreMgr().Get(kAdminTableCountKey, &nextAvailableId) == CHIP_NO_ERROR, + CHIP_NO_ERROR); + ChipLogProgress(AppServer, "Next available admin ID is %d", nextAvailableId); + + // TODO: The admin ID space allocation should be re-evaluated. With the current approach, the space could be + // exhausted while IDs are still available (e.g. if the admin IDs are allocated and freed over a period of time). + // Also, the current approach can make ID lookup slower as more IDs are allocated and freed. + for (AdminId id = 0; id < nextAvailableId; id++) + { + AdminPairingInfo * admin = adminPairings.AssignAdminId(id); + // Recreate the binding if one exists in persistent storage. Else skip to the next ID + if (admin->FetchFromKVS(gServerStorage) != CHIP_NO_ERROR) + { + adminPairings.ReleaseAdminId(id); + } + else + { + ChipLogProgress(AppServer, "Found admin pairing for %d, node ID %llu", admin->GetAdminId(), admin->GetNodeId()); + } + } + + return CHIP_NO_ERROR; +} + +void EraseAllAdminPairingsUpTo(AdminId nextAvailableId) +{ + PersistedStorage::KeyValueStoreMgr().Delete(kAdminTableCountKey); + + for (AdminId id = 0; id < nextAvailableId; id++) + { + AdminPairingInfo::DeleteFromKVS(gServerStorage, id); + } +} + +static CHIP_ERROR RestoreAllSessionsFromKVS(SecureSessionMgr & sessionMgr, RendezvousServer & server) +{ + uint16_t nextSessionKeyId = 0; + // It's not an error if the key doesn't exist. Just return right away. + VerifyOrReturnError(PersistedStorage::KeyValueStoreMgr().Get(kStorablePeerConnectionCountKey, &nextSessionKeyId) == + CHIP_NO_ERROR, + CHIP_NO_ERROR); + ChipLogProgress(AppServer, "Found %d stored connections", nextSessionKeyId); + + PASESession * session = chip::Platform::New(); + VerifyOrReturnError(session != nullptr, CHIP_ERROR_NO_MEMORY); + + for (uint16_t keyId = 0; keyId < nextSessionKeyId; keyId++) + { + StorablePeerConnection connection; + if (CHIP_NO_ERROR == connection.FetchFromKVS(gServerStorage, keyId)) + { + connection.GetPASESession(session); + + ChipLogProgress(AppServer, "Fetched the session information: from %llu", session->PeerConnection().GetPeerNodeId()); + sessionMgr.NewPairing(Optional::Value(session->PeerConnection().GetPeerAddress()), + session->PeerConnection().GetPeerNodeId(), session, + SecureSessionMgr::PairingDirection::kResponder, connection.GetAdminId(), nullptr); + session->Clear(); + } + } + + chip::Platform::Delete(session); + + server.GetRendezvousSession()->SetNextKeyId(nextSessionKeyId); + return CHIP_NO_ERROR; +} + +void EraseAllSessionsUpTo(uint16_t nextSessionKeyId) +{ + PersistedStorage::KeyValueStoreMgr().Delete(kStorablePeerConnectionCountKey); + + for (uint16_t keyId = 0; keyId < nextSessionKeyId; keyId++) + { + StorablePeerConnection::DeleteFromKVS(gServerStorage, keyId); + } +} + // TODO: The following class is setting the discriminator in Persistent Storage. This is // is needed since BLE reads the discriminator using ConfigurationMgr APIs. The // better solution will be to pass the discriminator to BLE without changing it @@ -108,6 +238,8 @@ class DeviceDiscriminatorCache }; DeviceDiscriminatorCache gDeviceDiscriminatorCache; +AdminPairingTable gAdminPairings; +AdminId gNextAvailableAdminId = 0; class ServerRendezvousAdvertisementDelegate : public RendezvousAdvertisementDelegate { @@ -126,24 +258,31 @@ class ServerRendezvousAdvertisementDelegate : public RendezvousAdvertisementDele gDeviceDiscriminatorCache.RestoreDiscriminator(); ReturnErrorOnFailure(chip::DeviceLayer::ConnectivityMgr().SetBLEAdvertisingEnabled(false)); - if (mDelegate != nullptr) { - mDelegate->OnPairingWindowClosed(); + if (mDelegate != nullptr) + mDelegate->OnPairingWindowClosed(); + } + + AdminPairingInfo * admin = gAdminPairings.FindAdmin(mAdmin); + if (admin != nullptr) + { + ReturnErrorOnFailure(PersistAdminPairingToKVS(admin, gNextAvailableAdminId)); } return CHIP_NO_ERROR; } void SetDelegate(AppDelegate * delegate) { mDelegate = delegate; } + void SetAdminId(AdminId id) { mAdmin = id; } + private: AppDelegate * mDelegate = nullptr; + AdminId mAdmin; }; DemoTransportMgr gTransports; SecureSessionMgr gSessions; RendezvousServer gRendezvousServer; -AdminPairingTable gAdminPairings; -AdminId gNextAvailableAdminId = 0; ServerRendezvousAdvertisementDelegate gAdvDelegate; @@ -167,7 +306,7 @@ static CHIP_ERROR OpenPairingWindowUsingVerifier(uint16_t discriminator, PASEVer VerifyOrReturnError(adminInfo != nullptr, CHIP_ERROR_NO_MEMORY); gNextAvailableAdminId++; - return gRendezvousServer.Init(std::move(params), &gTransports, &gSessions, adminInfo); + return gRendezvousServer.WaitForPairing(std::move(params), &gTransports, &gSessions, adminInfo); } class ServerCallback : public SecureSessionMgrDelegate @@ -357,6 +496,9 @@ CHIP_ERROR OpenDefaultPairingWindow(ResetAdmins resetAdmins) if (resetAdmins == ResetAdmins::kYes) { + uint16_t nextKeyId = gRendezvousServer.GetRendezvousSession()->GetNextKeyId(); + EraseAllAdminPairingsUpTo(gNextAvailableAdminId); + EraseAllSessionsUpTo(nextKeyId); gNextAvailableAdminId = 0; gAdminPairings.Reset(); } @@ -366,7 +508,7 @@ CHIP_ERROR OpenDefaultPairingWindow(ResetAdmins resetAdmins) VerifyOrReturnError(adminInfo != nullptr, CHIP_ERROR_NO_MEMORY); gNextAvailableAdminId++; - return gRendezvousServer.Init(std::move(params), &gTransports, &gSessions, adminInfo); + return gRendezvousServer.WaitForPairing(std::move(params), &gTransports, &gSessions, adminInfo); } // The function will initialize datamodel handler and then start the server @@ -376,9 +518,14 @@ void InitServer(AppDelegate * delegate) CHIP_ERROR err = CHIP_NO_ERROR; Optional peer(Transport::Type::kUndefined); + chip::Platform::MemoryInit(); + InitDataModelHandler(); gCallbacks.SetDelegate(delegate); - gRendezvousServer.SetDelegate(delegate); + + err = gRendezvousServer.Init(delegate, &gServerStorage); + SuccessOrExit(err); + gAdvDelegate.SetDelegate(delegate); // Init transport before operations with secure session mgr. @@ -423,6 +570,13 @@ void InitServer(AppDelegate * delegate) // If the network is already provisioned, proactively disable BLE advertisement. ChipLogProgress(AppServer, "Network already provisioned. Disabling BLE advertisement"); chip::DeviceLayer::ConnectivityMgr().SetBLEAdvertisingEnabled(false); + + // Restore any previous admin pairings + VerifyOrExit(CHIP_NO_ERROR == RestoreAllAdminPairingsFromKVS(gAdminPairings, gNextAvailableAdminId), + ChipLogError(AppServer, "Could not restore admin table")); + + VerifyOrExit(CHIP_NO_ERROR == RestoreAllSessionsFromKVS(gSessions, gRendezvousServer), + ChipLogError(AppServer, "Could not restore previous sessions")); } else { diff --git a/src/controller/CHIPDeviceController.h b/src/controller/CHIPDeviceController.h index b7534f46b3f75e..426cc2847fb7f9 100644 --- a/src/controller/CHIPDeviceController.h +++ b/src/controller/CHIPDeviceController.h @@ -29,8 +29,8 @@ #pragma once #include -#include #include +#include #include #include #include diff --git a/src/controller/CHIPDeviceController_deprecated.h b/src/controller/CHIPDeviceController_deprecated.h index 246204a9d45211..d4572b8f548bab 100644 --- a/src/controller/CHIPDeviceController_deprecated.h +++ b/src/controller/CHIPDeviceController_deprecated.h @@ -29,8 +29,8 @@ #pragma once #include -#include #include +#include #include #include #include @@ -68,13 +68,13 @@ class DLL_EXPORT ChipDeviceController : public Controller::DeviceStatusDelegate * System::Layer and InetLayer. */ CHIP_ERROR Init(NodeId localDeviceId, Controller::DevicePairingDelegate * pairingDelegate = nullptr, - Controller::PersistentStorageDelegate * storageDelegate = nullptr); + PersistentStorageDelegate * storageDelegate = nullptr); /** * Init function to be used when already-initialized System::Layer and InetLayer are available. */ CHIP_ERROR Init(NodeId localDeviceId, System::Layer * systemLayer, Inet::InetLayer * inetLayer, - Controller::DevicePairingDelegate * pairingDelegate = nullptr, - Controller::PersistentStorageDelegate * storageDelegate = nullptr); + Controller::DevicePairingDelegate * pairingDelegate = nullptr, + PersistentStorageDelegate * storageDelegate = nullptr); CHIP_ERROR Shutdown(); CHIP_ERROR SetUdpListenPort(uint16_t listenPort); diff --git a/src/controller/python/ChipDeviceController-StorageDelegate.cpp b/src/controller/python/ChipDeviceController-StorageDelegate.cpp index 31770e32fd1c68..96f7efcc6ae4ca 100644 --- a/src/controller/python/ChipDeviceController-StorageDelegate.cpp +++ b/src/controller/python/ChipDeviceController-StorageDelegate.cpp @@ -23,7 +23,7 @@ #include #include -#include +#include #include namespace chip { diff --git a/src/controller/python/ChipDeviceController-StorageDelegate.h b/src/controller/python/ChipDeviceController-StorageDelegate.h index e88dc6359fa533..ee4a5a0165f4f4 100644 --- a/src/controller/python/ChipDeviceController-StorageDelegate.h +++ b/src/controller/python/ChipDeviceController-StorageDelegate.h @@ -21,7 +21,7 @@ #include #include -#include +#include class PythonPersistentStorageDelegate; diff --git a/src/darwin/Framework/CHIP/CHIPPersistentStorageDelegateBridge.h b/src/darwin/Framework/CHIP/CHIPPersistentStorageDelegateBridge.h index ff2fec0a3b4ad3..58941447e1487c 100644 --- a/src/darwin/Framework/CHIP/CHIPPersistentStorageDelegateBridge.h +++ b/src/darwin/Framework/CHIP/CHIPPersistentStorageDelegateBridge.h @@ -18,11 +18,11 @@ #import "CHIPPersistentStorageDelegate.h" #import "CHIPError.h" -#include +#include NS_ASSUME_NONNULL_BEGIN -class CHIPPersistentStorageDelegateBridge : public chip::Controller::PersistentStorageDelegate +class CHIPPersistentStorageDelegateBridge : public chip::PersistentStorageDelegate { public: CHIPPersistentStorageDelegateBridge(); @@ -30,7 +30,7 @@ class CHIPPersistentStorageDelegateBridge : public chip::Controller::PersistentS void setFrameworkDelegate(id delegate, dispatch_queue_t queue); - void SetDelegate(chip::Controller::PersistentStorageResultDelegate * delegate) override; + void SetDelegate(chip::PersistentStorageResultDelegate * delegate) override; void GetKeyValue(const char * key) override; @@ -44,7 +44,7 @@ class CHIPPersistentStorageDelegateBridge : public chip::Controller::PersistentS id mDelegate; dispatch_queue_t mQueue; - chip::Controller::PersistentStorageResultDelegate * mCallback; + chip::PersistentStorageResultDelegate * mCallback; SendKeyValue mCompletionHandler; CHIPSendSetStatus mSetStatusHandler; CHIPSendDeleteStatus mDeleteStatusHandler; diff --git a/src/darwin/Framework/CHIP/CHIPPersistentStorageDelegateBridge.mm b/src/darwin/Framework/CHIP/CHIPPersistentStorageDelegateBridge.mm index f841550517623d..1be4b605ce3d78 100644 --- a/src/darwin/Framework/CHIP/CHIPPersistentStorageDelegateBridge.mm +++ b/src/darwin/Framework/CHIP/CHIPPersistentStorageDelegateBridge.mm @@ -39,14 +39,14 @@ }); } -void CHIPPersistentStorageDelegateBridge::SetDelegate(chip::Controller::PersistentStorageResultDelegate * delegate) +void CHIPPersistentStorageDelegateBridge::SetDelegate(chip::PersistentStorageResultDelegate * delegate) { dispatch_async(mWorkQueue, ^{ if (delegate) { mCallback = delegate; mCompletionHandler = ^(NSString * key, NSString * value) { - chip::Controller::PersistentStorageResultDelegate * callback = mCallback; + chip::PersistentStorageResultDelegate * callback = mCallback; if (callback) { dispatch_async(mWorkQueue, ^{ callback->OnValue([key UTF8String], [value UTF8String]); @@ -55,20 +55,20 @@ }; mSetStatusHandler = ^(NSString * key, NSError * status) { - chip::Controller::PersistentStorageResultDelegate * callback = mCallback; + chip::PersistentStorageResultDelegate * callback = mCallback; if (callback) { dispatch_async(mWorkQueue, ^{ - callback->OnStatus([key UTF8String], chip::Controller::PersistentStorageResultDelegate::Operation::kSET, + callback->OnStatus([key UTF8String], chip::PersistentStorageResultDelegate::Operation::kSET, [CHIPError errorToCHIPErrorCode:status]); }); } }; mDeleteStatusHandler = ^(NSString * key, NSError * status) { - chip::Controller::PersistentStorageResultDelegate * callback = mCallback; + chip::PersistentStorageResultDelegate * callback = mCallback; if (callback) { dispatch_async(mWorkQueue, ^{ - callback->OnStatus([key UTF8String], chip::Controller::PersistentStorageResultDelegate::Operation::kDELETE, + callback->OnStatus([key UTF8String], chip::PersistentStorageResultDelegate::Operation::kDELETE, [CHIPError errorToCHIPErrorCode:status]); }); } diff --git a/src/controller/CHIPPersistentStorageDelegate.h b/src/lib/core/CHIPPersistentStorageDelegate.h similarity index 73% rename from src/controller/CHIPPersistentStorageDelegate.h rename to src/lib/core/CHIPPersistentStorageDelegate.h index a2176f2bc63b80..b502ff75d7a90c 100644 --- a/src/controller/CHIPPersistentStorageDelegate.h +++ b/src/lib/core/CHIPPersistentStorageDelegate.h @@ -22,7 +22,6 @@ #include namespace chip { -namespace Controller { class DLL_EXPORT PersistentStorageResultDelegate { @@ -96,13 +95,40 @@ class DLL_EXPORT PersistentStorageDelegate /** * @brief - * Set the value for the key + * This is a synchronous Get API, where the value is returned via the output + * buffer. This API should be used sparingly, since it may block for + * some duration. + * + * This API can be used to retrieve a byte buffer value from the storage. + * + * @param[in] key Key to lookup + * @param[out] buffer Value for the key + * @param[in, out] size Input value buffer size, output length of value. + * The output length could be larger than input value. In + * such cases, the user should allocate the buffer large + * enough (>= output length), and call the API again. + */ + virtual CHIP_ERROR GetKeyValue(const char * key, void * buffer, uint16_t & size) { return CHIP_ERROR_NOT_IMPLEMENTED; } + + /** + * @brief + * Set the value for the key to a null terminated string. * * @param[in] key Key to be set * @param[in] value Value to be set */ virtual void SetKeyValue(const char * key, const char * value) = 0; + /** + * @brief + * Set the value for the key to a byte buffer. + * + * @param[in] key Key to be set + * @param[in] value Value to be set + * @param[in] size Size of the Value + */ + virtual CHIP_ERROR SetKeyValue(const char * key, const void * value, uint16_t size) { return CHIP_ERROR_NOT_IMPLEMENTED; } + /** * @brief * Deletes the value for the key @@ -112,5 +138,4 @@ class DLL_EXPORT PersistentStorageDelegate virtual void DeleteKeyValue(const char * key) = 0; }; -} // namespace Controller } // namespace chip diff --git a/src/platform/BUILD.gn b/src/platform/BUILD.gn index 7afbd9924c51f8..8d9dd43340a876 100644 --- a/src/platform/BUILD.gn +++ b/src/platform/BUILD.gn @@ -253,6 +253,8 @@ if (chip_device_platform != "none" && chip_device_platform != "external") { "cc13x2_26x2/DeviceNetworkProvisioningDelegateImpl.cpp", "cc13x2_26x2/DeviceNetworkProvisioningDelegateImpl.h", "cc13x2_26x2/InetPlatformConfig.h", + "cc13x2_26x2/KeyValueStoreManagerImpl.cpp", + "cc13x2_26x2/KeyValueStoreManagerImpl.h", "cc13x2_26x2/Logging.cpp", "cc13x2_26x2/PlatformManagerImpl.cpp", "cc13x2_26x2/PlatformManagerImpl.h", @@ -309,6 +311,11 @@ if (chip_device_platform != "none" && chip_device_platform != "external") { "Darwin/SystemPlatformConfig.h", ] + sources += [ + "Darwin/KeyValueStoreManagerImpl.cpp", + "Darwin/KeyValueStoreManagerImpl.h", + ] + if (chip_enable_ble) { sources += [ "Darwin/BleApplicationDelegate.h", @@ -354,7 +361,10 @@ if (chip_device_platform != "none" && chip_device_platform != "external") { "$dir_pw_kvs:crc16", "$dir_pw_log", ] - public_deps += [ "$dir_pw_kvs" ] + public_deps += [ + "$dir_pw_checksum", + "$dir_pw_kvs", + ] sources += [ "EFR32/KeyValueStoreManagerImpl.cpp", "EFR32/KeyValueStoreManagerImpl.h", @@ -417,6 +427,8 @@ if (chip_device_platform != "none" && chip_device_platform != "external") { "K32W/DeviceNetworkProvisioningDelegateImpl.h", "K32W/K32WConfig.cpp", "K32W/K32WConfig.h", + "K32W/KeyValueStoreManagerImpl.cpp", + "K32W/KeyValueStoreManagerImpl.h", "K32W/Logging.cpp", "K32W/NetworkProvisioningServerImpl.h", "K32W/PlatformManagerImpl.cpp", @@ -554,6 +566,11 @@ if (chip_device_platform != "none" && chip_device_platform != "external") { "qpg6100/qpg6100Config.h", ] + sources += [ + "qpg6100/KeyValueStoreManagerImpl.cpp", + "qpg6100/KeyValueStoreManagerImpl.h", + ] + if (chip_enable_openthread) { public_deps += [ "${openthread_root}:libopenthread-ftd" ] diff --git a/src/platform/Darwin/KeyValueStoreManagerImpl.cpp b/src/platform/Darwin/KeyValueStoreManagerImpl.cpp new file mode 100644 index 00000000000000..40c3fdeecb23f1 --- /dev/null +++ b/src/platform/Darwin/KeyValueStoreManagerImpl.cpp @@ -0,0 +1,34 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * Platform-specific key value storage implementation for Darwin + */ + +#include + +namespace chip { +namespace DeviceLayer { +namespace PersistedStorage { + +KeyValueStoreManagerImpl KeyValueStoreManagerImpl::sInstance; + +} // namespace PersistedStorage +} // namespace DeviceLayer +} // namespace chip diff --git a/src/platform/Darwin/KeyValueStoreManagerImpl.h b/src/platform/Darwin/KeyValueStoreManagerImpl.h new file mode 100644 index 00000000000000..c72b9c8bf51d08 --- /dev/null +++ b/src/platform/Darwin/KeyValueStoreManagerImpl.h @@ -0,0 +1,80 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * Platform-specific key value storage implementation for Darwin. + */ + +#pragma once + +namespace chip { +namespace DeviceLayer { +namespace PersistedStorage { + +class KeyValueStoreManagerImpl final : public KeyValueStoreManager +{ + // Allow the KeyValueStoreManager interface class to delegate method calls to + // the implementation methods provided by this class. + friend class KeyValueStoreManager; + +public: + // NOTE: Currently this platform does not support partial and offset reads + // these will return CHIP_ERROR_NOT_IMPLEMENTED. + CHIP_ERROR _Get(const char * key, void * value, size_t value_size, size_t * read_bytes_size = nullptr, size_t offset = 0) + { + return CHIP_ERROR_NOT_IMPLEMENTED; + } + + CHIP_ERROR _Delete(const char * key) { return CHIP_ERROR_NOT_IMPLEMENTED; } + + CHIP_ERROR _Put(const char * key, const void * value, size_t value_size) { return CHIP_ERROR_NOT_IMPLEMENTED; } + +private: + // ===== Members for internal use by the following friends. + friend KeyValueStoreManager & KeyValueStoreMgr(); + friend KeyValueStoreManagerImpl & KeyValueStoreMgrImpl(); + + static KeyValueStoreManagerImpl sInstance; +}; + +/** + * Returns the public interface of the KeyValueStoreManager singleton object. + * + * Chip applications should use this to access features of the KeyValueStoreManager object + * that are common to all platforms. + */ +inline KeyValueStoreManager & KeyValueStoreMgr(void) +{ + return KeyValueStoreManagerImpl::sInstance; +} + +/** + * Returns the platform-specific implementation of the KeyValueStoreManager singleton object. + * + * Chip applications can use this to gain access to features of the KeyValueStoreManager + * that are specific to the ESP32 platform. + */ +inline KeyValueStoreManagerImpl & KeyValueStoreMgrImpl(void) +{ + return KeyValueStoreManagerImpl::sInstance; +} + +} // namespace PersistedStorage +} // namespace DeviceLayer +} // namespace chip diff --git a/src/platform/K32W/KeyValueStoreManagerImpl.cpp b/src/platform/K32W/KeyValueStoreManagerImpl.cpp new file mode 100644 index 00000000000000..84eff6796744f2 --- /dev/null +++ b/src/platform/K32W/KeyValueStoreManagerImpl.cpp @@ -0,0 +1,34 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * Platform-specific key value storage implementation for K32W + */ + +#include + +namespace chip { +namespace DeviceLayer { +namespace PersistedStorage { + +KeyValueStoreManagerImpl KeyValueStoreManagerImpl::sInstance; + +} // namespace PersistedStorage +} // namespace DeviceLayer +} // namespace chip diff --git a/src/platform/K32W/KeyValueStoreManagerImpl.h b/src/platform/K32W/KeyValueStoreManagerImpl.h new file mode 100644 index 00000000000000..12ed71ef619b31 --- /dev/null +++ b/src/platform/K32W/KeyValueStoreManagerImpl.h @@ -0,0 +1,80 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * Platform-specific key value storage implementation for K32W + */ + +#pragma once + +namespace chip { +namespace DeviceLayer { +namespace PersistedStorage { + +class KeyValueStoreManagerImpl final : public KeyValueStoreManager +{ + // Allow the KeyValueStoreManager interface class to delegate method calls to + // the implementation methods provided by this class. + friend class KeyValueStoreManager; + +public: + // NOTE: Currently this platform does not support partial and offset reads + // these will return CHIP_ERROR_NOT_IMPLEMENTED. + CHIP_ERROR _Get(const char * key, void * value, size_t value_size, size_t * read_bytes_size = nullptr, size_t offset = 0) + { + return CHIP_ERROR_NOT_IMPLEMENTED; + } + + CHIP_ERROR _Delete(const char * key) { return CHIP_ERROR_NOT_IMPLEMENTED; } + + CHIP_ERROR _Put(const char * key, const void * value, size_t value_size) { return CHIP_ERROR_NOT_IMPLEMENTED; } + +private: + // ===== Members for internal use by the following friends. + friend KeyValueStoreManager & KeyValueStoreMgr(); + friend KeyValueStoreManagerImpl & KeyValueStoreMgrImpl(); + + static KeyValueStoreManagerImpl sInstance; +}; + +/** + * Returns the public interface of the KeyValueStoreManager singleton object. + * + * Chip applications should use this to access features of the KeyValueStoreManager object + * that are common to all platforms. + */ +inline KeyValueStoreManager & KeyValueStoreMgr(void) +{ + return KeyValueStoreManagerImpl::sInstance; +} + +/** + * Returns the platform-specific implementation of the KeyValueStoreManager singleton object. + * + * Chip applications can use this to gain access to features of the KeyValueStoreManager + * that are specific to the ESP32 platform. + */ +inline KeyValueStoreManagerImpl & KeyValueStoreMgrImpl(void) +{ + return KeyValueStoreManagerImpl::sInstance; +} + +} // namespace PersistedStorage +} // namespace DeviceLayer +} // namespace chip diff --git a/src/platform/cc13x2_26x2/KeyValueStoreManagerImpl.cpp b/src/platform/cc13x2_26x2/KeyValueStoreManagerImpl.cpp new file mode 100644 index 00000000000000..4d982b58126610 --- /dev/null +++ b/src/platform/cc13x2_26x2/KeyValueStoreManagerImpl.cpp @@ -0,0 +1,34 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * Platform-specific key value storage implementation for CC1352 + */ + +#include + +namespace chip { +namespace DeviceLayer { +namespace PersistedStorage { + +KeyValueStoreManagerImpl KeyValueStoreManagerImpl::sInstance; + +} // namespace PersistedStorage +} // namespace DeviceLayer +} // namespace chip diff --git a/src/platform/cc13x2_26x2/KeyValueStoreManagerImpl.h b/src/platform/cc13x2_26x2/KeyValueStoreManagerImpl.h new file mode 100644 index 00000000000000..24f46ee57d1356 --- /dev/null +++ b/src/platform/cc13x2_26x2/KeyValueStoreManagerImpl.h @@ -0,0 +1,80 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * Platform-specific key value storage implementation for CC1352. + */ + +#pragma once + +namespace chip { +namespace DeviceLayer { +namespace PersistedStorage { + +class KeyValueStoreManagerImpl final : public KeyValueStoreManager +{ + // Allow the KeyValueStoreManager interface class to delegate method calls to + // the implementation methods provided by this class. + friend class KeyValueStoreManager; + +public: + // NOTE: Currently this platform does not support partial and offset reads + // these will return CHIP_ERROR_NOT_IMPLEMENTED. + CHIP_ERROR _Get(const char * key, void * value, size_t value_size, size_t * read_bytes_size = nullptr, size_t offset = 0) + { + return CHIP_ERROR_NOT_IMPLEMENTED; + } + + CHIP_ERROR _Delete(const char * key) { return CHIP_ERROR_NOT_IMPLEMENTED; } + + CHIP_ERROR _Put(const char * key, const void * value, size_t value_size) { return CHIP_ERROR_NOT_IMPLEMENTED; } + +private: + // ===== Members for internal use by the following friends. + friend KeyValueStoreManager & KeyValueStoreMgr(); + friend KeyValueStoreManagerImpl & KeyValueStoreMgrImpl(); + + static KeyValueStoreManagerImpl sInstance; +}; + +/** + * Returns the public interface of the KeyValueStoreManager singleton object. + * + * Chip applications should use this to access features of the KeyValueStoreManager object + * that are common to all platforms. + */ +inline KeyValueStoreManager & KeyValueStoreMgr(void) +{ + return KeyValueStoreManagerImpl::sInstance; +} + +/** + * Returns the platform-specific implementation of the KeyValueStoreManager singleton object. + * + * Chip applications can use this to gain access to features of the KeyValueStoreManager + * that are specific to the ESP32 platform. + */ +inline KeyValueStoreManagerImpl & KeyValueStoreMgrImpl(void) +{ + return KeyValueStoreManagerImpl::sInstance; +} + +} // namespace PersistedStorage +} // namespace DeviceLayer +} // namespace chip diff --git a/src/platform/qpg6100/KeyValueStoreManagerImpl.cpp b/src/platform/qpg6100/KeyValueStoreManagerImpl.cpp new file mode 100644 index 00000000000000..c213ee6820c549 --- /dev/null +++ b/src/platform/qpg6100/KeyValueStoreManagerImpl.cpp @@ -0,0 +1,34 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * Platform-specific key value storage implementation for QPG6100 + */ + +#include + +namespace chip { +namespace DeviceLayer { +namespace PersistedStorage { + +KeyValueStoreManagerImpl KeyValueStoreManagerImpl::sInstance; + +} // namespace PersistedStorage +} // namespace DeviceLayer +} // namespace chip diff --git a/src/platform/qpg6100/KeyValueStoreManagerImpl.h b/src/platform/qpg6100/KeyValueStoreManagerImpl.h new file mode 100644 index 00000000000000..8d90fa3856dccd --- /dev/null +++ b/src/platform/qpg6100/KeyValueStoreManagerImpl.h @@ -0,0 +1,80 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * Platform-specific key value storage implementation for QPG6100. + */ + +#pragma once + +namespace chip { +namespace DeviceLayer { +namespace PersistedStorage { + +class KeyValueStoreManagerImpl final : public KeyValueStoreManager +{ + // Allow the KeyValueStoreManager interface class to delegate method calls to + // the implementation methods provided by this class. + friend class KeyValueStoreManager; + +public: + // NOTE: Currently this platform does not support partial and offset reads + // these will return CHIP_ERROR_NOT_IMPLEMENTED. + CHIP_ERROR _Get(const char * key, void * value, size_t value_size, size_t * read_bytes_size = nullptr, size_t offset = 0) + { + return CHIP_ERROR_NOT_IMPLEMENTED; + } + + CHIP_ERROR _Delete(const char * key) { return CHIP_ERROR_NOT_IMPLEMENTED; } + + CHIP_ERROR _Put(const char * key, const void * value, size_t value_size) { return CHIP_ERROR_NOT_IMPLEMENTED; } + +private: + // ===== Members for internal use by the following friends. + friend KeyValueStoreManager & KeyValueStoreMgr(); + friend KeyValueStoreManagerImpl & KeyValueStoreMgrImpl(); + + static KeyValueStoreManagerImpl sInstance; +}; + +/** + * Returns the public interface of the KeyValueStoreManager singleton object. + * + * Chip applications should use this to access features of the KeyValueStoreManager object + * that are common to all platforms. + */ +inline KeyValueStoreManager & KeyValueStoreMgr(void) +{ + return KeyValueStoreManagerImpl::sInstance; +} + +/** + * Returns the platform-specific implementation of the KeyValueStoreManager singleton object. + * + * Chip applications can use this to gain access to features of the KeyValueStoreManager + * that are specific to the ESP32 platform. + */ +inline KeyValueStoreManagerImpl & KeyValueStoreMgrImpl(void) +{ + return KeyValueStoreManagerImpl::sInstance; +} + +} // namespace PersistedStorage +} // namespace DeviceLayer +} // namespace chip diff --git a/src/transport/AdminPairingTable.cpp b/src/transport/AdminPairingTable.cpp new file mode 100644 index 00000000000000..b8ee7c71680006 --- /dev/null +++ b/src/transport/AdminPairingTable.cpp @@ -0,0 +1,144 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @brief Defines a table of admins that have provisioned the device. + */ + +#include +#include +#include +#include +#include + +namespace chip { +namespace Transport { + +CHIP_ERROR AdminPairingInfo::StoreIntoKVS(PersistentStorageDelegate & kvs) +{ + char key[KeySize()]; + ReturnErrorOnFailure(GenerateKey(mAdmin, key, sizeof(key))); + + StorableAdminPairingInfo info; + info.mNodeId = Encoding::LittleEndian::HostSwap64(mNodeId); + info.mAdmin = Encoding::LittleEndian::HostSwap16(mAdmin); + + VerifyOrReturnError(CanCastTo(sizeof(info)), CHIP_ERROR_INTERNAL); + uint16_t size = static_cast(sizeof(info)); + return kvs.SetKeyValue(key, &info, size); +} + +CHIP_ERROR AdminPairingInfo::FetchFromKVS(PersistentStorageDelegate & kvs) +{ + char key[KeySize()]; + ReturnErrorOnFailure(GenerateKey(mAdmin, key, sizeof(key))); + + StorableAdminPairingInfo info; + + VerifyOrReturnError(CanCastTo(sizeof(info)), CHIP_ERROR_INTERNAL); + uint16_t size = static_cast(sizeof(info)); + ReturnErrorOnFailure(kvs.GetKeyValue(key, &info, size)); + + mNodeId = Encoding::LittleEndian::HostSwap64(info.mNodeId); + AdminId id = Encoding::LittleEndian::HostSwap16(info.mAdmin); + ReturnErrorCodeIf(mAdmin != id, CHIP_ERROR_INCORRECT_STATE); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR AdminPairingInfo::DeleteFromKVS(PersistentStorageDelegate & kvs, AdminId id) +{ + char key[KeySize()]; + ReturnErrorOnFailure(GenerateKey(id, key, sizeof(key))); + + kvs.DeleteKeyValue(key); + return CHIP_NO_ERROR; +} + +constexpr size_t AdminPairingInfo::KeySize() +{ + return sizeof(kAdminTableKeyPrefix) + 2 * sizeof(AdminId); +} + +CHIP_ERROR AdminPairingInfo::GenerateKey(AdminId id, char * key, size_t len) +{ + VerifyOrReturnError(len >= KeySize(), CHIP_ERROR_INVALID_ARGUMENT); + int keySize = snprintf(key, len, "%s%x", kAdminTableKeyPrefix, id); + VerifyOrReturnError(keySize > 0, CHIP_ERROR_INTERNAL); + VerifyOrReturnError(len > (size_t) keySize, CHIP_ERROR_INTERNAL); + return CHIP_NO_ERROR; +} + +AdminPairingInfo * AdminPairingTable::AssignAdminId(AdminId adminId) +{ + for (size_t i = 0; i < CHIP_CONFIG_MAX_DEVICE_ADMINS; i++) + { + if (!mStates[i].IsInitialized()) + { + mStates[i].SetAdminId(adminId); + + return &mStates[i]; + } + } + + return nullptr; +} + +AdminPairingInfo * AdminPairingTable::AssignAdminId(AdminId adminId, NodeId nodeId) +{ + AdminPairingInfo * admin = AssignAdminId(adminId); + + if (admin != nullptr) + { + admin->SetNodeId(nodeId); + } + + return admin; +} + +void AdminPairingTable::ReleaseAdminId(AdminId adminId) +{ + AdminPairingInfo * admin = FindAdmin(adminId); + if (admin != nullptr) + { + admin->Reset(); + } +} + +AdminPairingInfo * AdminPairingTable::FindAdmin(AdminId adminId) +{ + for (size_t i = 0; i < CHIP_CONFIG_MAX_DEVICE_ADMINS; i++) + { + if (mStates[i].IsInitialized() && mStates[i].GetAdminId() == adminId) + { + return &mStates[i]; + } + } + + return nullptr; +} + +void AdminPairingTable::Reset() +{ + for (size_t i = 0; i < CHIP_CONFIG_MAX_DEVICE_ADMINS; i++) + { + return mStates[i].Reset(); + } +} + +} // namespace Transport +} // namespace chip diff --git a/src/transport/AdminPairingTable.h b/src/transport/AdminPairingTable.h index 19dd2189b72d18..b85c098b4be463 100644 --- a/src/transport/AdminPairingTable.h +++ b/src/transport/AdminPairingTable.h @@ -21,6 +21,7 @@ #pragma once +#include #include #include @@ -30,6 +31,11 @@ namespace Transport { typedef uint16_t AdminId; static constexpr AdminId kUndefinedAdminId = UINT16_MAX; +// KVS store is sensitive to length of key strings, based on the underlying +// platform. Keeping them short. +constexpr char kAdminTableKeyPrefix[] = "CHIPAdmin"; +constexpr char kAdminTableCountKey[] = "CHIPAdminNextId"; + struct OperationalCredentials { uint32_t placeholder; @@ -81,73 +87,42 @@ class DLL_EXPORT AdminPairingInfo mAdmin = kUndefinedAdminId; } + CHIP_ERROR StoreIntoKVS(PersistentStorageDelegate & kvs); + + CHIP_ERROR FetchFromKVS(PersistentStorageDelegate & kvs); + + static CHIP_ERROR DeleteFromKVS(PersistentStorageDelegate & kvs, AdminId id); + private: AdminId mAdmin = kUndefinedAdminId; NodeId mNodeId = kUndefinedNodeId; OperationalCredentials mOpCred; AccessControlList mACL; -}; - -class DLL_EXPORT AdminPairingTable -{ -public: - AdminPairingInfo * AssignAdminId(AdminId adminId) - { - for (size_t i = 0; i < CHIP_CONFIG_MAX_DEVICE_ADMINS; i++) - { - if (!mStates[i].IsInitialized()) - { - mStates[i].SetAdminId(adminId); - return &mStates[i]; - } - } + static constexpr size_t KeySize(); // { return sizeof(kAdminTableKeyPrefix) + 2 * sizeof(AdminId); } - return nullptr; - } + static CHIP_ERROR GenerateKey(AdminId id, char * key, size_t len); - AdminPairingInfo * AssignAdminId(AdminId adminId, NodeId nodeId) + struct StorableAdminPairingInfo { - AdminPairingInfo * admin = AssignAdminId(adminId); + uint16_t mAdmin; /* This field is serialized in LittleEndian byte order */ + uint64_t mNodeId; /* This field is serialized in LittleEndian byte order */ + }; +}; - if (admin != nullptr) - { - admin->SetNodeId(nodeId); - } +class DLL_EXPORT AdminPairingTable +{ +public: + AdminPairingInfo * AssignAdminId(AdminId adminId); - return admin; - } + AdminPairingInfo * AssignAdminId(AdminId adminId, NodeId nodeId); - void ReleaseAdminId(AdminId adminId) - { - AdminPairingInfo * admin = FindAdmin(adminId); - if (admin != nullptr) - { - admin->Reset(); - } - } + void ReleaseAdminId(AdminId adminId); - AdminPairingInfo * FindAdmin(AdminId adminId) - { - for (size_t i = 0; i < CHIP_CONFIG_MAX_DEVICE_ADMINS; i++) - { - if (mStates[i].IsInitialized() && mStates[i].GetAdminId() == adminId) - { - return &mStates[i]; - } - } - - return nullptr; - } + AdminPairingInfo * FindAdmin(AdminId adminId); - void Reset() - { - for (size_t i = 0; i < CHIP_CONFIG_MAX_DEVICE_ADMINS; i++) - { - return mStates[i].Reset(); - } - } + void Reset(); private: AdminPairingInfo mStates[CHIP_CONFIG_MAX_DEVICE_ADMINS]; diff --git a/src/transport/BUILD.gn b/src/transport/BUILD.gn index 3adaea5d0d8edc..ea57b63f16eb6c 100644 --- a/src/transport/BUILD.gn +++ b/src/transport/BUILD.gn @@ -13,12 +13,14 @@ # limitations under the License. import("//build_overrides/chip.gni") +import("//build_overrides/nlio.gni") import("${chip_root}/src/ble/ble.gni") static_library("transport") { output_name = "libTransportLayer" sources = [ + "AdminPairingTable.cpp", "AdminPairingTable.h", "CASESession.cpp", "CASESession.h", @@ -39,6 +41,8 @@ static_library("transport") { "SecureSessionMgr.cpp", "SecureSessionMgr.h", "SessionEstablishmentDelegate.h", + "StorablePeerConnection.cpp", + "StorablePeerConnection.h", "TransportMgr.h", "TransportMgrBase.cpp", "TransportMgrBase.h", @@ -62,5 +66,6 @@ static_library("transport") { "${chip_root}/src/platform", "${chip_root}/src/setup_payload", "${chip_root}/src/transport/raw", + "${nlio_root}:nlio", ] } diff --git a/src/transport/PASESession.h b/src/transport/PASESession.h index 494c9369a9a4cf..1b12bdccb754e5 100644 --- a/src/transport/PASESession.h +++ b/src/transport/PASESession.h @@ -150,7 +150,7 @@ class DLL_EXPORT PASESession * initialized once pairing is complete * @return CHIP_ERROR The result of session derivation */ - virtual CHIP_ERROR DeriveSecureSession(const uint8_t * info, size_t info_len, SecureSession & session); + CHIP_ERROR DeriveSecureSession(const uint8_t * info, size_t info_len, SecureSession & session); /** * @brief @@ -206,6 +206,10 @@ class DLL_EXPORT PASESession **/ CHIP_ERROR FromSerializable(const PASESessionSerializable & output); + /** @brief This function zeroes out and resets the memory used by the object. + **/ + void Clear(); + private: enum Spake2pErrorType : uint8_t { @@ -237,8 +241,6 @@ class DLL_EXPORT PASESession CHIP_ERROR AttachHeaderAndSend(Protocols::SecureChannel::MsgType msgType, System::PacketBufferHandle msgBuf); - void Clear(); - SessionEstablishmentDelegate * mDelegate = nullptr; Protocols::SecureChannel::MsgType mNextExpectedMsg = Protocols::SecureChannel::MsgType::PASE_Spake2pError; diff --git a/src/transport/RendezvousSession.cpp b/src/transport/RendezvousSession.cpp index abb1af1aaf064a..f5d25f4267614d 100644 --- a/src/transport/RendezvousSession.cpp +++ b/src/transport/RendezvousSession.cpp @@ -466,13 +466,13 @@ CHIP_ERROR RendezvousSession::WaitForPairing(uint32_t setupPINCode) UpdateState(State::kSecurePairing); return mPairingSession.WaitForPairing(setupPINCode, kSpake2p_Iteration_Count, reinterpret_cast(kSpake2pKeyExchangeSalt), - strlen(kSpake2pKeyExchangeSalt), 0, this); + strlen(kSpake2pKeyExchangeSalt), mNextKeyId++, this); } CHIP_ERROR RendezvousSession::WaitForPairing(const PASEVerifier & verifier) { UpdateState(State::kSecurePairing); - return mPairingSession.WaitForPairing(verifier, 0 /* keyId */, this); + return mPairingSession.WaitForPairing(verifier, mNextKeyId++, this); } CHIP_ERROR RendezvousSession::Pair(uint32_t setupPINCode) diff --git a/src/transport/RendezvousSession.h b/src/transport/RendezvousSession.h index 857bfe5fdc994f..91a312c6d0cd0e 100644 --- a/src/transport/RendezvousSession.h +++ b/src/transport/RendezvousSession.h @@ -142,6 +142,11 @@ class RendezvousSession : public SessionEstablishmentDelegate, */ const Inet::IPAddress & GetIPAddress() const { return mNetworkProvision.GetIPAddress(); } + Transport::AdminId GetAdminId() const { return (mAdmin != nullptr) ? mAdmin->GetAdminId() : Transport::kUndefinedAdminId; } + + uint16_t GetNextKeyId() const { return mNextKeyId; } + void SetNextKeyId(uint16_t id) { mNextKeyId = id; } + private: CHIP_ERROR HandlePairingMessage(const PacketHeader & packetHeader, const Transport::PeerAddress & peerAddress, System::PacketBufferHandle msgBuf); diff --git a/src/transport/StorablePeerConnection.cpp b/src/transport/StorablePeerConnection.cpp new file mode 100644 index 00000000000000..edb70b74f394b2 --- /dev/null +++ b/src/transport/StorablePeerConnection.cpp @@ -0,0 +1,75 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include + +namespace chip { + +StorablePeerConnection::StorablePeerConnection(PASESession & session, Transport::AdminId admin) +{ + session.ToSerializable(mSession.mOpCreds); + mSession.mAdmin = Encoding::LittleEndian::HostSwap16(admin); + mKeyId = session.GetLocalKeyId(); +} + +CHIP_ERROR StorablePeerConnection::StoreIntoKVS(PersistentStorageDelegate & kvs) +{ + char key[KeySize()]; + ReturnErrorOnFailure(GenerateKey(mKeyId, key, sizeof(key))); + + VerifyOrReturnError(CanCastTo(sizeof(mSession)), CHIP_ERROR_INTERNAL); + uint16_t size = static_cast(sizeof(mSession)); + return kvs.SetKeyValue(key, &mSession, size); +} + +CHIP_ERROR StorablePeerConnection::FetchFromKVS(PersistentStorageDelegate & kvs, uint16_t keyId) +{ + char key[KeySize()]; + ReturnErrorOnFailure(GenerateKey(keyId, key, sizeof(key))); + + VerifyOrReturnError(CanCastTo(sizeof(mSession)), CHIP_ERROR_INTERNAL); + uint16_t size = static_cast(sizeof(mSession)); + return kvs.GetKeyValue(key, &mSession, size); +} + +CHIP_ERROR StorablePeerConnection::DeleteFromKVS(PersistentStorageDelegate & kvs, uint16_t keyId) +{ + char key[KeySize()]; + ReturnErrorOnFailure(GenerateKey(keyId, key, sizeof(key))); + + kvs.DeleteKeyValue(key); + return CHIP_NO_ERROR; +} + +constexpr size_t StorablePeerConnection::KeySize() +{ + return sizeof(kStorablePeerConnectionKeyPrefix) + 2 * sizeof(uint16_t); +} + +CHIP_ERROR StorablePeerConnection::GenerateKey(uint16_t id, char * key, size_t len) +{ + VerifyOrReturnError(len >= KeySize(), CHIP_ERROR_INVALID_ARGUMENT); + int keySize = snprintf(key, len, "%s%x", kStorablePeerConnectionKeyPrefix, id); + VerifyOrReturnError(keySize > 0, CHIP_ERROR_INTERNAL); + VerifyOrReturnError(len > (size_t) keySize, CHIP_ERROR_INTERNAL); + return CHIP_NO_ERROR; +} + +} // namespace chip diff --git a/src/transport/StorablePeerConnection.h b/src/transport/StorablePeerConnection.h new file mode 100644 index 00000000000000..9038e677c2acf0 --- /dev/null +++ b/src/transport/StorablePeerConnection.h @@ -0,0 +1,64 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +namespace chip { + +// KVS store is sensitive to length of key strings, based on the underlying +// platform. Keeping them short. +constexpr char kStorablePeerConnectionKeyPrefix[] = "CHIPCnxn"; +constexpr char kStorablePeerConnectionCountKey[] = "CHIPNxtCnxn"; + +class DLL_EXPORT StorablePeerConnection +{ +public: + StorablePeerConnection() {} + + StorablePeerConnection(PASESession & session, Transport::AdminId admin); + + virtual ~StorablePeerConnection() {} + + CHIP_ERROR StoreIntoKVS(PersistentStorageDelegate & kvs); + + CHIP_ERROR FetchFromKVS(PersistentStorageDelegate & kvs, uint16_t keyId); + + static CHIP_ERROR DeleteFromKVS(PersistentStorageDelegate & kvs, uint16_t keyId); + + void GetPASESession(PASESession * session) { session->FromSerializable(mSession.mOpCreds); } + + Transport::AdminId GetAdminId() { return mSession.mAdmin; } + +private: + static constexpr size_t KeySize(); + + static CHIP_ERROR GenerateKey(uint16_t id, char * key, size_t len); + + struct StorableSession + { + PASESessionSerializable mOpCreds; + Transport::AdminId mAdmin; /* This field is serialized in LittleEndian byte order */ + }; + + StorableSession mSession; + uint16_t mKeyId; +}; + +} // namespace chip