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