Skip to content

Commit d55a3f0

Browse files
committed
Add source version check to OTA update
Add a field to the OTA metadata structure indicating the oldest base version it's safe to install this update /from/. This provides a clear path forward in case there are incompatibilities, eg. some case (bootloader compatibility) where 0.16.0 cannot be installed safely from 0.15.2, but a transitional 0.15.3 can arrange the groundwork.
1 parent 4612577 commit d55a3f0

File tree

2 files changed

+26
-3
lines changed

2 files changed

+26
-3
lines changed

‎wled00/wled_metadata.cpp‎

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
#endif
1717

1818
constexpr uint32_t WLED_CUSTOM_DESC_MAGIC = 0x57535453; // "WSTS" (WLED System Tag Structure)
19-
constexpr uint32_t WLED_CUSTOM_DESC_VERSION = 1;
19+
constexpr uint32_t WLED_CUSTOM_DESC_VERSION = 2; // v1 - original PR; v2 - "safe to update from" version
2020

2121
// Compile-time validation that release name doesn't exceed maximum length
2222
static_assert(sizeof(WLED_RELEASE_NAME) <= WLED_RELEASE_NAME_MAX_LEN,
@@ -59,6 +59,11 @@ const wled_metadata_t __attribute__((section(BUILD_METADATA_SECTION))) WLED_BUIL
5959
TOSTRING(WLED_VERSION),
6060
WLED_RELEASE_NAME, // release_name
6161
std::integral_constant<uint32_t, djb2_hash_constexpr(WLED_RELEASE_NAME)>::value, // hash - computed at compile time; integral_constant enforces this
62+
#if defined(ESP32) && defined(CONFIG_IDF_TARGET_ESP32)
63+
{ 0, 15, 3 }, // Some older ESP32 might have bootloader issues; assume we'll have it sorted by 0.15.3
64+
#else
65+
{ 0, 15, 2 }, // All other platforms can update safely
66+
#endif
6267
};
6368

6469
static const char repoString_s[] PROGMEM = WLED_REPO;
@@ -96,7 +101,7 @@ bool findWledMetadata(const uint8_t* binaryData, size_t dataSize, wled_metadata_
96101
memcpy(&candidate, binaryData + offset, sizeof(candidate));
97102

98103
// Found potential match, validate version
99-
if (candidate.desc_version != WLED_CUSTOM_DESC_VERSION) {
104+
if (candidate.desc_version > WLED_CUSTOM_DESC_VERSION) {
100105
DEBUG_PRINTF_P(PSTR("Found WLED structure at offset %u but version mismatch: %u\n"),
101106
offset, candidate.desc_version);
102107
continue;
@@ -151,13 +156,30 @@ bool shouldAllowOTA(const wled_metadata_t& firmwareDescription, char* errorMessa
151156

152157
if (strncmp_P(safeFirmwareRelease, releaseString, WLED_RELEASE_NAME_MAX_LEN) != 0) {
153158
if (errorMessage && errorMessageLen > 0) {
154-
snprintf_P(errorMessage, errorMessageLen, PSTR("Firmware compatibility mismatch: current='%s', uploaded='%s'."),
159+
snprintf_P(errorMessage, errorMessageLen, PSTR("Firmware release name mismatch: current='%s', uploaded='%s'."),
155160
releaseString, safeFirmwareRelease);
156161
errorMessage[errorMessageLen - 1] = '\0'; // Ensure null termination
157162
}
158163
return false;
159164
}
160165

166+
if (firmwareDescription.desc_version > 1) {
167+
// Add safe version check
168+
// Parse our version (x.y.z) and compare it to the "safe version" array
169+
char* our_version = const_cast<char*>(versionString); // rip off const for legacy strtol compatibility
170+
for(unsigned v_index = 0; v_index < 3; ++v_index) {
171+
long our_v_parsed = strtol(our_version, &our_version, 10);
172+
++our_version; // skip the decimal point
173+
if (firmwareDescription.safe_update_version[v_index] < our_v_parsed) {
174+
snprintf_P(errorMessage, errorMessageLen, PSTR("Cannot update from this version: requires at least %d.%d.%d, current='%s'."),
175+
firmwareDescription.safe_update_version[0], firmwareDescription.safe_update_version[1], firmwareDescription.safe_update_version[2],
176+
versionString);
177+
errorMessage[errorMessageLen - 1] = '\0'; // Ensure null termination
178+
return false;
179+
}
180+
}
181+
}
182+
161183
// TODO: additional checks go here
162184

163185
return true;

‎wled00/wled_metadata.h‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ typedef struct {
2626
char wled_version[WLED_VERSION_MAX_LEN];
2727
char release_name[WLED_RELEASE_NAME_MAX_LEN]; // Release name (null-terminated)
2828
uint32_t hash; // Structure sanity check
29+
uint8_t safe_update_version[3]; // Indicates version it's known to be safe to install this update from: major, minor, patch
2930
} __attribute__((packed)) wled_metadata_t;
3031

3132

0 commit comments

Comments
 (0)