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 #ifndef LWM2M_ENGINE_H
9 #define LWM2M_ENGINE_H
10 
11 #include "lwm2m_message_handling.h"
12 #include "lwm2m_object.h"
13 #include "lwm2m_observation.h"
14 #include "lwm2m_registry.h"
15 #include <zephyr/kernel.h>
16 
17 #define LWM2M_PROTOCOL_VERSION_MAJOR 1
18 #if defined(CONFIG_LWM2M_VERSION_1_1)
19 #define LWM2M_PROTOCOL_VERSION_MINOR 1
20 #else
21 #define LWM2M_PROTOCOL_VERSION_MINOR 0
22 #endif
23 
24 #define LWM2M_PROTOCOL_VERSION_STRING                                                              \
25 	STRINGIFY(LWM2M_PROTOCOL_VERSION_MAJOR)                                                    \
26 	"." STRINGIFY(LWM2M_PROTOCOL_VERSION_MINOR)
27 
28 /* Use this value to generate new token */
29 #define LWM2M_MSG_TOKEN_GENERATE_NEW 0xFFU
30 
31 /* length of time in milliseconds to wait for buffer allocations */
32 #define BUF_ALLOC_TIMEOUT K_SECONDS(1)
33 
34 /** initialization function */
35 struct lwm2m_init_func {
36 	int (*f)(void);
37 };
38 /**
39  * @defgroup LWM2M_PRIO LwM2M initialization priorities
40  * @{
41  */
42 #define LWM2M_PRIO_ENGINE 0	/**< Engine initialization */
43 #define LWM2M_PRIO_CORE 1	/**< Core object initialization */
44 #define LWM2M_PRIO_OBJ 2	/**< Object initializations */
45 #define LwM2M_PRIO_APP 3	/**< Application logic initialization */
46 /** @} */
47 
48 /**
49  * @brief Declare an initialization function to be executed when LwM2M engine starts.
50  *
51  * When LwM2M engine starts up, it first executes all initialization functions in following
52  * priority order:
53  * 1. LWM2M_PRIO_ENGINE
54  * 2. LWM2M_PRIO_CORE, this is where all LwM2M core objects are initialized
55  * 3. LWM2M_PRIO_OBJ, this is where all other than core objects are initialized
56  * 4. LwM2M_PRIO_APP, application initialization.
57  *                    For example create sensor objects, and register object callbacks.
58  *
59  * @param[in] prio Priority, one of @ref LWM2M_PRIO macros.
60  * @param[in] init_function Initialization function
61  */
62 #define LWM2M_ON_INIT(prio, init_function)                                                         \
63 	STRUCT_SECTION_ITERABLE(lwm2m_init_func,                                                   \
64 				CONCAT(LWM2M, prio, init_function)) = {.f = init_function}
65 
66 /**
67  * @brief Declare engine initialization function.
68  * @sa LWM2M_ON_INIT
69  * @param[in] init_function Initialization function
70  */
71 #define LWM2M_ENGINE_INIT(init_function) LWM2M_ON_INIT(LWM2M_PRIO_ENGINE, init_function)
72 
73 /**
74  * @brief Declare core object initialization function.
75  * @sa LWM2M_ON_INIT
76  * @param[in] init_function Initialization function
77  */
78 #define LWM2M_CORE_INIT(init_function) LWM2M_ON_INIT(LWM2M_PRIO_CORE, init_function)
79 
80 /**
81  * @brief Declare object initialization function.
82  * @sa LWM2M_ON_INIT
83  * @param[in] init_function Initialization function
84  */
85 #define LWM2M_OBJ_INIT(init_function) LWM2M_ON_INIT(LWM2M_PRIO_OBJ, init_function)
86 
87 /**
88  * @brief Declare application specific initialization function.
89  * @sa LWM2M_ON_INIT
90  * @param[in] init_function Initialization function
91  */
92 #define LWM2M_APP_INIT(init_function) LWM2M_ON_INIT(LWM2M_PRIO_APP, init_function)
93 
94 /**
95  * @brief Validates that writing is a legal operation on the field given by the object in
96  * @p obj_inst and the resource id in @p msg. Returns the field to obj_field (if it exists).
97  *
98  * @param[in] msg lwm2m message to signal for which resource the write access should checked
99  * @param[in] obj_inst Engine object instance to signal which object the resource belongs to
100  * @param[out] obj_field Engine obejct field buffer pointer to store the field being checked
101  * @return 0 for successful validation and negative in all other cases
102  */
103 int lwm2m_engine_validate_write_access(struct lwm2m_message *msg,
104 				       struct lwm2m_engine_obj_inst *obj_inst,
105 				       struct lwm2m_engine_obj_field **obj_field);
106 
107 /* LwM2M context functions */
108 /**
109  * @brief Removes all observes, clears all pending coap messages and resets all messages
110  * associated with this context.
111  *
112  * @param[in] client_ctx Context to close
113  */
114 void lwm2m_engine_context_close(struct lwm2m_ctx *client_ctx);
115 
116 /**
117  * @brief Initializes a lwm2m_ctx before a socket can be associated with it.
118  *
119  * @param[in] client_ctx Context to initialize
120  */
121 void lwm2m_engine_context_init(struct lwm2m_ctx *client_ctx);
122 
123 /* Message buffer functions */
124 uint8_t *lwm2m_get_message_buf(void);
125 int lwm2m_put_message_buf(uint8_t *buf);
126 int lwm2m_perform_composite_observation_op(struct lwm2m_message *msg, uint8_t *token,
127 					   uint8_t token_length, sys_slist_t *lwm2m_path_list);
128 
129 /**
130  * @brief Checks if context has access to the object specified by @p path
131  *
132  * @param[in] client_ctx lwm2m ctx of the connection
133  * @param[in] path Path of the object
134  * @return Returns false if the bootstrap flag of @p client_ctx is not set
135  */
136 bool lwm2m_engine_bootstrap_override(struct lwm2m_ctx *client_ctx, struct lwm2m_obj_path *path);
137 
138 /**
139  * @brief Deletes the object instance specified by msg->path. If the object instance id of the
140  * path is null (i.e path.level == 1), all object instances of that object will be deleted.
141  * Should only be called if delete request comes from a bootstrap server.
142  *
143  * @param[in] msg lwm2m message with operation delete
144  * @return 0 for success or negative in case of error
145  */
146 int bootstrap_delete(struct lwm2m_message *msg);
147 
148 /**
149  * @brief Adds the periodic @p service to the work queue. The period of the service becomes
150  * @p period_ms.
151  *
152  * @param[in] service Periodic service to be added
153  * @param[in] period_ms Period of the periodic service
154  * @return 0 for success or negative in case of error
155  */
156 int lwm2m_engine_add_service(k_work_handler_t service, uint32_t period_ms);
157 
158 /**
159  * @brief Update the period of a given service or remove it.
160  *
161  * Allow the period modification on an existing service created with
162  * lwm2m_engine_add_service(). When period is zero, service is removed.
163  *
164  * @param[in] service Handler of the periodic_service
165  * @param[in] period_ms New period for the periodic_service (in milliseconds) or zero.
166  *
167  * @return 0 for success, 1 when service was removed or negative in case of error.
168  */
169 int lwm2m_engine_update_service_period(k_work_handler_t service, uint32_t period_ms);
170 
171 /**
172  * @brief Call specific service handler only once at given timestamp.
173  *
174  * @param[in] service service to be called
175  * @param[in] timestamp Time when to call
176  * @return 0 for success or negative in case of error
177  */
178 int lwm2m_engine_call_at(k_work_handler_t service, int64_t timestamp);
179 
180 /**
181  * @brief Call given handler from engine context.
182  *
183  * @param[in] service Service callback to be called.
184  * @return 0 for success or negative in case of error
185  */
186 int lwm2m_engine_call_now(k_work_handler_t service);
187 
188 /**
189  * @brief Returns the index in the security objects list corresponding to the object instance
190  * id given by @p obj_inst_id
191  *
192  * @param[in] obj_inst_id object instance id of the security instance
193  * @return index in the list or negative in case of error
194  */
195 int lwm2m_security_inst_id_to_index(uint16_t obj_inst_id);
196 
197 /**
198  * @brief Returns the object instance id of the security having ssid given by @p short_id.
199  *
200  * @param[in] short_id ssid of the security object
201  * @return Object instance id or negative in case not found
202  */
203 int lwm2m_security_short_id_to_inst(uint16_t short_id);
204 
205 /**
206  * @brief Returns the object instance id of the security object instance at @p index
207  * in the security object list.
208  *
209  * @param[in] index Index in the security object list
210  * @return Object instance id of the security instance or negative in case of error
211  */
212 int lwm2m_security_index_to_inst_id(int index);
213 
214 #if defined(CONFIG_LWM2M_FIRMWARE_UPDATE_OBJ_SUPPORT)
215 /**
216  * @brief Sets the update state (as specified in  LWM2M SPEC E.6 regarding the firmware update)
217  * of the Firmware object instance given by @p obj_inst_id to @p state.
218  * (i.e Sets the value of resource 5/ @p obj_inst_id /3)
219  *
220  * @param[in] obj_inst_id Object instance id of the firmware object instance
221  * @param[in] state (STATE_IDLE through STATE_UPDATING)
222  */
223 void lwm2m_firmware_set_update_state_inst(uint16_t obj_inst_id, uint8_t state);
224 
225 /**
226  * @brief Sets the result state (as specified in  LWM2M SPEC E.6 regarding the firmware update)
227  * of the Firmware object instance given by @p obj_inst_id to @p result.
228  * (i.e Sets the value of resource 5/ @p obj_inst_id /5)
229  *
230  * @param[in] obj_inst_id Object instance id of the firmware object instance
231  * @param[in] result (RESULT_DEFAULT through RESULT_UNSUP_PROTO)
232  */
233 void lwm2m_firmware_set_update_result_inst(uint16_t obj_inst_id, uint8_t result);
234 
235 /**
236  * @brief Equivalent to lwm2m_firmware_set_update_state_inst(0, state).
237  *
238  * @param[in] state (STATE_IDLE through STATE_UPDATING)
239  */
240 void lwm2m_firmware_set_update_state(uint8_t state);
241 
242 /**
243  * @brief Equivalent to lwm2m_firmware_set_update_result_inst(0, result).
244  *
245  * @param[in] result (RESULT_DEFAULT through RESULT_UNSUP_PROTO)
246  */
247 void lwm2m_firmware_set_update_result(uint8_t result);
248 
249 /**
250  * @brief Returns the update state (as specified in  LWM2M SPEC E.6 regarding the firmware update)
251  * of the Firmware object instance given by @p obj_inst_id.
252  * (i.e Gets the value of resource 5/ @p obj_inst_id /3)
253  * @param[in] obj_inst_id Object instance id of the firmware object
254  * @return (STATE_IDLE through STATE_UPDATING)
255  */
256 uint8_t lwm2m_firmware_get_update_state_inst(uint16_t obj_inst_id);
257 
258 /**
259  * @brief Equivalent to lwm2m_firmware_get_update_state_inst(0).
260  *
261  * @return (STATE_IDLE through STATE_UPDATING)
262  */
263 uint8_t lwm2m_firmware_get_update_state(void);
264 
265 /**
266  * @brief Returns the result state (as specified in  LWM2M SPEC E.6 regarding the firmware update)
267  * of the Firmware object instance given by @p obj_inst_id.
268  * (i.e Gets the value of resource 5/ @p obj_inst_id /5)
269  * @param[in] obj_inst_id Object instance id of the firmware object
270  * @return (RESULT_DEFAULT through RESULT_UNSUP_PROTO)
271  */
272 uint8_t lwm2m_firmware_get_update_result_inst(uint16_t obj_inst_id);
273 
274 /**
275  * @brief Equivalent to lwm2m_firmware_get_update_result_inst(0).
276  *
277  * @return (RESULT_DEFAULT through RESULT_UNSUP_PROTO)
278  */
279 uint8_t lwm2m_firmware_get_update_result(void);
280 #endif
281 
282 /* Network Layer */
283 /**
284  * @brief Opens a socket for the client_ctx if it does not exist. Saves the
285  * socket file descriptor to client_ctx->sock_fd.
286  *
287  * @param[in] client_ctx lwm2m context to open a socket for
288  * @return 0 for success or negative in case of error
289  */
290 int lwm2m_open_socket(struct lwm2m_ctx *client_ctx);
291 
292 /**
293  * @brief Closes the socket with the file descriptor given by client_ctx->sock_fd.
294  * Does nothing if the context's socket is already closed.
295  *
296  * @param[in, out] client_ctx lwm2m context whose socket is to be closed
297  * @return 0 for success or negative in case of error
298  */
299 int lwm2m_close_socket(struct lwm2m_ctx *client_ctx);
300 
301 /**
302  * @brief Removes the socket with the file descriptor given by client_ctx->sock_fd from the
303  * lwm2m work loop. Keeps the socket open.
304  *
305  * @param[in, out] client_ctx lwm2m context whose socket is being suspended
306  * @return 0 for success or negative in case of error
307  */
308 int lwm2m_socket_suspend(struct lwm2m_ctx *client_ctx);
309 /**
310  * @brief Adds an existing socket to the lwm2m work loop. (The socket specified by the file
311  * descriptor in ctx->sock_fd)
312  *
313  * @param[in] ctx lwm2m context being added to the lwm2m work loop
314  * @return 0 for success or negative in case of error
315  */
316 int lwm2m_socket_add(struct lwm2m_ctx *ctx);
317 
318 /**
319  * @brief Removes a socket from the lwm2m work loop.
320  *
321  * @param[in] ctx lwm2m context to be removed from the lwm2m work loop
322  */
323 void lwm2m_socket_del(struct lwm2m_ctx *ctx);
324 
325 /**
326  * @brief Creates a socket for the @p client_ctx (if it does not exist) and adds it to
327  * the lwm2m work loop.
328  *
329  * @param client_ctx lwm2m context that the socket is being added for
330  * @return 0 for success or negative in case of error
331  */
332 int lwm2m_socket_start(struct lwm2m_ctx *client_ctx);
333 
334 /**
335  * @brief Closes the socket with file descriptor given by client_ctx->sock_fd.
336  *
337  * @param client_ctx Context whose socket is being closed
338  * @return 0 for success or negative in case of error
339  */
340 int lwm2m_socket_close(struct lwm2m_ctx *client_ctx);
341 
342 /**
343  * @brief Closes the socket connection when queue mode is enabled.
344  *
345  * @param[in, out] client_ctx lwm2m context to be closed
346  * @return 0 for success or negative in case of error
347  */
348 int lwm2m_engine_close_socket_connection(struct lwm2m_ctx *client_ctx);
349 
350 /**
351  * @brief Starts the socket of @p client_ctx. Requires CONFIG_LWM2M_DTLS_SUPPORT=y.
352  *
353  * @param[in] client_ctx lwm2m context to be re-added to the lwm2m work loop
354  * @return 0 for success or negative in case of error
355  */
356 int lwm2m_engine_connection_resume(struct lwm2m_ctx *client_ctx);
357 
358 /**
359  * @brief Moves all queued messages to pending.
360  *
361  * @param[in, out] client_ctx
362  * @return 0 for success or negative in case of error
363  */
364 int lwm2m_push_queued_buffers(struct lwm2m_ctx *client_ctx);
365 
366 /* Resources */
367 struct lwm2m_ctx **lwm2m_sock_ctx(void);
368 int lwm2m_sock_nfds(void);
369 
370 /**
371  * @brief Trigger the LwM2M engine to run.
372  *
373  * This function wakes up ongoing poll() from the socket-loop.
374  * It should be called when new transmissions are scheduled or service schedules are modified.
375  */
376 void lwm2m_engine_wake_up(void);
377 
378 #endif /* LWM2M_ENGINE_H */
379