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->len - opaque->offset;
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 	remaining -= in_len;
1104 	if (opaque->offset + in_len >= opaque->len) {
1105 		*last_block = true;
1106 	}
1107 
1108 	if (buf_read(buf, in_len, CPKT_BUF_READ(in->in_cpkt), &in->offset) < 0) {
1109 		*last_block = true;
1110 		return 0;
1111 	}
1112 
1113 	return (size_t)in_len;
1114 }
1115 
lwm2m_engine_get_queue_mode(char * queue)1116 void lwm2m_engine_get_queue_mode(char *queue)
1117 {
1118 	if (IS_ENABLED(CONFIG_LWM2M_QUEUE_MODE_ENABLED)) {
1119 		strncpy(queue, "Q", QUEUE_OPT_MAX_LEN);
1120 	} else {
1121 		strncpy(queue, "", QUEUE_OPT_MAX_LEN);
1122 	}
1123 }
1124 
lwm2m_engine_get_binding(char * binding)1125 void lwm2m_engine_get_binding(char *binding)
1126 {
1127 	/* Defaults to UDP. */
1128 	strncpy(binding, "U", BINDING_OPT_MAX_LEN);
1129 #if CONFIG_LWM2M_VERSION_1_0
1130 	/* In LwM2M 1.0 binding and queue mode are in same parameter */
1131 	char queue[QUEUE_OPT_MAX_LEN];
1132 
1133 	lwm2m_engine_get_queue_mode(queue);
1134 	strncat(binding, queue, QUEUE_OPT_MAX_LEN);
1135 #endif
1136 }
1137 /* Engine resource instance */
1138 
lwm2m_engine_allocate_resource_instance(struct lwm2m_engine_res * res,struct lwm2m_engine_res_inst ** res_inst,uint8_t resource_instance_id)1139 static int lwm2m_engine_allocate_resource_instance(struct lwm2m_engine_res *res,
1140 						   struct lwm2m_engine_res_inst **res_inst,
1141 						   uint8_t resource_instance_id)
1142 {
1143 	int i;
1144 
1145 	if (!res->res_instances || res->res_inst_count == 0) {
1146 		return -ENOMEM;
1147 	}
1148 
1149 	for (i = 0; i < res->res_inst_count; i++) {
1150 		if (res->res_instances[i].res_inst_id == RES_INSTANCE_NOT_CREATED) {
1151 			break;
1152 		}
1153 	}
1154 
1155 	if (i >= res->res_inst_count) {
1156 		return -ENOMEM;
1157 	}
1158 
1159 	res->res_instances[i].res_inst_id = resource_instance_id;
1160 	*res_inst = &res->res_instances[i];
1161 	return 0;
1162 }
1163 
lwm2m_engine_get_create_res_inst(const struct lwm2m_obj_path * path,struct lwm2m_engine_res ** res,struct lwm2m_engine_res_inst ** res_inst)1164 int lwm2m_engine_get_create_res_inst(const struct lwm2m_obj_path *path,
1165 				     struct lwm2m_engine_res **res,
1166 				     struct lwm2m_engine_res_inst **res_inst)
1167 {
1168 	int ret;
1169 	struct lwm2m_engine_res *r = NULL;
1170 	struct lwm2m_engine_res_inst *r_i = NULL;
1171 
1172 	ret = path_to_objs(path, NULL, NULL, &r, &r_i);
1173 	if (ret < 0) {
1174 		return ret;
1175 	}
1176 
1177 	if (!r) {
1178 		return -ENOENT;
1179 	}
1180 	/* Store resource pointer */
1181 	*res = r;
1182 
1183 	if (!r_i) {
1184 		if (path->level < LWM2M_PATH_LEVEL_RESOURCE_INST) {
1185 			return -EINVAL;
1186 		}
1187 
1188 		ret = lwm2m_engine_allocate_resource_instance(r, &r_i, path->res_inst_id);
1189 		if (ret < 0) {
1190 			return ret;
1191 		}
1192 	}
1193 
1194 	/* Store resource instance pointer */
1195 	*res_inst = r_i;
1196 	return 0;
1197 }
1198 
lwm2m_create_res_inst(const struct lwm2m_obj_path * path)1199 int lwm2m_create_res_inst(const struct lwm2m_obj_path *path)
1200 {
1201 	int ret;
1202 	struct lwm2m_engine_res *res = NULL;
1203 	struct lwm2m_engine_res_inst *res_inst = NULL;
1204 
1205 	if (path->level < LWM2M_PATH_LEVEL_RESOURCE_INST) {
1206 		LOG_ERR("path must have 4 parts");
1207 		return -EINVAL;
1208 	}
1209 	k_mutex_lock(&registry_lock, K_FOREVER);
1210 	ret = path_to_objs(path, NULL, NULL, &res, &res_inst);
1211 	if (ret < 0) {
1212 		k_mutex_unlock(&registry_lock);
1213 		return ret;
1214 	}
1215 
1216 	if (!res) {
1217 		LOG_ERR("resource %u not found", path->res_id);
1218 		k_mutex_unlock(&registry_lock);
1219 		return -ENOENT;
1220 	}
1221 
1222 	if (res_inst && res_inst->res_inst_id != RES_INSTANCE_NOT_CREATED) {
1223 		LOG_ERR("res instance %u already exists", path->res_inst_id);
1224 		k_mutex_unlock(&registry_lock);
1225 		return -EINVAL;
1226 	}
1227 	k_mutex_unlock(&registry_lock);
1228 	return lwm2m_engine_allocate_resource_instance(res, &res_inst, path->res_inst_id);
1229 }
1230 
lwm2m_delete_res_inst(const struct lwm2m_obj_path * path)1231 int lwm2m_delete_res_inst(const struct lwm2m_obj_path *path)
1232 {
1233 	int ret;
1234 	struct lwm2m_engine_res_inst *res_inst = NULL;
1235 
1236 	if (path->level < LWM2M_PATH_LEVEL_RESOURCE_INST) {
1237 		LOG_ERR("path must have 4 parts");
1238 		return -EINVAL;
1239 	}
1240 	k_mutex_lock(&registry_lock, K_FOREVER);
1241 	ret = path_to_objs(path, NULL, NULL, NULL, &res_inst);
1242 	if (ret < 0) {
1243 		k_mutex_unlock(&registry_lock);
1244 		return ret;
1245 	}
1246 
1247 	if (!res_inst) {
1248 		LOG_ERR("res instance %u not found", path->res_inst_id);
1249 		k_mutex_unlock(&registry_lock);
1250 		return -ENOENT;
1251 	}
1252 
1253 	res_inst->data_ptr = NULL;
1254 	res_inst->max_data_len = 0U;
1255 	res_inst->data_len = 0U;
1256 	res_inst->res_inst_id = RES_INSTANCE_NOT_CREATED;
1257 	k_mutex_unlock(&registry_lock);
1258 	return 0;
1259 }
1260 /* Register callbacks */
1261 
lwm2m_register_read_callback(const struct lwm2m_obj_path * path,lwm2m_engine_get_data_cb_t cb)1262 int lwm2m_register_read_callback(const struct lwm2m_obj_path *path, lwm2m_engine_get_data_cb_t cb)
1263 {
1264 	int ret;
1265 	struct lwm2m_engine_res *res = NULL;
1266 
1267 	ret = lwm2m_get_resource(path, &res);
1268 	if (ret < 0) {
1269 		return ret;
1270 	}
1271 
1272 	res->read_cb = cb;
1273 	return 0;
1274 }
1275 
lwm2m_register_pre_write_callback(const struct lwm2m_obj_path * path,lwm2m_engine_get_data_cb_t cb)1276 int lwm2m_register_pre_write_callback(const struct lwm2m_obj_path *path,
1277 				      lwm2m_engine_get_data_cb_t cb)
1278 {
1279 	int ret;
1280 	struct lwm2m_engine_res *res = NULL;
1281 
1282 	ret = lwm2m_get_resource(path, &res);
1283 	if (ret < 0) {
1284 		return ret;
1285 	}
1286 
1287 	res->pre_write_cb = cb;
1288 	return 0;
1289 }
1290 
lwm2m_register_validate_callback(const struct lwm2m_obj_path * path,lwm2m_engine_set_data_cb_t cb)1291 int lwm2m_register_validate_callback(const struct lwm2m_obj_path *path,
1292 				     lwm2m_engine_set_data_cb_t cb)
1293 {
1294 #if CONFIG_LWM2M_ENGINE_VALIDATION_BUFFER_SIZE > 0
1295 	int ret;
1296 	struct lwm2m_engine_res *res = NULL;
1297 
1298 	ret = lwm2m_get_resource(path, &res);
1299 	if (ret < 0) {
1300 		return ret;
1301 	}
1302 
1303 	res->validate_cb = cb;
1304 	return 0;
1305 #else
1306 	ARG_UNUSED(path);
1307 	ARG_UNUSED(cb);
1308 
1309 	LOG_ERR("Validation disabled. Set "
1310 		"CONFIG_LWM2M_ENGINE_VALIDATION_BUFFER_SIZE > 0 to "
1311 		"enable validation support.");
1312 	return -ENOTSUP;
1313 #endif /* CONFIG_LWM2M_ENGINE_VALIDATION_BUFFER_SIZE > 0 */
1314 }
1315 
lwm2m_register_post_write_callback(const struct lwm2m_obj_path * path,lwm2m_engine_set_data_cb_t cb)1316 int lwm2m_register_post_write_callback(const struct lwm2m_obj_path *path,
1317 				       lwm2m_engine_set_data_cb_t cb)
1318 {
1319 	int ret;
1320 	struct lwm2m_engine_res *res = NULL;
1321 
1322 	ret = lwm2m_get_resource(path, &res);
1323 	if (ret < 0) {
1324 		return ret;
1325 	}
1326 
1327 	res->post_write_cb = cb;
1328 	return 0;
1329 }
1330 
lwm2m_register_exec_callback(const struct lwm2m_obj_path * path,lwm2m_engine_execute_cb_t cb)1331 int lwm2m_register_exec_callback(const struct lwm2m_obj_path *path, lwm2m_engine_execute_cb_t cb)
1332 {
1333 	int ret;
1334 	struct lwm2m_engine_res *res = NULL;
1335 
1336 	ret = lwm2m_get_resource(path, &res);
1337 	if (ret < 0) {
1338 		return ret;
1339 	}
1340 
1341 	res->execute_cb = cb;
1342 	return 0;
1343 }
1344 
lwm2m_register_create_callback(uint16_t obj_id,lwm2m_engine_user_cb_t cb)1345 int lwm2m_register_create_callback(uint16_t obj_id, lwm2m_engine_user_cb_t cb)
1346 {
1347 	struct lwm2m_engine_obj *obj = NULL;
1348 
1349 	obj = get_engine_obj(obj_id);
1350 	if (!obj) {
1351 		LOG_ERR("unable to find obj: %u", obj_id);
1352 		return -ENOENT;
1353 	}
1354 
1355 	obj->user_create_cb = cb;
1356 	return 0;
1357 }
1358 
lwm2m_register_delete_callback(uint16_t obj_id,lwm2m_engine_user_cb_t cb)1359 int lwm2m_register_delete_callback(uint16_t obj_id, lwm2m_engine_user_cb_t cb)
1360 {
1361 	struct lwm2m_engine_obj *obj = NULL;
1362 
1363 	obj = get_engine_obj(obj_id);
1364 	if (!obj) {
1365 		LOG_ERR("unable to find obj: %u", obj_id);
1366 		return -ENOENT;
1367 	}
1368 
1369 	obj->user_delete_cb = cb;
1370 	return 0;
1371 }
1372 /* Generic data handlers */
1373 
lwm2m_get_or_create_engine_obj(struct lwm2m_message * msg,struct lwm2m_engine_obj_inst ** obj_inst,uint8_t * created)1374 int lwm2m_get_or_create_engine_obj(struct lwm2m_message *msg,
1375 				   struct lwm2m_engine_obj_inst **obj_inst, uint8_t *created)
1376 {
1377 	int ret = 0;
1378 
1379 	if (created) {
1380 		*created = 0U;
1381 	}
1382 
1383 	*obj_inst = get_engine_obj_inst(msg->path.obj_id, msg->path.obj_inst_id);
1384 	if (!*obj_inst) {
1385 		ret = lwm2m_create_obj_inst(msg->path.obj_id, msg->path.obj_inst_id, obj_inst);
1386 		if (ret < 0) {
1387 			return ret;
1388 		}
1389 
1390 		/* set created flag to one */
1391 		if (created) {
1392 			*created = 1U;
1393 		}
1394 
1395 		if (!msg->ctx->bootstrap_mode) {
1396 			engine_trigger_update(true);
1397 		}
1398 	}
1399 
1400 	return ret;
1401 }
1402 
lwm2m_engine_get_res(const struct lwm2m_obj_path * path)1403 struct lwm2m_engine_res *lwm2m_engine_get_res(const struct lwm2m_obj_path *path)
1404 {
1405 	struct lwm2m_engine_res *res = NULL;
1406 	int ret;
1407 
1408 	if (path->level < LWM2M_PATH_LEVEL_RESOURCE) {
1409 		return NULL;
1410 	}
1411 
1412 	ret = path_to_objs(path, NULL, NULL, &res, NULL);
1413 	if (ret < 0) {
1414 		return NULL;
1415 	}
1416 
1417 	return res;
1418 }
1419 
lwm2m_engine_get_res_inst(const struct lwm2m_obj_path * path)1420 struct lwm2m_engine_res_inst *lwm2m_engine_get_res_inst(const struct lwm2m_obj_path *path)
1421 {
1422 	struct lwm2m_engine_res_inst *res_inst = NULL;
1423 	int ret;
1424 
1425 	if (path->level != LWM2M_PATH_LEVEL_RESOURCE_INST) {
1426 		return NULL;
1427 	}
1428 
1429 	ret = path_to_objs(path, NULL, NULL, NULL, &res_inst);
1430 	if (ret < 0) {
1431 		return NULL;
1432 	}
1433 
1434 	return res_inst;
1435 }
1436 
lwm2m_engine_shall_report_obj_version(const struct lwm2m_engine_obj * obj)1437 bool lwm2m_engine_shall_report_obj_version(const struct lwm2m_engine_obj *obj)
1438 {
1439 	if (IS_ENABLED(CONFIG_LWM2M_ENGINE_ALWAYS_REPORT_OBJ_VERSION)) {
1440 		return true;
1441 	}
1442 
1443 	/* For non-core objects, report version other than 1.0 */
1444 	if (!obj->is_core) {
1445 		return obj->version_major != 1 || obj->version_minor != 0;
1446 	}
1447 
1448 	/* For core objects, report version based on default version array. */
1449 	for (size_t i = 0; i < ARRAY_SIZE(default_obj_versions); i++) {
1450 		if (obj->obj_id != default_obj_versions[i].obj_id) {
1451 			continue;
1452 		}
1453 
1454 		return obj->version_major != default_obj_versions[i].version_major ||
1455 		       obj->version_minor != default_obj_versions[i].version_minor;
1456 	}
1457 
1458 	return true;
1459 }
1460 
1461 #if defined(CONFIG_LWM2M_RESOURCE_DATA_CACHE_SUPPORT)
1462 static sys_slist_t lwm2m_timed_cache_list;
1463 static struct lwm2m_time_series_resource lwm2m_cache_entries[CONFIG_LWM2M_MAX_CACHED_RESOURCES];
1464 
1465 static struct lwm2m_time_series_resource *
lwm2m_cache_entry_allocate(const struct lwm2m_obj_path * path)1466 lwm2m_cache_entry_allocate(const struct lwm2m_obj_path *path)
1467 {
1468 	int i;
1469 	struct lwm2m_time_series_resource *entry;
1470 
1471 	entry = lwm2m_cache_entry_get_by_object(path);
1472 	if (entry) {
1473 		return entry;
1474 	}
1475 
1476 	for (i = 0; i < ARRAY_SIZE(lwm2m_cache_entries); i++) {
1477 		if (lwm2m_cache_entries[i].path.level == 0) {
1478 			lwm2m_cache_entries[i].path = *path;
1479 			sys_slist_append(&lwm2m_timed_cache_list, &lwm2m_cache_entries[i].node);
1480 			return &lwm2m_cache_entries[i];
1481 		}
1482 	}
1483 
1484 	return NULL;
1485 }
1486 
lwm2m_engine_cache_write(const struct lwm2m_engine_obj_field * obj_field,const struct lwm2m_obj_path * path,const void * value,uint16_t len)1487 static void lwm2m_engine_cache_write(const struct lwm2m_engine_obj_field *obj_field,
1488 				     const struct lwm2m_obj_path *path, const void *value,
1489 				     uint16_t len)
1490 {
1491 	struct lwm2m_time_series_resource *cache_entry;
1492 	struct lwm2m_time_series_elem elements;
1493 
1494 	cache_entry = lwm2m_cache_entry_get_by_object(path);
1495 	if (!cache_entry) {
1496 		return;
1497 	}
1498 
1499 	elements.t = time(NULL);
1500 
1501 	if (elements.t  <= 0) {
1502 		LOG_WRN("Time() not available");
1503 		return;
1504 	}
1505 
1506 	switch (obj_field->data_type) {
1507 	case LWM2M_RES_TYPE_U32:
1508 		elements.u32 = *(uint32_t *)value;
1509 		break;
1510 
1511 	case LWM2M_RES_TYPE_U16:
1512 		elements.u16 = *(uint16_t *)value;
1513 		break;
1514 
1515 	case LWM2M_RES_TYPE_U8:
1516 		elements.u8 = *(uint8_t *)value;
1517 		break;
1518 
1519 	case LWM2M_RES_TYPE_S64:
1520 		elements.i64 = *(int64_t *)value;
1521 		break;
1522 
1523 	case LWM2M_RES_TYPE_TIME:
1524 		if (len == sizeof(time_t)) {
1525 			elements.time = *(time_t *)value;
1526 		} else if (len == sizeof(uint32_t)) {
1527 			elements.time = (time_t) *((uint32_t *)value);
1528 		} else {
1529 			LOG_ERR("Not supporting size %d bytes for time", len);
1530 			return;
1531 		}
1532 		break;
1533 
1534 	case LWM2M_RES_TYPE_S32:
1535 		elements.i32 = *(int32_t *)value;
1536 		break;
1537 
1538 	case LWM2M_RES_TYPE_S16:
1539 		elements.i16 = *(int16_t *)value;
1540 		break;
1541 
1542 	case LWM2M_RES_TYPE_S8:
1543 		elements.i8 = *(int8_t *)value;
1544 		break;
1545 
1546 	case LWM2M_RES_TYPE_BOOL:
1547 		elements.b = *(bool *)value;
1548 		break;
1549 
1550 	default:
1551 		elements.f = *(double *)value;
1552 		break;
1553 	}
1554 
1555 	if (!lwm2m_cache_write(cache_entry, &elements)) {
1556 		LOG_WRN("Data cache full");
1557 	}
1558 }
1559 #endif /* CONFIG_LWM2M_RESOURCE_DATA_CACHE_SUPPORT */
1560 
1561 struct lwm2m_time_series_resource *
lwm2m_cache_entry_get_by_object(const struct lwm2m_obj_path * obj_path)1562 lwm2m_cache_entry_get_by_object(const struct lwm2m_obj_path *obj_path)
1563 {
1564 #if defined(CONFIG_LWM2M_RESOURCE_DATA_CACHE_SUPPORT)
1565 	struct lwm2m_time_series_resource *entry;
1566 
1567 	if (obj_path->level < LWM2M_PATH_LEVEL_RESOURCE) {
1568 		LOG_ERR("Path level wrong for cache %u", obj_path->level);
1569 		return NULL;
1570 	}
1571 
1572 	if (sys_slist_is_empty(&lwm2m_timed_cache_list)) {
1573 		return NULL;
1574 	}
1575 
1576 	SYS_SLIST_FOR_EACH_CONTAINER(&lwm2m_timed_cache_list, entry, node) {
1577 		if (lwm2m_obj_path_equal(&entry->path, obj_path)) {
1578 			return entry;
1579 		}
1580 	}
1581 #endif /* CONFIG_LWM2M_RESOURCE_DATA_CACHE_SUPPORT */
1582 	return NULL;
1583 
1584 }
1585 
lwm2m_enable_cache(const struct lwm2m_obj_path * path,struct lwm2m_time_series_elem * data_cache,size_t cache_len)1586 int lwm2m_enable_cache(const struct lwm2m_obj_path *path, struct lwm2m_time_series_elem *data_cache,
1587 		       size_t cache_len)
1588 {
1589 #if defined(CONFIG_LWM2M_RESOURCE_DATA_CACHE_SUPPORT)
1590 	struct lwm2m_engine_obj_inst *obj_inst;
1591 	struct lwm2m_engine_obj_field *obj_field;
1592 	struct lwm2m_engine_res_inst *res_inst = NULL;
1593 	struct lwm2m_time_series_resource *cache_entry;
1594 	int ret = 0;
1595 	size_t cache_entry_size = sizeof(struct lwm2m_time_series_elem);
1596 
1597 	/* look up resource obj */
1598 	ret = path_to_objs(path, &obj_inst, &obj_field, NULL, &res_inst);
1599 	if (ret < 0) {
1600 		return ret;
1601 	}
1602 
1603 	if (!res_inst) {
1604 		LOG_ERR("res instance %d not found", path->res_inst_id);
1605 		return -ENOENT;
1606 	}
1607 
1608 	switch (obj_field->data_type) {
1609 	case LWM2M_RES_TYPE_U32:
1610 	case LWM2M_RES_TYPE_TIME:
1611 	case LWM2M_RES_TYPE_U16:
1612 	case LWM2M_RES_TYPE_U8:
1613 	case LWM2M_RES_TYPE_S64:
1614 	case LWM2M_RES_TYPE_S32:
1615 	case LWM2M_RES_TYPE_S16:
1616 	case LWM2M_RES_TYPE_S8:
1617 	case LWM2M_RES_TYPE_BOOL:
1618 	case LWM2M_RES_TYPE_FLOAT:
1619 		/* Support only fixed width resource types */
1620 		cache_entry = lwm2m_cache_entry_allocate(path);
1621 		break;
1622 	default:
1623 		cache_entry = NULL;
1624 		break;
1625 	}
1626 
1627 	if (!cache_entry) {
1628 		return -ENODATA;
1629 	}
1630 
1631 	ring_buf_init(&cache_entry->rb, cache_entry_size * cache_len, (uint8_t *)data_cache);
1632 
1633 	return 0;
1634 #else
1635 	LOG_ERR("LwM2M resource cache is only supported for "
1636 		"CONFIG_LWM2M_RESOURCE_DATA_CACHE_SUPPORT");
1637 	return -ENOTSUP;
1638 #endif /* CONFIG_LWM2M_RESOURCE_DATA_CACHE_SUPPORT */
1639 }
1640 
1641 #if defined(CONFIG_LWM2M_RESOURCE_DATA_CACHE_SUPPORT)
lwm2m_engine_data_cache_init(void)1642 static int lwm2m_engine_data_cache_init(void)
1643 {
1644 	int i;
1645 
1646 	sys_slist_init(&lwm2m_timed_cache_list);
1647 
1648 	for (i = 0; i < ARRAY_SIZE(lwm2m_cache_entries); i++) {
1649 		lwm2m_cache_entries[i].path.level = LWM2M_PATH_LEVEL_NONE;
1650 	}
1651 	return 0;
1652 }
1653 LWM2M_ENGINE_INIT(lwm2m_engine_data_cache_init);
1654 #endif
1655 
lwm2m_cache_write(struct lwm2m_time_series_resource * cache_entry,struct lwm2m_time_series_elem * buf)1656 bool lwm2m_cache_write(struct lwm2m_time_series_resource *cache_entry,
1657 		       struct lwm2m_time_series_elem *buf)
1658 {
1659 #if defined(CONFIG_LWM2M_RESOURCE_DATA_CACHE_SUPPORT)
1660 	uint32_t length;
1661 	uint8_t *buf_ptr;
1662 	uint32_t element_size = sizeof(struct lwm2m_time_series_elem);
1663 
1664 	if (ring_buf_space_get(&cache_entry->rb) < element_size) {
1665 		/* No space  */
1666 		if (IS_ENABLED(CONFIG_LWM2M_CACHE_DROP_LATEST)) {
1667 			return false;
1668 		}
1669 		/* Free entry */
1670 		length = ring_buf_get_claim(&cache_entry->rb, &buf_ptr, element_size);
1671 		ring_buf_get_finish(&cache_entry->rb, length);
1672 	}
1673 
1674 	length = ring_buf_put_claim(&cache_entry->rb, &buf_ptr, element_size);
1675 
1676 	if (length != element_size) {
1677 		ring_buf_put_finish(&cache_entry->rb, 0);
1678 		LOG_ERR("Allocation failed %u", length);
1679 		return false;
1680 	}
1681 
1682 	ring_buf_put_finish(&cache_entry->rb, length);
1683 	/* Store data */
1684 	memcpy(buf_ptr, buf, element_size);
1685 	return true;
1686 #else
1687 	return NULL;
1688 #endif
1689 }
1690 
lwm2m_cache_read(struct lwm2m_time_series_resource * cache_entry,struct lwm2m_time_series_elem * buf)1691 bool lwm2m_cache_read(struct lwm2m_time_series_resource *cache_entry,
1692 		      struct lwm2m_time_series_elem *buf)
1693 {
1694 #if defined(CONFIG_LWM2M_RESOURCE_DATA_CACHE_SUPPORT)
1695 	uint32_t length;
1696 	uint8_t *buf_ptr;
1697 	uint32_t element_size = sizeof(struct lwm2m_time_series_elem);
1698 
1699 	if (ring_buf_is_empty(&cache_entry->rb)) {
1700 		return false;
1701 	}
1702 
1703 	length = ring_buf_get_claim(&cache_entry->rb, &buf_ptr, element_size);
1704 
1705 	if (length != element_size) {
1706 		LOG_ERR("Cache read fail %u", length);
1707 		ring_buf_get_finish(&cache_entry->rb, 0);
1708 		return false;
1709 	}
1710 
1711 	/* Read Data */
1712 	memcpy(buf, buf_ptr, element_size);
1713 	ring_buf_get_finish(&cache_entry->rb, length);
1714 	return true;
1715 
1716 #else
1717 	return NULL;
1718 #endif
1719 }
1720 
lwm2m_cache_size(const struct lwm2m_time_series_resource * cache_entry)1721 size_t lwm2m_cache_size(const struct lwm2m_time_series_resource *cache_entry)
1722 {
1723 #if defined(CONFIG_LWM2M_RESOURCE_DATA_CACHE_SUPPORT)
1724 	uint32_t bytes_available;
1725 
1726 	if (ring_buf_is_empty(&cache_entry->rb)) {
1727 		return 0;
1728 	}
1729 
1730 	bytes_available = ring_buf_size_get(&cache_entry->rb);
1731 
1732 	return (bytes_available / sizeof(struct lwm2m_time_series_elem));
1733 #else
1734 	return 0;
1735 #endif
1736 }
1737 
lwm2m_set_bulk(const struct lwm2m_res_item res_list[],size_t res_list_size)1738 int lwm2m_set_bulk(const struct lwm2m_res_item res_list[], size_t res_list_size)
1739 {
1740 	int ret;
1741 
1742 	k_mutex_lock(&registry_lock, K_FOREVER);
1743 	for (int i = 0; i < res_list_size; i++) {
1744 
1745 		ret = lwm2m_engine_set(res_list[i].path, res_list[i].value, res_list[i].size);
1746 
1747 		if (ret) {
1748 			k_mutex_unlock(&registry_lock);
1749 			return ret;
1750 		}
1751 	}
1752 	k_mutex_unlock(&registry_lock);
1753 
1754 	return 0;
1755 }
1756