Skip to content

Commit

Permalink
net: lib: fota_download: Add functions to use sec tag list
Browse files Browse the repository at this point in the history
Adds the functions fota_download() and fota_download_any() to
allow to use a list of sec tags instead of limiting tag count
to one. This lets a user set up several sec tags, which is already
supported by the download_client used by fota_download.

Signed-off-by: Jan Tore Guggedal <[email protected]>
  • Loading branch information
jtguggedal authored and rlubos committed Jan 16, 2024
1 parent 1b32fae commit 69df0e6
Show file tree
Hide file tree
Showing 8 changed files with 142 additions and 37 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -728,6 +728,10 @@ Libraries for networking

* Added support for using a password when connecting to a broker.

* :ref:`lib_fota_download` library:

* Added the functions :c:func:`fota_download` and :c:func:`fota_download_any` that can accept a security tag list and security tag count as arguments instead of a single security tag.

Libraries for NFC
-----------------

Expand Down
73 changes: 67 additions & 6 deletions include/net/fota_download.h
Original file line number Diff line number Diff line change
Expand Up @@ -112,11 +112,45 @@ typedef void (*fota_download_callback_t)(const struct fota_download_evt *evt);
*/
int fota_download_init(fota_download_callback_t client_callback);

/**@brief Start downloading the given file from the given host.
/**@brief Download the given file with the specified image type from the given host.
*
* Validate that the file type matches the expected type before proceeding with the download.
* When the download is complete, the secondary slot of MCUboot is tagged as having
* valid firmware inside it. The completion is reported through an event.
*
* URI parameters (host and file) are not copied, so pointers must stay valid
* until download is finished.
*
* @param host Name of host to start downloading from. Can include scheme
* and port number, for example https://google.com:443
* @param file Path to the file you wish to download. See fota_download_any()
* for details on expected format.
* @param sec_tag_list Security tags that you want to use with HTTPS. Pass NULL to disable TLS.
* @param sec_tag_count Number of TLS security tags in list. Pass 0 to disable TLS.
* @param pdn_id Packet Data Network ID to use for the download, or 0 to use the default.
* @param fragment_size Fragment size to be used for the download.
* If 0, @kconfig{CONFIG_DOWNLOAD_CLIENT_HTTP_FRAG_SIZE} is used.
* @param expected_type Type of firmware file to be downloaded and installed.
*
* @retval 0 If download has started successfully.
* @retval -EALREADY If download is already ongoing.
* @retval -E2BIG If sec_tag_count is larger than
* @kconfig{CONFIG_FOTA_DOWNLOAD_SEC_TAG_LIST_SIZE_MAX}
* Otherwise, a negative value is returned.
*/
int fota_download(const char *host, const char *file, const int *sec_tag_list,
uint8_t sec_tag_count, uint8_t pdn_id, size_t fragment_size,
const enum dfu_target_image_type expected_type);


/**@brief Start downloading the given file of any image type from the given host.
*
* When the download is complete, the secondary slot of MCUboot is tagged as having
* valid firmware inside it. The completion is reported through an event.
*
* URI parameters (host and file) are not copied, so pointers must stay valid
* until download is finished.
*
* @param host Name of host to start downloading from. Can include scheme
* and port number, e.g. https://google.com:443
* @param file Path to the file you wish to download. May be either a single
Expand All @@ -130,7 +164,34 @@ int fota_download_init(fota_download_callback_t client_callback);
* See <a href="https://developer.nordicsemi.com/nRF_Connect_SDK/doc/latest/nrf/ug_bootloader.html">
* Secure Bootloader Chain Docs</a> for details regarding the upgradable
* bootloader slots.
* @param sec_tag Security tag you want to use with HTTPS set to -1 to Disable.
* @param sec_tag_list Security tags that you want to use with HTTPS. Pass NULL to disable TLS.
* @param sec_tag_count Number of TLS security tags in list. Pass 0 to disable TLS.
* @param pdn_id Packet Data Network ID to use for the download, or 0 to use the default.
* @param fragment_size Fragment size to be used for the download.
* If 0, @kconfig{CONFIG_DOWNLOAD_CLIENT_HTTP_FRAG_SIZE} is used.
*
* @retval 0 If download has started successfully.
* @retval -EALREADY If download is already ongoing.
* @retval -E2BIG If sec_tag_count is larger than
* @kconfig{CONFIG_FOTA_DOWNLOAD_SEC_TAG_LIST_SIZE_MAX}
* Otherwise, a negative value is returned.
*/
int fota_download_any(const char *host, const char *file, const int *sec_tag_list,
uint8_t sec_tag_count, uint8_t pdn_id, size_t fragment_size);

