1 /*
2 * Copyright (c) 2016, The OpenThread Authors.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. Neither the name of the copyright holder nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 /**
30 * @file
31 * This file implements the OpenThread platform abstraction for non-volatile storage of settings.
32 */
33
34 #include "openthread-posix-config.h"
35 #include "platform-posix.h"
36
37 #include <assert.h>
38 #include <fcntl.h>
39 #include <inttypes.h>
40 #include <stddef.h>
41 #include <stdio.h>
42 #include <string.h>
43 #include <sys/stat.h>
44 #include <unistd.h>
45
46 #include <openthread/logging.h>
47 #include <openthread/platform/misc.h>
48 #include <openthread/platform/radio.h>
49 #include <openthread/platform/settings.h>
50 #if OPENTHREAD_POSIX_CONFIG_SECURE_SETTINGS_ENABLE
51 #include <openthread/platform/secure_settings.h>
52 #endif
53
54 #include "common/code_utils.hpp"
55 #include "common/encoding.hpp"
56 #include "posix/platform/settings.hpp"
57 #include "posix/platform/settings_file.hpp"
58
59 #include "system.hpp"
60
61 static ot::Posix::SettingsFile sSettingsFile;
62
63 #if OPENTHREAD_POSIX_CONFIG_SECURE_SETTINGS_ENABLE
64 static const uint16_t *sSensitiveKeys = nullptr;
65 static uint16_t sSensitiveKeysLength = 0;
66
isSensitiveKey(uint16_t aKey)67 static bool isSensitiveKey(uint16_t aKey)
68 {
69 bool ret = false;
70
71 VerifyOrExit(sSensitiveKeys != nullptr);
72
73 for (uint16_t i = 0; i < sSensitiveKeysLength; i++)
74 {
75 VerifyOrExit(aKey != sSensitiveKeys[i], ret = true);
76 }
77
78 exit:
79 return ret;
80 }
81 #endif
82
settingsFileInit(otInstance * aInstance)83 static otError settingsFileInit(otInstance *aInstance)
84 {
85 static constexpr size_t kMaxFileBaseNameSize = 32;
86 char fileBaseName[kMaxFileBaseNameSize];
87 const char *offset = getenv("PORT_OFFSET");
88 uint64_t nodeId;
89
90 otPlatRadioGetIeeeEui64(aInstance, reinterpret_cast<uint8_t *>(&nodeId));
91 nodeId = ot::BigEndian::HostSwap64(nodeId);
92
93 snprintf(fileBaseName, sizeof(fileBaseName), "%s_%" PRIx64, offset == nullptr ? "0" : offset, nodeId);
94 VerifyOrDie(strlen(fileBaseName) < kMaxFileBaseNameSize, OT_EXIT_FAILURE);
95
96 return sSettingsFile.Init(fileBaseName);
97 }
98
otPlatSettingsInit(otInstance * aInstance,const uint16_t * aSensitiveKeys,uint16_t aSensitiveKeysLength)99 void otPlatSettingsInit(otInstance *aInstance, const uint16_t *aSensitiveKeys, uint16_t aSensitiveKeysLength)
100 {
101 #if !OPENTHREAD_POSIX_CONFIG_SECURE_SETTINGS_ENABLE
102 OT_UNUSED_VARIABLE(aSensitiveKeys);
103 OT_UNUSED_VARIABLE(aSensitiveKeysLength);
104 #endif
105
106 #if OPENTHREAD_POSIX_CONFIG_SECURE_SETTINGS_ENABLE
107 sSensitiveKeys = aSensitiveKeys;
108 sSensitiveKeysLength = aSensitiveKeysLength;
109 #endif
110
111 // Don't touch the settings file the system runs in dry-run mode.
112 VerifyOrExit(!IsSystemDryRun());
113 SuccessOrExit(settingsFileInit(aInstance));
114
115 #if OPENTHREAD_POSIX_CONFIG_SECURE_SETTINGS_ENABLE
116 otPosixSecureSettingsInit(aInstance);
117 #endif
118
119 exit:
120 return;
121 }
122
otPlatSettingsDeinit(otInstance * aInstance)123 void otPlatSettingsDeinit(otInstance *aInstance)
124 {
125 OT_UNUSED_VARIABLE(aInstance);
126
127 VerifyOrExit(!IsSystemDryRun());
128
129 #if OPENTHREAD_POSIX_CONFIG_SECURE_SETTINGS_ENABLE
130 otPosixSecureSettingsDeinit(aInstance);
131 #endif
132
133 sSettingsFile.Deinit();
134
135 exit:
136 return;
137 }
138
otPlatSettingsGet(otInstance * aInstance,uint16_t aKey,int aIndex,uint8_t * aValue,uint16_t * aValueLength)139 otError otPlatSettingsGet(otInstance *aInstance, uint16_t aKey, int aIndex, uint8_t *aValue, uint16_t *aValueLength)
140 {
141 OT_UNUSED_VARIABLE(aInstance);
142
143 otError error = OT_ERROR_NOT_FOUND;
144
145 VerifyOrExit(!IsSystemDryRun());
146 #if OPENTHREAD_POSIX_CONFIG_SECURE_SETTINGS_ENABLE
147 if (isSensitiveKey(aKey))
148 {
149 error = otPosixSecureSettingsGet(aInstance, aKey, aIndex, aValue, aValueLength);
150 }
151 else
152 #endif
153 {
154 error = sSettingsFile.Get(aKey, aIndex, aValue, aValueLength);
155 }
156
157 exit:
158 VerifyOrDie(error != OT_ERROR_PARSE, OT_EXIT_FAILURE);
159 return error;
160 }
161
otPlatSettingsSet(otInstance * aInstance,uint16_t aKey,const uint8_t * aValue,uint16_t aValueLength)162 otError otPlatSettingsSet(otInstance *aInstance, uint16_t aKey, const uint8_t *aValue, uint16_t aValueLength)
163 {
164 OT_UNUSED_VARIABLE(aInstance);
165
166 otError error = OT_ERROR_NONE;
167
168 #if OPENTHREAD_POSIX_CONFIG_SECURE_SETTINGS_ENABLE
169 if (isSensitiveKey(aKey))
170 {
171 error = otPosixSecureSettingsSet(aInstance, aKey, aValue, aValueLength);
172 }
173 else
174 #endif
175 {
176 sSettingsFile.Set(aKey, aValue, aValueLength);
177 }
178
179 return error;
180 }
181
otPlatSettingsAdd(otInstance * aInstance,uint16_t aKey,const uint8_t * aValue,uint16_t aValueLength)182 otError otPlatSettingsAdd(otInstance *aInstance, uint16_t aKey, const uint8_t *aValue, uint16_t aValueLength)
183 {
184 OT_UNUSED_VARIABLE(aInstance);
185
186 otError error = OT_ERROR_NONE;
187
188 #if OPENTHREAD_POSIX_CONFIG_SECURE_SETTINGS_ENABLE
189 if (isSensitiveKey(aKey))
190 {
191 error = otPosixSecureSettingsAdd(aInstance, aKey, aValue, aValueLength);
192 }
193 else
194 #endif
195 {
196 sSettingsFile.Add(aKey, aValue, aValueLength);
197 }
198
199 return error;
200 }
201
otPlatSettingsDelete(otInstance * aInstance,uint16_t aKey,int aIndex)202 otError otPlatSettingsDelete(otInstance *aInstance, uint16_t aKey, int aIndex)
203 {
204 OT_UNUSED_VARIABLE(aInstance);
205
206 otError error;
207
208 #if OPENTHREAD_POSIX_CONFIG_SECURE_SETTINGS_ENABLE
209 if (isSensitiveKey(aKey))
210 {
211 error = otPosixSecureSettingsDelete(aInstance, aKey, aIndex);
212 }
213 else
214 #endif
215 {
216 error = sSettingsFile.Delete(aKey, aIndex);
217 }
218
219 return error;
220 }
221
otPlatSettingsWipe(otInstance * aInstance)222 void otPlatSettingsWipe(otInstance *aInstance)
223 {
224 OT_UNUSED_VARIABLE(aInstance);
225 #if OPENTHREAD_POSIX_CONFIG_SECURE_SETTINGS_ENABLE
226 otPosixSecureSettingsWipe(aInstance);
227 #endif
228
229 sSettingsFile.Wipe();
230 }
231
232 namespace ot {
233 namespace Posix {
234 #if OPENTHREAD_POSIX_CONFIG_SECURE_SETTINGS_ENABLE
PlatformSettingsGetSensitiveKeys(otInstance * aInstance,const uint16_t ** aKeys,uint16_t * aKeysLength)235 void PlatformSettingsGetSensitiveKeys(otInstance *aInstance, const uint16_t **aKeys, uint16_t *aKeysLength)
236 {
237 OT_UNUSED_VARIABLE(aInstance);
238
239 assert(aKeys != nullptr);
240 assert(aKeysLength != nullptr);
241
242 *aKeys = sSensitiveKeys;
243 *aKeysLength = sSensitiveKeysLength;
244 }
245 #endif
246
247 } // namespace Posix
248 } // namespace ot
249
250 #ifndef SELF_TEST
251 #define SELF_TEST 0
252 #endif
253
254 #if SELF_TEST
255
otLogCritPlat(const char * aFormat,...)256 void otLogCritPlat(const char *aFormat, ...) { OT_UNUSED_VARIABLE(aFormat); }
257
otExitCodeToString(uint8_t aExitCode)258 const char *otExitCodeToString(uint8_t aExitCode)
259 {
260 OT_UNUSED_VARIABLE(aExitCode);
261 return "";
262 }
263
otPlatRadioGetIeeeEui64(otInstance * aInstance,uint8_t * aIeeeEui64)264 void otPlatRadioGetIeeeEui64(otInstance *aInstance, uint8_t *aIeeeEui64)
265 {
266 OT_UNUSED_VARIABLE(aInstance);
267
268 memset(aIeeeEui64, 0, sizeof(uint64_t));
269 }
270
271 // Stub implementation for testing
IsSystemDryRun(void)272 bool IsSystemDryRun(void) { return false; }
273
main()274 int main()
275 {
276 otInstance *instance = nullptr;
277 uint8_t data[60];
278
279 for (uint8_t i = 0; i < sizeof(data); ++i)
280 {
281 data[i] = i;
282 }
283
284 otPlatSettingsInit(instance, nullptr, 0);
285
286 // verify empty situation
287 otPlatSettingsWipe(instance);
288 {
289 uint8_t value[sizeof(data)];
290 uint16_t length = sizeof(value);
291
292 assert(otPlatSettingsGet(instance, 0, 0, value, &length) == OT_ERROR_NOT_FOUND);
293 assert(otPlatSettingsDelete(instance, 0, 0) == OT_ERROR_NOT_FOUND);
294 assert(otPlatSettingsDelete(instance, 0, -1) == OT_ERROR_NOT_FOUND);
295 }
296
297 // verify write one record
298 assert(otPlatSettingsSet(instance, 0, data, sizeof(data) / 2) == OT_ERROR_NONE);
299 {
300 uint8_t value[sizeof(data)];
301 uint16_t length = sizeof(value);
302
303 assert(otPlatSettingsGet(instance, 0, 0, nullptr, nullptr) == OT_ERROR_NONE);
304 assert(otPlatSettingsGet(instance, 0, 0, nullptr, &length) == OT_ERROR_NONE);
305 assert(length == sizeof(data) / 2);
306
307 length = sizeof(value);
308 assert(otPlatSettingsGet(instance, 0, 0, value, &length) == OT_ERROR_NONE);
309 assert(length == sizeof(data) / 2);
310 assert(0 == memcmp(value, data, length));
311
312 // insufficient buffer
313 length -= 1;
314 value[length] = 0;
315 assert(otPlatSettingsGet(instance, 0, 0, value, &length) == OT_ERROR_NONE);
316 // verify length becomes the actual length of the record
317 assert(length == sizeof(data) / 2);
318 // verify this byte is not changed
319 assert(value[length] == 0);
320
321 // wrong index
322 assert(otPlatSettingsGet(instance, 0, 1, nullptr, nullptr) == OT_ERROR_NOT_FOUND);
323 // wrong key
324 assert(otPlatSettingsGet(instance, 1, 0, nullptr, nullptr) == OT_ERROR_NOT_FOUND);
325 }
326 otPlatSettingsWipe(instance);
327
328 // verify write two records
329 assert(otPlatSettingsSet(instance, 0, data, sizeof(data)) == OT_ERROR_NONE);
330 assert(otPlatSettingsAdd(instance, 0, data, sizeof(data) / 2) == OT_ERROR_NONE);
331 {
332 uint8_t value[sizeof(data)];
333 uint16_t length = sizeof(value);
334
335 assert(otPlatSettingsGet(instance, 0, 1, value, &length) == OT_ERROR_NONE);
336 assert(length == sizeof(data) / 2);
337 assert(0 == memcmp(value, data, length));
338
339 length = sizeof(value);
340 assert(otPlatSettingsGet(instance, 0, 0, value, &length) == OT_ERROR_NONE);
341 assert(length == sizeof(data));
342 assert(0 == memcmp(value, data, length));
343 }
344 otPlatSettingsWipe(instance);
345
346 // verify write two records of different keys
347 assert(otPlatSettingsSet(instance, 0, data, sizeof(data)) == OT_ERROR_NONE);
348 assert(otPlatSettingsAdd(instance, 1, data, sizeof(data) / 2) == OT_ERROR_NONE);
349 {
350 uint8_t value[sizeof(data)];
351 uint16_t length = sizeof(value);
352
353 assert(otPlatSettingsGet(instance, 1, 0, value, &length) == OT_ERROR_NONE);
354 assert(length == sizeof(data) / 2);
355 assert(0 == memcmp(value, data, length));
356
357 length = sizeof(value);
358 assert(otPlatSettingsGet(instance, 0, 0, value, &length) == OT_ERROR_NONE);
359 assert(length == sizeof(data));
360 assert(0 == memcmp(value, data, length));
361 }
362 otPlatSettingsWipe(instance);
363
364 // verify delete record
365 assert(otPlatSettingsAdd(instance, 0, data, sizeof(data)) == OT_ERROR_NONE);
366 assert(otPlatSettingsAdd(instance, 0, data, sizeof(data) / 2) == OT_ERROR_NONE);
367 assert(otPlatSettingsAdd(instance, 0, data, sizeof(data) / 3) == OT_ERROR_NONE);
368 {
369 uint8_t value[sizeof(data)];
370 uint16_t length = sizeof(value);
371
372 // wrong key
373 assert(otPlatSettingsDelete(instance, 1, 0) == OT_ERROR_NOT_FOUND);
374 assert(otPlatSettingsDelete(instance, 1, -1) == OT_ERROR_NOT_FOUND);
375
376 // wrong index
377 assert(otPlatSettingsDelete(instance, 0, 3) == OT_ERROR_NOT_FOUND);
378
379 // delete one record
380 assert(otPlatSettingsDelete(instance, 0, 1) == OT_ERROR_NONE);
381 assert(otPlatSettingsGet(instance, 0, 1, value, &length) == OT_ERROR_NONE);
382 assert(length == sizeof(data) / 3);
383 assert(0 == memcmp(value, data, length));
384
385 // delete all records
386 assert(otPlatSettingsDelete(instance, 0, -1) == OT_ERROR_NONE);
387 assert(otPlatSettingsGet(instance, 0, 0, nullptr, nullptr) == OT_ERROR_NOT_FOUND);
388 }
389 otPlatSettingsWipe(instance);
390
391 // verify delete all records of a type
392 assert(otPlatSettingsAdd(instance, 0, data, sizeof(data)) == OT_ERROR_NONE);
393 assert(otPlatSettingsAdd(instance, 1, data, sizeof(data) / 2) == OT_ERROR_NONE);
394 assert(otPlatSettingsAdd(instance, 0, data, sizeof(data) / 3) == OT_ERROR_NONE);
395 {
396 uint8_t value[sizeof(data)];
397 uint16_t length = sizeof(value);
398
399 assert(otPlatSettingsDelete(instance, 0, -1) == OT_ERROR_NONE);
400 assert(otPlatSettingsGet(instance, 0, 0, value, &length) == OT_ERROR_NOT_FOUND);
401 assert(otPlatSettingsGet(instance, 1, 0, value, &length) == OT_ERROR_NONE);
402 assert(length == sizeof(data) / 2);
403 assert(0 == memcmp(value, data, length));
404
405 assert(otPlatSettingsDelete(instance, 0, 0) == OT_ERROR_NOT_FOUND);
406 assert(otPlatSettingsGet(instance, 0, 0, nullptr, nullptr) == OT_ERROR_NOT_FOUND);
407 }
408 otPlatSettingsWipe(instance);
409 otPlatSettingsDeinit(instance);
410
411 return 0;
412 }
413 #endif
414