1 /*
2  * Copyright (c) 2017 Linaro Limited
3  * Copyright (c) 2018-2019 Foundries.io
4  * Copyright (c) 2021 Voi Technology AB
5  *
6  * SPDX-License-Identifier: Apache-2.0
7  */
8 
9 #define LOG_MODULE_NAME net_lwm2m_obj_swmgmt
10 #define LOG_LEVEL CONFIG_LWM2M_LOG_LEVEL
11 
12 #include <zephyr/logging/log.h>
13 LOG_MODULE_REGISTER(LOG_MODULE_NAME);
14 
15 #include <string.h>
16 #include <zephyr/init.h>
17 
18 #include <stdint.h>
19 #include <zephyr/net/lwm2m.h>
20 
21 #include "lwm2m_object.h"
22 #include "lwm2m_engine.h"
23 
24 #include "lwm2m_pull_context.h"
25 
26 #define SWMGMT_VERSION_MAJOR 1
27 #define SWMGMT_VERSION_MINOR 0
28 
29 #define SWMGMT_PACKAGE_NAME_ID 0
30 #define SWMGMT_PACKAGE_VERSION_ID 1
31 #define SWMGMT_PACKAGE_ID 2
32 #define SWMGMT_PACKAGE_URI_ID 3
33 #define SWMGMT_INSTALL_ID 4
34 #define SWMGMT_CHECKPOINT_ID 5
35 #define SWMGMT_UNINSTALL_ID 6
36 #define SWMGMT_UPDATE_STATE_ID 7
37 #define SWMGMT_UPDATE_SUPPORTED_OBJECTS_ID 8
38 #define SWMGMT_UPDATE_RESULT_ID 9
39 #define SWMGMT_ACTIVATE_ID 10
40 #define SWMGMT_DEACTIVATE_ID 11
41 #define SWMGMT_ACTIVATION_UPD_STATE_ID 12
42 #define SWMGMT_PACKAGE_SETTINGS_ID 13
43 #define SWMGMT_USER_NAME_ID 14
44 #define SWMGMT_PASSWORD_ID 15
45 #define SWMGMT_MAX_ID 16
46 
47 #define PACKAGE_NAME_LEN CONFIG_LWM2M_SWMGMT_PACKAGE_NAME_LEN
48 #define PACKAGE_VERSION_LEN CONFIG_LWM2M_SWMGMT_PACKAGE_VERSION_LEN
49 #define PACKAGE_URI_LEN CONFIG_LWM2M_SWMGMT_PACKAGE_URI_LEN
50 #define MAX_INSTANCE_COUNT CONFIG_LWM2M_SWMGMT_MAX_INSTANCE_COUNT
51 
52 /*
53  * Calculate resource instances as follows:
54  * start with SWMGMT_MAX_ID
55  * subtract EXEC resources (4)
56  */
57 #define NR_EXEC_RESOURCES 4
58 #define RESOURCE_INSTANCE_COUNT (SWMGMT_MAX_ID - NR_EXEC_RESOURCES)
59 
60 static struct lwm2m_engine_obj swmgmt;
61 static struct lwm2m_engine_obj_field fields[] = {
62 	OBJ_FIELD(SWMGMT_PACKAGE_NAME_ID, R, STRING),
63 	OBJ_FIELD(SWMGMT_PACKAGE_VERSION_ID, R, STRING),
64 	OBJ_FIELD(SWMGMT_PACKAGE_ID, W_OPT, OPAQUE),
65 	OBJ_FIELD(SWMGMT_PACKAGE_URI_ID, W_OPT, STRING),
66 	OBJ_FIELD_EXECUTE(SWMGMT_INSTALL_ID),
67 	OBJ_FIELD(SWMGMT_CHECKPOINT_ID, R_OPT, OBJLNK),
68 	OBJ_FIELD_EXECUTE(SWMGMT_UNINSTALL_ID),
69 	OBJ_FIELD(SWMGMT_UPDATE_STATE_ID, R, U8),
70 	OBJ_FIELD(SWMGMT_UPDATE_SUPPORTED_OBJECTS_ID, RW_OPT, BOOL),
71 	OBJ_FIELD(SWMGMT_UPDATE_RESULT_ID, R, U8),
72 	OBJ_FIELD_EXECUTE(SWMGMT_ACTIVATE_ID),
73 	OBJ_FIELD_EXECUTE(SWMGMT_DEACTIVATE_ID),
74 	OBJ_FIELD(SWMGMT_ACTIVATION_UPD_STATE_ID, R, BOOL),
75 	OBJ_FIELD(SWMGMT_PACKAGE_SETTINGS_ID, RW_OPT, OBJLNK),
76 	OBJ_FIELD(SWMGMT_USER_NAME_ID, W_OPT, STRING),
77 	OBJ_FIELD(SWMGMT_PASSWORD_ID, W_OPT, STRING),
78 };
79 
80 static struct lwm2m_engine_obj_inst inst[MAX_INSTANCE_COUNT];
81 static struct lwm2m_engine_res res[MAX_INSTANCE_COUNT][SWMGMT_MAX_ID];
82 static struct lwm2m_engine_res_inst res_inst[MAX_INSTANCE_COUNT][RESOURCE_INSTANCE_COUNT];
83 
84 #define UPD_STATE_INITIAL 0
85 #define UPD_STATE_DOWNLOAD_STARTED 1
86 #define UPD_STATE_DOWNLOADED 2
87 #define UPD_STATE_DELIVERED 3
88 #define UPD_STATE_INSTALLED 4
89 
90 #define EVENT_PKG_URI_WRITE 0
91 #define EVENT_PKG_WRITTEN 1
92 #define EVENT_PKG_INTEGRITY_VERIFIED 2
93 #define EVENT_INSTALL 4
94 #define EVENT_INSTALL_SUCCESSFUL 5
95 #define EVENT_INSTALL_FAIL 6
96 #define EVENT_DELETE_PACKAGE 7
97 #define EVENT_FOR_UPDATE 8
98 #define EVENT_DOWNLOAD_FAILED 9
99 #define EVENT_PKG_INTEGRITY_FAILED 10
100 #define EVENT_ACTIVATE 11
101 #define EVENT_DEACTIVATE 12
102 
103 /*
104  * 0: Initial value. Prior to download any new package in the Device, Update
105  *    Result MUST be reset to this initial value. One side effect of executing
106  *    the Uninstall resource is to reset Update Result to this initial value 0.
107  */
108 #define UPD_RES_INITIAL 0
109 
110 /* 1: Downloading. The package downloading process is ongoing. */
111 #define UPD_RES_DOWNLOADING 1
112 
113 /* 2: Software successfully installed. */
114 #define UPD_RES_SW_SUCCESSFULLY_INSTALLED 2
115 
116 /* 3: Successfully Downloaded and package integrity verified */
117 #define UPD_RES_DOWNLOADED_AND_VERIFIED 3
118 
119 /* 4-49: reserved for expansion of other scenarios>> */
120 /* 50: Not enough storage for the new software package. */
121 #define UPD_RES_NOT_ENOUGH_STORAGE 50
122 
123 /* 51: Out of memory during downloading process. */
124 #define UPD_RES_OUT_OF_MEMORY_DURING_DOWNLOAD 51
125 
126 /* 52: Connection lost during downloading process. */
127 #define UPD_RES_LOST_CONNECTION_DURING_DOWNLOAD 52
128 
129 /* 53: Package integrity check failure. */
130 #define UPD_RES_PACKAGE_INTEGRITY_CHECK_FAILURE 53
131 
132 /* 54: Unsupported package type. */
133 #define UPD_RES_UNSUPPORTED_PACKAGE_TYPE 54
134 
135 /* 55: Undefined */
136 /* 56: Invalid URI */
137 #define UPD_RES_INVALID_URI 56
138 
139 /* 57: Device defined update error */
140 #define UPD_RES_DEVICE_DEFINED_UPDATE_ERROR 57
141 
142 /* 58: Software installation failure */
143 #define UPD_RES_SW_INSTALLATION_FAILURE 58
144 
145 /* 59: Uninstallation Failure during forUpdate(arg=0) */
146 #define UPD_RES_UNINSTALLATION_FAILURE_FOR_UPDATE 59
147 
148 /*
149  * 60-200 : reserved for expansion selection to be in blocks depending on new
150  *          introduction of features
151  */
152 
153 struct lwm2m_swmgmt_data {
154 	uint16_t obj_inst_id;
155 
156 	char package_name[PACKAGE_NAME_LEN];
157 	char package_version[PACKAGE_VERSION_LEN];
158 
159 	bool next_package_is_upgrade;
160 
161 	uint8_t update_state;
162 	uint8_t update_result;
163 
164 	bool activation_state;
165 
166 	lwm2m_engine_get_data_cb_t read_package_cb;
167 	lwm2m_engine_execute_cb_t install_package_cb;
168 	lwm2m_engine_user_cb_t upgrade_package_cb;
169 	lwm2m_engine_execute_cb_t delete_package_cb;
170 	lwm2m_engine_execute_cb_t activate_cb;
171 	lwm2m_engine_execute_cb_t deactivate_cb;
172 	lwm2m_engine_set_data_cb_t write_package_cb;
173 
174 #ifdef CONFIG_LWM2M_FIRMWARE_UPDATE_PULL_SUPPORT
175 	char package_uri[PACKAGE_URI_LEN];
176 #endif
177 };
178 
179 /* Package pull request should come with a verify_cb which needs to be stored for when package
180  * gets downloaded
181  */
182 static int (*verify_package)(void);
183 
callback_execute_not_defined(uint16_t obj_inst_id,uint8_t * args,uint16_t args_len)184 static int callback_execute_not_defined(uint16_t obj_inst_id, uint8_t *args, uint16_t args_len)
185 {
186 	LOG_ERR("Callback not defined for inst %u", obj_inst_id);
187 	return -EINVAL;
188 }
189 
callback_write_not_defined(uint16_t obj_inst_id,uint16_t res_id,uint16_t res_inst_id,uint8_t * data,uint16_t data_len,bool last_block,size_t total_size,size_t offset)190 static int callback_write_not_defined(uint16_t obj_inst_id, uint16_t res_id,
191 				      uint16_t res_inst_id, uint8_t *data,
192 				      uint16_t data_len, bool last_block,
193 				      size_t total_size, size_t offset)
194 {
195 	LOG_ERR("Callback not defined for inst %u", obj_inst_id);
196 	return -EINVAL;
197 }
198 
callback_read_not_defined(uint16_t obj_inst_id,uint16_t res_id,uint16_t res_inst_id,size_t * data_len)199 static void *callback_read_not_defined(uint16_t obj_inst_id, uint16_t res_id, uint16_t res_inst_id,
200 				       size_t *data_len)
201 {
202 	LOG_ERR("Callback not defined for inst %u", obj_inst_id);
203 	return NULL;
204 }
205 
set_sw_update_state(struct lwm2m_swmgmt_data * instance,uint8_t state)206 static void set_sw_update_state(struct lwm2m_swmgmt_data *instance, uint8_t state)
207 {
208 	int ret;
209 	struct lwm2m_obj_path obj_path = LWM2M_OBJ(LWM2M_OBJECT_SOFTWARE_MANAGEMENT_ID,
210 						   instance->obj_inst_id,
211 						   SWMGMT_UPDATE_STATE_ID);
212 
213 	ret = lwm2m_set_u8(&obj_path, state);
214 	if (ret != 0) {
215 		LOG_ERR("Could not set state");
216 	}
217 }
218 
set_sw_update_result(struct lwm2m_swmgmt_data * instance,uint8_t result)219 static void set_sw_update_result(struct lwm2m_swmgmt_data *instance, uint8_t result)
220 {
221 	int ret;
222 	struct lwm2m_obj_path obj_path = LWM2M_OBJ(LWM2M_OBJECT_SOFTWARE_MANAGEMENT_ID,
223 						   instance->obj_inst_id,
224 						   SWMGMT_UPDATE_RESULT_ID);
225 
226 	ret = lwm2m_set_u8(&obj_path, result);
227 	if (ret != 0) {
228 		LOG_ERR("Could not set result");
229 	}
230 }
231 
set_sw_update_act_state(struct lwm2m_swmgmt_data * instance,bool state)232 static void set_sw_update_act_state(struct lwm2m_swmgmt_data *instance, bool state)
233 {
234 	int ret;
235 	struct lwm2m_obj_path obj_path = LWM2M_OBJ(LWM2M_OBJECT_SOFTWARE_MANAGEMENT_ID,
236 						   instance->obj_inst_id,
237 						   SWMGMT_ACTIVATION_UPD_STATE_ID);
238 
239 	ret = lwm2m_set_bool(&obj_path, state);
240 	if (ret != 0) {
241 		LOG_ERR("Could not set activation state");
242 	}
243 }
244 
245 static struct lwm2m_swmgmt_data swmgmt_data[MAX_INSTANCE_COUNT] = { 0 };
246 
find_index(uint16_t obj_inst_id)247 static struct lwm2m_swmgmt_data *find_index(uint16_t obj_inst_id)
248 {
249 	int index;
250 
251 	for (index = 0; index < MAX_INSTANCE_COUNT; index++) {
252 		if (inst[index].obj && inst[index].obj_inst_id == obj_inst_id) {
253 			return &swmgmt_data[index];
254 		}
255 	}
256 
257 	LOG_DBG("No instance found for obj id %u", obj_inst_id);
258 	return NULL;
259 }
260 
lwm2m_swmgmt_set_activate_cb(uint16_t obj_inst_id,lwm2m_engine_execute_cb_t cb)261 int lwm2m_swmgmt_set_activate_cb(uint16_t obj_inst_id, lwm2m_engine_execute_cb_t cb)
262 {
263 	struct lwm2m_swmgmt_data *instance = NULL;
264 
265 	instance = find_index(obj_inst_id);
266 	if (!instance) {
267 		return -ENOENT;
268 	}
269 
270 	if (!cb) {
271 		cb = callback_execute_not_defined;
272 	}
273 
274 	instance->activate_cb = cb;
275 	return 0;
276 }
277 
lwm2m_swmgmt_set_deactivate_cb(uint16_t obj_inst_id,lwm2m_engine_execute_cb_t cb)278 int lwm2m_swmgmt_set_deactivate_cb(uint16_t obj_inst_id, lwm2m_engine_execute_cb_t cb)
279 {
280 	struct lwm2m_swmgmt_data *instance = NULL;
281 
282 	instance = find_index(obj_inst_id);
283 	if (!instance) {
284 		return -ENOENT;
285 	}
286 
287 	if (!cb) {
288 		cb = callback_execute_not_defined;
289 	}
290 
291 	instance->deactivate_cb = cb;
292 	return 0;
293 }
294 
lwm2m_swmgmt_set_install_package_cb(uint16_t obj_inst_id,lwm2m_engine_execute_cb_t cb)295 int lwm2m_swmgmt_set_install_package_cb(uint16_t obj_inst_id, lwm2m_engine_execute_cb_t cb)
296 {
297 	struct lwm2m_swmgmt_data *instance = NULL;
298 
299 	instance = find_index(obj_inst_id);
300 	if (!instance) {
301 		return -ENOENT;
302 	}
303 
304 	if (!cb) {
305 		cb = callback_execute_not_defined;
306 	}
307 
308 	instance->install_package_cb = cb;
309 	return 0;
310 }
311 
lwm2m_swmgmt_set_delete_package_cb(uint16_t obj_inst_id,lwm2m_engine_execute_cb_t cb)312 int lwm2m_swmgmt_set_delete_package_cb(uint16_t obj_inst_id, lwm2m_engine_execute_cb_t cb)
313 {
314 	struct lwm2m_swmgmt_data *instance = NULL;
315 
316 	instance = find_index(obj_inst_id);
317 	if (!instance) {
318 		return -ENOENT;
319 	}
320 
321 	if (!cb) {
322 		cb = callback_execute_not_defined;
323 	}
324 
325 	instance->delete_package_cb = cb;
326 	return 0;
327 }
328 
lwm2m_swmgmt_set_write_package_cb(uint16_t obj_inst_id,lwm2m_engine_set_data_cb_t cb)329 int lwm2m_swmgmt_set_write_package_cb(uint16_t obj_inst_id, lwm2m_engine_set_data_cb_t cb)
330 {
331 	struct lwm2m_swmgmt_data *instance = NULL;
332 
333 	instance = find_index(obj_inst_id);
334 	if (!instance) {
335 		return -ENOENT;
336 	}
337 
338 	if (!cb) {
339 		cb = callback_write_not_defined;
340 	}
341 
342 	instance->write_package_cb = cb;
343 	return 0;
344 }
345 
lwm2m_swmgmt_set_read_package_version_cb(uint16_t obj_inst_id,lwm2m_engine_get_data_cb_t cb)346 int lwm2m_swmgmt_set_read_package_version_cb(uint16_t obj_inst_id, lwm2m_engine_get_data_cb_t cb)
347 {
348 	struct lwm2m_swmgmt_data *instance = NULL;
349 
350 	instance = find_index(obj_inst_id);
351 	if (!instance) {
352 		return -ENOENT;
353 	}
354 
355 	if (!cb) {
356 		cb = callback_read_not_defined;
357 	}
358 
359 	instance->read_package_cb = cb;
360 	return 0;
361 }
362 
state_read_pkg_version(uint16_t obj_inst_id,uint16_t res_id,uint16_t res_inst_id,size_t * data_len)363 void *state_read_pkg_version(uint16_t obj_inst_id, uint16_t res_id, uint16_t res_inst_id,
364 			     size_t *data_len)
365 {
366 	struct lwm2m_swmgmt_data *instance = NULL;
367 	void *result = NULL;
368 
369 	instance = find_index(obj_inst_id);
370 	if (!instance) {
371 		return NULL;
372 	}
373 
374 	if (instance->read_package_cb) {
375 		result = instance->read_package_cb(obj_inst_id, res_id, res_inst_id, data_len);
376 	}
377 
378 	return result;
379 }
380 
handle_event(struct lwm2m_swmgmt_data * instance,uint8_t event)381 static int handle_event(struct lwm2m_swmgmt_data *instance, uint8_t event)
382 {
383 	int ret = 0;
384 
385 	if (!instance) {
386 		return -EINVAL;
387 	}
388 
389 	switch (instance->update_state) {
390 	case UPD_STATE_INITIAL:
391 		switch (event) {
392 		case EVENT_PKG_URI_WRITE:
393 			set_sw_update_state(instance, UPD_STATE_DOWNLOAD_STARTED);
394 			set_sw_update_result(instance, UPD_RES_DOWNLOADING);
395 			ret = 0;
396 			break;
397 		default:
398 			ret = -EINVAL;
399 			break;
400 		}
401 		break;
402 	case UPD_STATE_DOWNLOAD_STARTED:
403 		switch (event) {
404 		case EVENT_PKG_WRITTEN:
405 			set_sw_update_state(instance, UPD_STATE_DOWNLOADED);
406 			set_sw_update_result(instance, UPD_RES_INITIAL);
407 			break;
408 		case EVENT_DOWNLOAD_FAILED:
409 			set_sw_update_state(instance, UPD_STATE_INITIAL);
410 
411 			/* Inform the instance of DOWNLOAD_FAILED by calling
412 			 * write_package_cb with a bunch of NULL parameters
413 			 */
414 			instance->write_package_cb(instance->obj_inst_id, 0, 0, NULL, 0, false, 0);
415 			break;
416 		default:
417 			ret = -EINVAL;
418 			break;
419 		}
420 		break;
421 	case UPD_STATE_DOWNLOADED:
422 		switch (event) {
423 		case (EVENT_PKG_INTEGRITY_VERIFIED):
424 			set_sw_update_state(instance, UPD_STATE_DELIVERED);
425 			set_sw_update_result(instance, UPD_RES_INITIAL);
426 			break;
427 		case (EVENT_PKG_INTEGRITY_FAILED):
428 			set_sw_update_state(instance, UPD_STATE_INITIAL);
429 			set_sw_update_result(instance, UPD_RES_PACKAGE_INTEGRITY_CHECK_FAILURE);
430 			break;
431 		default:
432 			ret = -EINVAL;
433 			break;
434 		}
435 		break;
436 	case UPD_STATE_DELIVERED:
437 		switch (event) {
438 		case EVENT_INSTALL:
439 			if (instance->next_package_is_upgrade) {
440 				ret = instance->upgrade_package_cb(instance->obj_inst_id);
441 			}
442 
443 			else {
444 				ret = instance->install_package_cb(instance->obj_inst_id, NULL, 0);
445 			}
446 
447 			break;
448 
449 		case EVENT_INSTALL_SUCCESSFUL:
450 			set_sw_update_state(instance, UPD_STATE_INSTALLED);
451 			set_sw_update_result(instance, UPD_RES_SW_SUCCESSFULLY_INSTALLED);
452 			instance->next_package_is_upgrade = false;
453 			break;
454 
455 		case EVENT_INSTALL_FAIL:
456 			set_sw_update_state(instance, UPD_STATE_DELIVERED);
457 			set_sw_update_result(instance, UPD_RES_SW_INSTALLATION_FAILURE);
458 			break;
459 
460 		case EVENT_DELETE_PACKAGE:
461 			ret = instance->delete_package_cb(instance->obj_inst_id, NULL, 0);
462 			if (ret == 0) {
463 				set_sw_update_state(instance, UPD_STATE_INITIAL);
464 				/* update_result unchanged */
465 			}
466 			break;
467 
468 		default:
469 			ret = -EINVAL;
470 			break;
471 		}
472 		break;
473 	case UPD_STATE_INSTALLED:
474 		switch (event) {
475 		case EVENT_ACTIVATE:
476 			ret = instance->activate_cb(instance->obj_inst_id, NULL, 0);
477 			if (ret == 0) {
478 				set_sw_update_act_state(instance, true);
479 			}
480 			break;
481 		case EVENT_DEACTIVATE:
482 			ret = instance->deactivate_cb(instance->obj_inst_id, NULL, 0);
483 			if (ret == 0) {
484 				set_sw_update_act_state(instance, false);
485 			}
486 			break;
487 		case EVENT_FOR_UPDATE:
488 			instance->next_package_is_upgrade = true;
489 			set_sw_update_state(instance, UPD_STATE_INITIAL);
490 			set_sw_update_result(instance, UPD_RES_INITIAL);
491 		case EVENT_DELETE_PACKAGE:
492 			ret = instance->delete_package_cb(instance->obj_inst_id, NULL, 0);
493 			if (ret == 0) {
494 				set_sw_update_state(instance, UPD_STATE_INITIAL);
495 				set_sw_update_result(instance, UPD_RES_INITIAL);
496 			}
497 			break;
498 		default:
499 			ret = -EINVAL;
500 			break;
501 		}
502 		break;
503 	default:
504 		ret = -EINVAL;
505 		break;
506 	}
507 
508 	return ret;
509 }
510 
install_cb(uint16_t obj_inst_id,uint8_t * args,uint16_t args_len)511 static int install_cb(uint16_t obj_inst_id, uint8_t *args, uint16_t args_len)
512 {
513 	struct lwm2m_swmgmt_data *instance = NULL;
514 
515 	instance = find_index(obj_inst_id);
516 
517 	return handle_event(instance, EVENT_INSTALL);
518 }
519 
lwm2m_swmgmt_install_completed(uint16_t obj_inst_id,int error_code)520 int lwm2m_swmgmt_install_completed(uint16_t obj_inst_id, int error_code)
521 {
522 	struct lwm2m_swmgmt_data *instance = NULL;
523 
524 	instance = find_index(obj_inst_id);
525 
526 	if (error_code) {
527 		error_code = handle_event(instance, EVENT_INSTALL_FAIL);
528 	} else {
529 		error_code = handle_event(instance, EVENT_INSTALL_SUCCESSFUL);
530 	}
531 
532 	return error_code;
533 }
534 
uninstall_cb(uint16_t obj_inst_id,uint8_t * args,uint16_t args_len)535 static int uninstall_cb(uint16_t obj_inst_id, uint8_t *args, uint16_t args_len)
536 {
537 	struct lwm2m_swmgmt_data *instance = NULL;
538 
539 	instance = find_index(obj_inst_id);
540 
541 	return handle_event(instance, EVENT_DELETE_PACKAGE);
542 }
543 
activate_cb(uint16_t obj_inst_id,uint8_t * args,uint16_t args_len)544 static int activate_cb(uint16_t obj_inst_id, uint8_t *args, uint16_t args_len)
545 {
546 	struct lwm2m_swmgmt_data *instance = NULL;
547 
548 	instance = find_index(obj_inst_id);
549 
550 	return handle_event(instance, EVENT_ACTIVATE);
551 }
552 
deactivate_cb(uint16_t obj_inst_id,uint8_t * args,uint16_t args_len)553 static int deactivate_cb(uint16_t obj_inst_id, uint8_t *args, uint16_t args_len)
554 {
555 	struct lwm2m_swmgmt_data *instance = NULL;
556 
557 	instance = find_index(obj_inst_id);
558 
559 	return handle_event(instance, EVENT_DEACTIVATE);
560 }
561 
package_write_cb(uint16_t obj_inst_id,uint16_t res_id,uint16_t res_inst_id,uint8_t * data,uint16_t data_len,bool last_block,size_t total_size,size_t offset)562 static int package_write_cb(uint16_t obj_inst_id, uint16_t res_id,
563 			    uint16_t res_inst_id, uint8_t *data,
564 			    uint16_t data_len, bool last_block,
565 			    size_t total_size, size_t offset)
566 {
567 	int ret = -EINVAL;
568 	struct lwm2m_swmgmt_data *instance = NULL;
569 
570 	instance = find_index(obj_inst_id);
571 
572 	ret = handle_event(instance, EVENT_PKG_URI_WRITE);
573 
574 	if (ret < 0) {
575 		return ret;
576 	}
577 
578 	ret = instance->write_package_cb(obj_inst_id, res_id, res_inst_id, data, data_len,
579 					 last_block, total_size);
580 
581 	if (ret < 0) {
582 		handle_event(instance, EVENT_DOWNLOAD_FAILED);
583 		switch (ret) {
584 		case -ENOMEM:
585 			set_sw_update_result(instance, UPD_RES_OUT_OF_MEMORY_DURING_DOWNLOAD);
586 			break;
587 		case -ENOSPC:
588 			set_sw_update_result(instance, UPD_RES_NOT_ENOUGH_STORAGE);
589 			ret = -EFBIG;
590 			break;
591 		case -EFAULT:
592 			set_sw_update_result(instance, UPD_RES_PACKAGE_INTEGRITY_CHECK_FAILURE);
593 			break;
594 		default:
595 			set_sw_update_result(instance, UPD_RES_LOST_CONNECTION_DURING_DOWNLOAD);
596 			break;
597 		}
598 
599 		return ret;
600 	}
601 
602 	if (last_block) {
603 		handle_event(instance, EVENT_PKG_WRITTEN);
604 	}
605 
606 	return 0;
607 }
608 
set_update_result(uint16_t obj_inst_id,int error_code)609 static void set_update_result(uint16_t obj_inst_id, int error_code)
610 {
611 	int ret;
612 	struct lwm2m_swmgmt_data *instance;
613 
614 	instance = find_index(obj_inst_id);
615 
616 	if (error_code == 0) {
617 		handle_event(instance, EVENT_PKG_WRITTEN);
618 
619 		/* If the verify function wasn't provided, skip the check. */
620 		if (verify_package) {
621 			ret = verify_package();
622 		} else {
623 			ret = 0;
624 		}
625 
626 		if (ret == 0) {
627 			handle_event(instance, EVENT_PKG_INTEGRITY_VERIFIED);
628 		} else {
629 			handle_event(instance, EVENT_PKG_INTEGRITY_FAILED);
630 		}
631 
632 		return;
633 	}
634 
635 	handle_event(instance, EVENT_DOWNLOAD_FAILED);
636 	if (error_code == -ENOMEM) {
637 		set_sw_update_result(instance, UPD_RES_OUT_OF_MEMORY_DURING_DOWNLOAD);
638 	} else if (error_code == -ENOSPC) {
639 		set_sw_update_result(instance, UPD_RES_NOT_ENOUGH_STORAGE);
640 	} else if (error_code == -EFAULT) {
641 		set_sw_update_result(instance, UPD_RES_PACKAGE_INTEGRITY_CHECK_FAILURE);
642 	} else if (error_code == -ENOTSUP) {
643 		set_sw_update_result(instance, UPD_RES_INVALID_URI);
644 	} else {
645 		set_sw_update_result(instance, UPD_RES_LOST_CONNECTION_DURING_DOWNLOAD);
646 	}
647 }
648 
package_uri_write_cb(uint16_t obj_inst_id,uint16_t res_id,uint16_t res_inst_id,uint8_t * data,uint16_t data_len,bool last_block,size_t total_size,size_t offset)649 static int package_uri_write_cb(uint16_t obj_inst_id, uint16_t res_id,
650 				uint16_t res_inst_id, uint8_t *data,
651 				uint16_t data_len, bool last_block,
652 				size_t total_size, size_t offset)
653 {
654 #ifdef CONFIG_LWM2M_FIRMWARE_UPDATE_PULL_SUPPORT
655 	int error_code;
656 	struct lwm2m_swmgmt_data *instance = NULL;
657 
658 	instance = find_index(obj_inst_id);
659 
660 	struct requesting_object req = { .obj_inst_id = obj_inst_id,
661 					 .is_firmware_uri = false,
662 					 .result_cb = set_update_result,
663 					 .write_cb = instance->write_package_cb,
664 					 .verify_cb = NULL };
665 
666 	verify_package = req.verify_cb;
667 
668 	error_code = lwm2m_pull_context_start_transfer(instance->package_uri, req, K_NO_WAIT);
669 
670 	if (error_code) {
671 		return error_code;
672 	}
673 
674 	return handle_event(instance, EVENT_PKG_URI_WRITE);
675 
676 #else
677 	return -EINVAL;
678 #endif
679 }
680 
swmgmt_create(uint16_t obj_inst_id)681 static struct lwm2m_engine_obj_inst *swmgmt_create(uint16_t obj_inst_id)
682 {
683 	struct lwm2m_swmgmt_data *instance = NULL;
684 	int index, res_idx = 0, res_inst_idx = 0;
685 
686 	/* Check that there is no other instance with this ID */
687 	for (index = 0; index < MAX_INSTANCE_COUNT; index++) {
688 		if (inst[index].obj && inst[index].obj_inst_id == obj_inst_id) {
689 			LOG_ERR("Can not create instance - "
690 				"already existing: %u",
691 				obj_inst_id);
692 			return NULL;
693 		}
694 	}
695 
696 	for (index = 0; index < MAX_INSTANCE_COUNT; index++) {
697 		if (!inst[index].obj) {
698 			break;
699 		}
700 	}
701 
702 	if (index >= MAX_INSTANCE_COUNT) {
703 		LOG_ERR("Can not create instance - no more room: %u", obj_inst_id);
704 		return NULL;
705 	}
706 
707 	instance = &swmgmt_data[index];
708 
709 	/* Set default values */
710 	(void)memset(res[index], 0, sizeof(res[index][0]) * ARRAY_SIZE(res[index]));
711 	init_res_instance(res_inst[index], ARRAY_SIZE(res_inst[index]));
712 
713 	(void)memset(instance->package_name, 0, PACKAGE_NAME_LEN);
714 	(void)memset(instance->package_version, 0, PACKAGE_VERSION_LEN);
715 
716 	instance->obj_inst_id = obj_inst_id;
717 	instance->update_state = 0;
718 	instance->update_result = 0;
719 	instance->activation_state = false;
720 
721 	instance->next_package_is_upgrade = false;
722 
723 	instance->install_package_cb = callback_execute_not_defined;
724 	instance->delete_package_cb = callback_execute_not_defined;
725 	instance->activate_cb = callback_execute_not_defined;
726 	instance->deactivate_cb = callback_execute_not_defined;
727 	instance->write_package_cb = callback_write_not_defined;
728 
729 #ifdef CONFIG_LWM2M_FIRMWARE_UPDATE_PULL_SUPPORT
730 	(void)memset(instance->package_uri, 0, PACKAGE_URI_LEN);
731 #endif
732 
733 	/* initialize instance resource data */
734 	INIT_OBJ_RES_DATA_LEN(SWMGMT_PACKAGE_NAME_ID, res[index], res_idx, res_inst[index],
735 			  res_inst_idx, &instance->package_name, PACKAGE_NAME_LEN, 0);
736 
737 	INIT_OBJ_RES_LEN(SWMGMT_PACKAGE_VERSION_ID, res[index], res_idx, res_inst[index],
738 			 res_inst_idx, 1, false, true, &instance->package_version,
739 			 PACKAGE_VERSION_LEN, 0, state_read_pkg_version, NULL, NULL, NULL, NULL);
740 
741 	INIT_OBJ_RES_OPT(SWMGMT_PACKAGE_ID, res[index], res_idx, res_inst[index], res_inst_idx, 1,
742 			 false, false, NULL, NULL, NULL, package_write_cb, NULL);
743 
744 #ifdef CONFIG_LWM2M_FIRMWARE_UPDATE_PULL_SUPPORT
745 	INIT_OBJ_RES(SWMGMT_PACKAGE_URI_ID, res[index], res_idx, res_inst[index], res_inst_idx, 1,
746 		     false, true, instance->package_uri, PACKAGE_URI_LEN, NULL, NULL, NULL,
747 		     package_uri_write_cb, NULL);
748 #else
749 	INIT_OBJ_RES_OPT(SWMGMT_PACKAGE_URI_ID, res[index], res_idx, res_inst[index], res_inst_idx,
750 			 1, false, true, NULL, NULL, NULL, package_uri_write_cb, NULL);
751 #endif
752 
753 	INIT_OBJ_RES_EXECUTE(SWMGMT_INSTALL_ID, res[index], res_idx, install_cb);
754 
755 	INIT_OBJ_RES_OPTDATA(SWMGMT_CHECKPOINT_ID, res[index], res_idx, res_inst[index],
756 			     res_inst_idx);
757 
758 	INIT_OBJ_RES_EXECUTE(SWMGMT_UNINSTALL_ID, res[index], res_idx, uninstall_cb);
759 
760 	INIT_OBJ_RES_DATA(SWMGMT_UPDATE_STATE_ID, res[index], res_idx, res_inst[index],
761 			  res_inst_idx, &instance->update_state, sizeof(uint8_t));
762 
763 	INIT_OBJ_RES_OPTDATA(SWMGMT_UPDATE_SUPPORTED_OBJECTS_ID, res[index], res_idx,
764 			     res_inst[index], res_inst_idx);
765 
766 	INIT_OBJ_RES_DATA(SWMGMT_UPDATE_RESULT_ID, res[index], res_idx, res_inst[index],
767 			  res_inst_idx, &instance->update_result, sizeof(uint8_t));
768 
769 	INIT_OBJ_RES_EXECUTE(SWMGMT_ACTIVATE_ID, res[index], res_idx, activate_cb);
770 	INIT_OBJ_RES_EXECUTE(SWMGMT_DEACTIVATE_ID, res[index], res_idx, deactivate_cb);
771 
772 	INIT_OBJ_RES_DATA(SWMGMT_ACTIVATION_UPD_STATE_ID, res[index], res_idx, res_inst[index],
773 			  res_inst_idx, &instance->activation_state, sizeof(bool));
774 
775 	INIT_OBJ_RES_OPTDATA(SWMGMT_PACKAGE_SETTINGS_ID, res[index], res_idx, res_inst[index],
776 			     res_inst_idx);
777 	INIT_OBJ_RES_OPTDATA(SWMGMT_USER_NAME_ID, res[index], res_idx, res_inst[index],
778 			     res_inst_idx);
779 	INIT_OBJ_RES_OPTDATA(SWMGMT_PASSWORD_ID, res[index], res_idx, res_inst[index],
780 			     res_inst_idx);
781 
782 	inst[index].resources = res[index];
783 	inst[index].resource_count = res_idx;
784 	return &inst[index];
785 }
786 
lwm2m_swmgmt_init(void)787 static int lwm2m_swmgmt_init(void)
788 {
789 	swmgmt.obj_id = LWM2M_OBJECT_SOFTWARE_MANAGEMENT_ID;
790 	swmgmt.version_major = SWMGMT_VERSION_MAJOR;
791 	swmgmt.version_minor = SWMGMT_VERSION_MINOR;
792 	swmgmt.fields = fields;
793 	swmgmt.field_count = ARRAY_SIZE(fields);
794 	swmgmt.max_instance_count = MAX_INSTANCE_COUNT;
795 	swmgmt.create_cb = swmgmt_create;
796 	lwm2m_register_obj(&swmgmt);
797 
798 	return 0;
799 }
800 
801 LWM2M_OBJ_INIT(lwm2m_swmgmt_init);
802