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