cryptnox-pos 1.0.0
Standalone USDC payment terminal firmware (ESP32 + Cryptnox smart card)
Loading...
Searching...
No Matches
ota.h File Reference

Firmware slot handling: receive an image into the idle slot, verify it, and install it only once somebody accepts it on the panel. More...

#include <stdbool.h>
#include <stddef.h>
Include dependency graph for ota.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Macros

#define OTA_ERR_MAX   160U
 Longest version string kept from an image header, plus NUL elsewhere.

Functions

bool ota_mark_valid (void)
 Confirm the running image, cancelling the rollback armed by the bootloader.
const char * ota_running_version (void)
 The running firmware's version, from the image header.
bool ota_last_update_failed (void)
 Whether the last update was installed and then thrown away.
bool ota_begin (size_t len, const char **err)
 Open the idle slot for an image of len bytes.
bool ota_write (const void *buf, size_t n)
 Append n bytes to the open slot.
bool ota_end (char *ver, size_t ver_n, const char **err)
 Close and verify the received image, then stage it for the panel.
void ota_abort (void)
 Give up on an upload in progress. Nothing is installed. Safe always.
bool ota_receiving (void)
 Whether an upload is in flight, so a second can be refused.
bool ota_staged (char *version, size_t version_n, bool *older)
 Fetch the version of an image that has been received and verified but not yet installed.
bool ota_commit (bool install)
 Resolve a staged image.

Detailed Description

Firmware slot handling: receive an image into the idle slot, verify it, and install it only once somebody accepts it on the panel.

This file owns the flash, not the network. The bytes arrive through the config portal (provision.h), which serves the update page and drives the three-call streaming API below; keeping the two apart means the partition logic is not entangled with a web server, and the portal has exactly one place to POST to.

Why the browser is the courier rather than esp_https_ota, which would be a tenth of the code: because that makes every terminal in the field open a connection to a third party who then knows how many units exist, where they are and which firmware each one runs. A payment terminal should not be the thing that publishes that. So:

you              download the image somewhere with internet
browser --HTTP--> http://192.168.4.1/api/ota   (streamed to flash)

Consequence for the operator: the file has to be on the phone or laptop before they join the terminal's setup network, because that network has no route anywhere. The portal used to offer a release-list check as well; it is gone, along with the URL it fetched — see docs/ota.md.

Threat model. What keeps a stranger's firmware off the device is not the transport and not the admin code: it is the signature (CONFIG_SECURE_SIGNED_ON_UPDATE_NO_SECURE_BOOT, see sdkconfig.defaults.release). ota_end refuses an image that is not signed by the key this firmware was built against, and it does so before the staged slot can become bootable. On top of that the portal only runs when an operator turns it on from behind the admin code, it closes itself, and nothing reboots until the received version is accepted on the panel — the same "a browser may propose, only the panel may accept" rule the payout addresses follow.

Definition in file ota.h.

Macro Definition Documentation

◆ OTA_ERR_MAX

#define OTA_ERR_MAX   160U

Longest version string kept from an image header, plus NUL elsewhere.

Definition at line 53 of file ota.h.

Function Documentation

◆ ota_abort()

void ota_abort ( void )

Give up on an upload in progress. Nothing is installed. Safe always.

Definition at line 156 of file ota.cpp.

References s_handle, s_receiving, and TAG.

Referenced by ota_post(), and prov_stop().

◆ ota_begin()

bool ota_begin ( size_t len,
const char ** err )

Open the idle slot for an image of len bytes.

Erases only the pages that will be written, which on a 1.94 MB slot is a few seconds saved with the operator watching. Refuses a second concurrent upload, a length that is not plausibly firmware, and a device whose partition table has no second app slot at all.

Parameters
[in]lenExact image length, from Content-Length.
[out]errSet to a caller-displayable reason on failure; never NULL on return, points at a string literal.
Returns
true with the slot open — the caller must then reach ota_end or ota_abort, or the slot stays claimed until the next boot.

Definition at line 94 of file ota.cpp.

References lock_ready(), OTA_MIN_IMAGE, refuse(), s_dst, s_handle, s_lock, s_receiving, s_staged, and TAG.

Referenced by ota_post().

◆ ota_commit()

bool ota_commit ( bool install)

Resolve a staged image.

