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_U16:
519 	case LWM2M_RES_TYPE_U8:
520 	case LWM2M_RES_TYPE_S64:
521 	case LWM2M_RES_TYPE_S32:
522 	case LWM2M_RES_TYPE_S16:
523 	case LWM2M_RES_TYPE_S8:
524 	case LWM2M_RES_TYPE_BOOL:
525 	case LWM2M_RES_TYPE_FLOAT:
526 	case LWM2M_RES_TYPE_OBJLNK:
527 		if (resource_length != buf_length) {
528 			return -EINVAL;
529 		}
530 		break;
531 	default:
532 		return 0;
533 	}
534 	return 0;
535 }
536 
lwm2m_engine_set(const struct lwm2m_obj_path * path,const void * value,uint16_t len)537 static int lwm2m_engine_set(const struct lwm2m_obj_path *path, const void *value, uint16_t len)
538 {
539 	struct lwm2m_engine_obj_inst *obj_inst;
540 	struct lwm2m_engine_obj_field *obj_field;
541 	struct lwm2m_engine_res *res = NULL;
542 	struct lwm2m_engine_res_inst *res_inst = NULL;
543 	void *data_ptr = NULL;
544 	size_t max_data_len = 0;
545 	int ret = 0;
546 	bool changed = false;
547 
548 	if (path->level < LWM2M_PATH_LEVEL_RESOURCE) {
549 		LOG_ERR("path must have at least 3 parts");
550 		return -EINVAL;
551 	}
552 
553 	LOG_DBG("path:%u/%u/%u, buf:%p, len:%d", path->obj_id, path->obj_inst_id,
554 		path->res_id, value, len);
555 
556 	k_mutex_lock(&registry_lock, K_FOREVER);
557 	/* look up resource obj */
558 	ret = path_to_objs(path, &obj_inst, &obj_field, &res, &res_inst);
559 	if (ret < 0) {
560 		k_mutex_unlock(&registry_lock);
561 		return ret;
562 	}
563 
564 	if (!res_inst) {
565 		LOG_ERR("res instance %d not found", path->res_inst_id);
566 		k_mutex_unlock(&registry_lock);
567 		return -ENOENT;
568 	}
569 
570 	if (LWM2M_HAS_RES_FLAG(res_inst, LWM2M_RES_DATA_FLAG_RO)) {
571 		LOG_ERR("res instance data pointer is read-only "
572 			"[%u/%u/%u/%u:lvl%u]", path->obj_id, path->obj_inst_id, path->res_id,
573 			path->res_inst_id, path->level);
574 		k_mutex_unlock(&registry_lock);
575 		return -EACCES;
576 	}
577 
578 	/* setup initial data elements */
579 	data_ptr = res_inst->data_ptr;
580 	max_data_len = res_inst->max_data_len;
581 
582 	/* allow user to override data elements via callback */
583 	if (res->pre_write_cb) {
584 		data_ptr = res->pre_write_cb(obj_inst->obj_inst_id, res->res_id,
585 					     res_inst->res_inst_id, &max_data_len);
586 	}
587 
588 	if (!data_ptr) {
589 		LOG_ERR("res instance data pointer is NULL [%u/%u/%u/%u:%u]", path->obj_id,
590 			path->obj_inst_id, path->res_id, path->res_inst_id, path->level);
591 		k_mutex_unlock(&registry_lock);
592 		return -EINVAL;
593 	}
594 
595 	ret = lwm2m_check_buf_sizes(obj_field->data_type, len, max_data_len);
596 	if (ret) {
597 		LOG_ERR("Incorrect buffer length %u for res data length %zu", len,
598 			max_data_len);
599 		k_mutex_unlock(&registry_lock);
600 		return ret;
601 	}
602 
603 	if (memcmp(data_ptr, value, len) != 0 || res_inst->data_len != len) {
604 		changed = true;
605 	}
606 
607 #if CONFIG_LWM2M_ENGINE_VALIDATION_BUFFER_SIZE > 0
608 	if (res->validate_cb) {
609 		ret = res->validate_cb(obj_inst->obj_inst_id, res->res_id, res_inst->res_inst_id,
610 				       (uint8_t *)value, len, false, 0, 0);
611 		if (ret < 0) {
612 			k_mutex_unlock(&registry_lock);
613 			return -EINVAL;
614 		}
615 	}
616 #endif /* CONFIG_LWM2M_ENGINE_VALIDATION_BUFFER_SIZE > 0 */
617 
618 	switch (obj_field->data_type) {
619 
620 	case LWM2M_RES_TYPE_OPAQUE:
621 		if (len) {
622 			memcpy((uint8_t *)data_ptr, value, len);
623 		}
624 		break;
625 
626 	case LWM2M_RES_TYPE_STRING:
627 		if (len) {
628 			strncpy(data_ptr, value, len - 1);
629 			((char *)data_ptr)[len - 1] = '\0';
630 		} else {
631 			((char *)data_ptr)[0] = '\0';
632 		}
633 		break;
634 
635 	case LWM2M_RES_TYPE_U32:
636 		*((uint32_t *)data_ptr) = *(uint32_t *)value;
637 		break;
638 
639 	case LWM2M_RES_TYPE_U16:
640 		*((uint16_t *)data_ptr) = *(uint16_t *)value;
641 		break;
642 
643 	case LWM2M_RES_TYPE_U8:
644 		*((uint8_t *)data_ptr) = *(uint8_t *)value;
645 		break;
646 
647 	case LWM2M_RES_TYPE_TIME:
648 		if (!lwm2m_validate_time_resource_lenghts(max_data_len, len)) {
649 			LOG_ERR("Time Set: buffer length %u  max data len %zu not supported", len,
650 				max_data_len);
651 			k_mutex_unlock(&registry_lock);
652 			return -EINVAL;
653 		}
654 
655 		if (max_data_len == sizeof(time_t)) {
656 			if (len == sizeof(time_t)) {
657 				*((time_t *)data_ptr) = *(time_t *)value;
658 			} else {
659 				*((time_t *)data_ptr) = (time_t) *((uint32_t *)value);
660 			}
661 		} else {
662 			LOG_WRN("Converting time to 32bit may cause integer overflow on resource "
663 				"[%u/%u/%u/%u:%u]", path->obj_id, path->obj_inst_id, path->res_id,
664 				path->res_inst_id, path->level);
665 			if (len == sizeof(uint32_t)) {
666 				*((uint32_t *)data_ptr) = *(uint32_t *)value;
667 			} else {
668 				*((uint32_t *)data_ptr) = (uint32_t) *((time_t *)value);
669 			}
670 		}
671 
672 		break;
673 
674 	case LWM2M_RES_TYPE_S64:
675 		*((int64_t *)data_ptr) = *(int64_t *)value;
676 		break;
677 
678 	case LWM2M_RES_TYPE_S32:
679 		*((int32_t *)data_ptr) = *(int32_t *)value;
680 		break;
681 
682 	case LWM2M_RES_TYPE_S16:
683 		*((int16_t *)data_ptr) = *(int16_t *)value;
684 		break;
685 
686 	case LWM2M_RES_TYPE_S8:
687 		*((int8_t *)data_ptr) = *(int8_t *)value;
688 		break;
689 
690 	case LWM2M_RES_TYPE_BOOL:
691 		*((bool *)data_ptr) = *(bool *)value;
692 		break;
693 
694 	case LWM2M_RES_TYPE_FLOAT:
695 		*(double *)data_ptr = *(double *)value;
696 		break;
697 
698 	case LWM2M_RES_TYPE_OBJLNK:
699 		*((struct lwm2m_objlnk *)data_ptr) = *(struct lwm2m_objlnk *)value;
700 		break;
701 
702 	default:
703 		LOG_ERR("unknown obj data_type %d", obj_field->data_type);
704 		k_mutex_unlock(&registry_lock);
705 		return -EINVAL;
706 	}
707 
708 	res_inst->data_len = len;
709 
710 	/* Cache Data Write */
711 #if defined(CONFIG_LWM2M_RESOURCE_DATA_CACHE_SUPPORT)
712 	lwm2m_engine_cache_write(obj_field, path, value, len);
713 #endif
714 
715 	if (res->post_write_cb) {
716 		ret = res->post_write_cb(obj_inst->obj_inst_id, res->res_id, res_inst->res_inst_id,
717 					 data_ptr, len, false, 0, 0);
718 	}
719 
720 	if (changed && LWM2M_HAS_PERM(obj_field, LWM2M_PERM_R)) {
721 		lwm2m_notify_observer_path(path);
722 	}
723 	k_mutex_unlock(&registry_lock);
724 	return ret;
725 }
726 
lwm2m_set_opaque(const struct lwm2m_obj_path * path,const char * data_ptr,uint16_t data_len)727 int lwm2m_set_opaque(const struct lwm2m_obj_path *path, const char *data_ptr, uint16_t data_len)
728 {
729 	return lwm2m_engine_set(path, data_ptr, data_len);
730 }
731 
lwm2m_set_string(const struct lwm2m_obj_path * path,const char * data_ptr)732 int lwm2m_set_string(const struct lwm2m_obj_path *path, const char *data_ptr)
733 {
734 	uint16_t len = strlen(data_ptr);
735 
736 	/* String resources contain terminator as well, opaque resources don't */
737 	if (is_string(path)) {
738 		len += 1;
739 	}
740 
741 	return lwm2m_engine_set(path, data_ptr, len);
742 }
743 
lwm2m_set_u8(const struct lwm2m_obj_path * path,uint8_t value)744 int lwm2m_set_u8(const struct lwm2m_obj_path *path, uint8_t value)
745 {
746 	return lwm2m_engine_set(path, &value, 1);
747 }
748 
lwm2m_set_u16(const struct lwm2m_obj_path * path,uint16_t value)749 int lwm2m_set_u16(const struct lwm2m_obj_path *path, uint16_t value)
750 {
751 	return lwm2m_engine_set(path, &value, 2);
752 }
753 
lwm2m_set_u32(const struct lwm2m_obj_path * path,uint32_t value)754 int lwm2m_set_u32(const struct lwm2m_obj_path *path, uint32_t value)
755 {
756 	return lwm2m_engine_set(path, &value, 4);
757 }
758 
lwm2m_set_s8(const struct lwm2m_obj_path * path,int8_t value)759 int lwm2m_set_s8(const struct lwm2m_obj_path *path, int8_t value)
760 {
761 	return lwm2m_engine_set(path, &value, 1);
762 }
763 
lwm2m_set_s16(const struct lwm2m_obj_path * path,int16_t value)764 int lwm2m_set_s16(const struct lwm2m_obj_path *path, int16_t value)
765 {
766 	return lwm2m_engine_set(path, &value, 2);
767 
768 }
769 
lwm2m_set_s32(const struct lwm2m_obj_path * path,int32_t value)770 int lwm2m_set_s32(const struct lwm2m_obj_path *path, int32_t value)
771 {
772 	return lwm2m_engine_set(path, &value, 4);
773 }
774 
lwm2m_set_s64(const struct lwm2m_obj_path * path,int64_t value)775 int lwm2m_set_s64(const struct lwm2m_obj_path *path, int64_t value)
776 {
777 	return lwm2m_engine_set(path, &value, 8);
778 }
779 
lwm2m_set_bool(const struct lwm2m_obj_path * path,bool value)780 int lwm2m_set_bool(const struct lwm2m_obj_path *path, bool value)
781 {
782 	uint8_t temp = (value != 0 ? 1 : 0);
783 
784 	return lwm2m_engine_set(path, &temp, 1);
785 }
786 
lwm2m_set_f64(const struct lwm2m_obj_path * path,const double value)787 int lwm2m_set_f64(const struct lwm2m_obj_path *path, const double value)
788 {
789 	return lwm2m_engine_set(path, &value, sizeof(double));
790 }
791 
lwm2m_set_objlnk(const struct lwm2m_obj_path * path,const struct lwm2m_objlnk * value)792 int lwm2m_set_objlnk(const struct lwm2m_obj_path *path, const struct lwm2m_objlnk *value)
793 {
794 	return lwm2m_engine_set(path, value, sizeof(struct lwm2m_objlnk));
795 }
796 
lwm2m_set_time(const struct lwm2m_obj_path * path,time_t value)797 int lwm2m_set_time(const struct lwm2m_obj_path *path, time_t value)
798 {
799 	return lwm2m_engine_set(path, &value, sizeof(time_t));
800 }
801 
lwm2m_set_res_data_len(const struct lwm2m_obj_path * path,uint16_t data_len)802 int lwm2m_set_res_data_len(const struct lwm2m_obj_path *path, uint16_t data_len)
803 {
804 	int ret;
805 	void *buffer_ptr;
806 	uint16_t buffer_len;
807 	uint16_t old_len;
808 	uint8_t data_flags;
809 
810 	ret = lwm2m_get_res_buf(path, &buffer_ptr, &buffer_len, &old_len, &data_flags);
811 	if (ret) {
812 		return ret;
813 	}
814 	return lwm2m_set_res_buf(path, buffer_ptr, buffer_len, data_len, data_flags);
815 }
816 /* User data getter functions */
817 
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)818 int lwm2m_get_res_buf(const struct lwm2m_obj_path *path, void **buffer_ptr, uint16_t *buffer_len,
819 		      uint16_t *data_len, uint8_t *data_flags)
820 {
821 	int ret;
822 	struct lwm2m_engine_res_inst *res_inst = NULL;
823 
824 	if (path->level < LWM2M_PATH_LEVEL_RESOURCE) {
825 		LOG_ERR("path must have at least 3 parts");
826 		return -EINVAL;
827 	}
828 
829 	k_mutex_lock(&registry_lock, K_FOREVER);
830 	/* look up resource obj */
831 	ret = path_to_objs(path, NULL, NULL, NULL, &res_inst);
832 	if (ret < 0) {
833 		k_mutex_unlock(&registry_lock);
834 		return ret;
835 	}
836 
837 	if (!res_inst) {
838 		LOG_ERR("res instance %d not found", path->res_inst_id);
839 		k_mutex_unlock(&registry_lock);
840 		return -ENOENT;
841 	}
842 
843 	if (buffer_ptr) {
844 		*buffer_ptr = res_inst->data_ptr;
845 	}
846 	if (buffer_len) {
847 		*buffer_len = res_inst->max_data_len;
848 	}
849 	if (data_len) {
850 		*data_len = res_inst->data_len;
851 	}
852 	if (data_flags) {
853 		*data_flags = res_inst->data_flags;
854 	}
855 
856 	k_mutex_unlock(&registry_lock);
857 	return 0;
858 }
859 
lwm2m_engine_get(const struct lwm2m_obj_path * path,void * buf,uint16_t buflen)860 static int lwm2m_engine_get(const struct lwm2m_obj_path *path, void *buf, uint16_t buflen)
861 {
862 	int ret = 0;
863 	struct lwm2m_engine_obj_inst *obj_inst;
864 	struct lwm2m_engine_obj_field *obj_field;
865 	struct lwm2m_engine_res *res = NULL;
866 	struct lwm2m_engine_res_inst *res_inst = NULL;
867 	void *data_ptr = NULL;
868 	size_t data_len = 0;
869 
870 	if (path->level < LWM2M_PATH_LEVEL_RESOURCE) {
871 		LOG_ERR("path must have at least 3 parts");
872 		return -EINVAL;
873 	}
874 	LOG_DBG("path:%u/%u/%u/%u, level %u, buf:%p, buflen:%d", path->obj_id, path->obj_inst_id,
875 		path->res_id, path->res_inst_id, path->level, buf, buflen);
876 
877 	k_mutex_lock(&registry_lock, K_FOREVER);
878 	/* look up resource obj */
879 	ret = path_to_objs(path, &obj_inst, &obj_field, &res, &res_inst);
880 	if (ret < 0) {
881 		k_mutex_unlock(&registry_lock);
882 		return ret;
883 	}
884 
885 	if (!res_inst) {
886 		LOG_ERR("res instance %d not found", path->res_inst_id);
887 		k_mutex_unlock(&registry_lock);
888 		return -ENOENT;
889 	}
890 
891 	/* setup initial data elements */
892 	data_ptr = res_inst->data_ptr;
893 	data_len = res_inst->data_len;
894 
895 	/* allow user to override data elements via callback */
896 	if (res->read_cb) {
897 		data_ptr = res->read_cb(obj_inst->obj_inst_id, res->res_id, res_inst->res_inst_id,
898 					&data_len);
899 	}
900 
901 	if (data_ptr && data_len > 0) {
902 		ret = lwm2m_check_buf_sizes(obj_field->data_type, data_len, buflen);
903 		if (ret) {
904 			LOG_ERR("Incorrect resource data length %zu. Buffer length %u", data_len,
905 				buflen);
906 			k_mutex_unlock(&registry_lock);
907 			return ret;
908 		}
909 
910 		switch (obj_field->data_type) {
911 
912 		case LWM2M_RES_TYPE_OPAQUE:
913 			memcpy(buf, data_ptr, data_len);
914 			break;
915 
916 		case LWM2M_RES_TYPE_STRING:
917 			strncpy(buf, data_ptr, data_len - 1);
918 			((char *)buf)[data_len - 1] = '\0';
919 			break;
920 
921 		case LWM2M_RES_TYPE_U32:
922 			*(uint32_t *)buf = *(uint32_t *)data_ptr;
923 			break;
924 		case LWM2M_RES_TYPE_TIME:
925 			if (!lwm2m_validate_time_resource_lenghts(data_len, buflen)) {
926 				LOG_ERR("Time get buffer length %u  data len %zu not supported",
927 					buflen, data_len);
928 				k_mutex_unlock(&registry_lock);
929 				return -EINVAL;
930 			}
931 
932 			if (data_len == sizeof(time_t)) {
933 				if (buflen == sizeof(time_t)) {
934 					*((time_t *)buf) = *(time_t *)data_ptr;
935 				} else {
936 					/* In this case get operation may not got correct value */
937 					LOG_WRN("Converting time to 32bit may cause integer "
938 						"overflow");
939 					*((uint32_t *)buf) = (uint32_t) *((time_t *)data_ptr);
940 				}
941 			} else {
942 				LOG_WRN("Converting time to 32bit may cause integer overflow");
943 				if (buflen == sizeof(uint32_t)) {
944 					*((uint32_t *)buf) = *(uint32_t *)data_ptr;
945 				} else {
946 					*((time_t *)buf) = (time_t) *((uint32_t *)data_ptr);
947 				}
948 			}
949 			break;
950 
951 		case LWM2M_RES_TYPE_U16:
952 			*(uint16_t *)buf = *(uint16_t *)data_ptr;
953 			break;
954 
955 		case LWM2M_RES_TYPE_U8:
956 			*(uint8_t *)buf = *(uint8_t *)data_ptr;
957 			break;
958 
959 		case LWM2M_RES_TYPE_S64:
960 			*(int64_t *)buf = *(int64_t *)data_ptr;
961 			break;
962 
963 		case LWM2M_RES_TYPE_S32:
964 			*(int32_t *)buf = *(int32_t *)data_ptr;
965 			break;
966 
967 		case LWM2M_RES_TYPE_S16:
968 			*(int16_t *)buf = *(int16_t *)data_ptr;
969 			break;
970 
971 		case LWM2M_RES_TYPE_S8:
972 			*(int8_t *)buf = *(int8_t *)data_ptr;
973 			break;
974 
975 		case LWM2M_RES_TYPE_BOOL:
976 			*(bool *)buf = *(bool *)data_ptr;
977 			break;
978 
979 		case LWM2M_RES_TYPE_FLOAT:
980 			*(double *)buf = *(double *)data_ptr;
981 			break;
982 
983 		case LWM2M_RES_TYPE_OBJLNK:
984 			*(struct lwm2m_objlnk *)buf = *(struct lwm2m_objlnk *)data_ptr;
985 			break;
986 
987 		default:
988 			LOG_ERR("unknown obj data_type %d", obj_field->data_type);
989 			k_mutex_unlock(&registry_lock);
990 			return -EINVAL;
991 		}
992 	} else if (obj_field->data_type == LWM2M_RES_TYPE_STRING) {
993 		/* Ensure empty string when there is no data */
994 		((char *)buf)[0] = '\0';
995 	}
996 	k_mutex_unlock(&registry_lock);
997 	return 0;
998 }
999 
lwm2m_get_opaque(const struct lwm2m_obj_path * path,void * buf,uint16_t buflen)1000 int lwm2m_get_opaque(const struct lwm2m_obj_path *path, void *buf, uint16_t buflen)
1001 {
1002 	return lwm2m_engine_get(path, buf, buflen);
1003 }
1004 
lwm2m_get_string(const struct lwm2m_obj_path * path,void * str,uint16_t buflen)1005 int lwm2m_get_string(const struct lwm2m_obj_path *path, void *str, uint16_t buflen)
1006 {
1007 	/* Ensure termination, in case resource is not a string type */
1008 	if (!is_string(path)) {
1009 		memset(str, 0, buflen);
1010 		buflen -= 1; /* Last terminator cannot be overwritten */
1011 	}
1012 
1013 	return lwm2m_engine_get(path, str, buflen);
1014 }
1015 
lwm2m_get_u8(const struct lwm2m_obj_path * path,uint8_t * value)1016 int lwm2m_get_u8(const struct lwm2m_obj_path *path, uint8_t *value)
1017 {
1018 	return lwm2m_engine_get(path, value, 1);
1019 }
1020 
lwm2m_get_u16(const struct lwm2m_obj_path * path,uint16_t * value)1021 int lwm2m_get_u16(const struct lwm2m_obj_path *path, uint16_t *value)
1022 {
1023 	return lwm2m_engine_get(path, value, 2);
1024 }
1025 
lwm2m_get_u32(const struct lwm2m_obj_path * path,uint32_t * value)1026 int lwm2m_get_u32(const struct lwm2m_obj_path *path, uint32_t *value)
1027 {
1028 	return lwm2m_engine_get(path, value, 4);
1029 }
1030 
lwm2m_get_s8(const struct lwm2m_obj_path * path,int8_t * value)1031 int lwm2m_get_s8(const struct lwm2m_obj_path *path, int8_t *value)
1032 {
1033 	return lwm2m_engine_get(path, value, 1);
1034 }
1035 
lwm2m_get_s16(const struct lwm2m_obj_path * path,int16_t * value)1036 int lwm2m_get_s16(const struct lwm2m_obj_path *path, int16_t *value)
1037 {
1038 	return lwm2m_engine_get(path, value, 2);
1039 }
1040 
lwm2m_get_s32(const struct lwm2m_obj_path * path,int32_t * value)1041 int lwm2m_get_s32(const struct lwm2m_obj_path *path, int32_t *value)
1042 {
1043 	return lwm2m_engine_get(path, value, 4);
1044 }
1045 
lwm2m_get_s64(const struct lwm2m_obj_path * path,int64_t * value)1046 int lwm2m_get_s64(const struct lwm2m_obj_path *path, int64_t *value)
1047 {
1048 	return lwm2m_engine_get(path, value, 8);
1049 }
1050 
lwm2m_get_bool(const struct lwm2m_obj_path * path,bool * value)1051 int lwm2m_get_bool(const struct lwm2m_obj_path *path, bool *value)
1052 {
1053 	int ret = 0;
1054 	int8_t temp = 0;
1055 
1056 	ret = lwm2m_get_s8(path, &temp);
1057 	if (!ret) {
1058 		*value = temp != 0;
1059 	}
1060 
1061 	return ret;
1062 }
1063 
lwm2m_get_f64(const struct lwm2m_obj_path * path,double * value)1064 int lwm2m_get_f64(const struct lwm2m_obj_path *path, double *value)
1065 {
1066 	return lwm2m_engine_get(path, value, sizeof(double));
1067 }
1068 
lwm2m_get_objlnk(const struct lwm2m_obj_path * path,struct lwm2m_objlnk * buf)1069 int lwm2m_get_objlnk(const struct lwm2m_obj_path *path, struct lwm2m_objlnk *buf)
1070 {
1071 	return lwm2m_engine_get(path, buf, sizeof(struct lwm2m_objlnk));
1072 }
1073 
lwm2m_get_time(const struct lwm2m_obj_path * path,time_t * buf)1074 int lwm2m_get_time(const struct lwm2m_obj_path *path, time_t *buf)
1075 {
1076 	return lwm2m_engine_get(path, buf, sizeof(time_t));
1077 }
1078 
lwm2m_get_resource(const struct lwm2m_obj_path * path,struct lwm2m_engine_res ** res)1079 int lwm2m_get_resource(const struct lwm2m_obj_path *path, struct lwm2m_engine_res **res)
1080 {
1081 	if (path->level < LWM2M_PATH_LEVEL_RESOURCE) {
1082 		LOG_ERR("path must have 3 parts");
1083 		return -EINVAL;
1084 	}
1085 
1086 	return path_to_objs(path, NULL, NULL, res, NULL);
1087 }
1088 
lwm2m_engine_get_opaque_more(struct lwm2m_input_context * in,uint8_t * buf,size_t buflen,struct lwm2m_opaque_context * opaque,bool * last_block)1089 size_t lwm2m_engine_get_opaque_more(struct lwm2m_input_context *in, uint8_t *buf, size_t buflen,
1090 				    struct lwm2m_opaque_context *opaque, bool *last_block)
1091 {
1092 	uint32_t in_len = opaque->remaining;
1093 	uint16_t remaining = in->in_cpkt->max_len - in->offset;
1094 
1095 	if (in_len > buflen) {
1096 		in_len = buflen;
1097 	}
1098 
1099 	if (in_len > remaining) {
1100 		in_len = remaining;
1101 	}
1102 
1103 	opaque->remaining -= in_len;
1104 	remaining -= in_len;
1105 	if (opaque->remaining == 0U || remaining == 0) {
1106 		*last_block = true;
1107 	}
1108 
1109 	if (buf_read(buf, in_len, CPKT_BUF_READ(in->in_cpkt), &in->offset) < 0) {
1110 		*last_block = true;
1111 		return 0;
1112 	}
1113 
1114 	return (size_t)in_len;
1115 }
1116 
lwm2m_engine_get_queue_mode(char * queue)1117 void lwm2m_engine_get_queue_mode(char *queue)
1118 {
1119 	if (IS_ENABLED(CONFIG_LWM2M_QUEUE_MODE_ENABLED)) {
1120 		strncpy(queue, "Q", QUEUE_OPT_MAX_LEN);
1121 	} else {
1122 		strncpy(queue, "", QUEUE_OPT_MAX_LEN);
1123 	}
1124 }
1125 
lwm2m_engine_get_binding(char * binding)1126 void lwm2m_engine_get_binding(char *binding)
1127 {
1128 	/* Defaults to UDP. */
1129 	strncpy(binding, "U", BINDING_OPT_MAX_LEN);
1130 #if CONFIG_LWM2M_VERSION_1_0
1131 	/* In LwM2M 1.0 binding and queue mode are in same parameter */
1132 	char queue[QUEUE_OPT_MAX_LEN];
1133 
1134 	lwm2m_engine_get_queue_mode(queue);
1135 	strncat(binding, queue, QUEUE_OPT_MAX_LEN);
1136 #endif
1137 }
1138 /* Engine resource instance */
1139 
lwm2m_engine_allocate_resource_instance(struct lwm2m_engine_res * res,struct lwm2m_engine_res_inst ** res_inst,uint8_t resource_instance_id)1140 static int lwm2m_engine_allocate_resource_instance(struct lwm2m_engine_res *res,
1141 						   struct lwm2m_engine_res_inst **res_inst,
1142 						   uint8_t resource_instance_id)
1143 {
1144 	int i;
1145 
1146 	if (!res->res_instances || res->res_inst_count == 0) {
1147 		return -ENOMEM;
1148 	}
1149 
1150 	for (i = 0; i < res->res_inst_count; i++) {
1151 		if (res->res_instances[i].res_inst_id == RES_INSTANCE_NOT_CREATED) {
1152 			break;
1153 		}
1154 	}
1155 
1156 	if (i >= res->res_inst_count) {
1157 		return -ENOMEM;
1158 	}
1159 
1160 	res->res_instances[i].res_inst_id = resource_instance_id;
1161 	*res_inst = &res->res_instances[i];
1162 	return 0;
1163 }
1164 
lwm2m_engine_get_create_res_inst(const struct lwm2m_obj_path * path,struct lwm2m_engine_res ** res,struct lwm2m_engine_res_inst ** res_inst)1165 int lwm2m_engine_get_create_res_inst(const struct lwm2m_obj_path *path,
1166 				     struct lwm2m_engine_res **res,
1167 				     struct lwm2m_engine_res_inst **res_inst)
1168 {
1169 	int ret;
1170 	struct lwm2m_engine_res *r = NULL;
1171 	struct lwm2m_engine_res_inst *r_i = NULL;
1172 
1173 	ret = path_to_objs(path, NULL, NULL, &r, &r_i);
1174 	if (ret < 0) {
1175 		return ret;
1176 	}
1177 
1178 	if (!r) {
1179 		return -ENOENT;
1180 	}
1181 	/* Store resource pointer */
1182 	*res = r;
1183 
1184 	if (!r_i) {
1185 		if (path->level < LWM2M_PATH_LEVEL_RESOURCE_INST) {
1186 			return -EINVAL;
1187 		}
1188 
1189 		ret = lwm2m_engine_allocate_resource_instance(r, &r_i, path->res_inst_id);
1190 		if (ret < 0) {
1191 			return ret;
1192 		}
1193 	}
1194 
1195 	/* Store resource instance pointer */
1196 	*res_inst = r_i;
1197 	return 0;
1198 }
1199 
lwm2m_create_res_inst(const struct lwm2m_obj_path * path)1200 int lwm2m_create_res_inst(const struct lwm2m_obj_path *path)
1201 {
1202 	int ret;
1203 	struct lwm2m_engine_res *res = NULL;
1204 	struct lwm2m_engine_res_inst *res_inst = NULL;
1205 
1206 	if (path->level < LWM2M_PATH_LEVEL_RESOURCE_INST) {
1207 		LOG_ERR("path must have 4 parts");
1208 		return -EINVAL;
1209 	}
1210 	k_mutex_lock(&registry_lock, K_FOREVER);
1211 	ret = path_to_objs(path, NULL, NULL, &res, &res_inst);
1212 	if (ret < 0) {
1213 		k_mutex_unlock(&registry_lock);
1214 		return ret;
1215 	}
1216 
1217 	if (!res) {
1218 		LOG_ERR("resource %u not found", path->res_id);
1219 		k_mutex_unlock(&registry_lock);
1220 		return -ENOENT;
1221 	}
1222 
1223 	if (res_inst && res_inst->res_inst_id != RES_INSTANCE_NOT_CREATED) {
1224 		LOG_ERR("res instance %u already exists", path->res_inst_id);
1225 		k_mutex_unlock(&registry_lock);
1226 		return -EINVAL;
1227 	}
1228 	k_mutex_unlock(&registry_lock);
1229 	return lwm2m_engine_allocate_resource_instance(res, &res_inst, path->res_inst_id);
1230 }
1231 
lwm2m_delete_res_inst(const struct lwm2m_obj_path * path)1232 int lwm2m_delete_res_inst(const struct lwm2m_obj_path *path)
1233 {
1234 	int ret;
1235 	struct lwm2m_engine_res_inst *res_inst = NULL;
1236 
1237 	if (path->level < LWM2M_PATH_LEVEL_RESOURCE_INST) {
1238 		LOG_ERR("path must have 4 parts");
1239 		return -EINVAL;
1240 	}
1241 	k_mutex_lock(&registry_lock, K_FOREVER);
1242 	ret = path_to_objs(path, NULL, NULL, NULL, &res_inst);
1243 	if (ret < 0) {
1244 		k_mutex_unlock(&registry_lock);
1245 		return ret;
1246 	}
1247 
1248 	if (!res_inst) {
1249 		LOG_ERR("res instance %u not found", path->res_inst_id);
1250 		k_mutex_unlock(&registry_lock);
1251 		return -ENOENT;
1252 	}
1253 
1254 	res_inst->data_ptr = NULL;
1255 	res_inst->max_data_len = 0U;
1256 	res_inst->data_len = 0U;
1257 	res_inst->res_inst_id = RES_INSTANCE_NOT_CREATED;
1258 	k_mutex_unlock(&registry_lock);
1259 	return 0;
1260 }
1261 /* Register callbacks */
1262 
lwm2m_register_read_callback(const struct lwm2m_obj_path * path,lwm2m_engine_get_data_cb_t cb)1263 int lwm2m_register_read_callback(const struct lwm2m_obj_path *path, lwm2m_engine_get_data_cb_t cb)
1264 {
1265 	int ret;
1266 	struct lwm2m_engine_res *res = NULL;
1267 
1268 	ret = lwm2m_get_resource(path, &res);
1269 	if (ret < 0) {
1270 		return ret;
1271 	}
1272 
1273 	res->read_cb = cb;
1274 	return 0;
1275 }
1276 
lwm2m_register_pre_write_callback(const struct lwm2m_obj_path * path,lwm2m_engine_get_data_cb_t cb)1277 int lwm2m_register_pre_write_callback(const struct lwm2m_obj_path *path,
1278 				      lwm2m_engine_get_data_cb_t cb)
1279 {
1280 	int ret;
1281 	struct lwm2m_engine_res *res = NULL;
1282 
1283 	ret = lwm2m_get_resource(path, &res);
1284 	if (ret < 0) {
1285 		return ret;
1286 	}
1287 
1288 	res->pre_write_cb = cb;
1289 	return 0;
1290 }
1291 
lwm2m_register_validate_callback(const struct lwm2m_obj_path * path,lwm2m_engine_set_data_cb_t cb)1292 int lwm2m_register_validate_callback(const struct lwm2m_obj_path *path,
1293 				     lwm2m_engine_set_data_cb_t cb)
1294 {
1295 #if CONFIG_LWM2M_ENGINE_VALIDATION_BUFFER_SIZE > 0
1296 	int ret;
1297 	struct lwm2m_engine_res *res = NULL;
1298 
1299 	ret = lwm2m_get_resource(path, &res);
1300 	if (ret < 0) {
1301 		return ret;
1302 	}
1303 
1304 	res->validate_cb = cb;
1305 	return 0;
1306 #else
1307 	ARG_UNUSED(path);
1308 	ARG_UNUSED(cb);
1309 
1310 	LOG_ERR("Validation disabled. Set "
1311 		"CONFIG_LWM2M_ENGINE_VALIDATION_BUFFER_SIZE > 0 to "
1312 		"enable validation support.");
1313 	return -ENOTSUP;
1314 #endif /* CONFIG_LWM2M_ENGINE_VALIDATION_BUFFER_SIZE > 0 */
1315 }
1316 
lwm2m_register_post_write_callback(const struct lwm2m_obj_path * path,lwm2m_engine_set_data_cb_t cb)1317 int lwm2m_register_post_write_callback(const struct lwm2m_obj_path *path,
1318 				       lwm2m_engine_set_data_cb_t cb)
1319 {
1320 	int ret;
1321 	struct lwm2m_engine_res *res = NULL;
1322 
1323 	ret = lwm2m_get_resource(path, &res);
1324 	if (ret < 0) {
1325 		return ret;
1326 	}
1327 
1328 	res->post_write_cb = cb;
1329 	return 0;
1330 }
1331 
lwm2m_register_exec_callback(const struct lwm2m_obj_path * path,lwm2m_engine_execute_cb_t cb)1332 int lwm2m_register_exec_callback(const struct lwm2m_obj_path *path, lwm2m_engine_execute_cb_t cb)
1333 {
1334 	int ret;
1335 	struct lwm2m_engine_res *res = NULL;
1336 
1337 	ret = lwm2m_get_resource(path, &res);
1338 	if (ret < 0) {
1339 		return ret;
1340 	}
1341 
1342 	res->execute_cb = cb;
1343 	return 0;
1344 }
1345 
lwm2m_register_create_callback(uint16_t obj_id,lwm2m_engine_user_cb_t cb)1346 int lwm2m_register_create_callback(uint16_t obj_id, lwm2m_engine_user_cb_t cb)
1347 {
1348 	struct lwm2m_engine_obj *obj = NULL;
1349 
1350 	obj = get_engine_obj(obj_id);
1351 	if (!obj) {
1352 		LOG_ERR("unable to find obj: %u", obj_id);
1353 		return -ENOENT;
1354 	}
1355 
1356 	obj->user_create_cb = cb;
1357 	return 0;
1358 }
1359 
lwm2m_register_delete_callback(uint16_t obj_id,lwm2m_engine_user_cb_t cb)1360 int lwm2m_register_delete_callback(uint16_t obj_id, lwm2m_engine_user_cb_t cb)
1361 {
1362 	struct lwm2m_engine_obj *obj = NULL;
1363 
1364 	obj = get_engine_obj(obj_id);
1365 	if (!obj) {
1366 		LOG_ERR("unable to find obj: %u", obj_id);
1367 		return -ENOENT;
1368 	}
1369 
1370 	obj->user_delete_cb = cb;
1371 	return 0;
1372 }
1373 /* Generic data handlers */
1374 
lwm2m_get_or_create_engine_obj(struct lwm2m_message * msg,struct lwm2m_engine_obj_inst ** obj_inst,uint8_t * created)1375 int lwm2m_get_or_create_engine_obj(struct lwm2m_message *msg,
1376 				   struct lwm2m_engine_obj_inst **obj_inst, uint8_t *created)
1377 {
1378 	int ret = 0;
1379 
1380 	if (created) {
1381 		*created = 0U;
1382 	}
1383 
1384 	*obj_inst = get_engine_obj_inst(msg->path.obj_id, msg->path.obj_inst_id);
1385 	if (!*obj_inst) {
1386 		ret = lwm2m_create_obj_inst(msg->path.obj_id, msg->path.obj_inst_id, obj_inst);
1387 		if (ret < 0) {
1388 			return ret;
1389 		}
1390 
1391 		/* set created flag to one */
1392 		if (created) {
1393 			*created = 1U;
1394 		}
1395 
1396 		if (!msg->ctx->bootstrap_mode) {
1397 			engine_trigger_update(true);
1398 		}
1399 	}
1400 
1401 	return ret;
1402 }
1403 
lwm2m_engine_get_res(const struct lwm2m_obj_path * path)1404 struct lwm2m_engine_res *lwm2m_engine_get_res(const struct lwm2m_obj_path *path)
1405 {
1406 	struct lwm2m_engine_res *res = NULL;
1407 	int ret;
1408 
1409 	if (path->level < LWM2M_PATH_LEVEL_RESOURCE) {
1410 		return NULL;
1411 	}
1412 
1413 	ret = path_to_objs(path, NULL, NULL, &res, NULL);
1414 	if (ret < 0) {
1415 		return NULL;
1416 	}
1417 
1418 	return res;
1419 }
1420 
lwm2m_engine_get_res_inst(const struct lwm2m_obj_path * path)1421 struct lwm2m_engine_res_inst *lwm2m_engine_get_res_inst(const struct lwm2m_obj_path *path)
1422 {
1423 	struct lwm2m_engine_res_inst *res_inst = NULL;
1424 	int ret;
1425 
1426 	if (path->level != LWM2M_PATH_LEVEL_RESOURCE_INST) {
1427 		return NULL;
1428 	}
1429 
1430 	ret = path_to_objs(path, NULL, NULL, NULL, &res_inst);
1431 	if (ret < 0) {
1432 		return NULL;
1433 	}
1434 
1435 	return res_inst;
1436 }
1437 
lwm2m_engine_shall_report_obj_version(const struct lwm2m_engine_obj * obj)1438 bool lwm2m_engine_shall_report_obj_version(const struct lwm2m_engine_obj *obj)
1439 {
1440 	if (IS_ENABLED(CONFIG_LWM2M_ENGINE_ALWAYS_REPORT_OBJ_VERSION)) {
1441 		return true;
1442 	}
1443 
1444 	/* For non-core objects, report version other than 1.0 */
1445 	if (!obj->is_core) {
1446 		return obj->version_major != 1 || obj->version_minor != 0;
1447 	}
1448 
1449 	/* For core objects, report version based on default version array. */
1450 	for (size_t i = 0; i < ARRAY_SIZE(default_obj_versions); i++) {
1451 		if (obj->obj_id != default_obj_versions[i].obj_id) {
1452 			continue;
1453 		}
1454 
1455 		return obj->version_major != default_obj_versions[i].version_major ||
1456 		       obj->version_minor != default_obj_versions[i].version_minor;
1457 	}
1458 
1459 	return true;
1460 }
1461 
1462 #if defined(CONFIG_LWM2M_RESOURCE_DATA_CACHE_SUPPORT)
1463 static sys_slist_t lwm2m_timed_cache_list;
1464 static struct lwm2m_time_series_resource lwm2m_cache_entries[CONFIG_LWM2M_MAX_CACHED_RESOURCES];
1465 
1466 static struct lwm2m_time_series_resource *
lwm2m_cache_entry_allocate(const struct lwm2m_obj_path * path)1467 lwm2m_cache_entry_allocate(const struct lwm2m_obj_path *path)
1468 {
1469 	int i;
1470 	struct lwm2m_time_series_resource *entry;
1471 
1472 	entry = lwm2m_cache_entry_get_by_object(path);
1473 	if (entry) {
1474 		return entry;
1475 	}
1476 
1477 	for (i = 0; i < ARRAY_SIZE(lwm2m_cache_entries); i++) {
1478 		if (lwm2m_cache_entries[i].path.level == 0) {
1479 			lwm2m_cache_entries[i].path = *path;
1480 			sys_slist_append(&lwm2m_timed_cache_list, &lwm2m_cache_entries[i].node);
1481 			return &lwm2m_cache_entries[i];
1482 		}
1483 	}
1484 
1485 	return NULL;
1486 }
1487 
lwm2m_engine_cache_write(const struct lwm2m_engine_obj_field * obj_field,const struct lwm2m_obj_path * path,const void * value,uint16_t len)1488 static void lwm2m_engine_cache_write(const struct lwm2m_engine_obj_field *obj_field,
1489 				     const struct lwm2m_obj_path *path, const void *value,
1490 				     uint16_t len)
1491 {
1492 	struct lwm2m_time_series_resource *cache_entry;
1493 	struct lwm2m_time_series_elem elements;
1494 
1495 	cache_entry = lwm2m_cache_entry_get_by_object(path);
1496 	if (!cache_entry) {
1497 		return;
1498 	}
1499 
1500 	elements.t = time(NULL);
1501 
1502 	if (elements.t  <= 0) {
1503 		LOG_WRN("Time() not available");
1504 		return;
1505 	}
1506 
1507 	switch (obj_field->data_type) {
1508 	case LWM2M_RES_TYPE_U32:
1509 		elements.u32 = *(uint32_t *)value;
1510 		break;
1511 
1512 	case LWM2M_RES_TYPE_U16:
1513 		elements.u16 = *(uint16_t *)value;
1514 		break;
1515 
1516 	case LWM2M_RES_TYPE_U8:
1517 		elements.u8 = *(uint8_t *)value;
1518 		break;
1519 
1520 	case LWM2M_RES_TYPE_S64:
1521 		elements.i64 = *(int64_t *)value;
1522 		break;
1523 
1524 	case LWM2M_RES_TYPE_TIME:
1525 		if (len == sizeof(time_t)) {
1526 			elements.time = *(time_t *)value;
1527 		} else if (len == sizeof(uint32_t)) {
1528 			elements.time = (time_t) *((uint32_t *)value);
1529 		} else {
1530 			LOG_ERR("Not supporting size %d bytes for time", len);
1531 			return;
1532 		}
1533 		break;
1534 
1535 	case LWM2M_RES_TYPE_S32:
1536 		elements.i32 = *(int32_t *)value;
1537 		break;
1538 
1539 	case LWM2M_RES_TYPE_S16:
1540 		elements.i16 = *(int16_t *)value;
1541 		break;
1542 
1543 	case LWM2M_RES_TYPE_S8:
1544 		elements.i8 = *(int8_t *)value;
1545 		break;
1546 
1547 	case LWM2M_RES_TYPE_BOOL:
1548 		elements.b = *(bool *)value;
1549 		break;
1550 
1551 	default:
1552 		elements.f = *(double *)value;
1553 		break;
1554 	}
1555 
1556 	if (!lwm2m_cache_write(cache_entry, &elements)) {
1557 		LOG_WRN("Data cache full");
1558 	}
1559 }
1560 #endif /* CONFIG_LWM2M_RESOURCE_DATA_CACHE_SUPPORT */
1561 
1562 struct lwm2m_time_series_resource *
lwm2m_cache_entry_get_by_object(const struct lwm2m_obj_path * obj_path)1563 lwm2m_cache_entry_get_by_object(const struct lwm2m_obj_path *obj_path)
1564 {
1565 #if defined(CONFIG_LWM2M_RESOURCE_DATA_CACHE_SUPPORT)
1566 	struct lwm2m_time_series_resource *entry;
1567 
1568 	if (obj_path->level < LWM2M_PATH_LEVEL_RESOURCE) {
1569 		LOG_ERR("Path level wrong for cache %u", obj_path->level);
1570 		return NULL;
1571 	}
1572 
1573 	if (sys_slist_is_empty(&lwm2m_timed_cache_list)) {
1574 		return NULL;
1575 	}
1576 
1577 	SYS_SLIST_FOR_EACH_CONTAINER(&lwm2m_timed_cache_list, entry, node) {
1578 		if (lwm2m_obj_path_equal(&entry->path, obj_path)) {
1579 			return entry;
1580 		}
1581 	}
1582 #endif /* CONFIG_LWM2M_RESOURCE_DATA_CACHE_SUPPORT */
1583 	return NULL;
1584 
1585 }
1586 
lwm2m_enable_cache(const struct lwm2m_obj_path * path,struct lwm2m_time_series_elem * data_cache,size_t cache_len)1587 int lwm2m_enable_cache(const struct lwm2m_obj_path *path, struct lwm2m_time_series_elem *data_cache,
1588 		       size_t cache_len)
1589 {
1590 #if defined(CONFIG_LWM2M_RESOURCE_DATA_CACHE_SUPPORT)
1591 	struct lwm2m_engine_obj_inst *obj_inst;
1592 	struct lwm2m_engine_obj_field *obj_field;
1593 	struct lwm2m_engine_res_inst *res_inst = NULL;
1594 	struct lwm2m_time_series_resource *cache_entry;
1595 	int ret = 0;
1596 	size_t cache_entry_size = sizeof(struct lwm2m_time_series_elem);
1597 
1598 	/* look up resource obj */
1599 	ret = path_to_objs(path, &obj_inst, &obj_field, NULL, &res_inst);
1600 	if (ret < 0) {
1601 		return ret;
1602 	}
1603 
1604 	if (!res_inst) {
1605 		LOG_ERR("res instance %d not found", path->res_inst_id);
1606 		return -ENOENT;
1607 	}
1608 
1609 	switch (obj_field->data_type) {
1610 	case LWM2M_RES_TYPE_U32:
1611 	case LWM2M_RES_TYPE_TIME:
1612 	case LWM2M_RES_TYPE_U16:
1613 	case LWM2M_RES_TYPE_U8:
1614 	case LWM2M_RES_TYPE_S64:
1615 	case LWM2M_RES_TYPE_S32:
1616 	case LWM2M_RES_TYPE_S16:
1617 	case LWM2M_RES_TYPE_S8:
1618 	case LWM2M_RES_TYPE_BOOL:
1619 	case LWM2M_RES_TYPE_FLOAT:
1620 		/* Support only fixed width resource types */
1621 		cache_entry = lwm2m_cache_entry_allocate(path);
1622 		break;
1623 	default:
1624 		cache_entry = NULL;
1625 		break;
1626 	}
1627 
1628 	if (!cache_entry) {
1629 		return -ENODATA;
1630 	}
1631 
1632 	ring_buf_init(&cache_entry->rb, cache_entry_size * cache_len, (uint8_t *)data_cache);
1633 
1634 	return 0;
1635 #else
1636 	LOG_ERR("LwM2M resource cache is only supported for "
1637 		"CONFIG_LWM2M_RESOURCE_DATA_CACHE_SUPPORT");
1638 	return -ENOTSUP;
1639 #endif /* CONFIG_LWM2M_RESOURCE_DATA_CACHE_SUPPORT */
1640 }
1641 
1642 #if defined(CONFIG_LWM2M_RESOURCE_DATA_CACHE_SUPPORT)
lwm2m_engine_data_cache_init(void)1643 static int lwm2m_engine_data_cache_init(void)
1644 {
1645 	int i;
1646 
1647 	sys_slist_init(&lwm2m_timed_cache_list);
1648 
1649 	for (i = 0; i < ARRAY_SIZE(lwm2m_cache_entries); i++) {
1650 		lwm2m_cache_entries[i].path.level = LWM2M_PATH_LEVEL_NONE;
1651 	}
1652 	return 0;
1653 }
1654 LWM2M_ENGINE_INIT(lwm2m_engine_data_cache_init);
1655 #endif
1656 
lwm2m_cache_write(struct lwm2m_time_series_resource * cache_entry,struct lwm2m_time_series_elem * buf)1657 bool lwm2m_cache_write(struct lwm2m_time_series_resource *cache_entry,
1658 		       struct lwm2m_time_series_elem *buf)
1659 {
1660 #if defined(CONFIG_LWM2M_RESOURCE_DATA_CACHE_SUPPORT)
1661 	uint32_t length;
1662 	uint8_t *buf_ptr;
1663 	uint32_t element_size = sizeof(struct lwm2m_time_series_elem);
1664 
1665 	if (ring_buf_space_get(&cache_entry->rb) < element_size) {
1666 		/* No space  */
1667 		if (IS_ENABLED(CONFIG_LWM2M_CACHE_DROP_LATEST)) {
1668 			return false;
1669 		}
1670 		/* Free entry */
1671 		length = ring_buf_get_claim(&cache_entry->rb, &buf_ptr, element_size);
1672 		ring_buf_get_finish(&cache_entry->rb, length);
1673 	}
1674 
1675 	length = ring_buf_put_claim(&cache_entry->rb, &buf_ptr, element_size);
1676 
1677 	if (length != element_size) {
1678 		ring_buf_put_finish(&cache_entry->rb, 0);
1679 		LOG_ERR("Allocation failed %u", length);
1680 		return false;
1681 	}
1682 
1683 	ring_buf_put_finish(&cache_entry->rb, length);
1684 	/* Store data */
1685 	memcpy(buf_ptr, buf, element_size);
1686 	return true;
1687 #else
1688 	return NULL;
1689 #endif
1690 }
1691 
lwm2m_cache_read(struct lwm2m_time_series_resource * cache_entry,struct lwm2m_time_series_elem * buf)1692 bool lwm2m_cache_read(struct lwm2m_time_series_resource *cache_entry,
1693 		      struct lwm2m_time_series_elem *buf)
1694 {
1695 #if defined(CONFIG_LWM2M_RESOURCE_DATA_CACHE_SUPPORT)
1696 	uint32_t length;
1697 	uint8_t *buf_ptr;
1698 	uint32_t element_size = sizeof(struct lwm2m_time_series_elem);
1699 
1700 	if (ring_buf_is_empty(&cache_entry->rb)) {
1701 		return false;
1702 	}
1703 
1704 	length = ring_buf_get_claim(&cache_entry->rb, &buf_ptr, element_size);
1705 
1706 	if (length != element_size) {
1707 		LOG_ERR("Cache read fail %u", length);
1708 		ring_buf_get_finish(&cache_entry->rb, 0);
1709 		return false;
1710 	}
1711 
1712 	/* Read Data */
1713 	memcpy(buf, buf_ptr, element_size);
1714 	ring_buf_get_finish(&cache_entry->rb, length);
1715 	return true;
1716 
1717 #else
1718 	return NULL;
1719 #endif
1720 }
1721 
lwm2m_cache_size(const struct lwm2m_time_series_resource * cache_entry)1722 size_t lwm2m_cache_size(const struct lwm2m_time_series_resource *cache_entry)
1723 {
1724 #if defined(CONFIG_LWM2M_RESOURCE_DATA_CACHE_SUPPORT)
1725 	uint32_t bytes_available;
1726 
1727 	/* ring_buf_is_empty() takes non-const pointer but still does not modify */
1728 	if (ring_buf_is_empty((struct ring_buf *) &cache_entry->rb)) {
1729 		return 0;
1730 	}
1731 
1732 	/* ring_buf_size_get() takes non-const pointer but still does not modify */
1733 	bytes_available = ring_buf_size_get((struct ring_buf *) &cache_entry->rb);
1734 
1735 	return (bytes_available / sizeof(struct lwm2m_time_series_elem));
1736 #else
1737 	return 0;
1738 #endif
1739 }
1740 
lwm2m_set_bulk(const struct lwm2m_res_item res_list[],size_t res_list_size)1741 int lwm2m_set_bulk(const struct lwm2m_res_item res_list[], size_t res_list_size)
1742 {
1743 	int ret;
1744 
1745 	k_mutex_lock(&registry_lock, K_FOREVER);
1746 	for (int i = 0; i < res_list_size; i++) {
1747 
1748 		ret = lwm2m_engine_set(res_list[i].path, res_list[i].value, res_list[i].size);
1749 
1750 		if (ret) {
1751 			k_mutex_unlock(&registry_lock);
1752 			return ret;
1753 		}
1754 	}
1755 	k_mutex_unlock(&registry_lock);
1756 
1757 	return 0;
1758 }
1759