1 /*
2  * Copyright (c) 2016-2017 Linaro Limited
3  * Copyright (c) 2018 Open Source Foundries Limited
4  * Copyright (c) 2018 Foundries.io
5  * Copyright (c) 2020 Linumiz
6  * Copyright (c) 2021 G-Technologies Sdn. Bhd.
7  * Copyright (c) 2024 Vogl Electronic GmbH
8  *
9  * SPDX-License-Identifier: Apache-2.0
10  */
11 
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 
16 #include <zephyr/data/json.h>
17 #include <zephyr/drivers/flash.h>
18 #include <zephyr/kernel.h>
19 #include <zephyr/logging/log.h>
20 #include <zephyr/logging/log_ctrl.h>
21 #include <zephyr/mgmt/hawkbit/hawkbit.h>
22 #include <zephyr/mgmt/hawkbit/config.h>
23 #include <zephyr/mgmt/hawkbit/event.h>
24 #include <zephyr/net/dns_resolve.h>
25 #include <zephyr/net/http/client.h>
26 #include <zephyr/net/net_ip.h>
27 #include <zephyr/net/net_mgmt.h>
28 #include <zephyr/net/socket.h>
29 #include <zephyr/settings/settings.h>
30 #include <zephyr/smf.h>
31 #include <zephyr/storage/flash_map.h>
32 #include <zephyr/sys/reboot.h>
33 
34 #include <bootutil/bootutil_public.h>
35 
36 #include "hawkbit_device.h"
37 #include "hawkbit_firmware.h"
38 #include "hawkbit_priv.h"
39 
40 LOG_MODULE_REGISTER(hawkbit, CONFIG_HAWKBIT_LOG_LEVEL);
41 
42 #define RECV_BUFFER_SIZE 640
43 #define URL_BUFFER_SIZE 300
44 #define SHA256_HASH_SIZE 32
45 #define RESPONSE_BUFFER_SIZE 1100
46 #define DDI_SECURITY_TOKEN_SIZE 32
47 #define RANGE_HEADER_SIZE 50
48 #define HAWKBIT_RECV_TIMEOUT (300 * MSEC_PER_SEC)
49 #define HAWKBIT_SET_SERVER_TIMEOUT K_MSEC(300)
50 
51 #define HAWKBIT_JSON_URL "/" CONFIG_HAWKBIT_TENANT "/controller/v1"
52 
53 #define HTTP_HEADER_CONTENT_TYPE_JSON "application/json;charset=UTF-8"
54 
55 #define SLOT1_LABEL slot1_partition
56 #define SLOT1_SIZE FIXED_PARTITION_SIZE(SLOT1_LABEL)
57 
58 static uint32_t poll_sleep = (CONFIG_HAWKBIT_POLL_INTERVAL * SEC_PER_MIN);
59 
60 static bool hawkbit_initialized;
61 
62 #ifndef CONFIG_HAWKBIT_DDI_NO_SECURITY
63 
64 #ifdef CONFIG_HAWKBIT_DDI_GATEWAY_SECURITY
65 #define AUTH_HEADER_START "Authorization: GatewayToken "
66 #else
67 #define AUTH_HEADER_START "Authorization: TargetToken "
68 #endif /* CONFIG_HAWKBIT_DDI_GATEWAY_SECURITY */
69 
70 #ifdef CONFIG_HAWKBIT_SET_SETTINGS_RUNTIME
71 #define AUTH_HEADER_FULL AUTH_HEADER_START "%s" HTTP_CRLF
72 #else
73 #define AUTH_HEADER_FULL AUTH_HEADER_START CONFIG_HAWKBIT_DDI_SECURITY_TOKEN HTTP_CRLF
74 #endif /* CONFIG_HAWKBIT_SET_SETTINGS_RUNTIME */
75 
76 #endif /* CONFIG_HAWKBIT_DDI_NO_SECURITY */
77 
78 static struct hawkbit_config {
79 	int32_t action_id;
80 #ifdef CONFIG_HAWKBIT_SET_SETTINGS_RUNTIME
81 	char server_addr[DNS_MAX_NAME_SIZE + 1];
82 	char server_port[sizeof(STRINGIFY(__UINT16_MAX__))];
83 #ifndef CONFIG_HAWKBIT_DDI_NO_SECURITY
84 	char ddi_security_token[DDI_SECURITY_TOKEN_SIZE + 1];
85 #endif
86 #ifdef CONFIG_HAWKBIT_USE_DYNAMIC_CERT_TAG
87 	sec_tag_t tls_tag;
88 #endif
89 #endif /* CONFIG_HAWKBIT_SET_SETTINGS_RUNTIME */
90 } hb_cfg;
91 
92 #ifdef CONFIG_HAWKBIT_SET_SETTINGS_RUNTIME
93 #define HAWKBIT_SERVER hb_cfg.server_addr
94 #define HAWKBIT_PORT hb_cfg.server_port
95 #define HAWKBIT_PORT_INT atoi(hb_cfg.server_port)
96 #else
97 #define HAWKBIT_SERVER CONFIG_HAWKBIT_SERVER
98 #define HAWKBIT_PORT STRINGIFY(CONFIG_HAWKBIT_PORT)
99 #define HAWKBIT_PORT_INT CONFIG_HAWKBIT_PORT
100 #endif /* CONFIG_HAWKBIT_SET_SETTINGS_RUNTIME */
101 
102 #ifdef CONFIG_HAWKBIT_DDI_NO_SECURITY
103 #define HAWKBIT_DDI_SECURITY_TOKEN NULL
104 #elif defined(CONFIG_HAWKBIT_SET_SETTINGS_RUNTIME)
105 #define HAWKBIT_DDI_SECURITY_TOKEN hb_cfg.ddi_security_token
106 #else
107 #define HAWKBIT_DDI_SECURITY_TOKEN CONFIG_HAWKBIT_DDI_SECURITY_TOKEN
108 #endif /* CONFIG_HAWKBIT_DDI_NO_SECURITY */
109 
110 #ifdef CONFIG_HAWKBIT_USE_DYNAMIC_CERT_TAG
111 #define HAWKBIT_CERT_TAG hb_cfg.tls_tag
112 #elif defined(HAWKBIT_USE_STATIC_CERT_TAG)
113 #define HAWKBIT_CERT_TAG CONFIG_HAWKBIT_STATIC_CERT_TAG
114 #else
115 #define HAWKBIT_CERT_TAG 0
116 #endif /* CONFIG_HAWKBIT_USE_DYNAMIC_CERT_TAG */
117 
118 struct hawkbit_download {
119 	size_t downloaded_size;
120 	size_t http_content_size;
121 	uint8_t file_hash[SHA256_HASH_SIZE];
122 	int32_t file_size;
123 };
124 
125 union hawkbit_results {
126 	struct hawkbit_dep_res dep;
127 	struct hawkbit_ctl_res base;
128 };
129 
130 struct hawkbit_context {
131 	int sock;
132 	uint8_t *response_data;
133 	size_t response_data_size;
134 	int32_t json_action_id;
135 	struct hawkbit_download dl;
136 	struct flash_img_context flash_ctx;
137 	enum hawkbit_response code_status;
138 	bool final_data_received;
139 	enum hawkbit_http_request type;
140 	union hawkbit_results results;
141 };
142 
143 struct s_object {
144 	struct smf_ctx ctx;
145 	struct hawkbit_context hb_context;
146 	char device_id[DEVICE_ID_HEX_MAX_SIZE];
147 };
148 
149 static const struct smf_state hawkbit_states[];
150 
151 enum hawkbit_state {
152 	S_HAWKBIT_START,
153 	S_HAWKBIT_HTTP,
154 	S_HAWKBIT_PROBE,
155 	S_HAWKBIT_CONFIG_DEVICE,
156 	S_HAWKBIT_CANCEL,
157 	S_HAWKBIT_PROBE_DEPLOYMENT_BASE,
158 	S_HAWKBIT_REPORT,
159 	S_HAWKBIT_DOWNLOAD,
160 	S_HAWKBIT_TERMINATE,
161 };
162 
163 int hawkbit_default_config_data_cb(const char *device_id, uint8_t *buffer,
164 			      const size_t buffer_size);
165 
166 static hawkbit_config_device_data_cb_handler_t hawkbit_config_device_data_cb_handler =
167 	hawkbit_default_config_data_cb;
168 
169 K_SEM_DEFINE(probe_sem, 1, 1);
170 
171 #ifdef CONFIG_HAWKBIT_EVENT_CALLBACKS
172 static sys_slist_t event_callbacks = SYS_SLIST_STATIC_INIT(&event_callbacks);
173 #endif
174 
175 static const struct json_obj_descr json_href_descr[] = {
176 	JSON_OBJ_DESCR_PRIM(struct hawkbit_href, href, JSON_TOK_STRING),
177 };
178 
179 static const struct json_obj_descr json_status_result_descr[] = {
180 	JSON_OBJ_DESCR_PRIM(struct hawkbit_status_result, finished, JSON_TOK_STRING),
181 };
182 
183 static const struct json_obj_descr json_status_descr[] = {
184 	JSON_OBJ_DESCR_PRIM(struct hawkbit_status, execution, JSON_TOK_STRING),
185 	JSON_OBJ_DESCR_OBJECT(struct hawkbit_status, result, json_status_result_descr),
186 };
187 
188 static const struct json_obj_descr json_ctl_res_sleep_descr[] = {
189 	JSON_OBJ_DESCR_PRIM(struct hawkbit_ctl_res_sleep, sleep, JSON_TOK_STRING),
190 };
191 
192 static const struct json_obj_descr json_ctl_res_polling_descr[] = {
193 	JSON_OBJ_DESCR_OBJECT(struct hawkbit_ctl_res_polling, polling, json_ctl_res_sleep_descr),
194 };
195 
196 static const struct json_obj_descr json_ctl_res_links_descr[] = {
197 	JSON_OBJ_DESCR_OBJECT(struct hawkbit_ctl_res_links, deploymentBase, json_href_descr),
198 	JSON_OBJ_DESCR_OBJECT(struct hawkbit_ctl_res_links, cancelAction, json_href_descr),
199 	JSON_OBJ_DESCR_OBJECT(struct hawkbit_ctl_res_links, configData, json_href_descr),
200 };
201 
202 static const struct json_obj_descr json_ctl_res_descr[] = {
203 	JSON_OBJ_DESCR_OBJECT(struct hawkbit_ctl_res, config, json_ctl_res_polling_descr),
204 	JSON_OBJ_DESCR_OBJECT(struct hawkbit_ctl_res, _links, json_ctl_res_links_descr),
205 };
206 
207 static const struct json_obj_descr json_cfg_data_descr[] = {
208 	JSON_OBJ_DESCR_PRIM(struct hawkbit_cfg_data, VIN, JSON_TOK_STRING),
209 };
210 
211 static const struct json_obj_descr json_cfg_descr[] = {
212 	JSON_OBJ_DESCR_PRIM(struct hawkbit_cfg, mode, JSON_TOK_STRING),
213 	JSON_OBJ_DESCR_OBJECT(struct hawkbit_cfg, data, json_cfg_data_descr),
214 };
215 
216 static const struct json_obj_descr json_cancel_descr[] = {
217 	JSON_OBJ_DESCR_OBJECT(struct hawkbit_cancel, status, json_status_descr),
218 };
219 
220 static const struct json_obj_descr json_dep_res_hashes_descr[] = {
221 	JSON_OBJ_DESCR_PRIM(struct hawkbit_dep_res_hashes, sha1, JSON_TOK_STRING),
222 	JSON_OBJ_DESCR_PRIM(struct hawkbit_dep_res_hashes, md5, JSON_TOK_STRING),
223 	JSON_OBJ_DESCR_PRIM(struct hawkbit_dep_res_hashes, sha256, JSON_TOK_STRING),
224 };
225 
226 static const struct json_obj_descr json_dep_res_links_descr[] = {
227 	JSON_OBJ_DESCR_OBJECT_NAMED(struct hawkbit_dep_res_links, "download-http", download_http,
228 				    json_href_descr),
229 	JSON_OBJ_DESCR_OBJECT_NAMED(struct hawkbit_dep_res_links, "md5sum-http", md5sum_http,
230 				    json_href_descr),
231 };
232 
233 static const struct json_obj_descr json_dep_res_arts_descr[] = {
234 	JSON_OBJ_DESCR_PRIM(struct hawkbit_dep_res_arts, filename, JSON_TOK_STRING),
235 	JSON_OBJ_DESCR_OBJECT(struct hawkbit_dep_res_arts, hashes, json_dep_res_hashes_descr),
236 	JSON_OBJ_DESCR_PRIM(struct hawkbit_dep_res_arts, size, JSON_TOK_NUMBER),
237 	JSON_OBJ_DESCR_OBJECT(struct hawkbit_dep_res_arts, _links, json_dep_res_links_descr),
238 };
239 
240 static const struct json_obj_descr json_dep_res_chunk_descr[] = {
241 	JSON_OBJ_DESCR_PRIM(struct hawkbit_dep_res_chunk, part, JSON_TOK_STRING),
242 	JSON_OBJ_DESCR_PRIM(struct hawkbit_dep_res_chunk, version, JSON_TOK_STRING),
243 	JSON_OBJ_DESCR_PRIM(struct hawkbit_dep_res_chunk, name, JSON_TOK_STRING),
244 	JSON_OBJ_DESCR_OBJ_ARRAY(struct hawkbit_dep_res_chunk, artifacts,
245 				 HAWKBIT_DEP_MAX_CHUNK_ARTS, num_artifacts, json_dep_res_arts_descr,
246 				 ARRAY_SIZE(json_dep_res_arts_descr)),
247 };
248 
249 static const struct json_obj_descr json_dep_res_deploy_descr[] = {
250 	JSON_OBJ_DESCR_PRIM(struct hawkbit_dep_res_deploy, download, JSON_TOK_STRING),
251 	JSON_OBJ_DESCR_PRIM(struct hawkbit_dep_res_deploy, update, JSON_TOK_STRING),
252 	JSON_OBJ_DESCR_OBJ_ARRAY(struct hawkbit_dep_res_deploy, chunks, HAWKBIT_DEP_MAX_CHUNKS,
253 				 num_chunks, json_dep_res_chunk_descr,
254 				 ARRAY_SIZE(json_dep_res_chunk_descr)),
255 };
256 
257 static const struct json_obj_descr json_dep_res_descr[] = {
258 	JSON_OBJ_DESCR_PRIM(struct hawkbit_dep_res, id, JSON_TOK_STRING),
259 	JSON_OBJ_DESCR_OBJECT(struct hawkbit_dep_res, deployment, json_dep_res_deploy_descr),
260 };
261 
262 static const struct json_obj_descr json_dep_fbk_descr[] = {
263 	JSON_OBJ_DESCR_OBJECT(struct hawkbit_dep_fbk, status, json_status_descr),
264 };
265 
hawkbit_settings_set(const char * name,size_t len,settings_read_cb read_cb,void * cb_arg)266 static int hawkbit_settings_set(const char *name, size_t len, settings_read_cb read_cb,
267 				void *cb_arg)
268 {
269 	const char *next;
270 	int rc;
271 
272 	if (settings_name_steq(name, "action_id", &next) && !next) {
273 		if (len != sizeof(hb_cfg.action_id)) {
274 			return -EINVAL;
275 		}
276 
277 		rc = read_cb(cb_arg, &hb_cfg.action_id, sizeof(hb_cfg.action_id));
278 		LOG_DBG("<%s> = %d", "hawkbit/action_id", hb_cfg.action_id);
279 		if (rc >= 0) {
280 			return 0;
281 		}
282 
283 		return rc;
284 	}
285 
286 #ifdef CONFIG_HAWKBIT_SET_SETTINGS_RUNTIME
287 	if (settings_name_steq(name, "server_addr", &next) && !next) {
288 		if (len != sizeof(hb_cfg.server_addr)) {
289 			return -EINVAL;
290 		}
291 
292 		rc = read_cb(cb_arg, &hb_cfg.server_addr, sizeof(hb_cfg.server_addr));
293 		LOG_DBG("<%s> = %s", "hawkbit/server_addr", hb_cfg.server_addr);
294 		if (rc >= 0) {
295 			return 0;
296 		}
297 
298 		return rc;
299 	}
300 
301 	if (settings_name_steq(name, "server_port", &next) && !next) {
302 		if (len != sizeof(uint16_t)) {
303 			return -EINVAL;
304 		}
305 
306 		uint16_t hawkbit_port = atoi(hb_cfg.server_port);
307 
308 		rc = read_cb(cb_arg, &hawkbit_port, sizeof(hawkbit_port));
309 		if (hawkbit_port != atoi(hb_cfg.server_port)) {
310 			snprintf(hb_cfg.server_port, sizeof(hb_cfg.server_port), "%u",
311 				 hawkbit_port);
312 		}
313 		LOG_DBG("<%s> = %s", "hawkbit/server_port", hb_cfg.server_port);
314 		if (rc >= 0) {
315 			return 0;
316 		}
317 
318 		return rc;
319 	}
320 
321 	if (settings_name_steq(name, "ddi_token", &next) && !next) {
322 #ifdef CONFIG_HAWKBIT_DDI_NO_SECURITY
323 		rc = read_cb(cb_arg, NULL, 0);
324 #else
325 		if (len != sizeof(hb_cfg.ddi_security_token)) {
326 			return -EINVAL;
327 		}
328 
329 		rc = read_cb(cb_arg, &hb_cfg.ddi_security_token, sizeof(hb_cfg.ddi_security_token));
330 		LOG_DBG("<%s> = %s", "hawkbit/ddi_token", hb_cfg.ddi_security_token);
331 		if (rc >= 0) {
332 			return 0;
333 		}
334 #endif /* CONFIG_HAWKBIT_DDI_NO_SECURITY */
335 		return rc;
336 	}
337 #else  /* CONFIG_HAWKBIT_SET_SETTINGS_RUNTIME */
338 	if (settings_name_steq(name, "server_addr", NULL) ||
339 	    settings_name_steq(name, "server_port", NULL) ||
340 	    settings_name_steq(name, "ddi_token", NULL)) {
341 		rc = read_cb(cb_arg, NULL, 0);
342 		return 0;
343 	}
344 #endif /* CONFIG_HAWKBIT_SET_SETTINGS_RUNTIME */
345 	/* This is to omit the error message, as that is fetched in stream_flash_progress_load()
346 	 * and we don't need to get it here.
347 	 */
348 	if (IS_ENABLED(CONFIG_HAWKBIT_SAVE_PROGRESS) &&
349 	    settings_name_steq(name, "flash_progress", NULL)) {
350 		return 0;
351 	}
352 
353 	return -ENOENT;
354 }
355 
hawkbit_settings_export(int (* cb)(const char * name,const void * value,size_t val_len))356 static int hawkbit_settings_export(int (*cb)(const char *name, const void *value, size_t val_len))
357 {
358 	LOG_DBG("export hawkbit settings");
359 	(void)cb("hawkbit/action_id", &hb_cfg.action_id, sizeof(hb_cfg.action_id));
360 #ifdef CONFIG_HAWKBIT_SET_SETTINGS_RUNTIME
361 	(void)cb("hawkbit/server_addr", &hb_cfg.server_addr, sizeof(hb_cfg.server_addr));
362 	uint16_t hawkbit_port = atoi(hb_cfg.server_port);
363 	(void)cb("hawkbit/server_port", &hawkbit_port, sizeof(hawkbit_port));
364 #ifndef CONFIG_HAWKBIT_DDI_NO_SECURITY
365 	(void)cb("hawkbit/ddi_token", &hb_cfg.ddi_security_token,
366 		 sizeof(hb_cfg.ddi_security_token));
367 #endif /* CONFIG_HAWKBIT_DDI_NO_SECURITY */
368 #endif /* CONFIG_HAWKBIT_SET_SETTINGS_RUNTIME */
369 	return 0;
370 }
371 
372 SETTINGS_STATIC_HANDLER_DEFINE(hawkbit, "hawkbit", NULL, hawkbit_settings_set, NULL,
373 			       hawkbit_settings_export);
374 
hawkbit_event_raise(enum hawkbit_event_type event)375 static void hawkbit_event_raise(enum hawkbit_event_type event)
376 {
377 #ifdef CONFIG_HAWKBIT_EVENT_CALLBACKS
378 	struct hawkbit_event_callback *cb, *tmp;
379 
380 	SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&event_callbacks, cb, tmp, node) {
381 		if (cb->event == event && cb->handler) {
382 			cb->handler(cb, event);
383 		}
384 	}
385 #endif
386 }
387 
388 #ifdef CONFIG_HAWKBIT_EVENT_CALLBACKS
hawkbit_event_add_callback(struct hawkbit_event_callback * cb)389 int hawkbit_event_add_callback(struct hawkbit_event_callback *cb)
390 {
391 	int ret = 0;
392 
393 	if (cb == NULL || cb->handler == NULL) {
394 		return -EINVAL;
395 	}
396 
397 	ret = k_sem_take(&probe_sem, K_FOREVER);
398 	if (ret == 0) {
399 		sys_slist_prepend(&event_callbacks, &cb->node);
400 		k_sem_give(&probe_sem);
401 	}
402 	return ret;
403 }
404 
hawkbit_event_remove_callback(struct hawkbit_event_callback * cb)405 int hawkbit_event_remove_callback(struct hawkbit_event_callback *cb)
406 {
407 	int ret = 0;
408 
409 	if (cb == NULL || cb->handler == NULL) {
410 		return -EINVAL;
411 	}
412 
413 	ret = k_sem_take(&probe_sem, K_FOREVER);
414 	if (ret == 0) {
415 		if (!sys_slist_find_and_remove(&event_callbacks, &cb->node)) {
416 			ret = -EINVAL;
417 		}
418 		k_sem_give(&probe_sem);
419 	}
420 
421 	return ret;
422 }
423 #endif /* CONFIG_HAWKBIT_EVENT_CALLBACKS */
424 
start_http_client(int * hb_sock)425 static bool start_http_client(int *hb_sock)
426 {
427 	int ret = -1;
428 	struct zsock_addrinfo *addr;
429 	struct zsock_addrinfo hints = {0};
430 	int resolve_attempts = 10;
431 	int protocol = IS_ENABLED(CONFIG_HAWKBIT_USE_TLS) ? IPPROTO_TLS_1_2 : IPPROTO_TCP;
432 
433 	if (IS_ENABLED(CONFIG_NET_IPV6)) {
434 		hints.ai_family = AF_INET6;
435 		hints.ai_socktype = SOCK_STREAM;
436 	} else if (IS_ENABLED(CONFIG_NET_IPV4)) {
437 		hints.ai_family = AF_INET;
438 		hints.ai_socktype = SOCK_STREAM;
439 	}
440 
441 	while (resolve_attempts--) {
442 		ret = zsock_getaddrinfo(HAWKBIT_SERVER, HAWKBIT_PORT, &hints, &addr);
443 		if (ret == 0) {
444 			break;
445 		}
446 
447 		k_sleep(K_MSEC(1));
448 	}
449 
450 	if (ret != 0) {
451 		LOG_ERR("Failed to resolve dns: %d", ret);
452 		return false;
453 	}
454 
455 	*hb_sock = zsock_socket(addr->ai_family, SOCK_STREAM, protocol);
456 	if (*hb_sock < 0) {
457 		LOG_ERR("Failed to create TCP socket");
458 		goto err;
459 	}
460 
461 #ifdef CONFIG_HAWKBIT_USE_TLS
462 	sec_tag_t sec_tag_opt[] = {
463 		HAWKBIT_CERT_TAG,
464 	};
465 
466 	if (zsock_setsockopt(*hb_sock, SOL_TLS, TLS_SEC_TAG_LIST, sec_tag_opt,
467 			     sizeof(sec_tag_opt)) < 0) {
468 		LOG_ERR("Failed to set TLS_TAG option");
469 		goto err_sock;
470 	}
471 
472 	if (zsock_setsockopt(*hb_sock, SOL_TLS, TLS_HOSTNAME, HAWKBIT_SERVER,
473 			     sizeof(CONFIG_HAWKBIT_SERVER)) < 0) {
474 		goto err_sock;
475 	}
476 #endif /* CONFIG_HAWKBIT_USE_TLS */
477 
478 	if (zsock_connect(*hb_sock, addr->ai_addr, addr->ai_addrlen) < 0) {
479 		LOG_ERR("Failed to connect to server");
480 		goto err_sock;
481 	}
482 
483 	zsock_freeaddrinfo(addr);
484 	return true;
485 
486 err_sock:
487 	zsock_close(*hb_sock);
488 err:
489 	zsock_freeaddrinfo(addr);
490 	return false;
491 }
492 
cleanup_connection(int * hb_sock)493 static void cleanup_connection(int *hb_sock)
494 {
495 	if (zsock_close(*hb_sock) < 0) {
496 		LOG_ERR("Failed to close the socket");
497 	}
498 }
499 
hawkbit_time2sec(const char * s)500 static int hawkbit_time2sec(const char *s)
501 {
502 	int sec;
503 
504 	/* Time: HH:MM:SS */
505 	sec = strtol(s, NULL, 10) * (60 * 60);
506 	sec += strtol(s + 3, NULL, 10) * 60;
507 	sec += strtol(s + 6, NULL, 10);
508 
509 	if (sec < 0) {
510 		return -1;
511 	} else {
512 		return sec;
513 	}
514 }
515 
hawkbit_status_finished(enum hawkbit_status_fini f)516 static const char *hawkbit_status_finished(enum hawkbit_status_fini f)
517 {
518 	switch (f) {
519 	case HAWKBIT_STATUS_FINISHED_SUCCESS:
520 		return "success";
521 	case HAWKBIT_STATUS_FINISHED_FAILURE:
522 		return "failure";
523 	case HAWKBIT_STATUS_FINISHED_NONE:
524 		return "none";
525 	default:
526 		LOG_ERR("%d is invalid", (int)f);
527 		return NULL;
528 	}
529 }
530 
hawkbit_status_execution(enum hawkbit_status_exec e)531 static const char *hawkbit_status_execution(enum hawkbit_status_exec e)
532 {
533 	switch (e) {
534 	case HAWKBIT_STATUS_EXEC_CLOSED:
535 		return "closed";
536 	case HAWKBIT_STATUS_EXEC_PROCEEDING:
537 		return "proceeding";
538 	case HAWKBIT_STATUS_EXEC_CANCELED:
539 		return "canceled";
540 	case HAWKBIT_STATUS_EXEC_SCHEDULED:
541 		return "scheduled";
542 	case HAWKBIT_STATUS_EXEC_REJECTED:
543 		return "rejected";
544 	case HAWKBIT_STATUS_EXEC_RESUMED:
545 		return "resumed";
546 	case HAWKBIT_STATUS_EXEC_NONE:
547 		return "none";
548 	default:
549 		LOG_ERR("%d is invalid", (int)e);
550 		return NULL;
551 	}
552 }
553 
hawkbit_device_acid_update(int32_t new_value)554 static int hawkbit_device_acid_update(int32_t new_value)
555 {
556 	int ret;
557 	hb_cfg.action_id = new_value;
558 
559 	ret = settings_save_one("hawkbit/action_id", &hb_cfg.action_id, sizeof(hb_cfg.action_id));
560 	if (ret < 0) {
561 		LOG_ERR("Failed to write device id: %d", ret);
562 		return -EIO;
563 	}
564 
565 	return 0;
566 }
567 
hawkbit_reset_action_id(void)568 int hawkbit_reset_action_id(void)
569 {
570 	int ret;
571 
572 	if (k_sem_take(&probe_sem, K_NO_WAIT) == 0) {
573 		ret = hawkbit_device_acid_update(0);
574 		k_sem_give(&probe_sem);
575 		return ret;
576 	}
577 	return -EAGAIN;
578 }
579 
hawkbit_get_action_id(void)580 int32_t hawkbit_get_action_id(void)
581 {
582 	return hb_cfg.action_id;
583 }
584 
hawkbit_get_poll_interval(void)585 uint32_t hawkbit_get_poll_interval(void)
586 {
587 	return poll_sleep;
588 }
589 
590 /*
591  * Update sleep interval, based on results from hawkBit base polling
592  * resource
593  */
hawkbit_update_sleep(struct hawkbit_ctl_res * hawkbit_res)594 static void hawkbit_update_sleep(struct hawkbit_ctl_res *hawkbit_res)
595 {
596 	int sleep_time;
597 	const char *sleep = hawkbit_res->config.polling.sleep;
598 
599 	if (strlen(sleep) != HAWKBIT_SLEEP_LENGTH) {
600 		LOG_ERR("Invalid poll sleep: %s", sleep);
601 	} else {
602 		sleep_time = hawkbit_time2sec(sleep);
603 		if (sleep_time > 0 && poll_sleep != sleep_time) {
604 			LOG_DBG("New poll sleep %d seconds", sleep_time);
605 			poll_sleep = (uint32_t)sleep_time;
606 		}
607 	}
608 }
609 
hawkbit_get_url(const char * href)610 static char *hawkbit_get_url(const char *href)
611 {
612 	char *helper;
613 
614 	helper = strstr(href, "//");
615 	if (helper != NULL) {
616 		helper = strstr(helper + 2u, "/");
617 	}
618 
619 	if (!helper) {
620 		LOG_ERR("Unexpected href format: %s", helper);
621 		return NULL;
622 	}
623 	return helper;
624 }
625 
626 /*
627  * Find URL component for the device cancel action id
628  */
hawkbit_find_cancel_action_id(struct hawkbit_ctl_res * res,int32_t * cancel_action_id)629 static int hawkbit_find_cancel_action_id(struct hawkbit_ctl_res *res,
630 					  int32_t *cancel_action_id)
631 {
632 	char *helper;
633 
634 	helper = strstr(res->_links.cancelAction.href, "cancelAction/");
635 	if (!helper) {
636 		/* A badly formatted cancel base is a server error */
637 		LOG_ERR("Missing %s/ in href %s", "cancelAction", res->_links.cancelAction.href);
638 		return -EINVAL;
639 	}
640 
641 	helper += sizeof("cancelAction/");
642 
643 	*cancel_action_id = strtol(helper, NULL, 10);
644 	if (*cancel_action_id <= 0) {
645 		LOG_ERR("Invalid action_id: %d", *cancel_action_id);
646 		return -EINVAL;
647 	}
648 
649 	return 0;
650 }
651 
hawkbit_deployment_get_action_id(struct hawkbit_dep_res * res,int32_t * action_id)652 static int hawkbit_deployment_get_action_id(struct hawkbit_dep_res *res, int32_t *action_id)
653 {
654 	int32_t id;
655 
656 	id = strtol(res->id, NULL, 10);
657 	if (id <= 0) {
658 		LOG_ERR("Invalid action_id: %d", id);
659 		return -EINVAL;
660 	}
661 
662 	*action_id = id;
663 
664 	return 0;
665 }
666 
667 /*
668  * Find URL component for this device's deployment operations
669  * resource.
670  */
hawkbit_parse_deployment(struct hawkbit_context * hb_context,struct hawkbit_dep_res * res,char ** download_http)671 static int hawkbit_parse_deployment(struct hawkbit_context *hb_context, struct hawkbit_dep_res *res,
672 				    char **download_http)
673 {
674 	const char *href;
675 	struct hawkbit_dep_res_chunk *chunk;
676 	size_t num_chunks, num_artifacts;
677 	struct hawkbit_dep_res_arts *artifact;
678 
679 	num_chunks = res->deployment.num_chunks;
680 	if (num_chunks != 1) {
681 		LOG_ERR("Expecting 1 chunk (got %d)", num_chunks);
682 		return -ENOSPC;
683 	}
684 
685 	chunk = &res->deployment.chunks[0];
686 	if (strcmp("bApp", chunk->part)) {
687 		LOG_ERR("Only part 'bApp' is supported; got %s", chunk->part);
688 		return -EINVAL;
689 	}
690 
691 	num_artifacts = chunk->num_artifacts;
692 	if (num_artifacts != 1) {
693 		LOG_ERR("Expecting 1 artifact (got %d)", num_artifacts);
694 		return -EINVAL;
695 	}
696 
697 	artifact = &chunk->artifacts[0];
698 	if (hex2bin(artifact->hashes.sha256, SHA256_HASH_SIZE << 1, hb_context->dl.file_hash,
699 		    sizeof(hb_context->dl.file_hash)) != SHA256_HASH_SIZE) {
700 		return -EINVAL;
701 	}
702 
703 	hb_context->dl.file_size = artifact->size;
704 
705 	if (hb_context->dl.file_size > SLOT1_SIZE) {
706 		LOG_ERR("Artifact file size too big (got %d, max is %d)", hb_context->dl.file_size,
707 			SLOT1_SIZE);
708 		return -ENOSPC;
709 	}
710 
711 	/*
712 	 * Find the download-http href.
713 	 */
714 	href = artifact->_links.download_http.href;
715 	if (!href) {
716 		LOG_ERR("Missing expected %s href", "download-http");
717 		return -EINVAL;
718 	}
719 
720 	/* Success. */
721 	if (download_http != NULL) {
722 		*download_http = hawkbit_get_url(href);
723 		if (*download_http == NULL) {
724 			LOG_ERR("Failed to parse %s url", "deploymentBase");
725 			return -EINVAL;
726 		}
727 	}
728 	return 0;
729 }
730 
hawkbit_dump_deployment(struct hawkbit_dep_res * d)731 static void hawkbit_dump_deployment(struct hawkbit_dep_res *d)
732 {
733 	struct hawkbit_dep_res_chunk *c = &d->deployment.chunks[0];
734 	struct hawkbit_dep_res_arts *a = &c->artifacts[0];
735 	struct hawkbit_dep_res_links *l = &a->_links;
736 
737 	LOG_DBG("%s=%s", "id", d->id);
738 	LOG_DBG("%s=%s", "download", d->deployment.download);
739 	LOG_DBG("%s=%s", "update", d->deployment.update);
740 	LOG_DBG("chunks[0].%s=%s", "part", c->part);
741 	LOG_DBG("chunks[0].%s=%s", "name", c->name);
742 	LOG_DBG("chunks[0].%s=%s", "version", c->version);
743 	LOG_DBG("chunks[0].artifacts[0].%s=%s", "filename", a->filename);
744 	LOG_DBG("chunks[0].artifacts[0].%s=%s", "hashes.sha1", a->hashes.sha1);
745 	LOG_DBG("chunks[0].artifacts[0].%s=%s", "hashes.md5", a->hashes.md5);
746 	LOG_DBG("chunks[0].artifacts[0].%s=%s", "hashes.sha256", a->hashes.sha256);
747 	LOG_DBG("chunks[0].size=%d", a->size);
748 	LOG_DBG("%s=%s", "download-http", l->download_http.href);
749 	LOG_DBG("%s=%s", "md5sum-http", l->md5sum_http.href);
750 }
751 
hawkbit_set_custom_data_cb(hawkbit_config_device_data_cb_handler_t cb)752 int hawkbit_set_custom_data_cb(hawkbit_config_device_data_cb_handler_t cb)
753 {
754 	if (IS_ENABLED(CONFIG_HAWKBIT_CUSTOM_ATTRIBUTES)) {
755 		if (cb == NULL) {
756 			LOG_ERR("Invalid callback");
757 			return -EINVAL;
758 		}
759 
760 		hawkbit_config_device_data_cb_handler = cb;
761 
762 		return 0;
763 	}
764 	return -ENOTSUP;
765 }
766 
hawkbit_default_config_data_cb(const char * device_id,uint8_t * buffer,const size_t buffer_size)767 int hawkbit_default_config_data_cb(const char *device_id, uint8_t *buffer, const size_t buffer_size)
768 {
769 	struct hawkbit_cfg cfg = {
770 		.mode = "merge",
771 		.data.VIN = device_id,
772 	};
773 
774 	return json_obj_encode_buf(json_cfg_descr, ARRAY_SIZE(json_cfg_descr), &cfg, buffer,
775 				   buffer_size);
776 }
777 
778 #ifdef CONFIG_HAWKBIT_SET_SETTINGS_RUNTIME
hawkbit_set_config(struct hawkbit_runtime_config * config)779 int hawkbit_set_config(struct hawkbit_runtime_config *config)
780 {
781 	if (k_sem_take(&probe_sem, HAWKBIT_SET_SERVER_TIMEOUT) == 0) {
782 		if (config->server_addr != NULL) {
783 			strncpy(hb_cfg.server_addr, config->server_addr,
784 				sizeof(hb_cfg.server_addr));
785 			LOG_DBG("configured %s: %s", "hawkbit/server_addr", hb_cfg.server_addr);
786 		}
787 		if (config->server_port != 0) {
788 			snprintf(hb_cfg.server_port, sizeof(hb_cfg.server_port), "%u",
789 				 config->server_port);
790 			LOG_DBG("configured %s: %s", "hawkbit/server_port", hb_cfg.server_port);
791 		}
792 #ifndef CONFIG_HAWKBIT_DDI_NO_SECURITY
793 		if (config->auth_token != NULL) {
794 			strncpy(hb_cfg.ddi_security_token, config->auth_token,
795 				sizeof(hb_cfg.ddi_security_token));
796 			LOG_DBG("configured %s: %s", "hawkbit/ddi_token",
797 				hb_cfg.ddi_security_token);
798 		}
799 #endif /* CONFIG_HAWKBIT_DDI_NO_SECURITY */
800 #ifdef CONFIG_HAWKBIT_USE_DYNAMIC_CERT_TAG
801 		if (config->tls_tag != 0) {
802 			hb_cfg.tls_tag = config->tls_tag;
803 			LOG_DBG("configured %s: %d", "hawkbit/tls_tag", hb_cfg.tls_tag);
804 		}
805 #endif /* CONFIG_HAWKBIT_USE_DYNAMIC_CERT_TAG */
806 		settings_save_subtree("hawkbit");
807 		k_sem_give(&probe_sem);
808 	} else {
809 		LOG_WRN("failed setting config");
810 		return -EAGAIN;
811 	}
812 
813 	return 0;
814 }
815 #endif /* CONFIG_HAWKBIT_SET_SETTINGS_RUNTIME */
816 
hawkbit_get_config(void)817 struct hawkbit_runtime_config hawkbit_get_config(void)
818 {
819 	struct hawkbit_runtime_config config = {
820 		.server_addr = HAWKBIT_SERVER,
821 		.server_port = HAWKBIT_PORT_INT,
822 		.auth_token = HAWKBIT_DDI_SECURITY_TOKEN,
823 		.tls_tag = HAWKBIT_CERT_TAG,
824 	};
825 
826 	return config;
827 }
828 
hawkbit_init(void)829 int hawkbit_init(void)
830 {
831 	bool image_ok;
832 	int ret = 0;
833 
834 	if (hawkbit_initialized) {
835 		return 0;
836 	}
837 
838 	ret = settings_subsys_init();
839 	if (ret < 0) {
840 		LOG_ERR("Failed to initialize settings subsystem: %d", ret);
841 		return ret;
842 	}
843 
844 	ret = settings_load_subtree("hawkbit");
845 	if (ret < 0) {
846 		LOG_ERR("Failed to load settings: %d", ret);
847 		return ret;
848 	}
849 
850 	LOG_DBG("Current action_id: %d", hb_cfg.action_id);
851 
852 	image_ok = boot_is_img_confirmed();
853 	LOG_INF("Current image is%s confirmed", image_ok ? "" : " not");
854 	if (!image_ok) {
855 		ret = boot_write_img_confirmed();
856 		if (ret < 0) {
857 			LOG_ERR("Failed to confirm current image: %d", ret);
858 			return ret;
859 		}
860 
861 		LOG_DBG("Marked current image as OK");
862 		ret = boot_erase_img_bank(flash_img_get_upload_slot());
863 		if (ret < 0) {
864 			LOG_ERR("Failed to erase second slot: %d", ret);
865 			return ret;
866 		}
867 	}
868 	hawkbit_initialized = true;
869 
870 	return ret;
871 }
872 
response_json_cb(struct http_response * rsp,enum http_final_call final_data,struct hawkbit_context * hb_context)873 static void response_json_cb(struct http_response *rsp, enum http_final_call final_data,
874 			     struct hawkbit_context *hb_context)
875 {
876 	size_t body_len;
877 	int ret;
878 	uint8_t *body_data = NULL, *rsp_tmp = NULL;
879 
880 	if (hb_context->dl.http_content_size == 0) {
881 		hb_context->dl.http_content_size = rsp->content_length;
882 	}
883 
884 	if (rsp->body_found) {
885 		body_data = rsp->body_frag_start;
886 		body_len = rsp->body_frag_len;
887 
888 		if ((hb_context->dl.downloaded_size + body_len) >
889 			hb_context->response_data_size) {
890 			hb_context->response_data_size =
891 				hb_context->dl.downloaded_size + body_len;
892 			rsp_tmp = k_realloc(hb_context->response_data,
893 						hb_context->response_data_size);
894 			if (rsp_tmp == NULL) {
895 				LOG_ERR("Failed to realloc memory");
896 				hb_context->code_status = HAWKBIT_ALLOC_ERROR;
897 				return;
898 			}
899 
900 			hb_context->response_data = rsp_tmp;
901 		}
902 		strncpy(hb_context->response_data + hb_context->dl.downloaded_size,
903 			body_data, body_len);
904 		hb_context->dl.downloaded_size += body_len;
905 	}
906 
907 	if (final_data == HTTP_DATA_FINAL) {
908 		if (hb_context->dl.http_content_size != hb_context->dl.downloaded_size) {
909 			LOG_ERR("HTTP response len mismatch, expected %d, got %d",
910 				hb_context->dl.http_content_size,
911 				hb_context->dl.downloaded_size);
912 			hb_context->code_status = HAWKBIT_METADATA_ERROR;
913 			return;
914 		}
915 
916 		hb_context->response_data[hb_context->dl.downloaded_size] = '\0';
917 		memset(&hb_context->results, 0, sizeof(hb_context->results));
918 		if (hb_context->type == HAWKBIT_PROBE) {
919 			ret = json_obj_parse(
920 				hb_context->response_data, hb_context->dl.downloaded_size,
921 				json_ctl_res_descr, ARRAY_SIZE(json_ctl_res_descr),
922 				&hb_context->results.base);
923 			if (ret < 0) {
924 				LOG_ERR("JSON parse error (%s): %d", "HAWKBIT_PROBE", ret);
925 				hb_context->code_status = HAWKBIT_METADATA_ERROR;
926 			}
927 		} else {
928 			ret = json_obj_parse(
929 				hb_context->response_data, hb_context->dl.downloaded_size,
930 				json_dep_res_descr, ARRAY_SIZE(json_dep_res_descr),
931 				&hb_context->results.dep);
932 			if (ret < 0) {
933 				LOG_ERR("JSON parse error (%s): %d", "deploymentBase", ret);
934 				hb_context->code_status = HAWKBIT_METADATA_ERROR;
935 			}
936 		}
937 	}
938 }
939 
response_download_cb(struct http_response * rsp,enum http_final_call final_data,struct hawkbit_context * hb_context)940 static void response_download_cb(struct http_response *rsp, enum http_final_call final_data,
941 				 struct hawkbit_context *hb_context)
942 {
943 	size_t body_len;
944 	int ret, downloaded;
945 	uint8_t *body_data = NULL;
946 	static uint8_t download_progress;
947 
948 	if (hb_context->dl.http_content_size == 0) {
949 		hb_context->dl.http_content_size = rsp->content_length;
950 		download_progress = 0;
951 		if (IS_ENABLED(CONFIG_HAWKBIT_SAVE_PROGRESS) && rsp->http_status_code != 206) {
952 			hb_context->flash_ctx.stream.bytes_written = 0;
953 		}
954 	}
955 
956 	if (!rsp->body_found) {
957 		return;
958 	}
959 
960 	body_data = rsp->body_frag_start;
961 	body_len = rsp->body_frag_len;
962 
963 	ret = flash_img_buffered_write(&hb_context->flash_ctx, body_data, body_len,
964 				       final_data == HTTP_DATA_FINAL);
965 	if (ret < 0) {
966 		LOG_ERR("Failed to write flash: %d", ret);
967 		hb_context->code_status = HAWKBIT_DOWNLOAD_ERROR;
968 		return;
969 	}
970 
971 #if defined CONFIG_HAWKBIT_SAVE_PROGRESS && IS_EQ(CONFIG_HAWKBIT_SAVE_PROGRESS_INTERVAL, 0)
972 	stream_flash_progress_save(&hb_context->flash_ctx.stream, "hawkbit/flash_progress");
973 #endif
974 
975 	hb_context->dl.downloaded_size = flash_img_bytes_written(&hb_context->flash_ctx);
976 
977 	downloaded = hb_context->dl.downloaded_size * 100 / hb_context->dl.file_size;
978 
979 	if (downloaded != download_progress) {
980 #if defined CONFIG_HAWKBIT_SAVE_PROGRESS && !IS_EQ(CONFIG_HAWKBIT_SAVE_PROGRESS_INTERVAL, 0)
981 		if ((downloaded / CONFIG_HAWKBIT_SAVE_PROGRESS_INTERVAL) >
982 		    (download_progress / CONFIG_HAWKBIT_SAVE_PROGRESS_INTERVAL)) {
983 			stream_flash_progress_save(&hb_context->flash_ctx.stream,
984 						   "hawkbit/flash_progress");
985 		}
986 #endif
987 		download_progress = downloaded;
988 		LOG_DBG("Downloaded: %u%% (%u / %u)", download_progress,
989 			hb_context->dl.downloaded_size, hb_context->dl.file_size);
990 	}
991 
992 	if (final_data == HTTP_DATA_FINAL) {
993 		hb_context->final_data_received = true;
994 	}
995 }
996 
response_cb(struct http_response * rsp,enum http_final_call final_data,void * userdata)997 static void response_cb(struct http_response *rsp, enum http_final_call final_data, void *userdata)
998 {
999 	struct hawkbit_context *hb_context = userdata;
1000 
1001 	if (!IN_RANGE(rsp->http_status_code, 200, 299)) {
1002 		LOG_ERR("HTTP request denied: %d", rsp->http_status_code);
1003 		if (rsp->http_status_code == 401 || rsp->http_status_code == 403) {
1004 			hb_context->code_status = HAWKBIT_PERMISSION_ERROR;
1005 		} else {
1006 			hb_context->code_status = HAWKBIT_METADATA_ERROR;
1007 		}
1008 		return;
1009 	}
1010 
1011 	switch (hb_context->type) {
1012 	case HAWKBIT_PROBE:
1013 	case HAWKBIT_PROBE_DEPLOYMENT_BASE:
1014 		response_json_cb(rsp, final_data, hb_context);
1015 		break;
1016 
1017 	case HAWKBIT_DOWNLOAD:
1018 		response_download_cb(rsp, final_data, hb_context);
1019 		break;
1020 
1021 	default:
1022 		break;
1023 	}
1024 }
1025 
send_request(struct hawkbit_context * hb_context,enum hawkbit_http_request type,char * url_buffer,uint8_t * status_buffer)1026 static bool send_request(struct hawkbit_context *hb_context, enum hawkbit_http_request type,
1027 			 char *url_buffer, uint8_t *status_buffer)
1028 {
1029 	int ret = 0;
1030 	uint8_t recv_buf_tcp[RECV_BUFFER_SIZE] = {0};
1031 	struct http_request http_req = {0};
1032 #ifndef CONFIG_HAWKBIT_DDI_NO_SECURITY
1033 #ifdef CONFIG_HAWKBIT_SET_SETTINGS_RUNTIME
1034 	char header[DDI_SECURITY_TOKEN_SIZE + sizeof(AUTH_HEADER_START) + sizeof(HTTP_CRLF) - 1];
1035 
1036 	snprintf(header, sizeof(header), AUTH_HEADER_FULL, hb_cfg.ddi_security_token);
1037 	const char *const headers[] = {header, NULL};
1038 #else
1039 	static const char *const headers[] = {AUTH_HEADER_FULL, NULL};
1040 #endif /* CONFIG_HAWKBIT_SET_SETTINGS_RUNTIME */
1041 #endif /* CONFIG_HAWKBIT_DDI_NO_SECURITY */
1042 
1043 	http_req.url = url_buffer;
1044 	http_req.host = HAWKBIT_SERVER;
1045 	http_req.port = HAWKBIT_PORT;
1046 	http_req.protocol = "HTTP/1.1";
1047 	http_req.response = response_cb;
1048 	http_req.recv_buf = recv_buf_tcp;
1049 	http_req.recv_buf_len = sizeof(recv_buf_tcp);
1050 #ifndef CONFIG_HAWKBIT_DDI_NO_SECURITY
1051 	http_req.header_fields = (const char **)headers;
1052 #endif
1053 	hb_context->final_data_received = false;
1054 	hb_context->type = type;
1055 
1056 	switch (type) {
1057 	case HAWKBIT_CONFIG_DEVICE:
1058 		/*
1059 		 * Feedback channel for the config data action
1060 		 * PUT: /{tenant}/controller/v1/{controllerId}/configData
1061 		 */
1062 		http_req.method = HTTP_PUT;
1063 		http_req.content_type_value = HTTP_HEADER_CONTENT_TYPE_JSON;
1064 		http_req.payload = status_buffer;
1065 		http_req.payload_len = strlen(status_buffer);
1066 
1067 		break;
1068 
1069 	case HAWKBIT_CANCEL:
1070 		/*
1071 		 * Feedback channel for cancel actions
1072 		 * POST: /{tenant}/controller/v1/{controllerId}/cancelAction/{actionId}/feedback
1073 		 */
1074 	case HAWKBIT_REPORT:
1075 		/*
1076 		 * Feedback channel for the DeploymentBase action
1077 		 * POST: /{tenant}/controller/v1/{controllerId}/deploymentBase/{actionId}/feedback
1078 		 */
1079 		http_req.method = HTTP_POST;
1080 		http_req.content_type_value = HTTP_HEADER_CONTENT_TYPE_JSON;
1081 		http_req.payload = status_buffer;
1082 		http_req.payload_len = strlen(status_buffer);
1083 
1084 		break;
1085 
1086 	case HAWKBIT_PROBE:
1087 		/*
1088 		 * Root resource for an individual Target
1089 		 * GET: /{tenant}/controller/v1/{controllerId}
1090 		 */
1091 	case HAWKBIT_PROBE_DEPLOYMENT_BASE:
1092 		/*
1093 		 * Resource for software module (Deployment Base)
1094 		 * GET: /{tenant}/controller/v1/{controllerId}/deploymentBase/{actionId}
1095 		 */
1096 
1097 		http_req.method = HTTP_GET;
1098 		hb_context->dl.http_content_size = 0;
1099 		hb_context->dl.downloaded_size = 0;
1100 
1101 		break;
1102 
1103 	case HAWKBIT_DOWNLOAD:
1104 		/*
1105 		 * Resource for software module (Deployment Base)
1106 		 * GET: /{tenant}/controller/v1/{controllerId}/softwaremodules/{softwareModuleId}/
1107 		 *      artifacts/{fileName}
1108 		 */
1109 		http_req.method = HTTP_GET;
1110 		hb_context->dl.http_content_size = 0;
1111 
1112 #ifdef CONFIG_HAWKBIT_SAVE_PROGRESS
1113 		hb_context->dl.downloaded_size = flash_img_bytes_written(&hb_context->flash_ctx);
1114 		if (IN_RANGE(hb_context->dl.downloaded_size, 1, hb_context->dl.file_size)) {
1115 			char header_range[RANGE_HEADER_SIZE] = {0};
1116 
1117 			snprintf(header_range, sizeof(header_range), "Range: bytes=%u-" HTTP_CRLF,
1118 				 hb_context->dl.downloaded_size);
1119 			const char *const headers_range[] = {header_range, NULL};
1120 
1121 			http_req.optional_headers = (const char **)headers_range;
1122 			LOG_DBG("optional header: %s", header_range);
1123 			LOG_INF("Resuming download from %d bytes", hb_context->dl.downloaded_size);
1124 		}
1125 #else
1126 		hb_context->dl.downloaded_size = 0;
1127 #endif
1128 
1129 		break;
1130 
1131 	default:
1132 		return false;
1133 	}
1134 
1135 	ret = http_client_req(hb_context->sock, &http_req, HAWKBIT_RECV_TIMEOUT, hb_context);
1136 	if (ret < 0) {
1137 		LOG_ERR("Failed to send request: %d", ret);
1138 		hb_context->code_status = HAWKBIT_NETWORKING_ERROR;
1139 		return false;
1140 	}
1141 
1142 	if (IN_RANGE(hb_context->code_status, HAWKBIT_NETWORKING_ERROR, HAWKBIT_ALLOC_ERROR)) {
1143 		return false;
1144 	}
1145 
1146 	return true;
1147 }
1148 
hawkbit_reboot(void)1149 void hawkbit_reboot(void)
1150 {
1151 	hawkbit_event_raise(HAWKBIT_EVENT_BEFORE_REBOOT);
1152 	LOG_PANIC();
1153 	sys_reboot(IS_ENABLED(CONFIG_HAWKBIT_REBOOT_COLD) ? SYS_REBOOT_COLD : SYS_REBOOT_WARM);
1154 }
1155 
check_hawkbit_server(void)1156 static bool check_hawkbit_server(void)
1157 {
1158 	if (strlen(HAWKBIT_SERVER) == 0) {
1159 		if (sizeof(CONFIG_HAWKBIT_SERVER) > 1) {
1160 			hawkbit_set_server_addr(CONFIG_HAWKBIT_SERVER);
1161 		} else {
1162 			LOG_ERR("no valid %s found", "hawkbit/server_addr");
1163 			return false;
1164 		}
1165 	}
1166 
1167 	if (HAWKBIT_PORT_INT == 0) {
1168 		if (CONFIG_HAWKBIT_PORT > 0) {
1169 			hawkbit_set_server_port(CONFIG_HAWKBIT_PORT);
1170 		} else {
1171 			LOG_ERR("no valid %s found", "hawkbit/server_port");
1172 			return false;
1173 		}
1174 	}
1175 
1176 #ifndef CONFIG_HAWKBIT_DDI_NO_SECURITY
1177 	if (strlen(HAWKBIT_DDI_SECURITY_TOKEN) == 0) {
1178 		if (sizeof(CONFIG_HAWKBIT_DDI_SECURITY_TOKEN) > 1) {
1179 			hawkbit_set_ddi_security_token(CONFIG_HAWKBIT_DDI_SECURITY_TOKEN);
1180 		} else {
1181 			LOG_ERR("no valid %s found", "hawkbit/ddi_token");
1182 			return false;
1183 		}
1184 	}
1185 #endif /* CONFIG_HAWKBIT_DDI_NO_SECURITY */
1186 
1187 	return true;
1188 }
1189 
s_start(void * o)1190 static void s_start(void *o)
1191 {
1192 	struct s_object *s = (struct s_object *)o;
1193 
1194 	if (!hawkbit_initialized) {
1195 		smf_set_terminate(SMF_CTX(s), HAWKBIT_NOT_INITIALIZED);
1196 		return;
1197 	}
1198 
1199 	if (!check_hawkbit_server()) {
1200 		smf_set_terminate(SMF_CTX(s), HAWKBIT_NETWORKING_ERROR);
1201 		return;
1202 	}
1203 
1204 	if (k_sem_take(&probe_sem, K_NO_WAIT) != 0) {
1205 		LOG_INF("hawkBit is already running");
1206 		smf_set_terminate(SMF_CTX(s), HAWKBIT_PROBE_IN_PROGRESS);
1207 		return;
1208 	}
1209 
1210 	if (!boot_is_img_confirmed()) {
1211 		LOG_ERR("Current image is not confirmed");
1212 		k_sem_give(&probe_sem);
1213 		smf_set_terminate(SMF_CTX(s), HAWKBIT_UNCONFIRMED_IMAGE);
1214 		return;
1215 	}
1216 
1217 	if (!hawkbit_get_device_identity(s->device_id, DEVICE_ID_HEX_MAX_SIZE)) {
1218 		k_sem_give(&probe_sem);
1219 		smf_set_terminate(SMF_CTX(s), HAWKBIT_METADATA_ERROR);
1220 		return;
1221 	}
1222 }
1223 
s_end(void * o)1224 static void s_end(void *o)
1225 {
1226 	ARG_UNUSED(o);
1227 	k_sem_give(&probe_sem);
1228 }
1229 
s_http_start(void * o)1230 static void s_http_start(void *o)
1231 {
1232 	struct s_object *s = (struct s_object *)o;
1233 
1234 	if (!start_http_client(&s->hb_context.sock)) {
1235 		s->hb_context.code_status = HAWKBIT_NETWORKING_ERROR;
1236 		smf_set_state(SMF_CTX(s), &hawkbit_states[S_HAWKBIT_TERMINATE]);
1237 	}
1238 
1239 	s->hb_context.response_data_size = RESPONSE_BUFFER_SIZE;
1240 
1241 	s->hb_context.response_data = k_calloc(s->hb_context.response_data_size, sizeof(uint8_t));
1242 	if (s->hb_context.response_data == NULL) {
1243 		cleanup_connection(&s->hb_context.sock);
1244 		s->hb_context.code_status = HAWKBIT_ALLOC_ERROR;
1245 		smf_set_state(SMF_CTX(s), &hawkbit_states[S_HAWKBIT_TERMINATE]);
1246 	}
1247 }
1248 
s_http_end(void * o)1249 static void s_http_end(void *o)
1250 {
1251 	struct s_object *s = (struct s_object *)o;
1252 
1253 	cleanup_connection(&s->hb_context.sock);
1254 	k_free(s->hb_context.response_data);
1255 }
1256 
1257 /*
1258  * Root resource for an individual Target
1259  * GET: /{tenant}/controller/v1/{controllerId}
1260  */
s_probe(void * o)1261 static void s_probe(void *o)
1262 {
1263 	struct s_object *s = (struct s_object *)o;
1264 	char url_buffer[URL_BUFFER_SIZE] = {0};
1265 
1266 	LOG_INF("Polling target data from hawkBit");
1267 
1268 	snprintk(url_buffer, sizeof(url_buffer), "%s/%s-%s", HAWKBIT_JSON_URL, CONFIG_BOARD,
1269 		 s->device_id);
1270 
1271 	if (!send_request(&s->hb_context, HAWKBIT_PROBE, url_buffer, NULL)) {
1272 		LOG_ERR("Send request failed (%s)", "HAWKBIT_PROBE");
1273 		smf_set_state(SMF_CTX(s), &hawkbit_states[S_HAWKBIT_TERMINATE]);
1274 		return;
1275 	}
1276 
1277 	if (s->hb_context.results.base.config.polling.sleep) {
1278 		/* Update the sleep time. */
1279 		LOG_DBG("config.polling.sleep=%s", s->hb_context.results.base.config.polling.sleep);
1280 		hawkbit_update_sleep(&s->hb_context.results.base);
1281 	}
1282 
1283 	if (s->hb_context.results.base._links.cancelAction.href) {
1284 		LOG_DBG("_links.%s.href=%s", "cancelAction",
1285 			s->hb_context.results.base._links.cancelAction.href);
1286 		smf_set_state(SMF_CTX(s), &hawkbit_states[S_HAWKBIT_CANCEL]);
1287 	} else if (s->hb_context.results.base._links.configData.href) {
1288 		LOG_DBG("_links.%s.href=%s", "configData",
1289 			s->hb_context.results.base._links.configData.href);
1290 		smf_set_state(SMF_CTX(s), &hawkbit_states[S_HAWKBIT_CONFIG_DEVICE]);
1291 	} else if (s->hb_context.results.base._links.deploymentBase.href) {
1292 		LOG_DBG("_links.%s.href=%s", "deploymentBase",
1293 			s->hb_context.results.base._links.deploymentBase.href);
1294 		smf_set_state(SMF_CTX(s), &hawkbit_states[S_HAWKBIT_PROBE_DEPLOYMENT_BASE]);
1295 	} else {
1296 		s->hb_context.code_status = HAWKBIT_NO_UPDATE;
1297 		hawkbit_event_raise(HAWKBIT_EVENT_NO_UPDATE);
1298 		smf_set_state(SMF_CTX(s), &hawkbit_states[S_HAWKBIT_TERMINATE]);
1299 	}
1300 }
1301 
1302 /*
1303  * Feedback channel for cancel actions
1304  * POST: /{tenant}/controller/v1/{controllerId}/cancelAction/{actionId}/feedback
1305  */
s_cancel(void * o)1306 static void s_cancel(void *o)
1307 {
1308 	int ret = 0;
1309 	int32_t cancel_action_id = 0;
1310 	struct s_object *s = (struct s_object *)o;
1311 	char *cancel_base;
1312 	uint8_t status_buffer[CONFIG_HAWKBIT_STATUS_BUFFER_SIZE] = {0};
1313 	char url_buffer[URL_BUFFER_SIZE] = {0};
1314 	struct hawkbit_cancel cancel = {0};
1315 
1316 	cancel_base = hawkbit_get_url(s->hb_context.results.base._links.cancelAction.href);
1317 	if (cancel_base == NULL) {
1318 		LOG_ERR("Can't find %s url", "cancelAction");
1319 		s->hb_context.code_status = HAWKBIT_METADATA_ERROR;
1320 		smf_set_state(SMF_CTX(s), &hawkbit_states[S_HAWKBIT_TERMINATE]);
1321 		return;
1322 	}
1323 
1324 	snprintk(url_buffer, sizeof(url_buffer), "%s/%s", cancel_base, "feedback");
1325 
1326 	ret = hawkbit_find_cancel_action_id(&s->hb_context.results.base, &cancel_action_id);
1327 	if (ret < 0) {
1328 		LOG_ERR("Can't find %s id: %d", "cancelAction", ret);
1329 		s->hb_context.code_status = HAWKBIT_METADATA_ERROR;
1330 		smf_set_state(SMF_CTX(s), &hawkbit_states[S_HAWKBIT_TERMINATE]);
1331 		return;
1332 	}
1333 
1334 	cancel.status.execution = hawkbit_status_execution(HAWKBIT_STATUS_EXEC_CLOSED);
1335 	cancel.status.result.finished = hawkbit_status_finished(
1336 		hb_cfg.action_id == cancel_action_id ? HAWKBIT_STATUS_FINISHED_FAILURE
1337 						     : HAWKBIT_STATUS_FINISHED_SUCCESS);
1338 
1339 	ret = json_obj_encode_buf(json_cancel_descr, ARRAY_SIZE(json_cancel_descr), &cancel,
1340 				  status_buffer, sizeof(status_buffer));
1341 	if (ret) {
1342 		LOG_ERR("Can't encode the JSON script (%s): %d", "HAWKBIT_CANCEL", ret);
1343 		s->hb_context.code_status = HAWKBIT_METADATA_ERROR;
1344 		smf_set_state(SMF_CTX(s), &hawkbit_states[S_HAWKBIT_TERMINATE]);
1345 		return;
1346 	}
1347 
1348 	if (!send_request(&s->hb_context, HAWKBIT_CANCEL, url_buffer, status_buffer)) {
1349 		LOG_ERR("Send request failed (%s)", "HAWKBIT_CANCEL");
1350 		smf_set_state(SMF_CTX(s), &hawkbit_states[S_HAWKBIT_TERMINATE]);
1351 		return;
1352 	}
1353 
1354 	LOG_INF("From hawkBit server requested update cancellation %s",
1355 		hb_cfg.action_id == cancel_action_id ? "rejected" : "accepted");
1356 
1357 	if (hb_cfg.action_id != cancel_action_id) {
1358 		hawkbit_event_raise(HAWKBIT_EVENT_CANCEL_UPDATE);
1359 	}
1360 
1361 	smf_set_state(SMF_CTX(s), &hawkbit_states[S_HAWKBIT_PROBE]);
1362 }
1363 
1364 /*
1365  * Feedback channel for the config data action
1366  * PUT: /{tenant}/controller/v1/{controllerId}/configData
1367  */
s_config_device(void * o)1368 static void s_config_device(void *o)
1369 {
1370 	int ret = 0;
1371 	struct s_object *s = (struct s_object *)o;
1372 	uint8_t status_buffer[CONFIG_HAWKBIT_STATUS_BUFFER_SIZE] = {0};
1373 	char *url_buffer;
1374 
1375 	url_buffer = hawkbit_get_url(s->hb_context.results.base._links.configData.href);
1376 	if (url_buffer == NULL) {
1377 		LOG_ERR("Can't find %s url", "configData");
1378 		s->hb_context.code_status = HAWKBIT_METADATA_ERROR;
1379 		smf_set_state(SMF_CTX(s), &hawkbit_states[S_HAWKBIT_TERMINATE]);
1380 		return;
1381 	}
1382 
1383 	ret = hawkbit_config_device_data_cb_handler(s->device_id, status_buffer,
1384 						    sizeof(status_buffer));
1385 	if (ret) {
1386 		LOG_ERR("Can't encode the JSON script (%s): %d", "HAWKBIT_CONFIG_DEVICE", ret);
1387 		s->hb_context.code_status = HAWKBIT_METADATA_ERROR;
1388 		smf_set_state(SMF_CTX(s), &hawkbit_states[S_HAWKBIT_TERMINATE]);
1389 		return;
1390 	}
1391 
1392 	if (!send_request(&s->hb_context, HAWKBIT_CONFIG_DEVICE, url_buffer, status_buffer)) {
1393 		LOG_ERR("Send request failed (%s)", "HAWKBIT_CONFIG_DEVICE");
1394 		smf_set_state(SMF_CTX(s), &hawkbit_states[S_HAWKBIT_TERMINATE]);
1395 		return;
1396 	}
1397 
1398 	smf_set_state(SMF_CTX(s), &hawkbit_states[S_HAWKBIT_PROBE]);
1399 }
1400 
1401 /*
1402  * Resource for software module (Deployment Base)
1403  * GET: /{tenant}/controller/v1/{controllerId}/deploymentBase/{actionId}
1404  */
s_probe_deployment_base(void * o)1405 static void s_probe_deployment_base(void *o)
1406 {
1407 	int ret = 0;
1408 	struct s_object *s = (struct s_object *)o;
1409 	char *url_buffer;
1410 
1411 	url_buffer = hawkbit_get_url(s->hb_context.results.base._links.deploymentBase.href);
1412 	if (url_buffer == NULL) {
1413 		LOG_ERR("Can't find %s url", "deploymentBase");
1414 		s->hb_context.code_status = HAWKBIT_METADATA_ERROR;
1415 		smf_set_state(SMF_CTX(s), &hawkbit_states[S_HAWKBIT_TERMINATE]);
1416 		return;
1417 	}
1418 
1419 	if (!send_request(&s->hb_context, HAWKBIT_PROBE_DEPLOYMENT_BASE, url_buffer, NULL)) {
1420 		LOG_ERR("Send request failed (%s)", "HAWKBIT_PROBE_DEPLOYMENT_BASE");
1421 		smf_set_state(SMF_CTX(s), &hawkbit_states[S_HAWKBIT_TERMINATE]);
1422 		return;
1423 	}
1424 
1425 	hawkbit_dump_deployment(&s->hb_context.results.dep);
1426 
1427 	ret = hawkbit_deployment_get_action_id(&s->hb_context.results.dep,
1428 					       &s->hb_context.json_action_id);
1429 	if (ret < 0) {
1430 		s->hb_context.code_status = HAWKBIT_METADATA_ERROR;
1431 		smf_set_state(SMF_CTX(s), &hawkbit_states[S_HAWKBIT_TERMINATE]);
1432 		return;
1433 	}
1434 
1435 	if (hb_cfg.action_id == s->hb_context.json_action_id) {
1436 		smf_set_state(SMF_CTX(s), &hawkbit_states[S_HAWKBIT_REPORT]);
1437 		return;
1438 	}
1439 
1440 	LOG_INF("Ready to download update");
1441 	smf_set_state(SMF_CTX(s), &hawkbit_states[S_HAWKBIT_DOWNLOAD]);
1442 }
1443 
1444 /*
1445  * Feedback channel for the DeploymentBase action
1446  * POST: /{tenant}/controller/v1/{controllerId}/deploymentBase/{actionId}/feedback
1447  */
s_report(void * o)1448 static void s_report(void *o)
1449 {
1450 	int ret = 0;
1451 	struct s_object *s = (struct s_object *)o;
1452 	struct hawkbit_dep_fbk feedback = {
1453 		.status.execution = hawkbit_status_execution(HAWKBIT_STATUS_EXEC_CLOSED),
1454 		.status.result.finished = hawkbit_status_finished(HAWKBIT_STATUS_FINISHED_SUCCESS),
1455 	};
1456 	uint8_t status_buffer[CONFIG_HAWKBIT_STATUS_BUFFER_SIZE] = {0};
1457 	char url_buffer[URL_BUFFER_SIZE] = {0};
1458 
1459 	snprintk(url_buffer, sizeof(url_buffer), "%s/%s-%s/%s/%d/%s", HAWKBIT_JSON_URL,
1460 		 CONFIG_BOARD, s->device_id, "deploymentBase", s->hb_context.json_action_id,
1461 		 "feedback");
1462 
1463 	LOG_INF("Reporting deployment feedback %s (%s) for action %d",
1464 		feedback.status.result.finished, feedback.status.execution,
1465 		s->hb_context.json_action_id);
1466 
1467 	ret = json_obj_encode_buf(json_dep_fbk_descr, ARRAY_SIZE(json_dep_fbk_descr), &feedback,
1468 				  status_buffer, sizeof(status_buffer));
1469 	if (ret) {
1470 		LOG_ERR("Can't encode the JSON script (%s): %d", "HAWKBIT_REPORT", ret);
1471 		s->hb_context.code_status = HAWKBIT_METADATA_ERROR;
1472 		smf_set_state(SMF_CTX(s), &hawkbit_states[S_HAWKBIT_TERMINATE]);
1473 		return;
1474 	}
1475 
1476 	if (!send_request(&s->hb_context, HAWKBIT_REPORT, url_buffer, status_buffer)) {
1477 		LOG_ERR("Send request failed (%s)", "HAWKBIT_REPORT");
1478 		smf_set_state(SMF_CTX(s), &hawkbit_states[S_HAWKBIT_TERMINATE]);
1479 		return;
1480 	}
1481 
1482 	smf_set_state(SMF_CTX(s), &hawkbit_states[S_HAWKBIT_PROBE]);
1483 }
1484 
s_download_start(void * o)1485 static void s_download_start(void *o)
1486 {
1487 	hawkbit_event_raise(HAWKBIT_EVENT_START_DOWNLOAD);
1488 }
1489 
s_download_end(void * o)1490 static void s_download_end(void *o)
1491 {
1492 	hawkbit_event_raise(HAWKBIT_EVENT_END_DOWNLOAD);
1493 }
1494 
1495 /*
1496  * Resource for software module (Deployment Base)
1497  * GET: /{tenant}/controller/v1/{controllerId}/softwaremodules/{softwareModuleId}/
1498  *      artifacts/{fileName}
1499  */
s_download(void * o)1500 static void s_download(void *o)
1501 {
1502 	int ret = 0;
1503 	struct s_object *s = (struct s_object *)o;
1504 	struct flash_img_check fic = {0};
1505 	const struct flash_area *flash_area_ptr;
1506 	char *url_buffer;
1507 
1508 	ret = hawkbit_parse_deployment(&s->hb_context, &s->hb_context.results.dep, &url_buffer);
1509 	if (ret < 0) {
1510 		LOG_ERR("Failed to parse %s: %d", "deploymentBase", ret);
1511 		s->hb_context.code_status = HAWKBIT_METADATA_ERROR;
1512 		smf_set_state(SMF_CTX(s), &hawkbit_states[S_HAWKBIT_TERMINATE]);
1513 		return;
1514 	}
1515 
1516 	flash_img_init(&s->hb_context.flash_ctx);
1517 
1518 	/* The flash_area pointer has to be copied before the download starts
1519 	 * because the flash_area will be set to NULL after the download has finished.
1520 	 */
1521 	flash_area_ptr = s->hb_context.flash_ctx.flash_area;
1522 
1523 #ifdef CONFIG_HAWKBIT_SAVE_PROGRESS
1524 	stream_flash_progress_load(&s->hb_context.flash_ctx.stream, "hawkbit/flash_progress");
1525 #endif
1526 
1527 	if (!send_request(&s->hb_context, HAWKBIT_DOWNLOAD, url_buffer, NULL)) {
1528 		LOG_ERR("Send request failed (%s)", "HAWKBIT_DOWNLOAD");
1529 		smf_set_state(SMF_CTX(s), &hawkbit_states[S_HAWKBIT_TERMINATE]);
1530 		return;
1531 	}
1532 
1533 	/* Check if download finished */
1534 	if (!s->hb_context.final_data_received) {
1535 		LOG_ERR("Download incomplete");
1536 		s->hb_context.code_status = HAWKBIT_DOWNLOAD_ERROR;
1537 		smf_set_state(SMF_CTX(s), &hawkbit_states[S_HAWKBIT_TERMINATE]);
1538 		return;
1539 	}
1540 
1541 #ifdef CONFIG_HAWKBIT_SAVE_PROGRESS
1542 	stream_flash_progress_clear(&s->hb_context.flash_ctx.stream, "hawkbit/flash_progress");
1543 #endif
1544 
1545 	/* Verify the hash of the stored firmware */
1546 	fic.match = s->hb_context.dl.file_hash;
1547 	fic.clen = s->hb_context.dl.downloaded_size;
1548 	if (flash_img_check(&s->hb_context.flash_ctx, &fic, flash_area_ptr->fa_id)) {
1549 		LOG_ERR("Failed to validate stored firmware");
1550 		s->hb_context.code_status = HAWKBIT_DOWNLOAD_ERROR;
1551 		smf_set_state(SMF_CTX(s), &hawkbit_states[S_HAWKBIT_TERMINATE]);
1552 		return;
1553 	}
1554 
1555 	/* Request mcuboot to upgrade */
1556 	if (boot_set_next(flash_area_ptr, false, false)) {
1557 		LOG_ERR("Failed to mark the image in slot 1 as pending");
1558 		s->hb_context.code_status = HAWKBIT_DOWNLOAD_ERROR;
1559 		smf_set_state(SMF_CTX(s), &hawkbit_states[S_HAWKBIT_TERMINATE]);
1560 		return;
1561 	}
1562 
1563 	/* If everything is successful */
1564 	s->hb_context.code_status = HAWKBIT_UPDATE_INSTALLED;
1565 	hawkbit_device_acid_update(s->hb_context.json_action_id);
1566 	hawkbit_event_raise(HAWKBIT_EVENT_UPDATE_DOWNLOADED);
1567 
1568 	smf_set_state(SMF_CTX(s), &hawkbit_states[S_HAWKBIT_TERMINATE]);
1569 }
1570 
s_terminate(void * o)1571 static void s_terminate(void *o)
1572 {
1573 	struct s_object *s = (struct s_object *)o;
1574 
1575 #ifdef CONFIG_HAWKBIT_EVENT_CALLBACKS
1576 	if (IN_RANGE(s->hb_context.code_status, HAWKBIT_NETWORKING_ERROR,
1577 		     HAWKBIT_PROBE_IN_PROGRESS)) {
1578 		hawkbit_event_raise(HAWKBIT_EVENT_ERROR);
1579 		switch (s->hb_context.code_status) {
1580 		case HAWKBIT_NETWORKING_ERROR:
1581 			hawkbit_event_raise(HAWKBIT_EVENT_ERROR_NETWORKING);
1582 			break;
1583 
1584 		case HAWKBIT_PERMISSION_ERROR:
1585 			hawkbit_event_raise(HAWKBIT_EVENT_ERROR_PERMISSION);
1586 			break;
1587 
1588 		case HAWKBIT_METADATA_ERROR:
1589 			hawkbit_event_raise(HAWKBIT_EVENT_ERROR_METADATA);
1590 			break;
1591 
1592 		case HAWKBIT_DOWNLOAD_ERROR:
1593 			hawkbit_event_raise(HAWKBIT_EVENT_ERROR_DOWNLOAD);
1594 			break;
1595 
1596 		case HAWKBIT_ALLOC_ERROR:
1597 			hawkbit_event_raise(HAWKBIT_EVENT_ERROR_ALLOC);
1598 			break;
1599 		default:
1600 			break;
1601 		}
1602 	}
1603 #endif
1604 
1605 	smf_set_terminate(SMF_CTX(s), s->hb_context.code_status);
1606 }
1607 
1608 static const struct smf_state hawkbit_states[] = {
1609 	[S_HAWKBIT_START] = SMF_CREATE_STATE(
1610 		s_start,
1611 		NULL,
1612 		s_end,
1613 		NULL,
1614 		NULL),
1615 	[S_HAWKBIT_HTTP] = SMF_CREATE_STATE(
1616 		s_http_start,
1617 		NULL,
1618 		s_http_end,
1619 		&hawkbit_states[S_HAWKBIT_START],
1620 		NULL),
1621 	[S_HAWKBIT_PROBE] = SMF_CREATE_STATE(
1622 		NULL,
1623 		s_probe,
1624 		NULL,
1625 		&hawkbit_states[S_HAWKBIT_HTTP],
1626 		NULL),
1627 	[S_HAWKBIT_CONFIG_DEVICE] = SMF_CREATE_STATE(
1628 		NULL,
1629 		s_config_device,
1630 		NULL,
1631 		&hawkbit_states[S_HAWKBIT_HTTP],
1632 		NULL),
1633 	[S_HAWKBIT_CANCEL] = SMF_CREATE_STATE(
1634 		NULL,
1635 		s_cancel,
1636 		NULL,
1637 		&hawkbit_states[S_HAWKBIT_HTTP],
1638 		NULL),
1639 	[S_HAWKBIT_PROBE_DEPLOYMENT_BASE] = SMF_CREATE_STATE(
1640 		NULL,
1641 		s_probe_deployment_base,
1642 		NULL,
1643 		&hawkbit_states[S_HAWKBIT_HTTP],
1644 		NULL),
1645 	[S_HAWKBIT_REPORT] = SMF_CREATE_STATE(
1646 		NULL,
1647 		s_report,
1648 		NULL,
1649 		&hawkbit_states[S_HAWKBIT_HTTP],
1650 		NULL),
1651 	[S_HAWKBIT_DOWNLOAD] = SMF_CREATE_STATE(
1652 		s_download_start,
1653 		s_download,
1654 		s_download_end,
1655 		&hawkbit_states[S_HAWKBIT_HTTP],
1656 		NULL),
1657 	[S_HAWKBIT_TERMINATE] = SMF_CREATE_STATE(
1658 		s_terminate,
1659 		NULL,
1660 		NULL,
1661 		NULL,
1662 		NULL),
1663 };
1664 
hawkbit_probe(void)1665 enum hawkbit_response hawkbit_probe(void)
1666 {
1667 	int32_t ret = 0;
1668 	struct s_object s_obj = {0};
1669 
1670 	smf_set_initial(SMF_CTX(&s_obj), &hawkbit_states[S_HAWKBIT_PROBE]);
1671 	hawkbit_event_raise(HAWKBIT_EVENT_START_RUN);
1672 
1673 	while (1) {
1674 		ret = smf_run_state(SMF_CTX(&s_obj));
1675 		if (ret != 0) {
1676 			hawkbit_event_raise(HAWKBIT_EVENT_END_RUN);
1677 			return (enum hawkbit_response)ret;
1678 		}
1679 	}
1680 }
1681