/**@brief Start downloading the given file of any image type from the given host.
*
* When the download is complete, the secondary slot of MCUboot is tagged as having
* valid firmware inside it. The completion is reported through an event.
*
* URI parameters (host and file) are not copied, so pointers must stay valid
* until download is finished.
*
* @param host Name of host to start downloading from. Can include scheme
* and port number, e.g. https://google.com:443
* @param file Path to the file you wish to download. See fota_download_any()
* for details on expected format.
* @param sec_tag Security tag you want to use with HTTPS. Pass -1 to disable TLS.
* @param pdn_id Packet Data Network ID to use for the download, or 0 to use the default.
* @param fragment_size Fragment size to be used for the download.
* If 0, @kconfig{CONFIG_DOWNLOAD_CLIENT_HTTP_FRAG_SIZE} is used.
Expand All @@ -142,9 +203,9 @@ int fota_download_init(fota_download_callback_t client_callback);
int fota_download_start(const char *host, const char *file, int sec_tag,
uint8_t pdn_id, size_t fragment_size);

/**@brief Start downloading the given file from the given host. Validate that the
* file type matches the expected type before starting the installation.
/**@brief Download the given file with the specified image type from the given host.
*
* Validate that the file type matches the expected type before proceeding with the download.
* When the download is complete, the secondary slot of MCUboot is tagged as having
* valid firmware inside it. The completion is reported through an event.
*
Expand All @@ -153,9 +214,9 @@ int fota_download_start(const char *host, const char *file, int sec_tag,
*
* @param host Name of host to start downloading from. Can include scheme
* and port number, for example https://google.com:443
* @param file Path to the file you wish to download. See fota_download_start()
* @param file Path to the file you wish to download. See fota_download_any()
* for details on expected format.
* @param sec_tag Security tag you want to use with HTTPS set to -1 to Disable.
* @param sec_tag Security tag you want to use with HTTPS. Pass -1 to disable TLS.
* @param pdn_id Packet Data Network ID to use for the download, or 0 to use the default.
* @param fragment_size Fragment size to be used for the download.
* If 0, @kconfig{CONFIG_DOWNLOAD_CLIENT_HTTP_FRAG_SIZE} is used.
Expand Down
7 changes: 5 additions & 2 deletions samples/cellular/http_update/modem_delta_update/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,8 @@ static int update_download(void)
{
int err;
const char *file;
int sec_tag = SEC_TAG;
uint8_t sec_tag_count = sec_tag < 0 ? 0 : 1;

err = modem_info_string_get(MODEM_INFO_FW_VERSION, modem_version,
MAX_MODEM_VERSION_LEN);
Expand All @@ -307,9 +309,10 @@ static int update_download(void)
}

/* Functions for getting the host and file */
err = fota_download_start(CONFIG_DOWNLOAD_HOST, file, SEC_TAG, 0, 0);
err = fota_download(CONFIG_DOWNLOAD_HOST, file, &sec_tag, sec_tag_count, 0, 0,
DFU_TARGET_IMAGE_TYPE_MODEM_DELTA);
if (err) {
printk("fota_download_start() failed, err %d\n", err);
printk("fota_download_any() failed, err %d\n", err);
return err;
}

Expand Down
7 changes: 5 additions & 2 deletions samples/cellular/http_update/modem_full_update/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -420,6 +420,8 @@ static int update_download(void)
{
int err;
const char *file;
int sec_tag = SEC_TAG;
uint8_t sec_tag_count = sec_tag < 0 ? 0 : 1;
const struct dfu_target_full_modem_params params = {
.buf = fmfu_buf,
.len = sizeof(fmfu_buf),
Expand Down Expand Up @@ -456,9 +458,10 @@ static int update_download(void)
}

/* Functions for getting the host and file */
err = fota_download_start(CONFIG_DOWNLOAD_HOST, file, SEC_TAG, 0, 0);
err = fota_download(CONFIG_DOWNLOAD_HOST, file, &sec_tag, sec_tag_count, 0, 0,
DFU_TARGET_IMAGE_TYPE_FULL_MODEM);
if (err != 0) {
printk("fota_download_start() failed, err %d\n", err);
printk("fota_download() failed, err %d\n", err);
return err;
}

Expand Down
6 changes: 6 additions & 0 deletions subsys/net/lib/fota_download/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,12 @@ config FOTA_DOWNLOAD_RESOURCE_LOCATOR_LENGTH
int "Size of buffer used for Resource locator"
default 512

config FOTA_DOWNLOAD_SEC_TAG_LIST_SIZE_MAX
int "Size of security tag list"
default 5
help
Maximum size of the list of security tags used to store TLS credentials.

module=FOTA_DOWNLOAD
module-dep=LOG
module-str=Firmware Over the Air Download
Expand Down
61 changes: 44 additions & 17 deletions subsys/net/lib/fota_download/src/fota_download.c
Original file line number Diff line number Diff line change
Expand Up @@ -348,13 +348,6 @@ static void download_with_offset(struct k_work *unused)
return;
}

