1 /*
2 * Copyright (c) 2018-2023 O.S.Systems
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/logging/log.h>
8 LOG_MODULE_REGISTER(updatehub, CONFIG_UPDATEHUB_LOG_LEVEL);
9
10 #include <zephyr/logging/log_ctrl.h>
11 #include <zephyr/net/socket.h>
12 #include <zephyr/net/net_mgmt.h>
13 #include <zephyr/net/net_ip.h>
14 #include <zephyr/net/udp.h>
15 #include <zephyr/net/coap.h>
16 #include <zephyr/net/dns_resolve.h>
17 #include <zephyr/sys/reboot.h>
18 #include <zephyr/data/json.h>
19 #include <zephyr/mgmt/updatehub.h>
20
21 #include "updatehub_priv.h"
22 #include "updatehub_firmware.h"
23 #include "updatehub_device.h"
24 #include "updatehub_timer.h"
25 #include "updatehub_integrity.h"
26 #include "updatehub_storage.h"
27
28 #if defined(CONFIG_UPDATEHUB_DTLS)
29 #define CA_CERTIFICATE_TAG 1
30 #include <zephyr/net/tls_credentials.h>
31 #endif
32
33 #define NETWORK_TIMEOUT (2 * MSEC_PER_SEC)
34 #define UPDATEHUB_POLL_INTERVAL K_MINUTES(CONFIG_UPDATEHUB_POLL_INTERVAL)
35 #define MAX_PATH_SIZE 255
36 /* MAX_PAYLOAD_SIZE must reflect size COAP_BLOCK_x option */
37 #define MAX_PAYLOAD_SIZE 1024
38 /* MAX_DOWNLOAD_DATA must be equal or bigger than:
39 * MAX_PAYLOAD_SIZE + (len + header + options)
40 * otherwise download size will be less than real size.
41 */
42 #define MAX_DOWNLOAD_DATA (MAX_PAYLOAD_SIZE + 32)
43 #define MAX_IP_SIZE 30
44
45 #if defined(CONFIG_UPDATEHUB_CE)
46 #define UPDATEHUB_SERVER CONFIG_UPDATEHUB_SERVER
47 #else
48 #define UPDATEHUB_SERVER "coap.updatehub.io"
49 #endif
50
51 #ifdef CONFIG_UPDATEHUB_DOWNLOAD_SHA256_VERIFICATION
52 #define _DOWNLOAD_SHA256_VERIFICATION
53 #elif defined(CONFIG_UPDATEHUB_DOWNLOAD_STORAGE_SHA256_VERIFICATION)
54 #define _DOWNLOAD_SHA256_VERIFICATION
55 #define _STORAGE_SHA256_VERIFICATION
56 #elif defined(CONFIG_UPDATEHUB_STORAGE_SHA256_VERIFICATION)
57 #define _STORAGE_SHA256_VERIFICATION
58 #endif
59
60 static struct updatehub_context {
61 struct coap_block_context block;
62 struct k_sem semaphore;
63 struct updatehub_storage_context storage_ctx;
64 struct updatehub_crypto_context crypto_ctx;
65 enum updatehub_response code_status;
66 uint8_t hash[SHA256_BIN_DIGEST_SIZE];
67 uint8_t uri_path[MAX_PATH_SIZE];
68 uint8_t payload[MAX_PAYLOAD_SIZE];
69 int downloaded_size;
70 struct pollfd fds[1];
71 int sock;
72 int nfds;
73 } ctx;
74
75 static struct update_info {
76 char package_uid[SHA256_HEX_DIGEST_SIZE];
77 char sha256sum_image[SHA256_HEX_DIGEST_SIZE];
78 int image_size;
79 } update_info;
80
81 static struct k_work_delayable updatehub_work_handle;
82
bin2hex_str(uint8_t * bin,size_t bin_len,char * str,size_t str_buf_len)83 static int bin2hex_str(uint8_t *bin, size_t bin_len, char *str, size_t str_buf_len)
84 {
85 if (bin == NULL || str == NULL) {
86 return -1;
87 }
88
89 /* ensures at least an empty string */
90 if (str_buf_len < 1) {
91 return -2;
92 }
93
94 memset(str, 0, str_buf_len);
95 bin2hex(bin, bin_len, str, str_buf_len);
96
97 return 0;
98 }
99
wait_fds(void)100 static void wait_fds(void)
101 {
102 if (poll(ctx.fds, ctx.nfds, NETWORK_TIMEOUT) < 0) {
103 LOG_ERR("Error in poll");
104 }
105 }
106
prepare_fds(void)107 static void prepare_fds(void)
108 {
109 ctx.fds[ctx.nfds].fd = ctx.sock;
110 ctx.fds[ctx.nfds].events = POLLIN;
111 ctx.nfds++;
112 }
113
metadata_hash_get(char * metadata)114 static int metadata_hash_get(char *metadata)
115 {
116 struct updatehub_crypto_context local_crypto_ctx;
117
118 if (updatehub_integrity_init(&local_crypto_ctx)) {
119 return -1;
120 }
121
122 if (updatehub_integrity_update(&local_crypto_ctx, metadata, strlen(metadata))) {
123 return -1;
124 }
125
126 if (updatehub_integrity_finish(&local_crypto_ctx, ctx.hash, sizeof(ctx.hash))) {
127 return -1;
128 }
129
130 if (bin2hex_str(ctx.hash, SHA256_BIN_DIGEST_SIZE,
131 update_info.package_uid, SHA256_HEX_DIGEST_SIZE)) {
132 return -1;
133 }
134
135 return 0;
136 }
137
138 static bool
is_compatible_hardware(struct resp_probe_some_boards * metadata_some_boards)139 is_compatible_hardware(struct resp_probe_some_boards *metadata_some_boards)
140 {
141 int i;
142
143 for (i = 0; i < metadata_some_boards->supported_hardware_len; i++) {
144 if (strncmp(metadata_some_boards->supported_hardware[i],
145 CONFIG_BOARD, strlen(CONFIG_BOARD)) == 0) {
146 return true;
147 }
148 }
149 return false;
150 }
151
cleanup_connection(void)152 static void cleanup_connection(void)
153 {
154 int i;
155
156 if (close(ctx.sock) < 0) {
157 LOG_ERR("Could not close the socket");
158 }
159
160 for (i = 0; i < ctx.nfds; i++) {
161 memset(&ctx.fds[i], 0, sizeof(ctx.fds[i]));
162 }
163
164 ctx.nfds = 0;
165 ctx.sock = 0;
166 }
167
start_coap_client(void)168 static bool start_coap_client(void)
169 {
170 struct addrinfo *addr;
171 struct addrinfo hints;
172 int resolve_attempts = 10;
173 int ret = -1;
174
175 memset(&hints, 0, sizeof(hints));
176
177 if (IS_ENABLED(CONFIG_NET_IPV6)) {
178 hints.ai_family = AF_INET6;
179 hints.ai_socktype = SOCK_STREAM;
180 } else if (IS_ENABLED(CONFIG_NET_IPV4)) {
181 hints.ai_family = AF_INET;
182 hints.ai_socktype = SOCK_STREAM;
183 }
184
185 #if defined(CONFIG_UPDATEHUB_DTLS)
186 int verify = TLS_PEER_VERIFY_REQUIRED;
187 sec_tag_t sec_list[] = { CA_CERTIFICATE_TAG };
188 int protocol = IPPROTO_DTLS_1_2;
189 char port[] = "5684";
190 #else
191 int protocol = IPPROTO_UDP;
192 char port[] = "5683";
193 #endif
194
195 while (resolve_attempts--) {
196 ret = getaddrinfo(UPDATEHUB_SERVER, port, &hints, &addr);
197 if (ret == 0) {
198 break;
199 }
200 k_sleep(K_SECONDS(1));
201 }
202 if (ret < 0) {
203 LOG_ERR("Could not resolve dns");
204 return false;
205 }
206
207 ret = 1;
208
209 ctx.sock = socket(addr->ai_family, SOCK_DGRAM, protocol);
210 if (ctx.sock < 0) {
211 LOG_ERR("Failed to create UDP socket");
212 goto error;
213 }
214
215 ret = -1;
216
217 #if defined(CONFIG_UPDATEHUB_DTLS)
218 if (setsockopt(ctx.sock, SOL_TLS, TLS_SEC_TAG_LIST,
219 sec_list, sizeof(sec_list)) < 0) {
220 LOG_ERR("Failed to set TLS_TAG option");
221 goto error;
222 }
223
224 if (setsockopt(ctx.sock, SOL_TLS, TLS_PEER_VERIFY, &verify, sizeof(int)) < 0) {
225 LOG_ERR("Failed to set TLS_PEER_VERIFY option");
226 goto error;
227 }
228 #endif
229
230 if (connect(ctx.sock, addr->ai_addr, addr->ai_addrlen) < 0) {
231 LOG_ERR("Cannot connect to UDP remote");
232 goto error;
233 }
234
235 prepare_fds();
236
237 ret = 0;
238 error:
239 freeaddrinfo(addr);
240
241 if (ret > 0) {
242 cleanup_connection();
243 }
244
245 return (ret == 0) ? true : false;
246 }
247
send_request(enum coap_msgtype msgtype,enum coap_method method,enum updatehub_uri_path type)248 static int send_request(enum coap_msgtype msgtype, enum coap_method method,
249 enum updatehub_uri_path type)
250 {
251 struct coap_packet request_packet;
252 int ret = -1;
253 uint8_t *data = k_malloc(MAX_PAYLOAD_SIZE);
254
255 if (data == NULL) {
256 LOG_ERR("Could not alloc data memory");
257 goto error;
258 }
259
260 ret = coap_packet_init(&request_packet, data, MAX_PAYLOAD_SIZE,
261 COAP_VERSION_1, COAP_TYPE_CON,
262 COAP_TOKEN_MAX_LEN, coap_next_token(), method,
263 coap_next_id());
264 if (ret < 0) {
265 LOG_ERR("Could not init packet");
266 goto error;
267 }
268
269 switch (method) {
270 case COAP_METHOD_GET:
271 snprintk(ctx.uri_path, MAX_PATH_SIZE,
272 "%s/%s/packages/%s/objects/%s", uri_path(type),
273 CONFIG_UPDATEHUB_PRODUCT_UID, update_info.package_uid,
274 update_info.sha256sum_image);
275
276 ret = coap_packet_append_option(&request_packet,
277 COAP_OPTION_URI_PATH,
278 ctx.uri_path,
279 strlen(ctx.uri_path));
280 if (ret < 0) {
281 LOG_ERR("Unable add option to request path");
282 goto error;
283 }
284
285 ret = coap_append_block2_option(&request_packet,
286 &ctx.block);
287 if (ret < 0) {
288 LOG_ERR("Unable coap append block 2");
289 goto error;
290 }
291
292 ret = coap_packet_append_option(&request_packet, 2048,
293 UPDATEHUB_API_HEADER, strlen(UPDATEHUB_API_HEADER));
294 if (ret < 0) {
295 LOG_ERR("Unable add option to add updatehub header");
296 goto error;
297 }
298
299 break;
300
301 case COAP_METHOD_POST:
302 ret = coap_packet_append_option(&request_packet,
303 COAP_OPTION_URI_PATH,
304 uri_path(type),
305 strlen(uri_path(type)));
306 if (ret < 0) {
307 LOG_ERR("Unable add option to request path");
308 goto error;
309 }
310
311 ret = coap_append_option_int(&request_packet,
312 COAP_OPTION_CONTENT_FORMAT,
313 COAP_CONTENT_FORMAT_APP_JSON);
314 if (ret < 0) {
315 LOG_ERR("Unable add option to request format");
316 goto error;
317 }
318
319 ret = coap_packet_append_option(&request_packet, 2048,
320 UPDATEHUB_API_HEADER, strlen(UPDATEHUB_API_HEADER));
321 if (ret < 0) {
322 LOG_ERR("Unable add option to add updatehub header");
323 goto error;
324 }
325
326 ret = coap_packet_append_payload_marker(&request_packet);
327 if (ret < 0) {
328 LOG_ERR("Unable to append payload marker");
329 goto error;
330 }
331
332 ret = coap_packet_append_payload(&request_packet,
333 ctx.payload,
334 strlen(ctx.payload));
335 if (ret < 0) {
336 LOG_ERR("Not able to append payload");
337 goto error;
338 }
339
340 break;
341
342 default:
343 LOG_ERR("Invalid method");
344 ret = -1;
345 goto error;
346 }
347
348 ret = send(ctx.sock, request_packet.data, request_packet.offset, 0);
349 if (ret < 0) {
350 LOG_ERR("Could not send request");
351 goto error;
352 }
353
354 error:
355 k_free(data);
356
357 return ret;
358 }
359
360 #ifdef _DOWNLOAD_SHA256_VERIFICATION
install_update_cb_sha256(void)361 static bool install_update_cb_sha256(void)
362 {
363 char sha256[SHA256_HEX_DIGEST_SIZE];
364
365 if (updatehub_integrity_finish(&ctx.crypto_ctx, ctx.hash, sizeof(ctx.hash))) {
366 LOG_ERR("Could not finish sha256sum");
367 return false;
368 }
369
370 if (bin2hex_str(ctx.hash, SHA256_BIN_DIGEST_SIZE,
371 sha256, SHA256_HEX_DIGEST_SIZE)) {
372 LOG_ERR("Could not create sha256sum hex representation");
373 return false;
374 }
375
376 if (strncmp(sha256, update_info.sha256sum_image,
377 SHA256_HEX_DIGEST_SIZE) != 0) {
378 LOG_ERR("SHA256SUM of image are not the same");
379 ctx.code_status = UPDATEHUB_DOWNLOAD_ERROR;
380 return false;
381 }
382
383 return true;
384 }
385 #endif
386
install_update_cb_check_blk_num(const struct coap_packet * resp)387 static int install_update_cb_check_blk_num(const struct coap_packet *resp)
388 {
389 int blk_num;
390 int blk2_opt;
391 uint16_t payload_len;
392
393 blk2_opt = coap_get_option_int(resp, COAP_OPTION_BLOCK2);
394 (void)coap_packet_get_payload(resp, &payload_len);
395
396 if ((payload_len == 0) || (blk2_opt < 0)) {
397 LOG_DBG("Invalid data received or block number is < 0");
398 return -ENOENT;
399 }
400
401 blk_num = GET_BLOCK_NUM(blk2_opt);
402
403 if (blk_num == updatehub_blk_get(UPDATEHUB_BLK_INDEX)) {
404 updatehub_blk_inc(UPDATEHUB_BLK_INDEX);
405
406 return 0;
407 }
408
409 return -EAGAIN;
410 }
411
install_update_cb(void)412 static void install_update_cb(void)
413 {
414 struct coap_packet response_packet;
415 uint8_t *data = k_malloc(MAX_DOWNLOAD_DATA);
416 const uint8_t *payload_start;
417 uint16_t payload_len;
418 int rcvd = -1;
419
420 if (data == NULL) {
421 LOG_ERR("Could not alloc data memory");
422 ctx.code_status = UPDATEHUB_DOWNLOAD_ERROR;
423 goto cleanup;
424 }
425
426 wait_fds();
427
428 rcvd = recv(ctx.sock, data, MAX_DOWNLOAD_DATA, MSG_DONTWAIT);
429 if (rcvd <= 0) {
430 ctx.code_status = UPDATEHUB_NETWORKING_ERROR;
431 LOG_ERR("Could not receive data");
432 goto cleanup;
433 }
434
435 if (coap_packet_parse(&response_packet, data, rcvd, NULL, 0) < 0) {
436 LOG_ERR("Invalid data received");
437 ctx.code_status = UPDATEHUB_DOWNLOAD_ERROR;
438 goto cleanup;
439 }
440
441 if (install_update_cb_check_blk_num(&response_packet) < 0) {
442 ctx.code_status = UPDATEHUB_DOWNLOAD_ERROR;
443 goto cleanup;
444 }
445
446 /* payload_len is > 0, checked at install_update_cb_check_blk_num */
447 payload_start = coap_packet_get_payload(&response_packet, &payload_len);
448
449 updatehub_tmr_stop();
450 updatehub_blk_set(UPDATEHUB_BLK_ATTEMPT, 0);
451 updatehub_blk_set(UPDATEHUB_BLK_TX_AVAILABLE, 1);
452
453 ctx.downloaded_size = ctx.downloaded_size + payload_len;
454
455 #ifdef _DOWNLOAD_SHA256_VERIFICATION
456 if (updatehub_integrity_update(&ctx.crypto_ctx,
457 payload_start,
458 payload_len)) {
459 LOG_ERR("Could not update sha256sum");
460 ctx.code_status = UPDATEHUB_DOWNLOAD_ERROR;
461 goto cleanup;
462 }
463 #endif
464
465 if (updatehub_storage_write(&ctx.storage_ctx, payload_start, payload_len,
466 ctx.downloaded_size == ctx.block.total_size)) {
467 LOG_ERR("Error to write on the flash");
468 ctx.code_status = UPDATEHUB_INSTALL_ERROR;
469 goto cleanup;
470 }
471
472 if (coap_update_from_block(&response_packet, &ctx.block) < 0) {
473 ctx.code_status = UPDATEHUB_DOWNLOAD_ERROR;
474 goto cleanup;
475 }
476
477 if (coap_next_block(&response_packet, &ctx.block) == 0) {
478 if (ctx.downloaded_size != ctx.block.total_size) {
479 LOG_ERR("Could not get the next coap block");
480 ctx.code_status = UPDATEHUB_DOWNLOAD_ERROR;
481 goto cleanup;
482 }
483
484 LOG_INF("Firmware download complete");
485
486 #ifdef _DOWNLOAD_SHA256_VERIFICATION
487 if (!install_update_cb_sha256()) {
488 LOG_ERR("Firmware - download validation has failed");
489 ctx.code_status = UPDATEHUB_DOWNLOAD_ERROR;
490 goto cleanup;
491 }
492 #else
493 if (hex2bin(update_info.sha256sum_image,
494 SHA256_HEX_DIGEST_SIZE - 1, ctx.hash,
495 SHA256_BIN_DIGEST_SIZE) != SHA256_BIN_DIGEST_SIZE) {
496 LOG_ERR("Firmware - metadata validation has failed");
497 ctx.code_status = UPDATEHUB_DOWNLOAD_ERROR;
498 goto cleanup;
499 }
500 #endif
501
502 #ifdef _STORAGE_SHA256_VERIFICATION
503 if (updatehub_storage_check(&ctx.storage_ctx,
504 UPDATEHUB_SLOT_PARTITION_1,
505 ctx.hash, ctx.downloaded_size)) {
506 LOG_ERR("Firmware - flash validation has failed");
507 ctx.code_status = UPDATEHUB_INSTALL_ERROR;
508 goto cleanup;
509 }
510 #endif
511 }
512
513 ctx.code_status = UPDATEHUB_OK;
514
515 cleanup:
516 k_free(data);
517 }
518
install_update(void)519 static enum updatehub_response install_update(void)
520 {
521 #ifdef _DOWNLOAD_SHA256_VERIFICATION
522 if (updatehub_integrity_init(&ctx.crypto_ctx)) {
523 LOG_ERR("Could not start sha256sum");
524 ctx.code_status = UPDATEHUB_DOWNLOAD_ERROR;
525 goto error;
526 }
527 #endif
528
529 if (!start_coap_client()) {
530 ctx.code_status = UPDATEHUB_NETWORKING_ERROR;
531 goto error;
532 }
533
534 if (coap_block_transfer_init(&ctx.block,
535 CONFIG_UPDATEHUB_COAP_BLOCK_SIZE_EXP,
536 update_info.image_size) < 0) {
537 LOG_ERR("Unable init block transfer");
538 ctx.code_status = UPDATEHUB_NETWORKING_ERROR;
539 goto cleanup;
540 }
541
542 if (updatehub_storage_init(&ctx.storage_ctx,
543 UPDATEHUB_SLOT_PARTITION_1)) {
544 LOG_ERR("Unable init flash");
545 ctx.code_status = UPDATEHUB_FLASH_INIT_ERROR;
546 goto cleanup;
547 }
548
549 ctx.downloaded_size = 0;
550 updatehub_blk_set(UPDATEHUB_BLK_ATTEMPT, 0);
551 updatehub_blk_set(UPDATEHUB_BLK_INDEX, 0);
552 updatehub_blk_set(UPDATEHUB_BLK_TX_AVAILABLE, 1);
553
554 while (ctx.downloaded_size != ctx.block.total_size) {
555 if (updatehub_blk_get(UPDATEHUB_BLK_TX_AVAILABLE)) {
556 if (send_request(COAP_TYPE_CON, COAP_METHOD_GET,
557 UPDATEHUB_DOWNLOAD) < 0) {
558 ctx.code_status = UPDATEHUB_NETWORKING_ERROR;
559 goto cleanup;
560 }
561
562 updatehub_blk_set(UPDATEHUB_BLK_TX_AVAILABLE, 0);
563 updatehub_blk_inc(UPDATEHUB_BLK_ATTEMPT);
564 updatehub_tmr_start();
565 }
566
567 install_update_cb();
568
569 if (ctx.code_status == UPDATEHUB_OK) {
570 continue;
571 }
572
573 if (ctx.code_status != UPDATEHUB_DOWNLOAD_ERROR &&
574 ctx.code_status != UPDATEHUB_NETWORKING_ERROR) {
575 LOG_DBG("status: %d", ctx.code_status);
576 goto cleanup;
577 }
578
579 if (updatehub_blk_get(UPDATEHUB_BLK_ATTEMPT) ==
580 CONFIG_UPDATEHUB_COAP_MAX_RETRY) {
581 updatehub_tmr_stop();
582
583 LOG_ERR("Could not get the packet");
584 ctx.code_status = UPDATEHUB_DOWNLOAD_ERROR;
585 goto cleanup;
586 }
587 }
588
589 cleanup:
590 cleanup_connection();
591
592 error:
593 ctx.downloaded_size = 0;
594
595 return ctx.code_status;
596 }
597
report(enum updatehub_state state)598 static int report(enum updatehub_state state)
599 {
600 struct report report;
601 int ret = -1;
602 const char *exec = state_name(state);
603 char *device_id = k_malloc(DEVICE_ID_HEX_MAX_SIZE);
604 char *firmware_version = k_malloc(FIRMWARE_IMG_VER_STRLEN_MAX);
605
606 if (device_id == NULL || firmware_version == NULL) {
607 LOG_ERR("Could not alloc device_id or firmware_version memory");
608 goto error;
609 }
610
611 if (!updatehub_get_device_identity(device_id, DEVICE_ID_HEX_MAX_SIZE)) {
612 goto error;
613 }
614
615 if (!updatehub_get_firmware_version(UPDATEHUB_SLOT_PARTITION_0,
616 firmware_version,
617 FIRMWARE_IMG_VER_STRLEN_MAX)) {
618 goto error;
619 }
620
621 memset(&report, 0, sizeof(report));
622 report.product_uid = CONFIG_UPDATEHUB_PRODUCT_UID;
623 report.device_identity.id = device_id;
624 report.version = firmware_version;
625 report.hardware = CONFIG_BOARD;
626 report.status = exec;
627 report.package_uid = update_info.package_uid;
628
629 switch (ctx.code_status) {
630 case UPDATEHUB_INSTALL_ERROR:
631 report.previous_state =
632 state_name(UPDATEHUB_STATE_INSTALLING);
633 break;
634 case UPDATEHUB_DOWNLOAD_ERROR:
635 report.previous_state =
636 state_name(UPDATEHUB_STATE_DOWNLOADING);
637 break;
638 case UPDATEHUB_FLASH_INIT_ERROR:
639 report.previous_state =
640 state_name(UPDATEHUB_FLASH_INIT_ERROR);
641 break;
642 default:
643 report.previous_state = "";
644 break;
645 }
646
647 if (strncmp(report.previous_state, "", sizeof("") - 1) != 0) {
648 report.error_message = updatehub_response(ctx.code_status);
649 } else {
650 report.error_message = "";
651 }
652
653 memset(&ctx.payload, 0, MAX_PAYLOAD_SIZE);
654 ret = json_obj_encode_buf(send_report_descr,
655 ARRAY_SIZE(send_report_descr),
656 &report, ctx.payload,
657 MAX_PAYLOAD_SIZE - 1);
658 if (ret < 0) {
659 LOG_ERR("Could not encode metadata");
660 goto error;
661 }
662
663 if (!start_coap_client()) {
664 goto error;
665 }
666
667 ret = send_request(COAP_TYPE_NON_CON, COAP_METHOD_POST,
668 UPDATEHUB_REPORT);
669 if (ret < 0) {
670 goto cleanup;
671 }
672
673 wait_fds();
674
675 cleanup:
676 cleanup_connection();
677
678 error:
679 k_free(firmware_version);
680 k_free(device_id);
681
682 return ret;
683 }
684
probe_cb(char * metadata,size_t metadata_size)685 static void probe_cb(char *metadata, size_t metadata_size)
686 {
687 struct coap_packet reply;
688 char tmp[MAX_DOWNLOAD_DATA];
689 const uint8_t *payload_start;
690 uint16_t payload_len;
691 size_t tmp_len;
692 int rcvd = -1;
693
694 wait_fds();
695
696 rcvd = recv(ctx.sock, tmp, MAX_DOWNLOAD_DATA, MSG_DONTWAIT);
697 if (rcvd <= 0) {
698 LOG_ERR("Could not receive data");
699 ctx.code_status = UPDATEHUB_NETWORKING_ERROR;
700 return;
701 }
702
703 if (coap_packet_parse(&reply, tmp, rcvd, NULL, 0) < 0) {
704 LOG_ERR("Invalid data received");
705 ctx.code_status = UPDATEHUB_DOWNLOAD_ERROR;
706 return;
707 }
708
709 if (coap_header_get_code(&reply) == COAP_RESPONSE_CODE_NOT_FOUND) {
710 LOG_INF("No update available");
711 ctx.code_status = UPDATEHUB_NO_UPDATE;
712 return;
713 }
714
715 payload_start = coap_packet_get_payload(&reply, &payload_len);
716 if (payload_len == 0) {
717 LOG_ERR("Invalid payload received");
718 ctx.code_status = UPDATEHUB_DOWNLOAD_ERROR;
719 return;
720 }
721
722 if (metadata_size < payload_len) {
723 LOG_ERR("There is no buffer available");
724 ctx.code_status = UPDATEHUB_METADATA_ERROR;
725 return;
726 }
727
728 memset(metadata, 0, metadata_size);
729 memcpy(metadata, payload_start, payload_len);
730
731 /* ensures payload have a valid string with size lower
732 * than metadata_size
733 */
734 tmp_len = strlen(metadata);
735 if (tmp_len >= metadata_size) {
736 LOG_ERR("Invalid metadata data received");
737 ctx.code_status = UPDATEHUB_METADATA_ERROR;
738 return;
739 }
740
741 ctx.code_status = UPDATEHUB_OK;
742
743 LOG_INF("Probe metadata received");
744 }
745
z_impl_updatehub_confirm(void)746 int z_impl_updatehub_confirm(void)
747 {
748 return updatehub_storage_mark_partition_as_confirmed(UPDATEHUB_SLOT_PARTITION_0);
749 }
750
z_impl_updatehub_reboot(void)751 int z_impl_updatehub_reboot(void)
752 {
753 sys_reboot(SYS_REBOOT_WARM);
754
755 return 0;
756 }
757
z_impl_updatehub_probe(void)758 enum updatehub_response z_impl_updatehub_probe(void)
759 {
760 struct probe request;
761 struct resp_probe_some_boards metadata_some_boards = { 0 };
762 struct resp_probe_any_boards metadata_any_boards = { 0 };
763
764 char *metadata = k_malloc(MAX_DOWNLOAD_DATA);
765 char *metadata_copy = k_malloc(MAX_DOWNLOAD_DATA);
766 char *device_id = k_malloc(DEVICE_ID_HEX_MAX_SIZE);
767 char *firmware_version = k_malloc(FIRMWARE_IMG_VER_STRLEN_MAX);
768
769 size_t sha256size;
770
771 if (device_id == NULL || firmware_version == NULL ||
772 metadata == NULL || metadata_copy == NULL) {
773 LOG_ERR("Could not alloc probe memory");
774 ctx.code_status = UPDATEHUB_METADATA_ERROR;
775 goto error;
776 }
777
778 if (!updatehub_storage_is_partition_good(&ctx.storage_ctx)) {
779 LOG_ERR("The current image is not confirmed");
780 ctx.code_status = UPDATEHUB_UNCONFIRMED_IMAGE;
781 goto error;
782 }
783
784 if (!updatehub_get_firmware_version(UPDATEHUB_SLOT_PARTITION_0,
785 firmware_version,
786 FIRMWARE_IMG_VER_STRLEN_MAX)) {
787 ctx.code_status = UPDATEHUB_METADATA_ERROR;
788 goto error;
789 }
790
791 if (!updatehub_get_device_identity(device_id, DEVICE_ID_HEX_MAX_SIZE)) {
792 ctx.code_status = UPDATEHUB_METADATA_ERROR;
793 goto error;
794 }
795
796 memset(&request, 0, sizeof(request));
797 request.product_uid = CONFIG_UPDATEHUB_PRODUCT_UID;
798 request.device_identity.id = device_id;
799 request.version = firmware_version;
800 request.hardware = CONFIG_BOARD;
801
802 memset(&ctx.payload, 0, MAX_PAYLOAD_SIZE);
803 if (json_obj_encode_buf(send_probe_descr,
804 ARRAY_SIZE(send_probe_descr),
805 &request, ctx.payload,
806 MAX_PAYLOAD_SIZE - 1) < 0) {
807 LOG_ERR("Could not encode metadata");
808 ctx.code_status = UPDATEHUB_METADATA_ERROR;
809 goto error;
810 }
811
812 ctx.nfds = 0;
813
814 if (!start_coap_client()) {
815 ctx.code_status = UPDATEHUB_NETWORKING_ERROR;
816 goto error;
817 }
818
819 if (send_request(COAP_TYPE_CON, COAP_METHOD_POST, UPDATEHUB_PROBE) < 0) {
820 ctx.code_status = UPDATEHUB_NETWORKING_ERROR;
821 goto cleanup;
822 }
823
824 probe_cb(metadata, MAX_DOWNLOAD_DATA);
825
826 if (ctx.code_status != UPDATEHUB_OK) {
827 goto cleanup;
828 }
829
830 memset(&update_info, 0, sizeof(update_info));
831 if (metadata_hash_get(metadata) < 0) {
832 LOG_ERR("Could not get metadata hash");
833 ctx.code_status = UPDATEHUB_METADATA_ERROR;
834 goto cleanup;
835 }
836
837 LOG_DBG("metadata size: %d", strlen(metadata));
838 LOG_HEXDUMP_DBG(metadata, MAX_DOWNLOAD_DATA, "metadata");
839
840 memcpy(metadata_copy, metadata, strlen(metadata));
841 if (json_obj_parse(metadata, strlen(metadata),
842 recv_probe_sh_array_descr,
843 ARRAY_SIZE(recv_probe_sh_array_descr),
844 &metadata_some_boards) < 0) {
845
846 if (json_obj_parse(metadata_copy, strlen(metadata_copy),
847 recv_probe_sh_string_descr,
848 ARRAY_SIZE(recv_probe_sh_string_descr),
849 &metadata_any_boards) < 0) {
850 LOG_ERR("Could not parse json");
851 ctx.code_status = UPDATEHUB_METADATA_ERROR;
852 goto cleanup;
853 }
854
855 if (metadata_any_boards.objects_len != 2) {
856 LOG_ERR("Could not parse json");
857 ctx.code_status = UPDATEHUB_METADATA_ERROR;
858 goto cleanup;
859 }
860
861 sha256size = strlen(
862 metadata_any_boards.objects[1].objects.sha256sum) + 1;
863
864 if (sha256size != SHA256_HEX_DIGEST_SIZE) {
865 LOG_ERR("SHA256 size is invalid");
866 ctx.code_status = UPDATEHUB_METADATA_ERROR;
867 goto cleanup;
868 }
869
870 memcpy(update_info.sha256sum_image,
871 metadata_any_boards.objects[1].objects.sha256sum,
872 SHA256_HEX_DIGEST_SIZE);
873 update_info.image_size = metadata_any_boards.objects[1].objects.size;
874 LOG_DBG("metadata_any: %s",
875 update_info.sha256sum_image);
876 } else {
877 if (metadata_some_boards.objects_len != 2) {
878 LOG_ERR("Could not parse json");
879 ctx.code_status = UPDATEHUB_METADATA_ERROR;
880 goto cleanup;
881 }
882
883 if (!is_compatible_hardware(&metadata_some_boards)) {
884 LOG_ERR("Incompatible hardware");
885 ctx.code_status =
886 UPDATEHUB_INCOMPATIBLE_HARDWARE;
887 goto cleanup;
888 }
889
890 sha256size = strlen(
891 metadata_some_boards.objects[1].objects.sha256sum) + 1;
892
893 if (sha256size != SHA256_HEX_DIGEST_SIZE) {
894 LOG_ERR("SHA256 size is invalid");
895 ctx.code_status = UPDATEHUB_METADATA_ERROR;
896 goto cleanup;
897 }
898
899 memcpy(update_info.sha256sum_image,
900 metadata_some_boards.objects[1].objects.sha256sum,
901 SHA256_HEX_DIGEST_SIZE);
902 update_info.image_size =
903 metadata_some_boards.objects[1].objects.size;
904 LOG_DBG("metadata_some: %s",
905 update_info.sha256sum_image);
906 }
907
908 ctx.code_status = UPDATEHUB_HAS_UPDATE;
909
910 cleanup:
911 cleanup_connection();
912
913 error:
914 k_free(metadata);
915 k_free(metadata_copy);
916 k_free(firmware_version);
917 k_free(device_id);
918
919 return ctx.code_status;
920 }
921
z_impl_updatehub_update(void)922 enum updatehub_response z_impl_updatehub_update(void)
923 {
924 if (report(UPDATEHUB_STATE_DOWNLOADING) < 0) {
925 LOG_ERR("Could not reporting downloading state");
926 goto error;
927 }
928
929 if (report(UPDATEHUB_STATE_INSTALLING) < 0) {
930 LOG_ERR("Could not reporting installing state");
931 goto error;
932 }
933
934 if (install_update() != UPDATEHUB_OK) {
935 goto error;
936 }
937
938 if (report(UPDATEHUB_STATE_DOWNLOADED) < 0) {
939 LOG_ERR("Could not reporting downloaded state");
940 goto error;
941 }
942
943 if (updatehub_storage_mark_partition_to_upgrade(&ctx.storage_ctx,
944 UPDATEHUB_SLOT_PARTITION_1)) {
945 LOG_ERR("Could not reporting downloaded state");
946 ctx.code_status = UPDATEHUB_INSTALL_ERROR;
947 goto error;
948 }
949
950 if (report(UPDATEHUB_STATE_INSTALLED) < 0) {
951 LOG_ERR("Could not reporting installed state");
952 goto error;
953 }
954
955 if (report(UPDATEHUB_STATE_REBOOTING) < 0) {
956 LOG_ERR("Could not reporting rebooting state");
957 goto error;
958 }
959
960 LOG_INF("Image flashed successfully, you can reboot now");
961
962 return ctx.code_status;
963
964 error:
965 if (ctx.code_status != UPDATEHUB_NETWORKING_ERROR) {
966 if (report(UPDATEHUB_STATE_ERROR) < 0) {
967 LOG_ERR("Could not reporting error state");
968 }
969 }
970
971 return ctx.code_status;
972 }
973
autohandler(struct k_work * work)974 static void autohandler(struct k_work *work)
975 {
976 switch (updatehub_probe()) {
977 case UPDATEHUB_UNCONFIRMED_IMAGE:
978 LOG_ERR("Image is unconfirmed. Rebooting to revert back to previous"
979 "confirmed image.");
980
981 LOG_PANIC();
982 updatehub_reboot();
983 break;
984
985 case UPDATEHUB_HAS_UPDATE:
986 switch (updatehub_update()) {
987 case UPDATEHUB_OK:
988 LOG_PANIC();
989 updatehub_reboot();
990 break;
991
992 default:
993 break;
994 }
995
996 break;
997
998 case UPDATEHUB_NO_UPDATE:
999 break;
1000
1001 default:
1002 break;
1003 }
1004
1005 k_work_reschedule(&updatehub_work_handle, UPDATEHUB_POLL_INTERVAL);
1006 }
1007
z_impl_updatehub_autohandler(void)1008 void z_impl_updatehub_autohandler(void)
1009 {
1010 #if defined(CONFIG_UPDATEHUB_DOWNLOAD_SHA256_VERIFICATION)
1011 LOG_INF("SHA-256 verification on download only");
1012 #endif
1013 #if defined(CONFIG_UPDATEHUB_STORAGE_SHA256_VERIFICATION)
1014 LOG_INF("SHA-256 verification from flash only");
1015 #endif
1016 #if defined(CONFIG_UPDATEHUB_DOWNLOAD_STORAGE_SHA256_VERIFICATION)
1017 LOG_INF("SHA-256 verification on download and from flash");
1018 #endif
1019
1020 k_work_init_delayable(&updatehub_work_handle, autohandler);
1021 k_work_reschedule(&updatehub_work_handle, K_NO_WAIT);
1022 }
1023