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)190 static int callback_write_not_defined(uint16_t obj_inst_id, uint16_t res_id, uint16_t res_inst_id,
191 				      uint8_t *data, uint16_t data_len, bool last_block,
192 				      size_t total_size)
193 {
194 	LOG_ERR("Callback not defined for inst %u", obj_inst_id);
195 	return -EINVAL;
196 }
197 
callback_read_not_defined(uint16_t obj_inst_id,uint16_t res_id,uint16_t res_inst_id,size_t * data_len)198 static void *callback_read_not_defined(uint16_t obj_inst_id, uint16_t res_id, uint16_t res_inst_id,
199 				       size_t *data_len)
200 {
201 	LOG_ERR("Callback not defined for inst %u", obj_inst_id);
202 	return NULL;
203 }
204 
set_sw_update_state(struct lwm2m_swmgmt_data * instance,uint8_t state)205 static void set_sw_update_state(struct lwm2m_swmgmt_data *instance, uint8_t state)
206 {
207 	int ret;
208 	struct lwm2m_obj_path obj_path = LWM2M_OBJ(LWM2M_OBJECT_SOFTWARE_MANAGEMENT_ID,
209 						   instance->obj_inst_id,
210 						   SWMGMT_UPDATE_STATE_ID);
211 
212 	ret = lwm2m_set_u8(obj_path, state);
213 	if (ret != 0) {
214 		LOG_ERR("Could not set state");
215 	}
216 }
217 
set_sw_update_result(struct lwm2m_swmgmt_data * instance,uint8_t result)218 static void set_sw_update_result(struct lwm2m_swmgmt_data *instance, uint8_t result)
219 {
220 	int ret;
221 	struct lwm2m_obj_path obj_path = LWM2M_OBJ(LWM2M_OBJECT_SOFTWARE_MANAGEMENT_ID,
222 						   instance->obj_inst_id,
223 						   SWMGMT_UPDATE_RESULT_ID);
224 
225 	ret = lwm2m_set_u8(&obj_path, result);
226 	if (ret != 0) {
227 		LOG_ERR("Could not set result");
228 	}
229 }
230 
set_sw_update_act_state(struct lwm2m_swmgmt_data * instance,bool state)231 static void set_sw_update_act_state(struct lwm2m_swmgmt_data *instance, bool state)
232 {
233 	int ret;
234 	struct lwm2m_obj_path obj_path = LWM2M_OBJ(LWM2M_OBJECT_SOFTWARE_MANAGEMENT_ID,
235 						   instance->obj_inst_id,
236 						   SWMGMT_ACTIVATION_UPD_STATE_ID);
237 
238 	ret = lwm2m_set_bool(&obj_path, state);
239 	if (ret != 0) {
240 		LOG_ERR("Could not set activation state");
241 	}
242 }
243 
244 static struct lwm2m_swmgmt_data swmgmt_data[MAX_INSTANCE_COUNT] = { 0 };
245 
find_index(uint16_t obj_inst_id)246 static struct lwm2m_swmgmt_data *find_index(uint16_t obj_inst_id)
247 {
248 	int index;
249 
250 	for (index = 0; index < MAX_INSTANCE_COUNT; index++) {
251 		if (inst[index].obj && inst[index].obj_inst_id == obj_inst_id) {
252 			return &swmgmt_data[index];
253 		}
254 	}
255 
256 	LOG_DBG("No instance found for obj id %u", obj_inst_id);
257 	return NULL;
258 }
259 
lwm2m_swmgmt_set_activate_cb(uint16_t obj_inst_id,lwm2m_engine_execute_cb_t cb)260 int lwm2m_swmgmt_set_activate_cb(uint16_t obj_inst_id, lwm2m_engine_execute_cb_t cb)
261 {
262 	struct lwm2m_swmgmt_data *instance = NULL;
263 
264 	instance = find_index(obj_inst_id);
265 	if (!instance) {
266 		return -ENOENT;
267 	}
268 
269 	if (!cb) {
270 		cb = callback_execute_not_defined;
271 	}
272 
273 	instance->activate_cb = cb;
274 	return 0;
275 }
276 
lwm2m_swmgmt_set_deactivate_cb(uint16_t obj_inst_id,lwm2m_engine_execute_cb_t cb)277 int lwm2m_swmgmt_set_deactivate_cb(uint16_t obj_inst_id, lwm2m_engine_execute_cb_t cb)
278 {
279 	struct lwm2m_swmgmt_data *instance = NULL;
280 
281 	instance = find_index(obj_inst_id);
282 	if (!instance) {
283 		return -ENOENT;
284 	}
285 
286 	if (!cb) {
287 		cb = callback_execute_not_defined;
288 	}
289 
290 	instance->deactivate_cb = cb;
291 	return 0;
292 }
293 
lwm2m_swmgmt_set_install_package_cb(uint16_t obj_inst_id,lwm2m_engine_execute_cb_t cb)294 int lwm2m_swmgmt_set_install_package_cb(uint16_t obj_inst_id, lwm2m_engine_execute_cb_t cb)
295 {
296 	struct lwm2m_swmgmt_data *instance = NULL;
297 
298 	instance = find_index(obj_inst_id);
299 	if (!instance) {
300 		return -ENOENT;
301 	}
302 
303 	if (!cb) {
304 		cb = callback_execute_not_defined;
305 	}
306 
307 	instance->install_package_cb = cb;
308 	return 0;
309 }
310 
lwm2m_swmgmt_set_delete_package_cb(uint16_t obj_inst_id,lwm2m_engine_execute_cb_t cb)311 int lwm2m_swmgmt_set_delete_package_cb(uint16_t obj_inst_id, lwm2m_engine_execute_cb_t cb)
312 {
313 	struct lwm2m_swmgmt_data *instance = NULL;
314 
315 	instance = find_index(obj_inst_id);
316 	if (!instance) {
317 		return -ENOENT;
318 	}
319 
320 	if (!cb) {
321 		cb = callback_execute_not_defined;
322 	}
323 
324 	instance->delete_package_cb = cb;
325 	return 0;
326 }
327 
lwm2m_swmgmt_set_write_package_cb(uint16_t obj_inst_id,lwm2m_engine_set_data_cb_t cb)328 int lwm2m_swmgmt_set_write_package_cb(uint16_t obj_inst_id, lwm2m_engine_set_data_cb_t cb)
329 {
330 	struct lwm2m_swmgmt_data *instance = NULL;
331 
332 	instance = find_index(obj_inst_id);
333 	if (!instance) {
334 		return -ENOENT;
335 	}
336 
337 	if (!cb) {
338 		cb = callback_write_not_defined;
339 	}
340 
341 	instance->write_package_cb = cb;
342 	return 0;
343 }
344 
lwm2m_swmgmt_set_read_package_version_cb(uint16_t obj_inst_id,lwm2m_engine_get_data_cb_t cb)345 int lwm2m_swmgmt_set_read_package_version_cb(uint16_t obj_inst_id, lwm2m_engine_get_data_cb_t cb)
346 {
347 	struct lwm2m_swmgmt_data *instance = NULL;
348 
349 	instance = find_index(obj_inst_id);
350 	if (!instance) {
351 		return -ENOENT;
352 	}
353 
354 	if (!cb) {
355 		cb = callback_read_not_defined;
356 	}
357 
358 	instance->read_package_cb = cb;
359 	return 0;
360 }
361 
state_read_pkg_version(uint16_t obj_inst_id,uint16_t res_id,uint16_t res_inst_id,size_t * data_len)362 void *state_read_pkg_version(uint16_t obj_inst_id, uint16_t res_id, uint16_t res_inst_id,
363 			     size_t *data_len)
364 {
365 	struct lwm2m_swmgmt_data *instance = NULL;
366 	void *result = NULL;
367 
368 	instance = find_index(obj_inst_id);
369 	if (!instance) {
370 		return NULL;
371 	}
372 
373 	if (instance->read_package_cb) {
374 		result = instance->read_package_cb(obj_inst_id, res_id, res_inst_id, data_len);
375 	}
376 
377 	return result;
378 }
379 
handle_event(struct lwm2m_swmgmt_data * instance,uint8_t event)380 static int handle_event(struct lwm2m_swmgmt_data *instance, uint8_t event)
381 {
382 	int ret = 0;
383 
384 	if (!instance) {
385 		return -EINVAL;
386 	}
387 
388 	switch (instance->update_state) {
389 	case UPD_STATE_INITIAL:
390 		switch (event) {
391 		case EVENT_PKG_URI_WRITE:
392 			set_sw_update_state(instance, UPD_STATE_DOWNLOAD_STARTED);
393 			set_sw_update_result(instance, UPD_RES_DOWNLOADING);
394 			ret = 0;
395 			break;
396 		default:
397 			ret = -EINVAL;
398 			break;
399 		}
400 		break;
401 	case UPD_STATE_DOWNLOAD_STARTED:
402 		switch (event) {
403 		case EVENT_PKG_WRITTEN:
404 			set_sw_update_state(instance, UPD_STATE_DOWNLOADED);
405 			set_sw_update_result(instance, UPD_RES_INITIAL);
406 			break;
407 		case EVENT_DOWNLOAD_FAILED:
408 			set_sw_update_state(instance, UPD_STATE_INITIAL);
409 
410 			/* Inform the instance of DOWNLOAD_FAILED by calling
411 			 * write_package_cb with a bunch of NULL parameters
412 			 */
413 			instance->write_package_cb(instance->obj_inst_id, 0, 0, NULL, 0, false, 0);
414 			break;
415 		default:
416 			ret = -EINVAL;
417 			break;
418 		}
419 		break;
420 	case UPD_STATE_DOWNLOADED:
421 		switch (event) {
422 		case (EVENT_PKG_INTEGRITY_VERIFIED):
423 			set_sw_update_state(instance, UPD_STATE_DELIVERED);
424 			set_sw_update_result(instance, UPD_RES_INITIAL);
425 			break;
426 		case (EVENT_PKG_INTEGRITY_FAILED):
427 			set_sw_update_state(instance, UPD_STATE_INITIAL);
428 			set_sw_update_result(instance, UPD_RES_PACKAGE_INTEGRITY_CHECK_FAILURE);
429 			break;
430 		default:
431 			ret = -EINVAL;
432 			break;
433 		}
434 		break;
435 	case UPD_STATE_DELIVERED:
436 		switch (event) {
437 		case EVENT_INSTALL:
438 			if (instance->next_package_is_upgrade) {
439 				ret = instance->upgrade_package_cb(instance->obj_inst_id);
440 			}
441 
442 			else {
443 				ret = instance->install_package_cb(instance->obj_inst_id, NULL, 0);
444 			}
445 
446 			break;
447 
448 		case EVENT_INSTALL_SUCCESSFUL:
449 			set_sw_update_state(instance, UPD_STATE_INSTALLED);
450 			set_sw_update_result(instance, UPD_RES_SW_SUCCESSFULLY_INSTALLED);
451 			instance->next_package_is_upgrade = false;
452 			break;
453 
454 		case EVENT_INSTALL_FAIL:
455 			set_sw_update_state(instance, UPD_STATE_DELIVERED);
456 			set_sw_update_result(instance, UPD_RES_SW_INSTALLATION_FAILURE);
457 			break;
458 
459 		case EVENT_DELETE_PACKAGE:
460 			ret = instance->delete_package_cb(instance->obj_inst_id, NULL, 0);
461 			if (ret == 0) {
462 				set_sw_update_state(instance, UPD_STATE_INITIAL);
463 				/* update_result unchanged */
464 			}
465 			break;
466 
467 		default:
468 			ret = -EINVAL;
469 			break;
470 		}
471 		break;
472 	case UPD_STATE_INSTALLED:
473 		switch (event) {
474 		case EVENT_ACTIVATE:
475 			ret = instance->activate_cb(instance->obj_inst_id, NULL, 0);
476 			if (ret == 0) {
477 				set_sw_update_act_state(instance, true);
478 			}
479 			break;
480 		case EVENT_DEACTIVATE:
481 			ret = instance->deactivate_cb(instance->obj_inst_id, NULL, 0);
482 			if (ret == 0) {
483 				set_sw_update_act_state(instance, false);
484 			}
485 			break;
486 		case EVENT_FOR_UPDATE:
487 			instance->next_package_is_upgrade = true;
488 			set_sw_update_state(instance, UPD_STATE_INITIAL);
489 			set_sw_update_result(instance, UPD_RES_INITIAL);
490 		case EVENT_DELETE_PACKAGE:
491 			ret = instance->delete_package_cb(instance->obj_inst_id, NULL, 0);
492 			if (ret == 0) {
493 				set_sw_update_state(instance, UPD_STATE_INITIAL);
494 				set_sw_update_result(instance, UPD_RES_INITIAL);
495 			}
496 			break;
497 		default:
498 			ret = -EINVAL;
499 			break;
500 		}
501 		break;
502 	default:
503 		ret = -EINVAL;
504 		break;
505 	}
506 
507 	return ret;
508 }
509 
install_cb(uint16_t obj_inst_id,uint8_t * args,uint16_t args_len)510 static int install_cb(uint16_t obj_inst_id, uint8_t *args, uint16_t args_len)
511 {
512 	struct lwm2m_swmgmt_data *instance = NULL;
513 
514 	instance = find_index(obj_inst_id);
515 
516 	return handle_event(instance, EVENT_INSTALL);
517 }
518 
lwm2m_swmgmt_install_completed(uint16_t obj_inst_id,int error_code)519 int lwm2m_swmgmt_install_completed(uint16_t obj_inst_id, int error_code)
520 {
521 	struct lwm2m_swmgmt_data *instance = NULL;
522 
523 	instance = find_index(obj_inst_id);
524 
525 	if (error_code) {
526 		error_code = handle_event(instance, EVENT_INSTALL_FAIL);
527 	} else {
528 		error_code = handle_event(instance, EVENT_INSTALL_SUCCESSFUL);
529 	}
530 
531 	return error_code;
532 }
533 
uninstall_cb(uint16_t obj_inst_id,uint8_t * args,uint16_t args_len)534 static int uninstall_cb(uint16_t obj_inst_id, uint8_t *args, uint16_t args_len)
535 {
536 	struct lwm2m_swmgmt_data *instance = NULL;
537 
538 	instance = find_index(obj_inst_id);
539 
540 	return handle_event(instance, EVENT_DELETE_PACKAGE);
541 }
542 
activate_cb(uint16_t obj_inst_id,uint8_t * args,uint16_t args_len)543 static int activate_cb(uint16_t obj_inst_id, uint8_t *args, uint16_t args_len)
544 {
545 	struct lwm2m_swmgmt_data *instance = NULL;
546 
547 	instance = find_index(obj_inst_id);
548 
549 	return handle_event(instance, EVENT_ACTIVATE);
550 }
551 
deactivate_cb(uint16_t obj_inst_id,uint8_t * args,uint16_t args_len)552 static int deactivate_cb(uint16_t obj_inst_id, uint8_t *args, uint16_t args_len)
553 {
554 	struct lwm2m_swmgmt_data *instance = NULL;
555 
556 	instance = find_index(obj_inst_id);
557 
558 	return handle_event(instance, EVENT_DEACTIVATE);
559 }
560 
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)561 static int package_write_cb(uint16_t obj_inst_id, uint16_t res_id, uint16_t res_inst_id,
562 			    uint8_t *data, uint16_t data_len, bool last_block, size_t total_size)
563 {
564 	int ret = -EINVAL;
565 	struct lwm2m_swmgmt_data *instance = NULL;
566 
567 	instance = find_index(obj_inst_id);
568 
569 	ret = handle_event(instance, EVENT_PKG_URI_WRITE);
570 
571 	if (ret < 0) {
572 		return ret;
573 	}
574 
575 	ret = instance->write_package_cb(obj_inst_id, res_id, res_inst_id, data, data_len,
576 					 last_block, total_size);
577 
578 	if (ret < 0) {
579 		handle_event(instance, EVENT_DOWNLOAD_FAILED);
580 		switch (ret) {
581 		case -ENOMEM:
582 			set_sw_update_result(instance, UPD_RES_OUT_OF_MEMORY_DURING_DOWNLOAD);
583 			break;
584 		case -ENOSPC:
585 			set_sw_update_result(instance, UPD_RES_NOT_ENOUGH_STORAGE);
586 			ret = -EFBIG;
587 			break;
588 		case -EFAULT:
589 			set_sw_update_result(instance, UPD_RES_PACKAGE_INTEGRITY_CHECK_FAILURE);
590 			break;
591 		default:
592 			set_sw_update_result(instance, UPD_RES_LOST_CONNECTION_DURING_DOWNLOAD);
593 			break;
594 		}
595 
596 		return ret;
597 	}
598 
599 	if (last_block) {
600 		handle_event(instance, EVENT_PKG_WRITTEN);
601 	}
602 
603 	return 0;
604 }
605 
set_update_result(uint16_t obj_inst_id,int error_code)606 static void set_update_result(uint16_t obj_inst_id, int error_code)
607 {
608 	int ret;
609 	struct lwm2m_swmgmt_data *instance;
610 
611 	instance = find_index(obj_inst_id);
612 
613 	if (error_code == 0) {
614 		handle_event(instance, EVENT_PKG_WRITTEN);
615 
616 		/* If the verify function wasn't provided, skip the check. */
617 		if (verify_package) {
618 			ret = verify_package();
619 		} else {
620 			ret = 0;
621 		}
622 
623 		if (ret == 0) {
624 			handle_event(instance, EVENT_PKG_INTEGRITY_VERIFIED);
625 		} else {
626 			handle_event(instance, EVENT_PKG_INTEGRITY_FAILED);
627 		}
628 
629 		return;
630 	}
631 
632 	handle_event(instance, EVENT_DOWNLOAD_FAILED);
633 	if (error_code == -ENOMEM) {
634 		set_sw_update_result(instance, UPD_RES_OUT_OF_MEMORY_DURING_DOWNLOAD);
635 	} else if (error_code == -ENOSPC) {
636 		set_sw_update_result(instance, UPD_RES_NOT_ENOUGH_STORAGE);
637 	} else if (error_code == -EFAULT) {
638 		set_sw_update_result(instance, UPD_RES_PACKAGE_INTEGRITY_CHECK_FAILURE);
639 	} else if (error_code == -ENOTSUP) {
640 		set_sw_update_result(instance, UPD_RES_INVALID_URI);
641 	} else {
642 		set_sw_update_result(instance, UPD_RES_LOST_CONNECTION_DURING_DOWNLOAD);
643 	}
644 }
645 
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)646 static int package_uri_write_cb(uint16_t obj_inst_id, uint16_t res_id, uint16_t res_inst_id,
647 				uint8_t *data, uint16_t data_len, bool last_block,
648 				size_t total_size)
649 {
650 #ifdef CONFIG_LWM2M_FIRMWARE_UPDATE_PULL_SUPPORT
651 	int error_code;
652 	struct lwm2m_swmgmt_data *instance = NULL;
653 
654 	instance = find_index(obj_inst_id);
655 
656 	struct requesting_object req = { .obj_inst_id = obj_inst_id,
657 					 .is_firmware_uri = false,
658 					 .result_cb = set_update_result,
659 					 .write_cb = instance->write_package_cb,
660 					 .verify_cb = NULL };
661 
662 	verify_package = req.verify_cb;
663 
664 	error_code = lwm2m_pull_context_start_transfer(instance->package_uri, req, K_NO_WAIT);
665 
666 	if (error_code) {
667 		return error_code;
668 	}
669 
670 	return handle_event(instance, EVENT_PKG_URI_WRITE);
671 
672 #else
673 	return -EINVAL;
674 #endif
675 }
676 
swmgmt_create(uint16_t obj_inst_id)677 static struct lwm2m_engine_obj_inst *swmgmt_create(uint16_t obj_inst_id)
678 {
679 	struct lwm2m_swmgmt_data *instance = NULL;
680 	int index, res_idx = 0, res_inst_idx = 0;
681 
682 	/* Check that there is no other instance with this ID */
683 	for (index = 0; index < MAX_INSTANCE_COUNT; index++) {
684 		if (inst[index].obj && inst[index].obj_inst_id == obj_inst_id) {
685 			LOG_ERR("Can not create instance - "
686 				"already existing: %u",
687 				obj_inst_id);
688 			return NULL;
689 		}
690 	}
691 
692 	for (index = 0; index < MAX_INSTANCE_COUNT; index++) {
693 		if (!inst[index].obj) {
694 			break;
695 		}
696 	}
697 
698 	if (index >= MAX_INSTANCE_COUNT) {
699 		LOG_ERR("Can not create instance - no more room: %u", obj_inst_id);
700 		return NULL;
701 	}
702 
703 	instance = &swmgmt_data[index];
704 
705 	/* Set default values */
706 	(void)memset(res[index], 0, sizeof(res[index][0]) * ARRAY_SIZE(res[index]));
707 	init_res_instance(res_inst[index], ARRAY_SIZE(res_inst[index]));
708 
709 	(void)memset(instance->package_name, 0, PACKAGE_NAME_LEN);
710 	(void)memset(instance->package_version, 0, PACKAGE_VERSION_LEN);
711 
712 	instance->obj_inst_id = obj_inst_id;
713 	instance->update_state = 0;
714 	instance->update_result = 0;
715 	instance->activation_state = false;
716 
717 	instance->next_package_is_upgrade = false;
718 
719 	instance->install_package_cb = callback_execute_not_defined;
720 	instance->delete_package_cb = callback_execute_not_defined;
721 	instance->activate_cb = callback_execute_not_defined;
722 	instance->deactivate_cb = callback_execute_not_defined;
723 	instance->write_package_cb = callback_write_not_defined;
724 
725 #ifdef CONFIG_LWM2M_FIRMWARE_UPDATE_PULL_SUPPORT
726 	(void)memset(instance->package_uri, 0, PACKAGE_URI_LEN);
727 #endif
728 
729 	/* initialize instance resource data */
730 	INIT_OBJ_RES_DATA_LEN(SWMGMT_PACKAGE_NAME_ID, res[index], res_idx, res_inst[index],
731 			  res_inst_idx, &instance->package_name, PACKAGE_NAME_LEN, 0);
732 
733 	INIT_OBJ_RES_LEN(SWMGMT_PACKAGE_VERSION_ID, res[index], res_idx, res_inst[index],
734 			 res_inst_idx, 1, false, true, &instance->package_version,
735 			 PACKAGE_VERSION_LEN, 0, state_read_pkg_version, NULL, NULL, NULL, NULL);
736 
737 	INIT_OBJ_RES_OPT(SWMGMT_PACKAGE_ID, res[index], res_idx, res_inst[index], res_inst_idx, 1,
738 			 false, false, NULL, NULL, NULL, package_write_cb, NULL);
739 
740 #ifdef CONFIG_LWM2M_FIRMWARE_UPDATE_PULL_SUPPORT
741 	INIT_OBJ_RES(SWMGMT_PACKAGE_URI_ID, res[index], res_idx, res_inst[index], res_inst_idx, 1,
742 		     false, true, instance->package_uri, PACKAGE_URI_LEN, NULL, NULL, NULL,
743 		     package_uri_write_cb, NULL);
744 #else
745 	INIT_OBJ_RES_OPT(SWMGMT_PACKAGE_URI_ID, res[index], res_idx, res_inst[index], res_inst_idx,
746 			 1, false, true, NULL, NULL, NULL, package_uri_write_cb, NULL);
747 #endif
748 
749 	INIT_OBJ_RES_EXECUTE(SWMGMT_INSTALL_ID, res[index], res_idx, install_cb);
750 
751 	INIT_OBJ_RES_OPTDATA(SWMGMT_CHECKPOINT_ID, res[index], res_idx, res_inst[index],
752 			     res_inst_idx);
753 
754 	INIT_OBJ_RES_EXECUTE(SWMGMT_UNINSTALL_ID, res[index], res_idx, uninstall_cb);
755 
756 	INIT_OBJ_RES_DATA(SWMGMT_UPDATE_STATE_ID, res[index], res_idx, res_inst[index],
757 			  res_inst_idx, &instance->update_state, sizeof(uint8_t));
758 
759 	INIT_OBJ_RES_OPTDATA(SWMGMT_UPDATE_SUPPORTED_OBJECTS_ID, res[index], res_idx,
760 			     res_inst[index], res_inst_idx);
761 
762 	INIT_OBJ_RES_DATA(SWMGMT_UPDATE_RESULT_ID, res[index], res_idx, res_inst[index],
763 			  res_inst_idx, &instance->update_result, sizeof(uint8_t));
764 
765 	INIT_OBJ_RES_EXECUTE(SWMGMT_ACTIVATE_ID, res[index], res_idx, activate_cb);
766 	INIT_OBJ_RES_EXECUTE(SWMGMT_DEACTIVATE_ID, res[index], res_idx, deactivate_cb);
767 
768 	INIT_OBJ_RES_DATA(SWMGMT_ACTIVATION_UPD_STATE_ID, res[index], res_idx, res_inst[index],
769 			  res_inst_idx, &instance->activation_state, sizeof(bool));
770 
771 	INIT_OBJ_RES_OPTDATA(SWMGMT_PACKAGE_SETTINGS_ID, res[index], res_idx, res_inst[index],
772 			     res_inst_idx);
773 	INIT_OBJ_RES_OPTDATA(SWMGMT_USER_NAME_ID, res[index], res_idx, res_inst[index],
774 			     res_inst_idx);
775 	INIT_OBJ_RES_OPTDATA(SWMGMT_PASSWORD_ID, res[index], res_idx, res_inst[index],
776 			     res_inst_idx);
777 
778 	inst[index].resources = res[index];
779 	inst[index].resource_count = res_idx;
780 	return &inst[index];
781 }
782 
lwm2m_swmgmt_init(void)783 static int lwm2m_swmgmt_init(void)
784 {
785 	swmgmt.obj_id = LWM2M_OBJECT_SOFTWARE_MANAGEMENT_ID;
786 	swmgmt.version_major = SWMGMT_VERSION_MAJOR;
787 	swmgmt.version_minor = SWMGMT_VERSION_MINOR;
788 	swmgmt.fields = fields;
789 	swmgmt.field_count = ARRAY_SIZE(fields);
790 	swmgmt.max_instance_count = MAX_INSTANCE_COUNT;
791 	swmgmt.create_cb = swmgmt_create;
792 	lwm2m_register_obj(&swmgmt);
793 
794 	return 0;
795 }
796 
797 SYS_INIT(lwm2m_swmgmt_init, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT);
798