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