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