feat: OTA über HTTP mit Trailer-Prüfung

This commit is contained in:
Michael Sauer
2026-09-12 01:36:57 +02:00
parent ebee9e8e61
commit aa8151c3d6
8 changed files with 146 additions and 19 deletions
+113
View File
@@ -0,0 +1,113 @@
#include <stdio.h>
#include <string.h>
#include "wm_include.h"
#include "wm_http_fwup.h"
#include "config/nl_settings.h"
#include "sys/nl_app.h"
#include "sys/nl_fwup_hook.h"
#include "sys/nl_ota.h"
#include "util/nl_fwup_trailer.h"
/* t_http_fwup() (sdk/Src/App/OTA/wm_http_fwup.c) has no declaration in any SDK header. */
extern int t_http_fwup(char *url);
#define NL_OTA_URL_MAX 256
#define NL_OTA_STACK 2048 /* words */
#define NL_OTA_PRIO 34
static char s_url[NL_OTA_URL_MAX];
static volatile bool s_busy;
static const char * volatile s_error;
static u32 s_stack[NL_OTA_STACK];
void nl_ota_init(void)
{
s_busy = false;
s_error = NULL;
}
bool nl_ota_busy(void) { return s_busy; }
const char *nl_ota_last_error(void) { return s_error; }
void nl_ota_set_error(const char *e) { s_error = e; }
/* Called by the SDK firmware-update path once the image has been written and hashed.
sha256 covers the whole payload (T_BOOTER header + compressed image), tail is the
512 byte end block that used to carry the QConnex RSA signature. */
bool nl_fwup_verify_tail(const uint8_t sha256[32], const uint8_t *tail, uint32_t tail_len)
{
nl_trailer_err_t e = nl_trailer_verify(tail, tail_len, NINLIGHT_DEVICE_ID, sha256);
if (e != NL_TRAILER_OK) {
s_error = nl_trailer_err_name(e);
printf("ota: trailer rejected (%s)\r\n", s_error);
return false;
}
{
char v[NL_TRAILER_VERSION_LEN];
nl_trailer_version(tail, v);
printf("ota: trailer ok, incoming version %s\r\n", v);
}
return true;
}
static void ota_task(void *arg)
{
int rc;
(void)arg;
printf("ota: downloading %s\r\n", s_url);
rc = t_http_fwup(s_url);
/* Only reached on failure - the SDK resets the chip itself after a good image. */
if (s_error == NULL)
s_error = "download";
printf("ota: failed (rc=%d, %s)\r\n", rc, s_error);
{
nl_settings_t *s;
nl_app_lock();
s = nl_app_settings();
s->ota_pending = 0;
nl_app_unlock();
(void)nl_app_save_settings();
}
s_busy = false;
tls_os_task_del(NL_OTA_PRIO, NULL);
}
int nl_ota_start(const char *url)
{
size_t n;
if (url == NULL || strncmp(url, "http://", 7) != 0)
return -1;
n = strlen(url);
if (n == 0 || n >= sizeof s_url)
return -1;
if (s_busy) {
s_error = "busy";
return -1;
}
s_busy = true;
s_error = NULL;
memcpy(s_url, url, n + 1);
/* Persist the open light state and mark the pending update before the flash gets busy. */
nl_app_flush();
{
nl_settings_t *s;
nl_app_lock();
s = nl_app_settings();
s->ota_pending = 1;
nl_app_unlock();
(void)nl_app_save_settings();
}
if (tls_os_task_create(NULL, "nl_ota", ota_task, NULL, (u8 *)s_stack, sizeof(s_stack),
NL_OTA_PRIO, 0) != TLS_OS_SUCCESS) {
s_busy = false;
s_error = "busy";
return -1;
}
return 0;
}