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 
54 /* Default core object version */
55 struct default_obj_version {
56 	uint16_t obj_id;
57 	uint8_t version_major;
58 	uint8_t version_minor;
59 };
60 
61 /* Based on Appendix E of the respective LwM2M specification. */
62 static const struct default_obj_version default_obj_versions[] = {
63 #if defined(CONFIG_LWM2M_VERSION_1_0)
64 	{ LWM2M_OBJECT_SECURITY_ID, 1, 0 },
65 	{ LWM2M_OBJECT_SERVER_ID, 1, 0 },
66 	{ LWM2M_OBJECT_ACCESS_CONTROL_ID, 1, 0 },
67 	{ LWM2M_OBJECT_DEVICE_ID, 1, 0 },
68 	{ LWM2M_OBJECT_CONNECTIVITY_MONITORING_ID, 1, 0 },
69 	{ LWM2M_OBJECT_FIRMWARE_ID, 1, 0 },
70 	{ LWM2M_OBJECT_LOCATION_ID, 1, 0 },
71 	{ LWM2M_OBJECT_CONNECTIVITY_STATISTICS_ID, 1, 0 },
72 #elif defined(CONFIG_LWM2M_VERSION_1_1)
73 	{ LWM2M_OBJECT_SECURITY_ID, 1, 1 },
74 	{ LWM2M_OBJECT_SERVER_ID, 1, 1 },
75 	{ LWM2M_OBJECT_ACCESS_CONTROL_ID, 1, 0 },
76 	{ LWM2M_OBJECT_DEVICE_ID, 1, 1 },
77 	{ LWM2M_OBJECT_CONNECTIVITY_MONITORING_ID, 1, 2 },
78 	{ LWM2M_OBJECT_FIRMWARE_ID, 1, 0 },
79 	{ LWM2M_OBJECT_LOCATION_ID, 1, 0 },
80 	{ LWM2M_OBJECT_CONNECTIVITY_STATISTICS_ID, 1, 0 },
81 	/* OSCORE object not implemented yet, but include it for completeness */
82 	{ LWM2M_OBJECT_OSCORE_ID, 1, 0 },
83 #else
84 #error "Default core object versions not defined for LwM2M version"
85 #endif
86 };
87 
88 /* Resources */
89 static sys_slist_t engine_obj_list;
90 static sys_slist_t engine_obj_inst_list;
91 
92 /* Resource wrappers */
lwm2m_engine_obj_list(void)93 sys_slist_t *lwm2m_engine_obj_list(void) { return &engine_obj_list; }
94 
lwm2m_engine_obj_inst_list(void)95 sys_slist_t *lwm2m_engine_obj_inst_list(void) { return &engine_obj_inst_list; }
96 
97 #if defined(CONFIG_LWM2M_RESOURCE_DATA_CACHE_SUPPORT)
98 static void lwm2m_engine_cache_write(const struct lwm2m_engine_obj_field *obj_field,
99 				     const struct lwm2m_obj_path *path, const void *value,
100 				     uint16_t len);
101 #endif
102 /* Engine object */
103 
lwm2m_register_obj(struct lwm2m_engine_obj * obj)104 void lwm2m_register_obj(struct lwm2m_engine_obj *obj)
105 {
106 	k_mutex_lock(&registry_lock, K_FOREVER);
107 #if defined(CONFIG_LWM2M_ACCESS_CONTROL_ENABLE)
108 	/* If bootstrap, then bootstrap server should create the ac obj instances */
109 #if !defined(CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP)
110 	int server_obj_inst_id = lwm2m_server_short_id_to_inst(CONFIG_LWM2M_SERVER_DEFAULT_SSID);
111 
112 	access_control_add_obj(obj->obj_id, server_obj_inst_id);
113 #endif /* CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP */
114 #endif /* CONFIG_LWM2M_ACCESS_CONTROL_ENABLE */
115 	sys_slist_append(&engine_obj_list, &obj->node);
116 	k_mutex_unlock(&registry_lock);
117 }
118 
lwm2m_unregister_obj(struct lwm2m_engine_obj * obj)119 void lwm2m_unregister_obj(struct lwm2m_engine_obj *obj)
120 {
121 	k_mutex_lock(&registry_lock, K_FOREVER);
122 #if defined(CONFIG_LWM2M_ACCESS_CONTROL_ENABLE)
123 	access_control_remove_obj(obj->obj_id);
124 #endif
125 	engine_remove_observer_by_id(obj->obj_id, -1);
126 	sys_slist_find_and_remove(&engine_obj_list, &obj->node);
127 	k_mutex_unlock(&registry_lock);
128 }
129 
get_engine_obj(int obj_id)130 struct lwm2m_engine_obj *get_engine_obj(int obj_id)
131 {
132 	struct lwm2m_engine_obj *obj;
133 
134 	SYS_SLIST_FOR_EACH_CONTAINER(&engine_obj_list, obj, node) {
135 		if (obj->obj_id == obj_id) {
136 			return obj;
137 		}
138 	}
139 
140 	return NULL;
141 }
142 
lwm2m_get_engine_obj_field(struct lwm2m_engine_obj * obj,int res_id)143 struct lwm2m_engine_obj_field *lwm2m_get_engine_obj_field(struct lwm2m_engine_obj *obj, int res_id)
144 {
145 	int i;
146 
147 	if (obj && obj->fields && obj->field_count > 0) {
148 		for (i = 0; i < obj->field_count; i++) {
149 			if (obj->fields[i].res_id == res_id) {
150 				return &obj->fields[i];
151 			}
152 		}
153 	}
154 
155 	return NULL;
156 }
157 
lwm2m_engine_get_obj(const struct lwm2m_obj_path * path)158 struct lwm2m_engine_obj *lwm2m_engine_get_obj(const struct lwm2m_obj_path *path)
159 {
160 	if (path->level < LWM2M_PATH_LEVEL_OBJECT) {
161 		return NULL;
162 	}
163 
164 	return get_engine_obj(path->obj_id);
165 }
166 /* Engine object instance */
167 
engine_register_obj_inst(struct lwm2m_engine_obj_inst * obj_inst)168 static void engine_register_obj_inst(struct lwm2m_engine_obj_inst *obj_inst)
169 {
170 #if defined(CONFIG_LWM2M_ACCESS_CONTROL_ENABLE)
171 	/* If bootstrap, then bootstrap server should create the ac obj instances */
172 #if !defined(CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP)
173 	int server_obj_inst_id = lwm2m_server_short_id_to_inst(CONFIG_LWM2M_SERVER_DEFAULT_SSID);
174 
175 	access_control_add(obj_inst->obj->obj_id, obj_inst->obj_inst_id, server_obj_inst_id);
176 #endif /* CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP */
177 #endif /* CONFIG_LWM2M_ACCESS_CONTROL_ENABLE */
178 	sys_slist_append(&engine_obj_inst_list, &obj_inst->node);
179 }
180 
engine_unregister_obj_inst(struct lwm2m_engine_obj_inst * obj_inst)181 static void engine_unregister_obj_inst(struct lwm2m_engine_obj_inst *obj_inst)
182 {
183 #if defined(CONFIG_LWM2M_ACCESS_CONTROL_ENABLE)
184 	access_control_remove(obj_inst->obj->obj_id, obj_inst->obj_inst_id);
185 #endif
186 	engine_remove_observer_by_id(obj_inst->obj->obj_id, obj_inst->obj_inst_id);
187 	sys_slist_find_and_remove(&engine_obj_inst_list, &obj_inst->node);
188 }
189 
get_engine_obj_inst(int obj_id,int obj_inst_id)190 struct lwm2m_engine_obj_inst *get_engine_obj_inst(int obj_id, int obj_inst_id)
191 {
192 	struct lwm2m_engine_obj_inst *obj_inst;
193 
194 	SYS_SLIST_FOR_EACH_CONTAINER(&engine_obj_inst_list, obj_inst, node) {
195 		if (obj_inst->obj->obj_id == obj_id && obj_inst->obj_inst_id == obj_inst_id) {
196 			return obj_inst;
197 		}
198 	}
199 
200 	return NULL;
201 }
202 
next_engine_obj_inst(int obj_id,int obj_inst_id)203 struct lwm2m_engine_obj_inst *next_engine_obj_inst(int obj_id, int obj_inst_id)
204 {
205 	struct lwm2m_engine_obj_inst *obj_inst, *next = NULL;
206 
207 	SYS_SLIST_FOR_EACH_CONTAINER(&engine_obj_inst_list, obj_inst, node) {
208 		if (obj_inst->obj->obj_id == obj_id && obj_inst->obj_inst_id > obj_inst_id &&
209 		    (!next || next->obj_inst_id > obj_inst->obj_inst_id)) {
210 			next = obj_inst;
211 		}
212 	}
213 
214 	return next;
215 }
216 
lwm2m_create_obj_inst(uint16_t obj_id,uint16_t obj_inst_id,struct lwm2m_engine_obj_inst ** obj_inst)217 int lwm2m_create_obj_inst(uint16_t obj_id, uint16_t obj_inst_id,
218 			  struct lwm2m_engine_obj_inst **obj_inst)
219 {
220 	k_mutex_lock(&registry_lock, K_FOREVER);
221 	struct lwm2m_engine_obj *obj;
222 	int ret;
223 
224 	*obj_inst = NULL;
225 	obj = get_engine_obj(obj_id);
226 	if (!obj) {
227 		LOG_ERR("unable to find obj: %u", obj_id);
228 		k_mutex_unlock(&registry_lock);
229 		return -ENOENT;
230 	}
231 
232 	if (!obj->create_cb) {
233 		LOG_ERR("obj %u has no create_cb", obj_id);
234 		k_mutex_unlock(&registry_lock);
235 		return -EINVAL;
236 	}
237 
238 	if (obj->instance_count + 1 > obj->max_instance_count) {
239 		LOG_ERR("no more instances available for obj %u", obj_id);
240 		k_mutex_unlock(&registry_lock);
241 		return -ENOMEM;
242 	}
243 
244 	*obj_inst = obj->create_cb(obj_inst_id);
245 	if (!*obj_inst) {
246 		LOG_ERR("unable to create obj %u instance %u", obj_id, obj_inst_id);
247 		/*
248 		 * Already checked for instance count total.
249 		 * This can only be an error if the object instance exists.
250 		 */
251 		k_mutex_unlock(&registry_lock);
252 		return -EEXIST;
253 	}
254 
255 	obj->instance_count++;
256 	(*obj_inst)->obj = obj;
257 	(*obj_inst)->obj_inst_id = obj_inst_id;
258 	engine_register_obj_inst(*obj_inst);
259 
260 	if (obj->user_create_cb) {
261 		ret = obj->user_create_cb(obj_inst_id);
262 		if (ret < 0) {
263 			LOG_ERR("Error in user obj create %u/%u: %d", obj_id, obj_inst_id, ret);
264 			k_mutex_unlock(&registry_lock);
265 			lwm2m_delete_obj_inst(obj_id, obj_inst_id);
266 			return ret;
267 		}
268 	}
269 	k_mutex_unlock(&registry_lock);
270 	return 0;
271 }
272 
lwm2m_delete_obj_inst(uint16_t obj_id,uint16_t obj_inst_id)273 int lwm2m_delete_obj_inst(uint16_t obj_id, uint16_t obj_inst_id)
274 {
275 	k_mutex_lock(&registry_lock, K_FOREVER);
276 	int i, ret = 0;
277 	struct lwm2m_engine_obj *obj;
278 	struct lwm2m_engine_obj_inst *obj_inst;
279 
280 	obj = get_engine_obj(obj_id);
281 	if (!obj) {
282 		k_mutex_unlock(&registry_lock);
283 		return -ENOENT;
284 	}
285 
286 	obj_inst = get_engine_obj_inst(obj_id, obj_inst_id);
287 	if (!obj_inst) {
288 		k_mutex_unlock(&registry_lock);
289 		return -ENOENT;
290 	}
291 
292 	if (obj->user_delete_cb) {
293 		ret = obj->user_delete_cb(obj_inst_id);
294 		if (ret < 0) {
295 			LOG_ERR("Error in user obj delete %u/%u: %d", obj_id, obj_inst_id, ret);
296 			/* don't return error */
297 		}
298 	}
299 
300 	engine_unregister_obj_inst(obj_inst);
301 	obj->instance_count--;
302 
303 	if (obj->delete_cb) {
304 		ret = obj->delete_cb(obj_inst_id);
305 	}
306 
307 	/* reset obj_inst and res_inst data structure */
308 	for (i = 0; i < obj_inst->resource_count; i++) {
309 		clear_attrs(&obj_inst->resources[i]);
310 		(void)memset(obj_inst->resources + i, 0, sizeof(struct lwm2m_engine_res));
311 	}
312 
313 	clear_attrs(obj_inst);
314 	(void)memset(obj_inst, 0, sizeof(struct lwm2m_engine_obj_inst));
315 	k_mutex_unlock(&registry_lock);
316 	return ret;
317 }
318 
lwm2m_create_object_inst(const struct lwm2m_obj_path * path)319 int lwm2m_create_object_inst(const struct lwm2m_obj_path *path)
320 {
321 	struct lwm2m_engine_obj_inst *obj_inst;
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_create_obj_inst(path->obj_id, path->obj_inst_id, &obj_inst);
330 	if (ret < 0) {
331 		return ret;
332 	}
333 
334 	engine_trigger_update(true);
335 
336 	return 0;
337 }
338 
lwm2m_delete_object_inst(const struct lwm2m_obj_path * path)339 int lwm2m_delete_object_inst(const struct lwm2m_obj_path *path)
340 {
341 	int ret = 0;
342 
343 	if (path->level != LWM2M_PATH_LEVEL_OBJECT_INST) {
344 		LOG_ERR("path must have 2 parts");
345 		return -EINVAL;
346 	}
347 
348 	ret = lwm2m_delete_obj_inst(path->obj_id, path->obj_inst_id);
349 	if (ret < 0) {
350 		return ret;
351 	}
352 
353 	engine_trigger_update(true);
354 
355 	return 0;
356 }
357 
lwm2m_engine_get_obj_inst(const struct lwm2m_obj_path * path)358 struct lwm2m_engine_obj_inst *lwm2m_engine_get_obj_inst(const struct lwm2m_obj_path *path)
359 {
360 	if (path->level < LWM2M_PATH_LEVEL_OBJECT_INST) {
361 		return NULL;
362 	}
363 
364 	return get_engine_obj_inst(path->obj_id, path->obj_inst_id);
365 }
366 
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)367 int path_to_objs(const struct lwm2m_obj_path *path, struct lwm2m_engine_obj_inst **obj_inst,
368 		 struct lwm2m_engine_obj_field **obj_field, struct lwm2m_engine_res **res,
369 		 struct lwm2m_engine_res_inst **res_inst)
370 {
371 	struct lwm2m_engine_obj_inst *oi;
372 	struct lwm2m_engine_obj_field *of;
373 	struct lwm2m_engine_res *r = NULL;
374 	struct lwm2m_engine_res_inst *ri = NULL;
375 	int i;
376 
377 	if (!path) {
378 		return -EINVAL;
379 	}
380 
381 	oi = get_engine_obj_inst(path->obj_id, path->obj_inst_id);
382 	if (!oi) {
383 		LOG_ERR("obj instance %d/%d not found", path->obj_id, path->obj_inst_id);
384 		return -ENOENT;
385 	}
386 
387 	if (!oi->resources || oi->resource_count == 0U) {
388 		LOG_ERR("obj instance has no resources");
389 		return -EINVAL;
390 	}
391 
392 	of = lwm2m_get_engine_obj_field(oi->obj, path->res_id);
393 	if (!of) {
394 		LOG_ERR("obj field %d not found", path->res_id);
395 		return -ENOENT;
396 	}
397 
398 	for (i = 0; i < oi->resource_count; i++) {
399 		if (oi->resources[i].res_id == path->res_id) {
400 			r = &oi->resources[i];
401 			break;
402 		}
403 	}
404 
405 	if (!r) {
406 		if (LWM2M_HAS_PERM(of, BIT(LWM2M_FLAG_OPTIONAL))) {
407 			LOG_DBG("resource %d not found", path->res_id);
408 		} else {
409 			LOG_ERR("resource %d not found", path->res_id);
410 		}
411 
412 		return -ENOENT;
413 	}
414 
415 	for (i = 0; i < r->res_inst_count; i++) {
416 		if (r->res_instances[i].res_inst_id == path->res_inst_id) {
417 			ri = &r->res_instances[i];
418 			break;
419 		}
420 	}
421 
422 	/* specifically don't complain about missing resource instance */
423 
424 	if (obj_inst) {
425 		*obj_inst = oi;
426 	}
427 
428 	if (obj_field) {
429 		*obj_field = of;
430 	}
431 
432 	if (res) {
433 		*res = r;
434 	}
435 
436 	if (ri && res_inst) {
437 		*res_inst = ri;
438 	}
439 
440 	return 0;
441 }
442 
is_string(const struct lwm2m_obj_path * path)443 static bool is_string(const struct lwm2m_obj_path *path)
444 {
445 	struct lwm2m_engine_obj_field *obj_field;
446 	int ret;
447 
448 	ret = path_to_objs(path, NULL, &obj_field, NULL, NULL);
449 	if (ret < 0 || !obj_field) {
450 		return false;
451 	}
452 	if (obj_field->data_type == LWM2M_RES_TYPE_STRING) {
453 		return true;
454 	}
455 	return false;
456 }
457 
458 /* User data setter functions */
459 
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)460 int lwm2m_set_res_buf(const struct lwm2m_obj_path *path, void *buffer_ptr, uint16_t buffer_len,
461 		      uint16_t data_len, uint8_t data_flags)
462 {
463 	int ret;
464 	struct lwm2m_engine_res_inst *res_inst = NULL;
465 
466 	if (path->level < LWM2M_PATH_LEVEL_RESOURCE) {
467 		LOG_ERR("path must have at least 3 parts");
468 		return -EINVAL;
469 	}
470 
471 	k_mutex_lock(&registry_lock, K_FOREVER);
472 	/* look up resource obj */
473 	ret = path_to_objs(path, NULL, NULL, NULL, &res_inst);
474 	if (ret < 0) {
475 		k_mutex_unlock(&registry_lock);
476 		return ret;
477 	}
478 
479 	if (!res_inst) {
480 		LOG_ERR("res instance %d not found", path->res_inst_id);
481 		k_mutex_unlock(&registry_lock);
482 		return -ENOENT;
483 	}
484 
485 	/* assign data elements */
486 	res_inst->data_ptr = buffer_ptr;
487 	res_inst->data_len = data_len;
488 	res_inst->max_data_len = buffer_len;
489 	res_inst->data_flags = data_flags;
490 
491 	k_mutex_unlock(&registry_lock);
492 	return ret;
493 }
494 
lwm2m_validate_time_resource_lenghts(uint16_t resource_length,uint16_t buf_length)495 static bool lwm2m_validate_time_resource_lenghts(uint16_t resource_length, uint16_t buf_length)
496 {
497 	if (resource_length != sizeof(time_t) && resource_length != sizeof(uint32_t)) {
498 		return false;
499 	}
500 
501 	if (buf_length != sizeof(time_t) && buf_length != sizeof(uint32_t)) {
502 		return false;
503 	}
504 
505 	return true;
506 }
507 
lwm2m_check_buf_sizes(uint8_t data_type,uint16_t resource_length,uint16_t buf_length)508 static int lwm2m_check_buf_sizes(uint8_t data_type, uint16_t resource_length, uint16_t buf_length)
509 {
510 	switch (data_type) {
511 	case LWM2M_RES_TYPE_OPAQUE:
512 	case LWM2M_RES_TYPE_STRING:
513 		if (resource_length > buf_length) {
514 			return -ENOMEM;
515 		}
516 		break;
517 	case LWM2M_RES_TYPE_U32:
518 	case LWM2M_RES_TYPE_U8:
519 	case LWM2M_RES_TYPE_S64:
520 	case LWM2M_RES_TYPE_S32:
521 	case LWM2M_RES_TYPE_S16:
522 	case LWM2M_RES_TYPE_S8:
523 	case LWM2M_RES_TYPE_BOOL:
524 	case LWM2M_RES_TYPE_FLOAT:
525 	case LWM2M_RES_TYPE_OBJLNK:
526 		if (resource_length != buf_length) {
527 			return -EINVAL;
528 		}
529 		break;
530 	default:
531 		return 0;
532 	}
533 	return 0;
534 }
535 
lwm2m_engine_set(const struct lwm2m_obj_path * path,const void * value,uint16_t len)536 static int lwm2m_engine_set(const struct lwm2m_obj_path *path, const void *value, uint16_t len)
537 {
538 	struct lwm2m_engine_obj_inst *obj_inst;
539 	struct lwm2m_engine_obj_field *obj_field;
540 	struct lwm2m_engine_res *res = NULL;
541 	struct lwm2m_engine_res_inst *res_inst = NULL;
542 	void *data_ptr = NULL;
543 	size_t max_data_len = 0;
544 	int ret = 0;
545 	bool changed = false;
546 
547 	if (path->level < LWM2M_PATH_LEVEL_RESOURCE) {
548 		LOG_ERR("path must have at least 3 parts");
549 		return -EINVAL;
550 	}
551 
552 	LOG_DBG("path:%u/%u/%u, buf:%p, len:%d", path->obj_id, path->obj_inst_id,
553 		path->res_id, value, len);
554 
555 	k_mutex_lock(&registry_lock, K_FOREVER);
556 	/* look up resource obj */
557 	ret = path_to_objs(path, &obj_inst, &obj_field, &res, &res_inst);
558 	if (ret < 0) {
559 		k_mutex_unlock(&registry_lock);
560 		return ret;
561 	}
562 
563 	if (!res_inst) {
564 		LOG_ERR("res instance %d not found", path->res_inst_id);
565 		k_mutex_unlock(&registry_lock);
566 		return -ENOENT;
567 	}
568 
569 	if (LWM2M_HAS_RES_FLAG(res_inst, LWM2M_RES_DATA_FLAG_RO)) {
570 		LOG_ERR("res instance data pointer is read-only "
571 			"[%u/%u/%u/%u:lvl%u]", path->obj_id, path->obj_inst_id, path->res_id,
572 			path->res_inst_id, path->level);
573 		k_mutex_unlock(&registry_lock);
574 		return -EACCES;
575 	}
576 
577 	/* setup initial data elements */
578 	data_ptr = res_inst->data_ptr;
579 	max_data_len = res_inst->max_data_len;
580 
581 	/* allow user to override data elements via callback */
582 	if (res->pre_write_cb) {
583 		data_ptr = res->pre_write_cb(obj_inst->obj_inst_id, res->res_id,
584 					     res_inst->res_inst_id, &max_data_len);
585 	}
586 
587 	if (!data_ptr) {
588 		LOG_ERR("res instance data pointer is NULL [%u/%u/%u/%u:%u]", path->obj_id,
589 			path->obj_inst_id, path->res_id, path->res_inst_id, path->level);
590 		k_mutex_unlock(&registry_lock);
591 		return -EINVAL;
592 	}
593 
594 	ret = lwm2m_check_buf_sizes(obj_field->data_type, len, max_data_len);
595 	if (ret) {
596 		LOG_ERR("Incorrect buffer length %u for res data length %zu", len,
597 			max_data_len);
598 		k_mutex_unlock(&registry_lock);
599 		return ret;
600 	}
601 
602 	if (memcmp(data_ptr, value, len) != 0 || res_inst->data_len != len) {
603 		changed = true;
604 	}
605 
606 #if CONFIG_LWM2M_ENGINE_VALIDATION_BUFFER_SIZE > 0
607 	if (res->validate_cb) {
608 		ret = res->validate_cb(obj_inst->obj_inst_id, res->res_id, res_inst->res_inst_id,
609 				       (uint8_t *)value, len, false, 0, 0);
610 		if (ret < 0) {
611 			k_mutex_unlock(&registry_lock);
612 			return -EINVAL;
613 		}
614 	}
615 #endif /* CONFIG_LWM2M_ENGINE_VALIDATION_BUFFER_SIZE > 0 */
616 
617 	switch (obj_field->data_type) {
618 
619 	case LWM2M_RES_TYPE_OPAQUE:
620 		if (len) {
621 			memcpy((uint8_t *)data_ptr, value, len);
622 		}
623 		break;
624 
625 	case LWM2M_RES_TYPE_STRING:
626 		if (len) {
627 			strncpy(data_ptr, value, len - 1);
628 			((char *)data_ptr)[len - 1] = '\0';
629 		} else {
630 			((char *)data_ptr)[0] = '\0';
631 		}
632 		break;
633 
634 	case LWM2M_RES_TYPE_U32:
635 		*((uint32_t *)data_ptr) = *(uint32_t *)value;
636 		break;
637 
638 	case LWM2M_RES_TYPE_U16:
639 		*((uint16_t *)data_ptr) = *(uint16_t *)value;
640 		break;
641 
642 	case LWM2M_RES_TYPE_U8:
643 		*((uint8_t *)data_ptr) = *(uint8_t *)value;
644 		break;
645 
646 	case LWM2M_RES_TYPE_TIME:
647 		if (!lwm2m_validate_time_resource_lenghts(max_data_len, len)) {
648 			LOG_ERR("Time Set: buffer length %u  max data len %zu not supported", len,
649 				max_data_len);
650 			return -EINVAL;
651 		}
652 
653 		if (max_data_len == sizeof(time_t)) {
654 			if (len == sizeof(time_t)) {
655 				*((time_t *)data_ptr) = *(time_t *)value;
656 			} else {
657 				*((time_t *)data_ptr) = (time_t) *((uint32_t *)value);
658 			}
659 		} else {
660 			LOG_WRN("Converting time to 32bit may cause integer overflow on resource "
661 				"[%u/%u/%u/%u:%u]", path->obj_id, path->obj_inst_id, path->res_id,
662 				path->res_inst_id, path->level);
663 			if (len == sizeof(uint32_t)) {
664 				*((uint32_t *)data_ptr) = *(uint32_t *)value;
665 			} else {
666 				*((uint32_t *)data_ptr) = (uint32_t) *((time_t *)value);
667 			}
668 		}
669 
670 		break;
671 
672 	case LWM2M_RES_TYPE_S64:
673 		*((int64_t *)data_ptr) = *(int64_t *)value;
674 		break;
675 
676 	case LWM2M_RES_TYPE_S32:
677 		*((int32_t *)data_ptr) = *(int32_t *)value;
678 		break;
679 
680 	case LWM2M_RES_TYPE_S16:
681 		*((int16_t *)data_ptr) = *(int16_t *)value;
682 		break;
683 
684 	case LWM2M_RES_TYPE_S8:
685 		*((int8_t *)data_ptr) = *(int8_t *)value;
686 		break;
687 
688 	case LWM2M_RES_TYPE_BOOL:
689 		*((bool *)data_ptr) = *(bool *)value;
690 		break;
691 
692 	case LWM2M_RES_TYPE_FLOAT:
693 		*(double *)data_ptr = *(double *)value;
694 		break;
695 
696 	case LWM2M_RES_TYPE_OBJLNK:
697 		*((struct lwm2m_objlnk *)data_ptr) = *(struct lwm2m_objlnk *)value;
698 		break;
699 
700 	default:
701 		LOG_ERR("unknown obj data_type %d", obj_field->data_type);
702 		k_mutex_unlock(&registry_lock);
703 		return -EINVAL;
704 	}
705 
706 	res_inst->data_len = len;
707 
708 	/* Cache Data Write */
709 #if defined(CONFIG_LWM2M_RESOURCE_DATA_CACHE_SUPPORT)
710 	lwm2m_engine_cache_write(obj_field, path, value, len);
711 #endif
712 
713 	if (res->post_write_cb) {
714 		ret = res->post_write_cb(obj_inst->obj_inst_id, res->res_id, res_inst->res_inst_id,
715 					 data_ptr, len, false, 0, 0);
716 	}
717 
718 	if (changed && LWM2M_HAS_PERM(obj_field, LWM2M_PERM_R)) {
719 		lwm2m_notify_observer_path(path);
720 	}
721 	k_mutex_unlock(&registry_lock);
722 	return ret;
723 }
724 
lwm2m_set_opaque(const struct lwm2m_obj_path * path,const char * data_ptr,uint16_t data_len)725 int lwm2m_set_opaque(const struct lwm2m_obj_path *path, const char *data_ptr, uint16_t data_len)
726 {
727 	return lwm2m_engine_set(path, data_ptr, data_len);
728 }
729 
lwm2m_set_string(const struct lwm2m_obj_path * path,const char * data_ptr)730 int lwm2m_set_string(const struct lwm2m_obj_path *path, const char *data_ptr)
731 {
732 	uint16_t len = strlen(data_ptr);
733 
734 	/* String resources contain terminator as well, opaque resources don't */
735 	if (is_string(path)) {
736 		len += 1;
737 	}
738 
739 	return lwm2m_engine_set(path, data_ptr, len);
740 }
741 
lwm2m_set_u8(const struct lwm2m_obj_path * path,uint8_t value)742 int lwm2m_set_u8(const struct lwm2m_obj_path *path, uint8_t value)
743 {
744 	return lwm2m_engine_set(path, &value, 1);
745 }
746 
lwm2m_set_u16(const struct lwm2m_obj_path * path,uint16_t value)747 int lwm2m_set_u16(const struct lwm2m_obj_path *path, uint16_t value)
748 {
749 	return lwm2m_engine_set(path, &value, 2);
750 }
751 
lwm2m_set_u32(const struct lwm2m_obj_path * path,uint32_t value)752 int lwm2m_set_u32(const struct lwm2m_obj_path *path, uint32_t value)
753 {
754 	return lwm2m_engine_set(path, &value, 4);
755 }
756 
lwm2m_set_u64(const struct lwm2m_obj_path * path,uint64_t value)757 int lwm2m_set_u64(const struct lwm2m_obj_path *path, uint64_t value)
758 {
759 	return lwm2m_engine_set(path, &value, 8);
760 }
761 
lwm2m_set_s8(const struct lwm2m_obj_path * path,int8_t value)762 int lwm2m_set_s8(const struct lwm2m_obj_path *path, int8_t value)
763 {
764 	return lwm2m_engine_set(path, &value, 1);
765 }
766 
lwm2m_set_s16(const struct lwm2m_obj_path * path,int16_t value)767 int lwm2m_set_s16(const struct lwm2m_obj_path *path, int16_t value)
768 {
769 	return lwm2m_engine_set(path, &value, 2);
770 
771 }
772 
lwm2m_set_s32(const struct lwm2m_obj_path * path,int32_t value)773 int lwm2m_set_s32(const struct lwm2m_obj_path *path, int32_t value)
774 {
775 	return lwm2m_engine_set(path, &value, 4);
776 }
777 
lwm2m_set_s64(const struct lwm2m_obj_path * path,int64_t value)778 int lwm2m_set_s64(const struct lwm2m_obj_path *path, int64_t value)
779 {
780 	return lwm2m_engine_set(path, &value, 8);
781 }
782 
lwm2m_set_bool(const struct lwm2m_obj_path * path,bool value)783 int lwm2m_set_bool(const struct lwm2m_obj_path *path, bool value)
784 {
785 	uint8_t temp = (value != 0 ? 1 : 0);
786 
787 	return lwm2m_engine_set(path, &temp, 1);
788 }
789 
lwm2m_set_f64(const struct lwm2m_obj_path * path,const double value)790 int lwm2m_set_f64(const struct lwm2m_obj_path *path, const double value)
791 {
792 	return lwm2m_engine_set(path, &value, sizeof(double));
793 }
794 
lwm2m_set_objlnk(const struct lwm2m_obj_path * path,const struct lwm2m_objlnk * value)795 int lwm2m_set_objlnk(const struct lwm2m_obj_path *path, const struct lwm2m_objlnk *value)
796 {
797 	return lwm2m_engine_set(path, value, sizeof(struct lwm2m_objlnk));
798 }
799 
lwm2m_set_time(const struct lwm2m_obj_path * path,time_t value)800 int lwm2m_set_time(const struct lwm2m_obj_path *path, time_t value)
801 {
802 	return lwm2m_engine_set(path, &value, sizeof(time_t));
803 }
804 
lwm2m_set_res_data_len(const struct lwm2m_obj_path * path,uint16_t data_len)805 int lwm2m_set_res_data_len(const struct lwm2m_obj_path *path, uint16_t data_len)
806 {
807 	int ret;
808 	void *buffer_ptr;
809 	uint16_t buffer_len;
810 	uint16_t old_len;
811 	uint8_t data_flags;
812 
813 	ret = lwm2m_get_res_buf(path, &buffer_ptr, &buffer_len, &old_len, &data_flags);
814 	if (ret) {
815 		return ret;
816 	}
817 	return lwm2m_set_res_buf(path, buffer_ptr, buffer_len, data_len, data_flags);
818 }
819 /* User data getter functions */
820 
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)821 int lwm2m_get_res_buf(const struct lwm2m_obj_path *path, void **buffer_ptr, uint16_t *buffer_len,
822 		      uint16_t *data_len, uint8_t *data_flags)
823 {
824 	int ret;
825 	struct lwm2m_engine_res_inst *res_inst = NULL;
826 
827 	if (path->level < LWM2M_PATH_LEVEL_RESOURCE) {
828 		LOG_ERR("path must have at least 3 parts");
829 		return -EINVAL;
830 	}
831 
832 	k_mutex_lock(&registry_lock, K_FOREVER);
833 	/* look up resource obj */
834 	ret = path_to_objs(path, NULL, NULL, NULL, &res_inst);
835 	if (ret < 0) {
836 		k_mutex_unlock(&registry_lock);
837 		return ret;
838 	}
839 
840 	if (!res_inst) {
841 		LOG_ERR("res instance %d not found", path->res_inst_id);
842 		k_mutex_unlock(&registry_lock);
843 		return -ENOENT;
844 	}
845 
846 	if (buffer_ptr) {
847 		*buffer_ptr = res_inst->data_ptr;
848 	}
849 	if (buffer_len) {
850 		*buffer_len = res_inst->max_data_len;
851 	}
852 	if (data_len) {
853 		*data_len = res_inst->data_len;
854 	}
855 	if (data_flags) {
856 		*data_flags = res_inst->data_flags;
857 	}
858 
859 	k_mutex_unlock(&registry_lock);
860 	return 0;
861 }
862 
lwm2m_engine_get(const struct lwm2m_obj_path * path,void * buf,uint16_t buflen)863 static int lwm2m_engine_get(const struct lwm2m_obj_path *path, void *buf, uint16_t buflen)
864 {
865 	int ret = 0;
866 	struct lwm2m_engine_obj_inst *obj_inst;
867 	struct lwm2m_engine_obj_field *obj_field;
868 	struct lwm2m_engine_res *res = NULL;
869 	struct lwm2m_engine_res_inst *res_inst = NULL;
870 	void *data_ptr = NULL;
871 	size_t data_len = 0;
872 
873 	if (path->level < LWM2M_PATH_LEVEL_RESOURCE) {
874 		LOG_ERR("path must have at least 3 parts");
875 		return -EINVAL;
876 	}
877 	LOG_DBG("path:%u/%u/%u/%u, level %u, buf:%p, buflen:%d", path->obj_id, path->obj_inst_id,
878 		path->res_id, path->res_inst_id, path->level, buf, buflen);
879 
880 	k_mutex_lock(&registry_lock, K_FOREVER);
881 	/* look up resource obj */
882 	ret = path_to_objs(path, &obj_inst, &obj_field, &res, &res_inst);
883 	if (ret < 0) {
884 		k_mutex_unlock(&registry_lock);
885 		return ret;
886 	}
887 
888 	if (!res_inst) {
889 		LOG_ERR("res instance %d not found", path->res_inst_id);
890 		k_mutex_unlock(&registry_lock);
891 		return -ENOENT;
892 	}
893 
894 	/* setup initial data elements */
895 	data_ptr = res_inst->data_ptr;
896 	data_len = res_inst->data_len;
897 
898 	/* allow user to override data elements via callback */
899 	if (res->read_cb) {
900 		data_ptr = res->read_cb(obj_inst->obj_inst_id, res->res_id, res_inst->res_inst_id,
901 					&data_len);
902 	}
903 
904 	if (data_ptr && data_len > 0) {
905 		ret = lwm2m_check_buf_sizes(obj_field->data_type, data_len, buflen);
906 		if (ret) {
907 			LOG_ERR("Incorrect resource data length %zu. Buffer length %u", data_len,
908 				buflen);
909 			k_mutex_unlock(&registry_lock);
910 			return ret;
911 		}
912 
913 		switch (obj_field->data_type) {
914 
915 		case LWM2M_RES_TYPE_OPAQUE:
916 			memcpy(buf, data_ptr, data_len);
917 			break;
918 
919 		case LWM2M_RES_TYPE_STRING:
920 			strncpy(buf, data_ptr, data_len - 1);
921 			((char *)buf)[data_len - 1] = '\0';
922 			break;
923 
924 		case LWM2M_RES_TYPE_U32:
925 			*(uint32_t *)buf = *(uint32_t *)data_ptr;
926 			break;
927 		case LWM2M_RES_TYPE_TIME:
928 			if (!lwm2m_validate_time_resource_lenghts(data_len, buflen)) {
929 				LOG_ERR("Time get buffer length %u  data len %zu not supported",
930 					buflen, data_len);
931 				return -EINVAL;
932 			}
933 
934 			if (data_len == sizeof(time_t)) {
935 				if (buflen == sizeof(time_t)) {
936 					*((time_t *)buf) = *(time_t *)data_ptr;
937 				} else {
938 					/* In this case get operation may not got correct value */
939 					LOG_WRN("Converting time to 32bit may cause integer "
940 						"overflow");
941 					*((uint32_t *)buf) = (uint32_t) *((time_t *)data_ptr);
942 				}
943 			} else {
944 				LOG_WRN("Converting time to 32bit may cause integer overflow");
945 				if (buflen == sizeof(uint32_t)) {
946 					*((uint32_t *)buf) = *(uint32_t *)data_ptr;
947 				} else {
948 					*((time_t *)buf) = (time_t) *((uint32_t *)data_ptr);
949 				}
950 			}
951 			break;
952 
953 		case LWM2M_RES_TYPE_U16:
954 			*(uint16_t *)buf = *(uint16_t *)data_ptr;
955 			break;
956 
957 		case LWM2M_RES_TYPE_U8:
958 			*(uint8_t *)buf = *(uint8_t *)data_ptr;
959 			break;
960 
961 		case LWM2M_RES_TYPE_S64:
962 			*(int64_t *)buf = *(int64_t *)data_ptr;
963 			break;
964 
965 		case LWM2M_RES_TYPE_S32:
966 			*(int32_t *)buf = *(int32_t *)data_ptr;
967 			break;
968 
969 		case LWM2M_RES_TYPE_S16:
970 			*(int16_t *)buf = *(int16_t *)data_ptr;
971 			break;
972 
973 		case LWM2M_RES_TYPE_S8:
974 			*(int8_t *)buf = *(int8_t *)data_ptr;
975 			break;
976 
977 		case LWM2M_RES_TYPE_BOOL:
978 			*(bool *)buf = *(bool *)data_ptr;
979 			break;
980 
981 		case LWM2M_RES_TYPE_FLOAT:
982 			*(double *)buf = *(double *)data_ptr;
983 			break;
984 
985 		case LWM2M_RES_TYPE_OBJLNK:
986 			*(struct lwm2m_objlnk *)buf = *(struct lwm2m_objlnk *)data_ptr;
987 			break;
988 
989 		default:
990 			LOG_ERR("unknown obj data_type %d", obj_field->data_type);
991 			k_mutex_unlock(&registry_lock);
992 			return -EINVAL;
993 		}
994 	} else if (obj_field->data_type == LWM2M_RES_TYPE_STRING) {
995 		/* Ensure empty string when there is no data */
996 		((char *)buf)[0] = '\0';
997 	}
998 	k_mutex_unlock(&registry_lock);
999 	return 0;
1000 }
1001 
lwm2m_get_opaque(const struct lwm2m_obj_path * path,void * buf,uint16_t buflen)1002 int lwm2m_get_opaque(const struct lwm2m_obj_path *path, void *buf, uint16_t buflen)
1003 {
1004 	return lwm2m_engine_get(path, buf, buflen);
1005 }
1006 
lwm2m_get_string(const struct lwm2m_obj_path * path,void * str,uint16_t buflen)1007 int lwm2m_get_string(const struct lwm2m_obj_path *path, void *str, uint16_t buflen)
1008 {
1009 	/* Ensure termination, in case resource is not a string type */
1010 	if (!is_string(path)) {
1011 		memset(str, 0, buflen);
1012 		buflen -= 1; /* Last terminator cannot be overwritten */
1013 	}
1014 
1015 	return lwm2m_engine_get(path, str, buflen);
1016 }
1017 
lwm2m_get_u8(const struct lwm2m_obj_path * path,uint8_t * value)1018 int lwm2m_get_u8(const struct lwm2m_obj_path *path, uint8_t *value)
1019 {
1020 	return lwm2m_engine_get(path, value, 1);
1021 }
1022 
lwm2m_get_u16(const struct lwm2m_obj_path * path,uint16_t * value)1023 int lwm2m_get_u16(const struct lwm2m_obj_path *path, uint16_t *value)
1024 {
1025 	return lwm2m_engine_get(path, value, 2);
1026 }
1027 
lwm2m_get_u32(const struct lwm2m_obj_path * path,uint32_t * value)1028 int lwm2m_get_u32(const struct lwm2m_obj_path *path, uint32_t *value)
1029 {
1030 	return lwm2m_engine_get(path, value, 4);
1031 }
1032 
lwm2m_get_u64(const struct lwm2m_obj_path * path,uint64_t * value)1033 int lwm2m_get_u64(const struct lwm2m_obj_path *path, uint64_t *value)
1034 {
1035 	return lwm2m_engine_get(path, value, 8);
1036 }
1037 
lwm2m_get_s8(const struct lwm2m_obj_path * path,int8_t * value)1038 int lwm2m_get_s8(const struct lwm2m_obj_path *path, int8_t *value)
1039 {
1040 	return lwm2m_engine_get(path, value, 1);
1041 }
1042 
lwm2m_get_s16(const struct lwm2m_obj_path * path,int16_t * value)1043 int lwm2m_get_s16(const struct lwm2m_obj_path *path, int16_t *value)
1044 {
1045 	return lwm2m_engine_get(path, value, 2);
1046 }
1047 
lwm2m_get_s32(const struct lwm2m_obj_path * path,int32_t * value)1048 int lwm2m_get_s32(const struct lwm2m_obj_path *path, int32_t *value)
1049 {
1050 	return lwm2m_engine_get(path, value, 4);
1051 }
1052 
lwm2m_get_s64(const struct lwm2m_obj_path * path,int64_t * value)1053 int lwm2m_get_s64(const struct lwm2m_obj_path *path, int64_t *value)
1054 {
1055 	return lwm2m_engine_get(path, value, 8);
1056 }
1057 
lwm2m_get_bool(const struct lwm2m_obj_path * path,bool * value)1058 int lwm2m_get_bool(const struct lwm2m_obj_path *path, bool *value)
1059 {
1060 	int ret = 0;
1061 	int8_t temp = 0;
1062 
1063 	ret = lwm2m_get_s8(path, &temp);
1064 	if (!ret) {
1065 		*value = temp != 0;
1066 	}
1067 
1068 	return ret;
1069 }
1070 
lwm2m_get_f64(const struct lwm2m_obj_path * path,double * value)1071 int lwm2m_get_f64(const struct lwm2m_obj_path *path, double *value)
1072 {
1073 	return lwm2m_engine_get(path, value, sizeof(double));
1074 }
1075 
lwm2m_get_objlnk(const struct lwm2m_obj_path * path,struct lwm2m_objlnk * buf)1076 int lwm2m_get_objlnk(const struct lwm2m_obj_path *path, struct lwm2m_objlnk *buf)
1077 {
1078 	return lwm2m_engine_get(path, buf, sizeof(struct lwm2m_objlnk));
1079 }
1080 
lwm2m_get_time(const struct lwm2m_obj_path * path,time_t * buf)1081 int lwm2m_get_time(const struct lwm2m_obj_path *path, time_t *buf)
1082 {
1083 	return lwm2m_engine_get(path, buf, sizeof(time_t));
1084 }
1085 
lwm2m_get_resource(const struct lwm2m_obj_path * path,struct lwm2m_engine_res ** res)1086 int lwm2m_get_resource(const struct lwm2m_obj_path *path, struct lwm2m_engine_res **res)
1087 {
1088 	if (path->level < LWM2M_PATH_LEVEL_RESOURCE) {
1089 		LOG_ERR("path must have 3 parts");
1090 		return -EINVAL;
1091 	}
1092 
1093 	return path_to_objs(path, NULL, NULL, res, NULL);
1094 }
1095 
lwm2m_engine_get_opaque_more(struct lwm2m_input_context * in,uint8_t * buf,size_t buflen,struct lwm2m_opaque_context * opaque,bool * last_block)1096 size_t lwm2m_engine_get_opaque_more(struct lwm2m_input_context *in, uint8_t *buf, size_t buflen,
1097 				    struct lwm2m_opaque_context *opaque, bool *last_block)
1098 {
1099 	uint32_t in_len = opaque->remaining;
1100 	uint16_t remaining = in->in_cpkt->max_len - in->offset;
1101 
1102 	if (in_len > buflen) {
1103 		in_len = buflen;
1104 	}
1105 
1106 	if (in_len > remaining) {
1107 		in_len = remaining;
1108 	}
1109 
1110 	opaque->remaining -= in_len;
1111 	remaining -= in_len;
1112 	if (opaque->remaining == 0U || remaining == 0) {
1113 		*last_block = true;
1114 	}
1115 
1116 	if (buf_read(buf, in_len, CPKT_BUF_READ(in->in_cpkt), &in->offset) < 0) {
1117 		*last_block = true;
1118 		return 0;
1119 	}
1120 
1121 	return (size_t)in_len;
1122 }
1123 
lwm2m_engine_get_queue_mode(char * queue)1124 void lwm2m_engine_get_queue_mode(char *queue)
1125 {
1126 	if (IS_ENABLED(CONFIG_LWM2M_QUEUE_MODE_ENABLED)) {
1127 		strncpy(queue, "Q", QUEUE_OPT_MAX_LEN);
1128 	} else {
1129 		strncpy(queue, "", QUEUE_OPT_MAX_LEN);
1130 	}
1131 }
1132 
lwm2m_engine_get_binding(char * binding)1133 void lwm2m_engine_get_binding(char *binding)
1134 {
1135 	/* Defaults to UDP. */
1136 	strncpy(binding, "U", BINDING_OPT_MAX_LEN);
1137 #if CONFIG_LWM2M_VERSION_1_0
1138 	/* In LwM2M 1.0 binding and queue mode are in same parameter */
1139 	char queue[QUEUE_OPT_MAX_LEN];
1140 
1141 	lwm2m_engine_get_queue_mode(queue);
1142 	strncat(binding, queue, QUEUE_OPT_MAX_LEN);
1143 #endif
1144 }
1145 /* Engine resource instance */
1146 
lwm2m_engine_allocate_resource_instance(struct lwm2m_engine_res * res,struct lwm2m_engine_res_inst ** res_inst,uint8_t resource_instance_id)1147 static int lwm2m_engine_allocate_resource_instance(struct lwm2m_engine_res *res,
1148 						   struct lwm2m_engine_res_inst **res_inst,
1149 						   uint8_t resource_instance_id)
1150 {
1151 	int i;
1152 
1153 	if (!res->res_instances || res->res_inst_count == 0) {
1154 		return -ENOMEM;
1155 	}
1156 
1157 	for (i = 0; i < res->res_inst_count; i++) {
1158 		if (res->res_instances[i].res_inst_id == RES_INSTANCE_NOT_CREATED) {
1159 			break;
1160 		}
1161 	}
1162 
1163 	if (i >= res->res_inst_count) {
1164 		return -ENOMEM;
1165 	}
1166 
1167 	res->res_instances[i].res_inst_id = resource_instance_id;
1168 	*res_inst = &res->res_instances[i];
1169 	return 0;
1170 }
1171 
lwm2m_engine_get_create_res_inst(const struct lwm2m_obj_path * path,struct lwm2m_engine_res ** res,struct lwm2m_engine_res_inst ** res_inst)1172 int lwm2m_engine_get_create_res_inst(const struct lwm2m_obj_path *path,
1173 				     struct lwm2m_engine_res **res,
1174 				     struct lwm2m_engine_res_inst **res_inst)
1175 {
1176 	int ret;
1177 	struct lwm2m_engine_res *r = NULL;
1178 	struct lwm2m_engine_res_inst *r_i = NULL;
1179 
1180 	ret = path_to_objs(path, NULL, NULL, &r, &r_i);
1181 	if (ret < 0) {
1182 		return ret;
1183 	}
1184 
1185 	if (!r) {
1186 		return -ENOENT;
1187 	}
1188 	/* Store resource pointer */
1189 	*res = r;
1190 
1191 	if (!r_i) {
1192 		if (path->level < LWM2M_PATH_LEVEL_RESOURCE_INST) {
1193 			return -EINVAL;
1194 		}
1195 
1196 		ret = lwm2m_engine_allocate_resource_instance(r, &r_i, path->res_inst_id);
1197 		if (ret < 0) {
1198 			return ret;
1199 		}
1200 	}
1201 
1202 	/* Store resource instance pointer */
1203 	*res_inst = r_i;
1204 	return 0;
1205 }
1206 
lwm2m_create_res_inst(const struct lwm2m_obj_path * path)1207 int lwm2m_create_res_inst(const struct lwm2m_obj_path *path)
1208 {
1209 	int ret;
1210 	struct lwm2m_engine_res *res = NULL;
1211 	struct lwm2m_engine_res_inst *res_inst = NULL;
1212 
1213 	if (path->level < LWM2M_PATH_LEVEL_RESOURCE_INST) {
1214 		LOG_ERR("path must have 4 parts");
1215 		return -EINVAL;
1216 	}
1217 	k_mutex_lock(&registry_lock, K_FOREVER);
1218 	ret = path_to_objs(path, NULL, NULL, &res, &res_inst);
1219 	if (ret < 0) {
1220 		k_mutex_unlock(&registry_lock);
1221 		return ret;
1222 	}
1223 
1224 	if (!res) {
1225 		LOG_ERR("resource %u not found", path->res_id);
1226 		k_mutex_unlock(&registry_lock);
1227 		return -ENOENT;
1228 	}
1229 
1230 	if (res_inst && res_inst->res_inst_id != RES_INSTANCE_NOT_CREATED) {
1231 		LOG_ERR("res instance %u already exists", path->res_inst_id);
1232 		k_mutex_unlock(&registry_lock);
1233 		return -EINVAL;
1234 	}
1235 	k_mutex_unlock(&registry_lock);
1236 	return lwm2m_engine_allocate_resource_instance(res, &res_inst, path->res_inst_id);
1237 }
1238 
lwm2m_delete_res_inst(const struct lwm2m_obj_path * path)1239 int lwm2m_delete_res_inst(const struct lwm2m_obj_path *path)
1240 {
1241 	int ret;
1242 	struct lwm2m_engine_res_inst *res_inst = NULL;
1243 
1244 	if (path->level < LWM2M_PATH_LEVEL_RESOURCE_INST) {
1245 		LOG_ERR("path must have 4 parts");
1246 		return -EINVAL;
1247 	}
1248 	k_mutex_lock(&registry_lock, K_FOREVER);
1249 	ret = path_to_objs(path, NULL, NULL, NULL, &res_inst);
1250 	if (ret < 0) {
1251 		k_mutex_unlock(&registry_lock);
1252 		return ret;
1253 	}
1254 
1255 	if (!res_inst) {
1256 		LOG_ERR("res instance %u not found", path->res_inst_id);
1257 		k_mutex_unlock(&registry_lock);
1258 		return -ENOENT;
1259 	}
1260 
1261 	res_inst->data_ptr = NULL;
1262 	res_inst->max_data_len = 0U;
1263 	res_inst->data_len = 0U;
1264 	res_inst->res_inst_id = RES_INSTANCE_NOT_CREATED;
1265 	k_mutex_unlock(&registry_lock);
1266 	return 0;
1267 }
1268 /* Register callbacks */
1269 
lwm2m_register_read_callback(const struct lwm2m_obj_path * path,lwm2m_engine_get_data_cb_t cb)1270 int lwm2m_register_read_callback(const struct lwm2m_obj_path *path, lwm2m_engine_get_data_cb_t cb)
1271 {
1272 	int ret;
1273 	struct lwm2m_engine_res *res = NULL;
1274 
1275 	ret = lwm2m_get_resource(path, &res);
1276 	if (ret < 0) {
1277 		return ret;
1278 	}
1279 
1280 	res->read_cb = cb;
1281 	return 0;
1282 }
1283 
lwm2m_register_pre_write_callback(const struct lwm2m_obj_path * path,lwm2m_engine_get_data_cb_t cb)1284 int lwm2m_register_pre_write_callback(const struct lwm2m_obj_path *path,
1285 				      lwm2m_engine_get_data_cb_t cb)
1286 {
1287 	int ret;
1288 	struct lwm2m_engine_res *res = NULL;
1289 
1290 	ret = lwm2m_get_resource(path, &res);
1291 	if (ret < 0) {
1292 		return ret;
1293 	}
1294 
1295 	res->pre_write_cb = cb;
1296 	return 0;
1297 }
1298 
lwm2m_register_validate_callback(const struct lwm2m_obj_path * path,lwm2m_engine_set_data_cb_t cb)1299 int lwm2m_register_validate_callback(const struct lwm2m_obj_path *path,
1300 				     lwm2m_engine_set_data_cb_t cb)
1301 {
1302 #if CONFIG_LWM2M_ENGINE_VALIDATION_BUFFER_SIZE > 0
1303 	int ret;
1304 	struct lwm2m_engine_res *res = NULL;
1305 
1306 	ret = lwm2m_get_resource(path, &res);
1307 	if (ret < 0) {
1308 		return ret;
1309 	}
1310 
1311 	res->validate_cb = cb;
1312 	return 0;
1313 #else
1314 	ARG_UNUSED(path);
1315 	ARG_UNUSED(cb);
1316 
1317 	LOG_ERR("Validation disabled. Set "
1318 		"CONFIG_LWM2M_ENGINE_VALIDATION_BUFFER_SIZE > 0 to "
1319 		"enable validation support.");
1320 	return -ENOTSUP;
1321 #endif /* CONFIG_LWM2M_ENGINE_VALIDATION_BUFFER_SIZE > 0 */
1322 }
1323 
lwm2m_register_post_write_callback(const struct lwm2m_obj_path * path,lwm2m_engine_set_data_cb_t cb)1324 int lwm2m_register_post_write_callback(const struct lwm2m_obj_path *path,
1325 				       lwm2m_engine_set_data_cb_t cb)
1326 {
1327 	int ret;
1328 	struct lwm2m_engine_res *res = NULL;
1329 
1330 	ret = lwm2m_get_resource(path, &res);
1331 	if (ret < 0) {
1332 		return ret;
1333 	}
1334 
1335 	res->post_write_cb = cb;
1336 	return 0;
1337 }
1338 
lwm2m_register_exec_callback(const struct lwm2m_obj_path * path,lwm2m_engine_execute_cb_t cb)1339 int lwm2m_register_exec_callback(const struct lwm2m_obj_path *path, lwm2m_engine_execute_cb_t cb)
1340 {
1341 	int ret;
1342 	struct lwm2m_engine_res *res = NULL;
1343 
1344 	ret = lwm2m_get_resource(path, &res);
1345 	if (ret < 0) {
1346 		return ret;
1347 	}
1348 
1349 	res->execute_cb = cb;
1350 	return 0;
1351 }
1352 
lwm2m_register_create_callback(uint16_t obj_id,lwm2m_engine_user_cb_t cb)1353 int lwm2m_register_create_callback(uint16_t obj_id, lwm2m_engine_user_cb_t cb)
1354 {
1355 	struct lwm2m_engine_obj *obj = NULL;
1356 
1357 	obj = get_engine_obj(obj_id);
1358 	if (!obj) {
1359 		LOG_ERR("unable to find obj: %u", obj_id);
1360 		return -ENOENT;
1361 	}
1362 
1363 	obj->user_create_cb = cb;
1364 	return 0;
1365 }
1366 
lwm2m_register_delete_callback(uint16_t obj_id,lwm2m_engine_user_cb_t cb)1367 int lwm2m_register_delete_callback(uint16_t obj_id, lwm2m_engine_user_cb_t cb)
1368 {
1369 	struct lwm2m_engine_obj *obj = NULL;
1370 
1371 	obj = get_engine_obj(obj_id);
1372 	if (!obj) {
1373 		LOG_ERR("unable to find obj: %u", obj_id);
1374 		return -ENOENT;
1375 	}
1376 
1377 	obj->user_delete_cb = cb;
1378 	return 0;
1379 }
1380 /* Generic data handlers */
1381 
lwm2m_get_or_create_engine_obj(struct lwm2m_message * msg,struct lwm2m_engine_obj_inst ** obj_inst,uint8_t * created)1382 int lwm2m_get_or_create_engine_obj(struct lwm2m_message *msg,
1383 				   struct lwm2m_engine_obj_inst **obj_inst, uint8_t *created)
1384 {
1385 	int ret = 0;
1386 
1387 	if (created) {
1388 		*created = 0U;
1389 	}
1390 
1391 	*obj_inst = get_engine_obj_inst(msg->path.obj_id, msg->path.obj_inst_id);
1392 	if (!*obj_inst) {
1393 		ret = lwm2m_create_obj_inst(msg->path.obj_id, msg->path.obj_inst_id, obj_inst);
1394 		if (ret < 0) {
1395 			return ret;
1396 		}
1397 
1398 		/* set created flag to one */
1399 		if (created) {
1400 			*created = 1U;
1401 		}
1402 
1403 		if (!msg->ctx->bootstrap_mode) {
1404 			engine_trigger_update(true);
1405 		}
1406 	}
1407 
1408 	return ret;
1409 }
1410 
lwm2m_engine_get_res(const struct lwm2m_obj_path * path)1411 struct lwm2m_engine_res *lwm2m_engine_get_res(const struct lwm2m_obj_path *path)
1412 {
1413 	struct lwm2m_engine_res *res = NULL;
1414 	int ret;
1415 
1416 	if (path->level < LWM2M_PATH_LEVEL_RESOURCE) {
1417 		return NULL;
1418 	}
1419 
1420 	ret = path_to_objs(path, NULL, NULL, &res, NULL);
1421 	if (ret < 0) {
1422 		return NULL;
1423 	}
1424 
1425 	return res;
1426 }
1427 
lwm2m_engine_get_res_inst(const struct lwm2m_obj_path * path)1428 struct lwm2m_engine_res_inst *lwm2m_engine_get_res_inst(const struct lwm2m_obj_path *path)
1429 {
1430 	struct lwm2m_engine_res_inst *res_inst = NULL;
1431 	int ret;
1432 
1433 	if (path->level != LWM2M_PATH_LEVEL_RESOURCE_INST) {
1434 		return NULL;
1435 	}
1436 
1437 	ret = path_to_objs(path, NULL, NULL, NULL, &res_inst);
1438 	if (ret < 0) {
1439 		return NULL;
1440 	}
1441 
1442 	return res_inst;
1443 }
1444 
lwm2m_engine_shall_report_obj_version(const struct lwm2m_engine_obj * obj)1445 bool lwm2m_engine_shall_report_obj_version(const struct lwm2m_engine_obj *obj)
1446 {
1447 	if (IS_ENABLED(CONFIG_LWM2M_ENGINE_ALWAYS_REPORT_OBJ_VERSION)) {
1448 		return true;
1449 	}
1450 
1451 	/* For non-core objects, report version other than 1.0 */
1452 	if (!obj->is_core) {
1453 		return obj->version_major != 1 || obj->version_minor != 0;
1454 	}
1455 
1456 	/* For core objects, report version based on default version array. */
1457 	for (size_t i = 0; i < ARRAY_SIZE(default_obj_versions); i++) {
1458 		if (obj->obj_id != default_obj_versions[i].obj_id) {
1459 			continue;
1460 		}
1461 
1462 		return obj->version_major != default_obj_versions[i].version_major ||
1463 		       obj->version_minor != default_obj_versions[i].version_minor;
1464 	}
1465 
1466 	return true;
1467 }
1468 
1469 #if defined(CONFIG_LWM2M_RESOURCE_DATA_CACHE_SUPPORT)
1470 static sys_slist_t lwm2m_timed_cache_list;
1471 static struct lwm2m_time_series_resource lwm2m_cache_entries[CONFIG_LWM2M_MAX_CACHED_RESOURCES];
1472 
1473 static struct lwm2m_time_series_resource *
lwm2m_cache_entry_allocate(const struct lwm2m_obj_path * path)1474 lwm2m_cache_entry_allocate(const struct lwm2m_obj_path *path)
1475 {
1476 	int i;
1477 	struct lwm2m_time_series_resource *entry;
1478 
1479 	entry = lwm2m_cache_entry_get_by_object(path);
1480 	if (entry) {
1481 		return entry;
1482 	}
1483 
1484 	for (i = 0; i < ARRAY_SIZE(lwm2m_cache_entries); i++) {
1485 		if (lwm2m_cache_entries[i].path.level == 0) {
1486 			lwm2m_cache_entries[i].path = *path;
1487 			sys_slist_append(&lwm2m_timed_cache_list, &lwm2m_cache_entries[i].node);
1488 			return &lwm2m_cache_entries[i];
1489 		}
1490 	}
1491 
1492 	return NULL;
1493 }
1494 
lwm2m_engine_cache_write(const struct lwm2m_engine_obj_field * obj_field,const struct lwm2m_obj_path * path,const void * value,uint16_t len)1495 static void lwm2m_engine_cache_write(const struct lwm2m_engine_obj_field *obj_field,
1496 				     const struct lwm2m_obj_path *path, const void *value,
1497 				     uint16_t len)
1498 {
1499 	struct lwm2m_time_series_resource *cache_entry;
1500 	struct lwm2m_time_series_elem elements;
1501 
1502 	cache_entry = lwm2m_cache_entry_get_by_object(path);
1503 	if (!cache_entry) {
1504 		return;
1505 	}
1506 
1507 	elements.t = time(NULL);
1508 
1509 	if (elements.t  <= 0) {
1510 		LOG_WRN("Time() not available");
1511 		return;
1512 	}
1513 
1514 	switch (obj_field->data_type) {
1515 	case LWM2M_RES_TYPE_U32:
1516 		elements.u32 = *(uint32_t *)value;
1517 		break;
1518 
1519 	case LWM2M_RES_TYPE_U16:
1520 		elements.u16 = *(uint16_t *)value;
1521 		break;
1522 
1523 	case LWM2M_RES_TYPE_U8:
1524 		elements.u8 = *(uint8_t *)value;
1525 		break;
1526 
1527 	case LWM2M_RES_TYPE_S64:
1528 		elements.i64 = *(int64_t *)value;
1529 		break;
1530 
1531 	case LWM2M_RES_TYPE_TIME:
1532 		if (len == sizeof(time_t)) {
1533 			elements.time = *(time_t *)value;
1534 		} else if (len == sizeof(uint32_t)) {
1535 			elements.time = (time_t) *((uint32_t *)value);
1536 		} else {
1537 			LOG_ERR("Not supporting size %d bytes for time", len);
1538 			return;
1539 		}
1540 		break;
1541 
1542 	case LWM2M_RES_TYPE_S32:
1543 		elements.i32 = *(int32_t *)value;
1544 		break;
1545 
1546 	case LWM2M_RES_TYPE_S16:
1547 		elements.i16 = *(int16_t *)value;
1548 		break;
1549 
1550 	case LWM2M_RES_TYPE_S8:
1551 		elements.i8 = *(int8_t *)value;
1552 		break;
1553 
1554 	case LWM2M_RES_TYPE_BOOL:
1555 		elements.b = *(bool *)value;
1556 		break;
1557 
1558 	default:
1559 		elements.f = *(double *)value;
1560 		break;
1561 	}
1562 
1563 	if (!lwm2m_cache_write(cache_entry, &elements)) {
1564 		LOG_WRN("Data cache full");
1565 	}
1566 }
1567 #endif /* CONFIG_LWM2M_RESOURCE_DATA_CACHE_SUPPORT */
1568 
1569 struct lwm2m_time_series_resource *
lwm2m_cache_entry_get_by_object(const struct lwm2m_obj_path * obj_path)1570 lwm2m_cache_entry_get_by_object(const struct lwm2m_obj_path *obj_path)
1571 {
1572 #if defined(CONFIG_LWM2M_RESOURCE_DATA_CACHE_SUPPORT)
1573 	struct lwm2m_time_series_resource *entry;
1574 
1575 	if (obj_path->level < LWM2M_PATH_LEVEL_RESOURCE) {
1576 		LOG_ERR("Path level wrong for cache %u", obj_path->level);
1577 		return NULL;
1578 	}
1579 
1580 	if (sys_slist_is_empty(&lwm2m_timed_cache_list)) {
1581 		return NULL;
1582 	}
1583 
1584 	SYS_SLIST_FOR_EACH_CONTAINER(&lwm2m_timed_cache_list, entry, node) {
1585 		if (lwm2m_obj_path_equal(&entry->path, obj_path)) {
1586 			return entry;
1587 		}
1588 	}
1589 #endif /* CONFIG_LWM2M_RESOURCE_DATA_CACHE_SUPPORT */
1590 	return NULL;
1591 
1592 }
1593 
lwm2m_enable_cache(const struct lwm2m_obj_path * path,struct lwm2m_time_series_elem * data_cache,size_t cache_len)1594 int lwm2m_enable_cache(const struct lwm2m_obj_path *path, struct lwm2m_time_series_elem *data_cache,
1595 		       size_t cache_len)
1596 {
1597 #if defined(CONFIG_LWM2M_RESOURCE_DATA_CACHE_SUPPORT)
1598 	struct lwm2m_engine_obj_inst *obj_inst;
1599 	struct lwm2m_engine_obj_field *obj_field;
1600 	struct lwm2m_engine_res_inst *res_inst = NULL;
1601 	struct lwm2m_time_series_resource *cache_entry;
1602 	int ret = 0;
1603 	size_t cache_entry_size = sizeof(struct lwm2m_time_series_elem);
1604 
1605 	/* look up resource obj */
1606 	ret = path_to_objs(path, &obj_inst, &obj_field, NULL, &res_inst);
1607 	if (ret < 0) {
1608 		return ret;
1609 	}
1610 
1611 	if (!res_inst) {
1612 		LOG_ERR("res instance %d not found", path->res_inst_id);
1613 		return -ENOENT;
1614 	}
1615 
1616 	switch (obj_field->data_type) {
1617 	case LWM2M_RES_TYPE_U32:
1618 	case LWM2M_RES_TYPE_TIME:
1619 	case LWM2M_RES_TYPE_U16:
1620 	case LWM2M_RES_TYPE_U8:
1621 	case LWM2M_RES_TYPE_S64:
1622 	case LWM2M_RES_TYPE_S32:
1623 	case LWM2M_RES_TYPE_S16:
1624 	case LWM2M_RES_TYPE_S8:
1625 	case LWM2M_RES_TYPE_BOOL:
1626 	case LWM2M_RES_TYPE_FLOAT:
1627 		/* Support only fixed width resource types */
1628 		cache_entry = lwm2m_cache_entry_allocate(path);
1629 		break;
1630 	default:
1631 		cache_entry = NULL;
1632 		break;
1633 	}
1634 
1635 	if (!cache_entry) {
1636 		return -ENODATA;
1637 	}
1638 
1639 	ring_buf_init(&cache_entry->rb, cache_entry_size * cache_len, (uint8_t *)data_cache);
1640 
1641 	return 0;
1642 #else
1643 	LOG_ERR("LwM2M resource cache is only supported for "
1644 		"CONFIG_LWM2M_RESOURCE_DATA_CACHE_SUPPORT");
1645 	return -ENOTSUP;
1646 #endif /* CONFIG_LWM2M_RESOURCE_DATA_CACHE_SUPPORT */
1647 }
1648 
1649 #if defined(CONFIG_LWM2M_RESOURCE_DATA_CACHE_SUPPORT)
lwm2m_engine_data_cache_init(void)1650 static int lwm2m_engine_data_cache_init(void)
1651 {
1652 	int i;
1653 
1654 	sys_slist_init(&lwm2m_timed_cache_list);
1655 
1656 	for (i = 0; i < ARRAY_SIZE(lwm2m_cache_entries); i++) {
1657 		lwm2m_cache_entries[i].path.level = LWM2M_PATH_LEVEL_NONE;
1658 	}
1659 	return 0;
1660 }
1661 LWM2M_ENGINE_INIT(lwm2m_engine_data_cache_init);
1662 #endif
1663 
lwm2m_cache_write(struct lwm2m_time_series_resource * cache_entry,struct lwm2m_time_series_elem * buf)1664 bool lwm2m_cache_write(struct lwm2m_time_series_resource *cache_entry,
1665 		       struct lwm2m_time_series_elem *buf)
1666 {
1667 #if defined(CONFIG_LWM2M_RESOURCE_DATA_CACHE_SUPPORT)
1668 	uint32_t length;
1669 	uint8_t *buf_ptr;
1670 	uint32_t element_size = sizeof(struct lwm2m_time_series_elem);
1671 
1672 	if (ring_buf_space_get(&cache_entry->rb) < element_size) {
1673 		/* No space  */
1674 		if (IS_ENABLED(CONFIG_LWM2M_CACHE_DROP_LATEST)) {
1675 			return false;
1676 		}
1677 		/* Free entry */
1678 		length = ring_buf_get_claim(&cache_entry->rb, &buf_ptr, element_size);
1679 		ring_buf_get_finish(&cache_entry->rb, length);
1680 	}
1681 
1682 	length = ring_buf_put_claim(&cache_entry->rb, &buf_ptr, element_size);
1683 
1684 	if (length != element_size) {
1685 		ring_buf_put_finish(&cache_entry->rb, 0);
1686 		LOG_ERR("Allocation failed %u", length);
1687 		return false;
1688 	}
1689 
1690 	ring_buf_put_finish(&cache_entry->rb, length);
1691 	/* Store data */
1692 	memcpy(buf_ptr, buf, element_size);
1693 	return true;
1694 #else
1695 	return NULL;
1696 #endif
1697 }
1698 
lwm2m_cache_read(struct lwm2m_time_series_resource * cache_entry,struct lwm2m_time_series_elem * buf)1699 bool lwm2m_cache_read(struct lwm2m_time_series_resource *cache_entry,
1700 		      struct lwm2m_time_series_elem *buf)
1701 {
1702 #if defined(CONFIG_LWM2M_RESOURCE_DATA_CACHE_SUPPORT)
1703 	uint32_t length;
1704 	uint8_t *buf_ptr;
1705 	uint32_t element_size = sizeof(struct lwm2m_time_series_elem);
1706 
1707 	if (ring_buf_is_empty(&cache_entry->rb)) {
1708 		return false;
1709 	}
1710 
1711 	length = ring_buf_get_claim(&cache_entry->rb, &buf_ptr, element_size);
1712 
1713 	if (length != element_size) {
1714 		LOG_ERR("Cache read fail %u", length);
1715 		ring_buf_get_finish(&cache_entry->rb, 0);
1716 		return false;
1717 	}
1718 
1719 	/* Read Data */
1720 	memcpy(buf, buf_ptr, element_size);
1721 	ring_buf_get_finish(&cache_entry->rb, length);
1722 	return true;
1723 
1724 #else
1725 	return NULL;
1726 #endif
1727 }
1728 
lwm2m_cache_size(const struct lwm2m_time_series_resource * cache_entry)1729 size_t lwm2m_cache_size(const struct lwm2m_time_series_resource *cache_entry)
1730 {
1731 #if defined(CONFIG_LWM2M_RESOURCE_DATA_CACHE_SUPPORT)
1732 	uint32_t bytes_available;
1733 
1734 	/* ring_buf_is_empty() takes non-const pointer but still does not modify */
1735 	if (ring_buf_is_empty((struct ring_buf *) &cache_entry->rb)) {
1736 		return 0;
1737 	}
1738 
1739 	/* ring_buf_size_get() takes non-const pointer but still does not modify */
1740 	bytes_available = ring_buf_size_get((struct ring_buf *) &cache_entry->rb);
1741 
1742 	return (bytes_available / sizeof(struct lwm2m_time_series_elem));
1743 #else
1744 	return 0;
1745 #endif
1746 }
1747 
lwm2m_set_bulk(const struct lwm2m_res_item res_list[],size_t res_list_size)1748 int lwm2m_set_bulk(const struct lwm2m_res_item res_list[], size_t res_list_size)
1749 {
1750 	int ret;
1751 
1752 	k_mutex_lock(&registry_lock, K_FOREVER);
1753 	for (int i = 0; i < res_list_size; i++) {
1754 
1755 		ret = lwm2m_engine_set(res_list[i].path, res_list[i].value, res_list[i].size);
1756 
1757 		if (ret) {
1758 			k_mutex_unlock(&registry_lock);
1759 			return ret;
1760 		}
1761 	}
1762 	k_mutex_unlock(&registry_lock);
1763 
1764 	return 0;
1765 }
1766