3 * Copyright (c) 2020 Project CHIP Authors
4 * Copyright (c) 2019-2020 Google LLC.
5 * Copyright (c) 2018 Nest Labs, Inc.
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
23 * Utilities for interacting with multiple file partitions and maps
24 * key-value config calls to the correct partition.
27 #include <platform/internal/CHIPDeviceLayerInternal.h>
28 #include <platform/internal/testing/ConfigUnitTest.h>
30 #include <core/CHIPEncoding.h>
31 #include <platform/Linux/CHIPLinuxStorage.h>
32 #include <platform/Linux/PosixConfig.h>
33 #include <support/CodeUtils.h>
36 namespace DeviceLayer {
39 static ChipLinuxStorage gChipLinuxFactoryStorage;
40 static ChipLinuxStorage gChipLinuxConfigStorage;
41 static ChipLinuxStorage gChipLinuxCountersStorage;
43 // *** CAUTION ***: Changing the names or namespaces of these values will *break* existing devices.
45 // NVS namespaces used to store device configuration information.
46 const char PosixConfig::kConfigNamespace_ChipFactory[] = "chip-factory";
47 const char PosixConfig::kConfigNamespace_ChipConfig[] = "chip-config";
48 const char PosixConfig::kConfigNamespace_ChipCounters[] = "chip-counters";
50 // Keys stored in the Chip-factory namespace
51 const PosixConfig::Key PosixConfig::kConfigKey_SerialNum = { kConfigNamespace_ChipFactory, "serial-num" };
52 const PosixConfig::Key PosixConfig::kConfigKey_MfrDeviceId = { kConfigNamespace_ChipFactory, "device-id" };
53 const PosixConfig::Key PosixConfig::kConfigKey_MfrDeviceCert = { kConfigNamespace_ChipFactory, "device-cert" };
54 const PosixConfig::Key PosixConfig::kConfigKey_MfrDeviceICACerts = { kConfigNamespace_ChipFactory, "device-ca-certs" };
55 const PosixConfig::Key PosixConfig::kConfigKey_MfrDevicePrivateKey = { kConfigNamespace_ChipFactory, "device-key" };
56 const PosixConfig::Key PosixConfig::kConfigKey_ProductRevision = { kConfigNamespace_ChipFactory, "product-rev" };
57 const PosixConfig::Key PosixConfig::kConfigKey_ManufacturingDate = { kConfigNamespace_ChipFactory, "mfg-date" };
58 const PosixConfig::Key PosixConfig::kConfigKey_SetupPinCode = { kConfigNamespace_ChipFactory, "pin-code" };
59 const PosixConfig::Key PosixConfig::kConfigKey_SetupDiscriminator = { kConfigNamespace_ChipFactory, "discriminator" };
61 // Keys stored in the Chip-config namespace
62 const PosixConfig::Key PosixConfig::kConfigKey_FabricId = { kConfigNamespace_ChipConfig, "fabric-id" };
63 const PosixConfig::Key PosixConfig::kConfigKey_ServiceConfig = { kConfigNamespace_ChipConfig, "service-config" };
64 const PosixConfig::Key PosixConfig::kConfigKey_PairedAccountId = { kConfigNamespace_ChipConfig, "account-id" };
65 const PosixConfig::Key PosixConfig::kConfigKey_ServiceId = { kConfigNamespace_ChipConfig, "service-id" };
66 const PosixConfig::Key PosixConfig::kConfigKey_FabricSecret = { kConfigNamespace_ChipConfig, "fabric-secret" };
67 const PosixConfig::Key PosixConfig::kConfigKey_GroupKeyIndex = { kConfigNamespace_ChipConfig, "group-key-index" };
68 const PosixConfig::Key PosixConfig::kConfigKey_LastUsedEpochKeyId = { kConfigNamespace_ChipConfig, "last-ek-id" };
69 const PosixConfig::Key PosixConfig::kConfigKey_FailSafeArmed = { kConfigNamespace_ChipConfig, "fail-safe-armed" };
70 const PosixConfig::Key PosixConfig::kConfigKey_WiFiStationSecType = { kConfigNamespace_ChipConfig, "sta-sec-type" };
71 const PosixConfig::Key PosixConfig::kConfigKey_OperationalDeviceId = { kConfigNamespace_ChipConfig, "op-device-id" };
72 const PosixConfig::Key PosixConfig::kConfigKey_OperationalDeviceCert = { kConfigNamespace_ChipConfig, "op-device-cert" };
73 const PosixConfig::Key PosixConfig::kConfigKey_OperationalDeviceICACerts = { kConfigNamespace_ChipConfig, "op-device-ca-certs" };
74 const PosixConfig::Key PosixConfig::kConfigKey_OperationalDevicePrivateKey = { kConfigNamespace_ChipConfig, "op-device-key" };
76 // Prefix used for NVS keys that contain Chip group encryption keys.
77 const char PosixConfig::kGroupKeyNamePrefix[] = "gk-";
79 ChipLinuxStorage * PosixConfig::GetStorageForNamespace(Key key)
81 if (strcmp(key.Namespace, kConfigNamespace_ChipFactory) == 0)
82 return &gChipLinuxFactoryStorage;
84 if (strcmp(key.Namespace, kConfigNamespace_ChipConfig) == 0)
85 return &gChipLinuxConfigStorage;
87 if (strcmp(key.Namespace, kConfigNamespace_ChipCounters) == 0)
88 return &gChipLinuxCountersStorage;
93 CHIP_ERROR PosixConfig::Init()
95 CHIP_ERROR err = CHIP_NO_ERROR;
99 CHIP_ERROR PosixConfig::ReadConfigValue(Key key, bool & val)
102 ChipLinuxStorage * storage;
105 storage = GetStorageForNamespace(key);
106 VerifyOrExit(storage != nullptr, err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND);
108 err = storage->ReadValue(key.Name, intVal);
109 if (err == CHIP_ERROR_KEY_NOT_FOUND)
111 err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND;
121 CHIP_ERROR PosixConfig::ReadConfigValue(Key key, uint32_t & val)
124 ChipLinuxStorage * storage;
126 storage = GetStorageForNamespace(key);
127 VerifyOrExit(storage != nullptr, err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND);
129 err = storage->ReadValue(key.Name, val);
130 if (err == CHIP_ERROR_KEY_NOT_FOUND)
132 err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND;
140 CHIP_ERROR PosixConfig::ReadConfigValue(Key key, uint64_t & val)
143 ChipLinuxStorage * storage;
145 storage = GetStorageForNamespace(key);
146 VerifyOrExit(storage != nullptr, err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND);
148 // Special case the MfrDeviceId value, optionally allowing it to be read as a blob containing
149 // a 64-bit big-endian integer, instead of a u64 value.
150 if (key == kConfigKey_MfrDeviceId)
152 uint8_t deviceIdBytes[sizeof(uint64_t)];
153 size_t deviceIdLen = sizeof(deviceIdBytes);
154 size_t deviceIdOutLen;
155 err = storage->ReadValueBin(key.Name, deviceIdBytes, deviceIdLen, deviceIdOutLen);
156 if (err == CHIP_NO_ERROR)
158 VerifyOrExit(deviceIdOutLen == sizeof(deviceIdBytes), err = CHIP_ERROR_INCORRECT_STATE);
159 val = Encoding::BigEndian::Get64(deviceIdBytes);
164 err = storage->ReadValue(key.Name, val);
165 if (err == CHIP_ERROR_KEY_NOT_FOUND)
167 err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND;
175 CHIP_ERROR PosixConfig::ReadConfigValueStr(Key key, char * buf, size_t bufSize, size_t & outLen)
178 ChipLinuxStorage * storage;
180 storage = GetStorageForNamespace(key);
181 VerifyOrExit(storage != nullptr, err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND);
183 err = storage->ReadValueStr(key.Name, buf, bufSize, outLen);
184 if (err == CHIP_ERROR_KEY_NOT_FOUND)
187 err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND;
189 else if (err == CHIP_ERROR_BUFFER_TOO_SMALL)
191 err = (buf == nullptr) ? CHIP_NO_ERROR : CHIP_ERROR_BUFFER_TOO_SMALL;
199 CHIP_ERROR PosixConfig::ReadConfigValueBin(Key key, uint8_t * buf, size_t bufSize, size_t & outLen)
202 ChipLinuxStorage * storage;
204 storage = GetStorageForNamespace(key);
205 VerifyOrExit(storage != nullptr, err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND);
207 err = storage->ReadValueBin(key.Name, buf, bufSize, outLen);
208 if (err == CHIP_ERROR_KEY_NOT_FOUND)
211 err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND;
213 else if (err == CHIP_ERROR_BUFFER_TOO_SMALL)
215 err = (buf == nullptr) ? CHIP_NO_ERROR : CHIP_ERROR_BUFFER_TOO_SMALL;
223 CHIP_ERROR PosixConfig::WriteConfigValue(Key key, bool val)
226 ChipLinuxStorage * storage;
228 storage = GetStorageForNamespace(key);
229 VerifyOrExit(storage != nullptr, err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND);
231 err = storage->WriteValue(key.Name, val);
234 // Commit the value to the persistent store.
235 err = storage->Commit();
238 ChipLogProgress(DeviceLayer, "NVS set: %s/%s = %s", key.Namespace, key.Name, val ? "true" : "false");
244 CHIP_ERROR PosixConfig::WriteConfigValue(Key key, uint32_t val)
247 ChipLinuxStorage * storage;
249 storage = GetStorageForNamespace(key);
250 VerifyOrExit(storage != nullptr, err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND);
252 err = storage->WriteValue(key.Name, val);
255 // Commit the value to the persistent store.
256 err = storage->Commit();
259 ChipLogProgress(DeviceLayer, "NVS set: %s/%s = %" PRIu32 " (0x%" PRIX32 ")", key.Namespace, key.Name, val, val);
265 CHIP_ERROR PosixConfig::WriteConfigValue(Key key, uint64_t val)
268 ChipLinuxStorage * storage;
270 storage = GetStorageForNamespace(key);
271 VerifyOrExit(storage != nullptr, err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND);
273 err = storage->WriteValue(key.Name, val);
276 // Commit the value to the persistent store.
277 err = storage->Commit();
280 ChipLogProgress(DeviceLayer, "NVS set: %s/%s = %" PRIu64 " (0x%" PRIX64 ")", key.Namespace, key.Name, val, val);
286 CHIP_ERROR PosixConfig::WriteConfigValueStr(Key key, const char * str)
289 ChipLinuxStorage * storage;
293 storage = GetStorageForNamespace(key);
294 VerifyOrExit(storage != nullptr, err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND);
296 err = storage->WriteValueStr(key.Name, str);
299 // Commit the value to the persistent store.
300 err = storage->Commit();
303 ChipLogProgress(DeviceLayer, "NVS set: %s/%s = \"%s\"", key.Namespace, key.Name, str);
308 err = ClearConfigValue(key);
316 CHIP_ERROR PosixConfig::WriteConfigValueStr(Key key, const char * str, size_t strLen)
318 #if CHIP_CONFIG_MEMORY_MGMT_MALLOC
320 char * strCopy = nullptr;
324 strCopy = strndup(str, strLen);
325 VerifyOrExit(strCopy != nullptr, err = CHIP_ERROR_NO_MEMORY);
328 err = PosixConfig::WriteConfigValueStr(key, strCopy);
331 if (strCopy != nullptr)
337 #error "Unsupported CHIP_CONFIG_MEMORY_MGMT configuration"
341 CHIP_ERROR PosixConfig::WriteConfigValueBin(Key key, const uint8_t * data, size_t dataLen)
344 ChipLinuxStorage * storage;
348 storage = GetStorageForNamespace(key);
349 VerifyOrExit(storage != nullptr, err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND);
351 err = storage->WriteValueBin(key.Name, data, dataLen);
354 // Commit the value to the persistent store.
355 err = storage->Commit();
358 ChipLogProgress(DeviceLayer, "NVS set: %s/%s = (blob length %" PRId32 ")", key.Namespace, key.Name, dataLen);
362 err = ClearConfigValue(key);
370 CHIP_ERROR PosixConfig::ClearConfigValue(Key key)
373 ChipLinuxStorage * storage;
375 storage = GetStorageForNamespace(key);
376 VerifyOrExit(storage != nullptr, err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND);
378 err = storage->ClearValue(key.Name);
379 if (err == CHIP_ERROR_KEY_NOT_FOUND)
381 ExitNow(err = CHIP_NO_ERROR);
385 // Commit the value to the persistent store.
386 err = storage->Commit();
389 ChipLogProgress(DeviceLayer, "NVS erase: %s/%s", key.Namespace, key.Name);
395 bool PosixConfig::ConfigValueExists(Key key)
397 ChipLinuxStorage * storage;
399 storage = GetStorageForNamespace(key);
400 if (storage == nullptr)
403 return storage->HasValue(key.Name);
406 CHIP_ERROR PosixConfig::EnsureNamespace(const char * ns)
408 CHIP_ERROR err = CHIP_NO_ERROR;
409 ChipLinuxStorage * storage = nullptr;
411 if (strcmp(ns, kConfigNamespace_ChipFactory) == 0)
413 storage = &gChipLinuxFactoryStorage;
414 err = storage->Init(CHIP_DEFAULT_FACTORY_PATH);
416 else if (strcmp(ns, kConfigNamespace_ChipConfig) == 0)
418 storage = &gChipLinuxConfigStorage;
419 err = storage->Init(CHIP_DEFAULT_CONFIG_PATH);
421 else if (strcmp(ns, kConfigNamespace_ChipCounters) == 0)
423 storage = &gChipLinuxCountersStorage;
424 err = storage->Init(CHIP_DEFAULT_DATA_PATH);
433 CHIP_ERROR PosixConfig::ClearNamespace(const char * ns)
435 CHIP_ERROR err = CHIP_NO_ERROR;
436 ChipLinuxStorage * storage = nullptr;
438 if (strcmp(ns, kConfigNamespace_ChipConfig) == 0)
440 storage = &gChipLinuxConfigStorage;
442 else if (strcmp(ns, kConfigNamespace_ChipCounters) == 0)
444 storage = &gChipLinuxCountersStorage;
447 VerifyOrExit(storage != nullptr, err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND);
449 err = storage->ClearAll();
450 if (err != CHIP_NO_ERROR)
452 ChipLogError(DeviceLayer, "Storage ClearAll failed: %s", ErrorStr(err));
456 err = storage->Commit();
457 if (err != CHIP_NO_ERROR)
459 ChipLogError(DeviceLayer, "Storage Commit failed: %s", ErrorStr(err));
466 CHIP_ERROR PosixConfig::FactoryResetConfig()
468 CHIP_ERROR err = CHIP_NO_ERROR;
469 ChipLinuxStorage * storage;
471 ChipLogProgress(DeviceLayer, "Performing factory reset");
473 storage = &gChipLinuxConfigStorage;
474 if (storage == nullptr)
476 ChipLogError(DeviceLayer, "Storage get failed");
477 err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND;
481 err = storage->ClearAll();
482 if (err != CHIP_NO_ERROR)
484 ChipLogError(DeviceLayer, "Storage ClearAll failed: %s", ErrorStr(err));
488 err = storage->Commit();
489 if (err != CHIP_NO_ERROR)
491 ChipLogError(DeviceLayer, "Storage Commit failed: %s", ErrorStr(err));
498 void PosixConfig::RunConfigUnitTest()
500 // Run common unit test.
501 ::chip::DeviceLayer::Internal::RunConfigUnitTest<PosixConfig>();
504 } // namespace Internal
505 } // namespace DeviceLayer