From dd4a578ef38e87f6decfb5364e9cfe9012953d53 Mon Sep 17 00:00:00 2001 From: Benjamin Valentin Date: Tue, 3 May 2022 00:27:29 +0200 Subject: [PATCH] suit/transport/vfs: add VFS as source for firmware updates --- sys/Makefile.dep | 4 +++ sys/include/suit/transport/vfs.h | 52 +++++++++++++++++++++++++++ sys/suit/handlers_command_seq.c | 12 +++++++ sys/suit/transport/coap.c | 28 +++++++++++++-- sys/suit/transport/vfs.c | 61 ++++++++++++++++++++++++++++++++ 5 files changed, 154 insertions(+), 3 deletions(-) create mode 100644 sys/include/suit/transport/vfs.h create mode 100644 sys/suit/transport/vfs.c diff --git a/sys/Makefile.dep b/sys/Makefile.dep index 9b6e9c59a4..ac747e24cb 100644 --- a/sys/Makefile.dep +++ b/sys/Makefile.dep @@ -854,6 +854,10 @@ ifneq (,$(filter suit_transport_coap, $(USEMODULE))) USEMODULE += sock_util endif +ifneq (,$(filter suit_transport_vfs, $(USEMODULE))) + USEMODULE += vfs_util +endif + ifneq (,$(filter suit_storage_%, $(USEMODULE))) USEMODULE += suit_storage endif diff --git a/sys/include/suit/transport/vfs.h b/sys/include/suit/transport/vfs.h new file mode 100644 index 0000000000..5fd725af31 --- /dev/null +++ b/sys/include/suit/transport/vfs.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2022 ML!PA Consulting GmbH + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ +/** + * @defgroup sys_suit_transport_vfs SUIT secure firmware OTA VFS transport + * @ingroup sys_suit + * @brief SUIT firmware VFS transport + * + * Allows to load firmware updates from the filesystem. + * URL scheme: file:////manifest.suit + * + * e.g. set `SUIT_COAP_ROOT` to `file:///sd0/fw` and place the + * update files to the folder fw/ on the first SD card. + * @{ + * + * @brief VFS transport backend definitions for SUIT manifests + * @author Benjamin Valentin + * + */ + +#ifndef SUIT_TRANSPORT_VFS_H +#define SUIT_TRANSPORT_VFS_H + +#include "net/nanocoap.h" +#include "suit.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief fetch a payload from the filesystem + * + * @param[in] manifest suit manifest context + * @param[in] cb filesystem block callback + * @param[in] ctx callback context + * + * @returns SUIT_OK if valid + * @returns negative otherwise + */ +int suit_transport_vfs_fetch(const suit_manifest_t *manifest, coap_blockwise_cb_t cb, void *ctx); + +#ifdef __cplusplus +} +#endif + +#endif /* SUIT_TRANSPORT_VFS_H */ +/** @} */ diff --git a/sys/suit/handlers_command_seq.c b/sys/suit/handlers_command_seq.c index 2fcd2f5dc3..c18e674e95 100644 --- a/sys/suit/handlers_command_seq.c +++ b/sys/suit/handlers_command_seq.c @@ -39,6 +39,9 @@ #include "suit/transport/coap.h" #include "net/nanocoap_sock.h" #endif +#ifdef MODULE_SUIT_TRANSPORT_VFS +#include "suit/transport/vfs.h" +#endif #include "suit/transport/mock.h" #if defined(MODULE_PROGRESS_BAR) @@ -342,6 +345,7 @@ static inline void _print_download_progress(suit_manifest_t *manifest, #endif } +#if defined(MODULE_SUIT_TRANSPORT_COAP) || defined(MODULE_SUIT_TRANSPORT_VFS) static int _storage_helper(void *arg, size_t offset, uint8_t *buf, size_t len, int more) { @@ -384,6 +388,7 @@ static int _storage_helper(void *arg, size_t offset, uint8_t *buf, size_t len, } return res; } +#endif static int _dtv_fetch(suit_manifest_t *manifest, int key, nanocbor_value_t *_it) @@ -416,6 +421,8 @@ static int _dtv_fetch(suit_manifest_t *manifest, int key, LOG_DEBUG("URL parsing failed\n)"); return err; } + + assert(manifest->urlbuf && url_len < manifest->urlbuf_len); memcpy(manifest->urlbuf, url, url_len); manifest->urlbuf[url_len] = '\0'; @@ -441,6 +448,11 @@ static int _dtv_fetch(suit_manifest_t *manifest, int key, else if (strncmp(manifest->urlbuf, "test://", 7) == 0) { res = suit_transport_mock_fetch(manifest); } +#endif +#ifdef MODULE_SUIT_TRANSPORT_VFS + else if (strncmp(manifest->urlbuf, "file://", 7) == 0) { + res = suit_transport_vfs_fetch(manifest, _storage_helper, manifest); + } #endif else { LOG_WARNING("suit: unsupported URL scheme!\n)"); diff --git a/sys/suit/transport/coap.c b/sys/suit/transport/coap.c index 9538c2b5ab..5015bdfa59 100644 --- a/sys/suit/transport/coap.c +++ b/sys/suit/transport/coap.c @@ -34,8 +34,13 @@ #include "periph/pm.h" #include "ztimer.h" +#ifdef MODULE_SUIT_TRANSPORT_COAP #include "suit/transport/coap.h" #include "net/sock/util.h" +#endif +#ifdef MODULE_SUIT_TRANSPORT_VFS +#include "vfs_util.h" +#endif #ifdef MODULE_RIOTBOOT_SLOT #include "riotboot/slot.h" @@ -81,10 +86,27 @@ static kernel_pid_t _suit_coap_pid; static void _suit_handle_url(const char *url, coap_blksize_t blksize) { + ssize_t size; LOG_INFO("suit_coap: downloading \"%s\"\n", url); - ssize_t size = nanocoap_get_blockwise_url_to_buf(url, blksize, - _manifest_buf, - SUIT_MANIFEST_BUFSIZE); + + if (0) {} +#ifdef MODULE_SUIT_TRANSPORT_COAP + else if (strncmp(url, "coap://", 7) == 0) { + size = nanocoap_get_blockwise_url_to_buf(url, blksize, + _manifest_buf, + sizeof(_manifest_buf)); + } +#endif +#ifdef MODULE_SUIT_TRANSPORT_VFS + else if (strncmp(url, "file:/", 6) == 0) { + size = vfs_file_to_buffer(&url[6], _manifest_buf, sizeof(_manifest_buf)); + } +#endif + else { + LOG_WARNING("suit_coap: unsupported URL scheme!\n)"); + return; + } + if (size >= 0) { LOG_INFO("suit_coap: got manifest with size %u\n", (unsigned)size); diff --git a/sys/suit/transport/vfs.c b/sys/suit/transport/vfs.c new file mode 100644 index 0000000000..9d0debd774 --- /dev/null +++ b/sys/suit/transport/vfs.c @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2022 ML!PA Consulting GmbH + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup sys_suit_transport_vfs + * @{ + * + * @fil + * @brief SUIT VFS + * + * @author Benjamin Valentin + * @} + */ + +#include +#include + +#include "suit/transport/vfs.h" +#include "log.h" +#include "vfs.h" + +int suit_transport_vfs_fetch(const suit_manifest_t *manifest, coap_blockwise_cb_t cb, void *ctx) +{ + const char *file = &manifest->urlbuf[7]; + size_t offset = 0; + int res, fd; + + LOG_DEBUG("suit_vfs: read firmware from %s\n", file); + + fd = vfs_open(file, O_RDONLY, 0); + if (fd < 0) { + return fd; + } + + void *buf = manifest->urlbuf; + size_t max_len = manifest->urlbuf_len; + while ((res = vfs_read(fd, buf, max_len)) > 0) { + size_t len = res; + res = cb(ctx, offset, buf, len, 1); + if (res < 0) { + LOG_ERROR("suit_vfs: write failed with %d\n", res); + break; + } + offset += len; + } + + if (res < 0) { + LOG_ERROR("suit_vfs: read failed with %d\n", res); + } else { + res = cb(ctx, offset, buf, 0, 0); + } + + vfs_close(fd); + + return res; +}