Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

suit/transport/vfs: add VFS as source for firmware updates #18045

Merged
merged 5 commits into from
Jun 7, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions examples/suit_update/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ QUIET ?= 1

USEMODULE += suit suit_transport_coap

# enable VFS transport (only works on boards with external storage)
USEMODULE += suit_transport_vfs
USEMODULE += vfs_default

# Display a progress bar during firmware download
USEMODULE += progress_bar

Expand Down
5 changes: 5 additions & 0 deletions sys/Makefile.dep
Original file line number Diff line number Diff line change
Expand Up @@ -846,6 +846,7 @@ endif

ifneq (,$(filter suit_transport_%, $(USEMODULE)))
USEMODULE += suit_transport
USEMODULE += suit_transport_worker
fjmolinas marked this conversation as resolved.
Show resolved Hide resolved
endif

ifneq (,$(filter suit_transport_coap, $(USEMODULE)))
Expand All @@ -854,6 +855,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
Expand Down
16 changes: 0 additions & 16 deletions sys/include/suit.h
Original file line number Diff line number Diff line change
Expand Up @@ -325,22 +325,6 @@ static inline bool suit_component_check_flag(suit_component_t *component,
int suit_component_name_to_string(const suit_manifest_t *manifest,
const suit_component_t *component,
char separator, char *buf, size_t buf_len);

/**
* @brief Helper function for writing bytes on flash a specified offset
*
* @param[in] arg ptr to the SUIT manifest
* @param[in] offset offset to write to on flash
* @param[in] buf bytes to write
* @param[in] len length of bytes to write
* @param[in] more whether more data is coming
*
* @return 0 on success
* @return <0 on error
*/
int suit_storage_helper(void *arg, size_t offset, uint8_t *buf, size_t len,
int more);

#ifdef __cplusplus
}
#endif
Expand Down
52 changes: 52 additions & 0 deletions sys/include/suit/transport/vfs.h
Original file line number Diff line number Diff line change
@@ -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://<path>/<to>/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 <benjamin.valentin@ml-pa.com>
*
*/

#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 */
/** @} */
2 changes: 1 addition & 1 deletion sys/shell/commands/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ ifneq (,$(filter nimble_statconn,$(USEMODULE)))
SRC += sc_nimble_statconn.c
endif

ifneq (,$(filter suit_transport_coap,$(USEMODULE)))
ifneq (,$(filter suit_transport_worker,$(USEMODULE)))
SRC += sc_suit.c
endif

Expand Down
4 changes: 2 additions & 2 deletions sys/shell/commands/shell_commands.c
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ extern int _nimble_netif_handler(int argc, char **argv);
extern int _nimble_statconn_handler(int argc, char **argv);
#endif

#ifdef MODULE_SUIT_TRANSPORT_COAP
#ifdef MODULE_SUIT_TRANSPORT_WORKER
extern int _suit_handler(int argc, char **argv);
#endif

Expand Down Expand Up @@ -382,7 +382,7 @@ const shell_command_t _shell_command_list[] = {
#ifdef MODULE_NIMBLE_STATCONN
{ "statconn", "NimBLE netif statconn", _nimble_statconn_handler},
#endif
#ifdef MODULE_SUIT_TRANSPORT_COAP
#ifdef MODULE_SUIT_TRANSPORT_WORKER
{ "suit", "Trigger a SUIT firmware update", _suit_handler },
#endif
#ifdef MODULE_CRYPTOAUTHLIB
Expand Down
87 changes: 86 additions & 1 deletion sys/suit/handlers_command_seq.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,20 @@
#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)
#include "progress_bar.h"
#endif

#include "log.h"

#define ENABLE_DEBUG 0
#include "debug.h"

static int _get_component_size(suit_manifest_t *manifest,
suit_component_t *comp,
uint32_t *img_size)
Expand Down Expand Up @@ -312,6 +322,74 @@ static int _start_storage(suit_manifest_t *manifest, suit_component_t *comp)
return suit_storage_start(comp->storage_backend, manifest, img_size);
}

static inline void _print_download_progress(suit_manifest_t *manifest,
size_t offset, size_t len,
size_t image_size)
{
(void)manifest;
(void)offset;
(void)len;
DEBUG("_suit_flashwrite(): writing %u bytes at pos %u\n", len, offset);
#if defined(MODULE_PROGRESS_BAR)
if (image_size != 0) {
char _suffix[7] = { 0 };
uint8_t _progress = 100 * (offset + len) / image_size;
sprintf(_suffix, " %3d%%", _progress);
progress_bar_print("Fetching firmware ", _suffix, _progress);
if (_progress == 100) {
puts("");
}
}
#else
(void) image_size;
#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)
{
suit_manifest_t *manifest = (suit_manifest_t *)arg;

uint32_t image_size;
nanocbor_value_t param_size;
size_t total = offset + len;
suit_component_t *comp = &manifest->components[manifest->component_current];
suit_param_ref_t *ref_size = &comp->param_size;

/* Grab the total image size from the manifest */
if ((suit_param_ref_to_cbor(manifest, ref_size, &param_size) == 0) ||
(nanocbor_get_uint32(&param_size, &image_size) < 0)) {
/* Early exit if the total image size can't be determined */
return -1;
}

if (image_size < offset + len) {
/* Extra newline at the start to compensate for the progress bar */
LOG_ERROR(
"\n_suit_coap(): Image beyond size, offset + len=%u, "
"image_size=%u\n", (unsigned)(total), (unsigned)image_size);
return -1;
}

if (!more && image_size != total) {
LOG_INFO("Incorrect size received, got %u, expected %u\n",
(unsigned)total, (unsigned)image_size);
return -1;
}

_print_download_progress(manifest, offset, len, image_size);

int res = suit_storage_write(comp->storage_backend, manifest, buf, offset, len);
if (!more) {
LOG_INFO("Finalizing payload store\n");
/* Finalize the write if no more data available */
res = suit_storage_finish(comp->storage_backend, manifest);
}
return res;
}
#endif

static int _dtv_fetch(suit_manifest_t *manifest, int key,
nanocbor_value_t *_it)
{
Expand Down Expand Up @@ -343,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';

Expand All @@ -360,14 +440,19 @@ static int _dtv_fetch(suit_manifest_t *manifest, int key,
#ifdef MODULE_SUIT_TRANSPORT_COAP
else if (strncmp(manifest->urlbuf, "coap://", 7) == 0) {
res = nanocoap_get_blockwise_url(manifest->urlbuf, CONFIG_SUIT_COAP_BLOCKSIZE,
suit_storage_helper,
_storage_helper,
manifest);
}
#endif
#ifdef MODULE_SUIT_TRANSPORT_MOCK
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)");
Expand Down
Loading