1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00
RIOT/sys/suit/handlers.c
Koen Zandberg 7742750abd
suit: Introduce generic storage backend
This commit introduces a common storage backend for SUIT manifest
payloads. Different backends can be compiled into a single firmware.
Degending on the component name in the SUIT manifest, a storage backend
is selected by the parser.
2020-09-30 13:32:38 +02:00

159 lines
4.5 KiB
C

/*
* Copyright (C) 2019 Koen Zandberg
*
* 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
* @{
*
* @file
* @brief SUIT content handler helper functions
*
* @author Koen Zandberg <koen@bergzand.net>
*
* @}
*/
#include <inttypes.h>
#include <nanocbor/nanocbor.h>
#include <assert.h>
#include "suit/handlers.h"
#include "suit.h"
#include "log.h"
static suit_manifest_handler_t _get_handler(int key,
const suit_manifest_handler_t *map,
size_t len)
{
if (key < 0 || (size_t)key >= len) {
return NULL;
}
return map[key];
}
uint16_t suit_param_ref_to_cbor(const suit_manifest_t *manifest,
const suit_param_ref_t *ref,
nanocbor_value_t *val)
{
size_t len = manifest->len - ref->offset;
const uint8_t *start = manifest->buf + ref->offset;
nanocbor_decoder_init(val, start, len);
return ref->offset;
}
void suit_param_cbor_to_ref(const suit_manifest_t *manifest,
suit_param_ref_t *ref,
const nanocbor_value_t *val)
{
assert(val->cur >= manifest->buf);
ref->offset = val->cur - manifest->buf;
}
int suit_component_name_to_string(const suit_manifest_t *manifest,
const suit_component_t *component,
char separator, char *buf, size_t buf_len)
{
assert(buf_len);
nanocbor_value_t comp_id, arr;
suit_param_ref_to_cbor(manifest, &component->identifier, &comp_id);
if (nanocbor_enter_array(&comp_id, &arr) < 0) {
return SUIT_ERR_INVALID_MANIFEST;
}
size_t pos = 0;
while (!nanocbor_at_end(&arr)) {
const uint8_t *bstr;
size_t bstr_len;
if (separator) {
buf[pos++] = separator;
}
if (nanocbor_get_bstr(&arr, &bstr, &bstr_len) < 0) {
return SUIT_ERR_INVALID_MANIFEST;
}
if ((buf_len - pos - 1) < bstr_len) {
/* No space */
return SUIT_ERR_NO_MEM;
}
memcpy(&buf[pos], bstr, bstr_len);
pos += bstr_len;
}
buf[pos] = '\0';
LOG_INFO("Formatted component name: %s\n", buf);
return SUIT_OK;
}
int suit_handle_manifest_structure(suit_manifest_t *manifest,
nanocbor_value_t *it,
const suit_manifest_handler_t *handlers,
size_t handlers_len)
{
LOG_DEBUG("Handling command sequence\n");
nanocbor_value_t container;
if ((nanocbor_enter_array(it, &container) < 0) &&
(nanocbor_enter_map(it, &container) < 0)) {
LOG_DEBUG("Neither array nor map: %d\n", nanocbor_get_type(it));
return SUIT_ERR_INVALID_MANIFEST;
}
while (!nanocbor_at_end(&container)) {
int32_t key;
if (nanocbor_get_int32(&container, &key) < 0) {
LOG_DEBUG("No key found: %d\n", nanocbor_get_type(&container));
return SUIT_ERR_INVALID_MANIFEST;
}
nanocbor_value_t value = container;
LOG_DEBUG("Executing handler with key %" PRIi32 "\n", key);
suit_manifest_handler_t handler = _get_handler(key, handlers,
handlers_len);
if (!handler) {
return SUIT_ERR_UNSUPPORTED;
}
int res = handler(manifest, key, &value);
if (res < 0) {
LOG_DEBUG("Sequence handler error\n");
return res;
}
nanocbor_skip(&container);
}
nanocbor_leave_container(it, &container);
LOG_DEBUG("Leaving sequence handler\n");
return 0;
}
int suit_handle_manifest_structure_bstr(suit_manifest_t *manifest,
nanocbor_value_t *bseq,
const suit_manifest_handler_t *handlers,
size_t handlers_len)
{
const uint8_t *buf;
size_t len;
LOG_DEBUG("Handling command sequence starting with CBOR type %d\n",
nanocbor_get_type(bseq));
if (nanocbor_get_bstr(bseq, &buf, &len) < 0) {
return SUIT_ERR_INVALID_MANIFEST;
}
nanocbor_value_t it;
nanocbor_decoder_init(&it, buf, len);
return suit_handle_manifest_structure(manifest, &it, handlers,
handlers_len);
}