1 /*
2 * Copyright (c) 2019 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/kernel.h>
8 #include <zephyr/logging/log.h>
9 #include <zephyr/settings/settings.h>
10 #include <zephyr/random/random.h>
11
12 #include <openthread/platform/settings.h>
13
14 LOG_MODULE_REGISTER(net_otPlat_settings, CONFIG_OPENTHREAD_L2_LOG_LEVEL);
15
16 #define OT_SETTINGS_ROOT_KEY "ot"
17 #define OT_SETTINGS_MAX_PATH_LEN 32
18
19 struct ot_setting_delete_ctx {
20 /* Setting subtree to delete. */
21 const char *subtree;
22
23 /* Current entry index, used to iterate over multiple setting
24 * instances.
25 */
26 int index;
27
28 /* Target index to delete. -1 to delete entire subtree. */
29 int target_index;
30
31 /* Operation result. */
32 int status;
33
34 /* Indicates if delete subtree root. */
35 bool delete_subtree_root;
36 };
37
ot_setting_delete_cb(const char * key,size_t len,settings_read_cb read_cb,void * cb_arg,void * param)38 static int ot_setting_delete_cb(const char *key, size_t len,
39 settings_read_cb read_cb, void *cb_arg,
40 void *param)
41 {
42 int ret;
43 char path[OT_SETTINGS_MAX_PATH_LEN];
44 struct ot_setting_delete_ctx *ctx =
45 (struct ot_setting_delete_ctx *)param;
46
47 ARG_UNUSED(len);
48 ARG_UNUSED(read_cb);
49 ARG_UNUSED(cb_arg);
50
51 if ((ctx->target_index != -1) && (ctx->target_index != ctx->index)) {
52 ctx->index++;
53 return 0;
54 }
55
56 if (key == NULL && ctx->delete_subtree_root == false) {
57 return 0;
58 }
59
60 ret = snprintk(path, sizeof(path), "%s%s%s", ctx->subtree,
61 key ? "/" : "", key ? key : "");
62 __ASSERT(ret < sizeof(path), "Setting path buffer too small.");
63
64 LOG_DBG("Removing: %s", path);
65
66 ret = settings_delete(path);
67 if (ret != 0) {
68 LOG_ERR("Failed to remove setting %s, ret %d", path,
69 ret);
70 __ASSERT_NO_MSG(false);
71 }
72
73 ctx->status = 0;
74
75 if (ctx->target_index == ctx->index) {
76 /* Break the loop on index match, otherwise it was -1
77 * (delete all).
78 */
79 return 1;
80 }
81
82 return 0;
83 }
84
ot_setting_delete_subtree(int key,int index,bool delete_subtree_root)85 static int ot_setting_delete_subtree(int key, int index, bool delete_subtree_root)
86 {
87 int ret;
88 char subtree[OT_SETTINGS_MAX_PATH_LEN];
89 struct ot_setting_delete_ctx delete_ctx = {
90 .subtree = subtree,
91 .status = -ENOENT,
92 .target_index = index,
93 .delete_subtree_root = delete_subtree_root,
94 };
95
96 if (key == -1) {
97 ret = snprintk(subtree, sizeof(subtree), "%s",
98 OT_SETTINGS_ROOT_KEY);
99 } else {
100 ret = snprintk(subtree, sizeof(subtree), "%s/%x",
101 OT_SETTINGS_ROOT_KEY, key);
102 }
103 __ASSERT(ret < sizeof(subtree), "Setting path buffer too small.");
104
105 ret = settings_load_subtree_direct(subtree, ot_setting_delete_cb,
106 &delete_ctx);
107 if (ret != 0) {
108 LOG_ERR("Failed to delete OT subtree %s, index %d, ret %d",
109 subtree, index, ret);
110 __ASSERT_NO_MSG(false);
111 }
112
113 return delete_ctx.status;
114 }
115
ot_setting_exists_cb(const char * key,size_t len,settings_read_cb read_cb,void * cb_arg,void * param)116 static int ot_setting_exists_cb(const char *key, size_t len,
117 settings_read_cb read_cb, void *cb_arg,
118 void *param)
119 {
120 bool *exists = (bool *)param;
121
122 ARG_UNUSED(len);
123 ARG_UNUSED(read_cb);
124 ARG_UNUSED(cb_arg);
125 ARG_UNUSED(key);
126
127 *exists = true;
128
129 return 1;
130 }
131
ot_setting_exists(const char * path)132 static bool ot_setting_exists(const char *path)
133 {
134 bool exists = false;
135
136 (void)settings_load_subtree_direct(path, ot_setting_exists_cb, &exists);
137
138 return exists;
139 }
140
141 struct ot_setting_read_ctx {
142 /* Buffer for the setting. */
143 uint8_t *value;
144
145 /* Buffer length on input, setting length read on output. */
146 uint16_t *length;
147
148 /* Current entry index, used to iterate over multiple setting
149 * instances.
150 */
151 int index;
152
153 /* Target instance to read. */
154 int target_index;
155
156 /* Operation result. */
157 int status;
158 };
159
ot_setting_read_cb(const char * key,size_t len,settings_read_cb read_cb,void * cb_arg,void * param)160 static int ot_setting_read_cb(const char *key, size_t len,
161 settings_read_cb read_cb, void *cb_arg,
162 void *param)
163 {
164 int ret;
165 struct ot_setting_read_ctx *ctx = (struct ot_setting_read_ctx *)param;
166
167 ARG_UNUSED(len);
168 ARG_UNUSED(read_cb);
169 ARG_UNUSED(cb_arg);
170
171 if (ctx->target_index != ctx->index) {
172 ctx->index++;
173 return 0;
174 }
175
176 /* Found setting, break the loop. */
177
178 if ((ctx->value == NULL) || (ctx->length == NULL)) {
179 goto out;
180 }
181
182 if (*(ctx->length) < len) {
183 len = *(ctx->length);
184 }
185
186 ret = read_cb(cb_arg, ctx->value, len);
187 if (ret <= 0) {
188 LOG_ERR("Failed to read the setting, ret: %d", ret);
189 ctx->status = -EIO;
190 return 1;
191 }
192
193 out:
194 if (ctx->length != NULL) {
195 *(ctx->length) = len;
196 }
197
198 ctx->status = 0;
199
200 return 1;
201 }
202
203 /* OpenThread APIs */
204
otPlatSettingsInit(otInstance * aInstance,const uint16_t * aSensitiveKeys,uint16_t aSensitiveKeysLength)205 void otPlatSettingsInit(otInstance *aInstance, const uint16_t *aSensitiveKeys,
206 uint16_t aSensitiveKeysLength)
207 {
208 int ret;
209
210 ARG_UNUSED(aInstance);
211 ARG_UNUSED(aSensitiveKeys);
212 ARG_UNUSED(aSensitiveKeysLength);
213
214 ret = settings_subsys_init();
215 if (ret != 0) {
216 LOG_ERR("settings_subsys_init failed (ret %d)", ret);
217 }
218 }
219
otPlatSettingsGet(otInstance * aInstance,uint16_t aKey,int aIndex,uint8_t * aValue,uint16_t * aValueLength)220 otError otPlatSettingsGet(otInstance *aInstance, uint16_t aKey, int aIndex,
221 uint8_t *aValue, uint16_t *aValueLength)
222 {
223 int ret;
224 char path[OT_SETTINGS_MAX_PATH_LEN];
225 struct ot_setting_read_ctx read_ctx = {
226 .value = aValue,
227 .length = (uint16_t *)aValueLength,
228 .status = -ENOENT,
229 .target_index = aIndex
230 };
231
232 ARG_UNUSED(aInstance);
233
234 LOG_DBG("%s Entry aKey %u aIndex %d", __func__, aKey, aIndex);
235
236 ret = snprintk(path, sizeof(path), "%s/%x", OT_SETTINGS_ROOT_KEY, aKey);
237 __ASSERT(ret < sizeof(path), "Setting path buffer too small.");
238
239 ret = settings_load_subtree_direct(path, ot_setting_read_cb, &read_ctx);
240 if (ret != 0) {
241 LOG_ERR("Failed to load OT setting aKey %d, aIndex %d, ret %d",
242 aKey, aIndex, ret);
243 }
244
245 if (read_ctx.status != 0) {
246 LOG_DBG("aKey %u aIndex %d not found", aKey, aIndex);
247 return OT_ERROR_NOT_FOUND;
248 }
249
250 return OT_ERROR_NONE;
251 }
252
otPlatSettingsSet(otInstance * aInstance,uint16_t aKey,const uint8_t * aValue,uint16_t aValueLength)253 otError otPlatSettingsSet(otInstance *aInstance, uint16_t aKey,
254 const uint8_t *aValue, uint16_t aValueLength)
255 {
256 int ret;
257 char path[OT_SETTINGS_MAX_PATH_LEN];
258
259 ARG_UNUSED(aInstance);
260
261 LOG_DBG("%s Entry aKey %u", __func__, aKey);
262
263 (void)ot_setting_delete_subtree(aKey, -1, false);
264
265 ret = snprintk(path, sizeof(path), "%s/%x", OT_SETTINGS_ROOT_KEY, aKey);
266 __ASSERT(ret < sizeof(path), "Setting path buffer too small.");
267
268 ret = settings_save_one(path, aValue, aValueLength);
269 if (ret != 0) {
270 LOG_ERR("Failed to store setting %d, ret %d", aKey, ret);
271 return OT_ERROR_NO_BUFS;
272 }
273
274 return OT_ERROR_NONE;
275 }
276
otPlatSettingsAdd(otInstance * aInstance,uint16_t aKey,const uint8_t * aValue,uint16_t aValueLength)277 otError otPlatSettingsAdd(otInstance *aInstance, uint16_t aKey,
278 const uint8_t *aValue, uint16_t aValueLength)
279 {
280 int ret;
281 char path[OT_SETTINGS_MAX_PATH_LEN];
282
283 ARG_UNUSED(aInstance);
284
285 LOG_DBG("%s Entry aKey %u", __func__, aKey);
286
287 do {
288 ret = snprintk(path, sizeof(path), "%s/%x/%08x",
289 OT_SETTINGS_ROOT_KEY, aKey, sys_rand32_get());
290 __ASSERT(ret < sizeof(path), "Setting path buffer too small.");
291 } while (ot_setting_exists(path));
292
293 ret = settings_save_one(path, aValue, aValueLength);
294 if (ret != 0) {
295 LOG_ERR("Failed to store setting %d, ret %d", aKey, ret);
296 return OT_ERROR_NO_BUFS;
297 }
298
299 return OT_ERROR_NONE;
300 }
301
otPlatSettingsDelete(otInstance * aInstance,uint16_t aKey,int aIndex)302 otError otPlatSettingsDelete(otInstance *aInstance, uint16_t aKey, int aIndex)
303 {
304 int ret;
305
306 ARG_UNUSED(aInstance);
307
308 LOG_DBG("%s Entry aKey %u aIndex %d", __func__, aKey, aIndex);
309
310 ret = ot_setting_delete_subtree(aKey, aIndex, true);
311 if (ret != 0) {
312 LOG_DBG("Entry not found aKey %u aIndex %d", aKey, aIndex);
313 return OT_ERROR_NOT_FOUND;
314 }
315
316 return OT_ERROR_NONE;
317 }
318
otPlatSettingsWipe(otInstance * aInstance)319 void otPlatSettingsWipe(otInstance *aInstance)
320 {
321 ARG_UNUSED(aInstance);
322
323 (void)ot_setting_delete_subtree(-1, -1, true);
324 }
325
otPlatSettingsDeinit(otInstance * aInstance)326 void otPlatSettingsDeinit(otInstance *aInstance)
327 {
328 ARG_UNUSED(aInstance);
329 }
330