int fota_download_start(const char *host, const char *file, int sec_tag,
uint8_t pdn_id, size_t fragment_size)
{
return fota_download_start_with_image_type(host, file, sec_tag, pdn_id,
fragment_size, DFU_TARGET_IMAGE_TYPE_ANY);
}

static bool is_ip_address(const char *host)
{
struct sockaddr sa;
Expand Down Expand Up @@ -419,14 +412,22 @@ int fota_download_s0_active_get(bool *const s0_active)
#endif /* PM_S1_ADDRESS */
}

int fota_download_start_with_image_type(const char *host, const char *file,
int sec_tag, uint8_t pdn_id, size_t fragment_size,

int fota_download_any(const char *host, const char *file, const int *sec_tag_list,
uint8_t sec_tag_count, uint8_t pdn_id, size_t fragment_size)
{
return fota_download(host, file, sec_tag_list, sec_tag_count, pdn_id,
fragment_size, DFU_TARGET_IMAGE_TYPE_ANY);
}

int fota_download(const char *host, const char *file,
const int *sec_tag_list, uint8_t sec_tag_count, uint8_t pdn_id, size_t fragment_size,
const enum dfu_target_image_type expected_type)
{
static int sec_tag_list[1];
uint32_t host_hash = 0;
uint32_t file_hash = 0;
int err = -1;
static int sec_tag_list_copy[CONFIG_FOTA_DOWNLOAD_SEC_TAG_LIST_SIZE_MAX];

struct download_client_cfg config = {
.pdn_id = pdn_id,
Expand All @@ -441,6 +442,10 @@ int fota_download_start_with_image_type(const char *host, const char *file,
return -EALREADY;
}

if (sec_tag_count > ARRAY_SIZE(sec_tag_list_copy)) {
return -E2BIG;
}

atomic_clear_bit(&flags, FLAG_CLOSED);
atomic_clear_bit(&flags, FLAG_RESUME);
set_error_state(FOTA_DOWNLOAD_ERROR_CAUSE_NO_ERROR);
Expand All @@ -456,19 +461,21 @@ int fota_download_start_with_image_type(const char *host, const char *file,
} else {
atomic_clear_bit(&flags, FLAG_NEW_URI);
}

dl_host_hash = host_hash;
dl_file_hash = file_hash;
dl_host = host;
dl_file = file;

if (sec_tag != -1 && !is_ip_address(host)) {
config.set_tls_hostname = true;
}
if ((sec_tag_list != NULL) && (sec_tag_count > 0)) {
memcpy(sec_tag_list_copy, sec_tag_list, sec_tag_count * sizeof(sec_tag_list[0]));

if (sec_tag != -1) {
sec_tag_list[0] = sec_tag;
config.sec_tag_list = sec_tag_list;
config.sec_tag_count = 1;
config.sec_tag_count = sec_tag_count;
config.sec_tag_list = sec_tag_list_copy;

if (!is_ip_address(host)) {
config.set_tls_hostname = true;
}
}

socket_retries_left = CONFIG_FOTA_SOCKET_RETRIES;
Expand Down Expand Up @@ -519,6 +526,26 @@ int fota_download_start_with_image_type(const char *host, const char *file,
return 0;
}

int fota_download_start(const char *host, const char *file, int sec_tag,
uint8_t pdn_id, size_t fragment_size)
{
int sec_tag_list[1] = { sec_tag };
uint8_t sec_tag_count = sec_tag < 0 ? 0 : 1;

return fota_download_any(host, file, sec_tag_list, sec_tag_count, pdn_id, fragment_size);
}

int fota_download_start_with_image_type(const char *host, const char *file,
int sec_tag, uint8_t pdn_id, size_t fragment_size,
const enum dfu_target_image_type expected_type)
{
int sec_tag_list[1] = { sec_tag };
uint8_t sec_tag_count = sec_tag < 0 ? 0 : 1;

return fota_download(host, file, sec_tag_list, sec_tag_count, pdn_id,
fragment_size, expected_type);
}

static int fota_download_object_init(void)
{
int err;
Expand Down
1 change: 1 addition & 0 deletions tests/subsys/net/lib/fota_download/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ target_compile_options(app
-DCONFIG_FOTA_DOWNLOAD_RESOURCE_LOCATOR_LENGTH=512
-DCONFIG_FOTA_DOWNLOAD_FILE_NAME_LENGTH=128
-DCONFIG_FOTA_DOWNLOAD_HOST_NAME_LENGTH=128
-DCONFIG_FOTA_DOWNLOAD_SEC_TAG_LIST_SIZE_MAX=5
${info_magic}
${ext_api_magic}
)
20 changes: 10 additions & 10 deletions tests/subsys/net/lib/fota_download/src/test_fota_download.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
static char buf[1024];

#define BASE_DOMAIN "something.com"
#define NO_TLS -1
#define NO_TLS NULL
#define ARBITRARY_IMAGE_OFFSET 512

/* Stubs and mocks */
Expand Down Expand Up @@ -285,7 +285,7 @@ static void init(void)
* @param expected_selection - The resource locator that fota_download_start is expected to select
* @param s0_active - If true, pretend that s0 is active. Otherwise, pretend that s1 is active.
*/
static void test_fota_download_start_generic(const char * const resource_locator,
static void test_fota_download_any_generic(const char * const resource_locator,
const char * const expected_selection, bool s0_active)
{
int err;
Expand All @@ -297,7 +297,7 @@ static void test_fota_download_start_generic(const char * const resource_locator

/* Start the download, check that it succeeds */
strcpy(buf, resource_locator);
err = fota_download_start(BASE_DOMAIN, buf, NO_TLS, 0, 0);
err = fota_download_any(BASE_DOMAIN, buf, NO_TLS, 0, 0, 0);
zassert_equal(err, 0, NULL);

/* Verify that the correct resource was selected */
Expand All @@ -323,17 +323,17 @@ ZTEST(fota_download_tests, test_fota_download_cancel_before_init)

ZTEST(fota_download_tests, test_download_single)
{
test_fota_download_start_generic(S0_A, S0_A, S1_ACTIVE);
test_fota_download_any_generic(S0_A, S0_A, S1_ACTIVE);
}

ZTEST(fota_download_tests, test_download_dual_s0_active)
{
test_fota_download_start_generic(S0_B " " S1_B, S1_B, S0_ACTIVE);
test_fota_download_any_generic(S0_B " " S1_B, S1_B, S0_ACTIVE);
}

ZTEST(fota_download_tests, test_download_dual_s1_active)
{
test_fota_download_start_generic(S0_C " " S1_C, S0_C, S1_ACTIVE);
test_fota_download_any_generic(S0_C " " S1_C, S0_C, S1_ACTIVE);
}

ZTEST(fota_download_tests, test_download_with_offset)
Expand All @@ -359,7 +359,7 @@ ZTEST(fota_download_tests, test_download_with_offset)
/* Check that application is being notified when
* download_with_offset fails to get fw image offset
*/
err = fota_download_start(BASE_DOMAIN, buf, NO_TLS, 0, 0);
err = fota_download_any(BASE_DOMAIN, buf, NO_TLS, 0, 0, 0);
zassert_ok(err, NULL);

err = download_client_event_handler(&evt);
Expand All @@ -378,7 +378,7 @@ ZTEST(fota_download_tests, test_download_with_offset)
/* Check that application is being notified when
* download_with_offset fails to connect
*/
err = fota_download_start(BASE_DOMAIN, buf, NO_TLS, 0, 0);
err = fota_download_any(BASE_DOMAIN, buf, NO_TLS, 0, 0, 0);
zassert_ok(err, NULL);

err = download_client_event_handler(&evt);
Expand All @@ -396,7 +396,7 @@ ZTEST(fota_download_tests, test_download_with_offset)
/* Check that application is being notified when
* download_with_offset fails to start download
*/
err = fota_download_start(BASE_DOMAIN, buf, NO_TLS, 0, 0);
err = fota_download_any(BASE_DOMAIN, buf, NO_TLS, 0, 0, 0);
zassert_ok(err, NULL);

err = download_client_event_handler(&evt);
Expand All @@ -412,7 +412,7 @@ ZTEST(fota_download_tests, test_download_with_offset)


/* Successfully restart download with offset */
err = fota_download_start(BASE_DOMAIN, buf, NO_TLS, 0, 0);
err = fota_download_any(BASE_DOMAIN, buf, NO_TLS, 0, 0, 0);
zassert_ok(err, NULL);

err = download_client_event_handler(&evt);
Expand Down

0 comments on commit 69df0e6

Please sign in to comment.