/* * * Copyright (c) 2020-2022 Project CHIP Authors * Copyright (c) 2019-2020 Google LLC. * Copyright (c) 2018 Nest Labs, Inc. * 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 * Utilities for interacting with the the ESP32 "NVS" key-value store. */ /* this file behaves like a config.h, comes first */ #include #include #include #include #include #include #include #include "kvstore_global_api/kvstore_global_api.h" #include "platform/mbed_error.h" namespace chip { namespace DeviceLayer { namespace Internal { // *** CAUTION ***: Changing the names or namespaces of these values will *break* existing devices. #define STR_EXPAND(tok) #tok // Note: An external mbed parameter could be useful so an application can put // chip NVS values in a single place #define CHIP_CONFIG_KV_STORE_PARTITION STR_EXPAND(MBED_CONF_STORAGE_DEFAULT_KV) // NVS namespaces used to store device configuration information. #define CHIP_CONFIG_FACTORY_PREFIX "chip-factory-" #define CHIP_CONFIG_CONFIG_PREFIX "chip-config-" #define CHIP_CONFIG_COUNTER_PREFIX "chip-counters-" #define FACTORY_KEY(key) CHIP_CONFIG_KV_STORE_PARTITION CHIP_CONFIG_FACTORY_PREFIX key #define CONFIG_KEY(key) CHIP_CONFIG_KV_STORE_PARTITION CHIP_CONFIG_CONFIG_PREFIX key #define COUNTER_KEY(key) CHIP_CONFIG_KV_STORE_PARTITION CHIP_CONFIG_COUNTER_PREFIX key const char MbedConfig::kConfigNamespace_ChipFactory[] = CHIP_CONFIG_KV_STORE_PARTITION CHIP_CONFIG_FACTORY_PREFIX; const char MbedConfig::kConfigNamespace_ChipConfig[] = CHIP_CONFIG_KV_STORE_PARTITION CHIP_CONFIG_CONFIG_PREFIX; const char MbedConfig::kConfigNamespace_ChipCounters[] = CHIP_CONFIG_KV_STORE_PARTITION CHIP_CONFIG_COUNTER_PREFIX; // Keys stored in the chip-factory namespace const MbedConfig::Key MbedConfig::kConfigKey_SerialNum = { FACTORY_KEY("serial-num") }; const MbedConfig::Key MbedConfig::kConfigKey_MfrDeviceId = { FACTORY_KEY("device-id") }; const MbedConfig::Key MbedConfig::kConfigKey_MfrDeviceCert = { FACTORY_KEY("device-cert") }; const MbedConfig::Key MbedConfig::kConfigKey_MfrDeviceICACerts = { FACTORY_KEY("device-ca-certs") }; const MbedConfig::Key MbedConfig::kConfigKey_MfrDevicePrivateKey = { FACTORY_KEY("device-key") }; const MbedConfig::Key MbedConfig::kConfigKey_HardwareVersion = { FACTORY_KEY("hardware-ver") }; const MbedConfig::Key MbedConfig::kConfigKey_ManufacturingDate = { FACTORY_KEY("mfg-date") }; const MbedConfig::Key MbedConfig::kConfigKey_SetupPinCode = { FACTORY_KEY("pin-code") }; const MbedConfig::Key MbedConfig::kConfigKey_SetupDiscriminator = { FACTORY_KEY("discriminator") }; const MbedConfig::Key MbedConfig::kConfigKey_Spake2pIterationCount = { FACTORY_KEY("iteration-count") }; const MbedConfig::Key MbedConfig::kConfigKey_Spake2pSalt = { FACTORY_KEY("salt") }; const MbedConfig::Key MbedConfig::kConfigKey_Spake2pVerifier = { FACTORY_KEY("verifier") }; // Keys stored in the chip-config namespace const MbedConfig::Key MbedConfig::kConfigKey_ServiceConfig = { CONFIG_KEY("service-config") }; const MbedConfig::Key MbedConfig::kConfigKey_PairedAccountId = { CONFIG_KEY("account-id") }; const MbedConfig::Key MbedConfig::kConfigKey_ServiceId = { CONFIG_KEY("service-id") }; const MbedConfig::Key MbedConfig::kConfigKey_LastUsedEpochKeyId = { CONFIG_KEY("last-ek-id") }; const MbedConfig::Key MbedConfig::kConfigKey_FailSafeArmed = { CONFIG_KEY("fail-safe-armed") }; const MbedConfig::Key MbedConfig::kConfigKey_RegulatoryLocation = { CONFIG_KEY("regulatory-location") }; const MbedConfig::Key MbedConfig::kConfigKey_CountryCode = { CONFIG_KEY("country-code") }; const MbedConfig::Key MbedConfig::kConfigKey_UniqueId = { CONFIG_KEY("unique-id") }; // Keys stored in the Chip-counters namespace const MbedConfig::Key MbedConfig::kCounterKey_RebootCount = { COUNTER_KEY("reboot-count") }; const MbedConfig::Key MbedConfig::kCounterKey_UpTime = { COUNTER_KEY("up-time") }; const MbedConfig::Key MbedConfig::kCounterKey_TotalOperationalHours = { COUNTER_KEY("total-hours") }; CHIP_ERROR MbedConfig::ReadConfigValue(Key key, bool & val) { if (!ConfigValueExists(key)) { return CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND; } size_t actual_size = 0; int err = kv_get(key, reinterpret_cast(&val), sizeof(val), &actual_size); if (err != MBED_SUCCESS) { return CHIP_ERROR_INTERNAL; } if (actual_size != sizeof(val)) { return CHIP_ERROR_BAD_REQUEST; } return CHIP_NO_ERROR; } CHIP_ERROR MbedConfig::ReadConfigValue(Key key, uint32_t & val) { if (!ConfigValueExists(key)) { return CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND; } size_t actual_size = 0; int err = kv_get(key, reinterpret_cast(&val), sizeof(val), &actual_size); if (err != MBED_SUCCESS) { return CHIP_ERROR_INTERNAL; } if (actual_size != sizeof(val)) { return CHIP_ERROR_BAD_REQUEST; } return CHIP_NO_ERROR; } CHIP_ERROR MbedConfig::ReadConfigValue(Key key, uint64_t & val) { if (!ConfigValueExists(key)) { return CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND; } size_t actual_size = 0; int err = kv_get(key, &val, sizeof(val), &actual_size); if (err != MBED_SUCCESS) { return CHIP_ERROR_INTERNAL; } if (actual_size != sizeof(val)) { return CHIP_ERROR_BAD_REQUEST; } return CHIP_NO_ERROR; } CHIP_ERROR MbedConfig::ReadConfigValueStr(Key key, char * buf, size_t bufSize, size_t & outLen) { CHIP_ERROR err = ReadConfigValueBin(key, reinterpret_cast(buf), bufSize, outLen); // Note: The system expect the trailing null to be added. if (err != CHIP_NO_ERROR) { return err; } if (outLen >= bufSize) { return CHIP_ERROR_INVALID_ARGUMENT; } buf[outLen] = 0; return CHIP_NO_ERROR; } CHIP_ERROR MbedConfig::ReadConfigValueBin(Key key, uint8_t * buf, size_t bufSize, size_t & outLen) { if (!ConfigValueExists(key)) { return CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND; } kv_info_t info; int err = kv_get_info(key, &info); if (err != MBED_SUCCESS) { return CHIP_ERROR_INTERNAL; } err = kv_get(key, reinterpret_cast(buf), bufSize, &outLen); if (err != MBED_SUCCESS) { return CHIP_ERROR_INTERNAL; } if (bufSize < info.size) { return CHIP_ERROR_BUFFER_TOO_SMALL; } return CHIP_NO_ERROR; } CHIP_ERROR MbedConfig::WriteConfigValue(Key key, bool val) { int err = kv_set(key, reinterpret_cast(&val), sizeof(val), 0); return err == MBED_SUCCESS ? CHIP_NO_ERROR : CHIP_ERROR_INTERNAL; } CHIP_ERROR MbedConfig::WriteConfigValue(Key key, uint32_t val) { int err = kv_set(key, reinterpret_cast(&val), sizeof(val), 0); return err == MBED_SUCCESS ? CHIP_NO_ERROR : CHIP_ERROR_INTERNAL; } CHIP_ERROR MbedConfig::WriteConfigValue(Key key, uint64_t val) { int err = kv_set(key, reinterpret_cast(&val), sizeof(val), 0); return err == MBED_SUCCESS ? CHIP_NO_ERROR : CHIP_ERROR_INTERNAL; } CHIP_ERROR MbedConfig::WriteConfigValueStr(Key key, const char * str) { return WriteConfigValueBin(key, reinterpret_cast(str), strlen(str)); } CHIP_ERROR MbedConfig::WriteConfigValueStr(Key key, const char * str, size_t strLen) { return WriteConfigValueBin(key, reinterpret_cast(str), strLen); } CHIP_ERROR MbedConfig::WriteConfigValueBin(Key key, const uint8_t * data, size_t dataLen) { // Two different behavior: If the pointer is not null, the value is updated // or create. If the pointer is null, the key is removed if it exist. if (data != nullptr) { int err = kv_set(key, reinterpret_cast(data), dataLen, 0); return err == MBED_SUCCESS ? CHIP_NO_ERROR : CHIP_ERROR_INTERNAL; } else if (ConfigValueExists(key)) { return ClearConfigValue(key); } else { // Nothing to do, data is null and the key does not exist. return CHIP_NO_ERROR; } } CHIP_ERROR MbedConfig::ClearConfigValue(Key key) { int err = kv_remove(key); return err == MBED_SUCCESS ? CHIP_NO_ERROR : CHIP_ERROR_INTERNAL; } bool MbedConfig::ConfigValueExists(Key key) { kv_info_t info; int err = kv_get_info(key, &info); return err == MBED_SUCCESS ? true : false; } CHIP_ERROR MbedConfig::FactoryResetConfig() { // kv_reset is not used, we want to preserve other setting and factory // configuration auto err = ClearNamespace(kConfigNamespace_ChipConfig); if (err != CHIP_NO_ERROR) { return err; } return ClearNamespace(kConfigNamespace_ChipCounters); } CHIP_ERROR MbedConfig::ConstructCounterKey(Key id, char * buf, size_t bufSize) { auto length = snprintf(buf, bufSize - 1, CHIP_CONFIG_KV_STORE_PARTITION CHIP_CONFIG_COUNTER_PREFIX "%s", id); if (length < 0) { return CHIP_ERROR_INTERNAL; } else if ((size_t) length > (bufSize - 1)) { return CHIP_ERROR_INVALID_ARGUMENT; } else { return CHIP_NO_ERROR; } } CHIP_ERROR MbedConfig::ReadCounter(Key counterId, uint32_t & value) { char key[50] = { 0 }; auto err = ConstructCounterKey(counterId, key, sizeof(key)); if (err != CHIP_NO_ERROR) { return err; } return ReadConfigValue(key, value); } CHIP_ERROR MbedConfig::WriteCounter(Key counterId, uint32_t value) { char key[50] = { 0 }; auto err = ConstructCounterKey(counterId, key, sizeof(key)); if (err != CHIP_NO_ERROR) { return err; } return WriteConfigValue(key, value); } CHIP_ERROR MbedConfig::ClearNamespace(const char * ns) { kv_iterator_t it; char key[50]; int err = kv_iterator_open(&it, ns); if (err) { return CHIP_ERROR_INTERNAL; } while (kv_iterator_next(it, key, sizeof(key)) != MBED_ERROR_ITEM_NOT_FOUND) { kv_remove(key); memset(key, 0, sizeof(key)); } err = kv_iterator_close(it); return err == MBED_SUCCESS ? CHIP_NO_ERROR : CHIP_ERROR_INTERNAL; } void MbedConfig::RunConfigUnitTest() { // Run common unit test. ::chip::DeviceLayer::Internal::RunConfigUnitTest(); } } // namespace Internal } // namespace DeviceLayer } // namespace chip