Fix for x86_64 build fail
[platform/upstream/connectedhomeip.git] / src / platform / Linux / PosixConfig.cpp
1 /*
2  *
3  *    Copyright (c) 2020 Project CHIP Authors
4  *    Copyright (c) 2019-2020 Google LLC.
5  *    Copyright (c) 2018 Nest Labs, Inc.
6  *    All rights reserved.
7  *
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
11  *
12  *        http://www.apache.org/licenses/LICENSE-2.0
13  *
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.
19  */
20
21 /**
22  *    @file
23  *          Utilities for interacting with multiple file partitions and maps
24  *          key-value config calls to the correct partition.
25  */
26
27 #include <platform/internal/CHIPDeviceLayerInternal.h>
28 #include <platform/internal/testing/ConfigUnitTest.h>
29
30 #include <core/CHIPEncoding.h>
31 #include <platform/Linux/CHIPLinuxStorage.h>
32 #include <platform/Linux/PosixConfig.h>
33 #include <support/CodeUtils.h>
34
35 namespace chip {
36 namespace DeviceLayer {
37 namespace Internal {
38
39 static ChipLinuxStorage gChipLinuxFactoryStorage;
40 static ChipLinuxStorage gChipLinuxConfigStorage;
41 static ChipLinuxStorage gChipLinuxCountersStorage;
42
43 // *** CAUTION ***: Changing the names or namespaces of these values will *break* existing devices.
44
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";
49
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" };
60
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" };
75
76 // Prefix used for NVS keys that contain Chip group encryption keys.
77 const char PosixConfig::kGroupKeyNamePrefix[] = "gk-";
78
79 ChipLinuxStorage * PosixConfig::GetStorageForNamespace(Key key)
80 {
81     if (strcmp(key.Namespace, kConfigNamespace_ChipFactory) == 0)
82         return &gChipLinuxFactoryStorage;
83
84     if (strcmp(key.Namespace, kConfigNamespace_ChipConfig) == 0)
85         return &gChipLinuxConfigStorage;
86
87     if (strcmp(key.Namespace, kConfigNamespace_ChipCounters) == 0)
88         return &gChipLinuxCountersStorage;
89
90     return nullptr;
91 }
92
93 CHIP_ERROR PosixConfig::Init()
94 {
95     CHIP_ERROR err = CHIP_NO_ERROR;
96     return err;
97 }
98
99 CHIP_ERROR PosixConfig::ReadConfigValue(Key key, bool & val)
100 {
101     CHIP_ERROR err;
102     ChipLinuxStorage * storage;
103     uint32_t intVal;
104
105     storage = GetStorageForNamespace(key);
106     VerifyOrExit(storage != nullptr, err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND);
107
108     err = storage->ReadValue(key.Name, intVal);
109     if (err == CHIP_ERROR_KEY_NOT_FOUND)
110     {
111         err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND;
112     }
113     SuccessOrExit(err);
114
115     val = (intVal != 0);
116
117 exit:
118     return err;
119 }
120
121 CHIP_ERROR PosixConfig::ReadConfigValue(Key key, uint32_t & val)
122 {
123     CHIP_ERROR err;
124     ChipLinuxStorage * storage;
125
126     storage = GetStorageForNamespace(key);
127     VerifyOrExit(storage != nullptr, err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND);
128
129     err = storage->ReadValue(key.Name, val);
130     if (err == CHIP_ERROR_KEY_NOT_FOUND)
131     {
132         err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND;
133     }
134     SuccessOrExit(err);
135
136 exit:
137     return err;
138 }
139
140 CHIP_ERROR PosixConfig::ReadConfigValue(Key key, uint64_t & val)
141 {
142     CHIP_ERROR err;
143     ChipLinuxStorage * storage;
144
145     storage = GetStorageForNamespace(key);
146     VerifyOrExit(storage != nullptr, err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND);
147
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)
151     {
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)
157         {
158             VerifyOrExit(deviceIdOutLen == sizeof(deviceIdBytes), err = CHIP_ERROR_INCORRECT_STATE);
159             val = Encoding::BigEndian::Get64(deviceIdBytes);
160             ExitNow();
161         }
162     }
163
164     err = storage->ReadValue(key.Name, val);
165     if (err == CHIP_ERROR_KEY_NOT_FOUND)
166     {
167         err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND;
168     }
169     SuccessOrExit(err);
170
171 exit:
172     return err;
173 }
174
175 CHIP_ERROR PosixConfig::ReadConfigValueStr(Key key, char * buf, size_t bufSize, size_t & outLen)
176 {
177     CHIP_ERROR err;
178     ChipLinuxStorage * storage;
179
180     storage = GetStorageForNamespace(key);
181     VerifyOrExit(storage != nullptr, err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND);
182
183     err = storage->ReadValueStr(key.Name, buf, bufSize, outLen);
184     if (err == CHIP_ERROR_KEY_NOT_FOUND)
185     {
186         outLen = 0;
187         err    = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND;
188     }
189     else if (err == CHIP_ERROR_BUFFER_TOO_SMALL)
190     {
191         err = (buf == nullptr) ? CHIP_NO_ERROR : CHIP_ERROR_BUFFER_TOO_SMALL;
192     }
193     SuccessOrExit(err);
194
195 exit:
196     return err;
197 }
198
199 CHIP_ERROR PosixConfig::ReadConfigValueBin(Key key, uint8_t * buf, size_t bufSize, size_t & outLen)
200 {
201     CHIP_ERROR err;
202     ChipLinuxStorage * storage;
203
204     storage = GetStorageForNamespace(key);
205     VerifyOrExit(storage != nullptr, err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND);
206
207     err = storage->ReadValueBin(key.Name, buf, bufSize, outLen);
208     if (err == CHIP_ERROR_KEY_NOT_FOUND)
209     {
210         outLen = 0;
211         err    = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND;
212     }
213     else if (err == CHIP_ERROR_BUFFER_TOO_SMALL)
214     {
215         err = (buf == nullptr) ? CHIP_NO_ERROR : CHIP_ERROR_BUFFER_TOO_SMALL;
216     }
217     SuccessOrExit(err);
218
219 exit:
220     return err;
221 }
222
223 CHIP_ERROR PosixConfig::WriteConfigValue(Key key, bool val)
224 {
225     CHIP_ERROR err;
226     ChipLinuxStorage * storage;
227
228     storage = GetStorageForNamespace(key);
229     VerifyOrExit(storage != nullptr, err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND);
230
231     err = storage->WriteValue(key.Name, val);
232     SuccessOrExit(err);
233
234     // Commit the value to the persistent store.
235     err = storage->Commit();
236     SuccessOrExit(err);
237
238     ChipLogProgress(DeviceLayer, "NVS set: %s/%s = %s", key.Namespace, key.Name, val ? "true" : "false");
239
240 exit:
241     return err;
242 }
243
244 CHIP_ERROR PosixConfig::WriteConfigValue(Key key, uint32_t val)
245 {
246     CHIP_ERROR err;
247     ChipLinuxStorage * storage;
248
249     storage = GetStorageForNamespace(key);
250     VerifyOrExit(storage != nullptr, err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND);
251
252     err = storage->WriteValue(key.Name, val);
253     SuccessOrExit(err);
254
255     // Commit the value to the persistent store.
256     err = storage->Commit();
257     SuccessOrExit(err);
258
259     ChipLogProgress(DeviceLayer, "NVS set: %s/%s = %" PRIu32 " (0x%" PRIX32 ")", key.Namespace, key.Name, val, val);
260
261 exit:
262     return err;
263 }
264
265 CHIP_ERROR PosixConfig::WriteConfigValue(Key key, uint64_t val)
266 {
267     CHIP_ERROR err;
268     ChipLinuxStorage * storage;
269
270     storage = GetStorageForNamespace(key);
271     VerifyOrExit(storage != nullptr, err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND);
272
273     err = storage->WriteValue(key.Name, val);
274     SuccessOrExit(err);
275
276     // Commit the value to the persistent store.
277     err = storage->Commit();
278     SuccessOrExit(err);
279
280     ChipLogProgress(DeviceLayer, "NVS set: %s/%s = %" PRIu64 " (0x%" PRIX64 ")", key.Namespace, key.Name, val, val);
281
282 exit:
283     return err;
284 }
285
286 CHIP_ERROR PosixConfig::WriteConfigValueStr(Key key, const char * str)
287 {
288     CHIP_ERROR err;
289     ChipLinuxStorage * storage;
290
291     if (str != nullptr)
292     {
293         storage = GetStorageForNamespace(key);
294         VerifyOrExit(storage != nullptr, err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND);
295
296         err = storage->WriteValueStr(key.Name, str);
297         SuccessOrExit(err);
298
299         // Commit the value to the persistent store.
300         err = storage->Commit();
301         SuccessOrExit(err);
302
303         ChipLogProgress(DeviceLayer, "NVS set: %s/%s = \"%s\"", key.Namespace, key.Name, str);
304     }
305
306     else
307     {
308         err = ClearConfigValue(key);
309         SuccessOrExit(err);
310     }
311
312 exit:
313     return err;
314 }
315
316 CHIP_ERROR PosixConfig::WriteConfigValueStr(Key key, const char * str, size_t strLen)
317 {
318 #if CHIP_CONFIG_MEMORY_MGMT_MALLOC
319     CHIP_ERROR err;
320     char * strCopy = nullptr;
321
322     if (str != nullptr)
323     {
324         strCopy = strndup(str, strLen);
325         VerifyOrExit(strCopy != nullptr, err = CHIP_ERROR_NO_MEMORY);
326     }
327
328     err = PosixConfig::WriteConfigValueStr(key, strCopy);
329
330 exit:
331     if (strCopy != nullptr)
332     {
333         free(strCopy);
334     }
335     return err;
336 #else
337 #error "Unsupported CHIP_CONFIG_MEMORY_MGMT configuration"
338 #endif
339 }
340
341 CHIP_ERROR PosixConfig::WriteConfigValueBin(Key key, const uint8_t * data, size_t dataLen)
342 {
343     CHIP_ERROR err;
344     ChipLinuxStorage * storage;
345
346     if (data != nullptr)
347     {
348         storage = GetStorageForNamespace(key);
349         VerifyOrExit(storage != nullptr, err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND);
350
351         err = storage->WriteValueBin(key.Name, data, dataLen);
352         SuccessOrExit(err);
353
354         // Commit the value to the persistent store.
355         err = storage->Commit();
356         SuccessOrExit(err);
357
358         ChipLogProgress(DeviceLayer, "NVS set: %s/%s = (blob length %" PRId32 ")", key.Namespace, key.Name, dataLen);
359     }
360     else
361     {
362         err = ClearConfigValue(key);
363         SuccessOrExit(err);
364     }
365
366 exit:
367     return err;
368 }
369
370 CHIP_ERROR PosixConfig::ClearConfigValue(Key key)
371 {
372     CHIP_ERROR err;
373     ChipLinuxStorage * storage;
374
375     storage = GetStorageForNamespace(key);
376     VerifyOrExit(storage != nullptr, err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND);
377
378     err = storage->ClearValue(key.Name);
379     if (err == CHIP_ERROR_KEY_NOT_FOUND)
380     {
381         ExitNow(err = CHIP_NO_ERROR);
382     }
383     SuccessOrExit(err);
384
385     // Commit the value to the persistent store.
386     err = storage->Commit();
387     SuccessOrExit(err);
388
389     ChipLogProgress(DeviceLayer, "NVS erase: %s/%s", key.Namespace, key.Name);
390
391 exit:
392     return err;
393 }
394
395 bool PosixConfig::ConfigValueExists(Key key)
396 {
397     ChipLinuxStorage * storage;
398
399     storage = GetStorageForNamespace(key);
400     if (storage == nullptr)
401         return false;
402
403     return storage->HasValue(key.Name);
404 }
405
406 CHIP_ERROR PosixConfig::EnsureNamespace(const char * ns)
407 {
408     CHIP_ERROR err             = CHIP_NO_ERROR;
409     ChipLinuxStorage * storage = nullptr;
410
411     if (strcmp(ns, kConfigNamespace_ChipFactory) == 0)
412     {
413         storage = &gChipLinuxFactoryStorage;
414         err     = storage->Init(CHIP_DEFAULT_FACTORY_PATH);
415     }
416     else if (strcmp(ns, kConfigNamespace_ChipConfig) == 0)
417     {
418         storage = &gChipLinuxConfigStorage;
419         err     = storage->Init(CHIP_DEFAULT_CONFIG_PATH);
420     }
421     else if (strcmp(ns, kConfigNamespace_ChipCounters) == 0)
422     {
423         storage = &gChipLinuxCountersStorage;
424         err     = storage->Init(CHIP_DEFAULT_DATA_PATH);
425     }
426
427     SuccessOrExit(err);
428
429 exit:
430     return err;
431 }
432
433 CHIP_ERROR PosixConfig::ClearNamespace(const char * ns)
434 {
435     CHIP_ERROR err             = CHIP_NO_ERROR;
436     ChipLinuxStorage * storage = nullptr;
437
438     if (strcmp(ns, kConfigNamespace_ChipConfig) == 0)
439     {
440         storage = &gChipLinuxConfigStorage;
441     }
442     else if (strcmp(ns, kConfigNamespace_ChipCounters) == 0)
443     {
444         storage = &gChipLinuxCountersStorage;
445     }
446
447     VerifyOrExit(storage != nullptr, err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND);
448
449     err = storage->ClearAll();
450     if (err != CHIP_NO_ERROR)
451     {
452         ChipLogError(DeviceLayer, "Storage ClearAll failed: %s", ErrorStr(err));
453     }
454     SuccessOrExit(err);
455
456     err = storage->Commit();
457     if (err != CHIP_NO_ERROR)
458     {
459         ChipLogError(DeviceLayer, "Storage Commit failed: %s", ErrorStr(err));
460     }
461
462 exit:
463     return err;
464 }
465
466 CHIP_ERROR PosixConfig::FactoryResetConfig()
467 {
468     CHIP_ERROR err = CHIP_NO_ERROR;
469     ChipLinuxStorage * storage;
470
471     ChipLogProgress(DeviceLayer, "Performing factory reset");
472
473     storage = &gChipLinuxConfigStorage;
474     if (storage == nullptr)
475     {
476         ChipLogError(DeviceLayer, "Storage get failed");
477         err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND;
478     }
479     SuccessOrExit(err);
480
481     err = storage->ClearAll();
482     if (err != CHIP_NO_ERROR)
483     {
484         ChipLogError(DeviceLayer, "Storage ClearAll failed: %s", ErrorStr(err));
485     }
486     SuccessOrExit(err);
487
488     err = storage->Commit();
489     if (err != CHIP_NO_ERROR)
490     {
491         ChipLogError(DeviceLayer, "Storage Commit failed: %s", ErrorStr(err));
492     }
493
494 exit:
495     return err;
496 }
497
498 void PosixConfig::RunConfigUnitTest()
499 {
500     // Run common unit test.
501     ::chip::DeviceLayer::Internal::RunConfigUnitTest<PosixConfig>();
502 }
503
504 } // namespace Internal
505 } // namespace DeviceLayer
506 } // namespace chip