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
35 #include "openthread-posix-config.h"
36 #include "platform-posix.h"
37
38 #include <assert.h>
39 #include <fcntl.h>
40 #include <inttypes.h>
41 #include <stddef.h>
42 #include <stdio.h>
43 #include <string.h>
44 #include <sys/stat.h>
45 #include <unistd.h>
46
47 #include <openthread/logging.h>
48 #include <openthread/platform/misc.h>
49 #include <openthread/platform/radio.h>
50 #include <openthread/platform/settings.h>
51 #if OPENTHREAD_POSIX_CONFIG_SECURE_SETTINGS_ENABLE
52 #include <openthread/platform/secure_settings.h>
53 #endif
54
55 #include "common/code_utils.hpp"
56 #include "common/encoding.hpp"
57 #include "posix/platform/settings.hpp"
58
59 #include "system.hpp"
60
61 static const size_t kMaxFileNameSize = sizeof(OPENTHREAD_CONFIG_POSIX_SETTINGS_PATH) + 32;
62
63 static int sSettingsFd = -1;
64
65 #if OPENTHREAD_POSIX_CONFIG_SECURE_SETTINGS_ENABLE
66 static const uint16_t *sSensitiveKeys = nullptr;
67 static uint16_t sSensitiveKeysLength = 0;
68
isSensitiveKey(uint16_t aKey)69 static bool isSensitiveKey(uint16_t aKey)
70 {
71 bool ret = false;
72
73 VerifyOrExit(sSensitiveKeys != nullptr);
74
75 for (uint16_t i = 0; i < sSensitiveKeysLength; i++)
76 {
77 VerifyOrExit(aKey != sSensitiveKeys[i], ret = true);
78 }
79
80 exit:
81 return ret;
82 }
83 #endif
84
getSettingsFileName(otInstance * aInstance,char aFileName[kMaxFileNameSize],bool aSwap)85 static void getSettingsFileName(otInstance *aInstance, char aFileName[kMaxFileNameSize], bool aSwap)
86 {
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 snprintf(aFileName, kMaxFileNameSize, OPENTHREAD_CONFIG_POSIX_SETTINGS_PATH "/%s_%" PRIx64 ".%s",
93 offset == nullptr ? "0" : offset, nodeId, (aSwap ? "swap" : "data"));
94 }
95
swapOpen(otInstance * aInstance)96 static int swapOpen(otInstance *aInstance)
97 {
98 char fileName[kMaxFileNameSize];
99 int fd;
100
101 getSettingsFileName(aInstance, fileName, true);
102
103 fd = open(fileName, O_RDWR | O_CREAT | O_TRUNC | O_CLOEXEC, 0600);
104 VerifyOrDie(fd != -1, OT_EXIT_ERROR_ERRNO);
105
106 return fd;
107 }
108
109 /**
110 * Reads @p aLength bytes from the data file and appends to the swap file.
111 *
112 * @param[in] aFd The file descriptor of the current swap file.
113 * @param[in] aLength Number of bytes to copy.
114 *
115 */
swapWrite(otInstance * aInstance,int aFd,uint16_t aLength)116 static void swapWrite(otInstance *aInstance, int aFd, uint16_t aLength)
117 {
118 OT_UNUSED_VARIABLE(aInstance);
119
120 const size_t kBlockSize = 512;
121 uint8_t buffer[kBlockSize];
122
123 while (aLength > 0)
124 {
125 uint16_t count = aLength >= sizeof(buffer) ? sizeof(buffer) : aLength;
126 ssize_t rval = read(sSettingsFd, buffer, count);
127
128 VerifyOrDie(rval > 0, OT_EXIT_FAILURE);
129 count = static_cast<uint16_t>(rval);
130 rval = write(aFd, buffer, count);
131 assert(rval == count);
132 VerifyOrDie(rval == count, OT_EXIT_FAILURE);
133 aLength -= count;
134 }
135 }
136
swapPersist(otInstance * aInstance,int aFd)137 static void swapPersist(otInstance *aInstance, int aFd)
138 {
139 char swapFile[kMaxFileNameSize];
140 char dataFile[kMaxFileNameSize];
141
142 getSettingsFileName(aInstance, swapFile, true);
143 getSettingsFileName(aInstance, dataFile, false);
144
145 VerifyOrDie(0 == close(sSettingsFd), OT_EXIT_ERROR_ERRNO);
146 VerifyOrDie(0 == fsync(aFd), OT_EXIT_ERROR_ERRNO);
147 VerifyOrDie(0 == rename(swapFile, dataFile), OT_EXIT_ERROR_ERRNO);
148
149 sSettingsFd = aFd;
150 }
151
swapDiscard(otInstance * aInstance,int aFd)152 static void swapDiscard(otInstance *aInstance, int aFd)
153 {
154 char swapFileName[kMaxFileNameSize];
155
156 VerifyOrDie(0 == close(aFd), OT_EXIT_ERROR_ERRNO);
157 getSettingsFileName(aInstance, swapFileName, true);
158 VerifyOrDie(0 == unlink(swapFileName), OT_EXIT_ERROR_ERRNO);
159 }
160
otPlatSettingsInit(otInstance * aInstance,const uint16_t * aSensitiveKeys,uint16_t aSensitiveKeysLength)161 void otPlatSettingsInit(otInstance *aInstance, const uint16_t *aSensitiveKeys, uint16_t aSensitiveKeysLength)
162 {
163 #if !OPENTHREAD_POSIX_CONFIG_SECURE_SETTINGS_ENABLE
164 OT_UNUSED_VARIABLE(aSensitiveKeys);
165 OT_UNUSED_VARIABLE(aSensitiveKeysLength);
166 #endif
167
168 otError error = OT_ERROR_NONE;
169
170 #if OPENTHREAD_POSIX_CONFIG_SECURE_SETTINGS_ENABLE
171 sSensitiveKeys = aSensitiveKeys;
172 sSensitiveKeysLength = aSensitiveKeysLength;
173 #endif
174
175 // Don't touch the settings file the system runs in dry-run mode.
176 VerifyOrExit(!IsSystemDryRun());
177
178 {
179 struct stat st;
180
181 if (stat(OPENTHREAD_CONFIG_POSIX_SETTINGS_PATH, &st) == -1)
182 {
183 VerifyOrDie(mkdir(OPENTHREAD_CONFIG_POSIX_SETTINGS_PATH, 0755) == 0, OT_EXIT_ERROR_ERRNO);
184 }
185 }
186
187 {
188 char fileName[kMaxFileNameSize];
189
190 getSettingsFileName(aInstance, fileName, false);
191 sSettingsFd = open(fileName, O_RDWR | O_CREAT | O_CLOEXEC, 0600);
192 }
193
194 VerifyOrDie(sSettingsFd != -1, OT_EXIT_ERROR_ERRNO);
195
196 for (off_t size = lseek(sSettingsFd, 0, SEEK_END), offset = lseek(sSettingsFd, 0, SEEK_SET); offset < size;)
197 {
198 uint16_t key;
199 uint16_t length;
200 ssize_t rval;
201
202 rval = read(sSettingsFd, &key, sizeof(key));
203 VerifyOrExit(rval == sizeof(key), error = OT_ERROR_PARSE);
204
205 rval = read(sSettingsFd, &length, sizeof(length));
206 VerifyOrExit(rval == sizeof(length), error = OT_ERROR_PARSE);
207
208 offset += sizeof(key) + sizeof(length) + length;
209 VerifyOrExit(offset == lseek(sSettingsFd, length, SEEK_CUR), error = OT_ERROR_PARSE);
210 }
211
212 #if OPENTHREAD_POSIX_CONFIG_SECURE_SETTINGS_ENABLE
213 otPosixSecureSettingsInit(aInstance);
214 #endif
215
216 exit:
217 if (error == OT_ERROR_PARSE)
218 {
219 VerifyOrDie(ftruncate(sSettingsFd, 0) == 0, OT_EXIT_ERROR_ERRNO);
220 }
221 }
222
otPlatSettingsDeinit(otInstance * aInstance)223 void otPlatSettingsDeinit(otInstance *aInstance)
224 {
225 OT_UNUSED_VARIABLE(aInstance);
226
227 VerifyOrExit(!IsSystemDryRun());
228
229 #if OPENTHREAD_POSIX_CONFIG_SECURE_SETTINGS_ENABLE
230 otPosixSecureSettingsDeinit(aInstance);
231 #endif
232
233 VerifyOrExit(sSettingsFd != -1);
234 VerifyOrDie(close(sSettingsFd) == 0, OT_EXIT_ERROR_ERRNO);
235 sSettingsFd = -1;
236
237 exit:
238 return;
239 }
240
otPlatSettingsGet(otInstance * aInstance,uint16_t aKey,int aIndex,uint8_t * aValue,uint16_t * aValueLength)241 otError otPlatSettingsGet(otInstance *aInstance, uint16_t aKey, int aIndex, uint8_t *aValue, uint16_t *aValueLength)
242 {
243 OT_UNUSED_VARIABLE(aInstance);
244
245 otError error = OT_ERROR_NOT_FOUND;
246
247 VerifyOrExit(!IsSystemDryRun());
248 #if OPENTHREAD_POSIX_CONFIG_SECURE_SETTINGS_ENABLE
249 if (isSensitiveKey(aKey))
250 {
251 error = otPosixSecureSettingsGet(aInstance, aKey, aIndex, aValue, aValueLength);
252 }
253 else
254 #endif
255 {
256 error = ot::Posix::PlatformSettingsGet(aInstance, aKey, aIndex, aValue, aValueLength);
257 }
258
259 exit:
260 VerifyOrDie(error != OT_ERROR_PARSE, OT_EXIT_FAILURE);
261 return error;
262 }
263
otPlatSettingsSet(otInstance * aInstance,uint16_t aKey,const uint8_t * aValue,uint16_t aValueLength)264 otError otPlatSettingsSet(otInstance *aInstance, uint16_t aKey, const uint8_t *aValue, uint16_t aValueLength)
265 {
266 otError error = OT_ERROR_NONE;
267
268 #if OPENTHREAD_POSIX_CONFIG_SECURE_SETTINGS_ENABLE
269 if (isSensitiveKey(aKey))
270 {
271 error = otPosixSecureSettingsSet(aInstance, aKey, aValue, aValueLength);
272 }
273 else
274 #endif
275 {
276 ot::Posix::PlatformSettingsSet(aInstance, aKey, aValue, aValueLength);
277 }
278
279 return error;
280 }
281
otPlatSettingsAdd(otInstance * aInstance,uint16_t aKey,const uint8_t * aValue,uint16_t aValueLength)282 otError otPlatSettingsAdd(otInstance *aInstance, uint16_t aKey, const uint8_t *aValue, uint16_t aValueLength)
283 {
284 OT_UNUSED_VARIABLE(aInstance);
285
286 otError error = OT_ERROR_NONE;
287
288 #if OPENTHREAD_POSIX_CONFIG_SECURE_SETTINGS_ENABLE
289 if (isSensitiveKey(aKey))
290 {
291 error = otPosixSecureSettingsAdd(aInstance, aKey, aValue, aValueLength);
292 }
293 else
294 #endif
295 {
296 ot::Posix::PlatformSettingsAdd(aInstance, aKey, aValue, aValueLength);
297 }
298
299 return error;
300 }
301
otPlatSettingsDelete(otInstance * aInstance,uint16_t aKey,int aIndex)302 otError otPlatSettingsDelete(otInstance *aInstance, uint16_t aKey, int aIndex)
303 {
304 otError error;
305
306 #if OPENTHREAD_POSIX_CONFIG_SECURE_SETTINGS_ENABLE
307 if (isSensitiveKey(aKey))
308 {
309 error = otPosixSecureSettingsDelete(aInstance, aKey, aIndex);
310 }
311 else
312 #endif
313 {
314 error = ot::Posix::PlatformSettingsDelete(aInstance, aKey, aIndex, nullptr);
315 }
316
317 return error;
318 }
319
otPlatSettingsWipe(otInstance * aInstance)320 void otPlatSettingsWipe(otInstance *aInstance)
321 {
322 OT_UNUSED_VARIABLE(aInstance);
323 #if OPENTHREAD_POSIX_CONFIG_SECURE_SETTINGS_ENABLE
324 otPosixSecureSettingsWipe(aInstance);
325 #endif
326
327 VerifyOrDie(0 == ftruncate(sSettingsFd, 0), OT_EXIT_ERROR_ERRNO);
328 }
329
330 namespace ot {
331 namespace Posix {
332
PlatformSettingsGet(otInstance * aInstance,uint16_t aKey,int aIndex,uint8_t * aValue,uint16_t * aValueLength)333 otError PlatformSettingsGet(otInstance *aInstance, uint16_t aKey, int aIndex, uint8_t *aValue, uint16_t *aValueLength)
334 {
335 OT_UNUSED_VARIABLE(aInstance);
336
337 otError error = OT_ERROR_NOT_FOUND;
338 const off_t size = lseek(sSettingsFd, 0, SEEK_END);
339 off_t offset = lseek(sSettingsFd, 0, SEEK_SET);
340
341 VerifyOrExit(offset == 0 && size >= 0, error = OT_ERROR_PARSE);
342
343 while (offset < size)
344 {
345 uint16_t key;
346 uint16_t length;
347 ssize_t rval;
348
349 rval = read(sSettingsFd, &key, sizeof(key));
350 VerifyOrExit(rval == sizeof(key), error = OT_ERROR_PARSE);
351
352 rval = read(sSettingsFd, &length, sizeof(length));
353 VerifyOrExit(rval == sizeof(length), error = OT_ERROR_PARSE);
354
355 if (key == aKey)
356 {
357 if (aIndex == 0)
358 {
359 error = OT_ERROR_NONE;
360
361 if (aValueLength)
362 {
363 if (aValue)
364 {
365 uint16_t readLength = (length <= *aValueLength ? length : *aValueLength);
366
367 VerifyOrExit(read(sSettingsFd, aValue, readLength) == readLength, error = OT_ERROR_PARSE);
368 }
369
370 *aValueLength = length;
371 }
372
373 break;
374 }
375 else
376 {
377 --aIndex;
378 }
379 }
380
381 offset += sizeof(key) + sizeof(length) + length;
382 VerifyOrExit(offset == lseek(sSettingsFd, length, SEEK_CUR), error = OT_ERROR_PARSE);
383 }
384
385 exit:
386 return error;
387 }
388
PlatformSettingsSet(otInstance * aInstance,uint16_t aKey,const uint8_t * aValue,uint16_t aValueLength)389 void PlatformSettingsSet(otInstance *aInstance, uint16_t aKey, const uint8_t *aValue, uint16_t aValueLength)
390 {
391 int swapFd = -1;
392
393 switch (PlatformSettingsDelete(aInstance, aKey, -1, &swapFd))
394 {
395 case OT_ERROR_NONE:
396 case OT_ERROR_NOT_FOUND:
397 break;
398
399 default:
400 assert(false);
401 break;
402 }
403
404 VerifyOrDie(write(swapFd, &aKey, sizeof(aKey)) == sizeof(aKey) &&
405 write(swapFd, &aValueLength, sizeof(aValueLength)) == sizeof(aValueLength) &&
406 write(swapFd, aValue, aValueLength) == aValueLength,
407 OT_EXIT_FAILURE);
408
409 swapPersist(aInstance, swapFd);
410 }
411
PlatformSettingsAdd(otInstance * aInstance,uint16_t aKey,const uint8_t * aValue,uint16_t aValueLength)412 void PlatformSettingsAdd(otInstance *aInstance, uint16_t aKey, const uint8_t *aValue, uint16_t aValueLength)
413 {
414 off_t size = lseek(sSettingsFd, 0, SEEK_END);
415 int swapFd = swapOpen(aInstance);
416
417 if (size > 0)
418 {
419 VerifyOrDie(0 == lseek(sSettingsFd, 0, SEEK_SET), OT_EXIT_ERROR_ERRNO);
420 swapWrite(aInstance, swapFd, static_cast<uint16_t>(size));
421 }
422
423 VerifyOrDie(write(swapFd, &aKey, sizeof(aKey)) == sizeof(aKey) &&
424 write(swapFd, &aValueLength, sizeof(aValueLength)) == sizeof(aValueLength) &&
425 write(swapFd, aValue, aValueLength) == aValueLength,
426 OT_EXIT_FAILURE);
427
428 swapPersist(aInstance, swapFd);
429 }
430
PlatformSettingsDelete(otInstance * aInstance,uint16_t aKey,int aIndex,int * aSwapFd)431 otError PlatformSettingsDelete(otInstance *aInstance, uint16_t aKey, int aIndex, int *aSwapFd)
432 {
433 otError error = OT_ERROR_NOT_FOUND;
434 off_t size = lseek(sSettingsFd, 0, SEEK_END);
435 off_t offset = lseek(sSettingsFd, 0, SEEK_SET);
436 int swapFd = swapOpen(aInstance);
437
438 assert(swapFd != -1);
439 assert(offset == 0);
440 VerifyOrExit(offset == 0 && size >= 0, error = OT_ERROR_FAILED);
441
442 while (offset < size)
443 {
444 uint16_t key;
445 uint16_t length;
446 ssize_t rval;
447
448 rval = read(sSettingsFd, &key, sizeof(key));
449 VerifyOrExit(rval == sizeof(key), error = OT_ERROR_FAILED);
450
451 rval = read(sSettingsFd, &length, sizeof(length));
452 VerifyOrExit(rval == sizeof(length), error = OT_ERROR_FAILED);
453
454 offset += sizeof(key) + sizeof(length) + length;
455
456 if (aKey == key)
457 {
458 if (aIndex == 0)
459 {
460 VerifyOrExit(offset == lseek(sSettingsFd, length, SEEK_CUR), error = OT_ERROR_FAILED);
461 swapWrite(aInstance, swapFd, static_cast<uint16_t>(size - offset));
462 error = OT_ERROR_NONE;
463 break;
464 }
465 else if (aIndex == -1)
466 {
467 VerifyOrExit(offset == lseek(sSettingsFd, length, SEEK_CUR), error = OT_ERROR_FAILED);
468 error = OT_ERROR_NONE;
469 continue;
470 }
471 else
472 {
473 --aIndex;
474 }
475 }
476
477 rval = write(swapFd, &key, sizeof(key));
478 VerifyOrExit(rval == sizeof(key), error = OT_ERROR_FAILED);
479
480 rval = write(swapFd, &length, sizeof(length));
481 VerifyOrExit(rval == sizeof(length), error = OT_ERROR_FAILED);
482
483 swapWrite(aInstance, swapFd, length);
484 }
485
486 exit:
487 if (aSwapFd != nullptr)
488 {
489 *aSwapFd = swapFd;
490 }
491 else if (error == OT_ERROR_NONE)
492 {
493 swapPersist(aInstance, swapFd);
494 }
495 else if (error == OT_ERROR_NOT_FOUND)
496 {
497 swapDiscard(aInstance, swapFd);
498 }
499 else if (error == OT_ERROR_FAILED)
500 {
501 swapDiscard(aInstance, swapFd);
502 DieNow(error);
503 }
504
505 return error;
506 }
507
508 #if OPENTHREAD_POSIX_CONFIG_SECURE_SETTINGS_ENABLE
PlatformSettingsGetSensitiveKeys(otInstance * aInstance,const uint16_t ** aKeys,uint16_t * aKeysLength)509 void PlatformSettingsGetSensitiveKeys(otInstance *aInstance, const uint16_t **aKeys, uint16_t *aKeysLength)
510 {
511 OT_UNUSED_VARIABLE(aInstance);
512
513 assert(aKeys != nullptr);
514 assert(aKeysLength != nullptr);
515
516 *aKeys = sSensitiveKeys;
517 *aKeysLength = sSensitiveKeysLength;
518 }
519 #endif
520
521 } // namespace Posix
522 } // namespace ot
523
524 #ifndef SELF_TEST
525 #define SELF_TEST 0
526 #endif
527
528 #if SELF_TEST
529
otLogCritPlat(const char * aFormat,...)530 void otLogCritPlat(const char *aFormat, ...) { OT_UNUSED_VARIABLE(aFormat); }
531
otExitCodeToString(uint8_t aExitCode)532 const char *otExitCodeToString(uint8_t aExitCode)
533 {
534 OT_UNUSED_VARIABLE(aExitCode);
535 return "";
536 }
537
otPlatRadioGetIeeeEui64(otInstance * aInstance,uint8_t * aIeeeEui64)538 void otPlatRadioGetIeeeEui64(otInstance *aInstance, uint8_t *aIeeeEui64)
539 {
540 OT_UNUSED_VARIABLE(aInstance);
541
542 memset(aIeeeEui64, 0, sizeof(uint64_t));
543 }
544
545 // Stub implementation for testing
IsSystemDryRun(void)546 bool IsSystemDryRun(void) { return false; }
547
main()548 int main()
549 {
550 otInstance *instance = nullptr;
551 uint8_t data[60];
552
553 for (uint8_t i = 0; i < sizeof(data); ++i)
554 {
555 data[i] = i;
556 }
557
558 otPlatSettingsInit(instance, nullptr, 0);
559
560 // verify empty situation
561 otPlatSettingsWipe(instance);
562 {
563 uint8_t value[sizeof(data)];
564 uint16_t length = sizeof(value);
565
566 assert(otPlatSettingsGet(instance, 0, 0, value, &length) == OT_ERROR_NOT_FOUND);
567 assert(otPlatSettingsDelete(instance, 0, 0) == OT_ERROR_NOT_FOUND);
568 assert(otPlatSettingsDelete(instance, 0, -1) == OT_ERROR_NOT_FOUND);
569 }
570
571 // verify write one record
572 assert(otPlatSettingsSet(instance, 0, data, sizeof(data) / 2) == OT_ERROR_NONE);
573 {
574 uint8_t value[sizeof(data)];
575 uint16_t length = sizeof(value);
576
577 assert(otPlatSettingsGet(instance, 0, 0, nullptr, nullptr) == OT_ERROR_NONE);
578 assert(otPlatSettingsGet(instance, 0, 0, nullptr, &length) == OT_ERROR_NONE);
579 assert(length == sizeof(data) / 2);
580
581 length = sizeof(value);
582 assert(otPlatSettingsGet(instance, 0, 0, value, &length) == OT_ERROR_NONE);
583 assert(length == sizeof(data) / 2);
584 assert(0 == memcmp(value, data, length));
585
586 // insufficient buffer
587 length -= 1;
588 value[length] = 0;
589 assert(otPlatSettingsGet(instance, 0, 0, value, &length) == OT_ERROR_NONE);
590 // verify length becomes the actual length of the record
591 assert(length == sizeof(data) / 2);
592 // verify this byte is not changed
593 assert(value[length] == 0);
594
595 // wrong index
596 assert(otPlatSettingsGet(instance, 0, 1, nullptr, nullptr) == OT_ERROR_NOT_FOUND);
597 // wrong key
598 assert(otPlatSettingsGet(instance, 1, 0, nullptr, nullptr) == OT_ERROR_NOT_FOUND);
599 }
600 otPlatSettingsWipe(instance);
601
602 // verify write two records
603 assert(otPlatSettingsSet(instance, 0, data, sizeof(data)) == OT_ERROR_NONE);
604 assert(otPlatSettingsAdd(instance, 0, data, sizeof(data) / 2) == OT_ERROR_NONE);
605 {
606 uint8_t value[sizeof(data)];
607 uint16_t length = sizeof(value);
608
609 assert(otPlatSettingsGet(instance, 0, 1, value, &length) == OT_ERROR_NONE);
610 assert(length == sizeof(data) / 2);
611 assert(0 == memcmp(value, data, length));
612
613 length = sizeof(value);
614 assert(otPlatSettingsGet(instance, 0, 0, value, &length) == OT_ERROR_NONE);
615 assert(length == sizeof(data));
616 assert(0 == memcmp(value, data, length));
617 }
618 otPlatSettingsWipe(instance);
619
620 // verify write two records of different keys
621 assert(otPlatSettingsSet(instance, 0, data, sizeof(data)) == OT_ERROR_NONE);
622 assert(otPlatSettingsAdd(instance, 1, data, sizeof(data) / 2) == OT_ERROR_NONE);
623 {
624 uint8_t value[sizeof(data)];
625 uint16_t length = sizeof(value);
626
627 assert(otPlatSettingsGet(instance, 1, 0, value, &length) == OT_ERROR_NONE);
628 assert(length == sizeof(data) / 2);
629 assert(0 == memcmp(value, data, length));
630
631 length = sizeof(value);
632 assert(otPlatSettingsGet(instance, 0, 0, value, &length) == OT_ERROR_NONE);
633 assert(length == sizeof(data));
634 assert(0 == memcmp(value, data, length));
635 }
636 otPlatSettingsWipe(instance);
637
638 // verify delete record
639 assert(otPlatSettingsAdd(instance, 0, data, sizeof(data)) == OT_ERROR_NONE);
640 assert(otPlatSettingsAdd(instance, 0, data, sizeof(data) / 2) == OT_ERROR_NONE);
641 assert(otPlatSettingsAdd(instance, 0, data, sizeof(data) / 3) == OT_ERROR_NONE);
642 {
643 uint8_t value[sizeof(data)];
644 uint16_t length = sizeof(value);
645
646 // wrong key
647 assert(otPlatSettingsDelete(instance, 1, 0) == OT_ERROR_NOT_FOUND);
648 assert(otPlatSettingsDelete(instance, 1, -1) == OT_ERROR_NOT_FOUND);
649
650 // wrong index
651 assert(otPlatSettingsDelete(instance, 0, 3) == OT_ERROR_NOT_FOUND);
652
653 // delete one record
654 assert(otPlatSettingsDelete(instance, 0, 1) == OT_ERROR_NONE);
655 assert(otPlatSettingsGet(instance, 0, 1, value, &length) == OT_ERROR_NONE);
656 assert(length == sizeof(data) / 3);
657 assert(0 == memcmp(value, data, length));
658
659 // delete all records
660 assert(otPlatSettingsDelete(instance, 0, -1) == OT_ERROR_NONE);
661 assert(otPlatSettingsGet(instance, 0, 0, nullptr, nullptr) == OT_ERROR_NOT_FOUND);
662 }
663 otPlatSettingsWipe(instance);
664
665 // verify delete all records of a type
666 assert(otPlatSettingsAdd(instance, 0, data, sizeof(data)) == OT_ERROR_NONE);
667 assert(otPlatSettingsAdd(instance, 1, data, sizeof(data) / 2) == OT_ERROR_NONE);
668 assert(otPlatSettingsAdd(instance, 0, data, sizeof(data) / 3) == OT_ERROR_NONE);
669 {
670 uint8_t value[sizeof(data)];
671 uint16_t length = sizeof(value);
672
673 assert(otPlatSettingsDelete(instance, 0, -1) == OT_ERROR_NONE);
674 assert(otPlatSettingsGet(instance, 0, 0, value, &length) == OT_ERROR_NOT_FOUND);
675 assert(otPlatSettingsGet(instance, 1, 0, value, &length) == OT_ERROR_NONE);
676 assert(length == sizeof(data) / 2);
677 assert(0 == memcmp(value, data, length));
678
679 assert(otPlatSettingsDelete(instance, 0, 0) == OT_ERROR_NOT_FOUND);
680 assert(otPlatSettingsGet(instance, 0, 0, nullptr, nullptr) == OT_ERROR_NOT_FOUND);
681 }
682 otPlatSettingsWipe(instance);
683 otPlatSettingsDeinit(instance);
684
685 return 0;
686 }
687 #endif
688