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 /* User data setter functions */
440 
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)441 int lwm2m_set_res_buf(const struct lwm2m_obj_path *path, void *buffer_ptr, uint16_t buffer_len,
442 		      uint16_t data_len, uint8_t data_flags)
443 {
444 	int ret;
445 	struct lwm2m_engine_res_inst *res_inst = NULL;
446 
447 	if (path->level < LWM2M_PATH_LEVEL_RESOURCE) {
448 		LOG_ERR("path must have at least 3 parts");
449 		return -EINVAL;
450 	}
451 
452 	k_mutex_lock(&registry_lock, K_FOREVER);
453 	/* look up resource obj */
454 	ret = path_to_objs(path, NULL, NULL, NULL, &res_inst);
455 	if (ret < 0) {
456 		k_mutex_unlock(&registry_lock);
457 		return ret;
458 	}
459 
460 	if (!res_inst) {
461 		LOG_ERR("res instance %d not found", path->res_inst_id);
462 		k_mutex_unlock(&registry_lock);
463 		return -ENOENT;
464 	}
465 
466 	/* assign data elements */
467 	res_inst->data_ptr = buffer_ptr;
468 	res_inst->data_len = data_len;
469 	res_inst->max_data_len = buffer_len;
470 	res_inst->data_flags = data_flags;
471 
472 	k_mutex_unlock(&registry_lock);
473 	return ret;
474 }
475 
lwm2m_engine_set_res_buf(const char * pathstr,void * buffer_ptr,uint16_t buffer_len,uint16_t data_len,uint8_t data_flags)476 int lwm2m_engine_set_res_buf(const char *pathstr, void *buffer_ptr, uint16_t buffer_len,
477 			     uint16_t data_len, uint8_t data_flags)
478 {
479 	struct lwm2m_obj_path path;
480 	int ret = 0;
481 
482 	/* translate path -> path_obj */
483 	ret = lwm2m_string_to_path(pathstr, &path, '/');
484 	if (ret < 0) {
485 		return ret;
486 	}
487 
488 	return lwm2m_set_res_buf(&path, buffer_ptr, buffer_len, data_len, data_flags);
489 }
490 
lwm2m_engine_set_res_data(const char * pathstr,void * data_ptr,uint16_t data_len,uint8_t data_flags)491 int lwm2m_engine_set_res_data(const char *pathstr, void *data_ptr, uint16_t data_len,
492 			      uint8_t data_flags)
493 {
494 	struct lwm2m_obj_path path;
495 	int ret = 0;
496 
497 	/* translate path -> path_obj */
498 	ret = lwm2m_string_to_path(pathstr, &path, '/');
499 	if (ret < 0) {
500 		return ret;
501 	}
502 
503 	return lwm2m_set_res_buf(&path, data_ptr, data_len, data_len, data_flags);
504 }
505 
lwm2m_validate_time_resource_lenghts(uint16_t resource_length,uint16_t buf_length)506 static bool lwm2m_validate_time_resource_lenghts(uint16_t resource_length, uint16_t buf_length)
507 {
508 	if (resource_length != sizeof(time_t) && resource_length != sizeof(uint32_t)) {
509 		return false;
510 	}
511 
512 	if (buf_length != sizeof(time_t) && buf_length != sizeof(uint32_t)) {
513 		return false;
514 	}
515 
516 	return true;
517 }
518 
lwm2m_check_buf_sizes(uint8_t data_type,uint16_t resource_length,uint16_t buf_length)519 static int lwm2m_check_buf_sizes(uint8_t data_type, uint16_t resource_length, uint16_t buf_length)
520 {
521 	switch (data_type) {
522 	case LWM2M_RES_TYPE_OPAQUE:
523 	case LWM2M_RES_TYPE_STRING:
524 		if (resource_length > buf_length) {
525 			return -ENOMEM;
526 		}
527 		break;
528 	case LWM2M_RES_TYPE_U32:
529 	case LWM2M_RES_TYPE_U8:
530 	case LWM2M_RES_TYPE_S64:
531 	case LWM2M_RES_TYPE_S32:
532 	case LWM2M_RES_TYPE_S16:
533 	case LWM2M_RES_TYPE_S8:
534 	case LWM2M_RES_TYPE_BOOL:
535 	case LWM2M_RES_TYPE_FLOAT:
536 	case LWM2M_RES_TYPE_OBJLNK:
537 		if (resource_length != buf_length) {
538 			return -EINVAL;
539 		}
540 		break;
541 	default:
542 		return 0;
543 	}
544 	return 0;
545 }
546 
lwm2m_engine_set(const struct lwm2m_obj_path * path,const void * value,uint16_t len)547 static int lwm2m_engine_set(const struct lwm2m_obj_path *path, const void *value, uint16_t len)
548 {
549 	struct lwm2m_engine_obj_inst *obj_inst;
550 	struct lwm2m_engine_obj_field *obj_field;
551 	struct lwm2m_engine_res *res = NULL;
552 	struct lwm2m_engine_res_inst *res_inst = NULL;
553 	void *data_ptr = NULL;
554 	size_t max_data_len = 0;
555 	int ret = 0;
556 	bool changed = false;
557 
558 	if (path->level < LWM2M_PATH_LEVEL_RESOURCE) {
559 		LOG_ERR("path must have at least 3 parts");
560 		return -EINVAL;
561 	}
562 
563 	LOG_DBG("path:%u/%u/%u, buf:%p, len:%d", path->obj_id, path->obj_inst_id,
564 		path->res_id, value, len);
565 
566 	k_mutex_lock(&registry_lock, K_FOREVER);
567 	/* look up resource obj */
568 	ret = path_to_objs(path, &obj_inst, &obj_field, &res, &res_inst);
569 	if (ret < 0) {
570 		k_mutex_unlock(&registry_lock);
571 		return ret;
572 	}
573 
574 	if (!res_inst) {
575 		LOG_ERR("res instance %d not found", path->res_inst_id);
576 		k_mutex_unlock(&registry_lock);
577 		return -ENOENT;
578 	}
579 
580 	if (LWM2M_HAS_RES_FLAG(res_inst, LWM2M_RES_DATA_FLAG_RO)) {
581 		LOG_ERR("res instance data pointer is read-only "
582 			"[%u/%u/%u/%u:lvl%u]", path->obj_id, path->obj_inst_id, path->res_id,
583 			path->res_inst_id, path->level);
584 		k_mutex_unlock(&registry_lock);
585 		return -EACCES;
586 	}
587 
588 	/* setup initial data elements */
589 	data_ptr = res_inst->data_ptr;
590 	max_data_len = res_inst->max_data_len;
591 
592 	/* allow user to override data elements via callback */
593 	if (res->pre_write_cb) {
594 		data_ptr = res->pre_write_cb(obj_inst->obj_inst_id, res->res_id,
595 					     res_inst->res_inst_id, &max_data_len);
596 	}
597 
598 	if (!data_ptr) {
599 		LOG_ERR("res instance data pointer is NULL [%u/%u/%u/%u:%u]", path->obj_id,
600 			path->obj_inst_id, path->res_id, path->res_inst_id, path->level);
601 		k_mutex_unlock(&registry_lock);
602 		return -EINVAL;
603 	}
604 
605 	ret = lwm2m_check_buf_sizes(obj_field->data_type, len, max_data_len);
606 	if (ret) {
607 		LOG_ERR("Incorrect buffer length %u for res data length %zu", len,
608 			max_data_len);
609 		k_mutex_unlock(&registry_lock);
610 		return ret;
611 	}
612 
613 	if (memcmp(data_ptr, value, len) != 0) {
614 		changed = true;
615 	}
616 
617 #if CONFIG_LWM2M_ENGINE_VALIDATION_BUFFER_SIZE > 0
618 	if (res->validate_cb) {
619 		ret = res->validate_cb(obj_inst->obj_inst_id, res->res_id, res_inst->res_inst_id,
620 				       (uint8_t *)value, len, false, 0);
621 		if (ret < 0) {
622 			k_mutex_unlock(&registry_lock);
623 			return -EINVAL;
624 		}
625 	}
626 #endif /* CONFIG_LWM2M_ENGINE_VALIDATION_BUFFER_SIZE > 0 */
627 
628 	switch (obj_field->data_type) {
629 
630 	case LWM2M_RES_TYPE_OPAQUE:
631 		memcpy((uint8_t *)data_ptr, value, len);
632 		break;
633 
634 	case LWM2M_RES_TYPE_STRING:
635 		/* check length (note: we add 1 to string length for NULL pad) */
636 		if (len > max_data_len - 1) {
637 			LOG_ERR("String length %u is too long for res instance %d data", len,
638 				path->res_id);
639 			k_mutex_unlock(&registry_lock);
640 			return -ENOMEM;
641 		}
642 		memcpy((uint8_t *)data_ptr, value, len);
643 		((uint8_t *)data_ptr)[len] = '\0';
644 		break;
645 
646 	case LWM2M_RES_TYPE_U32:
647 		*((uint32_t *)data_ptr) = *(uint32_t *)value;
648 		break;
649 
650 	case LWM2M_RES_TYPE_U16:
651 		*((uint16_t *)data_ptr) = *(uint16_t *)value;
652 		break;
653 
654 	case LWM2M_RES_TYPE_U8:
655 		*((uint8_t *)data_ptr) = *(uint8_t *)value;
656 		break;
657 
658 	case LWM2M_RES_TYPE_TIME:
659 		if (!lwm2m_validate_time_resource_lenghts(max_data_len, len)) {
660 			LOG_ERR("Time Set: buffer length %u  max data len %zu not supported", len,
661 				max_data_len);
662 			return -EINVAL;
663 		}
664 
665 		if (max_data_len == sizeof(time_t)) {
666 			if (len == sizeof(time_t)) {
667 				*((time_t *)data_ptr) = *(time_t *)value;
668 			} else {
669 				*((time_t *)data_ptr) = (time_t) *((uint32_t *)value);
670 			}
671 		} else {
672 			LOG_WRN("Converting time to 32bit may cause integer overflow on resource "
673 				"[%u/%u/%u/%u:%u]", path->obj_id, path->obj_inst_id, path->res_id,
674 				path->res_inst_id, path->level);
675 			if (len == sizeof(uint32_t)) {
676 				*((uint32_t *)data_ptr) = *(uint32_t *)value;
677 			} else {
678 				*((uint32_t *)data_ptr) = (uint32_t) *((time_t *)value);
679 			}
680 		}
681 
682 		break;
683 
684 	case LWM2M_RES_TYPE_S64:
685 		*((int64_t *)data_ptr) = *(int64_t *)value;
686 		break;
687 
688 	case LWM2M_RES_TYPE_S32:
689 		*((int32_t *)data_ptr) = *(int32_t *)value;
690 		break;
691 
692 	case LWM2M_RES_TYPE_S16:
693 		*((int16_t *)data_ptr) = *(int16_t *)value;
694 		break;
695 
696 	case LWM2M_RES_TYPE_S8:
697 		*((int8_t *)data_ptr) = *(int8_t *)value;
698 		break;
699 
700 	case LWM2M_RES_TYPE_BOOL:
701 		*((bool *)data_ptr) = *(bool *)value;
702 		break;
703 
704 	case LWM2M_RES_TYPE_FLOAT:
705 		*(double *)data_ptr = *(double *)value;
706 		break;
707 
708 	case LWM2M_RES_TYPE_OBJLNK:
709 		*((struct lwm2m_objlnk *)data_ptr) = *(struct lwm2m_objlnk *)value;
710 		break;
711 
712 	default:
713 		LOG_ERR("unknown obj data_type %d", obj_field->data_type);
714 		k_mutex_unlock(&registry_lock);
715 		return -EINVAL;
716 	}
717 
718 	res_inst->data_len = len;
719 
720 	/* Cache Data Write */
721 #if defined(CONFIG_LWM2M_RESOURCE_DATA_CACHE_SUPPORT)
722 	lwm2m_engine_cache_write(obj_field, path, value, len);
723 #endif
724 
725 	if (res->post_write_cb) {
726 		ret = res->post_write_cb(obj_inst->obj_inst_id, res->res_id, res_inst->res_inst_id,
727 					 data_ptr, len, false, 0);
728 	}
729 
730 	if (changed && LWM2M_HAS_PERM(obj_field, LWM2M_PERM_R)) {
731 		lwm2m_notify_observer_path(path);
732 	}
733 	k_mutex_unlock(&registry_lock);
734 	return ret;
735 }
736 
lwm2m_set_opaque(const struct lwm2m_obj_path * path,const char * data_ptr,uint16_t data_len)737 int lwm2m_set_opaque(const struct lwm2m_obj_path *path, const char *data_ptr, uint16_t data_len)
738 {
739 	return lwm2m_engine_set(path, data_ptr, data_len);
740 }
741 
lwm2m_engine_set_opaque(const char * pathstr,const char * data_ptr,uint16_t data_len)742 int lwm2m_engine_set_opaque(const char *pathstr, const char *data_ptr, uint16_t data_len)
743 {
744 	struct lwm2m_obj_path path;
745 	int ret = 0;
746 
747 	ret = lwm2m_string_to_path(pathstr, &path, '/');
748 	if (ret < 0) {
749 		return ret;
750 	}
751 	return lwm2m_set_opaque(&path, data_ptr, data_len);
752 }
753 
lwm2m_set_string(const struct lwm2m_obj_path * path,const char * data_ptr)754 int lwm2m_set_string(const struct lwm2m_obj_path *path, const char *data_ptr)
755 {
756 	return lwm2m_engine_set(path, data_ptr, strlen(data_ptr));
757 }
758 
lwm2m_engine_set_string(const char * pathstr,const char * data_ptr)759 int lwm2m_engine_set_string(const char *pathstr, const char *data_ptr)
760 {
761 	struct lwm2m_obj_path path;
762 	int ret = 0;
763 
764 	ret = lwm2m_string_to_path(pathstr, &path, '/');
765 	if (ret < 0) {
766 		return ret;
767 	}
768 	return lwm2m_set_string(&path, data_ptr);
769 }
770 
lwm2m_set_u8(const struct lwm2m_obj_path * path,uint8_t value)771 int lwm2m_set_u8(const struct lwm2m_obj_path *path, uint8_t value)
772 {
773 	return lwm2m_engine_set(path, &value, 1);
774 }
775 
lwm2m_engine_set_u8(const char * pathstr,uint8_t value)776 int lwm2m_engine_set_u8(const char *pathstr, uint8_t value)
777 {
778 	struct lwm2m_obj_path path;
779 	int ret = 0;
780 
781 	ret = lwm2m_string_to_path(pathstr, &path, '/');
782 	if (ret < 0) {
783 		return ret;
784 	}
785 	return lwm2m_set_u8(&path, value);
786 }
787 
lwm2m_set_u16(const struct lwm2m_obj_path * path,uint16_t value)788 int lwm2m_set_u16(const struct lwm2m_obj_path *path, uint16_t value)
789 {
790 	return lwm2m_engine_set(path, &value, 2);
791 }
792 
lwm2m_engine_set_u16(const char * pathstr,uint16_t value)793 int lwm2m_engine_set_u16(const char *pathstr, uint16_t value)
794 {
795 	struct lwm2m_obj_path path;
796 	int ret = 0;
797 
798 	ret = lwm2m_string_to_path(pathstr, &path, '/');
799 	if (ret < 0) {
800 		return ret;
801 	}
802 	return lwm2m_set_u16(&path, value);
803 }
804 
lwm2m_set_u32(const struct lwm2m_obj_path * path,uint32_t value)805 int lwm2m_set_u32(const struct lwm2m_obj_path *path, uint32_t value)
806 {
807 	return lwm2m_engine_set(path, &value, 4);
808 }
809 
lwm2m_engine_set_u32(const char * pathstr,uint32_t value)810 int lwm2m_engine_set_u32(const char *pathstr, uint32_t value)
811 {
812 	struct lwm2m_obj_path path;
813 	int ret = 0;
814 
815 	ret = lwm2m_string_to_path(pathstr, &path, '/');
816 	if (ret < 0) {
817 		return ret;
818 	}
819 	return lwm2m_set_u32(&path, value);
820 }
821 
lwm2m_set_u64(const struct lwm2m_obj_path * path,uint64_t value)822 int lwm2m_set_u64(const struct lwm2m_obj_path *path, uint64_t value)
823 {
824 	return lwm2m_engine_set(path, &value, 8);
825 }
826 
lwm2m_engine_set_u64(const char * pathstr,uint64_t value)827 int lwm2m_engine_set_u64(const char *pathstr, uint64_t value)
828 {
829 	struct lwm2m_obj_path path;
830 	int ret = 0;
831 
832 	ret = lwm2m_string_to_path(pathstr, &path, '/');
833 	if (ret < 0) {
834 		return ret;
835 	}
836 	return lwm2m_set_u64(&path, value);
837 }
838 
lwm2m_set_s8(const struct lwm2m_obj_path * path,int8_t value)839 int lwm2m_set_s8(const struct lwm2m_obj_path *path, int8_t value)
840 {
841 	return lwm2m_engine_set(path, &value, 1);
842 }
843 
lwm2m_engine_set_s8(const char * pathstr,int8_t value)844 int lwm2m_engine_set_s8(const char *pathstr, int8_t value)
845 {
846 	struct lwm2m_obj_path path;
847 	int ret = 0;
848 
849 	ret = lwm2m_string_to_path(pathstr, &path, '/');
850 	if (ret < 0) {
851 		return ret;
852 	}
853 	return lwm2m_set_s8(&path, value);
854 }
855 
lwm2m_set_s16(const struct lwm2m_obj_path * path,int16_t value)856 int lwm2m_set_s16(const struct lwm2m_obj_path *path, int16_t value)
857 {
858 	return lwm2m_engine_set(path, &value, 2);
859 
860 }
861 
lwm2m_engine_set_s16(const char * pathstr,int16_t value)862 int lwm2m_engine_set_s16(const char *pathstr, int16_t value)
863 {
864 	struct lwm2m_obj_path path;
865 	int ret = 0;
866 
867 	ret = lwm2m_string_to_path(pathstr, &path, '/');
868 	if (ret < 0) {
869 		return ret;
870 	}
871 	return lwm2m_set_s16(&path, value);
872 }
873 
lwm2m_set_s32(const struct lwm2m_obj_path * path,int32_t value)874 int lwm2m_set_s32(const struct lwm2m_obj_path *path, int32_t value)
875 {
876 	return lwm2m_engine_set(path, &value, 4);
877 }
878 
lwm2m_engine_set_s32(const char * pathstr,int32_t value)879 int lwm2m_engine_set_s32(const char *pathstr, int32_t value)
880 {
881 	struct lwm2m_obj_path path;
882 	int ret = 0;
883 
884 	ret = lwm2m_string_to_path(pathstr, &path, '/');
885 	if (ret < 0) {
886 		return ret;
887 	}
888 	return lwm2m_set_s32(&path, value);
889 }
890 
lwm2m_set_s64(const struct lwm2m_obj_path * path,int64_t value)891 int lwm2m_set_s64(const struct lwm2m_obj_path *path, int64_t value)
892 {
893 	return lwm2m_engine_set(path, &value, 8);
894 }
895 
lwm2m_engine_set_s64(const char * pathstr,int64_t value)896 int lwm2m_engine_set_s64(const char *pathstr, int64_t value)
897 {
898 	struct lwm2m_obj_path path;
899 	int ret = 0;
900 
901 	ret = lwm2m_string_to_path(pathstr, &path, '/');
902 	if (ret < 0) {
903 		return ret;
904 	}
905 	return lwm2m_set_s64(&path, value);
906 }
907 
lwm2m_set_bool(const struct lwm2m_obj_path * path,bool value)908 int lwm2m_set_bool(const struct lwm2m_obj_path *path, bool value)
909 {
910 	uint8_t temp = (value != 0 ? 1 : 0);
911 
912 	return lwm2m_engine_set(path, &temp, 1);
913 }
914 
lwm2m_engine_set_bool(const char * pathstr,bool value)915 int lwm2m_engine_set_bool(const char *pathstr, bool value)
916 {
917 	struct lwm2m_obj_path path;
918 	int ret = 0;
919 
920 	ret = lwm2m_string_to_path(pathstr, &path, '/');
921 	if (ret < 0) {
922 		return ret;
923 	}
924 	return lwm2m_set_bool(&path, value);
925 }
926 
lwm2m_set_f64(const struct lwm2m_obj_path * path,const double value)927 int lwm2m_set_f64(const struct lwm2m_obj_path *path, const double value)
928 {
929 	return lwm2m_engine_set(path, &value, sizeof(double));
930 }
931 
lwm2m_engine_set_float(const char * pathstr,const double * value)932 int lwm2m_engine_set_float(const char *pathstr, const double *value)
933 {
934 	struct lwm2m_obj_path path;
935 	int ret = 0;
936 
937 	ret = lwm2m_string_to_path(pathstr, &path, '/');
938 	if (ret < 0) {
939 		return ret;
940 	}
941 	return lwm2m_set_f64(&path, *value);
942 }
943 
lwm2m_set_objlnk(const struct lwm2m_obj_path * path,const struct lwm2m_objlnk * value)944 int lwm2m_set_objlnk(const struct lwm2m_obj_path *path, const struct lwm2m_objlnk *value)
945 {
946 	return lwm2m_engine_set(path, value, sizeof(struct lwm2m_objlnk));
947 }
948 
lwm2m_engine_set_objlnk(const char * pathstr,const struct lwm2m_objlnk * value)949 int lwm2m_engine_set_objlnk(const char *pathstr, const struct lwm2m_objlnk *value)
950 {
951 	struct lwm2m_obj_path path;
952 	int ret = 0;
953 
954 	ret = lwm2m_string_to_path(pathstr, &path, '/');
955 	if (ret < 0) {
956 		return ret;
957 	}
958 	return lwm2m_set_objlnk(&path, value);
959 }
960 
lwm2m_set_time(const struct lwm2m_obj_path * path,time_t value)961 int lwm2m_set_time(const struct lwm2m_obj_path *path, time_t value)
962 {
963 	return lwm2m_engine_set(path, &value, sizeof(time_t));
964 }
965 
lwm2m_engine_set_time(const char * pathstr,time_t value)966 int lwm2m_engine_set_time(const char *pathstr, time_t value)
967 {
968 	struct lwm2m_obj_path path;
969 	int ret = 0;
970 
971 	ret = lwm2m_string_to_path(pathstr, &path, '/');
972 	if (ret < 0) {
973 		return ret;
974 	}
975 	return lwm2m_set_time(&path, value);
976 }
977 
lwm2m_set_res_data_len(const struct lwm2m_obj_path * path,uint16_t data_len)978 int lwm2m_set_res_data_len(const struct lwm2m_obj_path *path, uint16_t data_len)
979 {
980 	int ret;
981 	void *buffer_ptr;
982 	uint16_t buffer_len;
983 	uint16_t old_len;
984 	uint8_t data_flags;
985 
986 	ret = lwm2m_get_res_buf(path, &buffer_ptr, &buffer_len, &old_len, &data_flags);
987 	if (ret) {
988 		return ret;
989 	}
990 	return lwm2m_set_res_buf(path, buffer_ptr, buffer_len, data_len, data_flags);
991 }
992 
lwm2m_engine_set_res_data_len(const char * pathstr,uint16_t data_len)993 int lwm2m_engine_set_res_data_len(const char *pathstr, uint16_t data_len)
994 {
995 	struct lwm2m_obj_path path;
996 	int ret = 0;
997 
998 	/* translate path -> path_obj */
999 	ret = lwm2m_string_to_path(pathstr, &path, '/');
1000 	if (ret < 0) {
1001 		return ret;
1002 	}
1003 
1004 	return lwm2m_set_res_data_len(&path, data_len);
1005 }
1006 /* User data getter functions */
1007 
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)1008 int lwm2m_get_res_buf(const struct lwm2m_obj_path *path, void **buffer_ptr, uint16_t *buffer_len,
1009 		      uint16_t *data_len, uint8_t *data_flags)
1010 {
1011 	int ret;
1012 	struct lwm2m_engine_res_inst *res_inst = NULL;
1013 
1014 	if (path->level < LWM2M_PATH_LEVEL_RESOURCE) {
1015 		LOG_ERR("path must have at least 3 parts");
1016 		return -EINVAL;
1017 	}
1018 
1019 	k_mutex_lock(&registry_lock, K_FOREVER);
1020 	/* look up resource obj */
1021 	ret = path_to_objs(path, NULL, NULL, NULL, &res_inst);
1022 	if (ret < 0) {
1023 		k_mutex_unlock(&registry_lock);
1024 		return ret;
1025 	}
1026 
1027 	if (!res_inst) {
1028 		LOG_ERR("res instance %d not found", path->res_inst_id);
1029 		k_mutex_unlock(&registry_lock);
1030 		return -ENOENT;
1031 	}
1032 
1033 	if (buffer_ptr) {
1034 		*buffer_ptr = res_inst->data_ptr;
1035 	}
1036 	if (buffer_len) {
1037 		*buffer_len = res_inst->max_data_len;
1038 	}
1039 	if (data_len) {
1040 		*data_len = res_inst->data_len;
1041 	}
1042 	if (data_flags) {
1043 		*data_flags = res_inst->data_flags;
1044 	}
1045 
1046 	k_mutex_unlock(&registry_lock);
1047 	return 0;
1048 }
1049 
lwm2m_engine_get_res_buf(const char * pathstr,void ** buffer_ptr,uint16_t * buffer_len,uint16_t * data_len,uint8_t * data_flags)1050 int lwm2m_engine_get_res_buf(const char *pathstr, void **buffer_ptr, uint16_t *buffer_len,
1051 			     uint16_t *data_len, uint8_t *data_flags)
1052 {
1053 	struct lwm2m_obj_path path;
1054 	int ret = 0;
1055 
1056 	/* translate path -> path_obj */
1057 	ret = lwm2m_string_to_path(pathstr, &path, '/');
1058 	if (ret < 0) {
1059 		return ret;
1060 	}
1061 
1062 	return lwm2m_get_res_buf(&path, buffer_ptr, buffer_len, data_len, data_flags);
1063 }
1064 
lwm2m_engine_get_res_data(const char * pathstr,void ** data_ptr,uint16_t * data_len,uint8_t * data_flags)1065 int lwm2m_engine_get_res_data(const char *pathstr, void **data_ptr, uint16_t *data_len,
1066 			      uint8_t *data_flags)
1067 {
1068 	struct lwm2m_obj_path path;
1069 	int ret = 0;
1070 
1071 	/* translate path -> path_obj */
1072 	ret = lwm2m_string_to_path(pathstr, &path, '/');
1073 	if (ret < 0) {
1074 		return ret;
1075 	}
1076 
1077 	return lwm2m_get_res_buf(&path, data_ptr, NULL, data_len, data_flags);
1078 }
1079 
lwm2m_engine_get(const struct lwm2m_obj_path * path,void * buf,uint16_t buflen)1080 static int lwm2m_engine_get(const struct lwm2m_obj_path *path, void *buf, uint16_t buflen)
1081 {
1082 	int ret = 0;
1083 	struct lwm2m_engine_obj_inst *obj_inst;
1084 	struct lwm2m_engine_obj_field *obj_field;
1085 	struct lwm2m_engine_res *res = NULL;
1086 	struct lwm2m_engine_res_inst *res_inst = NULL;
1087 	void *data_ptr = NULL;
1088 	size_t data_len = 0;
1089 
1090 	if (path->level < LWM2M_PATH_LEVEL_RESOURCE) {
1091 		LOG_ERR("path must have at least 3 parts");
1092 		return -EINVAL;
1093 	}
1094 	LOG_DBG("path:%u/%u/%u/%u, level %u, buf:%p, buflen:%d", path->obj_id, path->obj_inst_id,
1095 		path->res_id, path->res_inst_id, path->level, buf, buflen);
1096 
1097 	k_mutex_lock(&registry_lock, K_FOREVER);
1098 	/* look up resource obj */
1099 	ret = path_to_objs(path, &obj_inst, &obj_field, &res, &res_inst);
1100 	if (ret < 0) {
1101 		k_mutex_unlock(&registry_lock);
1102 		return ret;
1103 	}
1104 
1105 	if (!res_inst) {
1106 		LOG_ERR("res instance %d not found", path->res_inst_id);
1107 		k_mutex_unlock(&registry_lock);
1108 		return -ENOENT;
1109 	}
1110 
1111 	/* setup initial data elements */
1112 	data_ptr = res_inst->data_ptr;
1113 	data_len = res_inst->data_len;
1114 
1115 	/* allow user to override data elements via callback */
1116 	if (res->read_cb) {
1117 		data_ptr = res->read_cb(obj_inst->obj_inst_id, res->res_id, res_inst->res_inst_id,
1118 					&data_len);
1119 	}
1120 
1121 	if (data_ptr && data_len > 0) {
1122 		ret = lwm2m_check_buf_sizes(obj_field->data_type, data_len, buflen);
1123 		if (ret) {
1124 			LOG_ERR("Incorrect resource data length %zu. Buffer length %u", data_len,
1125 				buflen);
1126 			k_mutex_unlock(&registry_lock);
1127 			return ret;
1128 		}
1129 
1130 		switch (obj_field->data_type) {
1131 
1132 		case LWM2M_RES_TYPE_OPAQUE:
1133 			memcpy(buf, data_ptr, data_len);
1134 			break;
1135 
1136 		case LWM2M_RES_TYPE_STRING:
1137 			strncpy((uint8_t *)buf, (uint8_t *)data_ptr, buflen);
1138 			break;
1139 
1140 		case LWM2M_RES_TYPE_U32:
1141 			*(uint32_t *)buf = *(uint32_t *)data_ptr;
1142 			break;
1143 		case LWM2M_RES_TYPE_TIME:
1144 			if (!lwm2m_validate_time_resource_lenghts(data_len, buflen)) {
1145 				LOG_ERR("Time get buffer length %u  data len %zu not supported",
1146 					buflen, data_len);
1147 				return -EINVAL;
1148 			}
1149 
1150 			if (data_len == sizeof(time_t)) {
1151 				if (buflen == sizeof(time_t)) {
1152 					*((time_t *)buf) = *(time_t *)data_ptr;
1153 				} else {
1154 					/* In this case get operation may not got correct value */
1155 					LOG_WRN("Converting time to 32bit may cause integer "
1156 						"overflow");
1157 					*((uint32_t *)buf) = (uint32_t) *((time_t *)data_ptr);
1158 				}
1159 			} else {
1160 				LOG_WRN("Converting time to 32bit may cause integer overflow");
1161 				if (buflen == sizeof(uint32_t)) {
1162 					*((uint32_t *)buf) = *(uint32_t *)data_ptr;
1163 				} else {
1164 					*((time_t *)buf) = (time_t) *((uint32_t *)data_ptr);
1165 				}
1166 			}
1167 			break;
1168 
1169 		case LWM2M_RES_TYPE_U16:
1170 			*(uint16_t *)buf = *(uint16_t *)data_ptr;
1171 			break;
1172 
1173 		case LWM2M_RES_TYPE_U8:
1174 			*(uint8_t *)buf = *(uint8_t *)data_ptr;
1175 			break;
1176 
1177 		case LWM2M_RES_TYPE_S64:
1178 			*(int64_t *)buf = *(int64_t *)data_ptr;
1179 			break;
1180 
1181 		case LWM2M_RES_TYPE_S32:
1182 			*(int32_t *)buf = *(int32_t *)data_ptr;
1183 			break;
1184 
1185 		case LWM2M_RES_TYPE_S16:
1186 			*(int16_t *)buf = *(int16_t *)data_ptr;
1187 			break;
1188 
1189 		case LWM2M_RES_TYPE_S8:
1190 			*(int8_t *)buf = *(int8_t *)data_ptr;
1191 			break;
1192 
1193 		case LWM2M_RES_TYPE_BOOL:
1194 			*(bool *)buf = *(bool *)data_ptr;
1195 			break;
1196 
1197 		case LWM2M_RES_TYPE_FLOAT:
1198 			*(double *)buf = *(double *)data_ptr;
1199 			break;
1200 
1201 		case LWM2M_RES_TYPE_OBJLNK:
1202 			*(struct lwm2m_objlnk *)buf = *(struct lwm2m_objlnk *)data_ptr;
1203 			break;
1204 
1205 		default:
1206 			LOG_ERR("unknown obj data_type %d", obj_field->data_type);
1207 			k_mutex_unlock(&registry_lock);
1208 			return -EINVAL;
1209 		}
1210 	}
1211 	k_mutex_unlock(&registry_lock);
1212 	return 0;
1213 }
1214 
lwm2m_get_opaque(const struct lwm2m_obj_path * path,void * buf,uint16_t buflen)1215 int lwm2m_get_opaque(const struct lwm2m_obj_path *path, void *buf, uint16_t buflen)
1216 {
1217 	return lwm2m_engine_get(path, buf, buflen);
1218 }
1219 
lwm2m_engine_get_opaque(const char * pathstr,void * buf,uint16_t buflen)1220 int lwm2m_engine_get_opaque(const char *pathstr, void *buf, uint16_t buflen)
1221 {
1222 	struct lwm2m_obj_path path;
1223 	int ret = 0;
1224 
1225 	ret = lwm2m_string_to_path(pathstr, &path, '/');
1226 	if (ret < 0) {
1227 		return ret;
1228 	}
1229 	return lwm2m_get_opaque(&path, buf, buflen);
1230 }
1231 
lwm2m_get_string(const struct lwm2m_obj_path * path,void * str,uint16_t strlen)1232 int lwm2m_get_string(const struct lwm2m_obj_path *path, void *str, uint16_t strlen)
1233 {
1234 	return lwm2m_engine_get(path, str, strlen);
1235 }
1236 
lwm2m_engine_get_string(const char * pathstr,void * str,uint16_t strlen)1237 int lwm2m_engine_get_string(const char *pathstr, void *str, uint16_t strlen)
1238 {
1239 	struct lwm2m_obj_path path;
1240 	int ret = 0;
1241 
1242 	ret = lwm2m_string_to_path(pathstr, &path, '/');
1243 	if (ret < 0) {
1244 		return ret;
1245 	}
1246 	return lwm2m_get_opaque(&path, str, strlen);
1247 }
1248 
lwm2m_get_u8(const struct lwm2m_obj_path * path,uint8_t * value)1249 int lwm2m_get_u8(const struct lwm2m_obj_path *path, uint8_t *value)
1250 {
1251 	return lwm2m_engine_get(path, value, 1);
1252 }
1253 
lwm2m_engine_get_u8(const char * pathstr,uint8_t * value)1254 int lwm2m_engine_get_u8(const char *pathstr, uint8_t *value)
1255 {
1256 	struct lwm2m_obj_path path;
1257 	int ret = 0;
1258 
1259 	ret = lwm2m_string_to_path(pathstr, &path, '/');
1260 	if (ret < 0) {
1261 		return ret;
1262 	}
1263 	return lwm2m_get_u8(&path, value);
1264 }
1265 
lwm2m_get_u16(const struct lwm2m_obj_path * path,uint16_t * value)1266 int lwm2m_get_u16(const struct lwm2m_obj_path *path, uint16_t *value)
1267 {
1268 	return lwm2m_engine_get(path, value, 2);
1269 }
1270 
lwm2m_engine_get_u16(const char * pathstr,uint16_t * value)1271 int lwm2m_engine_get_u16(const char *pathstr, uint16_t *value)
1272 {
1273 	struct lwm2m_obj_path path;
1274 	int ret = 0;
1275 
1276 	ret = lwm2m_string_to_path(pathstr, &path, '/');
1277 	if (ret < 0) {
1278 		return ret;
1279 	}
1280 	return lwm2m_get_u16(&path, value);
1281 }
1282 
lwm2m_get_u32(const struct lwm2m_obj_path * path,uint32_t * value)1283 int lwm2m_get_u32(const struct lwm2m_obj_path *path, uint32_t *value)
1284 {
1285 	return lwm2m_engine_get(path, value, 4);
1286 }
1287 
lwm2m_engine_get_u32(const char * pathstr,uint32_t * value)1288 int lwm2m_engine_get_u32(const char *pathstr, uint32_t *value)
1289 {
1290 	struct lwm2m_obj_path path;
1291 	int ret = 0;
1292 
1293 	ret = lwm2m_string_to_path(pathstr, &path, '/');
1294 	if (ret < 0) {
1295 		return ret;
1296 	}
1297 	return lwm2m_get_u32(&path, value);
1298 }
1299 
lwm2m_get_u64(const struct lwm2m_obj_path * path,uint64_t * value)1300 int lwm2m_get_u64(const struct lwm2m_obj_path *path, uint64_t *value)
1301 {
1302 	return lwm2m_engine_get(path, value, 8);
1303 }
1304 
lwm2m_engine_get_u64(const char * pathstr,uint64_t * value)1305 int lwm2m_engine_get_u64(const char *pathstr, uint64_t *value)
1306 {
1307 	struct lwm2m_obj_path path;
1308 	int ret = 0;
1309 
1310 	ret = lwm2m_string_to_path(pathstr, &path, '/');
1311 	if (ret < 0) {
1312 		return ret;
1313 	}
1314 	return lwm2m_get_u64(&path, value);
1315 }
1316 
lwm2m_get_s8(const struct lwm2m_obj_path * path,int8_t * value)1317 int lwm2m_get_s8(const struct lwm2m_obj_path *path, int8_t *value)
1318 {
1319 	return lwm2m_engine_get(path, value, 1);
1320 }
1321 
lwm2m_engine_get_s8(const char * pathstr,int8_t * value)1322 int lwm2m_engine_get_s8(const char *pathstr, int8_t *value)
1323 {
1324 	struct lwm2m_obj_path path;
1325 	int ret = 0;
1326 
1327 	ret = lwm2m_string_to_path(pathstr, &path, '/');
1328 	if (ret < 0) {
1329 		return ret;
1330 	}
1331 	return lwm2m_get_s8(&path, value);
1332 }
1333 
lwm2m_get_s16(const struct lwm2m_obj_path * path,int16_t * value)1334 int lwm2m_get_s16(const struct lwm2m_obj_path *path, int16_t *value)
1335 {
1336 	return lwm2m_engine_get(path, value, 2);
1337 }
1338 
lwm2m_engine_get_s16(const char * pathstr,int16_t * value)1339 int lwm2m_engine_get_s16(const char *pathstr, int16_t *value)
1340 {
1341 	struct lwm2m_obj_path path;
1342 	int ret = 0;
1343 
1344 	ret = lwm2m_string_to_path(pathstr, &path, '/');
1345 	if (ret < 0) {
1346 		return ret;
1347 	}
1348 	return lwm2m_get_s16(&path, value);
1349 }
1350 
lwm2m_get_s32(const struct lwm2m_obj_path * path,int32_t * value)1351 int lwm2m_get_s32(const struct lwm2m_obj_path *path, int32_t *value)
1352 {
1353 	return lwm2m_engine_get(path, value, 4);
1354 }
1355 
lwm2m_engine_get_s32(const char * pathstr,int32_t * value)1356 int lwm2m_engine_get_s32(const char *pathstr, int32_t *value)
1357 {
1358 	struct lwm2m_obj_path path;
1359 	int ret = 0;
1360 
1361 	ret = lwm2m_string_to_path(pathstr, &path, '/');
1362 	if (ret < 0) {
1363 		return ret;
1364 	}
1365 	return lwm2m_get_s32(&path, value);
1366 }
1367 
lwm2m_get_s64(const struct lwm2m_obj_path * path,int64_t * value)1368 int lwm2m_get_s64(const struct lwm2m_obj_path *path, int64_t *value)
1369 {
1370 	return lwm2m_engine_get(path, value, 8);
1371 }
1372 
lwm2m_engine_get_s64(const char * pathstr,int64_t * value)1373 int lwm2m_engine_get_s64(const char *pathstr, int64_t *value)
1374 {
1375 	struct lwm2m_obj_path path;
1376 	int ret = 0;
1377 
1378 	ret = lwm2m_string_to_path(pathstr, &path, '/');
1379 	if (ret < 0) {
1380 		return ret;
1381 	}
1382 	return lwm2m_get_s64(&path, value);
1383 }
1384 
lwm2m_get_bool(const struct lwm2m_obj_path * path,bool * value)1385 int lwm2m_get_bool(const struct lwm2m_obj_path *path, bool *value)
1386 {
1387 	int ret = 0;
1388 	int8_t temp = 0;
1389 
1390 	ret = lwm2m_get_s8(path, &temp);
1391 	if (!ret) {
1392 		*value = temp != 0;
1393 	}
1394 
1395 	return ret;
1396 }
1397 
lwm2m_engine_get_bool(const char * pathstr,bool * value)1398 int lwm2m_engine_get_bool(const char *pathstr, bool *value)
1399 {
1400 	struct lwm2m_obj_path path;
1401 	int ret = 0;
1402 
1403 	ret = lwm2m_string_to_path(pathstr, &path, '/');
1404 	if (ret < 0) {
1405 		return ret;
1406 	}
1407 	return lwm2m_get_bool(&path, value);
1408 }
1409 
lwm2m_get_f64(const struct lwm2m_obj_path * path,double * value)1410 int lwm2m_get_f64(const struct lwm2m_obj_path *path, double *value)
1411 {
1412 	return lwm2m_engine_get(path, value, sizeof(double));
1413 }
1414 
lwm2m_engine_get_float(const char * pathstr,double * buf)1415 int lwm2m_engine_get_float(const char *pathstr, double *buf)
1416 {
1417 	struct lwm2m_obj_path path;
1418 	int ret = 0;
1419 
1420 	ret = lwm2m_string_to_path(pathstr, &path, '/');
1421 	if (ret < 0) {
1422 		return ret;
1423 	}
1424 	return lwm2m_get_f64(&path, buf);
1425 }
1426 
lwm2m_get_objlnk(const struct lwm2m_obj_path * path,struct lwm2m_objlnk * buf)1427 int lwm2m_get_objlnk(const struct lwm2m_obj_path *path, struct lwm2m_objlnk *buf)
1428 {
1429 	return lwm2m_engine_get(path, buf, sizeof(struct lwm2m_objlnk));
1430 }
1431 
lwm2m_engine_get_objlnk(const char * pathstr,struct lwm2m_objlnk * buf)1432 int lwm2m_engine_get_objlnk(const char *pathstr, struct lwm2m_objlnk *buf)
1433 {
1434 	struct lwm2m_obj_path path;
1435 	int ret = 0;
1436 
1437 	ret = lwm2m_string_to_path(pathstr, &path, '/');
1438 	if (ret < 0) {
1439 		return ret;
1440 	}
1441 	return lwm2m_get_objlnk(&path, buf);
1442 }
1443 
lwm2m_get_time(const struct lwm2m_obj_path * path,time_t * buf)1444 int lwm2m_get_time(const struct lwm2m_obj_path *path, time_t *buf)
1445 {
1446 	return lwm2m_engine_get(path, buf, sizeof(time_t));
1447 }
1448 
lwm2m_engine_get_time(const char * pathstr,time_t * buf)1449 int lwm2m_engine_get_time(const char *pathstr, time_t *buf)
1450 {
1451 	struct lwm2m_obj_path path;
1452 	int ret = 0;
1453 
1454 	ret = lwm2m_string_to_path(pathstr, &path, '/');
1455 	if (ret < 0) {
1456 		return ret;
1457 	}
1458 	return lwm2m_get_time(&path, buf);
1459 }
1460 
lwm2m_get_resource(const struct lwm2m_obj_path * path,struct lwm2m_engine_res ** res)1461 int lwm2m_get_resource(const struct lwm2m_obj_path *path, struct lwm2m_engine_res **res)
1462 {
1463 	if (path->level < LWM2M_PATH_LEVEL_RESOURCE) {
1464 		LOG_ERR("path must have 3 parts");
1465 		return -EINVAL;
1466 	}
1467 
1468 	return path_to_objs(path, NULL, NULL, res, NULL);
1469 }
1470 
lwm2m_engine_get_resource(const char * pathstr,struct lwm2m_engine_res ** res)1471 int lwm2m_engine_get_resource(const char *pathstr, struct lwm2m_engine_res **res)
1472 {
1473 	int ret;
1474 	struct lwm2m_obj_path path;
1475 
1476 	ret = lwm2m_string_to_path(pathstr, &path, '/');
1477 	if (ret < 0) {
1478 		return ret;
1479 	}
1480 
1481 	return lwm2m_get_resource(&path, res);
1482 }
1483 
lwm2m_engine_get_opaque_more(struct lwm2m_input_context * in,uint8_t * buf,size_t buflen,struct lwm2m_opaque_context * opaque,bool * last_block)1484 size_t lwm2m_engine_get_opaque_more(struct lwm2m_input_context *in, uint8_t *buf, size_t buflen,
1485 				    struct lwm2m_opaque_context *opaque, bool *last_block)
1486 {
1487 	uint32_t in_len = opaque->remaining;
1488 	uint16_t remaining = in->in_cpkt->max_len - in->offset;
1489 
1490 	if (in_len > buflen) {
1491 		in_len = buflen;
1492 	}
1493 
1494 	if (in_len > remaining) {
1495 		in_len = remaining;
1496 	}
1497 
1498 	opaque->remaining -= in_len;
1499 	remaining -= in_len;
1500 	if (opaque->remaining == 0U || remaining == 0) {
1501 		*last_block = true;
1502 	}
1503 
1504 	if (buf_read(buf, in_len, CPKT_BUF_READ(in->in_cpkt), &in->offset) < 0) {
1505 		*last_block = true;
1506 		return 0;
1507 	}
1508 
1509 	return (size_t)in_len;
1510 }
1511 
lwm2m_engine_get_queue_mode(char * queue)1512 void lwm2m_engine_get_queue_mode(char *queue)
1513 {
1514 	if (IS_ENABLED(CONFIG_LWM2M_QUEUE_MODE_ENABLED)) {
1515 		strncpy(queue, "Q", QUEUE_OPT_MAX_LEN);
1516 	} else {
1517 		strncpy(queue, "", QUEUE_OPT_MAX_LEN);
1518 	}
1519 }
1520 
lwm2m_engine_get_binding(char * binding)1521 void lwm2m_engine_get_binding(char *binding)
1522 {
1523 	/* Defaults to UDP. */
1524 	strncpy(binding, "U", BINDING_OPT_MAX_LEN);
1525 #if CONFIG_LWM2M_VERSION_1_0
1526 	/* In LwM2M 1.0 binding and queue mode are in same parameter */
1527 	char queue[QUEUE_OPT_MAX_LEN];
1528 
1529 	lwm2m_engine_get_queue_mode(queue);
1530 	strncat(binding, queue, QUEUE_OPT_MAX_LEN);
1531 #endif
1532 }
1533 /* Engine resource instance */
1534 
lwm2m_engine_allocate_resource_instance(struct lwm2m_engine_res * res,struct lwm2m_engine_res_inst ** res_inst,uint8_t resource_instance_id)1535 static int lwm2m_engine_allocate_resource_instance(struct lwm2m_engine_res *res,
1536 						   struct lwm2m_engine_res_inst **res_inst,
1537 						   uint8_t resource_instance_id)
1538 {
1539 	int i;
1540 
1541 	if (!res->res_instances || res->res_inst_count == 0) {
1542 		return -ENOMEM;
1543 	}
1544 
1545 	for (i = 0; i < res->res_inst_count; i++) {
1546 		if (res->res_instances[i].res_inst_id == RES_INSTANCE_NOT_CREATED) {
1547 			break;
1548 		}
1549 	}
1550 
1551 	if (i >= res->res_inst_count) {
1552 		return -ENOMEM;
1553 	}
1554 
1555 	res->res_instances[i].res_inst_id = resource_instance_id;
1556 	*res_inst = &res->res_instances[i];
1557 	return 0;
1558 }
1559 
lwm2m_engine_get_create_res_inst(const struct lwm2m_obj_path * path,struct lwm2m_engine_res ** res,struct lwm2m_engine_res_inst ** res_inst)1560 int lwm2m_engine_get_create_res_inst(const struct lwm2m_obj_path *path,
1561 				     struct lwm2m_engine_res **res,
1562 				     struct lwm2m_engine_res_inst **res_inst)
1563 {
1564 	int ret;
1565 	struct lwm2m_engine_res *r = NULL;
1566 	struct lwm2m_engine_res_inst *r_i = NULL;
1567 
1568 	ret = path_to_objs(path, NULL, NULL, &r, &r_i);
1569 	if (ret < 0) {
1570 		return ret;
1571 	}
1572 
1573 	if (!r) {
1574 		return -ENOENT;
1575 	}
1576 	/* Store resource pointer */
1577 	*res = r;
1578 
1579 	if (!r_i) {
1580 		if (path->level < LWM2M_PATH_LEVEL_RESOURCE_INST) {
1581 			return -EINVAL;
1582 		}
1583 
1584 		ret = lwm2m_engine_allocate_resource_instance(r, &r_i, path->res_inst_id);
1585 		if (ret < 0) {
1586 			return ret;
1587 		}
1588 	}
1589 
1590 	/* Store resource instance pointer */
1591 	*res_inst = r_i;
1592 	return 0;
1593 }
1594 
lwm2m_create_res_inst(const struct lwm2m_obj_path * path)1595 int lwm2m_create_res_inst(const struct lwm2m_obj_path *path)
1596 {
1597 	int ret;
1598 	struct lwm2m_engine_res *res = NULL;
1599 	struct lwm2m_engine_res_inst *res_inst = NULL;
1600 
1601 	if (path->level < LWM2M_PATH_LEVEL_RESOURCE_INST) {
1602 		LOG_ERR("path must have 4 parts");
1603 		return -EINVAL;
1604 	}
1605 	k_mutex_lock(&registry_lock, K_FOREVER);
1606 	ret = path_to_objs(path, NULL, NULL, &res, &res_inst);
1607 	if (ret < 0) {
1608 		k_mutex_unlock(&registry_lock);
1609 		return ret;
1610 	}
1611 
1612 	if (!res) {
1613 		LOG_ERR("resource %u not found", path->res_id);
1614 		k_mutex_unlock(&registry_lock);
1615 		return -ENOENT;
1616 	}
1617 
1618 	if (res_inst && res_inst->res_inst_id != RES_INSTANCE_NOT_CREATED) {
1619 		LOG_ERR("res instance %u already exists", path->res_inst_id);
1620 		k_mutex_unlock(&registry_lock);
1621 		return -EINVAL;
1622 	}
1623 	k_mutex_unlock(&registry_lock);
1624 	return lwm2m_engine_allocate_resource_instance(res, &res_inst, path->res_inst_id);
1625 }
1626 
lwm2m_engine_create_res_inst(const char * pathstr)1627 int lwm2m_engine_create_res_inst(const char *pathstr)
1628 {
1629 	int ret;
1630 	struct lwm2m_obj_path path;
1631 
1632 	ret = lwm2m_string_to_path(pathstr, &path, '/');
1633 	if (ret < 0) {
1634 		return ret;
1635 	}
1636 
1637 	return lwm2m_create_res_inst(&path);
1638 }
1639 
lwm2m_delete_res_inst(const struct lwm2m_obj_path * path)1640 int lwm2m_delete_res_inst(const struct lwm2m_obj_path *path)
1641 {
1642 	int ret;
1643 	struct lwm2m_engine_res_inst *res_inst = NULL;
1644 
1645 	if (path->level < LWM2M_PATH_LEVEL_RESOURCE_INST) {
1646 		LOG_ERR("path must have 4 parts");
1647 		return -EINVAL;
1648 	}
1649 	k_mutex_lock(&registry_lock, K_FOREVER);
1650 	ret = path_to_objs(path, NULL, NULL, NULL, &res_inst);
1651 	if (ret < 0) {
1652 		k_mutex_unlock(&registry_lock);
1653 		return ret;
1654 	}
1655 
1656 	if (!res_inst) {
1657 		LOG_ERR("res instance %u not found", path->res_inst_id);
1658 		k_mutex_unlock(&registry_lock);
1659 		return -ENOENT;
1660 	}
1661 
1662 	res_inst->data_ptr = NULL;
1663 	res_inst->max_data_len = 0U;
1664 	res_inst->data_len = 0U;
1665 	res_inst->res_inst_id = RES_INSTANCE_NOT_CREATED;
1666 	k_mutex_unlock(&registry_lock);
1667 	return 0;
1668 }
1669 
lwm2m_engine_delete_res_inst(const char * pathstr)1670 int lwm2m_engine_delete_res_inst(const char *pathstr)
1671 {
1672 	int ret;
1673 	struct lwm2m_obj_path path;
1674 
1675 	ret = lwm2m_string_to_path(pathstr, &path, '/');
1676 	if (ret < 0) {
1677 		return ret;
1678 	}
1679 
1680 	return lwm2m_delete_res_inst(&path);
1681 }
1682 /* Register callbacks */
1683 
lwm2m_register_read_callback(const struct lwm2m_obj_path * path,lwm2m_engine_get_data_cb_t cb)1684 int lwm2m_register_read_callback(const struct lwm2m_obj_path *path, lwm2m_engine_get_data_cb_t cb)
1685 {
1686 	int ret;
1687 	struct lwm2m_engine_res *res = NULL;
1688 
1689 	ret = lwm2m_get_resource(path, &res);
1690 	if (ret < 0) {
1691 		return ret;
1692 	}
1693 
1694 	res->read_cb = cb;
1695 	return 0;
1696 }
1697 
lwm2m_engine_register_read_callback(const char * pathstr,lwm2m_engine_get_data_cb_t cb)1698 int lwm2m_engine_register_read_callback(const char *pathstr, lwm2m_engine_get_data_cb_t cb)
1699 {
1700 	int ret;
1701 	struct lwm2m_obj_path path;
1702 
1703 	ret = lwm2m_string_to_path(pathstr, &path, '/');
1704 	if (ret < 0) {
1705 		return ret;
1706 	}
1707 
1708 	return lwm2m_register_read_callback(&path, cb);
1709 }
1710 
lwm2m_register_pre_write_callback(const struct lwm2m_obj_path * path,lwm2m_engine_get_data_cb_t cb)1711 int lwm2m_register_pre_write_callback(const struct lwm2m_obj_path *path,
1712 				      lwm2m_engine_get_data_cb_t cb)
1713 {
1714 	int ret;
1715 	struct lwm2m_engine_res *res = NULL;
1716 
1717 	ret = lwm2m_get_resource(path, &res);
1718 	if (ret < 0) {
1719 		return ret;
1720 	}
1721 
1722 	res->pre_write_cb = cb;
1723 	return 0;
1724 }
1725 
lwm2m_engine_register_pre_write_callback(const char * pathstr,lwm2m_engine_get_data_cb_t cb)1726 int lwm2m_engine_register_pre_write_callback(const char *pathstr, lwm2m_engine_get_data_cb_t cb)
1727 {
1728 	int ret;
1729 	struct lwm2m_obj_path path;
1730 
1731 	ret = lwm2m_string_to_path(pathstr, &path, '/');
1732 	if (ret < 0) {
1733 		return ret;
1734 	}
1735 
1736 	return lwm2m_register_pre_write_callback(&path, cb);
1737 }
1738 
lwm2m_register_validate_callback(const struct lwm2m_obj_path * path,lwm2m_engine_set_data_cb_t cb)1739 int lwm2m_register_validate_callback(const struct lwm2m_obj_path *path,
1740 				     lwm2m_engine_set_data_cb_t cb)
1741 {
1742 #if CONFIG_LWM2M_ENGINE_VALIDATION_BUFFER_SIZE > 0
1743 	int ret;
1744 	struct lwm2m_engine_res *res = NULL;
1745 
1746 	ret = lwm2m_get_resource(path, &res);
1747 	if (ret < 0) {
1748 		return ret;
1749 	}
1750 
1751 	res->validate_cb = cb;
1752 	return 0;
1753 #else
1754 	ARG_UNUSED(path);
1755 	ARG_UNUSED(cb);
1756 
1757 	LOG_ERR("Validation disabled. Set "
1758 		"CONFIG_LWM2M_ENGINE_VALIDATION_BUFFER_SIZE > 0 to "
1759 		"enable validation support.");
1760 	return -ENOTSUP;
1761 #endif /* CONFIG_LWM2M_ENGINE_VALIDATION_BUFFER_SIZE > 0 */
1762 }
1763 
lwm2m_engine_register_validate_callback(const char * pathstr,lwm2m_engine_set_data_cb_t cb)1764 int lwm2m_engine_register_validate_callback(const char *pathstr, lwm2m_engine_set_data_cb_t cb)
1765 {
1766 #if CONFIG_LWM2M_ENGINE_VALIDATION_BUFFER_SIZE > 0
1767 	int ret;
1768 	struct lwm2m_obj_path path;
1769 
1770 	ret = lwm2m_string_to_path(pathstr, &path, '/');
1771 	if (ret < 0) {
1772 		return ret;
1773 	}
1774 
1775 	return lwm2m_register_validate_callback(&path, cb);
1776 #else
1777 	ARG_UNUSED(pathstr);
1778 	ARG_UNUSED(cb);
1779 
1780 	LOG_ERR("Validation disabled. Set "
1781 		"CONFIG_LWM2M_ENGINE_VALIDATION_BUFFER_SIZE > 0 to "
1782 		"enable validation support.");
1783 	return -ENOTSUP;
1784 #endif /* CONFIG_LWM2M_ENGINE_VALIDATION_BUFFER_SIZE > 0 */
1785 }
1786 
lwm2m_register_post_write_callback(const struct lwm2m_obj_path * path,lwm2m_engine_set_data_cb_t cb)1787 int lwm2m_register_post_write_callback(const struct lwm2m_obj_path *path,
1788 				       lwm2m_engine_set_data_cb_t cb)
1789 {
1790 	int ret;
1791 	struct lwm2m_engine_res *res = NULL;
1792 
1793 	ret = lwm2m_get_resource(path, &res);
1794 	if (ret < 0) {
1795 		return ret;
1796 	}
1797 
1798 	res->post_write_cb = cb;
1799 	return 0;
1800 }
1801 
lwm2m_engine_register_post_write_callback(const char * pathstr,lwm2m_engine_set_data_cb_t cb)1802 int lwm2m_engine_register_post_write_callback(const char *pathstr, lwm2m_engine_set_data_cb_t cb)
1803 {
1804 	int ret;
1805 	struct lwm2m_obj_path path;
1806 
1807 	ret = lwm2m_string_to_path(pathstr, &path, '/');
1808 	if (ret < 0) {
1809 		return ret;
1810 	}
1811 
1812 	return lwm2m_register_post_write_callback(&path, cb);
1813 }
1814 
lwm2m_register_exec_callback(const struct lwm2m_obj_path * path,lwm2m_engine_execute_cb_t cb)1815 int lwm2m_register_exec_callback(const struct lwm2m_obj_path *path, lwm2m_engine_execute_cb_t cb)
1816 {
1817 	int ret;
1818 	struct lwm2m_engine_res *res = NULL;
1819 
1820 	ret = lwm2m_get_resource(path, &res);
1821 	if (ret < 0) {
1822 		return ret;
1823 	}
1824 
1825 	res->execute_cb = cb;
1826 	return 0;
1827 }
1828 
lwm2m_engine_register_exec_callback(const char * pathstr,lwm2m_engine_execute_cb_t cb)1829 int lwm2m_engine_register_exec_callback(const char *pathstr, lwm2m_engine_execute_cb_t cb)
1830 {
1831 	int ret;
1832 	struct lwm2m_obj_path path;
1833 
1834 	ret = lwm2m_string_to_path(pathstr, &path, '/');
1835 	if (ret < 0) {
1836 		return ret;
1837 	}
1838 
1839 	return lwm2m_register_exec_callback(&path, cb);
1840 }
1841 
lwm2m_register_create_callback(uint16_t obj_id,lwm2m_engine_user_cb_t cb)1842 int lwm2m_register_create_callback(uint16_t obj_id, lwm2m_engine_user_cb_t cb)
1843 {
1844 	struct lwm2m_engine_obj *obj = NULL;
1845 
1846 	obj = get_engine_obj(obj_id);
1847 	if (!obj) {
1848 		LOG_ERR("unable to find obj: %u", obj_id);
1849 		return -ENOENT;
1850 	}
1851 
1852 	obj->user_create_cb = cb;
1853 	return 0;
1854 }
1855 
lwm2m_engine_register_create_callback(uint16_t obj_id,lwm2m_engine_user_cb_t cb)1856 int lwm2m_engine_register_create_callback(uint16_t obj_id, lwm2m_engine_user_cb_t cb)
1857 {
1858 	return lwm2m_register_create_callback(obj_id, cb);
1859 }
1860 
lwm2m_register_delete_callback(uint16_t obj_id,lwm2m_engine_user_cb_t cb)1861 int lwm2m_register_delete_callback(uint16_t obj_id, lwm2m_engine_user_cb_t cb)
1862 {
1863 	struct lwm2m_engine_obj *obj = NULL;
1864 
1865 	obj = get_engine_obj(obj_id);
1866 	if (!obj) {
1867 		LOG_ERR("unable to find obj: %u", obj_id);
1868 		return -ENOENT;
1869 	}
1870 
1871 	obj->user_delete_cb = cb;
1872 	return 0;
1873 }
1874 
lwm2m_engine_register_delete_callback(uint16_t obj_id,lwm2m_engine_user_cb_t cb)1875 int lwm2m_engine_register_delete_callback(uint16_t obj_id, lwm2m_engine_user_cb_t cb)
1876 {
1877 	return lwm2m_register_delete_callback(obj_id, cb);
1878 }
1879 /* Generic data handlers */
1880 
lwm2m_get_or_create_engine_obj(struct lwm2m_message * msg,struct lwm2m_engine_obj_inst ** obj_inst,uint8_t * created)1881 int lwm2m_get_or_create_engine_obj(struct lwm2m_message *msg,
1882 				   struct lwm2m_engine_obj_inst **obj_inst, uint8_t *created)
1883 {
1884 	int ret = 0;
1885 
1886 	if (created) {
1887 		*created = 0U;
1888 	}
1889 
1890 	*obj_inst = get_engine_obj_inst(msg->path.obj_id, msg->path.obj_inst_id);
1891 	if (!*obj_inst) {
1892 		ret = lwm2m_create_obj_inst(msg->path.obj_id, msg->path.obj_inst_id, obj_inst);
1893 		if (ret < 0) {
1894 			return ret;
1895 		}
1896 
1897 		/* set created flag to one */
1898 		if (created) {
1899 			*created = 1U;
1900 		}
1901 
1902 		if (!msg->ctx->bootstrap_mode) {
1903 			engine_trigger_update(true);
1904 		}
1905 	}
1906 
1907 	return ret;
1908 }
1909 
lwm2m_engine_get_res(const struct lwm2m_obj_path * path)1910 struct lwm2m_engine_res *lwm2m_engine_get_res(const struct lwm2m_obj_path *path)
1911 {
1912 	struct lwm2m_engine_res *res = NULL;
1913 	int ret;
1914 
1915 	if (path->level < LWM2M_PATH_LEVEL_RESOURCE) {
1916 		return NULL;
1917 	}
1918 
1919 	ret = path_to_objs(path, NULL, NULL, &res, NULL);
1920 	if (ret < 0) {
1921 		return NULL;
1922 	}
1923 
1924 	return res;
1925 }
1926 
lwm2m_engine_get_res_inst(const struct lwm2m_obj_path * path)1927 struct lwm2m_engine_res_inst *lwm2m_engine_get_res_inst(const struct lwm2m_obj_path *path)
1928 {
1929 	struct lwm2m_engine_res_inst *res_inst = NULL;
1930 	int ret;
1931 
1932 	if (path->level != LWM2M_PATH_LEVEL_RESOURCE_INST) {
1933 		return NULL;
1934 	}
1935 
1936 	ret = path_to_objs(path, NULL, NULL, NULL, &res_inst);
1937 	if (ret < 0) {
1938 		return NULL;
1939 	}
1940 
1941 	return res_inst;
1942 }
1943 
lwm2m_engine_shall_report_obj_version(const struct lwm2m_engine_obj * obj)1944 bool lwm2m_engine_shall_report_obj_version(const struct lwm2m_engine_obj *obj)
1945 {
1946 	if (obj->is_core) {
1947 		return obj->version_major != LWM2M_PROTOCOL_VERSION_MAJOR ||
1948 		       obj->version_minor != LWM2M_PROTOCOL_VERSION_MINOR;
1949 	}
1950 
1951 	return obj->version_major != 1 || obj->version_minor != 0;
1952 }
1953 
1954 #if defined(CONFIG_LWM2M_RESOURCE_DATA_CACHE_SUPPORT)
1955 static sys_slist_t lwm2m_timed_cache_list;
1956 static struct lwm2m_time_series_resource lwm2m_cache_entries[CONFIG_LWM2M_MAX_CACHED_RESOURCES];
1957 
1958 static struct lwm2m_time_series_resource *
lwm2m_cache_entry_allocate(const struct lwm2m_obj_path * path)1959 lwm2m_cache_entry_allocate(const struct lwm2m_obj_path *path)
1960 {
1961 	int i;
1962 	struct lwm2m_time_series_resource *entry;
1963 
1964 	entry = lwm2m_cache_entry_get_by_object(path);
1965 	if (entry) {
1966 		return entry;
1967 	}
1968 
1969 	for (i = 0; i < ARRAY_SIZE(lwm2m_cache_entries); i++) {
1970 		if (lwm2m_cache_entries[i].path.level == 0) {
1971 			lwm2m_cache_entries[i].path = *path;
1972 			sys_slist_append(&lwm2m_timed_cache_list, &lwm2m_cache_entries[i].node);
1973 			return &lwm2m_cache_entries[i];
1974 		}
1975 	}
1976 
1977 	return NULL;
1978 }
1979 
lwm2m_engine_cache_write(const struct lwm2m_engine_obj_field * obj_field,const struct lwm2m_obj_path * path,const void * value,uint16_t len)1980 static void lwm2m_engine_cache_write(const struct lwm2m_engine_obj_field *obj_field,
1981 				     const struct lwm2m_obj_path *path, const void *value,
1982 				     uint16_t len)
1983 {
1984 	struct lwm2m_time_series_resource *cache_entry;
1985 	struct lwm2m_time_series_elem elements;
1986 
1987 	cache_entry = lwm2m_cache_entry_get_by_object(path);
1988 	if (!cache_entry) {
1989 		return;
1990 	}
1991 
1992 	elements.t = time(NULL);
1993 
1994 	if (elements.t  <= 0) {
1995 		LOG_WRN("Time() not available");
1996 		return;
1997 	}
1998 
1999 	switch (obj_field->data_type) {
2000 	case LWM2M_RES_TYPE_U32:
2001 		elements.u32 = *(uint32_t *)value;
2002 		break;
2003 
2004 	case LWM2M_RES_TYPE_U16:
2005 		elements.u16 = *(uint16_t *)value;
2006 		break;
2007 
2008 	case LWM2M_RES_TYPE_U8:
2009 		elements.u8 = *(uint8_t *)value;
2010 		break;
2011 
2012 	case LWM2M_RES_TYPE_S64:
2013 		elements.i64 = *(int64_t *)value;
2014 		break;
2015 
2016 	case LWM2M_RES_TYPE_TIME:
2017 		if (len == sizeof(time_t)) {
2018 			elements.time = *(time_t *)value;
2019 		} else if (len == sizeof(uint32_t)) {
2020 			elements.time = (time_t) *((uint32_t *)value);
2021 		} else {
2022 			LOG_ERR("Not supporting size %d bytes for time", len);
2023 			return;
2024 		}
2025 		break;
2026 
2027 	case LWM2M_RES_TYPE_S32:
2028 		elements.i32 = *(int32_t *)value;
2029 		break;
2030 
2031 	case LWM2M_RES_TYPE_S16:
2032 		elements.i16 = *(int16_t *)value;
2033 		break;
2034 
2035 	case LWM2M_RES_TYPE_S8:
2036 		elements.i8 = *(int8_t *)value;
2037 		break;
2038 
2039 	case LWM2M_RES_TYPE_BOOL:
2040 		elements.b = *(bool *)value;
2041 		break;
2042 
2043 	default:
2044 		elements.f = *(double *)value;
2045 		break;
2046 	}
2047 
2048 	if (!lwm2m_cache_write(cache_entry, &elements)) {
2049 		LOG_WRN("Data cache full");
2050 	}
2051 }
2052 #endif /* CONFIG_LWM2M_RESOURCE_DATA_CACHE_SUPPORT */
2053 
2054 struct lwm2m_time_series_resource *
lwm2m_cache_entry_get_by_object(const struct lwm2m_obj_path * obj_path)2055 lwm2m_cache_entry_get_by_object(const struct lwm2m_obj_path *obj_path)
2056 {
2057 #if defined(CONFIG_LWM2M_RESOURCE_DATA_CACHE_SUPPORT)
2058 	struct lwm2m_time_series_resource *entry;
2059 
2060 	if (obj_path->level < LWM2M_PATH_LEVEL_RESOURCE) {
2061 		LOG_ERR("Path level wrong for cache %u", obj_path->level);
2062 		return NULL;
2063 	}
2064 
2065 	if (sys_slist_is_empty(&lwm2m_timed_cache_list)) {
2066 		return NULL;
2067 	}
2068 
2069 	SYS_SLIST_FOR_EACH_CONTAINER(&lwm2m_timed_cache_list, entry, node) {
2070 		if (lwm2m_obj_path_equal(&entry->path, obj_path)) {
2071 			return entry;
2072 		}
2073 	}
2074 #endif /* CONFIG_LWM2M_RESOURCE_DATA_CACHE_SUPPORT */
2075 	return NULL;
2076 
2077 }
2078 
lwm2m_enable_cache(const struct lwm2m_obj_path * path,struct lwm2m_time_series_elem * data_cache,size_t cache_len)2079 int lwm2m_enable_cache(const struct lwm2m_obj_path *path, struct lwm2m_time_series_elem *data_cache,
2080 		       size_t cache_len)
2081 {
2082 #if defined(CONFIG_LWM2M_RESOURCE_DATA_CACHE_SUPPORT)
2083 	struct lwm2m_engine_obj_inst *obj_inst;
2084 	struct lwm2m_engine_obj_field *obj_field;
2085 	struct lwm2m_engine_res_inst *res_inst = NULL;
2086 	struct lwm2m_time_series_resource *cache_entry;
2087 	int ret = 0;
2088 	size_t cache_entry_size = sizeof(struct lwm2m_time_series_elem);
2089 
2090 	/* look up resource obj */
2091 	ret = path_to_objs(path, &obj_inst, &obj_field, NULL, &res_inst);
2092 	if (ret < 0) {
2093 		return ret;
2094 	}
2095 
2096 	if (!res_inst) {
2097 		LOG_ERR("res instance %d not found", path->res_inst_id);
2098 		return -ENOENT;
2099 	}
2100 
2101 	switch (obj_field->data_type) {
2102 	case LWM2M_RES_TYPE_U32:
2103 	case LWM2M_RES_TYPE_TIME:
2104 	case LWM2M_RES_TYPE_U16:
2105 	case LWM2M_RES_TYPE_U8:
2106 	case LWM2M_RES_TYPE_S64:
2107 	case LWM2M_RES_TYPE_S32:
2108 	case LWM2M_RES_TYPE_S16:
2109 	case LWM2M_RES_TYPE_S8:
2110 	case LWM2M_RES_TYPE_BOOL:
2111 	case LWM2M_RES_TYPE_FLOAT:
2112 		/* Support only fixed width resource types */
2113 		cache_entry = lwm2m_cache_entry_allocate(path);
2114 		break;
2115 	default:
2116 		cache_entry = NULL;
2117 		break;
2118 	}
2119 
2120 	if (!cache_entry) {
2121 		return -ENODATA;
2122 	}
2123 
2124 	ring_buf_init(&cache_entry->rb, cache_entry_size * cache_len, (uint8_t *)data_cache);
2125 
2126 	return 0;
2127 #else
2128 	LOG_ERR("LwM2M resource cache is only supported for "
2129 		"CONFIG_LWM2M_RESOURCE_DATA_CACHE_SUPPORT");
2130 	return -ENOTSUP;
2131 #endif /* CONFIG_LWM2M_RESOURCE_DATA_CACHE_SUPPORT */
2132 }
2133 
lwm2m_engine_enable_cache(const char * resource_path,struct lwm2m_time_series_elem * data_cache,size_t cache_len)2134 int lwm2m_engine_enable_cache(const char *resource_path, struct lwm2m_time_series_elem *data_cache,
2135 			    size_t cache_len)
2136 {
2137 #if defined(CONFIG_LWM2M_RESOURCE_DATA_CACHE_SUPPORT)
2138 	struct lwm2m_obj_path path;
2139 	int ret;
2140 
2141 	/* translate path -> path_obj */
2142 	ret = lwm2m_string_to_path(resource_path, &path, '/');
2143 	if (ret < 0) {
2144 		return ret;
2145 	}
2146 
2147 	if (path.level < LWM2M_PATH_LEVEL_RESOURCE) {
2148 		LOG_ERR("path must have at least 3 parts");
2149 		return -EINVAL;
2150 	}
2151 
2152 	return lwm2m_enable_cache(&path, data_cache, cache_len);
2153 #else
2154 	LOG_ERR("LwM2M resource cache is only supported for "
2155 		"CONFIG_LWM2M_RESOURCE_DATA_CACHE_SUPPORT");
2156 	return -ENOTSUP;
2157 #endif /* CONFIG_LWM2M_RESOURCE_DATA_CACHE_SUPPORT */
2158 }
2159 
lwm2m_engine_data_cache_init(void)2160 int lwm2m_engine_data_cache_init(void)
2161 {
2162 #if defined(CONFIG_LWM2M_RESOURCE_DATA_CACHE_SUPPORT)
2163 	int i;
2164 
2165 	sys_slist_init(&lwm2m_timed_cache_list);
2166 
2167 	for (i = 0; i < ARRAY_SIZE(lwm2m_cache_entries); i++) {
2168 		lwm2m_cache_entries[i].path.level = LWM2M_PATH_LEVEL_NONE;
2169 	}
2170 #endif
2171 	return 0;
2172 }
2173 
lwm2m_cache_write(struct lwm2m_time_series_resource * cache_entry,struct lwm2m_time_series_elem * buf)2174 bool lwm2m_cache_write(struct lwm2m_time_series_resource *cache_entry,
2175 		       struct lwm2m_time_series_elem *buf)
2176 {
2177 #if defined(CONFIG_LWM2M_RESOURCE_DATA_CACHE_SUPPORT)
2178 	uint32_t length;
2179 	uint8_t *buf_ptr;
2180 	uint32_t element_size = sizeof(struct lwm2m_time_series_elem);
2181 
2182 	if (ring_buf_space_get(&cache_entry->rb) < element_size) {
2183 		/* No space  */
2184 		if (IS_ENABLED(CONFIG_LWM2M_CACHE_DROP_LATEST)) {
2185 			return false;
2186 		}
2187 		/* Free entry */
2188 		length = ring_buf_get_claim(&cache_entry->rb, &buf_ptr, element_size);
2189 		ring_buf_get_finish(&cache_entry->rb, length);
2190 	}
2191 
2192 	length = ring_buf_put_claim(&cache_entry->rb, &buf_ptr, element_size);
2193 
2194 	if (length != element_size) {
2195 		ring_buf_put_finish(&cache_entry->rb, 0);
2196 		LOG_ERR("Allocation failed %u", length);
2197 		return false;
2198 	}
2199 
2200 	ring_buf_put_finish(&cache_entry->rb, length);
2201 	/* Store data */
2202 	memcpy(buf_ptr, buf, element_size);
2203 	return true;
2204 #else
2205 	return NULL;
2206 #endif
2207 }
2208 
lwm2m_cache_read(struct lwm2m_time_series_resource * cache_entry,struct lwm2m_time_series_elem * buf)2209 bool lwm2m_cache_read(struct lwm2m_time_series_resource *cache_entry,
2210 		      struct lwm2m_time_series_elem *buf)
2211 {
2212 #if defined(CONFIG_LWM2M_RESOURCE_DATA_CACHE_SUPPORT)
2213 	uint32_t length;
2214 	uint8_t *buf_ptr;
2215 	uint32_t element_size = sizeof(struct lwm2m_time_series_elem);
2216 
2217 	if (ring_buf_is_empty(&cache_entry->rb)) {
2218 		return false;
2219 	}
2220 
2221 	length = ring_buf_get_claim(&cache_entry->rb, &buf_ptr, element_size);
2222 
2223 	if (length != element_size) {
2224 		LOG_ERR("Cache read fail %u", length);
2225 		ring_buf_get_finish(&cache_entry->rb, 0);
2226 		return false;
2227 	}
2228 
2229 	/* Read Data */
2230 	memcpy(buf, buf_ptr, element_size);
2231 	ring_buf_get_finish(&cache_entry->rb, length);
2232 	return true;
2233 
2234 #else
2235 	return NULL;
2236 #endif
2237 }
2238 
lwm2m_cache_size(const struct lwm2m_time_series_resource * cache_entry)2239 size_t lwm2m_cache_size(const struct lwm2m_time_series_resource *cache_entry)
2240 {
2241 #if defined(CONFIG_LWM2M_RESOURCE_DATA_CACHE_SUPPORT)
2242 	uint32_t bytes_available;
2243 
2244 	/* ring_buf_is_empty() takes non-const pointer but still does not modify */
2245 	if (ring_buf_is_empty((struct ring_buf *) &cache_entry->rb)) {
2246 		return 0;
2247 	}
2248 
2249 	/* ring_buf_size_get() takes non-const pointer but still does not modify */
2250 	bytes_available = ring_buf_size_get((struct ring_buf *) &cache_entry->rb);
2251 
2252 	return (bytes_available / sizeof(struct lwm2m_time_series_elem));
2253 #else
2254 	return 0;
2255 #endif
2256 }
2257