feat: OTA über HTTP mit Trailer-Prüfung
This commit is contained in:
+1
-1
@@ -67,7 +67,7 @@ set(NL_FW_SOURCES
|
|||||||
src/drivers/nl_sm2135eh.c
|
src/drivers/nl_sm2135eh.c
|
||||||
src/sys/nl_console_cmd.c
|
src/sys/nl_console_cmd.c
|
||||||
src/sys/nl_console.c
|
src/sys/nl_console.c
|
||||||
src/sys/fwup_hook_default.c
|
src/sys/nl_ota.c
|
||||||
src/sys/sdk_stubs.c
|
src/sys/sdk_stubs.c
|
||||||
src/net/nl_names.c
|
src/net/nl_names.c
|
||||||
src/net/nl_http.c
|
src/net/nl_http.c
|
||||||
|
|||||||
+3
-1
@@ -6,7 +6,9 @@ Lib/GNU, Bin/secboot.img, Tools/GNU/link_w600_2m.ld (→ ld/) und wm_tool.c (→
|
|||||||
|
|
||||||
1. `Platform/Common/fwup/wm_fwup.c`: wolfSSL-SHA256 durch `nl_sha256_*` ersetzt, die QConnex-RSA-Prüfung
|
1. `Platform/Common/fwup/wm_fwup.c`: wolfSSL-SHA256 durch `nl_sha256_*` ersetzt, die QConnex-RSA-Prüfung
|
||||||
`Check_OTA_Image()` durch den Hook `nl_fwup_verify_tail()` (src/sys/nl_fwup_hook.h). Das Image-Format
|
`Check_OTA_Image()` durch den Hook `nl_fwup_verify_tail()` (src/sys/nl_fwup_hook.h). Das Image-Format
|
||||||
(Header + Payload + 512-Byte-Endblock) bleibt unverändert.
|
(Header + Payload + 512-Byte-Endblock) bleibt unverändert. Die starke Definition des Hooks liegt seit
|
||||||
|
Plan 3 in `src/sys/nl_ota.c` (Trailer-Prüfung über `nl_trailer_verify()`); die bisherige `weak`-Variante
|
||||||
|
`src/sys/fwup_hook_default.c` ist entfallen.
|
||||||
2. `Src/OS/RTOS/include/FreeRTOSConfig.h`: `configGENERATE_RUN_TIME_STATS 0`, QConnex-Debug-Hooks entfernt.
|
2. `Src/OS/RTOS/include/FreeRTOSConfig.h`: `configGENERATE_RUN_TIME_STATS 0`, QConnex-Debug-Hooks entfernt.
|
||||||
3. `undefined reference` beim Linken auf `EarlyInit` und `pre_gpio_config` (von
|
3. `undefined reference` beim Linken auf `EarlyInit` und `pre_gpio_config` (von
|
||||||
`sdk/Platform/Sys/wm_main.c` als `extern`-Hooks erwartet, aber nur von der App bereitgestellt):
|
`sdk/Platform/Sys/wm_main.c` als `extern`-Hooks erwartet, aber nur von der App bereitgestellt):
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
#include "sys/nl_app.h"
|
#include "sys/nl_app.h"
|
||||||
#include "sys/nl_app_api.h"
|
#include "sys/nl_app_api.h"
|
||||||
#include "sys/nl_console.h"
|
#include "sys/nl_console.h"
|
||||||
|
#include "sys/nl_ota.h"
|
||||||
|
|
||||||
#include "nl_version.h"
|
#include "nl_version.h"
|
||||||
|
|
||||||
@@ -163,6 +164,14 @@ static void app_task(void *arg)
|
|||||||
nl_state_log_init(base + NL_FL_STATE_0, base + NL_FL_STATE_1);
|
nl_state_log_init(base + NL_FL_STATE_0, base + NL_FL_STATE_1);
|
||||||
have_last = nl_state_log_load(&last);
|
have_last = nl_state_log_load(&last);
|
||||||
store_unlock();
|
store_unlock();
|
||||||
|
if (s_settings.ota_pending) {
|
||||||
|
/* We came back from an update attempt: restore the light the user had on. */
|
||||||
|
s_settings.ota_pending = 0;
|
||||||
|
printf("boot after ota attempt\r\n");
|
||||||
|
store_lock();
|
||||||
|
(void)nl_settings_save(&s_settings);
|
||||||
|
store_unlock();
|
||||||
|
}
|
||||||
printf("boot #%u, settings: pob=%u fade=%u/%u, last state: %s\r\n", boots,
|
printf("boot #%u, settings: pob=%u fade=%u/%u, last state: %s\r\n", boots,
|
||||||
s_settings.power_on_behaviour, s_settings.fade_in_ms, s_settings.fade_out_ms,
|
s_settings.power_on_behaviour, s_settings.fade_in_ms, s_settings.fade_out_ms,
|
||||||
have_last ? "yes" : "no");
|
have_last ? "yes" : "no");
|
||||||
@@ -184,6 +193,7 @@ static void app_task(void *arg)
|
|||||||
nl_app_factory_reset(); /* does not return */
|
nl_app_factory_reset(); /* does not return */
|
||||||
|
|
||||||
tls_watchdog_init(20u * 1000u * 1000u); /* 20 s */
|
tls_watchdog_init(20u * 1000u * 1000u); /* 20 s */
|
||||||
|
nl_ota_init();
|
||||||
nl_console_start();
|
nl_console_start();
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,10 +0,0 @@
|
|||||||
#include "sys/nl_fwup_hook.h"
|
|
||||||
|
|
||||||
/* Until OTA support (plan 3) provides a strong definition, every update is rejected. */
|
|
||||||
__attribute__((weak)) bool nl_fwup_verify_tail(const uint8_t sha256[32], const uint8_t *tail, uint32_t tail_len)
|
|
||||||
{
|
|
||||||
(void)sha256;
|
|
||||||
(void)tail;
|
|
||||||
(void)tail_len;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
@@ -11,6 +11,7 @@
|
|||||||
#include "net/nl_wifi.h"
|
#include "net/nl_wifi.h"
|
||||||
#include "sys/nl_app.h"
|
#include "sys/nl_app.h"
|
||||||
#include "sys/nl_app_api.h"
|
#include "sys/nl_app_api.h"
|
||||||
|
#include "sys/nl_ota.h"
|
||||||
|
|
||||||
#include "nl_version.h"
|
#include "nl_version.h"
|
||||||
|
|
||||||
@@ -88,7 +89,7 @@ static void get_info(nl_sys_info_t *out)
|
|||||||
out->wifi_error = w.error;
|
out->wifi_error = w.error;
|
||||||
out->uptime_s = nl_app_now_ms() / 1000u;
|
out->uptime_s = nl_app_now_ms() / 1000u;
|
||||||
out->free_heap = tls_mem_get_avail_heapsize();
|
out->free_heap = tls_mem_get_avail_heapsize();
|
||||||
out->last_ota_error = NULL;
|
out->last_ota_error = nl_ota_last_error();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void factory_reset(void) { nl_app_request_factory_reset(); }
|
static void factory_reset(void) { nl_app_request_factory_reset(); }
|
||||||
@@ -100,11 +101,7 @@ static void ping(void)
|
|||||||
nl_app_unlock();
|
nl_app_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
static int fw_update(const char *url)
|
static int fw_update(const char *url) { return nl_ota_start(url); }
|
||||||
{
|
|
||||||
(void)url;
|
|
||||||
return -1; /* OTA arrives in plan 3 */
|
|
||||||
}
|
|
||||||
|
|
||||||
const nl_api_ctx_t *nl_app_api_ctx(void)
|
const nl_api_ctx_t *nl_app_api_ctx(void)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -6,7 +6,8 @@
|
|||||||
|
|
||||||
/* Called by the SDK updater (sdk/Platform/Common/fwup/wm_fwup.c) after the image CRC
|
/* Called by the SDK updater (sdk/Platform/Common/fwup/wm_fwup.c) after the image CRC
|
||||||
* matched. sha256 covers the T_BOOTER header plus payload, tail is the 512 byte block
|
* matched. sha256 covers the T_BOOTER header plus payload, tail is the 512 byte block
|
||||||
* appended to the image. Return true to accept the image. */
|
* appended to the image. Return true to accept the image.
|
||||||
|
* Strong definition: src/sys/nl_ota.c (checks the trailer via nl_trailer_verify()). */
|
||||||
bool nl_fwup_verify_tail(const uint8_t sha256[32], const uint8_t *tail, uint32_t tail_len);
|
bool nl_fwup_verify_tail(const uint8_t sha256[32], const uint8_t *tail, uint32_t tail_len);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
#ifndef NL_OTA_H
|
||||||
|
#define NL_OTA_H
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
void nl_ota_init(void);
|
||||||
|
/* Starts a download task for an http:// URL. 0 = started, -1 = busy or invalid. */
|
||||||
|
int nl_ota_start(const char *url);
|
||||||
|
bool nl_ota_busy(void);
|
||||||
|
/* NULL, or one of: download, crc, trailer, device_mismatch, hash, busy */
|
||||||
|
const char *nl_ota_last_error(void);
|
||||||
|
void nl_ota_set_error(const char *e);
|
||||||
|
|
||||||
|
#endif
|
||||||
Reference in New Issue
Block a user