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  *
8  * SPDX-License-Identifier: Apache-2.0
9  */
10 
11 #include <zephyr/logging/log.h>
12 
13 LOG_MODULE_REGISTER(hawkbit, CONFIG_HAWKBIT_LOG_LEVEL);
14 
15 #include <stdio.h>
16 #include <zephyr/kernel.h>
17 #include <string.h>
18 #include <stdlib.h>
19 #include <zephyr/fs/nvs.h>
20 #include <zephyr/data/json.h>
21 #include <zephyr/net/net_ip.h>
22 #include <zephyr/net/socket.h>
23 #include <zephyr/net/net_mgmt.h>
24 #include <zephyr/sys/reboot.h>
25 #include <zephyr/drivers/flash.h>
26 #include <zephyr/net/http/client.h>
27 #include <zephyr/net/dns_resolve.h>
28 #include <zephyr/logging/log_ctrl.h>
29 #include <zephyr/storage/flash_map.h>
30 
31 #include "hawkbit_priv.h"
32 #include "hawkbit_device.h"
33 #include <zephyr/mgmt/hawkbit.h>
34 #include "hawkbit_firmware.h"
35 
36 #if defined(CONFIG_NET_SOCKETS_SOCKOPT_TLS)
37 #define CA_CERTIFICATE_TAG 1
38 #include <zephyr/net/tls_credentials.h>
39 #endif
40 
41 #define ADDRESS_ID 1
42 
43 #define CANCEL_BASE_SIZE 50
44 #define RECV_BUFFER_SIZE 640
45 #define URL_BUFFER_SIZE 300
46 #define SHA256_HASH_SIZE 32
47 #define STATUS_BUFFER_SIZE 200
48 #define DOWNLOAD_HTTP_SIZE 200
49 #define DEPLOYMENT_BASE_SIZE 50
50 #define RESPONSE_BUFFER_SIZE 1100
51 #define HAWKBIT_RECV_TIMEOUT (300 * MSEC_PER_SEC)
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 #define STORAGE_LABEL storage_partition
59 #define STORAGE_DEV FIXED_PARTITION_DEVICE(STORAGE_LABEL)
60 #define STORAGE_OFFSET FIXED_PARTITION_OFFSET(STORAGE_LABEL)
61 
62 #if ((CONFIG_HAWKBIT_POLL_INTERVAL > 1) && (CONFIG_HAWKBIT_POLL_INTERVAL < 43200))
63 static uint32_t poll_sleep = (CONFIG_HAWKBIT_POLL_INTERVAL * 60 * MSEC_PER_SEC);
64 #else
65 static uint32_t poll_sleep = (300 * MSEC_PER_SEC);
66 #endif
67 
68 static struct nvs_fs fs;
69 
70 struct hawkbit_download {
71 	int download_status;
72 	int download_progress;
73 	size_t downloaded_size;
74 	size_t http_content_size;
75 	uint8_t file_hash[SHA256_HASH_SIZE];
76 };
77 
78 static struct hawkbit_context {
79 	int sock;
80 	int32_t action_id;
81 	uint8_t *response_data;
82 	int32_t json_action_id;
83 	size_t url_buffer_size;
84 	size_t status_buffer_size;
85 	struct hawkbit_download dl;
86 	struct http_request http_req;
87 	struct flash_img_context flash_ctx;
88 	uint8_t url_buffer[URL_BUFFER_SIZE];
89 	uint8_t status_buffer[STATUS_BUFFER_SIZE];
90 	uint8_t recv_buf_tcp[RECV_BUFFER_SIZE];
91 	enum hawkbit_response code_status;
92 	bool final_data_received;
93 } hb_context;
94 
95 static union {
96 	struct hawkbit_dep_res dep;
97 	struct hawkbit_ctl_res base;
98 	struct hawkbit_cancel cancel;
99 } hawkbit_results;
100 
101 static struct k_work_delayable hawkbit_work_handle;
102 
103 static struct k_sem probe_sem;
104 
105 static const struct json_obj_descr json_href_descr[] = {
106 	JSON_OBJ_DESCR_PRIM(struct hawkbit_href, href, JSON_TOK_STRING),
107 };
108 
109 static const struct json_obj_descr json_status_result_descr[] = {
110 	JSON_OBJ_DESCR_PRIM(struct hawkbit_status_result, finished, JSON_TOK_STRING),
111 };
112 
113 static const struct json_obj_descr json_status_descr[] = {
114 	JSON_OBJ_DESCR_PRIM(struct hawkbit_status, execution, JSON_TOK_STRING),
115 	JSON_OBJ_DESCR_OBJECT(struct hawkbit_status, result, json_status_result_descr),
116 };
117 
118 static const struct json_obj_descr json_ctl_res_sleep_descr[] = {
119 	JSON_OBJ_DESCR_PRIM(struct hawkbit_ctl_res_sleep, sleep, JSON_TOK_STRING),
120 };
121 
122 static const struct json_obj_descr json_ctl_res_polling_descr[] = {
123 	JSON_OBJ_DESCR_OBJECT(struct hawkbit_ctl_res_polling, polling, json_ctl_res_sleep_descr),
124 };
125 
126 static const struct json_obj_descr json_ctl_res_links_descr[] = {
127 	JSON_OBJ_DESCR_OBJECT(struct hawkbit_ctl_res_links, deploymentBase, json_href_descr),
128 	JSON_OBJ_DESCR_OBJECT(struct hawkbit_ctl_res_links, cancelAction, json_href_descr),
129 	JSON_OBJ_DESCR_OBJECT(struct hawkbit_ctl_res_links, configData, json_href_descr),
130 };
131 
132 static const struct json_obj_descr json_ctl_res_descr[] = {
133 	JSON_OBJ_DESCR_OBJECT(struct hawkbit_ctl_res, config, json_ctl_res_polling_descr),
134 	JSON_OBJ_DESCR_OBJECT(struct hawkbit_ctl_res, _links, json_ctl_res_links_descr),
135 };
136 
137 static const struct json_obj_descr json_cfg_data_descr[] = {
138 	JSON_OBJ_DESCR_PRIM(struct hawkbit_cfg_data, VIN, JSON_TOK_STRING),
139 	JSON_OBJ_DESCR_PRIM(struct hawkbit_cfg_data, hwRevision, JSON_TOK_STRING),
140 };
141 
142 static const struct json_obj_descr json_cfg_descr[] = {
143 	JSON_OBJ_DESCR_PRIM(struct hawkbit_cfg, mode, JSON_TOK_STRING),
144 	JSON_OBJ_DESCR_OBJECT(struct hawkbit_cfg, data, json_cfg_data_descr),
145 	JSON_OBJ_DESCR_PRIM(struct hawkbit_cfg, id, JSON_TOK_STRING),
146 	JSON_OBJ_DESCR_PRIM(struct hawkbit_cfg, time, JSON_TOK_STRING),
147 	JSON_OBJ_DESCR_OBJECT(struct hawkbit_cfg, status, json_status_descr),
148 };
149 
150 static const struct json_obj_descr json_close_descr[] = {
151 	JSON_OBJ_DESCR_PRIM(struct hawkbit_close, id, JSON_TOK_STRING),
152 	JSON_OBJ_DESCR_PRIM(struct hawkbit_close, time, JSON_TOK_STRING),
153 	JSON_OBJ_DESCR_OBJECT(struct hawkbit_close, status, json_status_descr),
154 };
155 
156 static const struct json_obj_descr json_dep_res_hashes_descr[] = {
157 	JSON_OBJ_DESCR_PRIM(struct hawkbit_dep_res_hashes, sha1, JSON_TOK_STRING),
158 	JSON_OBJ_DESCR_PRIM(struct hawkbit_dep_res_hashes, md5, JSON_TOK_STRING),
159 	JSON_OBJ_DESCR_PRIM(struct hawkbit_dep_res_hashes, sha256, JSON_TOK_STRING),
160 };
161 
162 static const struct json_obj_descr json_dep_res_links_descr[] = {
163 	JSON_OBJ_DESCR_OBJECT_NAMED(struct hawkbit_dep_res_links, "download-http", download_http,
164 				    json_href_descr),
165 	JSON_OBJ_DESCR_OBJECT_NAMED(struct hawkbit_dep_res_links, "md5sum-http", md5sum_http,
166 				    json_href_descr),
167 };
168 
169 static const struct json_obj_descr json_dep_res_arts_descr[] = {
170 	JSON_OBJ_DESCR_PRIM(struct hawkbit_dep_res_arts, filename, JSON_TOK_STRING),
171 	JSON_OBJ_DESCR_OBJECT(struct hawkbit_dep_res_arts, hashes, json_dep_res_hashes_descr),
172 	JSON_OBJ_DESCR_PRIM(struct hawkbit_dep_res_arts, size, JSON_TOK_NUMBER),
173 	JSON_OBJ_DESCR_OBJECT(struct hawkbit_dep_res_arts, _links, json_dep_res_links_descr),
174 };
175 
176 static const struct json_obj_descr json_dep_res_chunk_descr[] = {
177 	JSON_OBJ_DESCR_PRIM(struct hawkbit_dep_res_chunk, part, JSON_TOK_STRING),
178 	JSON_OBJ_DESCR_PRIM(struct hawkbit_dep_res_chunk, version, JSON_TOK_STRING),
179 	JSON_OBJ_DESCR_PRIM(struct hawkbit_dep_res_chunk, name, JSON_TOK_STRING),
180 	JSON_OBJ_DESCR_OBJ_ARRAY(struct hawkbit_dep_res_chunk, artifacts,
181 				 HAWKBIT_DEP_MAX_CHUNK_ARTS, num_artifacts, json_dep_res_arts_descr,
182 				 ARRAY_SIZE(json_dep_res_arts_descr)),
183 };
184 
185 static const struct json_obj_descr json_dep_res_deploy_descr[] = {
186 	JSON_OBJ_DESCR_PRIM(struct hawkbit_dep_res_deploy, download, JSON_TOK_STRING),
187 	JSON_OBJ_DESCR_PRIM(struct hawkbit_dep_res_deploy, update, JSON_TOK_STRING),
188 	JSON_OBJ_DESCR_OBJ_ARRAY(struct hawkbit_dep_res_deploy, chunks, HAWKBIT_DEP_MAX_CHUNKS,
189 				 num_chunks, json_dep_res_chunk_descr,
190 				 ARRAY_SIZE(json_dep_res_chunk_descr)),
191 };
192 
193 static const struct json_obj_descr json_dep_res_descr[] = {
194 	JSON_OBJ_DESCR_PRIM(struct hawkbit_dep_res, id, JSON_TOK_STRING),
195 	JSON_OBJ_DESCR_OBJECT(struct hawkbit_dep_res, deployment, json_dep_res_deploy_descr),
196 };
197 
198 static const struct json_obj_descr json_dep_fbk_descr[] = {
199 	JSON_OBJ_DESCR_PRIM(struct hawkbit_dep_fbk, id, JSON_TOK_STRING),
200 	JSON_OBJ_DESCR_OBJECT(struct hawkbit_dep_fbk, status, json_status_descr),
201 };
202 
start_http_client(void)203 static bool start_http_client(void)
204 {
205 	int ret = -1;
206 	struct addrinfo *addr;
207 	struct addrinfo hints;
208 	int resolve_attempts = 10;
209 
210 #if defined(CONFIG_NET_SOCKETS_SOCKOPT_TLS)
211 	int protocol = IPPROTO_TLS_1_2;
212 #else
213 	int protocol = IPPROTO_TCP;
214 #endif
215 
216 	(void)memset(&hints, 0, sizeof(hints));
217 
218 	if (IS_ENABLED(CONFIG_NET_IPV6)) {
219 		hints.ai_family = AF_INET6;
220 		hints.ai_socktype = SOCK_STREAM;
221 	} else if (IS_ENABLED(CONFIG_NET_IPV4)) {
222 		hints.ai_family = AF_INET;
223 		hints.ai_socktype = SOCK_STREAM;
224 	}
225 
226 	while (resolve_attempts--) {
227 		ret = getaddrinfo(CONFIG_HAWKBIT_SERVER, CONFIG_HAWKBIT_PORT, &hints, &addr);
228 		if (ret == 0) {
229 			break;
230 		}
231 
232 		k_sleep(K_MSEC(1));
233 	}
234 
235 	if (ret != 0) {
236 		LOG_ERR("Could not resolve dns: %d", ret);
237 		return false;
238 	}
239 
240 	hb_context.sock = socket(addr->ai_family, SOCK_STREAM, protocol);
241 	if (hb_context.sock < 0) {
242 		LOG_ERR("Failed to create TCP socket");
243 		goto err;
244 	}
245 
246 #if defined(CONFIG_NET_SOCKETS_SOCKOPT_TLS)
247 	sec_tag_t sec_tag_opt[] = {
248 		CA_CERTIFICATE_TAG,
249 	};
250 
251 	if (setsockopt(hb_context.sock, SOL_TLS, TLS_SEC_TAG_LIST, sec_tag_opt,
252 		       sizeof(sec_tag_opt)) < 0) {
253 		LOG_ERR("Failed to set TLS_TAG option");
254 		goto err_sock;
255 	}
256 
257 	if (setsockopt(hb_context.sock, SOL_TLS, TLS_HOSTNAME, CONFIG_HAWKBIT_SERVER,
258 		       sizeof(CONFIG_HAWKBIT_SERVER)) < 0) {
259 		goto err_sock;
260 	}
261 #endif
262 
263 	if (connect(hb_context.sock, addr->ai_addr, addr->ai_addrlen) < 0) {
264 		LOG_ERR("Failed to connect to server");
265 		goto err_sock;
266 	}
267 
268 	freeaddrinfo(addr);
269 	return true;
270 
271 err_sock:
272 	close(hb_context.sock);
273 err:
274 	freeaddrinfo(addr);
275 	return false;
276 }
277 
cleanup_connection(void)278 static void cleanup_connection(void)
279 {
280 	if (close(hb_context.sock) < 0) {
281 		LOG_ERR("Could not close the socket");
282 	}
283 }
284 
hawkbit_time2sec(const char * s)285 static int hawkbit_time2sec(const char *s)
286 {
287 	int sec;
288 
289 	/* Time: HH:MM:SS */
290 	sec = strtol(s, NULL, 10) * (60 * 60);
291 	sec += strtol(s + 3, NULL, 10) * 60;
292 	sec += strtol(s + 6, NULL, 10);
293 
294 	if (sec < 0) {
295 		return -1;
296 	} else {
297 		return sec;
298 	}
299 }
300 
hawkbit_status_finished(enum hawkbit_status_fini f)301 static const char *hawkbit_status_finished(enum hawkbit_status_fini f)
302 {
303 	switch (f) {
304 	case HAWKBIT_STATUS_FINISHED_SUCCESS:
305 		return "success";
306 	case HAWKBIT_STATUS_FINISHED_FAILURE:
307 		return "failure";
308 	case HAWKBIT_STATUS_FINISHED_NONE:
309 		return "none";
310 	default:
311 		LOG_ERR("%d is invalid", (int)f);
312 		return NULL;
313 	}
314 }
315 
hawkbit_status_execution(enum hawkbit_status_exec e)316 static const char *hawkbit_status_execution(enum hawkbit_status_exec e)
317 {
318 	switch (e) {
319 	case HAWKBIT_STATUS_EXEC_CLOSED:
320 		return "closed";
321 	case HAWKBIT_STATUS_EXEC_PROCEEDING:
322 		return "proceeding";
323 	case HAWKBIT_STATUS_EXEC_CANCELED:
324 		return "canceled";
325 	case HAWKBIT_STATUS_EXEC_SCHEDULED:
326 		return "scheduled";
327 	case HAWKBIT_STATUS_EXEC_REJECTED:
328 		return "rejected";
329 	case HAWKBIT_STATUS_EXEC_RESUMED:
330 		return "resumed";
331 	case HAWKBIT_STATUS_EXEC_NONE:
332 		return "none";
333 	default:
334 		LOG_ERR("%d is invalid", (int)e);
335 		return NULL;
336 	}
337 }
338 
hawkbit_device_acid_update(int32_t new_value)339 static int hawkbit_device_acid_update(int32_t new_value)
340 {
341 	int ret;
342 
343 	ret = nvs_write(&fs, ADDRESS_ID, &new_value, sizeof(new_value));
344 	if (ret < 0) {
345 		LOG_ERR("Failed to write device id: %d", ret);
346 		return -EIO;
347 	}
348 
349 	return 0;
350 }
351 
352 /*
353  * Update sleep interval, based on results from hawkbit base polling
354  * resource
355  */
hawkbit_update_sleep(struct hawkbit_ctl_res * hawkbit_res)356 static void hawkbit_update_sleep(struct hawkbit_ctl_res *hawkbit_res)
357 {
358 	uint32_t sleep_time;
359 	const char *sleep = hawkbit_res->config.polling.sleep;
360 
361 	if (strlen(sleep) != HAWKBIT_SLEEP_LENGTH) {
362 		LOG_ERR("Invalid poll sleep: %s", sleep);
363 	} else {
364 		sleep_time = hawkbit_time2sec(sleep);
365 		if (sleep_time > 0 && poll_sleep != (MSEC_PER_SEC * sleep_time)) {
366 			LOG_DBG("New poll sleep %d seconds", sleep_time);
367 			poll_sleep = sleep_time * MSEC_PER_SEC;
368 		}
369 	}
370 }
371 
372 /*
373  * Find URL component for the device cancel operation and action id
374  */
hawkbit_find_cancelAction_base(struct hawkbit_ctl_res * res,char * cancel_base)375 static int hawkbit_find_cancelAction_base(struct hawkbit_ctl_res *res, char *cancel_base)
376 {
377 	size_t len;
378 	const char *href;
379 	char *helper, *endptr;
380 
381 	href = res->_links.cancelAction.href;
382 	if (!href) {
383 		*cancel_base = '\0';
384 		return 0;
385 	}
386 
387 	LOG_DBG("_links.%s.href=%s", "cancelAction", href);
388 
389 	helper = strstr(href, "cancelAction/");
390 	if (!helper) {
391 		/* A badly formatted cancel base is a server error */
392 		LOG_ERR("Missing cancelBase/ in href %s", href);
393 		return -EINVAL;
394 	}
395 
396 	len = strlen(helper);
397 	if (len > CANCEL_BASE_SIZE - 1) {
398 		/* Lack of memory is an application error */
399 		LOG_ERR("cancelBase %s is too big (len %zu, max %zu)", helper, len,
400 			CANCEL_BASE_SIZE - 1);
401 		return -ENOMEM;
402 	}
403 
404 	strncpy(cancel_base, helper, CANCEL_BASE_SIZE);
405 
406 	helper = strtok(helper, "/");
407 	if (helper == 0) {
408 		return -EINVAL;
409 	}
410 
411 	helper = strtok(NULL, "/");
412 	if (helper == 0) {
413 		return -EINVAL;
414 	}
415 
416 	hb_context.action_id = strtol(helper, &endptr, 10);
417 	if (hb_context.action_id <= 0) {
418 		LOG_ERR("Invalid action ID: %d", hb_context.action_id);
419 		return -EINVAL;
420 	}
421 
422 	return 0;
423 }
424 
425 /*
426  * Find URL component for the device's deployment operations
427  * resource
428  */
hawkbit_find_deployment_base(struct hawkbit_ctl_res * res,char * deployment_base)429 static int hawkbit_find_deployment_base(struct hawkbit_ctl_res *res, char *deployment_base)
430 {
431 	const char *href;
432 	const char *helper;
433 	size_t len;
434 
435 	href = res->_links.deploymentBase.href;
436 	if (!href) {
437 		*deployment_base = '\0';
438 		return 0;
439 	}
440 
441 	LOG_DBG("_links.%s.href=%s", "deploymentBase", href);
442 
443 	helper = strstr(href, "deploymentBase/");
444 	if (!helper) {
445 		/* A badly formatted deployment base is a server error */
446 		LOG_ERR("Missing deploymentBase/ in href %s", href);
447 		return -EINVAL;
448 	}
449 
450 	len = strlen(helper);
451 	if (len > DEPLOYMENT_BASE_SIZE - 1) {
452 		/* Lack of memory is an application error */
453 		LOG_ERR("deploymentBase %s is too big (len %zu, max %zu)", helper, len,
454 			DEPLOYMENT_BASE_SIZE - 1);
455 		return -ENOMEM;
456 	}
457 
458 	strncpy(deployment_base, helper, DEPLOYMENT_BASE_SIZE);
459 	return 0;
460 }
461 
462 /*
463  * Find URL component for this device's deployment operations
464  * resource.
465  */
hawkbit_parse_deployment(struct hawkbit_dep_res * res,int32_t * json_action_id,char * download_http,int32_t * file_size)466 static int hawkbit_parse_deployment(struct hawkbit_dep_res *res, int32_t *json_action_id,
467 				    char *download_http, int32_t *file_size)
468 {
469 	int32_t size;
470 	char *endptr;
471 	const char *href;
472 	const char *helper;
473 	struct hawkbit_dep_res_chunk *chunk;
474 	size_t len, num_chunks, num_artifacts;
475 	struct hawkbit_dep_res_arts *artifact;
476 
477 	hb_context.action_id = strtol(res->id, &endptr, 10);
478 	if (hb_context.action_id < 0) {
479 		LOG_ERR("Negative action ID: %d", hb_context.action_id);
480 		return -EINVAL;
481 	}
482 
483 	*json_action_id = hb_context.action_id;
484 
485 	num_chunks = res->deployment.num_chunks;
486 	if (num_chunks != 1) {
487 		LOG_ERR("Expecting one chunk (got %d)", num_chunks);
488 		return -ENOSPC;
489 	}
490 
491 	chunk = &res->deployment.chunks[0];
492 	if (strcmp("bApp", chunk->part)) {
493 		LOG_ERR("Only part 'bApp' is supported; got %s", chunk->part);
494 		return -EINVAL;
495 	}
496 
497 	num_artifacts = chunk->num_artifacts;
498 	if (num_artifacts != 1) {
499 		LOG_ERR("Expecting one artifact (got %d)", num_artifacts);
500 		return -EINVAL;
501 	}
502 
503 	artifact = &chunk->artifacts[0];
504 	if (hex2bin(artifact->hashes.sha256, SHA256_HASH_SIZE << 1, hb_context.dl.file_hash,
505 		    sizeof(hb_context.dl.file_hash)) != SHA256_HASH_SIZE) {
506 		return -EINVAL;
507 	}
508 
509 	size = artifact->size;
510 
511 	if (size > SLOT1_SIZE) {
512 		LOG_ERR("Artifact file size too big (got %d, max is %d)", size, SLOT1_SIZE);
513 		return -ENOSPC;
514 	}
515 
516 	/*
517 	 * Find the download-http href. We only support the DEFAULT
518 	 * tenant on the same hawkbit server.
519 	 */
520 	href = artifact->_links.download_http.href;
521 	if (!href) {
522 		LOG_ERR("Missing expected download-http href");
523 		return -EINVAL;
524 	}
525 
526 	helper = strstr(href, "/DEFAULT/controller/v1");
527 	if (!helper) {
528 		LOG_ERR("Unexpected download-http href format: %s", helper);
529 		return -EINVAL;
530 	}
531 
532 	len = strlen(helper);
533 	if (len == 0) {
534 		LOG_ERR("Empty download-http");
535 		return -EINVAL;
536 	} else if (len > DOWNLOAD_HTTP_SIZE - 1) {
537 		LOG_ERR("download-http %s is too big (len: %zu, max: %zu)", helper, len,
538 			DOWNLOAD_HTTP_SIZE - 1);
539 		return -ENOMEM;
540 	}
541 
542 	/* Success. */
543 	strncpy(download_http, helper, DOWNLOAD_HTTP_SIZE);
544 	*file_size = size;
545 	return 0;
546 }
547 
hawkbit_dump_deployment(struct hawkbit_dep_res * d)548 static void hawkbit_dump_deployment(struct hawkbit_dep_res *d)
549 {
550 	struct hawkbit_dep_res_chunk *c = &d->deployment.chunks[0];
551 	struct hawkbit_dep_res_arts *a = &c->artifacts[0];
552 	struct hawkbit_dep_res_links *l = &a->_links;
553 
554 	LOG_DBG("id=%s", d->id);
555 	LOG_DBG("download=%s", d->deployment.download);
556 	LOG_DBG("update=%s", d->deployment.update);
557 	LOG_DBG("chunks[0].part=%s", c->part);
558 	LOG_DBG("chunks[0].name=%s", c->name);
559 	LOG_DBG("chunks[0].version=%s", c->version);
560 	LOG_DBG("chunks[0].artifacts[0].filename=%s", a->filename);
561 	LOG_DBG("chunks[0].artifacts[0].hashes.sha1=%s", a->hashes.sha1);
562 	LOG_DBG("chunks[0].artifacts[0].hashes.md5=%s", a->hashes.md5);
563 	LOG_DBG("chunks[0].artifacts[0].hashes.sha256=%s", a->hashes.sha256);
564 	LOG_DBG("chunks[0].size=%d", a->size);
565 	LOG_DBG("download-http=%s", l->download_http.href);
566 	LOG_DBG("md5sum =%s", l->md5sum_http.href);
567 }
568 
hawkbit_init(void)569 int hawkbit_init(void)
570 {
571 	bool image_ok;
572 	int ret = 0, rc = 0;
573 	struct flash_pages_info info;
574 	int32_t action_id;
575 
576 	fs.flash_device = STORAGE_DEV;
577 	if (!device_is_ready(fs.flash_device)) {
578 		LOG_ERR("Flash device not ready");
579 		return -ENODEV;
580 	}
581 
582 	fs.offset = STORAGE_OFFSET;
583 	rc = flash_get_page_info_by_offs(fs.flash_device, fs.offset, &info);
584 	if (rc) {
585 		LOG_ERR("Unable to get storage page info: %d", rc);
586 		return -EIO;
587 	}
588 
589 	fs.sector_size = info.size;
590 	fs.sector_count = 3U;
591 
592 	rc = nvs_mount(&fs);
593 	if (rc) {
594 		LOG_ERR("Storage flash mount failed: %d", rc);
595 		return rc;
596 	}
597 
598 	rc = nvs_read(&fs, ADDRESS_ID, &action_id, sizeof(action_id));
599 	LOG_DBG("Action id: current %d", action_id);
600 
601 	image_ok = boot_is_img_confirmed();
602 	LOG_INF("Image is%s confirmed OK", image_ok ? "" : " not");
603 	if (!image_ok) {
604 		ret = boot_write_img_confirmed();
605 		if (ret < 0) {
606 			LOG_ERR("Couldn't confirm this image: %d", ret);
607 			return ret;
608 		}
609 
610 		LOG_DBG("Marked image as OK");
611 		ret = boot_erase_img_bank(FIXED_PARTITION_ID(SLOT1_LABEL));
612 		if (ret) {
613 			LOG_ERR("Failed to erase second slot: %d", ret);
614 			return ret;
615 		}
616 	}
617 
618 	k_sem_init(&probe_sem, 1, 1);
619 
620 	return ret;
621 }
622 
enum_for_http_req_string(char * userdata)623 static int enum_for_http_req_string(char *userdata)
624 {
625 	int i = 0;
626 	char *name = http_request[i].http_req_str;
627 
628 	while (name) {
629 		if (strcmp(name, userdata) == 0) {
630 			return http_request[i].n;
631 		}
632 
633 		name = http_request[++i].http_req_str;
634 	}
635 
636 	return 0;
637 }
638 
response_cb(struct http_response * rsp,enum http_final_call final_data,void * userdata)639 static void response_cb(struct http_response *rsp, enum http_final_call final_data, void *userdata)
640 {
641 	static size_t body_len;
642 	int ret, type, downloaded;
643 	uint8_t *body_data = NULL, *rsp_tmp = NULL;
644 	static size_t response_buffer_size = RESPONSE_BUFFER_SIZE;
645 
646 	type = enum_for_http_req_string(userdata);
647 
648 	switch (type) {
649 	case HAWKBIT_PROBE:
650 		if (hb_context.dl.http_content_size == 0) {
651 			hb_context.dl.http_content_size = rsp->content_length;
652 		}
653 
654 		if (rsp->body_found) {
655 			body_data = rsp->body_frag_start;
656 			body_len = rsp->body_frag_len;
657 
658 			if ((hb_context.dl.downloaded_size + body_len) > response_buffer_size) {
659 				response_buffer_size <<= 1;
660 				rsp_tmp = realloc(hb_context.response_data, response_buffer_size);
661 				if (rsp_tmp == NULL) {
662 					LOG_ERR("Failed to realloc memory");
663 					hb_context.code_status = HAWKBIT_METADATA_ERROR;
664 					break;
665 				}
666 
667 				hb_context.response_data = rsp_tmp;
668 			}
669 			strncpy(hb_context.response_data + hb_context.dl.downloaded_size, body_data,
670 				body_len);
671 			hb_context.dl.downloaded_size += body_len;
672 		}
673 
674 		if (final_data == HTTP_DATA_FINAL) {
675 			if (hb_context.dl.http_content_size != hb_context.dl.downloaded_size) {
676 				LOG_ERR("HTTP response len mismatch, expected %d, got %d",
677 					hb_context.dl.http_content_size,
678 					hb_context.dl.downloaded_size);
679 				hb_context.code_status = HAWKBIT_METADATA_ERROR;
680 				break;
681 			}
682 
683 			hb_context.response_data[hb_context.dl.downloaded_size] = '\0';
684 			ret = json_obj_parse(hb_context.response_data,
685 					     hb_context.dl.downloaded_size, json_ctl_res_descr,
686 					     ARRAY_SIZE(json_ctl_res_descr), &hawkbit_results.base);
687 			if (ret < 0) {
688 				LOG_ERR("JSON parse error (HAWKBIT_PROBE): %d", ret);
689 				hb_context.code_status = HAWKBIT_METADATA_ERROR;
690 			}
691 		}
692 
693 		break;
694 
695 	case HAWKBIT_CLOSE:
696 	case HAWKBIT_REPORT:
697 	case HAWKBIT_CONFIG_DEVICE:
698 		if (strcmp(rsp->http_status, "OK") < 0) {
699 			LOG_ERR("Failed to cancel the update");
700 		}
701 
702 		break;
703 
704 	case HAWKBIT_PROBE_DEPLOYMENT_BASE:
705 		if (hb_context.dl.http_content_size == 0) {
706 			hb_context.dl.http_content_size = rsp->content_length;
707 		}
708 
709 		if (rsp->body_found) {
710 			body_data = rsp->body_frag_start;
711 			body_len = rsp->body_frag_len;
712 
713 			if ((hb_context.dl.downloaded_size + body_len) > response_buffer_size) {
714 				response_buffer_size <<= 1;
715 				rsp_tmp = realloc(hb_context.response_data, response_buffer_size);
716 				if (rsp_tmp == NULL) {
717 					LOG_ERR("Failed to realloc memory");
718 					hb_context.code_status = HAWKBIT_METADATA_ERROR;
719 					break;
720 				}
721 
722 				hb_context.response_data = rsp_tmp;
723 			}
724 			strncpy(hb_context.response_data + hb_context.dl.downloaded_size, body_data,
725 				body_len);
726 			hb_context.dl.downloaded_size += body_len;
727 		}
728 
729 		if (final_data == HTTP_DATA_FINAL) {
730 			if (hb_context.dl.http_content_size != hb_context.dl.downloaded_size) {
731 				LOG_ERR("HTTP response len mismatch");
732 				hb_context.code_status = HAWKBIT_METADATA_ERROR;
733 				break;
734 			}
735 
736 			hb_context.response_data[hb_context.dl.downloaded_size] = '\0';
737 			ret = json_obj_parse(hb_context.response_data,
738 					     hb_context.dl.downloaded_size, json_dep_res_descr,
739 					     ARRAY_SIZE(json_dep_res_descr), &hawkbit_results.dep);
740 			if (ret < 0) {
741 				LOG_ERR("DeploymentBase JSON parse error: %d", ret);
742 				hb_context.code_status = HAWKBIT_METADATA_ERROR;
743 			}
744 		}
745 
746 		break;
747 
748 	case HAWKBIT_DOWNLOAD:
749 		if (hb_context.dl.http_content_size == 0) {
750 			hb_context.dl.http_content_size = rsp->content_length;
751 		}
752 
753 		if (rsp->body_found) {
754 			body_data = rsp->body_frag_start;
755 			body_len = rsp->body_frag_len;
756 
757 			ret = flash_img_buffered_write(&hb_context.flash_ctx, body_data, body_len,
758 						       final_data == HTTP_DATA_FINAL);
759 			if (ret < 0) {
760 				LOG_ERR("Flash write error: %d", ret);
761 				hb_context.code_status = HAWKBIT_DOWNLOAD_ERROR;
762 				break;
763 			}
764 		}
765 
766 		hb_context.dl.downloaded_size = flash_img_bytes_written(&hb_context.flash_ctx);
767 
768 		downloaded = hb_context.dl.downloaded_size * 100 / hb_context.dl.http_content_size;
769 
770 		if (downloaded > hb_context.dl.download_progress) {
771 			hb_context.dl.download_progress = downloaded;
772 			LOG_DBG("Download percentage: %d%% ", hb_context.dl.download_progress);
773 		}
774 
775 		if (final_data == HTTP_DATA_FINAL) {
776 			hb_context.final_data_received = true;
777 		}
778 
779 		break;
780 	}
781 }
782 
send_request(enum http_method method,enum hawkbit_http_request type,enum hawkbit_status_fini finished,enum hawkbit_status_exec execution)783 static bool send_request(enum http_method method, enum hawkbit_http_request type,
784 			 enum hawkbit_status_fini finished, enum hawkbit_status_exec execution)
785 {
786 	int ret = 0;
787 
788 	struct hawkbit_cfg cfg;
789 	struct hawkbit_close close;
790 	struct hawkbit_dep_fbk feedback;
791 	char acid[11];
792 	const char *fini = hawkbit_status_finished(finished);
793 	const char *exec = hawkbit_status_execution(execution);
794 	char device_id[DEVICE_ID_HEX_MAX_SIZE] = { 0 };
795 #ifndef CONFIG_HAWKBIT_DDI_NO_SECURITY
796 	static const char *const headers[] = {
797 #ifdef CONFIG_HAWKBIT_DDI_GATEWAY_SECURITY
798 		"Authorization: GatewayToken " CONFIG_HAWKBIT_DDI_SECURITY_TOKEN "\r\n",
799 #else
800 		"Authorization: TargetToken " CONFIG_HAWKBIT_DDI_SECURITY_TOKEN "\r\n",
801 #endif /* CONFIG_HAWKBIT_DDI_GATEWAY_SECURITY */
802 		NULL
803 	};
804 #endif /* CONFIG_HAWKBIT_DDI_NO_SECURITY */
805 
806 	if (!hawkbit_get_device_identity(device_id, DEVICE_ID_HEX_MAX_SIZE)) {
807 		hb_context.code_status = HAWKBIT_METADATA_ERROR;
808 	}
809 
810 	memset(&hb_context.http_req, 0, sizeof(hb_context.http_req));
811 	memset(&hb_context.recv_buf_tcp, 0, sizeof(hb_context.recv_buf_tcp));
812 	hb_context.http_req.url = hb_context.url_buffer;
813 	hb_context.http_req.method = method;
814 	hb_context.http_req.host = CONFIG_HAWKBIT_SERVER;
815 	hb_context.http_req.port = CONFIG_HAWKBIT_PORT;
816 	hb_context.http_req.protocol = "HTTP/1.1";
817 	hb_context.http_req.response = response_cb;
818 	hb_context.http_req.recv_buf = hb_context.recv_buf_tcp;
819 	hb_context.http_req.recv_buf_len = sizeof(hb_context.recv_buf_tcp);
820 #ifndef CONFIG_HAWKBIT_DDI_NO_SECURITY
821 	hb_context.http_req.header_fields = (const char **)headers;
822 #endif
823 	hb_context.final_data_received = false;
824 
825 	switch (type) {
826 	case HAWKBIT_PROBE:
827 		ret = http_client_req(hb_context.sock, &hb_context.http_req, HAWKBIT_RECV_TIMEOUT,
828 				      "HAWKBIT_PROBE");
829 		if (ret < 0) {
830 			LOG_ERR("Unable to send HTTP request (HAWKBIT_PROBE): %d", ret);
831 			return false;
832 		}
833 
834 		break;
835 
836 	case HAWKBIT_CONFIG_DEVICE:
837 		memset(&cfg, 0, sizeof(cfg));
838 		cfg.mode = "merge";
839 		cfg.data.VIN = device_id;
840 		cfg.data.hwRevision = "3";
841 		cfg.id = "";
842 		cfg.time = "";
843 		cfg.status.execution = exec;
844 		cfg.status.result.finished = fini;
845 
846 		ret = json_obj_encode_buf(json_cfg_descr, ARRAY_SIZE(json_cfg_descr), &cfg,
847 					  hb_context.status_buffer,
848 					  hb_context.status_buffer_size - 1);
849 		if (ret) {
850 			LOG_ERR("Can't encode the JSON script (HAWKBIT_CONFIG_DEVICE): %d", ret);
851 			return false;
852 		}
853 
854 		hb_context.http_req.content_type_value = HTTP_HEADER_CONTENT_TYPE_JSON;
855 		hb_context.http_req.payload = hb_context.status_buffer;
856 		hb_context.http_req.payload_len = strlen(hb_context.status_buffer);
857 
858 		ret = http_client_req(hb_context.sock, &hb_context.http_req, HAWKBIT_RECV_TIMEOUT,
859 				      "HAWKBIT_CONFIG_DEVICE");
860 		if (ret < 0) {
861 			LOG_ERR("Unable to send HTTP request (HAWKBIT_CONFIG_DEVICE): %d", ret);
862 			return false;
863 		}
864 
865 		break;
866 
867 	case HAWKBIT_CLOSE:
868 		memset(&close, 0, sizeof(close));
869 		memset(&hb_context.status_buffer, 0, sizeof(hb_context.status_buffer));
870 		snprintk(acid, sizeof(acid), "%d", hb_context.action_id);
871 		close.id = acid;
872 		close.time = "";
873 		close.status.execution = exec;
874 		close.status.result.finished = fini;
875 
876 		ret = json_obj_encode_buf(json_close_descr, ARRAY_SIZE(json_close_descr), &close,
877 					  hb_context.status_buffer,
878 					  hb_context.status_buffer_size - 1);
879 		if (ret) {
880 			LOG_ERR("Can't encode the JSON script (HAWKBIT_CLOSE): %d", ret);
881 			return false;
882 		}
883 
884 		hb_context.http_req.content_type_value = HTTP_HEADER_CONTENT_TYPE_JSON;
885 		hb_context.http_req.payload = hb_context.status_buffer;
886 		hb_context.http_req.payload_len = strlen(hb_context.status_buffer);
887 
888 		ret = http_client_req(hb_context.sock, &hb_context.http_req, HAWKBIT_RECV_TIMEOUT,
889 				      "HAWKBIT_CLOSE");
890 		if (ret < 0) {
891 			LOG_ERR("Unable to send HTTP request (HAWKBIT_CLOSE): %d", ret);
892 			return false;
893 		}
894 
895 		break;
896 
897 	case HAWKBIT_PROBE_DEPLOYMENT_BASE:
898 		hb_context.http_req.content_type_value = NULL;
899 		ret = http_client_req(hb_context.sock, &hb_context.http_req, HAWKBIT_RECV_TIMEOUT,
900 				      "HAWKBIT_PROBE_DEPLOYMENT_BASE");
901 		if (ret < 0) {
902 			LOG_ERR("Unable to send HTTP request (HAWKBIT_PROBE_DEPLOYMENT_BASE): %d",
903 				ret);
904 			return false;
905 		}
906 
907 		break;
908 
909 	case HAWKBIT_REPORT:
910 		if (!fini || !exec) {
911 			return -EINVAL;
912 		}
913 
914 		LOG_INF("Reporting deployment feedback %s (%s) for action %d", fini, exec,
915 			hb_context.json_action_id);
916 		/* Build JSON */
917 		memset(&feedback, 0, sizeof(feedback));
918 		snprintk(acid, sizeof(acid), "%d", hb_context.json_action_id);
919 		feedback.id = acid;
920 		feedback.status.result.finished = fini;
921 		feedback.status.execution = exec;
922 
923 		ret = json_obj_encode_buf(json_dep_fbk_descr, ARRAY_SIZE(json_dep_fbk_descr),
924 					  &feedback, hb_context.status_buffer,
925 					  hb_context.status_buffer_size - 1);
926 		if (ret) {
927 			LOG_ERR("Can't encode the JSON script (HAWKBIT_REPORT): %d", ret);
928 			return ret;
929 		}
930 
931 		hb_context.http_req.content_type_value = HTTP_HEADER_CONTENT_TYPE_JSON;
932 		hb_context.http_req.payload = hb_context.status_buffer;
933 		hb_context.http_req.payload_len = strlen(hb_context.status_buffer);
934 
935 		ret = http_client_req(hb_context.sock, &hb_context.http_req, HAWKBIT_RECV_TIMEOUT,
936 				      "HAWKBIT_REPORT");
937 		if (ret < 0) {
938 			LOG_ERR("Unable to send HTTP request (HAWKBIT_REPORT): %d", ret);
939 			return false;
940 		}
941 
942 		break;
943 
944 	case HAWKBIT_DOWNLOAD:
945 		ret = http_client_req(hb_context.sock, &hb_context.http_req, HAWKBIT_RECV_TIMEOUT,
946 				      "HAWKBIT_DOWNLOAD");
947 		if (ret < 0) {
948 			LOG_ERR("Unable to send HTTP request (HAWKBIT_DOWNLOAD): %d", ret);
949 			return false;
950 		}
951 
952 		break;
953 	}
954 
955 	return true;
956 }
957 
hawkbit_probe(void)958 enum hawkbit_response hawkbit_probe(void)
959 {
960 	int ret;
961 	int32_t action_id;
962 	int32_t file_size = 0;
963 	struct flash_img_check fic;
964 	char device_id[DEVICE_ID_HEX_MAX_SIZE] = { 0 },
965 	     cancel_base[CANCEL_BASE_SIZE] = { 0 },
966 	     download_http[DOWNLOAD_HTTP_SIZE] = { 0 },
967 	     deployment_base[DEPLOYMENT_BASE_SIZE] = { 0 },
968 	     firmware_version[BOOT_IMG_VER_STRLEN_MAX] = { 0 };
969 
970 	if (k_sem_take(&probe_sem, K_NO_WAIT) != 0) {
971 		return HAWKBIT_PROBE_IN_PROGRESS;
972 	}
973 
974 	memset(&hb_context, 0, sizeof(hb_context));
975 	hb_context.response_data = malloc(RESPONSE_BUFFER_SIZE);
976 
977 	if (!boot_is_img_confirmed()) {
978 		LOG_ERR("The current image is not confirmed");
979 		hb_context.code_status = HAWKBIT_UNCONFIRMED_IMAGE;
980 		goto error;
981 	}
982 
983 	if (!hawkbit_get_firmware_version(firmware_version, BOOT_IMG_VER_STRLEN_MAX)) {
984 		hb_context.code_status = HAWKBIT_METADATA_ERROR;
985 		goto error;
986 	}
987 
988 	if (!hawkbit_get_device_identity(device_id, DEVICE_ID_HEX_MAX_SIZE)) {
989 		hb_context.code_status = HAWKBIT_METADATA_ERROR;
990 		goto error;
991 	}
992 
993 	if (!start_http_client()) {
994 		hb_context.code_status = HAWKBIT_NETWORKING_ERROR;
995 		goto error;
996 	}
997 
998 	/*
999 	 * Query the hawkbit base polling resource.
1000 	 */
1001 	LOG_INF("Polling target data from Hawkbit");
1002 
1003 	memset(hb_context.url_buffer, 0, sizeof(hb_context.url_buffer));
1004 	hb_context.dl.http_content_size = 0;
1005 	hb_context.dl.downloaded_size = 0;
1006 	hb_context.url_buffer_size = URL_BUFFER_SIZE;
1007 	snprintk(hb_context.url_buffer, hb_context.url_buffer_size, "%s/%s-%s",
1008 		 HAWKBIT_JSON_URL, CONFIG_BOARD, device_id);
1009 	memset(&hawkbit_results.base, 0, sizeof(hawkbit_results.base));
1010 
1011 	if (!send_request(HTTP_GET, HAWKBIT_PROBE, HAWKBIT_STATUS_FINISHED_NONE,
1012 			  HAWKBIT_STATUS_EXEC_NONE)) {
1013 		LOG_ERR("Send request failed (HAWKBIT_PROBE)");
1014 		hb_context.code_status = HAWKBIT_NETWORKING_ERROR;
1015 		goto cleanup;
1016 	}
1017 
1018 	if (hb_context.code_status == HAWKBIT_METADATA_ERROR) {
1019 		goto cleanup;
1020 	}
1021 
1022 	if (hawkbit_results.base.config.polling.sleep) {
1023 		/* Update the sleep time. */
1024 		hawkbit_update_sleep(&hawkbit_results.base);
1025 		LOG_DBG("config.polling.sleep=%s", hawkbit_results.base.config.polling.sleep);
1026 	}
1027 
1028 
1029 	if (hawkbit_results.base._links.cancelAction.href) {
1030 		ret = hawkbit_find_cancelAction_base(&hawkbit_results.base, cancel_base);
1031 		memset(hb_context.url_buffer, 0, sizeof(hb_context.url_buffer));
1032 		hb_context.dl.http_content_size = 0;
1033 		hb_context.url_buffer_size = URL_BUFFER_SIZE;
1034 		snprintk(hb_context.url_buffer, hb_context.url_buffer_size, "%s/%s-%s/%s/feedback",
1035 			 HAWKBIT_JSON_URL, CONFIG_BOARD, device_id, cancel_base);
1036 		memset(&hawkbit_results.cancel, 0, sizeof(hawkbit_results.cancel));
1037 
1038 		if (!send_request(HTTP_POST, HAWKBIT_CLOSE, HAWKBIT_STATUS_FINISHED_SUCCESS,
1039 				  HAWKBIT_STATUS_EXEC_CLOSED)) {
1040 			LOG_ERR("Send request failed (HAWKBIT_CLOSE)");
1041 			hb_context.code_status = HAWKBIT_NETWORKING_ERROR;
1042 			goto cleanup;
1043 		}
1044 
1045 		hb_context.code_status = HAWKBIT_CANCEL_UPDATE;
1046 		goto cleanup;
1047 	}
1048 
1049 	if (hawkbit_results.base._links.configData.href) {
1050 		LOG_DBG("_links.%s.href=%s", "configData",
1051 			hawkbit_results.base._links.configData.href);
1052 		memset(hb_context.url_buffer, 0, sizeof(hb_context.url_buffer));
1053 		hb_context.dl.http_content_size = 0;
1054 		hb_context.url_buffer_size = URL_BUFFER_SIZE;
1055 		snprintk(hb_context.url_buffer, hb_context.url_buffer_size, "%s/%s-%s/configData",
1056 			 HAWKBIT_JSON_URL, CONFIG_BOARD, device_id);
1057 
1058 		if (!send_request(HTTP_PUT, HAWKBIT_CONFIG_DEVICE, HAWKBIT_STATUS_FINISHED_SUCCESS,
1059 				  HAWKBIT_STATUS_EXEC_CLOSED)) {
1060 			LOG_ERR("Send request failed (HAWKBIT_CONFIG_DEVICE)");
1061 			hb_context.code_status = HAWKBIT_NETWORKING_ERROR;
1062 			goto cleanup;
1063 		}
1064 	}
1065 
1066 	ret = hawkbit_find_deployment_base(&hawkbit_results.base, deployment_base);
1067 	if (ret < 0) {
1068 		hb_context.code_status = HAWKBIT_METADATA_ERROR;
1069 		LOG_ERR("Unable to find URL for the device's deploymentBase: %d", ret);
1070 		goto cleanup;
1071 	}
1072 
1073 	if (strlen(deployment_base) == 0) {
1074 		hb_context.code_status = HAWKBIT_NO_UPDATE;
1075 		goto cleanup;
1076 	}
1077 
1078 	memset(hb_context.url_buffer, 0, sizeof(hb_context.url_buffer));
1079 	hb_context.dl.http_content_size = 0;
1080 	hb_context.dl.downloaded_size = 0;
1081 	hb_context.url_buffer_size = URL_BUFFER_SIZE;
1082 	snprintk(hb_context.url_buffer, hb_context.url_buffer_size, "%s/%s-%s/%s", HAWKBIT_JSON_URL,
1083 		 CONFIG_BOARD, device_id, deployment_base);
1084 	memset(&hawkbit_results.dep, 0, sizeof(hawkbit_results.dep));
1085 	memset(hb_context.response_data, 0, RESPONSE_BUFFER_SIZE);
1086 
1087 	if (!send_request(HTTP_GET, HAWKBIT_PROBE_DEPLOYMENT_BASE, HAWKBIT_STATUS_FINISHED_NONE,
1088 			  HAWKBIT_STATUS_EXEC_NONE)) {
1089 		LOG_ERR("Send request failed (HAWKBIT_PROBE_DEPLOYMENT_BASE)");
1090 		hb_context.code_status = HAWKBIT_NETWORKING_ERROR;
1091 		goto cleanup;
1092 	}
1093 
1094 	if (hb_context.code_status == HAWKBIT_METADATA_ERROR) {
1095 		goto cleanup;
1096 	}
1097 
1098 	hawkbit_dump_deployment(&hawkbit_results.dep);
1099 
1100 	hb_context.dl.http_content_size = 0;
1101 	ret = hawkbit_parse_deployment(&hawkbit_results.dep, &hb_context.json_action_id,
1102 				       download_http, &file_size);
1103 	if (ret < 0) {
1104 		LOG_ERR("Unable to parse deployment base: %d", ret);
1105 		goto cleanup;
1106 	}
1107 
1108 	nvs_read(&fs, ADDRESS_ID, &action_id, sizeof(action_id));
1109 
1110 	if (action_id == (int32_t)hb_context.json_action_id) {
1111 		LOG_INF("Preventing repeated attempt to install %d", hb_context.json_action_id);
1112 		hb_context.dl.http_content_size = 0;
1113 		memset(hb_context.url_buffer, 0, sizeof(hb_context.url_buffer));
1114 		hb_context.url_buffer_size = URL_BUFFER_SIZE;
1115 		snprintk(hb_context.url_buffer, hb_context.url_buffer_size,
1116 			 "%s/%s-%s/deploymentBase/%d/feedback", HAWKBIT_JSON_URL, CONFIG_BOARD,
1117 			 device_id, hb_context.json_action_id);
1118 
1119 		if (!send_request(HTTP_POST, HAWKBIT_REPORT, HAWKBIT_STATUS_FINISHED_SUCCESS,
1120 				  HAWKBIT_STATUS_EXEC_CLOSED)) {
1121 			LOG_ERR("Send request failed (HAWKBIT_REPORT)");
1122 			hb_context.code_status = HAWKBIT_NETWORKING_ERROR;
1123 			goto cleanup;
1124 		}
1125 
1126 		hb_context.code_status = HAWKBIT_OK;
1127 		goto cleanup;
1128 	}
1129 
1130 	LOG_INF("Ready to install update");
1131 
1132 	hb_context.dl.http_content_size = 0;
1133 	memset(hb_context.url_buffer, 0, sizeof(hb_context.url_buffer));
1134 	hb_context.url_buffer_size = URL_BUFFER_SIZE;
1135 
1136 	snprintk(hb_context.url_buffer, hb_context.url_buffer_size, "%s", download_http);
1137 
1138 	flash_img_init(&hb_context.flash_ctx);
1139 
1140 	ret = (int)send_request(HTTP_GET, HAWKBIT_DOWNLOAD,
1141 			  HAWKBIT_STATUS_FINISHED_NONE,
1142 			  HAWKBIT_STATUS_EXEC_NONE);
1143 
1144 	if (!ret) {
1145 		LOG_ERR("Send request failed (HAWKBIT_DOWNLOAD): %d", ret);
1146 		hb_context.code_status = HAWKBIT_NETWORKING_ERROR;
1147 		goto cleanup;
1148 	}
1149 
1150 	if (hb_context.code_status == HAWKBIT_DOWNLOAD_ERROR) {
1151 		goto cleanup;
1152 	}
1153 
1154 	/* Check if download finished */
1155 	if (!hb_context.final_data_received) {
1156 		LOG_ERR("Download is not complete");
1157 		hb_context.code_status = HAWKBIT_DOWNLOAD_ERROR;
1158 		goto cleanup;
1159 	}
1160 
1161 	/* Verify the hash of the stored firmware */
1162 	fic.match = hb_context.dl.file_hash;
1163 	fic.clen = hb_context.dl.downloaded_size;
1164 	if (flash_img_check(&hb_context.flash_ctx, &fic, FIXED_PARTITION_ID(SLOT1_LABEL))) {
1165 		LOG_ERR("Firmware - flash validation has failed");
1166 		hb_context.code_status = HAWKBIT_DOWNLOAD_ERROR;
1167 		goto cleanup;
1168 	}
1169 
1170 	/* Request mcuboot to upgrade */
1171 	if (boot_request_upgrade(BOOT_UPGRADE_TEST)) {
1172 		LOG_ERR("Failed to mark the image in slot 1 as pending");
1173 		hb_context.code_status = HAWKBIT_DOWNLOAD_ERROR;
1174 		goto cleanup;
1175 	}
1176 
1177 	/* If everything is successful */
1178 	hb_context.code_status = HAWKBIT_UPDATE_INSTALLED;
1179 	hawkbit_device_acid_update(hb_context.json_action_id);
1180 
1181 	hb_context.dl.http_content_size = 0;
1182 
1183 cleanup:
1184 	cleanup_connection();
1185 
1186 error:
1187 	free(hb_context.response_data);
1188 	k_sem_give(&probe_sem);
1189 	return hb_context.code_status;
1190 }
1191 
autohandler(struct k_work * work)1192 static void autohandler(struct k_work *work)
1193 {
1194 	switch (hawkbit_probe()) {
1195 	case HAWKBIT_UNCONFIRMED_IMAGE:
1196 		LOG_ERR("Image is unconfirmed");
1197 		LOG_ERR("Rebooting to previous confirmed image");
1198 		LOG_ERR("If this image is flashed using a hardware tool");
1199 		LOG_ERR("Make sure that it is a confirmed image");
1200 		k_sleep(K_SECONDS(1));
1201 		sys_reboot(SYS_REBOOT_WARM);
1202 		break;
1203 
1204 	case HAWKBIT_NO_UPDATE:
1205 		LOG_INF("No update found");
1206 		break;
1207 
1208 	case HAWKBIT_CANCEL_UPDATE:
1209 		LOG_INF("Hawkbit update cancelled from server");
1210 		break;
1211 
1212 	case HAWKBIT_OK:
1213 		LOG_INF("Image is already updated");
1214 		break;
1215 
1216 	case HAWKBIT_UPDATE_INSTALLED:
1217 		LOG_INF("Update installed, please reboot");
1218 		break;
1219 
1220 	case HAWKBIT_DOWNLOAD_ERROR:
1221 		LOG_INF("Update failed");
1222 		break;
1223 
1224 	case HAWKBIT_NETWORKING_ERROR:
1225 		LOG_INF("Network error");
1226 		break;
1227 
1228 	case HAWKBIT_METADATA_ERROR:
1229 		LOG_INF("Metadata error");
1230 		break;
1231 
1232 	case HAWKBIT_PROBE_IN_PROGRESS:
1233 		LOG_INF("Hawkbit is already running");
1234 		break;
1235 	}
1236 
1237 	k_work_reschedule(&hawkbit_work_handle, K_MSEC(poll_sleep));
1238 }
1239 
hawkbit_autohandler(void)1240 void hawkbit_autohandler(void)
1241 {
1242 	k_work_init_delayable(&hawkbit_work_handle, autohandler);
1243 	k_work_reschedule(&hawkbit_work_handle, K_NO_WAIT);
1244 }
1245