1 /*
2  * Copyright (c) 2017 Linaro Limited
3  * Copyright (c) 2018-2019 Foundries.io
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 /*
9  * Uses some original concepts by:
10  *         Joakim Eriksson <joakime@sics.se>
11  *         Niclas Finne <nfi@sics.se>
12  *         Joel Hoglund <joel@sics.se>
13  */
14 
15 #define LOG_MODULE_NAME net_lwm2m_registry
16 #define LOG_LEVEL	CONFIG_LWM2M_LOG_LEVEL
17 
18 #include <zephyr/logging/log.h>
19 #include <zephyr/sys/ring_buffer.h>
20 LOG_MODULE_REGISTER(LOG_MODULE_NAME);
21 
22 #include "lwm2m_engine.h"
23 #include "lwm2m_object.h"
24 #include "lwm2m_obj_access_control.h"
25 #include "lwm2m_util.h"
26 #include "lwm2m_rd_client.h"
27 
28 #include <ctype.h>
29 #include <errno.h>
30 #include <stddef.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <time.h>
35 
36 #include <zephyr/types.h>
37 
38 #define BINDING_OPT_MAX_LEN 3 /* "UQ" */
39 #define QUEUE_OPT_MAX_LEN   2 /* "Q" */
40 
41 /* Thread safety */
42 static K_MUTEX_DEFINE(registry_lock);
43 
lwm2m_registry_lock(void)44 void lwm2m_registry_lock(void)
45 {
46 	(void)k_mutex_lock(&registry_lock, K_FOREVER);
47 }
48 
lwm2m_registry_unlock(void)49 void lwm2m_registry_unlock(void)
50 {
51 	(void)k_mutex_unlock(&registry_lock);
52 }
53 /* Resources */
54 static sys_slist_t engine_obj_list;
55 static sys_slist_t engine_obj_inst_list;
56 
57 /* Resource wrappers */
lwm2m_engine_obj_list(void)58 sys_slist_t *lwm2m_engine_obj_list(void) { return &engine_obj_list; }
59 
lwm2m_engine_obj_inst_list(void)60 sys_slist_t *lwm2m_engine_obj_inst_list(void) { return &engine_obj_inst_list; }
61 
62 #if defined(CONFIG_LWM2M_RESOURCE_DATA_CACHE_SUPPORT)
63 static void lwm2m_engine_cache_write(const struct lwm2m_engine_obj_field *obj_field,
64 				     const struct lwm2m_obj_path *path, const void *value,
65 				     uint16_t len);
66 #endif
67 /* Engine object */
68 
lwm2m_register_obj(struct lwm2m_engine_obj * obj)69 void lwm2m_register_obj(struct lwm2m_engine_obj *obj)
70 {
71 	k_mutex_lock(&registry_lock, K_FOREVER);
72 #if defined(CONFIG_LWM2M_ACCESS_CONTROL_ENABLE)
73 	/* If bootstrap, then bootstrap server should create the ac obj instances */
74 #if !IS_ENABLED(CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP)
75 	int server_obj_inst_id = lwm2m_server_short_id_to_inst(CONFIG_LWM2M_SERVER_DEFAULT_SSID);
76 
77 	access_control_add_obj(obj->obj_id, server_obj_inst_id);
78 #endif /* CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP */
79 #endif /* CONFIG_LWM2M_ACCESS_CONTROL_ENABLE */
80 	sys_slist_append(&engine_obj_list, &obj->node);
81 	k_mutex_unlock(&registry_lock);
82 }
83 
lwm2m_unregister_obj(struct lwm2m_engine_obj * obj)84 void lwm2m_unregister_obj(struct lwm2m_engine_obj *obj)
85 {
86 	k_mutex_lock(&registry_lock, K_FOREVER);
87 #if defined(CONFIG_LWM2M_ACCESS_CONTROL_ENABLE)
88 	access_control_remove_obj(obj->obj_id);
89 #endif
90 	engine_remove_observer_by_id(obj->obj_id, -1);
91 	sys_slist_find_and_remove(&engine_obj_list, &obj->node);
92 	k_mutex_unlock(&registry_lock);
93 }
94 
get_engine_obj(int obj_id)95 struct lwm2m_engine_obj *get_engine_obj(int obj_id)
96 {
97 	struct lwm2m_engine_obj *obj;
98 
99 	SYS_SLIST_FOR_EACH_CONTAINER(&engine_obj_list, obj, node) {
100 		if (obj->obj_id == obj_id) {
101 			return obj;
102 		}
103 	}
104 
105 	return NULL;
106 }
107 
lwm2m_get_engine_obj_field(struct lwm2m_engine_obj * obj,int res_id)108 struct lwm2m_engine_obj_field *lwm2m_get_engine_obj_field(struct lwm2m_engine_obj *obj, int res_id)
109 {
110 	int i;
111 
112 	if (obj && obj->fields && obj->field_count > 0) {
113 		for (i = 0; i < obj->field_count; i++) {
114 			if (obj->fields[i].res_id == res_id) {
115 				return &obj->fields[i];
116 			}
117 		}
118 	}
119 
120 	return NULL;
121 }
122 
lwm2m_engine_get_obj(const struct lwm2m_obj_path * path)123 struct lwm2m_engine_obj *lwm2m_engine_get_obj(const struct lwm2m_obj_path *path)
124 {
125 	if (path->level < LWM2M_PATH_LEVEL_OBJECT) {
126 		return NULL;
127 	}
128 
129 	return get_engine_obj(path->obj_id);
130 }
131 /* Engine object instance */
132 
engine_register_obj_inst(struct lwm2m_engine_obj_inst * obj_inst)133 static void engine_register_obj_inst(struct lwm2m_engine_obj_inst *obj_inst)
134 {
135 #if defined(CONFIG_LWM2M_ACCESS_CONTROL_ENABLE)
136 	/* If bootstrap, then bootstrap server should create the ac obj instances */
137 #if !IS_ENABLED(CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP)
138 	int server_obj_inst_id = lwm2m_server_short_id_to_inst(CONFIG_LWM2M_SERVER_DEFAULT_SSID);
139 
140 	access_control_add(obj_inst->obj->obj_id, obj_inst->obj_inst_id, server_obj_inst_id);
141 #endif /* CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP */
142 #endif /* CONFIG_LWM2M_ACCESS_CONTROL_ENABLE */
143 	sys_slist_append(&engine_obj_inst_list, &obj_inst->node);
144 }
145 
engine_unregister_obj_inst(struct lwm2m_engine_obj_inst * obj_inst)146 static void engine_unregister_obj_inst(struct lwm2m_engine_obj_inst *obj_inst)
147 {
148 #if defined(CONFIG_LWM2M_ACCESS_CONTROL_ENABLE)
149 	access_control_remove(obj_inst->obj->obj_id, obj_inst->obj_inst_id);
150 #endif
151 	engine_remove_observer_by_id(obj_inst->obj->obj_id, obj_inst->obj_inst_id);
152 	sys_slist_find_and_remove(&engine_obj_inst_list, &obj_inst->node);
153 }
154 
get_engine_obj_inst(int obj_id,int obj_inst_id)155 struct lwm2m_engine_obj_inst *get_engine_obj_inst(int obj_id, int obj_inst_id)
156 {
157 	struct lwm2m_engine_obj_inst *obj_inst;
158 
159 	SYS_SLIST_FOR_EACH_CONTAINER(&engine_obj_inst_list, obj_inst, node) {
160 		if (obj_inst->obj->obj_id == obj_id && obj_inst->obj_inst_id == obj_inst_id) {
161 			return obj_inst;
162 		}
163 	}
164 
165 	return NULL;
166 }
167 
next_engine_obj_inst(int obj_id,int obj_inst_id)168 struct lwm2m_engine_obj_inst *next_engine_obj_inst(int obj_id, int obj_inst_id)
169 {
170 	struct lwm2m_engine_obj_inst *obj_inst, *next = NULL;
171 
172 	SYS_SLIST_FOR_EACH_CONTAINER(&engine_obj_inst_list, obj_inst, node) {
173 		if (obj_inst->obj->obj_id == obj_id && obj_inst->obj_inst_id > obj_inst_id &&
174 		    (!next || next->obj_inst_id > obj_inst->obj_inst_id)) {
175 			next = obj_inst;
176 		}
177 	}
178 
179 	return next;
180 }
181 
lwm2m_create_obj_inst(uint16_t obj_id,uint16_t obj_inst_id,struct lwm2m_engine_obj_inst ** obj_inst)182 int lwm2m_create_obj_inst(uint16_t obj_id, uint16_t obj_inst_id,
183 			  struct lwm2m_engine_obj_inst **obj_inst)
184 {
185 	k_mutex_lock(&registry_lock, K_FOREVER);
186 	struct lwm2m_engine_obj *obj;
187 	int ret;
188 
189 	*obj_inst = NULL;
190 	obj = get_engine_obj(obj_id);
191 	if (!obj) {
192 		LOG_ERR("unable to find obj: %u", obj_id);
193 		k_mutex_unlock(&registry_lock);
194 		return -ENOENT;
195 	}
196 
197 	if (!obj->create_cb) {
198 		LOG_ERR("obj %u has no create_cb", obj_id);
199 		k_mutex_unlock(&registry_lock);
200 		return -EINVAL;
201 	}
202 
203 	if (obj->instance_count + 1 > obj->max_instance_count) {
204 		LOG_ERR("no more instances available for obj %u", obj_id);
205 		k_mutex_unlock(&registry_lock);
206 		return -ENOMEM;
207 	}
208 
209 	*obj_inst = obj->create_cb(obj_inst_id);
210 	if (!*obj_inst) {
211 		LOG_ERR("unable to create obj %u instance %u", obj_id, obj_inst_id);
212 		/*
213 		 * Already checked for instance count total.
214 		 * This can only be an error if the object instance exists.
215 		 */
216 		k_mutex_unlock(&registry_lock);
217 		return -EEXIST;
218 	}
219 
220 	obj->instance_count++;
221 	(*obj_inst)->obj = obj;
222 	(*obj_inst)->obj_inst_id = obj_inst_id;
223 	engine_register_obj_inst(*obj_inst);
224 
225 	if (obj->user_create_cb) {
226 		ret = obj->user_create_cb(obj_inst_id);
227 		if (ret < 0) {
228 			LOG_ERR("Error in user obj create %u/%u: %d", obj_id, obj_inst_id, ret);
229 			k_mutex_unlock(&registry_lock);
230 			lwm2m_delete_obj_inst(obj_id, obj_inst_id);
231 			return ret;
232 		}
233 	}
234 	k_mutex_unlock(&registry_lock);
235 	return 0;
236 }
237 
lwm2m_delete_obj_inst(uint16_t obj_id,uint16_t obj_inst_id)238 int lwm2m_delete_obj_inst(uint16_t obj_id, uint16_t obj_inst_id)
239 {
240 	k_mutex_lock(&registry_lock, K_FOREVER);
241 	int i, ret = 0;
242 	struct lwm2m_engine_obj *obj;
243 	struct lwm2m_engine_obj_inst *obj_inst;
244 
245 	obj = get_engine_obj(obj_id);
246 	if (!obj) {
247 		k_mutex_unlock(&registry_lock);
248 		return -ENOENT;
249 	}
250 
251 	obj_inst = get_engine_obj_inst(obj_id, obj_inst_id);
252 	if (!obj_inst) {
253 		k_mutex_unlock(&registry_lock);
254 		return -ENOENT;
255 	}
256 
257 	if (obj->user_delete_cb) {
258 		ret = obj->user_delete_cb(obj_inst_id);
259 		if (ret < 0) {
260 			LOG_ERR("Error in user obj delete %u/%u: %d", obj_id, obj_inst_id, ret);
261 			/* don't return error */
262 		}
263 	}
264 
265 	engine_unregister_obj_inst(obj_inst);
266 	obj->instance_count--;
267 
268 	if (obj->delete_cb) {
269 		ret = obj->delete_cb(obj_inst_id);
270 	}
271 
272 	/* reset obj_inst and res_inst data structure */
273 	for (i = 0; i < obj_inst->resource_count; i++) {
274 		clear_attrs(&obj_inst->resources[i]);
275 		(void)memset(obj_inst->resources + i, 0, sizeof(struct lwm2m_engine_res));
276 	}
277 
278 	clear_attrs(obj_inst);
279 	(void)memset(obj_inst, 0, sizeof(struct lwm2m_engine_obj_inst));
280 	k_mutex_unlock(&registry_lock);
281 	return ret;
282 }
283 
lwm2m_create_object_inst(const struct lwm2m_obj_path * path)284 int lwm2m_create_object_inst(const struct lwm2m_obj_path *path)
285 {
286 	struct lwm2m_engine_obj_inst *obj_inst;
287 	int ret = 0;
288 
289 	if (path->level != LWM2M_PATH_LEVEL_OBJECT_INST) {
290 		LOG_ERR("path must have 2 parts");
291 		return -EINVAL;
292 	}
293 
294 	ret = lwm2m_create_obj_inst(path->obj_id, path->obj_inst_id, &obj_inst);
295 	if (ret < 0) {
296 		return ret;
297 	}
298 
299 	engine_trigger_update(true);
300 
301 	return 0;
302 }
303 
lwm2m_engine_create_obj_inst(const char * pathstr)304 int lwm2m_engine_create_obj_inst(const char *pathstr)
305 {
306 	struct lwm2m_obj_path path;
307 	int ret = 0;
308 
309 	LOG_DBG("path:%s", pathstr);
310 
311 	/* translate path -> path_obj */
312 	ret = lwm2m_string_to_path(pathstr, &path, '/');
313 	if (ret < 0) {
314 		return ret;
315 	}
316 
317 	return lwm2m_create_object_inst(&path);
318 }
319 
lwm2m_delete_object_inst(const struct lwm2m_obj_path * path)320 int lwm2m_delete_object_inst(const struct lwm2m_obj_path *path)
321 {
322 	int ret = 0;
323 
324 	if (path->level != LWM2M_PATH_LEVEL_OBJECT_INST) {
325 		LOG_ERR("path must have 2 parts");
326 		return -EINVAL;
327 	}
328 
329 	ret = lwm2m_delete_obj_inst(path->obj_id, path->obj_inst_id);
330 	if (ret < 0) {
331 		return ret;
332 	}
333 
334 	engine_trigger_update(true);
335 
336 	return 0;
337 }
338 
lwm2m_engine_delete_obj_inst(const char * pathstr)339 int lwm2m_engine_delete_obj_inst(const char *pathstr)
340 {
341 	struct lwm2m_obj_path path;
342 	int ret = 0;
343 
344 	LOG_DBG("path: %s", pathstr);
345 
346 	/* translate path -> path_obj */
347 	ret = lwm2m_string_to_path(pathstr, &path, '/');
348 	if (ret < 0) {
349 		return ret;
350 	}
351 
352 	return lwm2m_delete_object_inst(&path);
353 }
354 
lwm2m_engine_get_obj_inst(const struct lwm2m_obj_path * path)355 struct lwm2m_engine_obj_inst *lwm2m_engine_get_obj_inst(const struct lwm2m_obj_path *path)
356 {
357 	if (path->level < LWM2M_PATH_LEVEL_OBJECT_INST) {
358 		return NULL;
359 	}
360 
361 	return get_engine_obj_inst(path->obj_id, path->obj_inst_id);
362 }
363 
path_to_objs(const struct lwm2m_obj_path * path,struct lwm2m_engine_obj_inst ** obj_inst,struct lwm2m_engine_obj_field ** obj_field,struct lwm2m_engine_res ** res,struct lwm2m_engine_res_inst ** res_inst)364 int path_to_objs(const struct lwm2m_obj_path *path, struct lwm2m_engine_obj_inst **obj_inst,
365 		 struct lwm2m_engine_obj_field **obj_field, struct lwm2m_engine_res **res,
366 		 struct lwm2m_engine_res_inst **res_inst)
367 {
368 	struct lwm2m_engine_obj_inst *oi;
369 	struct lwm2m_engine_obj_field *of;
370 	struct lwm2m_engine_res *r = NULL;
371 	struct lwm2m_engine_res_inst *ri = NULL;
372 	int i;
373 
374 	if (!path) {
375 		return -EINVAL;
376 	}
377 
378 	oi = get_engine_obj_inst(path->obj_id, path->obj_inst_id);
379 	if (!oi) {
380 		LOG_ERR("obj instance %d/%d not found", path->obj_id, path->obj_inst_id);
381 		return -ENOENT;
382 	}
383 
384 	if (!oi->resources || oi->resource_count == 0U) {
385 		LOG_ERR("obj instance has no resources");
386 		return -EINVAL;
387 	}
388 
389 	of = lwm2m_get_engine_obj_field(oi->obj, path->res_id);
390 	if (!of) {
391 		LOG_ERR("obj field %d not found", path->res_id);
392 		return -ENOENT;
393 	}
394 
395 	for (i = 0; i < oi->resource_count; i++) {
396 		if (oi->resources[i].res_id == path->res_id) {
397 			r = &oi->resources[i];
398 			break;
399 		}
400 	}
401 
402 	if (!r) {
403 		if (LWM2M_HAS_PERM(of, BIT(LWM2M_FLAG_OPTIONAL))) {
404 			LOG_DBG("resource %d not found", path->res_id);
405 		} else {
406 			LOG_ERR("resource %d not found", path->res_id);
407 		}
408 
409 		return -ENOENT;
410 	}
411 
412 	for (i = 0; i < r->res_inst_count; i++) {
413 		if (r->res_instances[i].res_inst_id == path->res_inst_id) {
414 			ri = &r->res_instances[i];
415 			break;
416 		}
417 	}
418 
419 	/* specifically don't complain about missing resource instance */
420 
421 	if (obj_inst) {
422 		*obj_inst = oi;
423 	}
424 
425 	if (obj_field) {
426 		*obj_field = of;
427 	}
428 
429 	if (res) {
430 		*res = r;
431 	}
432 
433 	if (ri && res_inst) {
434 		*res_inst = ri;
435 	}
436 
437 	return 0;
438 }
439 
is_string(const struct lwm2m_obj_path * path)440 static bool is_string(const struct lwm2m_obj_path *path)
441 {
442 	struct lwm2m_engine_obj_field *obj_field;
443 	int ret;
444 
445 	ret = path_to_objs(path, NULL, &obj_field, NULL, NULL);
446 	if (ret < 0 || !obj_field) {
447 		return false;
448 	}
449 	if (obj_field->data_type == LWM2M_RES_TYPE_STRING) {
450 		return true;
451 	}
452 	return false;
453 }
454 
455 /* User data setter functions */
456 
lwm2m_set_res_buf(const struct lwm2m_obj_path * path,void * buffer_ptr,uint16_t buffer_len,uint16_t data_len,uint8_t data_flags)457 int lwm2m_set_res_buf(const struct lwm2m_obj_path *path, void *buffer_ptr, uint16_t buffer_len,
458 		      uint16_t data_len, uint8_t data_flags)
459 {
460 	int ret;
461 	struct lwm2m_engine_res_inst *res_inst = NULL;
462 
463 	if (path->level < LWM2M_PATH_LEVEL_RESOURCE) {
464 		LOG_ERR("path must have at least 3 parts");
465 		return -EINVAL;
466 	}
467 
468 	k_mutex_lock(&registry_lock, K_FOREVER);
469 	/* look up resource obj */
470 	ret = path_to_objs(path, NULL, NULL, NULL, &res_inst);
471 	if (ret < 0) {
472 		k_mutex_unlock(&registry_lock);
473 		return ret;
474 	}
475 
476 	if (!res_inst) {
477 		LOG_ERR("res instance %d not found", path->res_inst_id);
478 		k_mutex_unlock(&registry_lock);
479 		return -ENOENT;
480 	}
481 
482 	/* assign data elements */
483 	res_inst->data_ptr = buffer_ptr;
484 	res_inst->data_len = data_len;
485 	res_inst->max_data_len = buffer_len;
486 	res_inst->data_flags = data_flags;
487 
488 	k_mutex_unlock(&registry_lock);
489 	return ret;
490 }
491 
lwm2m_engine_set_res_buf(const char * pathstr,void * buffer_ptr,uint16_t buffer_len,uint16_t data_len,uint8_t data_flags)492 int lwm2m_engine_set_res_buf(const char *pathstr, void *buffer_ptr, uint16_t buffer_len,
493 			     uint16_t data_len, uint8_t data_flags)
494 {
495 	struct lwm2m_obj_path path;
496 	int ret = 0;
497 
498 	/* translate path -> path_obj */
499 	ret = lwm2m_string_to_path(pathstr, &path, '/');
500 	if (ret < 0) {
501 		return ret;
502 	}
503 
504 	return lwm2m_set_res_buf(&path, buffer_ptr, buffer_len, data_len, data_flags);
505 }
506 
lwm2m_engine_set_res_data(const char * pathstr,void * data_ptr,uint16_t data_len,uint8_t data_flags)507 int lwm2m_engine_set_res_data(const char *pathstr, void *data_ptr, uint16_t data_len,
508 			      uint8_t data_flags)
509 {
510 	struct lwm2m_obj_path path;
511 	int ret = 0;
512 
513 	/* translate path -> path_obj */
514 	ret = lwm2m_string_to_path(pathstr, &path, '/');
515 	if (ret < 0) {
516 		return ret;
517 	}
518 
519 	return lwm2m_set_res_buf(&path, data_ptr, data_len, data_len, data_flags);
520 }
521 
lwm2m_validate_time_resource_lenghts(uint16_t resource_length,uint16_t buf_length)522 static bool lwm2m_validate_time_resource_lenghts(uint16_t resource_length, uint16_t buf_length)
523 {
524 	if (resource_length != sizeof(time_t) && resource_length != sizeof(uint32_t)) {
525 		return false;
526 	}
527 
528 	if (buf_length != sizeof(time_t) && buf_length != sizeof(uint32_t)) {
529 		return false;
530 	}
531 
532 	return true;
533 }
534 
lwm2m_check_buf_sizes(uint8_t data_type,uint16_t resource_length,uint16_t buf_length)535 static int lwm2m_check_buf_sizes(uint8_t data_type, uint16_t resource_length, uint16_t buf_length)
536 {
537 	switch (data_type) {
538 	case LWM2M_RES_TYPE_OPAQUE:
539 	case LWM2M_RES_TYPE_STRING:
540 		if (resource_length > buf_length) {
541 			return -ENOMEM;
542 		}
543 		break;
544 	case LWM2M_RES_TYPE_U32:
545 	case LWM2M_RES_TYPE_U8:
546 	case LWM2M_RES_TYPE_S64:
547 	case LWM2M_RES_TYPE_S32:
548 	case LWM2M_RES_TYPE_S16:
549 	case LWM2M_RES_TYPE_S8:
550 	case LWM2M_RES_TYPE_BOOL:
551 	case LWM2M_RES_TYPE_FLOAT:
552 	case LWM2M_RES_TYPE_OBJLNK:
553 		if (resource_length != buf_length) {
554 			return -EINVAL;
555 		}
556 		break;
557 	default:
558 		return 0;
559 	}
560 	return 0;
561 }
562 
lwm2m_engine_set(const struct lwm2m_obj_path * path,const void * value,uint16_t len)563 static int lwm2m_engine_set(const struct lwm2m_obj_path *path, const void *value, uint16_t len)
564 {
565 	struct lwm2m_engine_obj_inst *obj_inst;
566 	struct lwm2m_engine_obj_field *obj_field;
567 	struct lwm2m_engine_res *res = NULL;
568 	struct lwm2m_engine_res_inst *res_inst = NULL;
569 	void *data_ptr = NULL;
570 	size_t max_data_len = 0;
571 	int ret = 0;
572 	bool changed = false;
573 
574 	if (path->level < LWM2M_PATH_LEVEL_RESOURCE) {
575 		LOG_ERR("path must have at least 3 parts");
576 		return -EINVAL;
577 	}
578 
579 	LOG_DBG("path:%u/%u/%u, buf:%p, len:%d", path->obj_id, path->obj_inst_id,
580 		path->res_id, value, len);
581 
582 	k_mutex_lock(&registry_lock, K_FOREVER);
583 	/* look up resource obj */
584 	ret = path_to_objs(path, &obj_inst, &obj_field, &res, &res_inst);
585 	if (ret < 0) {
586 		k_mutex_unlock(&registry_lock);
587 		return ret;
588 	}
589 
590 	if (!res_inst) {
591 		LOG_ERR("res instance %d not found", path->res_inst_id);
592 		k_mutex_unlock(&registry_lock);
593 		return -ENOENT;
594 	}
595 
596 	if (LWM2M_HAS_RES_FLAG(res_inst, LWM2M_RES_DATA_FLAG_RO)) {
597 		LOG_ERR("res instance data pointer is read-only "
598 			"[%u/%u/%u/%u:lvl%u]", path->obj_id, path->obj_inst_id, path->res_id,
599 			path->res_inst_id, path->level);
600 		k_mutex_unlock(&registry_lock);
601 		return -EACCES;
602 	}
603 
604 	/* setup initial data elements */
605 	data_ptr = res_inst->data_ptr;
606 	max_data_len = res_inst->max_data_len;
607 
608 	/* allow user to override data elements via callback */
609 	if (res->pre_write_cb) {
610 		data_ptr = res->pre_write_cb(obj_inst->obj_inst_id, res->res_id,
611 					     res_inst->res_inst_id, &max_data_len);
612 	}
613 
614 	if (!data_ptr) {
615 		LOG_ERR("res instance data pointer is NULL [%u/%u/%u/%u:%u]", path->obj_id,
616 			path->obj_inst_id, path->res_id, path->res_inst_id, path->level);
617 		k_mutex_unlock(&registry_lock);
618 		return -EINVAL;
619 	}
620 
621 	ret = lwm2m_check_buf_sizes(obj_field->data_type, len, max_data_len);
622 	if (ret) {
623 		LOG_ERR("Incorrect buffer length %u for res data length %zu", len,
624 			max_data_len);
625 		k_mutex_unlock(&registry_lock);
626 		return ret;
627 	}
628 
629 	if (memcmp(data_ptr, value, len) != 0 || res_inst->data_len != len) {
630 		changed = true;
631 	}
632 
633 #if CONFIG_LWM2M_ENGINE_VALIDATION_BUFFER_SIZE > 0
634 	if (res->validate_cb) {
635 		ret = res->validate_cb(obj_inst->obj_inst_id, res->res_id, res_inst->res_inst_id,
636 				       (uint8_t *)value, len, false, 0);
637 		if (ret < 0) {
638 			k_mutex_unlock(&registry_lock);
639 			return -EINVAL;
640 		}
641 	}
642 #endif /* CONFIG_LWM2M_ENGINE_VALIDATION_BUFFER_SIZE > 0 */
643 
644 	switch (obj_field->data_type) {
645 
646 	case LWM2M_RES_TYPE_OPAQUE:
647 		if (len) {
648 			memcpy((uint8_t *)data_ptr, value, len);
649 		}
650 		break;
651 
652 	case LWM2M_RES_TYPE_STRING:
653 		if (len) {
654 			strncpy(data_ptr, value, len - 1);
655 			((char *)data_ptr)[len - 1] = '\0';
656 		} else {
657 			((char *)data_ptr)[0] = '\0';
658 		}
659 		break;
660 
661 	case LWM2M_RES_TYPE_U32:
662 		*((uint32_t *)data_ptr) = *(uint32_t *)value;
663 		break;
664 
665 	case LWM2M_RES_TYPE_U16:
666 		*((uint16_t *)data_ptr) = *(uint16_t *)value;
667 		break;
668 
669 	case LWM2M_RES_TYPE_U8:
670 		*((uint8_t *)data_ptr) = *(uint8_t *)value;
671 		break;
672 
673 	case LWM2M_RES_TYPE_TIME:
674 		if (!lwm2m_validate_time_resource_lenghts(max_data_len, len)) {
675 			LOG_ERR("Time Set: buffer length %u  max data len %zu not supported", len,
676 				max_data_len);
677 			return -EINVAL;
678 		}
679 
680 		if (max_data_len == sizeof(time_t)) {
681 			if (len == sizeof(time_t)) {
682 				*((time_t *)data_ptr) = *(time_t *)value;
683 			} else {
684 				*((time_t *)data_ptr) = (time_t) *((uint32_t *)value);
685 			}
686 		} else {
687 			LOG_WRN("Converting time to 32bit may cause integer overflow on resource "
688 				"[%u/%u/%u/%u:%u]", path->obj_id, path->obj_inst_id, path->res_id,
689 				path->res_inst_id, path->level);
690 			if (len == sizeof(uint32_t)) {
691 				*((uint32_t *)data_ptr) = *(uint32_t *)value;
692 			} else {
693 				*((uint32_t *)data_ptr) = (uint32_t) *((time_t *)value);
694 			}
695 		}
696 
697 		break;
698 
699 	case LWM2M_RES_TYPE_S64:
700 		*((int64_t *)data_ptr) = *(int64_t *)value;
701 		break;
702 
703 	case LWM2M_RES_TYPE_S32:
704 		*((int32_t *)data_ptr) = *(int32_t *)value;
705 		break;
706 
707 	case LWM2M_RES_TYPE_S16:
708 		*((int16_t *)data_ptr) = *(int16_t *)value;
709 		break;
710 
711 	case LWM2M_RES_TYPE_S8:
712 		*((int8_t *)data_ptr) = *(int8_t *)value;
713 		break;
714 
715 	case LWM2M_RES_TYPE_BOOL:
716 		*((bool *)data_ptr) = *(bool *)value;
717 		break;
718 
719 	case LWM2M_RES_TYPE_FLOAT:
720 		*(double *)data_ptr = *(double *)value;
721 		break;
722 
723 	case LWM2M_RES_TYPE_OBJLNK:
724 		*((struct lwm2m_objlnk *)data_ptr) = *(struct lwm2m_objlnk *)value;
725 		break;
726 
727 	default:
728 		LOG_ERR("unknown obj data_type %d", obj_field->data_type);
729 		k_mutex_unlock(&registry_lock);
730 		return -EINVAL;
731 	}
732 
733 	res_inst->data_len = len;
734 
735 	/* Cache Data Write */
736 #if defined(CONFIG_LWM2M_RESOURCE_DATA_CACHE_SUPPORT)
737 	lwm2m_engine_cache_write(obj_field, path, value, len);
738 #endif
739 
740 	if (res->post_write_cb) {
741 		ret = res->post_write_cb(obj_inst->obj_inst_id, res->res_id, res_inst->res_inst_id,
742 					 data_ptr, len, false, 0);
743 	}
744 
745 	if (changed && LWM2M_HAS_PERM(obj_field, LWM2M_PERM_R)) {
746 		lwm2m_notify_observer_path(path);
747 	}
748 	k_mutex_unlock(&registry_lock);
749 	return ret;
750 }
751 
lwm2m_set_opaque(const struct lwm2m_obj_path * path,const char * data_ptr,uint16_t data_len)752 int lwm2m_set_opaque(const struct lwm2m_obj_path *path, const char *data_ptr, uint16_t data_len)
753 {
754 	return lwm2m_engine_set(path, data_ptr, data_len);
755 }
756 
lwm2m_engine_set_opaque(const char * pathstr,const char * data_ptr,uint16_t data_len)757 int lwm2m_engine_set_opaque(const char *pathstr, const char *data_ptr, uint16_t data_len)
758 {
759 	struct lwm2m_obj_path path;
760 	int ret = 0;
761 
762 	ret = lwm2m_string_to_path(pathstr, &path, '/');
763 	if (ret < 0) {
764 		return ret;
765 	}
766 	return lwm2m_set_opaque(&path, data_ptr, data_len);
767 }
768 
lwm2m_set_string(const struct lwm2m_obj_path * path,const char * data_ptr)769 int lwm2m_set_string(const struct lwm2m_obj_path *path, const char *data_ptr)
770 {
771 	uint16_t len = strlen(data_ptr);
772 
773 	/* String resources contain terminator as well, opaque resources don't */
774 	if (is_string(path)) {
775 		len += 1;
776 	}
777 
778 	return lwm2m_engine_set(path, data_ptr, len);
779 }
780 
lwm2m_engine_set_string(const char * pathstr,const char * data_ptr)781 int lwm2m_engine_set_string(const char *pathstr, const char *data_ptr)
782 {
783 	struct lwm2m_obj_path path;
784 	int ret = 0;
785 
786 	ret = lwm2m_string_to_path(pathstr, &path, '/');
787 	if (ret < 0) {
788 		return ret;
789 	}
790 	return lwm2m_set_string(&path, data_ptr);
791 }
792 
lwm2m_set_u8(const struct lwm2m_obj_path * path,uint8_t value)793 int lwm2m_set_u8(const struct lwm2m_obj_path *path, uint8_t value)
794 {
795 	return lwm2m_engine_set(path, &value, 1);
796 }
797 
lwm2m_engine_set_u8(const char * pathstr,uint8_t value)798 int lwm2m_engine_set_u8(const char *pathstr, uint8_t value)
799 {
800 	struct lwm2m_obj_path path;
801 	int ret = 0;
802 
803 	ret = lwm2m_string_to_path(pathstr, &path, '/');
804 	if (ret < 0) {
805 		return ret;
806 	}
807 	return lwm2m_set_u8(&path, value);
808 }
809 
lwm2m_set_u16(const struct lwm2m_obj_path * path,uint16_t value)810 int lwm2m_set_u16(const struct lwm2m_obj_path *path, uint16_t value)
811 {
812 	return lwm2m_engine_set(path, &value, 2);
813 }
814 
lwm2m_engine_set_u16(const char * pathstr,uint16_t value)815 int lwm2m_engine_set_u16(const char *pathstr, uint16_t value)
816 {
817 	struct lwm2m_obj_path path;
818 	int ret = 0;
819 
820 	ret = lwm2m_string_to_path(pathstr, &path, '/');
821 	if (ret < 0) {
822 		return ret;
823 	}
824 	return lwm2m_set_u16(&path, value);
825 }
826 
lwm2m_set_u32(const struct lwm2m_obj_path * path,uint32_t value)827 int lwm2m_set_u32(const struct lwm2m_obj_path *path, uint32_t value)
828 {
829 	return lwm2m_engine_set(path, &value, 4);
830 }
831 
lwm2m_engine_set_u32(const char * pathstr,uint32_t value)832 int lwm2m_engine_set_u32(const char *pathstr, uint32_t value)
833 {
834 	struct lwm2m_obj_path path;
835 	int ret = 0;
836 
837 	ret = lwm2m_string_to_path(pathstr, &path, '/');
838 	if (ret < 0) {
839 		return ret;
840 	}
841 	return lwm2m_set_u32(&path, value);
842 }
843 
lwm2m_set_u64(const struct lwm2m_obj_path * path,uint64_t value)844 int lwm2m_set_u64(const struct lwm2m_obj_path *path, uint64_t value)
845 {
846 	return lwm2m_engine_set(path, &value, 8);
847 }
848 
lwm2m_engine_set_u64(const char * pathstr,uint64_t value)849 int lwm2m_engine_set_u64(const char *pathstr, uint64_t value)
850 {
851 	struct lwm2m_obj_path path;
852 	int ret = 0;
853 
854 	ret = lwm2m_string_to_path(pathstr, &path, '/');
855 	if (ret < 0) {
856 		return ret;
857 	}
858 	return lwm2m_set_u64(&path, value);
859 }
860 
lwm2m_set_s8(const struct lwm2m_obj_path * path,int8_t value)861 int lwm2m_set_s8(const struct lwm2m_obj_path *path, int8_t value)
862 {
863 	return lwm2m_engine_set(path, &value, 1);
864 }
865 
lwm2m_engine_set_s8(const char * pathstr,int8_t value)866 int lwm2m_engine_set_s8(const char *pathstr, int8_t value)
867 {
868 	struct lwm2m_obj_path path;
869 	int ret = 0;
870 
871 	ret = lwm2m_string_to_path(pathstr, &path, '/');
872 	if (ret < 0) {
873 		return ret;
874 	}
875 	return lwm2m_set_s8(&path, value);
876 }
877 
lwm2m_set_s16(const struct lwm2m_obj_path * path,int16_t value)878 int lwm2m_set_s16(const struct lwm2m_obj_path *path, int16_t value)
879 {
880 	return lwm2m_engine_set(path, &value, 2);
881 
882 }
883 
lwm2m_engine_set_s16(const char * pathstr,int16_t value)884 int lwm2m_engine_set_s16(const char *pathstr, int16_t value)
885 {
886 	struct lwm2m_obj_path path;
887 	int ret = 0;
888 
889 	ret = lwm2m_string_to_path(pathstr, &path, '/');
890 	if (ret < 0) {
891 		return ret;
892 	}
893 	return lwm2m_set_s16(&path, value);
894 }
895 
lwm2m_set_s32(const struct lwm2m_obj_path * path,int32_t value)896 int lwm2m_set_s32(const struct lwm2m_obj_path *path, int32_t value)
897 {
898 	return lwm2m_engine_set(path, &value, 4);
899 }
900 
lwm2m_engine_set_s32(const char * pathstr,int32_t value)901 int lwm2m_engine_set_s32(const char *pathstr, int32_t value)
902 {
903 	struct lwm2m_obj_path path;
904 	int ret = 0;
905 
906 	ret = lwm2m_string_to_path(pathstr, &path, '/');
907 	if (ret < 0) {
908 		return ret;
909 	}
910 	return lwm2m_set_s32(&path, value);
911 }
912 
lwm2m_set_s64(const struct lwm2m_obj_path * path,int64_t value)913 int lwm2m_set_s64(const struct lwm2m_obj_path *path, int64_t value)
914 {
915 	return lwm2m_engine_set(path, &value, 8);
916 }
917 
lwm2m_engine_set_s64(const char * pathstr,int64_t value)918 int lwm2m_engine_set_s64(const char *pathstr, int64_t value)
919 {
920 	struct lwm2m_obj_path path;
921 	int ret = 0;
922 
923 	ret = lwm2m_string_to_path(pathstr, &path, '/');
924 	if (ret < 0) {
925 		return ret;
926 	}
927 	return lwm2m_set_s64(&path, value);
928 }
929 
lwm2m_set_bool(const struct lwm2m_obj_path * path,bool value)930 int lwm2m_set_bool(const struct lwm2m_obj_path *path, bool value)
931 {
932 	uint8_t temp = (value != 0 ? 1 : 0);
933 
934 	return lwm2m_engine_set(path, &temp, 1);
935 }
936 
lwm2m_engine_set_bool(const char * pathstr,bool value)937 int lwm2m_engine_set_bool(const char *pathstr, bool value)
938 {
939 	struct lwm2m_obj_path path;
940 	int ret = 0;
941 
942 	ret = lwm2m_string_to_path(pathstr, &path, '/');
943 	if (ret < 0) {
944 		return ret;
945 	}
946 	return lwm2m_set_bool(&path, value);
947 }
948 
lwm2m_set_f64(const struct lwm2m_obj_path * path,const double value)949 int lwm2m_set_f64(const struct lwm2m_obj_path *path, const double value)
950 {
951 	return lwm2m_engine_set(path, &value, sizeof(double));
952 }
953 
lwm2m_engine_set_float(const char * pathstr,const double * value)954 int lwm2m_engine_set_float(const char *pathstr, const double *value)
955 {
956 	struct lwm2m_obj_path path;
957 	int ret = 0;
958 
959 	ret = lwm2m_string_to_path(pathstr, &path, '/');
960 	if (ret < 0) {
961 		return ret;
962 	}
963 	return lwm2m_set_f64(&path, *value);
964 }
965 
lwm2m_set_objlnk(const struct lwm2m_obj_path * path,const struct lwm2m_objlnk * value)966 int lwm2m_set_objlnk(const struct lwm2m_obj_path *path, const struct lwm2m_objlnk *value)
967 {
968 	return lwm2m_engine_set(path, value, sizeof(struct lwm2m_objlnk));
969 }
970 
lwm2m_engine_set_objlnk(const char * pathstr,const struct lwm2m_objlnk * value)971 int lwm2m_engine_set_objlnk(const char *pathstr, const struct lwm2m_objlnk *value)
972 {
973 	struct lwm2m_obj_path path;
974 	int ret = 0;
975 
976 	ret = lwm2m_string_to_path(pathstr, &path, '/');
977 	if (ret < 0) {
978 		return ret;
979 	}
980 	return lwm2m_set_objlnk(&path, value);
981 }
982 
lwm2m_set_time(const struct lwm2m_obj_path * path,time_t value)983 int lwm2m_set_time(const struct lwm2m_obj_path *path, time_t value)
984 {
985 	return lwm2m_engine_set(path, &value, sizeof(time_t));
986 }
987 
lwm2m_engine_set_time(const char * pathstr,time_t value)988 int lwm2m_engine_set_time(const char *pathstr, time_t value)
989 {
990 	struct lwm2m_obj_path path;
991 	int ret = 0;
992 
993 	ret = lwm2m_string_to_path(pathstr, &path, '/');
994 	if (ret < 0) {
995 		return ret;
996 	}
997 	return lwm2m_set_time(&path, value);
998 }
999 
lwm2m_set_res_data_len(const struct lwm2m_obj_path * path,uint16_t data_len)1000 int lwm2m_set_res_data_len(const struct lwm2m_obj_path *path, uint16_t data_len)
1001 {
1002 	int ret;
1003 	void *buffer_ptr;
1004 	uint16_t buffer_len;
1005 	uint16_t old_len;
1006 	uint8_t data_flags;
1007 
1008 	ret = lwm2m_get_res_buf(path, &buffer_ptr, &buffer_len, &old_len, &data_flags);
1009 	if (ret) {
1010 		return ret;
1011 	}
1012 	return lwm2m_set_res_buf(path, buffer_ptr, buffer_len, data_len, data_flags);
1013 }
1014 
lwm2m_engine_set_res_data_len(const char * pathstr,uint16_t data_len)1015 int lwm2m_engine_set_res_data_len(const char *pathstr, uint16_t data_len)
1016 {
1017 	struct lwm2m_obj_path path;
1018 	int ret = 0;
1019 
1020 	/* translate path -> path_obj */
1021 	ret = lwm2m_string_to_path(pathstr, &path, '/');
1022 	if (ret < 0) {
1023 		return ret;
1024 	}
1025 
1026 	return lwm2m_set_res_data_len(&path, data_len);
1027 }
1028 /* User data getter functions */
1029 
lwm2m_get_res_buf(const struct lwm2m_obj_path * path,void ** buffer_ptr,uint16_t * buffer_len,uint16_t * data_len,uint8_t * data_flags)1030 int lwm2m_get_res_buf(const struct lwm2m_obj_path *path, void **buffer_ptr, uint16_t *buffer_len,
1031 		      uint16_t *data_len, uint8_t *data_flags)
1032 {
1033 	int ret;
1034 	struct lwm2m_engine_res_inst *res_inst = NULL;
1035 
1036 	if (path->level < LWM2M_PATH_LEVEL_RESOURCE) {
1037 		LOG_ERR("path must have at least 3 parts");
1038 		return -EINVAL;
1039 	}
1040 
1041 	k_mutex_lock(&registry_lock, K_FOREVER);
1042 	/* look up resource obj */
1043 	ret = path_to_objs(path, NULL, NULL, NULL, &res_inst);
1044 	if (ret < 0) {
1045 		k_mutex_unlock(&registry_lock);
1046 		return ret;
1047 	}
1048 
1049 	if (!res_inst) {
1050 		LOG_ERR("res instance %d not found", path->res_inst_id);
1051 		k_mutex_unlock(&registry_lock);
1052 		return -ENOENT;
1053 	}
1054 
1055 	if (buffer_ptr) {
1056 		*buffer_ptr = res_inst->data_ptr;
1057 	}
1058 	if (buffer_len) {
1059 		*buffer_len = res_inst->max_data_len;
1060 	}
1061 	if (data_len) {
1062 		*data_len = res_inst->data_len;
1063 	}
1064 	if (data_flags) {
1065 		*data_flags = res_inst->data_flags;
1066 	}
1067 
1068 	k_mutex_unlock(&registry_lock);
1069 	return 0;
1070 }
1071 
lwm2m_engine_get_res_buf(const char * pathstr,void ** buffer_ptr,uint16_t * buffer_len,uint16_t * data_len,uint8_t * data_flags)1072 int lwm2m_engine_get_res_buf(const char *pathstr, void **buffer_ptr, uint16_t *buffer_len,
1073 			     uint16_t *data_len, uint8_t *data_flags)
1074 {
1075 	struct lwm2m_obj_path path;
1076 	int ret = 0;
1077 
1078 	/* translate path -> path_obj */
1079 	ret = lwm2m_string_to_path(pathstr, &path, '/');
1080 	if (ret < 0) {
1081 		return ret;
1082 	}
1083 
1084 	return lwm2m_get_res_buf(&path, buffer_ptr, buffer_len, data_len, data_flags);
1085 }
1086 
lwm2m_engine_get_res_data(const char * pathstr,void ** data_ptr,uint16_t * data_len,uint8_t * data_flags)1087 int lwm2m_engine_get_res_data(const char *pathstr, void **data_ptr, uint16_t *data_len,
1088 			      uint8_t *data_flags)
1089 {
1090 	struct lwm2m_obj_path path;
1091 	int ret = 0;
1092 
1093 	/* translate path -> path_obj */
1094 	ret = lwm2m_string_to_path(pathstr, &path, '/');
1095 	if (ret < 0) {
1096 		return ret;
1097 	}
1098 
1099 	return lwm2m_get_res_buf(&path, data_ptr, NULL, data_len, data_flags);
1100 }
1101 
lwm2m_engine_get(const struct lwm2m_obj_path * path,void * buf,uint16_t buflen)1102 static int lwm2m_engine_get(const struct lwm2m_obj_path *path, void *buf, uint16_t buflen)
1103 {
1104 	int ret = 0;
1105 	struct lwm2m_engine_obj_inst *obj_inst;
1106 	struct lwm2m_engine_obj_field *obj_field;
1107 	struct lwm2m_engine_res *res = NULL;
1108 	struct lwm2m_engine_res_inst *res_inst = NULL;
1109 	void *data_ptr = NULL;
1110 	size_t data_len = 0;
1111 
1112 	if (path->level < LWM2M_PATH_LEVEL_RESOURCE) {
1113 		LOG_ERR("path must have at least 3 parts");
1114 		return -EINVAL;
1115 	}
1116 	LOG_DBG("path:%u/%u/%u/%u, level %u, buf:%p, buflen:%d", path->obj_id, path->obj_inst_id,
1117 		path->res_id, path->res_inst_id, path->level, buf, buflen);
1118 
1119 	k_mutex_lock(&registry_lock, K_FOREVER);
1120 	/* look up resource obj */
1121 	ret = path_to_objs(path, &obj_inst, &obj_field, &res, &res_inst);
1122 	if (ret < 0) {
1123 		k_mutex_unlock(&registry_lock);
1124 		return ret;
1125 	}
1126 
1127 	if (!res_inst) {
1128 		LOG_ERR("res instance %d not found", path->res_inst_id);
1129 		k_mutex_unlock(&registry_lock);
1130 		return -ENOENT;
1131 	}
1132 
1133 	/* setup initial data elements */
1134 	data_ptr = res_inst->data_ptr;
1135 	data_len = res_inst->data_len;
1136 
1137 	/* allow user to override data elements via callback */
1138 	if (res->read_cb) {
1139 		data_ptr = res->read_cb(obj_inst->obj_inst_id, res->res_id, res_inst->res_inst_id,
1140 					&data_len);
1141 	}
1142 
1143 	if (data_ptr && data_len > 0) {
1144 		ret = lwm2m_check_buf_sizes(obj_field->data_type, data_len, buflen);
1145 		if (ret) {
1146 			LOG_ERR("Incorrect resource data length %zu. Buffer length %u", data_len,
1147 				buflen);
1148 			k_mutex_unlock(&registry_lock);
1149 			return ret;
1150 		}
1151 
1152 		switch (obj_field->data_type) {
1153 
1154 		case LWM2M_RES_TYPE_OPAQUE:
1155 			memcpy(buf, data_ptr, data_len);
1156 			break;
1157 
1158 		case LWM2M_RES_TYPE_STRING:
1159 			strncpy(buf, data_ptr, data_len - 1);
1160 			((char *)buf)[data_len - 1] = '\0';
1161 			break;
1162 
1163 		case LWM2M_RES_TYPE_U32:
1164 			*(uint32_t *)buf = *(uint32_t *)data_ptr;
1165 			break;
1166 		case LWM2M_RES_TYPE_TIME:
1167 			if (!lwm2m_validate_time_resource_lenghts(data_len, buflen)) {
1168 				LOG_ERR("Time get buffer length %u  data len %zu not supported",
1169 					buflen, data_len);
1170 				return -EINVAL;
1171 			}
1172 
1173 			if (data_len == sizeof(time_t)) {
1174 				if (buflen == sizeof(time_t)) {
1175 					*((time_t *)buf) = *(time_t *)data_ptr;
1176 				} else {
1177 					/* In this case get operation may not got correct value */
1178 					LOG_WRN("Converting time to 32bit may cause integer "
1179 						"overflow");
1180 					*((uint32_t *)buf) = (uint32_t) *((time_t *)data_ptr);
1181 				}
1182 			} else {
1183 				LOG_WRN("Converting time to 32bit may cause integer overflow");
1184 				if (buflen == sizeof(uint32_t)) {
1185 					*((uint32_t *)buf) = *(uint32_t *)data_ptr;
1186 				} else {
1187 					*((time_t *)buf) = (time_t) *((uint32_t *)data_ptr);
1188 				}
1189 			}
1190 			break;
1191 
1192 		case LWM2M_RES_TYPE_U16:
1193 			*(uint16_t *)buf = *(uint16_t *)data_ptr;
1194 			break;
1195 
1196 		case LWM2M_RES_TYPE_U8:
1197 			*(uint8_t *)buf = *(uint8_t *)data_ptr;
1198 			break;
1199 
1200 		case LWM2M_RES_TYPE_S64:
1201 			*(int64_t *)buf = *(int64_t *)data_ptr;
1202 			break;
1203 
1204 		case LWM2M_RES_TYPE_S32:
1205 			*(int32_t *)buf = *(int32_t *)data_ptr;
1206 			break;
1207 
1208 		case LWM2M_RES_TYPE_S16:
1209 			*(int16_t *)buf = *(int16_t *)data_ptr;
1210 			break;
1211 
1212 		case LWM2M_RES_TYPE_S8:
1213 			*(int8_t *)buf = *(int8_t *)data_ptr;
1214 			break;
1215 
1216 		case LWM2M_RES_TYPE_BOOL:
1217 			*(bool *)buf = *(bool *)data_ptr;
1218 			break;
1219 
1220 		case LWM2M_RES_TYPE_FLOAT:
1221 			*(double *)buf = *(double *)data_ptr;
1222 			break;
1223 
1224 		case LWM2M_RES_TYPE_OBJLNK:
1225 			*(struct lwm2m_objlnk *)buf = *(struct lwm2m_objlnk *)data_ptr;
1226 			break;
1227 
1228 		default:
1229 			LOG_ERR("unknown obj data_type %d", obj_field->data_type);
1230 			k_mutex_unlock(&registry_lock);
1231 			return -EINVAL;
1232 		}
1233 	} else if (obj_field->data_type == LWM2M_RES_TYPE_STRING) {
1234 		/* Ensure empty string when there is no data */
1235 		((char *)buf)[0] = '\0';
1236 	}
1237 	k_mutex_unlock(&registry_lock);
1238 	return 0;
1239 }
1240 
lwm2m_get_opaque(const struct lwm2m_obj_path * path,void * buf,uint16_t buflen)1241 int lwm2m_get_opaque(const struct lwm2m_obj_path *path, void *buf, uint16_t buflen)
1242 {
1243 	return lwm2m_engine_get(path, buf, buflen);
1244 }
1245 
lwm2m_engine_get_opaque(const char * pathstr,void * buf,uint16_t buflen)1246 int lwm2m_engine_get_opaque(const char *pathstr, void *buf, uint16_t buflen)
1247 {
1248 	struct lwm2m_obj_path path;
1249 	int ret = 0;
1250 
1251 	ret = lwm2m_string_to_path(pathstr, &path, '/');
1252 	if (ret < 0) {
1253 		return ret;
1254 	}
1255 	return lwm2m_get_opaque(&path, buf, buflen);
1256 }
1257 
lwm2m_get_string(const struct lwm2m_obj_path * path,void * str,uint16_t buflen)1258 int lwm2m_get_string(const struct lwm2m_obj_path *path, void *str, uint16_t buflen)
1259 {
1260 	/* Ensure termination, in case resource is not a string type */
1261 	if (!is_string(path)) {
1262 		memset(str, 0, buflen);
1263 		buflen -= 1; /* Last terminator cannot be overwritten */
1264 	}
1265 
1266 	return lwm2m_engine_get(path, str, buflen);
1267 }
1268 
lwm2m_engine_get_string(const char * pathstr,void * str,uint16_t buflen)1269 int lwm2m_engine_get_string(const char *pathstr, void *str, uint16_t buflen)
1270 {
1271 	struct lwm2m_obj_path path;
1272 	int ret = 0;
1273 
1274 	ret = lwm2m_string_to_path(pathstr, &path, '/');
1275 	if (ret < 0) {
1276 		return ret;
1277 	}
1278 	return lwm2m_get_string(&path, str, buflen);
1279 }
1280 
lwm2m_get_u8(const struct lwm2m_obj_path * path,uint8_t * value)1281 int lwm2m_get_u8(const struct lwm2m_obj_path *path, uint8_t *value)
1282 {
1283 	return lwm2m_engine_get(path, value, 1);
1284 }
1285 
lwm2m_engine_get_u8(const char * pathstr,uint8_t * value)1286 int lwm2m_engine_get_u8(const char *pathstr, uint8_t *value)
1287 {
1288 	struct lwm2m_obj_path path;
1289 	int ret = 0;
1290 
1291 	ret = lwm2m_string_to_path(pathstr, &path, '/');
1292 	if (ret < 0) {
1293 		return ret;
1294 	}
1295 	return lwm2m_get_u8(&path, value);
1296 }
1297 
lwm2m_get_u16(const struct lwm2m_obj_path * path,uint16_t * value)1298 int lwm2m_get_u16(const struct lwm2m_obj_path *path, uint16_t *value)
1299 {
1300 	return lwm2m_engine_get(path, value, 2);
1301 }
1302 
lwm2m_engine_get_u16(const char * pathstr,uint16_t * value)1303 int lwm2m_engine_get_u16(const char *pathstr, uint16_t *value)
1304 {
1305 	struct lwm2m_obj_path path;
1306 	int ret = 0;
1307 
1308 	ret = lwm2m_string_to_path(pathstr, &path, '/');
1309 	if (ret < 0) {
1310 		return ret;
1311 	}
1312 	return lwm2m_get_u16(&path, value);
1313 }
1314 
lwm2m_get_u32(const struct lwm2m_obj_path * path,uint32_t * value)1315 int lwm2m_get_u32(const struct lwm2m_obj_path *path, uint32_t *value)
1316 {
1317 	return lwm2m_engine_get(path, value, 4);
1318 }
1319 
lwm2m_engine_get_u32(const char * pathstr,uint32_t * value)1320 int lwm2m_engine_get_u32(const char *pathstr, uint32_t *value)
1321 {
1322 	struct lwm2m_obj_path path;
1323 	int ret = 0;
1324 
1325 	ret = lwm2m_string_to_path(pathstr, &path, '/');
1326 	if (ret < 0) {
1327 		return ret;
1328 	}
1329 	return lwm2m_get_u32(&path, value);
1330 }
1331 
lwm2m_get_u64(const struct lwm2m_obj_path * path,uint64_t * value)1332 int lwm2m_get_u64(const struct lwm2m_obj_path *path, uint64_t *value)
1333 {
1334 	return lwm2m_engine_get(path, value, 8);
1335 }
1336 
lwm2m_engine_get_u64(const char * pathstr,uint64_t * value)1337 int lwm2m_engine_get_u64(const char *pathstr, uint64_t *value)
1338 {
1339 	struct lwm2m_obj_path path;
1340 	int ret = 0;
1341 
1342 	ret = lwm2m_string_to_path(pathstr, &path, '/');
1343 	if (ret < 0) {
1344 		return ret;
1345 	}
1346 	return lwm2m_get_u64(&path, value);
1347 }
1348 
lwm2m_get_s8(const struct lwm2m_obj_path * path,int8_t * value)1349 int lwm2m_get_s8(const struct lwm2m_obj_path *path, int8_t *value)
1350 {
1351 	return lwm2m_engine_get(path, value, 1);
1352 }
1353 
lwm2m_engine_get_s8(const char * pathstr,int8_t * value)1354 int lwm2m_engine_get_s8(const char *pathstr, int8_t *value)
1355 {
1356 	struct lwm2m_obj_path path;
1357 	int ret = 0;
1358 
1359 	ret = lwm2m_string_to_path(pathstr, &path, '/');
1360 	if (ret < 0) {
1361 		return ret;
1362 	}
1363 	return lwm2m_get_s8(&path, value);
1364 }
1365 
lwm2m_get_s16(const struct lwm2m_obj_path * path,int16_t * value)1366 int lwm2m_get_s16(const struct lwm2m_obj_path *path, int16_t *value)
1367 {
1368 	return lwm2m_engine_get(path, value, 2);
1369 }
1370 
lwm2m_engine_get_s16(const char * pathstr,int16_t * value)1371 int lwm2m_engine_get_s16(const char *pathstr, int16_t *value)
1372 {
1373 	struct lwm2m_obj_path path;
1374 	int ret = 0;
1375 
1376 	ret = lwm2m_string_to_path(pathstr, &path, '/');
1377 	if (ret < 0) {
1378 		return ret;
1379 	}
1380 	return lwm2m_get_s16(&path, value);
1381 }
1382 
lwm2m_get_s32(const struct lwm2m_obj_path * path,int32_t * value)1383 int lwm2m_get_s32(const struct lwm2m_obj_path *path, int32_t *value)
1384 {
1385 	return lwm2m_engine_get(path, value, 4);
1386 }
1387 
lwm2m_engine_get_s32(const char * pathstr,int32_t * value)1388 int lwm2m_engine_get_s32(const char *pathstr, int32_t *value)
1389 {
1390 	struct lwm2m_obj_path path;
1391 	int ret = 0;
1392 
1393 	ret = lwm2m_string_to_path(pathstr, &path, '/');
1394 	if (ret < 0) {
1395 		return ret;
1396 	}
1397 	return lwm2m_get_s32(&path, value);
1398 }
1399 
lwm2m_get_s64(const struct lwm2m_obj_path * path,int64_t * value)1400 int lwm2m_get_s64(const struct lwm2m_obj_path *path, int64_t *value)
1401 {
1402 	return lwm2m_engine_get(path, value, 8);
1403 }
1404 
lwm2m_engine_get_s64(const char * pathstr,int64_t * value)1405 int lwm2m_engine_get_s64(const char *pathstr, int64_t *value)
1406 {
1407 	struct lwm2m_obj_path path;
1408 	int ret = 0;
1409 
1410 	ret = lwm2m_string_to_path(pathstr, &path, '/');
1411 	if (ret < 0) {
1412 		return ret;
1413 	}
1414 	return lwm2m_get_s64(&path, value);
1415 }
1416 
lwm2m_get_bool(const struct lwm2m_obj_path * path,bool * value)1417 int lwm2m_get_bool(const struct lwm2m_obj_path *path, bool *value)
1418 {
1419 	int ret = 0;
1420 	int8_t temp = 0;
1421 
1422 	ret = lwm2m_get_s8(path, &temp);
1423 	if (!ret) {
1424 		*value = temp != 0;
1425 	}
1426 
1427 	return ret;
1428 }
1429 
lwm2m_engine_get_bool(const char * pathstr,bool * value)1430 int lwm2m_engine_get_bool(const char *pathstr, bool *value)
1431 {
1432 	struct lwm2m_obj_path path;
1433 	int ret = 0;
1434 
1435 	ret = lwm2m_string_to_path(pathstr, &path, '/');
1436 	if (ret < 0) {
1437 		return ret;
1438 	}
1439 	return lwm2m_get_bool(&path, value);
1440 }
1441 
lwm2m_get_f64(const struct lwm2m_obj_path * path,double * value)1442 int lwm2m_get_f64(const struct lwm2m_obj_path *path, double *value)
1443 {
1444 	return lwm2m_engine_get(path, value, sizeof(double));
1445 }
1446 
lwm2m_engine_get_float(const char * pathstr,double * buf)1447 int lwm2m_engine_get_float(const char *pathstr, double *buf)
1448 {
1449 	struct lwm2m_obj_path path;
1450 	int ret = 0;
1451 
1452 	ret = lwm2m_string_to_path(pathstr, &path, '/');
1453 	if (ret < 0) {
1454 		return ret;
1455 	}
1456 	return lwm2m_get_f64(&path, buf);
1457 }
1458 
lwm2m_get_objlnk(const struct lwm2m_obj_path * path,struct lwm2m_objlnk * buf)1459 int lwm2m_get_objlnk(const struct lwm2m_obj_path *path, struct lwm2m_objlnk *buf)
1460 {
1461 	return lwm2m_engine_get(path, buf, sizeof(struct lwm2m_objlnk));
1462 }
1463 
lwm2m_engine_get_objlnk(const char * pathstr,struct lwm2m_objlnk * buf)1464 int lwm2m_engine_get_objlnk(const char *pathstr, struct lwm2m_objlnk *buf)
1465 {
1466 	struct lwm2m_obj_path path;
1467 	int ret = 0;
1468 
1469 	ret = lwm2m_string_to_path(pathstr, &path, '/');
1470 	if (ret < 0) {
1471 		return ret;
1472 	}
1473 	return lwm2m_get_objlnk(&path, buf);
1474 }
1475 
lwm2m_get_time(const struct lwm2m_obj_path * path,time_t * buf)1476 int lwm2m_get_time(const struct lwm2m_obj_path *path, time_t *buf)
1477 {
1478 	return lwm2m_engine_get(path, buf, sizeof(time_t));
1479 }
1480 
lwm2m_engine_get_time(const char * pathstr,time_t * buf)1481 int lwm2m_engine_get_time(const char *pathstr, time_t *buf)
1482 {
1483 	struct lwm2m_obj_path path;
1484 	int ret = 0;
1485 
1486 	ret = lwm2m_string_to_path(pathstr, &path, '/');
1487 	if (ret < 0) {
1488 		return ret;
1489 	}
1490 	return lwm2m_get_time(&path, buf);
1491 }
1492 
lwm2m_get_resource(const struct lwm2m_obj_path * path,struct lwm2m_engine_res ** res)1493 int lwm2m_get_resource(const struct lwm2m_obj_path *path, struct lwm2m_engine_res **res)
1494 {
1495 	if (path->level < LWM2M_PATH_LEVEL_RESOURCE) {
1496 		LOG_ERR("path must have 3 parts");
1497 		return -EINVAL;
1498 	}
1499 
1500 	return path_to_objs(path, NULL, NULL, res, NULL);
1501 }
1502 
lwm2m_engine_get_resource(const char * pathstr,struct lwm2m_engine_res ** res)1503 int lwm2m_engine_get_resource(const char *pathstr, struct lwm2m_engine_res **res)
1504 {
1505 	int ret;
1506 	struct lwm2m_obj_path path;
1507 
1508 	ret = lwm2m_string_to_path(pathstr, &path, '/');
1509 	if (ret < 0) {
1510 		return ret;
1511 	}
1512 
1513 	return lwm2m_get_resource(&path, res);
1514 }
1515 
lwm2m_engine_get_opaque_more(struct lwm2m_input_context * in,uint8_t * buf,size_t buflen,struct lwm2m_opaque_context * opaque,bool * last_block)1516 size_t lwm2m_engine_get_opaque_more(struct lwm2m_input_context *in, uint8_t *buf, size_t buflen,
1517 				    struct lwm2m_opaque_context *opaque, bool *last_block)
1518 {
1519 	uint32_t in_len = opaque->remaining;
1520 	uint16_t remaining = in->in_cpkt->max_len - in->offset;
1521 
1522 	if (in_len > buflen) {
1523 		in_len = buflen;
1524 	}
1525 
1526 	if (in_len > remaining) {
1527 		in_len = remaining;
1528 	}
1529 
1530 	opaque->remaining -= in_len;
1531 	remaining -= in_len;
1532 	if (opaque->remaining == 0U || remaining == 0) {
1533 		*last_block = true;
1534 	}
1535 
1536 	if (buf_read(buf, in_len, CPKT_BUF_READ(in->in_cpkt), &in->offset) < 0) {
1537 		*last_block = true;
1538 		return 0;
1539 	}
1540 
1541 	return (size_t)in_len;
1542 }
1543 
lwm2m_engine_get_queue_mode(char * queue)1544 void lwm2m_engine_get_queue_mode(char *queue)
1545 {
1546 	if (IS_ENABLED(CONFIG_LWM2M_QUEUE_MODE_ENABLED)) {
1547 		strncpy(queue, "Q", QUEUE_OPT_MAX_LEN);
1548 	} else {
1549 		strncpy(queue, "", QUEUE_OPT_MAX_LEN);
1550 	}
1551 }
1552 
lwm2m_engine_get_binding(char * binding)1553 void lwm2m_engine_get_binding(char *binding)
1554 {
1555 	/* Defaults to UDP. */
1556 	strncpy(binding, "U", BINDING_OPT_MAX_LEN);
1557 #if CONFIG_LWM2M_VERSION_1_0
1558 	/* In LwM2M 1.0 binding and queue mode are in same parameter */
1559 	char queue[QUEUE_OPT_MAX_LEN];
1560 
1561 	lwm2m_engine_get_queue_mode(queue);
1562 	strncat(binding, queue, QUEUE_OPT_MAX_LEN);
1563 #endif
1564 }
1565 /* Engine resource instance */
1566 
lwm2m_engine_allocate_resource_instance(struct lwm2m_engine_res * res,struct lwm2m_engine_res_inst ** res_inst,uint8_t resource_instance_id)1567 static int lwm2m_engine_allocate_resource_instance(struct lwm2m_engine_res *res,
1568 						   struct lwm2m_engine_res_inst **res_inst,
1569 						   uint8_t resource_instance_id)
1570 {
1571 	int i;
1572 
1573 	if (!res->res_instances || res->res_inst_count == 0) {
1574 		return -ENOMEM;
1575 	}
1576 
1577 	for (i = 0; i < res->res_inst_count; i++) {
1578 		if (res->res_instances[i].res_inst_id == RES_INSTANCE_NOT_CREATED) {
1579 			break;
1580 		}
1581 	}
1582 
1583 	if (i >= res->res_inst_count) {
1584 		return -ENOMEM;
1585 	}
1586 
1587 	res->res_instances[i].res_inst_id = resource_instance_id;
1588 	*res_inst = &res->res_instances[i];
1589 	return 0;
1590 }
1591 
lwm2m_engine_get_create_res_inst(const struct lwm2m_obj_path * path,struct lwm2m_engine_res ** res,struct lwm2m_engine_res_inst ** res_inst)1592 int lwm2m_engine_get_create_res_inst(const struct lwm2m_obj_path *path,
1593 				     struct lwm2m_engine_res **res,
1594 				     struct lwm2m_engine_res_inst **res_inst)
1595 {
1596 	int ret;
1597 	struct lwm2m_engine_res *r = NULL;
1598 	struct lwm2m_engine_res_inst *r_i = NULL;
1599 
1600 	ret = path_to_objs(path, NULL, NULL, &r, &r_i);
1601 	if (ret < 0) {
1602 		return ret;
1603 	}
1604 
1605 	if (!r) {
1606 		return -ENOENT;
1607 	}
1608 	/* Store resource pointer */
1609 	*res = r;
1610 
1611 	if (!r_i) {
1612 		if (path->level < LWM2M_PATH_LEVEL_RESOURCE_INST) {
1613 			return -EINVAL;
1614 		}
1615 
1616 		ret = lwm2m_engine_allocate_resource_instance(r, &r_i, path->res_inst_id);
1617 		if (ret < 0) {
1618 			return ret;
1619 		}
1620 	}
1621 
1622 	/* Store resource instance pointer */
1623 	*res_inst = r_i;
1624 	return 0;
1625 }
1626 
lwm2m_create_res_inst(const struct lwm2m_obj_path * path)1627 int lwm2m_create_res_inst(const struct lwm2m_obj_path *path)
1628 {
1629 	int ret;
1630 	struct lwm2m_engine_res *res = NULL;
1631 	struct lwm2m_engine_res_inst *res_inst = NULL;
1632 
1633 	if (path->level < LWM2M_PATH_LEVEL_RESOURCE_INST) {
1634 		LOG_ERR("path must have 4 parts");
1635 		return -EINVAL;
1636 	}
1637 	k_mutex_lock(&registry_lock, K_FOREVER);
1638 	ret = path_to_objs(path, NULL, NULL, &res, &res_inst);
1639 	if (ret < 0) {
1640 		k_mutex_unlock(&registry_lock);
1641 		return ret;
1642 	}
1643 
1644 	if (!res) {
1645 		LOG_ERR("resource %u not found", path->res_id);
1646 		k_mutex_unlock(&registry_lock);
1647 		return -ENOENT;
1648 	}
1649 
1650 	if (res_inst && res_inst->res_inst_id != RES_INSTANCE_NOT_CREATED) {
1651 		LOG_ERR("res instance %u already exists", path->res_inst_id);
1652 		k_mutex_unlock(&registry_lock);
1653 		return -EINVAL;
1654 	}
1655 	k_mutex_unlock(&registry_lock);
1656 	return lwm2m_engine_allocate_resource_instance(res, &res_inst, path->res_inst_id);
1657 }
1658 
lwm2m_engine_create_res_inst(const char * pathstr)1659 int lwm2m_engine_create_res_inst(const char *pathstr)
1660 {
1661 	int ret;
1662 	struct lwm2m_obj_path path;
1663 
1664 	ret = lwm2m_string_to_path(pathstr, &path, '/');
1665 	if (ret < 0) {
1666 		return ret;
1667 	}
1668 
1669 	return lwm2m_create_res_inst(&path);
1670 }
1671 
lwm2m_delete_res_inst(const struct lwm2m_obj_path * path)1672 int lwm2m_delete_res_inst(const struct lwm2m_obj_path *path)
1673 {
1674 	int ret;
1675 	struct lwm2m_engine_res_inst *res_inst = NULL;
1676 
1677 	if (path->level < LWM2M_PATH_LEVEL_RESOURCE_INST) {
1678 		LOG_ERR("path must have 4 parts");
1679 		return -EINVAL;
1680 	}
1681 	k_mutex_lock(&registry_lock, K_FOREVER);
1682 	ret = path_to_objs(path, NULL, NULL, NULL, &res_inst);
1683 	if (ret < 0) {
1684 		k_mutex_unlock(&registry_lock);
1685 		return ret;
1686 	}
1687 
1688 	if (!res_inst) {
1689 		LOG_ERR("res instance %u not found", path->res_inst_id);
1690 		k_mutex_unlock(&registry_lock);
1691 		return -ENOENT;
1692 	}
1693 
1694 	res_inst->data_ptr = NULL;
1695 	res_inst->max_data_len = 0U;
1696 	res_inst->data_len = 0U;
1697 	res_inst->res_inst_id = RES_INSTANCE_NOT_CREATED;
1698 	k_mutex_unlock(&registry_lock);
1699 	return 0;
1700 }
1701 
lwm2m_engine_delete_res_inst(const char * pathstr)1702 int lwm2m_engine_delete_res_inst(const char *pathstr)
1703 {
1704 	int ret;
1705 	struct lwm2m_obj_path path;
1706 
1707 	ret = lwm2m_string_to_path(pathstr, &path, '/');
1708 	if (ret < 0) {
1709 		return ret;
1710 	}
1711 
1712 	return lwm2m_delete_res_inst(&path);
1713 }
1714 /* Register callbacks */
1715 
lwm2m_register_read_callback(const struct lwm2m_obj_path * path,lwm2m_engine_get_data_cb_t cb)1716 int lwm2m_register_read_callback(const struct lwm2m_obj_path *path, lwm2m_engine_get_data_cb_t cb)
1717 {
1718 	int ret;
1719 	struct lwm2m_engine_res *res = NULL;
1720 
1721 	ret = lwm2m_get_resource(path, &res);
1722 	if (ret < 0) {
1723 		return ret;
1724 	}
1725 
1726 	res->read_cb = cb;
1727 	return 0;
1728 }
1729 
lwm2m_engine_register_read_callback(const char * pathstr,lwm2m_engine_get_data_cb_t cb)1730 int lwm2m_engine_register_read_callback(const char *pathstr, lwm2m_engine_get_data_cb_t cb)
1731 {
1732 	int ret;
1733 	struct lwm2m_obj_path path;
1734 
1735 	ret = lwm2m_string_to_path(pathstr, &path, '/');
1736 	if (ret < 0) {
1737 		return ret;
1738 	}
1739 
1740 	return lwm2m_register_read_callback(&path, cb);
1741 }
1742 
lwm2m_register_pre_write_callback(const struct lwm2m_obj_path * path,lwm2m_engine_get_data_cb_t cb)1743 int lwm2m_register_pre_write_callback(const struct lwm2m_obj_path *path,
1744 				      lwm2m_engine_get_data_cb_t cb)
1745 {
1746 	int ret;
1747 	struct lwm2m_engine_res *res = NULL;
1748 
1749 	ret = lwm2m_get_resource(path, &res);
1750 	if (ret < 0) {
1751 		return ret;
1752 	}
1753 
1754 	res->pre_write_cb = cb;
1755 	return 0;
1756 }
1757 
lwm2m_engine_register_pre_write_callback(const char * pathstr,lwm2m_engine_get_data_cb_t cb)1758 int lwm2m_engine_register_pre_write_callback(const char *pathstr, lwm2m_engine_get_data_cb_t cb)
1759 {
1760 	int ret;
1761 	struct lwm2m_obj_path path;
1762 
1763 	ret = lwm2m_string_to_path(pathstr, &path, '/');
1764 	if (ret < 0) {
1765 		return ret;
1766 	}
1767 
1768 	return lwm2m_register_pre_write_callback(&path, cb);
1769 }
1770 
lwm2m_register_validate_callback(const struct lwm2m_obj_path * path,lwm2m_engine_set_data_cb_t cb)1771 int lwm2m_register_validate_callback(const struct lwm2m_obj_path *path,
1772 				     lwm2m_engine_set_data_cb_t cb)
1773 {
1774 #if CONFIG_LWM2M_ENGINE_VALIDATION_BUFFER_SIZE > 0
1775 	int ret;
1776 	struct lwm2m_engine_res *res = NULL;
1777 
1778 	ret = lwm2m_get_resource(path, &res);
1779 	if (ret < 0) {
1780 		return ret;
1781 	}
1782 
1783 	res->validate_cb = cb;
1784 	return 0;
1785 #else
1786 	ARG_UNUSED(path);
1787 	ARG_UNUSED(cb);
1788 
1789 	LOG_ERR("Validation disabled. Set "
1790 		"CONFIG_LWM2M_ENGINE_VALIDATION_BUFFER_SIZE > 0 to "
1791 		"enable validation support.");
1792 	return -ENOTSUP;
1793 #endif /* CONFIG_LWM2M_ENGINE_VALIDATION_BUFFER_SIZE > 0 */
1794 }
1795 
lwm2m_engine_register_validate_callback(const char * pathstr,lwm2m_engine_set_data_cb_t cb)1796 int lwm2m_engine_register_validate_callback(const char *pathstr, lwm2m_engine_set_data_cb_t cb)
1797 {
1798 #if CONFIG_LWM2M_ENGINE_VALIDATION_BUFFER_SIZE > 0
1799 	int ret;
1800 	struct lwm2m_obj_path path;
1801 
1802 	ret = lwm2m_string_to_path(pathstr, &path, '/');
1803 	if (ret < 0) {
1804 		return ret;
1805 	}
1806 
1807 	return lwm2m_register_validate_callback(&path, cb);
1808 #else
1809 	ARG_UNUSED(pathstr);
1810 	ARG_UNUSED(cb);
1811 
1812 	LOG_ERR("Validation disabled. Set "
1813 		"CONFIG_LWM2M_ENGINE_VALIDATION_BUFFER_SIZE > 0 to "
1814 		"enable validation support.");
1815 	return -ENOTSUP;
1816 #endif /* CONFIG_LWM2M_ENGINE_VALIDATION_BUFFER_SIZE > 0 */
1817 }
1818 
lwm2m_register_post_write_callback(const struct lwm2m_obj_path * path,lwm2m_engine_set_data_cb_t cb)1819 int lwm2m_register_post_write_callback(const struct lwm2m_obj_path *path,
1820 				       lwm2m_engine_set_data_cb_t cb)
1821 {
1822 	int ret;
1823 	struct lwm2m_engine_res *res = NULL;
1824 
1825 	ret = lwm2m_get_resource(path, &res);
1826 	if (ret < 0) {
1827 		return ret;
1828 	}
1829 
1830 	res->post_write_cb = cb;
1831 	return 0;
1832 }
1833 
lwm2m_engine_register_post_write_callback(const char * pathstr,lwm2m_engine_set_data_cb_t cb)1834 int lwm2m_engine_register_post_write_callback(const char *pathstr, lwm2m_engine_set_data_cb_t cb)
1835 {
1836 	int ret;
1837 	struct lwm2m_obj_path path;
1838 
1839 	ret = lwm2m_string_to_path(pathstr, &path, '/');
1840 	if (ret < 0) {
1841 		return ret;
1842 	}
1843 
1844 	return lwm2m_register_post_write_callback(&path, cb);
1845 }
1846 
lwm2m_register_exec_callback(const struct lwm2m_obj_path * path,lwm2m_engine_execute_cb_t cb)1847 int lwm2m_register_exec_callback(const struct lwm2m_obj_path *path, lwm2m_engine_execute_cb_t cb)
1848 {
1849 	int ret;
1850 	struct lwm2m_engine_res *res = NULL;
1851 
1852 	ret = lwm2m_get_resource(path, &res);
1853 	if (ret < 0) {
1854 		return ret;
1855 	}
1856 
1857 	res->execute_cb = cb;
1858 	return 0;
1859 }
1860 
lwm2m_engine_register_exec_callback(const char * pathstr,lwm2m_engine_execute_cb_t cb)1861 int lwm2m_engine_register_exec_callback(const char *pathstr, lwm2m_engine_execute_cb_t cb)
1862 {
1863 	int ret;
1864 	struct lwm2m_obj_path path;
1865 
1866 	ret = lwm2m_string_to_path(pathstr, &path, '/');
1867 	if (ret < 0) {
1868 		return ret;
1869 	}
1870 
1871 	return lwm2m_register_exec_callback(&path, cb);
1872 }
1873 
lwm2m_register_create_callback(uint16_t obj_id,lwm2m_engine_user_cb_t cb)1874 int lwm2m_register_create_callback(uint16_t obj_id, lwm2m_engine_user_cb_t cb)
1875 {
1876 	struct lwm2m_engine_obj *obj = NULL;
1877 
1878 	obj = get_engine_obj(obj_id);
1879 	if (!obj) {
1880 		LOG_ERR("unable to find obj: %u", obj_id);
1881 		return -ENOENT;
1882 	}
1883 
1884 	obj->user_create_cb = cb;
1885 	return 0;
1886 }
1887 
lwm2m_engine_register_create_callback(uint16_t obj_id,lwm2m_engine_user_cb_t cb)1888 int lwm2m_engine_register_create_callback(uint16_t obj_id, lwm2m_engine_user_cb_t cb)
1889 {
1890 	return lwm2m_register_create_callback(obj_id, cb);
1891 }
1892 
lwm2m_register_delete_callback(uint16_t obj_id,lwm2m_engine_user_cb_t cb)1893 int lwm2m_register_delete_callback(uint16_t obj_id, lwm2m_engine_user_cb_t cb)
1894 {
1895 	struct lwm2m_engine_obj *obj = NULL;
1896 
1897 	obj = get_engine_obj(obj_id);
1898 	if (!obj) {
1899 		LOG_ERR("unable to find obj: %u", obj_id);
1900 		return -ENOENT;
1901 	}
1902 
1903 	obj->user_delete_cb = cb;
1904 	return 0;
1905 }
1906 
lwm2m_engine_register_delete_callback(uint16_t obj_id,lwm2m_engine_user_cb_t cb)1907 int lwm2m_engine_register_delete_callback(uint16_t obj_id, lwm2m_engine_user_cb_t cb)
1908 {
1909 	return lwm2m_register_delete_callback(obj_id, cb);
1910 }
1911 /* Generic data handlers */
1912 
lwm2m_get_or_create_engine_obj(struct lwm2m_message * msg,struct lwm2m_engine_obj_inst ** obj_inst,uint8_t * created)1913 int lwm2m_get_or_create_engine_obj(struct lwm2m_message *msg,
1914 				   struct lwm2m_engine_obj_inst **obj_inst, uint8_t *created)
1915 {
1916 	int ret = 0;
1917 
1918 	if (created) {
1919 		*created = 0U;
1920 	}
1921 
1922 	*obj_inst = get_engine_obj_inst(msg->path.obj_id, msg->path.obj_inst_id);
1923 	if (!*obj_inst) {
1924 		ret = lwm2m_create_obj_inst(msg->path.obj_id, msg->path.obj_inst_id, obj_inst);
1925 		if (ret < 0) {
1926 			return ret;
1927 		}
1928 
1929 		/* set created flag to one */
1930 		if (created) {
1931 			*created = 1U;
1932 		}
1933 
1934 		if (!msg->ctx->bootstrap_mode) {
1935 			engine_trigger_update(true);
1936 		}
1937 	}
1938 
1939 	return ret;
1940 }
1941 
lwm2m_engine_get_res(const struct lwm2m_obj_path * path)1942 struct lwm2m_engine_res *lwm2m_engine_get_res(const struct lwm2m_obj_path *path)
1943 {
1944 	struct lwm2m_engine_res *res = NULL;
1945 	int ret;
1946 
1947 	if (path->level < LWM2M_PATH_LEVEL_RESOURCE) {
1948 		return NULL;
1949 	}
1950 
1951 	ret = path_to_objs(path, NULL, NULL, &res, NULL);
1952 	if (ret < 0) {
1953 		return NULL;
1954 	}
1955 
1956 	return res;
1957 }
1958 
lwm2m_engine_get_res_inst(const struct lwm2m_obj_path * path)1959 struct lwm2m_engine_res_inst *lwm2m_engine_get_res_inst(const struct lwm2m_obj_path *path)
1960 {
1961 	struct lwm2m_engine_res_inst *res_inst = NULL;
1962 	int ret;
1963 
1964 	if (path->level != LWM2M_PATH_LEVEL_RESOURCE_INST) {
1965 		return NULL;
1966 	}
1967 
1968 	ret = path_to_objs(path, NULL, NULL, NULL, &res_inst);
1969 	if (ret < 0) {
1970 		return NULL;
1971 	}
1972 
1973 	return res_inst;
1974 }
1975 
lwm2m_engine_shall_report_obj_version(const struct lwm2m_engine_obj * obj)1976 bool lwm2m_engine_shall_report_obj_version(const struct lwm2m_engine_obj *obj)
1977 {
1978 	if (obj->is_core) {
1979 		return obj->version_major != LWM2M_PROTOCOL_VERSION_MAJOR ||
1980 		       obj->version_minor != LWM2M_PROTOCOL_VERSION_MINOR;
1981 	}
1982 
1983 	return obj->version_major != 1 || obj->version_minor != 0;
1984 }
1985 
1986 #if defined(CONFIG_LWM2M_RESOURCE_DATA_CACHE_SUPPORT)
1987 static sys_slist_t lwm2m_timed_cache_list;
1988 static struct lwm2m_time_series_resource lwm2m_cache_entries[CONFIG_LWM2M_MAX_CACHED_RESOURCES];
1989 
1990 static struct lwm2m_time_series_resource *
lwm2m_cache_entry_allocate(const struct lwm2m_obj_path * path)1991 lwm2m_cache_entry_allocate(const struct lwm2m_obj_path *path)
1992 {
1993 	int i;
1994 	struct lwm2m_time_series_resource *entry;
1995 
1996 	entry = lwm2m_cache_entry_get_by_object(path);
1997 	if (entry) {
1998 		return entry;
1999 	}
2000 
2001 	for (i = 0; i < ARRAY_SIZE(lwm2m_cache_entries); i++) {
2002 		if (lwm2m_cache_entries[i].path.level == 0) {
2003 			lwm2m_cache_entries[i].path = *path;
2004 			sys_slist_append(&lwm2m_timed_cache_list, &lwm2m_cache_entries[i].node);
2005 			return &lwm2m_cache_entries[i];
2006 		}
2007 	}
2008 
2009 	return NULL;
2010 }
2011 
lwm2m_engine_cache_write(const struct lwm2m_engine_obj_field * obj_field,const struct lwm2m_obj_path * path,const void * value,uint16_t len)2012 static void lwm2m_engine_cache_write(const struct lwm2m_engine_obj_field *obj_field,
2013 				     const struct lwm2m_obj_path *path, const void *value,
2014 				     uint16_t len)
2015 {
2016 	struct lwm2m_time_series_resource *cache_entry;
2017 	struct lwm2m_time_series_elem elements;
2018 
2019 	cache_entry = lwm2m_cache_entry_get_by_object(path);
2020 	if (!cache_entry) {
2021 		return;
2022 	}
2023 
2024 	elements.t = time(NULL);
2025 
2026 	if (elements.t  <= 0) {
2027 		LOG_WRN("Time() not available");
2028 		return;
2029 	}
2030 
2031 	switch (obj_field->data_type) {
2032 	case LWM2M_RES_TYPE_U32:
2033 		elements.u32 = *(uint32_t *)value;
2034 		break;
2035 
2036 	case LWM2M_RES_TYPE_U16:
2037 		elements.u16 = *(uint16_t *)value;
2038 		break;
2039 
2040 	case LWM2M_RES_TYPE_U8:
2041 		elements.u8 = *(uint8_t *)value;
2042 		break;
2043 
2044 	case LWM2M_RES_TYPE_S64:
2045 		elements.i64 = *(int64_t *)value;
2046 		break;
2047 
2048 	case LWM2M_RES_TYPE_TIME:
2049 		if (len == sizeof(time_t)) {
2050 			elements.time = *(time_t *)value;
2051 		} else if (len == sizeof(uint32_t)) {
2052 			elements.time = (time_t) *((uint32_t *)value);
2053 		} else {
2054 			LOG_ERR("Not supporting size %d bytes for time", len);
2055 			return;
2056 		}
2057 		break;
2058 
2059 	case LWM2M_RES_TYPE_S32:
2060 		elements.i32 = *(int32_t *)value;
2061 		break;
2062 
2063 	case LWM2M_RES_TYPE_S16:
2064 		elements.i16 = *(int16_t *)value;
2065 		break;
2066 
2067 	case LWM2M_RES_TYPE_S8:
2068 		elements.i8 = *(int8_t *)value;
2069 		break;
2070 
2071 	case LWM2M_RES_TYPE_BOOL:
2072 		elements.b = *(bool *)value;
2073 		break;
2074 
2075 	default:
2076 		elements.f = *(double *)value;
2077 		break;
2078 	}
2079 
2080 	if (!lwm2m_cache_write(cache_entry, &elements)) {
2081 		LOG_WRN("Data cache full");
2082 	}
2083 }
2084 #endif /* CONFIG_LWM2M_RESOURCE_DATA_CACHE_SUPPORT */
2085 
2086 struct lwm2m_time_series_resource *
lwm2m_cache_entry_get_by_object(const struct lwm2m_obj_path * obj_path)2087 lwm2m_cache_entry_get_by_object(const struct lwm2m_obj_path *obj_path)
2088 {
2089 #if defined(CONFIG_LWM2M_RESOURCE_DATA_CACHE_SUPPORT)
2090 	struct lwm2m_time_series_resource *entry;
2091 
2092 	if (obj_path->level < LWM2M_PATH_LEVEL_RESOURCE) {
2093 		LOG_ERR("Path level wrong for cache %u", obj_path->level);
2094 		return NULL;
2095 	}
2096 
2097 	if (sys_slist_is_empty(&lwm2m_timed_cache_list)) {
2098 		return NULL;
2099 	}
2100 
2101 	SYS_SLIST_FOR_EACH_CONTAINER(&lwm2m_timed_cache_list, entry, node) {
2102 		if (lwm2m_obj_path_equal(&entry->path, obj_path)) {
2103 			return entry;
2104 		}
2105 	}
2106 #endif /* CONFIG_LWM2M_RESOURCE_DATA_CACHE_SUPPORT */
2107 	return NULL;
2108 
2109 }
2110 
lwm2m_enable_cache(const struct lwm2m_obj_path * path,struct lwm2m_time_series_elem * data_cache,size_t cache_len)2111 int lwm2m_enable_cache(const struct lwm2m_obj_path *path, struct lwm2m_time_series_elem *data_cache,
2112 		       size_t cache_len)
2113 {
2114 #if defined(CONFIG_LWM2M_RESOURCE_DATA_CACHE_SUPPORT)
2115 	struct lwm2m_engine_obj_inst *obj_inst;
2116 	struct lwm2m_engine_obj_field *obj_field;
2117 	struct lwm2m_engine_res_inst *res_inst = NULL;
2118 	struct lwm2m_time_series_resource *cache_entry;
2119 	int ret = 0;
2120 	size_t cache_entry_size = sizeof(struct lwm2m_time_series_elem);
2121 
2122 	/* look up resource obj */
2123 	ret = path_to_objs(path, &obj_inst, &obj_field, NULL, &res_inst);
2124 	if (ret < 0) {
2125 		return ret;
2126 	}
2127 
2128 	if (!res_inst) {
2129 		LOG_ERR("res instance %d not found", path->res_inst_id);
2130 		return -ENOENT;
2131 	}
2132 
2133 	switch (obj_field->data_type) {
2134 	case LWM2M_RES_TYPE_U32:
2135 	case LWM2M_RES_TYPE_TIME:
2136 	case LWM2M_RES_TYPE_U16:
2137 	case LWM2M_RES_TYPE_U8:
2138 	case LWM2M_RES_TYPE_S64:
2139 	case LWM2M_RES_TYPE_S32:
2140 	case LWM2M_RES_TYPE_S16:
2141 	case LWM2M_RES_TYPE_S8:
2142 	case LWM2M_RES_TYPE_BOOL:
2143 	case LWM2M_RES_TYPE_FLOAT:
2144 		/* Support only fixed width resource types */
2145 		cache_entry = lwm2m_cache_entry_allocate(path);
2146 		break;
2147 	default:
2148 		cache_entry = NULL;
2149 		break;
2150 	}
2151 
2152 	if (!cache_entry) {
2153 		return -ENODATA;
2154 	}
2155 
2156 	ring_buf_init(&cache_entry->rb, cache_entry_size * cache_len, (uint8_t *)data_cache);
2157 
2158 	return 0;
2159 #else
2160 	LOG_ERR("LwM2M resource cache is only supported for "
2161 		"CONFIG_LWM2M_RESOURCE_DATA_CACHE_SUPPORT");
2162 	return -ENOTSUP;
2163 #endif /* CONFIG_LWM2M_RESOURCE_DATA_CACHE_SUPPORT */
2164 }
2165 
lwm2m_engine_enable_cache(const char * resource_path,struct lwm2m_time_series_elem * data_cache,size_t cache_len)2166 int lwm2m_engine_enable_cache(const char *resource_path, struct lwm2m_time_series_elem *data_cache,
2167 			    size_t cache_len)
2168 {
2169 #if defined(CONFIG_LWM2M_RESOURCE_DATA_CACHE_SUPPORT)
2170 	struct lwm2m_obj_path path;
2171 	int ret;
2172 
2173 	/* translate path -> path_obj */
2174 	ret = lwm2m_string_to_path(resource_path, &path, '/');
2175 	if (ret < 0) {
2176 		return ret;
2177 	}
2178 
2179 	if (path.level < LWM2M_PATH_LEVEL_RESOURCE) {
2180 		LOG_ERR("path must have at least 3 parts");
2181 		return -EINVAL;
2182 	}
2183 
2184 	return lwm2m_enable_cache(&path, data_cache, cache_len);
2185 #else
2186 	LOG_ERR("LwM2M resource cache is only supported for "
2187 		"CONFIG_LWM2M_RESOURCE_DATA_CACHE_SUPPORT");
2188 	return -ENOTSUP;
2189 #endif /* CONFIG_LWM2M_RESOURCE_DATA_CACHE_SUPPORT */
2190 }
2191 
lwm2m_engine_data_cache_init(void)2192 int lwm2m_engine_data_cache_init(void)
2193 {
2194 #if defined(CONFIG_LWM2M_RESOURCE_DATA_CACHE_SUPPORT)
2195 	int i;
2196 
2197 	sys_slist_init(&lwm2m_timed_cache_list);
2198 
2199 	for (i = 0; i < ARRAY_SIZE(lwm2m_cache_entries); i++) {
2200 		lwm2m_cache_entries[i].path.level = LWM2M_PATH_LEVEL_NONE;
2201 	}
2202 #endif
2203 	return 0;
2204 }
2205 
lwm2m_cache_write(struct lwm2m_time_series_resource * cache_entry,struct lwm2m_time_series_elem * buf)2206 bool lwm2m_cache_write(struct lwm2m_time_series_resource *cache_entry,
2207 		       struct lwm2m_time_series_elem *buf)
2208 {
2209 #if defined(CONFIG_LWM2M_RESOURCE_DATA_CACHE_SUPPORT)
2210 	uint32_t length;
2211 	uint8_t *buf_ptr;
2212 	uint32_t element_size = sizeof(struct lwm2m_time_series_elem);
2213 
2214 	if (ring_buf_space_get(&cache_entry->rb) < element_size) {
2215 		/* No space  */
2216 		if (IS_ENABLED(CONFIG_LWM2M_CACHE_DROP_LATEST)) {
2217 			return false;
2218 		}
2219 		/* Free entry */
2220 		length = ring_buf_get_claim(&cache_entry->rb, &buf_ptr, element_size);
2221 		ring_buf_get_finish(&cache_entry->rb, length);
2222 	}
2223 
2224 	length = ring_buf_put_claim(&cache_entry->rb, &buf_ptr, element_size);
2225 
2226 	if (length != element_size) {
2227 		ring_buf_put_finish(&cache_entry->rb, 0);
2228 		LOG_ERR("Allocation failed %u", length);
2229 		return false;
2230 	}
2231 
2232 	ring_buf_put_finish(&cache_entry->rb, length);
2233 	/* Store data */
2234 	memcpy(buf_ptr, buf, element_size);
2235 	return true;
2236 #else
2237 	return NULL;
2238 #endif
2239 }
2240 
lwm2m_cache_read(struct lwm2m_time_series_resource * cache_entry,struct lwm2m_time_series_elem * buf)2241 bool lwm2m_cache_read(struct lwm2m_time_series_resource *cache_entry,
2242 		      struct lwm2m_time_series_elem *buf)
2243 {
2244 #if defined(CONFIG_LWM2M_RESOURCE_DATA_CACHE_SUPPORT)
2245 	uint32_t length;
2246 	uint8_t *buf_ptr;
2247 	uint32_t element_size = sizeof(struct lwm2m_time_series_elem);
2248 
2249 	if (ring_buf_is_empty(&cache_entry->rb)) {
2250 		return false;
2251 	}
2252 
2253 	length = ring_buf_get_claim(&cache_entry->rb, &buf_ptr, element_size);
2254 
2255 	if (length != element_size) {
2256 		LOG_ERR("Cache read fail %u", length);
2257 		ring_buf_get_finish(&cache_entry->rb, 0);
2258 		return false;
2259 	}
2260 
2261 	/* Read Data */
2262 	memcpy(buf, buf_ptr, element_size);
2263 	ring_buf_get_finish(&cache_entry->rb, length);
2264 	return true;
2265 
2266 #else
2267 	return NULL;
2268 #endif
2269 }
2270 
lwm2m_cache_size(const struct lwm2m_time_series_resource * cache_entry)2271 size_t lwm2m_cache_size(const struct lwm2m_time_series_resource *cache_entry)
2272 {
2273 #if defined(CONFIG_LWM2M_RESOURCE_DATA_CACHE_SUPPORT)
2274 	uint32_t bytes_available;
2275 
2276 	/* ring_buf_is_empty() takes non-const pointer but still does not modify */
2277 	if (ring_buf_is_empty((struct ring_buf *) &cache_entry->rb)) {
2278 		return 0;
2279 	}
2280 
2281 	/* ring_buf_size_get() takes non-const pointer but still does not modify */
2282 	bytes_available = ring_buf_size_get((struct ring_buf *) &cache_entry->rb);
2283 
2284 	return (bytes_available / sizeof(struct lwm2m_time_series_elem));
2285 #else
2286 	return 0;
2287 #endif
2288 }
2289