Parameters
[in]installtrue to make the staged slot bootable and reboot into it — this call does not return. false to discard the staging, leaving the running slot untouched.
Returns
false if nothing was staged, or if the slot could not be made bootable. Does not return on success with install true.

Definition at line 291 of file ota.cpp.

References OTA_VERSION_MAX, s_lock, s_staged, s_staged_ver, and TAG.

Referenced by btn_event_cb().

◆ ota_end()

bool ota_end ( char * ver,
size_t ver_n,
const char ** err )

Close and verify the received image, then stage it for the panel.

The gate. Checks the image's own SHA-256, and — on a signed build — its signature against the public key in the running firmware. An image that fails here never becomes bootable, whoever uploaded it. On success the version is read out of the image that was just verified, never out of anything the browser said about it, and the image is staged: written, valid, and still not bootable.

Parameters
[out]verVersion from the image header, may be NULL.
[in]ver_nCapacity of ver.
[out]errDisplayable reason on failure; never NULL on return.
Returns
true if the image is staged and awaiting acceptance on the panel.

Definition at line 167 of file ota.cpp.

References ota_running_version(), ota_version_cmp(), OTA_VERSION_MAX, s_dst, s_handle, s_lock, s_receiving, s_staged, s_staged_older, s_staged_ver, and TAG.

Referenced by ota_post().

◆ ota_last_update_failed()

bool ota_last_update_failed ( void )

Whether the last update was installed and then thrown away.

The failure this exists to name: an image installs, boots, and never reaches ota_mark_valid — because bring-up did not finish, or because somebody power-cycled the terminal during the seconds it takes — so the bootloader reverts to the slot that was working and the panel goes on reading the old version. Correct behaviour, and completely silent: indistinguishable from an update that never happened at all.

Read from the idle slot's state in otadata, so it needs no bookkeeping of its own and clears itself: the next update writes that slot and overwrites the verdict.

Returns
true if the slot an update would go to holds an image the bootloader aborted or marked invalid.

Definition at line 221 of file ota.cpp.

Referenced by build_settings(), and ota_mark_valid().

◆ ota_mark_valid()

bool ota_mark_valid ( void )

Confirm the running image, cancelling the rollback armed by the bootloader.

Call once, and only once the image has proven it can drive its own hardware — panel, card reader and wallet layer all up. Not the uplink: a router or RPC provider that is down during the first boot is the venue's problem, and waiting on it rolled good images back. Until it is called, a freshly installed image is on probation: any reset that happens first (panic, watchdog, brown-out) sends the next boot back to the slot that was working. Calling it early is the same as not having rollback at all.

No-op on a build without CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE, and on a boot that is not the first after an update.

Returns
true if this boot was the first on a freshly installed image, i.e. the probation was real and has just been lifted. The caller uses it to greet the operator once after an update; every later boot returns false.

Definition at line 231 of file ota.cpp.

References ota_last_update_failed(), ota_running_version(), and TAG.

Referenced by pos_boot().

◆ ota_receiving()

bool ota_receiving ( void )

Whether an upload is in flight, so a second can be refused.

Definition at line 165 of file ota.cpp.

References s_receiving.

Referenced by ota_post(), and ui_task().

◆ ota_running_version()

const char * ota_running_version ( void )

The running firmware's version, from the image header.

Returns
Version string ("1.0.0"), never NULL. Valid for the program lifetime.

Definition at line 263 of file ota.cpp.

References s_running_ver.

Referenced by build_ota_confirm(), build_settings(), ota_end(), ota_mark_valid(), pos_boot(), and state_get().

◆ ota_staged()

bool ota_staged ( char * version,
size_t version_n,
bool * older )

Fetch the version of an image that has been received and verified but not yet installed.

Parameters
[out]versionVersion from the staged image's header, may be NULL.
[in]version_nCapacity of version.
[out]olderSet true if the staged version is behind the running one — a downgrade, which the panel must say out loud. May be NULL.
Returns
true if an image is staged and waiting to be accepted.

Definition at line 275 of file ota.cpp.

References s_lock, s_staged, s_staged_older, and s_staged_ver.

Referenced by build_ota_confirm(), ota_post(), and ui_task().

◆ ota_write()

bool ota_write ( const void * buf,
size_t n )

Append n bytes to the open slot.

Returns
false on a write error.

Definition at line 145 of file ota.cpp.

References s_handle, s_receiving, and TAG.

Referenced by ota_post().