Firmware Over-the-Air over HTTP

Overview

The FOTA HTTP library downloads a firmware image from an HTTP server and writes it straight into the MCUboot slot that is not currently running. It then lets the application request the swap, confirm the new image or erase the slot. Unlike hawkBit or UpdateHub, no device management protocol is involved: any web server able to serve a file can act as the update source, which makes it a good fit for simple deployments and for bench testing.

The image is streamed to flash through the Flash Image as it arrives, so its size is not limited by RAM. The slot is erased progressively during the write, and the MCUboot trailer of the slot is cleared before the first byte lands, so a leftover from a previous image can never be mistaken for a pending swap.

After the download the library reads the MCUboot header back from flash and fails with -ENOEXEC when the data is not an image. It does not verify the signature: MCUboot does that before the image is ever booted, and that check decides whether the image runs. An optional SHA-256 comparison against a digest supplied by the caller is available with CONFIG_FOTA_HTTP_SHA256_CHECK to catch a corrupted transfer before the reboot. An image rejected by that comparison, or by the downgrade check below, is erased from the slot. After a download that failed part way, fota_http_apply() refuses the slot until another download into it succeeds, while the partial data stays in place for a resume.

Update cycle

The typical sequence is:

  1. fota_http_download() or fota_http_download_async() fetches the image into the secondary slot. The optional fota_http_download_params members sha256, resume and the TLS ones only exist when their Kconfig option is enabled.

  2. fota_http_apply() marks the image for a test boot, or as permanent.

  3. The device reboots and MCUboot swaps the image in.

  4. On a test boot the application validates itself and calls fota_http_confirm(). Without that call, the next reboot makes MCUboot revert to the previous image.

The revert step requires an MCUboot mode with revert support, such as swap-using-move or swap-using-offset. In overwrite-only mode the previous image is gone as soon as the swap happens and confirmation has no effect, so check which mode the board’s sysbuild configuration selects.

While a test image runs, the secondary slot holds the image MCUboot would revert to, so fota_http_download() refuses with -EPERM until fota_http_confirm() has been called.

Threads and stack

fota_http_download() blocks the calling thread for the whole transfer and needs enough stack for the HTTP client and, with https, the TLS handshake. With CONFIG_FOTA_HTTP_ASYNC, fota_http_download_async() runs the same transfer on a thread owned by the library, sized by CONFIG_FOTA_HTTP_THREAD_STACK_SIZE, and reports the result through a completion callback. The shell command selects the asynchronous variant so the shell stack size does not matter. Applications that only call fota_http_download() leave it disabled and do not pay for the thread stack.

Only one download runs at a time. fota_http_cancel() aborts the transfer in progress when the next fragment arrives or the request times out.

Redirects and resume

Responses with status 301, 302, 303, 307 or 308 are followed up to CONFIG_FOTA_HTTP_MAX_REDIRECTS times. Both absolute and path-only Location headers are accepted.

With CONFIG_FOTA_HTTP_RESUME the download offset is saved in settings while the transfer runs and when it fails. A later download with the resume parameter set continues from that offset with an HTTP Range request. The offset is only reused when the URL and image index match the interrupted download, and when the server sent an ETag or Last-Modified header the request carries If-Range with it, so a file that changed on the server is fetched again from the start. A server that ignores the Range header and answers with the full file restarts the transfer from zero, and so does a 416 Range Not Satisfiable answer, which is what a server sends when the file grew shorter than the saved offset. A validator too long to store also drops the saved progress, so the next download starts from the beginning rather than resuming against a file that may have changed. The offset is cleared once the image is complete.

Multiple images

In a layout with more than one updateable image, the image_index parameter selects which secondary slot the download goes to. fota_http_apply() and fota_http_confirm() both take the same index, so a layout that carries firmware for a second device confirms only what this device validated. When several images must run together, download and apply every one of them before rebooting: MCUboot validates the whole set and swaps it in one go, and confirm each one afterwards, because an image left unconfirmed is reverted on its own. fota_http_confirm_pending() only reports image 0, so an application that updates several images tracks the rest itself. A downgrade check with CONFIG_FOTA_HTTP_REJECT_DOWNGRADE only covers image 0.

With direct-XIP bootloaders the slot an image runs from is fixed at link time, so the device must fetch the image variant built for the free slot. fota_http_get_download_slot() reports which slot that is. This only covers single-image layouts: for every image after the first the library always uploads to the odd-numbered slot of the pair, which is correct for the swap and overwrite modes but not for direct-XIP.

Downgrade protection

CONFIG_FOTA_HTTP_REJECT_DOWNGRADE compares the version in the downloaded header with the running image and fails the download when it is older, erasing the rejected image so it cannot be applied by mistake. This is a convenience check for the application. An enforced policy belongs in the bootloader, see the MCUboot downgrade prevention and hardware rollback protection options.

TLS

https URLs are accepted when CONFIG_FOTA_HTTP_TLS is enabled. The CA certificate of the server is looked up under CONFIG_FOTA_HTTP_TLS_SEC_TAG, or under the tags passed in the download parameters, and can be registered with fota_http_tls_add_ca() or directly with tls_credential_add(). For mutual TLS, register the client certificate and key with fota_http_tls_add_client_cert().

Peer verification is required by default and CONFIG_FOTA_HTTP_TLS_PEER_VERIFY should stay at its default in production. The host name from the URL is verified against the certificate. When the URL carries an IP address and the certificate has no matching entry, pass the expected name in the tls_hostname parameter.

Certificate validity dates are only enforced when CONFIG_MBEDTLS_HAVE_TIME_DATE is enabled, which requires a correct wall clock on the device before the first download. TLS 1.3 can be selected with CONFIG_FOTA_HTTP_TLS_VERSION_1_3.

Shell commands

With CONFIG_FOTA_HTTP_SHELL enabled, a fota command exposes the library from the console:

fota download <url> [resume] [image=<n>]   download an image
fota cancel                                abort the download in progress
fota apply [permanent] [image=<n>]         boot the downloaded image on the next reset
fota confirm [image]                       confirm the running image
fota status                                show images and confirmation state
fota erase [image]                         erase the secondary slot

See the Firmware Over-the-Air over HTTP sample for a complete walkthrough.

API Reference

FOTA HTTP