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  * Copyright (c) 2015, Yanzi Networks AB.
10  * All rights reserved.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions and the following disclaimer.
17  * 2. Redistributions in binary form must reproduce the above copyright
18  *    notice, this list of conditions and the following disclaimer in the
19  *    documentation and/or other materials provided with the distribution.
20  * 3. Neither the name of the copyright holder nor the names of its
21  *    contributors may be used to endorse or promote products derived
22  *    from this software without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS
25  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
27  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
28  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
29  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
30  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
31  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
33  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
35  * OF THE POSSIBILITY OF SUCH DAMAGE.
36  */
37 
38 /*
39  * Original Authors:
40  *         Joakim Eriksson <joakime@sics.se>
41  *         Niclas Finne <nfi@sics.se>
42  */
43 
44 #ifndef LWM2M_OBJECT_H_
45 #define LWM2M_OBJECT_H_
46 
47 /* stdint conversions */
48 #include <zephyr/types.h>
49 #include <stddef.h>
50 #include <zephyr/kernel.h>
51 
52 #include <zephyr/net/net_ip.h>
53 #include <zephyr/sys/printk.h>
54 #include <zephyr/sys/util.h>
55 #include <sys/types.h>
56 #include <time.h>
57 
58 #include <zephyr/net/coap.h>
59 #include <zephyr/net/lwm2m.h>
60 
61 #include "buf_util.h"
62 
63 /* #####/###/#####/### + NULL */
64 #define MAX_RESOURCE_LEN	20
65 
66 /* operations / permissions */
67 /* values from 0 to 7 can be used as permission checks */
68 #define LWM2M_OP_READ		0
69 #define LWM2M_OP_WRITE		1
70 #define LWM2M_OP_CREATE		2
71 #define LWM2M_OP_DELETE		3
72 #define LWM2M_OP_EXECUTE	4
73 #define LWM2M_FLAG_OPTIONAL	7
74 /* values >7 aren't used for permission checks */
75 #define LWM2M_OP_DISCOVER	8
76 #define LWM2M_OP_WRITE_ATTR	9
77 
78 /* resource permissions */
79 #define LWM2M_PERM_R		BIT(LWM2M_OP_READ)
80 #define LWM2M_PERM_R_OPT	(BIT(LWM2M_OP_READ) | \
81 				 BIT(LWM2M_FLAG_OPTIONAL))
82 #define LWM2M_PERM_W		(BIT(LWM2M_OP_WRITE) | \
83 				 BIT(LWM2M_OP_CREATE))
84 #define LWM2M_PERM_W_OPT	(BIT(LWM2M_OP_WRITE) | \
85 				 BIT(LWM2M_OP_CREATE) | \
86 				 BIT(LWM2M_FLAG_OPTIONAL))
87 #define LWM2M_PERM_X		BIT(LWM2M_OP_EXECUTE)
88 #define LWM2M_PERM_X_OPT	(BIT(LWM2M_OP_EXECUTE) | \
89 				 BIT(LWM2M_FLAG_OPTIONAL))
90 #define LWM2M_PERM_RW		(BIT(LWM2M_OP_READ) | \
91 				 BIT(LWM2M_OP_WRITE) | \
92 				 BIT(LWM2M_OP_CREATE))
93 #define LWM2M_PERM_RW_OPT	(BIT(LWM2M_OP_READ) | \
94 				 BIT(LWM2M_OP_WRITE) | \
95 				 BIT(LWM2M_OP_CREATE) | \
96 				 BIT(LWM2M_FLAG_OPTIONAL))
97 #define LWM2M_PERM_RWX		(BIT(LWM2M_OP_READ) | \
98 				 BIT(LWM2M_OP_WRITE) | \
99 				 BIT(LWM2M_OP_CREATE) | \
100 				 BIT(LWM2M_OP_EXECUTE))
101 #define LWM2M_PERM_RWX_OPT	(BIT(LWM2M_OP_READ) | \
102 				 BIT(LWM2M_OP_WRITE) | \
103 				 BIT(LWM2M_OP_CREATE) | \
104 				 BIT(LWM2M_OP_EXECUTE) | \
105 				 BIT(LWM2M_FLAG_OPTIONAL))
106 
107 #define LWM2M_HAS_PERM(of, p)	(((of)->permissions & p) == p)
108 
109 /* resource types */
110 #define LWM2M_RES_TYPE_NONE	0
111 #define LWM2M_RES_TYPE_OPAQUE	1
112 #define LWM2M_RES_TYPE_STRING	2
113 #define LWM2M_RES_TYPE_UINT	3
114 #define LWM2M_RES_TYPE_U32	3
115 #define LWM2M_RES_TYPE_U16	4
116 #define LWM2M_RES_TYPE_U8	5
117 #define LWM2M_RES_TYPE_INT64	6
118 #define LWM2M_RES_TYPE_S64	6
119 #define LWM2M_RES_TYPE_INT	7
120 #define LWM2M_RES_TYPE_S32	7
121 #define LWM2M_RES_TYPE_S16	8
122 #define LWM2M_RES_TYPE_S8	9
123 #define LWM2M_RES_TYPE_BOOL	10
124 #define LWM2M_RES_TYPE_TIME	11
125 #define LWM2M_RES_TYPE_FLOAT	12
126 #define LWM2M_RES_TYPE_OBJLNK	13
127 
128 /* remember that we have already output a value - can be between two block's */
129 #define WRITER_OUTPUT_VALUE      1
130 #define WRITER_RESOURCE_INSTANCE 2
131 
132 BUILD_ASSERT(CONFIG_LWM2M_COAP_BLOCK_SIZE <= CONFIG_LWM2M_COAP_MAX_MSG_SIZE,
133 	     "CoAP block size can't exceed maximum message size");
134 
135 #define MAX_PACKET_SIZE		(CONFIG_LWM2M_COAP_MAX_MSG_SIZE + \
136 				 CONFIG_LWM2M_ENGINE_MESSAGE_HEADER_SIZE)
137 
138 #if defined(CONFIG_LWM2M_COAP_BLOCK_TRANSFER)
139 BUILD_ASSERT(CONFIG_LWM2M_COAP_ENCODE_BUFFER_SIZE >
140 		     (CONFIG_LWM2M_COAP_BLOCK_SIZE + CONFIG_LWM2M_ENGINE_MESSAGE_HEADER_SIZE),
141 	     "The buffer for serializing message needs to be bigger than a message with one block");
142 #endif
143 
144 /* buffer util macros */
145 #define CPKT_BUF_WRITE(cpkt)	(cpkt)->data, &(cpkt)->offset, (cpkt)->max_len
146 #define CPKT_BUF_READ(cpkt)	(cpkt)->data, (cpkt)->max_len
147 #define CPKT_BUF_W_PTR(cpkt)	((cpkt)->data + (cpkt)->offset)
148 #define CPKT_BUF_W_SIZE(cpkt)	((cpkt)->max_len - (cpkt)->offset)
149 
150 #define CPKT_BUF_W_REGION(cpkt)  CPKT_BUF_W_PTR(cpkt), CPKT_BUF_W_SIZE(cpkt)
151 
152 /* Input context buffer util macros */
153 #define ICTX_BUF_R_LEFT_SZ(i_ctx) ((i_ctx)->in_cpkt->max_len - (i_ctx)->offset)
154 #define ICTX_BUF_R_PTR(i_ctx)	  ((i_ctx)->in_cpkt->data + (i_ctx)->offset)
155 #define ICTX_BUF_R_REGION(i_ctx)   ICTX_BUF_R_PTR(i_ctx), ICTX_BUF_R_LEFT_SZ(i_ctx)
156 
157 struct lwm2m_engine_obj;
158 struct lwm2m_message;
159 
160 #define LWM2M_PATH_LEVEL_NONE 0
161 #define LWM2M_PATH_LEVEL_OBJECT 1
162 #define LWM2M_PATH_LEVEL_OBJECT_INST 2
163 #define LWM2M_PATH_LEVEL_RESOURCE 3
164 #define LWM2M_PATH_LEVEL_RESOURCE_INST 4
165 
166 /* path representing object instances */
167 #define OBJ_FIELD(_id, _perm, _type) \
168 	{ .res_id = _id, \
169 	  .permissions = LWM2M_PERM_ ## _perm, \
170 	  .data_type = LWM2M_RES_TYPE_ ## _type, }
171 
172 /* Keep OBJ_FIELD_DATA around for historical reasons */
173 #define OBJ_FIELD_DATA(res_id, perm, type) \
174 	OBJ_FIELD(res_id, perm, type)
175 
176 #define OBJ_FIELD_EXECUTE(res_id) \
177 	OBJ_FIELD(res_id, X, NONE)
178 
179 #define OBJ_FIELD_EXECUTE_OPT(res_id) \
180 	OBJ_FIELD(res_id, X_OPT, NONE)
181 
182 struct lwm2m_engine_obj_field {
183 	uint16_t  res_id;
184 	uint8_t   permissions;
185 	uint8_t   data_type;
186 };
187 
188 typedef struct lwm2m_engine_obj_inst *
189 	(*lwm2m_engine_obj_create_cb_t)(uint16_t obj_inst_id);
190 
191 struct lwm2m_engine_obj {
192 	/* object list */
193 	sys_snode_t node;
194 
195 	/* object field definitions */
196 	struct lwm2m_engine_obj_field *fields;
197 
198 	/* object event callbacks */
199 	lwm2m_engine_obj_create_cb_t create_cb;
200 	lwm2m_engine_user_cb_t delete_cb;
201 	lwm2m_engine_user_cb_t user_create_cb;
202 	lwm2m_engine_user_cb_t user_delete_cb;
203 
204 	/* object member data */
205 	uint16_t obj_id;
206 	uint16_t field_count;
207 	uint16_t instance_count;
208 	uint16_t max_instance_count;
209 
210 	/* Object version information. */
211 	uint8_t version_major;
212 	uint8_t version_minor;
213 
214 	/* Object is a core object (defined in the official LwM2M spec.) */
215 	bool is_core : 1;
216 };
217 
218 /* Resource instances with this value are considered "not created" yet */
219 #define RES_INSTANCE_NOT_CREATED 65535
220 
221 /* Resource macros */
222 
223 #if CONFIG_LWM2M_ENGINE_VALIDATION_BUFFER_SIZE > 0
224 #define _INIT_OBJ_RES(_id, _r_ptr, _r_idx, _ri_ptr, _ri_count, _multi_ri, \
225 		      _r_cb, _pre_w_cb, _val_cb, _post_w_cb, _ex_cb) \
226 	_r_ptr[_r_idx].res_id = _id; \
227 	_r_ptr[_r_idx].res_instances = _ri_ptr; \
228 	_r_ptr[_r_idx].res_inst_count = _ri_count; \
229 	_r_ptr[_r_idx].multi_res_inst = _multi_ri; \
230 	_r_ptr[_r_idx].read_cb = _r_cb; \
231 	_r_ptr[_r_idx].pre_write_cb = _pre_w_cb; \
232 	_r_ptr[_r_idx].validate_cb = _val_cb; \
233 	_r_ptr[_r_idx].post_write_cb = _post_w_cb; \
234 	_r_ptr[_r_idx].execute_cb = _ex_cb
235 #else
236 #define _INIT_OBJ_RES(_id, _r_ptr, _r_idx, _ri_ptr, _ri_count, _multi_ri, \
237 		      _r_cb, _pre_w_cb, _val_cb, _post_w_cb, _ex_cb) \
238 	_r_ptr[_r_idx].res_id = _id; \
239 	_r_ptr[_r_idx].res_instances = _ri_ptr; \
240 	_r_ptr[_r_idx].res_inst_count = _ri_count; \
241 	_r_ptr[_r_idx].multi_res_inst = _multi_ri; \
242 	_r_ptr[_r_idx].read_cb = _r_cb; \
243 	_r_ptr[_r_idx].pre_write_cb = _pre_w_cb; \
244 	_r_ptr[_r_idx].post_write_cb = _post_w_cb; \
245 	_r_ptr[_r_idx].execute_cb = _ex_cb
246 #endif /* CONFIG_LWM2M_ENGINE_VALIDATION_BUFFER_SIZE > 0 */
247 
248 #define _INIT_OBJ_RES_INST(_ri_ptr, _ri_idx, _ri_count, _ri_create, \
249 			   _data_ptr, _data_sz, _data_len) \
250 	do { \
251 		if (_ri_ptr != NULL && _ri_count > 0) { \
252 			for (int _i = 0; _i < _ri_count; _i++) { \
253 				_ri_ptr[_ri_idx + _i].data_ptr = \
254 						(_data_ptr + _i); \
255 				_ri_ptr[_ri_idx + _i].max_data_len = \
256 						_data_sz; \
257 				_ri_ptr[_ri_idx + _i].data_len = \
258 						_data_len; \
259 				if (_ri_create) { \
260 					_ri_ptr[_ri_idx + _i].res_inst_id = \
261 						_i; \
262 				} else { \
263 					_ri_ptr[_ri_idx + _i].res_inst_id = \
264 						RES_INSTANCE_NOT_CREATED; \
265 				} \
266 			} \
267 		} \
268 		_ri_idx += _ri_count; \
269 	} while (false)
270 
271 #define _INIT_OBJ_RES_INST_OPT(_ri_ptr, _ri_idx, _ri_count, _ri_create) \
272 	do { \
273 		if (_ri_count > 0) { \
274 			for (int _i = 0; _i < _ri_count; _i++) { \
275 				_ri_ptr[_ri_idx + _i].data_ptr = NULL; \
276 				_ri_ptr[_ri_idx + _i].max_data_len = 0; \
277 				_ri_ptr[_ri_idx + _i].data_len = 0; \
278 				if (_ri_create) { \
279 					_ri_ptr[_ri_idx + _i].res_inst_id = \
280 						_i; \
281 				} else { \
282 					_ri_ptr[_ri_idx + _i].res_inst_id = \
283 						RES_INSTANCE_NOT_CREATED; \
284 				} \
285 			} \
286 		} \
287 		_ri_idx += _ri_count; \
288 	} while (false)
289 
290 #define INIT_OBJ_RES(_id, _r_ptr, _r_idx, \
291 		     _ri_ptr, _ri_idx, _ri_count, _multi_ri, _ri_create, \
292 		     _data_ptr, _data_len, \
293 		     _r_cb, _pre_w_cb, _val_cb, _post_w_cb, _ex_cb) \
294 	do { \
295 		_INIT_OBJ_RES(_id, _r_ptr, _r_idx, \
296 			      (_ri_ptr + _ri_idx), _ri_count, _multi_ri, \
297 			      _r_cb, _pre_w_cb, _val_cb, _post_w_cb, _ex_cb); \
298 		_INIT_OBJ_RES_INST(_ri_ptr, _ri_idx, _ri_count, _ri_create, \
299 				   _data_ptr, _data_len, _data_len); \
300 	++_r_idx; \
301 	} while (false)
302 
303 #define INIT_OBJ_RES_LEN(_id, _r_ptr, _r_idx, \
304 		     _ri_ptr, _ri_idx, _ri_count, _multi_ri, _ri_create, \
305 		     _data_ptr, _data_sz, _data_len, \
306 		     _r_cb, _pre_w_cb, _val_cb, _post_w_cb, _ex_cb) \
307 	do { \
308 		_INIT_OBJ_RES(_id, _r_ptr, _r_idx, \
309 			      (_ri_ptr + _ri_idx), _ri_count, _multi_ri, \
310 			      _r_cb, _pre_w_cb, _val_cb, _post_w_cb, _ex_cb); \
311 		_INIT_OBJ_RES_INST(_ri_ptr, _ri_idx, _ri_count, _ri_create, \
312 				   _data_ptr, _data_sz, _data_len); \
313 	++_r_idx; \
314 	} while (false)
315 
316 #define INIT_OBJ_RES_OPT(_id, _r_ptr, _r_idx, \
317 			 _ri_ptr, _ri_idx, _ri_count, _multi_ri, _ri_create, \
318 			 _r_cb, _pre_w_cb, _val_cb, _post_w_cb, _ex_cb) \
319 	do { \
320 		_INIT_OBJ_RES(_id, _r_ptr, _r_idx, \
321 			      (_ri_ptr + _ri_idx), _ri_count, _multi_ri, \
322 			      _r_cb, _pre_w_cb, _val_cb, _post_w_cb, _ex_cb); \
323 		_INIT_OBJ_RES_INST_OPT(_ri_ptr, _ri_idx, _ri_count, _ri_create); \
324 		++_r_idx; \
325 	} while (false)
326 
327 #define INIT_OBJ_RES_MULTI_DATA(_id, _r_ptr, _r_idx, \
328 				_ri_ptr, _ri_idx, _ri_count, _ri_create, \
329 				_data_ptr, _data_len) \
330 	INIT_OBJ_RES(_id, _r_ptr, _r_idx, \
331 		     _ri_ptr, _ri_idx, _ri_count, true, _ri_create, \
332 		     _data_ptr, _data_len, NULL, NULL, NULL, NULL, NULL)
333 
334 #define INIT_OBJ_RES_MULTI_DATA_LEN(_id, _r_ptr, _r_idx, \
335 				_ri_ptr, _ri_idx, _ri_count, _ri_create, \
336 				_data_ptr, _data_sz, _data_len) \
337 	INIT_OBJ_RES_LEN(_id, _r_ptr, _r_idx, \
338 		     _ri_ptr, _ri_idx, _ri_count, true, _ri_create, \
339 		     _data_ptr, _data_sz, _data_len, NULL, NULL, NULL, NULL, NULL)
340 
341 #define INIT_OBJ_RES_MULTI_OPTDATA(_id, _r_ptr, _r_idx, \
342 				   _ri_ptr, _ri_idx, _ri_count, _ri_create) \
343 	INIT_OBJ_RES_OPT(_id, _r_ptr, _r_idx, \
344 			 _ri_ptr, _ri_idx, _ri_count, true, _ri_create, \
345 			 NULL, NULL, NULL, NULL, NULL)
346 
347 #define INIT_OBJ_RES_DATA_LEN(_id, _r_ptr, _r_idx, _ri_ptr, _ri_idx, \
348 			  _data_ptr, _data_sz, _data_len) \
349 	INIT_OBJ_RES_LEN(_id, _r_ptr, _r_idx, _ri_ptr, _ri_idx, 1U, false, true, \
350 		     _data_ptr, _data_sz, _data_len, NULL, NULL, NULL, NULL, NULL)
351 
352 #define INIT_OBJ_RES_DATA(_id, _r_ptr, _r_idx, _ri_ptr, _ri_idx, _data_ptr, _data_len)     \
353 	INIT_OBJ_RES_DATA_LEN(_id, _r_ptr, _r_idx, _ri_ptr, _ri_idx, _data_ptr, _data_len, \
354 			      _data_len)
355 
356 #define INIT_OBJ_RES_OPTDATA(_id, _r_ptr, _r_idx, _ri_ptr, _ri_idx) \
357 	INIT_OBJ_RES_OPT(_id, _r_ptr, _r_idx, _ri_ptr, _ri_idx, 1U, false, \
358 			 true, NULL, NULL, NULL, NULL, NULL)
359 
360 #define INIT_OBJ_RES_EXECUTE(_id, _r_ptr, _r_idx, _ex_cb) \
361 	do { \
362 		_INIT_OBJ_RES(_id, _r_ptr, _r_idx, NULL, 0, false, \
363 			      NULL, NULL, NULL, NULL, _ex_cb); \
364 		++_r_idx; \
365 	} while (false)
366 
367 
368 #define LWM2M_ATTR_PMIN	0
369 #define LWM2M_ATTR_PMAX	1
370 #define LWM2M_ATTR_GT	2
371 #define LWM2M_ATTR_LT	3
372 #define LWM2M_ATTR_STEP	4
373 #define NR_LWM2M_ATTR	5
374 
375 /* TODO: support multiple server (sec 5.4.2) */
376 struct lwm2m_attr {
377 	void *ref;
378 
379 	/* values */
380 	union {
381 		double float_val;
382 		int32_t int_val;
383 	};
384 
385 	uint8_t type;
386 };
387 
388 struct lwm2m_engine_res_inst {
389 	void  *data_ptr;
390 	uint16_t max_data_len;
391 	uint16_t data_len;
392 	uint16_t res_inst_id; /* 65535 == not "created" */
393 	uint8_t  data_flags;
394 };
395 
396 struct lwm2m_engine_res {
397 	lwm2m_engine_get_data_cb_t		read_cb;
398 	lwm2m_engine_get_data_cb_t		pre_write_cb;
399 #if CONFIG_LWM2M_ENGINE_VALIDATION_BUFFER_SIZE > 0
400 	lwm2m_engine_set_data_cb_t		validate_cb;
401 #endif
402 	lwm2m_engine_set_data_cb_t		post_write_cb;
403 	lwm2m_engine_execute_cb_t		execute_cb;
404 
405 	struct lwm2m_engine_res_inst *res_instances;
406 	uint16_t res_id;
407 	uint8_t  res_inst_count;
408 	bool multi_res_inst;
409 };
410 
411 struct lwm2m_engine_obj_inst {
412 	/* instance list */
413 	sys_snode_t node;
414 
415 	struct lwm2m_engine_obj *obj;
416 	struct lwm2m_engine_res *resources;
417 
418 	/* object instance member data */
419 	uint16_t obj_inst_id;
420 	uint16_t resource_count;
421 };
422 
423 /* Initialize resource instances prior to use */
init_res_instance(struct lwm2m_engine_res_inst * ri,size_t ri_len)424 static inline void init_res_instance(struct lwm2m_engine_res_inst *ri,
425 				     size_t ri_len)
426 {
427 	size_t i;
428 
429 	memset(ri, 0, sizeof(*ri) * ri_len);
430 	for (i = 0; i < ri_len; i++) {
431 		ri[i].res_inst_id = RES_INSTANCE_NOT_CREATED;
432 	}
433 }
434 
435 struct lwm2m_opaque_context {
436 	size_t len;
437 	size_t remaining;
438 };
439 
440 struct lwm2m_block_context {
441 	struct coap_block_context ctx;
442 	struct lwm2m_opaque_context opaque;
443 	int64_t timestamp;
444 	uint32_t expected;
445 	bool last_block : 1;
446 	struct lwm2m_obj_path path;
447 };
448 
449 struct lwm2m_output_context {
450 	const struct lwm2m_writer *writer;
451 	struct coap_packet *out_cpkt;
452 
453 #if defined(CONFIG_LWM2M_COAP_BLOCK_TRANSFER)
454 	/* Corresponding block context. NULL if block transfer is not used. */
455 	struct coap_block_context *block_ctx;
456 #endif
457 
458 	/* private output data */
459 	void *user_data;
460 };
461 
462 struct lwm2m_input_context {
463 	const struct lwm2m_reader *reader;
464 	struct coap_packet *in_cpkt;
465 
466 	/* current position in buffer */
467 	uint16_t offset;
468 
469 	/* Corresponding block context. NULL if block transfer is not used. */
470 	struct lwm2m_block_context *block_ctx;
471 
472 	/* private output data */
473 	void *user_data;
474 };
475 
476 /* Establish a message timeout callback */
477 typedef void (*lwm2m_message_timeout_cb_t)(struct lwm2m_message *msg);
478 
479 /* Internal LwM2M message structure to track in-flight messages. */
480 struct lwm2m_message {
481 	sys_snode_t node;
482 
483 	/** LwM2M context related to this message */
484 	struct lwm2m_ctx *ctx;
485 
486 	/** Incoming / outgoing contexts */
487 	struct lwm2m_input_context in;
488 	struct lwm2m_output_context out;
489 
490 	/** Incoming path */
491 	struct lwm2m_obj_path path;
492 
493 	/** CoAP packet data related to the outgoing message */
494 	struct coap_packet cpkt;
495 
496 	/** Buffer data related outgoing message */
497 	uint8_t msg_data[MAX_PACKET_SIZE];
498 
499 #if defined(CONFIG_LWM2M_COAP_BLOCK_TRANSFER)
500 	/** Buffer data containing complete message */
501 	struct coap_packet body_encode_buffer;
502 #endif
503 
504 	/** Message transmission handling for TYPE_CON */
505 	struct coap_pending *pending;
506 	struct coap_reply *reply;
507 #if defined(CONFIG_LWM2M_RESOURCE_DATA_CACHE_SUPPORT)
508 	struct lwm2m_cache_read_info *cache_info;
509 #endif
510 
511 	/** Message configuration */
512 	uint8_t *token;
513 	coap_reply_t reply_cb;
514 	lwm2m_message_timeout_cb_t message_timeout_cb;
515 	lwm2m_send_cb_t send_status_cb;
516 	uint16_t mid;
517 	uint8_t type;
518 	uint8_t code;
519 	uint8_t tkl;
520 
521 	/** Incoming message action */
522 	uint8_t operation;
523 
524 	/* Information whether the message was acknowledged. */
525 	bool acknowledged : 1;
526 };
527 
528 /* LWM2M format writer for the various formats supported */
529 struct lwm2m_writer {
530 	int (*put_begin)(struct lwm2m_output_context *out,
531 			 struct lwm2m_obj_path *path);
532 	int (*put_end)(struct lwm2m_output_context *out,
533 		       struct lwm2m_obj_path *path);
534 	int (*put_begin_oi)(struct lwm2m_output_context *out,
535 			    struct lwm2m_obj_path *path);
536 	int (*put_end_oi)(struct lwm2m_output_context *out,
537 			  struct lwm2m_obj_path *path);
538 	int (*put_begin_r)(struct lwm2m_output_context *out,
539 			   struct lwm2m_obj_path *path);
540 	int (*put_end_r)(struct lwm2m_output_context *out,
541 			 struct lwm2m_obj_path *path);
542 	int (*put_begin_ri)(struct lwm2m_output_context *out,
543 			    struct lwm2m_obj_path *path);
544 	int (*put_end_ri)(struct lwm2m_output_context *out,
545 			  struct lwm2m_obj_path *path);
546 	int (*put_data_timestamp)(struct lwm2m_output_context *out,
547 				time_t value);
548 	int (*put_s8)(struct lwm2m_output_context *out,
549 		      struct lwm2m_obj_path *path, int8_t value);
550 	int (*put_s16)(struct lwm2m_output_context *out,
551 		       struct lwm2m_obj_path *path, int16_t value);
552 	int (*put_s32)(struct lwm2m_output_context *out,
553 		       struct lwm2m_obj_path *path, int32_t value);
554 	int (*put_s64)(struct lwm2m_output_context *out,
555 		       struct lwm2m_obj_path *path, int64_t value);
556 	int (*put_time)(struct lwm2m_output_context *out,
557 		       struct lwm2m_obj_path *path, time_t value);
558 	int (*put_string)(struct lwm2m_output_context *out,
559 			  struct lwm2m_obj_path *path, char *buf,
560 			  size_t buflen);
561 	int (*put_float)(struct lwm2m_output_context *out,
562 			 struct lwm2m_obj_path *path, double *value);
563 	int (*put_bool)(struct lwm2m_output_context *out,
564 			struct lwm2m_obj_path *path, bool value);
565 	int (*put_opaque)(struct lwm2m_output_context *out,
566 			  struct lwm2m_obj_path *path, char *buf,
567 			  size_t buflen);
568 	int (*put_objlnk)(struct lwm2m_output_context *out,
569 			  struct lwm2m_obj_path *path,
570 			  struct lwm2m_objlnk *value);
571 	int (*put_corelink)(struct lwm2m_output_context *out,
572 			    const struct lwm2m_obj_path *path);
573 };
574 
575 struct lwm2m_reader {
576 	int (*get_s32)(struct lwm2m_input_context *in, int32_t *value);
577 	int (*get_s64)(struct lwm2m_input_context *in, int64_t *value);
578 	int (*get_time)(struct lwm2m_input_context *in, time_t *value);
579 	int (*get_string)(struct lwm2m_input_context *in, uint8_t *buf,
580 			  size_t buflen);
581 	int (*get_float)(struct lwm2m_input_context *in, double *value);
582 	int (*get_bool)(struct lwm2m_input_context *in, bool *value);
583 	int (*get_opaque)(struct lwm2m_input_context *in, uint8_t *buf,
584 			  size_t buflen, struct lwm2m_opaque_context *opaque,
585 			  bool *last_block);
586 	int (*get_objlnk)(struct lwm2m_input_context *in,
587 			  struct lwm2m_objlnk *value);
588 };
589 
590 /* output user_data management functions */
591 
engine_set_out_user_data(struct lwm2m_output_context * out,void * user_data)592 static inline void engine_set_out_user_data(struct lwm2m_output_context *out,
593 					    void *user_data)
594 {
595 	out->user_data = user_data;
596 }
597 
engine_get_out_user_data(struct lwm2m_output_context * out)598 static inline void *engine_get_out_user_data(struct lwm2m_output_context *out)
599 {
600 	return out->user_data;
601 }
602 
603 static inline void
engine_clear_out_user_data(struct lwm2m_output_context * out)604 engine_clear_out_user_data(struct lwm2m_output_context *out)
605 {
606 	out->user_data = NULL;
607 }
608 
engine_set_in_user_data(struct lwm2m_input_context * in,void * user_data)609 static inline void engine_set_in_user_data(struct lwm2m_input_context *in,
610 					   void *user_data)
611 {
612 	in->user_data = user_data;
613 }
614 
engine_get_in_user_data(struct lwm2m_input_context * in)615 static inline void *engine_get_in_user_data(struct lwm2m_input_context *in)
616 {
617 	return in->user_data;
618 }
619 
620 static inline void
engine_clear_in_user_data(struct lwm2m_input_context * in)621 engine_clear_in_user_data(struct lwm2m_input_context *in)
622 {
623 	in->user_data = NULL;
624 }
625 
626 /* inline multi-format write / read functions */
627 
engine_put_begin(struct lwm2m_output_context * out,struct lwm2m_obj_path * path)628 static inline int engine_put_begin(struct lwm2m_output_context *out,
629 				   struct lwm2m_obj_path *path)
630 {
631 	if (out->writer->put_begin) {
632 		return out->writer->put_begin(out, path);
633 	}
634 
635 	return 0;
636 }
637 
engine_put_end(struct lwm2m_output_context * out,struct lwm2m_obj_path * path)638 static inline int engine_put_end(struct lwm2m_output_context *out,
639 				 struct lwm2m_obj_path *path)
640 {
641 	if (out->writer->put_end) {
642 		return out->writer->put_end(out, path);
643 	}
644 
645 	return 0;
646 }
647 
engine_put_begin_oi(struct lwm2m_output_context * out,struct lwm2m_obj_path * path)648 static inline int engine_put_begin_oi(struct lwm2m_output_context *out,
649 				      struct lwm2m_obj_path *path)
650 {
651 	if (out->writer->put_begin_oi) {
652 		return out->writer->put_begin_oi(out, path);
653 	}
654 
655 	return 0;
656 }
657 
engine_put_end_oi(struct lwm2m_output_context * out,struct lwm2m_obj_path * path)658 static inline int engine_put_end_oi(struct lwm2m_output_context *out,
659 				    struct lwm2m_obj_path *path)
660 {
661 	if (out->writer->put_end_oi) {
662 		return out->writer->put_end_oi(out, path);
663 	}
664 
665 	return 0;
666 }
667 
engine_put_begin_r(struct lwm2m_output_context * out,struct lwm2m_obj_path * path)668 static inline int engine_put_begin_r(struct lwm2m_output_context *out,
669 				     struct lwm2m_obj_path *path)
670 {
671 	if (out->writer->put_begin_r) {
672 		return out->writer->put_begin_r(out, path);
673 	}
674 
675 	return 0;
676 }
677 
engine_put_end_r(struct lwm2m_output_context * out,struct lwm2m_obj_path * path)678 static inline int engine_put_end_r(struct lwm2m_output_context *out,
679 				   struct lwm2m_obj_path *path)
680 {
681 	if (out->writer->put_end_r) {
682 		return out->writer->put_end_r(out, path);
683 	}
684 
685 	return 0;
686 }
687 
engine_put_begin_ri(struct lwm2m_output_context * out,struct lwm2m_obj_path * path)688 static inline int engine_put_begin_ri(struct lwm2m_output_context *out,
689 				      struct lwm2m_obj_path *path)
690 {
691 	if (out->writer->put_begin_ri) {
692 		return out->writer->put_begin_ri(out, path);
693 	}
694 
695 	return 0;
696 }
697 
engine_put_end_ri(struct lwm2m_output_context * out,struct lwm2m_obj_path * path)698 static inline int engine_put_end_ri(struct lwm2m_output_context *out,
699 				    struct lwm2m_obj_path *path)
700 {
701 	if (out->writer->put_end_ri) {
702 		return out->writer->put_end_ri(out, path);
703 	}
704 
705 	return 0;
706 }
707 
engine_put_s8(struct lwm2m_output_context * out,struct lwm2m_obj_path * path,int8_t value)708 static inline int engine_put_s8(struct lwm2m_output_context *out,
709 				struct lwm2m_obj_path *path, int8_t value)
710 {
711 	return out->writer->put_s8(out, path, value);
712 }
713 
engine_put_s16(struct lwm2m_output_context * out,struct lwm2m_obj_path * path,int16_t value)714 static inline int engine_put_s16(struct lwm2m_output_context *out,
715 				 struct lwm2m_obj_path *path, int16_t value)
716 {
717 	return out->writer->put_s16(out, path, value);
718 }
719 
engine_put_s32(struct lwm2m_output_context * out,struct lwm2m_obj_path * path,int32_t value)720 static inline int engine_put_s32(struct lwm2m_output_context *out,
721 				 struct lwm2m_obj_path *path, int32_t value)
722 {
723 	return out->writer->put_s32(out, path, value);
724 }
725 
engine_put_s64(struct lwm2m_output_context * out,struct lwm2m_obj_path * path,int64_t value)726 static inline int engine_put_s64(struct lwm2m_output_context *out,
727 				 struct lwm2m_obj_path *path, int64_t value)
728 {
729 	return out->writer->put_s64(out, path, value);
730 }
731 
engine_put_string(struct lwm2m_output_context * out,struct lwm2m_obj_path * path,char * buf,size_t buflen)732 static inline int engine_put_string(struct lwm2m_output_context *out,
733 				    struct lwm2m_obj_path *path, char *buf,
734 				    size_t buflen)
735 {
736 	return out->writer->put_string(out, path, buf, buflen);
737 }
738 
engine_put_float(struct lwm2m_output_context * out,struct lwm2m_obj_path * path,double * value)739 static inline int engine_put_float(struct lwm2m_output_context *out,
740 				   struct lwm2m_obj_path *path, double *value)
741 {
742 	return out->writer->put_float(out, path, value);
743 }
744 
engine_put_time(struct lwm2m_output_context * out,struct lwm2m_obj_path * path,time_t value)745 static inline int engine_put_time(struct lwm2m_output_context *out,
746 				  struct lwm2m_obj_path *path, time_t value)
747 {
748 	return out->writer->put_time(out, path, value);
749 }
750 
engine_put_bool(struct lwm2m_output_context * out,struct lwm2m_obj_path * path,bool value)751 static inline int engine_put_bool(struct lwm2m_output_context *out,
752 				  struct lwm2m_obj_path *path, bool value)
753 {
754 	return out->writer->put_bool(out, path, value);
755 }
756 
engine_put_opaque(struct lwm2m_output_context * out,struct lwm2m_obj_path * path,char * buf,size_t buflen)757 static inline int engine_put_opaque(struct lwm2m_output_context *out,
758 				    struct lwm2m_obj_path *path, char *buf,
759 				    size_t buflen)
760 {
761 	if (out->writer->put_opaque) {
762 		return out->writer->put_opaque(out, path, buf, buflen);
763 	}
764 
765 	return 0;
766 }
767 
engine_put_objlnk(struct lwm2m_output_context * out,struct lwm2m_obj_path * path,struct lwm2m_objlnk * value)768 static inline int engine_put_objlnk(struct lwm2m_output_context *out,
769 				    struct lwm2m_obj_path *path,
770 				    struct lwm2m_objlnk *value)
771 {
772 	return out->writer->put_objlnk(out, path, value);
773 }
774 
engine_put_corelink(struct lwm2m_output_context * out,const struct lwm2m_obj_path * path)775 static inline int engine_put_corelink(struct lwm2m_output_context *out,
776 				      const struct lwm2m_obj_path *path)
777 {
778 	if (out->writer->put_corelink) {
779 		return out->writer->put_corelink(out, path);
780 	}
781 
782 	return -ENOTSUP;
783 }
784 
engine_put_timestamp(struct lwm2m_output_context * out,time_t timestamp)785 static inline int engine_put_timestamp(struct lwm2m_output_context *out, time_t timestamp)
786 {
787 	if (out->writer->put_data_timestamp) {
788 		return out->writer->put_data_timestamp(out, timestamp);
789 	}
790 
791 	return -ENOTSUP;
792 }
793 
engine_get_s32(struct lwm2m_input_context * in,int32_t * value)794 static inline int engine_get_s32(struct lwm2m_input_context *in, int32_t *value)
795 {
796 	return in->reader->get_s32(in, value);
797 }
798 
engine_get_s64(struct lwm2m_input_context * in,int64_t * value)799 static inline int engine_get_s64(struct lwm2m_input_context *in, int64_t *value)
800 {
801 	return in->reader->get_s64(in, value);
802 }
803 
engine_get_string(struct lwm2m_input_context * in,uint8_t * buf,size_t buflen)804 static inline int engine_get_string(struct lwm2m_input_context *in,
805 				    uint8_t *buf, size_t buflen)
806 {
807 	return in->reader->get_string(in, buf, buflen);
808 }
809 
engine_get_time(struct lwm2m_input_context * in,time_t * value)810 static inline int engine_get_time(struct lwm2m_input_context *in, time_t *value)
811 {
812 	return in->reader->get_time(in, value);
813 }
814 
engine_get_float(struct lwm2m_input_context * in,double * value)815 static inline int engine_get_float(struct lwm2m_input_context *in,
816 				   double *value)
817 {
818 	return in->reader->get_float(in, value);
819 }
820 
engine_get_bool(struct lwm2m_input_context * in,bool * value)821 static inline int engine_get_bool(struct lwm2m_input_context *in, bool *value)
822 {
823 	return in->reader->get_bool(in, value);
824 }
825 
engine_get_opaque(struct lwm2m_input_context * in,uint8_t * buf,size_t buflen,struct lwm2m_opaque_context * opaque,bool * last_block)826 static inline int engine_get_opaque(struct lwm2m_input_context *in,
827 				    uint8_t *buf, size_t buflen,
828 				    struct lwm2m_opaque_context *opaque,
829 				    bool *last_block)
830 {
831 	if (in->reader->get_opaque) {
832 		return in->reader->get_opaque(in, buf, buflen,
833 					      opaque, last_block);
834 	}
835 
836 	return 0;
837 }
838 
engine_get_objlnk(struct lwm2m_input_context * in,struct lwm2m_objlnk * value)839 static inline int engine_get_objlnk(struct lwm2m_input_context *in,
840 				    struct lwm2m_objlnk *value)
841 {
842 	return in->reader->get_objlnk(in, value);
843 }
844 
845 #endif /* LWM2M_OBJECT_H_ */
846