diff --git a/doc/nrf/releases_and_maturity/releases/release-notes-changelog.rst b/doc/nrf/releases_and_maturity/releases/release-notes-changelog.rst index 74fbf3eb9f59..8b9df4478333 100644 --- a/doc/nrf/releases_and_maturity/releases/release-notes-changelog.rst +++ b/doc/nrf/releases_and_maturity/releases/release-notes-changelog.rst @@ -543,6 +543,18 @@ Libraries for networking * Fixed the warning due to missing ``https`` download protocol. +* :ref:`lib_downloader` library: + + * Updated to support Proxy-URI option and an authentication callback after connecting. + +* :ref:`lib_fota_download` library: + + * Updated to use the :ref:`lib_downloader` library for CoAP downloads. + +* :ref:`lib_nrf_cloud` library: + + * Updated to use the :ref:`lib_downloader` library for CoAP downloads. + Libraries for NFC ----------------- diff --git a/include/net/downloader.h b/include/net/downloader.h index 3a731acf8839..a56a764017a0 100644 --- a/include/net/downloader.h +++ b/include/net/downloader.h @@ -185,6 +185,16 @@ struct downloader_host_cfg { * Set to @c AF_UNSPEC (0) to fallback to @c AF_INET if @c AF_INET6 does not work. */ int family; + /** + * Callback to do client authentication. + * This is called after connecting. + */ + int (*auth_cb)(int sock); + /** + * CoAP Proxy-URI option. + * This string is used in case you are requesting a proxied file from a CoAP server. + */ + const char *proxy_uri; }; /** diff --git a/include/net/fota_download.h b/include/net/fota_download.h index 6a45cbf18580..fbb24ebcf726 100644 --- a/include/net/fota_download.h +++ b/include/net/fota_download.h @@ -63,11 +63,6 @@ enum fota_download_evt_id { /** FOTA download abandoned due to a cancellation request. */ FOTA_DOWNLOAD_EVT_CANCELLED, - - /** Resume the download at offset. - * Only generated if @kconfig{CONFIG_FOTA_DOWNLOAD_EXTERNAL_DL} is enabled. - */ - FOTA_DOWNLOAD_EVT_RESUME_OFFSET, }; /** @@ -101,8 +96,6 @@ struct fota_download_evt { enum fota_download_error_cause cause; /** Download progress %. */ int progress; - /** Resume at offset @ref FOTA_DOWNLOAD_EVT_RESUME_OFFSET */ - size_t resume_offset; }; }; @@ -152,6 +145,32 @@ 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 Download the given file with the specified image type from the given host. + * + * Identical to fota_download_start_with_image_type(), + * but with additional host configuration options. + * + * @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 Security tag you want to use with COAPS. Pass -1 to disable DTLS. + * @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, no fragmentation is used. + * @param expected_type Type of firmware file to be downloaded and installed. + * @param host_cfg Additional host configuration options. + * + * @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_with_host_cfg(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, + const struct downloader_host_cfg *host_cfg); + /**@brief Start downloading the given file of any image type from the given host. * @@ -281,31 +300,6 @@ int fota_download_s0_active_get(bool *const s0_active); */ int fota_download_b1_file_parse(char *s0_s1_files); -/**@brief Start a FOTA download using an external download client. - * Requires @kconfig{CONFIG_FOTA_DOWNLOAD_EXTERNAL_DL} to be enabled. - * - * @param host Name of host. - * @param file File path of the firmware image. - * @param expected_type Type of firmware image to be installed. - * @param image_size Size of the firmware image. - * - * @retval 0 If successful. - * Otherwise, a (negative) error code is returned. - */ -int fota_download_external_start(const char *host, const char *file, - const enum dfu_target_image_type expected_type, - const size_t image_size); - -/**@brief Handle a download event from an external download client. - * Requires @kconfig{CONFIG_FOTA_DOWNLOAD_EXTERNAL_DL} to be enabled. - * - * @param evt Download event. - * - * @retval 0 If successful. - * Otherwise, a (negative) error code is returned. - */ -int fota_download_external_evt_handle(struct downloader_evt const *const evt); - #ifdef __cplusplus } #endif diff --git a/subsys/net/lib/downloader/Kconfig b/subsys/net/lib/downloader/Kconfig index a905ec849412..0e91692f95fe 100644 --- a/subsys/net/lib/downloader/Kconfig +++ b/subsys/net/lib/downloader/Kconfig @@ -32,7 +32,7 @@ config DOWNLOADER_SHELL config DOWNLOADER_TRANSPORT_PARAMS_SIZE int "Maximum transport parameter size" - default 128 + default 256 config DOWNLOADER_TRANSPORT_HTTP bool "HTTP transport" diff --git a/subsys/net/lib/downloader/src/transports/coap.c b/subsys/net/lib/downloader/src/transports/coap.c index 72e427411c67..39764873ee90 100644 --- a/subsys/net/lib/downloader/src/transports/coap.c +++ b/subsys/net/lib/downloader/src/transports/coap.c @@ -25,6 +25,9 @@ LOG_MODULE_DECLARE(downloader, CONFIG_DOWNLOADER_LOG_LEVEL); #define FILENAME_SIZE CONFIG_DOWNLOADER_MAX_FILENAME_SIZE #define COAP_PATH_ELEM_DELIM "/" +#define COAP "coap://" +#define COAPS "coaps://" + struct transport_params_coap { /** Flag whether config is set */ bool cfg_set; @@ -54,6 +57,10 @@ struct transport_params_coap { bool new_data_req; /** Request retransmission */ bool retransmission_req; + /* Proxy-URI option value */ + const char *proxy_uri; + /* Client auth callback */ + int (*auth_cb)(int sock); }; BUILD_ASSERT(CONFIG_DOWNLOADER_TRANSPORT_PARAMS_SIZE >= sizeof(struct transport_params_coap)); @@ -280,11 +287,8 @@ static int coap_request_send(struct downloader *dl) return err; } - err = dl_parse_url_file(dl->file, file, sizeof(file)); - if (err) { - LOG_ERR("Unable to parse url"); - return err; - } + LOG_DBG("dl->file: %s", dl->file); + strncpy(file, dl->file, sizeof(file) - 1); path_elem = strtok_r(file, COAP_PATH_ELEM_DELIM, &path_elem_saveptr); do { @@ -308,6 +312,15 @@ static int coap_request_send(struct downloader *dl) return err; } + if (coap->proxy_uri != NULL) { + err = coap_packet_append_option(&request, COAP_OPTION_PROXY_URI, + coap->proxy_uri, strlen(coap->proxy_uri)); + if (err) { + LOG_ERR("Unable to add Proxy-URI option"); + return err; + } + } + if (!has_pending(dl)) { struct coap_transmission_parameters params = coap_get_transmission_parameters(); @@ -342,9 +355,9 @@ static int coap_request_send(struct downloader *dl) static bool dl_coap_proto_supported(struct downloader *dl, const char *url) { - if (strncmp(url, "coaps://", 8) == 0) { + if (strncmp(url, COAPS, (sizeof(COAPS) - 1)) == 0) { return true; - } else if (strncmp(url, "coap://", 7) == 0) { + } else if (strncmp(url, COAP, (sizeof(COAP) - 1)) == 0) { return true; } @@ -369,14 +382,14 @@ static int dl_coap_init(struct downloader *dl, struct downloader_host_cfg *dl_ho coap->cfg = tmp_cfg; coap->cfg_set = cfg_set; } else { - coap->cfg.block_size = 5; + coap->cfg.block_size = COAP_BLOCK_1024; coap->cfg.max_retransmission = 4; } coap->sock.proto = IPPROTO_UDP; coap->sock.type = SOCK_DGRAM; - if (strncmp(url, "coaps://", 8) == 0 || + if (strncmp(url, COAPS, (sizeof(COAPS) - 1)) == 0 || (dl_host_cfg->sec_tag_count != 0 && dl_host_cfg->sec_tag_list != NULL)) { coap->sock.proto = IPPROTO_DTLS_1_2; coap->sock.type = SOCK_DGRAM; @@ -405,6 +418,10 @@ static int dl_coap_init(struct downloader *dl, struct downloader_host_cfg *dl_ho coap->sock.type |= SOCK_NATIVE_TLS; } + /* Copy proxy-uri and auth-cb to internal struct */ + coap->proxy_uri = dl_host_cfg->proxy_uri; + coap->auth_cb = dl_host_cfg->auth_cb; + return 0; } @@ -448,6 +465,11 @@ static int dl_coap_connect(struct downloader *dl) coap->new_data_req = true; + /* Run auth callback if set */ + if (coap->auth_cb != NULL) { + return coap->auth_cb(coap->sock.fd); + } + return err; } diff --git a/subsys/net/lib/downloader/src/transports/http.c b/subsys/net/lib/downloader/src/transports/http.c index 439422ea1702..ec54915e6687 100644 --- a/subsys/net/lib/downloader/src/transports/http.c +++ b/subsys/net/lib/downloader/src/transports/http.c @@ -430,11 +430,11 @@ static int http_parse(struct downloader *dl, size_t len) static bool dl_http_proto_supported(struct downloader *dl, const char *url) { - if (strncmp(url, HTTPS, strlen(HTTPS)) == 0) { + if (strncmp(url, HTTPS, (sizeof(HTTPS) - 1)) == 0) { return true; } - if (strncmp(url, HTTP, strlen(HTTP)) == 0) { + if (strncmp(url, HTTP, (sizeof(HTTP) - 1)) == 0) { return true; } @@ -458,8 +458,8 @@ static int dl_http_init(struct downloader *dl, struct downloader_host_cfg *dl_ho http->sock.proto = IPPROTO_TCP; http->sock.type = SOCK_STREAM; - if (strncmp(url, HTTPS, strlen(HTTPS)) == 0 || - (strncmp(url, HTTP, strlen(HTTP)) != 0 && + if (strncmp(url, HTTPS, (sizeof(HTTPS) - 1)) == 0 || + (strncmp(url, HTTP, (sizeof(HTTP) - 1)) != 0 && (dl_host_cfg->sec_tag_count != 0 && dl_host_cfg->sec_tag_list != NULL))) { http->sock.proto = IPPROTO_TLS_1_2; http->sock.type = SOCK_STREAM; diff --git a/subsys/net/lib/fota_download/Kconfig b/subsys/net/lib/fota_download/Kconfig index 5c99846fa9a8..c43daa4c159a 100644 --- a/subsys/net/lib/fota_download/Kconfig +++ b/subsys/net/lib/fota_download/Kconfig @@ -66,10 +66,6 @@ config FOTA_DOWNLOAD_SEC_TAG_LIST_SIZE_MAX help Maximum size of the list of security tags used to store TLS credentials. -config FOTA_DOWNLOAD_EXTERNAL_DL - bool "Use external download events to perform FOTA updates" - select EXPERIMENTAL - module=FOTA_DOWNLOAD module-dep=LOG module-str=Firmware Over the Air Download diff --git a/subsys/net/lib/fota_download/src/fota_download.c b/subsys/net/lib/fota_download/src/fota_download.c index b206124c424e..3432712a312d 100644 --- a/subsys/net/lib/fota_download/src/fota_download.c +++ b/subsys/net/lib/fota_download/src/fota_download.c @@ -25,11 +25,6 @@ LOG_MODULE_REGISTER(fota_download, CONFIG_FOTA_DOWNLOAD_LOG_LEVEL); -#if defined(CONFIG_FOTA_DOWNLOAD_EXTERNAL_DL) -static size_t ext_file_sz; -static size_t ext_rcvd_sz; -#endif - static fota_download_callback_t callback; static const char *dl_host; static const char *dl_file; @@ -105,15 +100,6 @@ static void send_progress(int progress) #endif } -static void send_ext_resume(const size_t offset) -{ -#if defined(CONFIG_FOTA_DOWNLOAD_EXTERNAL_DL) - const struct fota_download_evt evt = { .id = FOTA_DOWNLOAD_EVT_RESUME_OFFSET, - .resume_offset = offset }; - callback(&evt); -#endif -} - static void stopped(void) { atomic_clear_bit(&flags, FLAG_DOWNLOADING); @@ -143,27 +129,16 @@ static void dfu_target_callback_handler(enum dfu_target_evt_id evt) static size_t file_size_get(size_t *size) { -#if defined(CONFIG_FOTA_DOWNLOAD_EXTERNAL_DL) - *size = ext_file_sz; - return 0; -#endif return downloader_file_size_get(&dl, size); } static size_t downloaded_size_get(size_t *size) { -#if defined(CONFIG_FOTA_DOWNLOAD_EXTERNAL_DL) - *size = ext_rcvd_sz; - return 0; -#endif return downloader_downloaded_size_get(&dl, size); } static int dl_cancel(void) { -#if defined(CONFIG_FOTA_DOWNLOAD_EXTERNAL_DL) - return 0; -#endif return downloader_cancel(&dl); } @@ -264,10 +239,6 @@ static int downloader_callback(const struct downloader_evt *event) } } -#if defined(CONFIG_FOTA_DOWNLOAD_EXTERNAL_DL) - ext_rcvd_sz += event->fragment.len; -#endif - err = dfu_target_write(event->fragment.buf, event->fragment.len); if (err && err == -EINVAL) { LOG_INF("Image refused"); @@ -321,7 +292,8 @@ static int downloader_callback(const struct downloader_evt *event) /* In case of socket errors we can return 0 to retry/continue, * or non-zero to stop */ - if ((socket_retries_left) && (event->error == -ECONNRESET)) { + if ((socket_retries_left) + && ((event->error == -ECONNRESET) || (event->error == -EAGAIN))) { LOG_WRN("Download socket error. %d retries left...", socket_retries_left); socket_retries_left--; @@ -371,11 +343,6 @@ static int downloader_callback(const struct downloader_evt *event) static int get_from_offset(const size_t offset) { - if (IS_ENABLED(CONFIG_FOTA_DOWNLOAD_EXTERNAL_DL)) { - send_ext_resume(offset); - return 0; - } - int err = downloader_get_with_host_and_file(&dl, &dl_host_cfg, dl_host, dl_file, offset); if (err != 0) { @@ -533,47 +500,21 @@ static void set_host_and_file(char const *const host, char const *const file) dl_file = file; } -#if defined(CONFIG_FOTA_DOWNLOAD_EXTERNAL_DL) -int fota_download_external_evt_handle(struct downloader_evt const *const evt) -{ - return downloader_callback(evt); -} - -int fota_download_external_start(const char *host, const char *file, - const enum dfu_target_image_type expected_type, - const size_t image_size) +int fota_download_with_host_cfg(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, + const struct downloader_host_cfg *host_cfg) { - if (host == NULL || file == NULL || callback == NULL || image_size == 0) { - return -EINVAL; - } - - if (atomic_test_and_set_bit(&flags, FLAG_DOWNLOADING)) { - return -EALREADY; - } - - atomic_clear_bit(&flags, FLAG_STOPPED); - atomic_clear_bit(&flags, FLAG_RESUME); - set_error_state(FOTA_DOWNLOAD_ERROR_CAUSE_NO_ERROR); - - set_host_and_file(host, file); - - socket_retries_left = CONFIG_FOTA_SOCKET_RETRIES; - - img_type_expected = expected_type; - ext_file_sz = image_size; - ext_rcvd_sz = 0; - - atomic_set_bit(&flags, FLAG_FIRST_FRAGMENT); - - return 0; + dl_host_cfg = *host_cfg; + LOG_DBG("Downloading %s/%s", host, file); + return fota_download_start_with_image_type(host, file, sec_tag, + pdn_id, fragment_size, expected_type); } -#endif /* CONFIG_FOTA_DOWNLOAD_EXTERNAL_DL */ 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) { - __ASSERT_NO_MSG(!IS_ENABLED(CONFIG_FOTA_DOWNLOAD_EXTERNAL_DL)); if (host == NULL || file == NULL || callback == NULL) { return -EINVAL; diff --git a/subsys/net/lib/nrf_cloud/Kconfig.nrf_cloud_coap b/subsys/net/lib/nrf_cloud/Kconfig.nrf_cloud_coap index e82968c574f6..b2d191926f4a 100644 --- a/subsys/net/lib/nrf_cloud/Kconfig.nrf_cloud_coap +++ b/subsys/net/lib/nrf_cloud/Kconfig.nrf_cloud_coap @@ -68,6 +68,7 @@ endif # WIFI config NRF_CLOUD_COAP_DOWNLOADS bool "Download files using CoAP instead of HTTP [EXPERIMENTAL]" depends on NRF_CLOUD_COAP + select DOWNLOADER_TRANSPORT_COAP select EXPERIMENTAL help Use nRF Cloud CoAP's proxy download resource to download files for FOTA and P-GPS. diff --git a/subsys/net/lib/nrf_cloud/Kconfig.nrf_cloud_fota b/subsys/net/lib/nrf_cloud/Kconfig.nrf_cloud_fota index 7ea7f4f62d10..ca5247e67a44 100644 --- a/subsys/net/lib/nrf_cloud/Kconfig.nrf_cloud_fota +++ b/subsys/net/lib/nrf_cloud/Kconfig.nrf_cloud_fota @@ -50,7 +50,6 @@ config NRF_CLOUD_FOTA_POLL bool "FOTA job polling helpers (REST/CoAP)" depends on !NRF_CLOUD_FOTA depends on FOTA_DOWNLOAD - select FOTA_DOWNLOAD_EXTERNAL_DL if NRF_CLOUD_COAP_DOWNLOADS help When enabled, nRF Cloud FOTA job polling helpers will be built. These functions make it easy to request, download, and handle modem, boot, diff --git a/subsys/net/lib/nrf_cloud/coap/include/nrf_cloud_coap_transport.h b/subsys/net/lib/nrf_cloud/coap/include/nrf_cloud_coap_transport.h index ec46ae2402ef..2e7af845722c 100644 --- a/subsys/net/lib/nrf_cloud/coap/include/nrf_cloud_coap_transport.h +++ b/subsys/net/lib/nrf_cloud/coap/include/nrf_cloud_coap_transport.h @@ -97,18 +97,17 @@ int nrf_cloud_coap_transport_pause(struct nrf_cloud_coap_client *const client); */ int nrf_cloud_coap_transport_resume(struct nrf_cloud_coap_client *const client); -/**@brief Get the CoAP options required to perform a proxy download. +/**@brief Get the URI required to perform a proxy download. * - * @param opt_accept Option to be populated with COAP_OPTION_ACCEPT details. - * @param opt_proxy_uri Option to be populated with COAP_OPTION_PROXY_URI details. + * @param uri Buffer to store the URI. + * @param uri_len Length of the URI buffer. * @param host Download host. * @param path Download file path. * * @return 0 if successful, otherwise a negative error code. */ -int nrf_cloud_coap_transport_proxy_dl_opts_get(struct coap_client_option *const opt_accept, - struct coap_client_option *const opt_proxy_uri, - char const *const host, char const *const path); +int nrf_cloud_coap_transport_proxy_dl_uri_get(char *const uri, size_t uri_len, + char const *const host, char const *const path); /**@brief Check if device is connected and authorized to use nRF Cloud CoAP. * diff --git a/subsys/net/lib/nrf_cloud/coap/src/nrf_cloud_coap_transport.c b/subsys/net/lib/nrf_cloud/coap/src/nrf_cloud_coap_transport.c index 83bf54716fde..74912150df7b 100644 --- a/subsys/net/lib/nrf_cloud/coap/src/nrf_cloud_coap_transport.c +++ b/subsys/net/lib/nrf_cloud/coap/src/nrf_cloud_coap_transport.c @@ -928,49 +928,33 @@ int nrf_cloud_coap_transport_resume(struct nrf_cloud_coap_client *const client) #define PROXY_URI_DL_HTTPS_LEN (sizeof(PROXY_URI_DL_HTTPS) - 1) #define PROXY_URI_DL_SEP "/" #define PROXY_URI_DL_SEP_LEN (sizeof(PROXY_URI_DL_SEP) - 1) -#define PROXY_URI_ADDED_LEN (PROXY_URI_DL_HTTPS_LEN + PROXY_URI_DL_SEP_LEN) -int nrf_cloud_coap_transport_proxy_dl_opts_get(struct coap_client_option *const opt_accept, - struct coap_client_option *const opt_proxy_uri, - char const *const host, char const *const path) +int nrf_cloud_coap_transport_proxy_dl_uri_get(char *const uri, size_t uri_len, + char const *const host, char const *const path) { - __ASSERT_NO_MSG(opt_accept != NULL); - __ASSERT_NO_MSG(opt_proxy_uri != NULL); + __ASSERT_NO_MSG(uri != NULL); __ASSERT_NO_MSG(host != NULL); __ASSERT_NO_MSG(path != NULL); - size_t uri_idx = 0; size_t host_len = strlen(host); size_t path_len = strlen(path); - opt_accept->code = COAP_OPTION_ACCEPT; - opt_accept->len = 1; - opt_accept->value[0] = COAP_CONTENT_FORMAT_TEXT_PLAIN; + const size_t needed_len = + PROXY_URI_DL_HTTPS_LEN + host_len + PROXY_URI_DL_SEP_LEN + path_len; - opt_proxy_uri->code = COAP_OPTION_PROXY_URI; - opt_proxy_uri->len = host_len + path_len + PROXY_URI_ADDED_LEN; - - if (opt_proxy_uri->len > CONFIG_COAP_EXTENDED_OPTIONS_LEN_VALUE) { + if (needed_len > uri_len) { LOG_ERR("Host and path for CoAP proxy GET is too large: %u bytes", - opt_proxy_uri->len); - LOG_INF("Increase CONFIG_COAP_EXTENDED_OPTIONS_LEN_VALUE, current value: %d", - CONFIG_COAP_EXTENDED_OPTIONS_LEN_VALUE); + needed_len); return -E2BIG; } /* We don't want a NULL terminated string, so just copy the data to create the full URI */ - memcpy(&opt_proxy_uri->value[uri_idx], PROXY_URI_DL_HTTPS, PROXY_URI_DL_HTTPS_LEN); - uri_idx += PROXY_URI_DL_HTTPS_LEN; - - memcpy(&opt_proxy_uri->value[uri_idx], host, host_len); - uri_idx += host_len; - - memcpy(&opt_proxy_uri->value[uri_idx], PROXY_URI_DL_SEP, PROXY_URI_DL_SEP_LEN); - uri_idx += PROXY_URI_DL_SEP_LEN; - - memcpy(&opt_proxy_uri->value[uri_idx], path, path_len); + memcpy(uri, PROXY_URI_DL_HTTPS, PROXY_URI_DL_HTTPS_LEN); + memcpy(&uri[PROXY_URI_DL_HTTPS_LEN], host, host_len); + memcpy(&uri[PROXY_URI_DL_HTTPS_LEN + host_len], PROXY_URI_DL_SEP, PROXY_URI_DL_SEP_LEN); + memcpy(&uri[PROXY_URI_DL_HTTPS_LEN + host_len + PROXY_URI_DL_SEP_LEN], path, path_len); - LOG_DBG("Proxy URI: %.*s", opt_proxy_uri->len, opt_proxy_uri->value); + LOG_DBG("Proxy URI: %.*s", needed_len, uri); return 0; } diff --git a/subsys/net/lib/nrf_cloud/include/nrf_cloud_download.h b/subsys/net/lib/nrf_cloud/include/nrf_cloud_download.h index 285f170ad3da..1d3322d891aa 100644 --- a/subsys/net/lib/nrf_cloud/include/nrf_cloud_download.h +++ b/subsys/net/lib/nrf_cloud/include/nrf_cloud_download.h @@ -51,13 +51,6 @@ struct nrf_cloud_download_data { /* Downloader data */ struct downloader *dl; }; - -#if defined(CONFIG_NRF_CLOUD_COAP_DOWNLOADS) - /* Track the received bytes for CoAP downloads */ - size_t coap_rcvd_bytes; - /* Offset used when resuming a download */ - size_t resume_offset; -#endif }; /** @brief Start download. Only one download at a time is allowed. FOTA downloads have priority. @@ -71,9 +64,6 @@ int nrf_cloud_download_start(struct nrf_cloud_download_data *const cloud_dl); */ void nrf_cloud_download_cancel(void); -/** @brief Resume a CoAP download at the provided offset. */ -int nrf_cloud_download_coap_offset_resume(const size_t offset); - /** @brief Reset the active download state. Call when download has ended. */ void nrf_cloud_download_end(void); diff --git a/subsys/net/lib/nrf_cloud/src/nrf_cloud_download.c b/subsys/net/lib/nrf_cloud/src/nrf_cloud_download.c index 5a66f106dc91..42a87da402f0 100644 --- a/subsys/net/lib/nrf_cloud/src/nrf_cloud_download.c +++ b/subsys/net/lib/nrf_cloud/src/nrf_cloud_download.c @@ -34,239 +34,63 @@ static K_MUTEX_DEFINE(active_dl_mutex); static struct nrf_cloud_download_data active_dl = { .type = NRF_CLOUD_DL_TYPE_NONE }; #if defined(CONFIG_NRF_CLOUD_COAP_DOWNLOADS) -#define ACPT_IDX 0 -#define PRXY_IDX 1 -#define OPT_CNT 2 -/* CoAP option array */ -static struct coap_client_option cc_opts[OPT_CNT] = {0}; /* CoAP client to be used for file downloads */ static struct nrf_cloud_coap_client coap_client; -/* Workqueue item used to resume a downlaod */ -static struct k_work_delayable resume_work; -static void resume_work_fn(struct k_work *unused); - -static int coap_dl_init(void) -{ - k_work_init_delayable(&resume_work, resume_work_fn); - return nrf_cloud_coap_transport_init(&coap_client); -} - -static int coap_dl_connect_and_auth(void) -{ - int ret = nrf_cloud_coap_transport_connect(&coap_client); - - if (ret) { - LOG_ERR("CoAP connect failed, error; %d", ret); - return -EIO; - } - - ret = nrf_cloud_coap_transport_authenticate(&coap_client); - if (ret) { - LOG_ERR("CoAP authentication failed, error; %d", ret); - return -EACCES; - } - - return 0; -} - -static int fota_dl_evt_send(const struct downloader_evt *evt) -{ -#if defined(CONFIG_FOTA_DOWNLOAD_EXTERNAL_DL) - return fota_download_external_evt_handle(evt); -#endif - return -ENOTSUP; -} - -static int coap_dl_event_send(struct nrf_cloud_download_data const *const dl, - const struct downloader_evt *const evt) -{ - /* Send events as if we are the downoad_client */ - if (dl->type == NRF_CLOUD_DL_TYPE_FOTA) { - return fota_dl_evt_send(evt); - } else if (dl->type == NRF_CLOUD_DL_TYPE_DL_CLIENT) { - return dl->dl->cfg.callback(evt); - } - - return -EINVAL; -} - -static int coap_dl_disconnect(void) -{ - return nrf_cloud_coap_transport_disconnect(&coap_client); -} - -static void coap_dl_cb(int16_t result_code, size_t offset, const uint8_t *payload, size_t len, - bool last_block, void *user_data) +int nrf_cloud_download_handle_coap_auth(int socket) { - int ret; - bool send_closed_evt = false; - bool send_done_evt = last_block; - bool stop_on_err = false; - struct nrf_cloud_download_data *dl = (struct nrf_cloud_download_data *)user_data; - struct downloader_evt evt = {0}; - - LOG_DBG("CoAP result: %d, offset: 0x%X, len: 0x%X, last_block: %d", - result_code, offset, len, last_block); - - if (result_code == COAP_RESPONSE_CODE_CONTENT) { - evt.id = DOWNLOADER_EVT_FRAGMENT; - evt.fragment.buf = payload; - evt.fragment.len = len; - } else if (result_code == -ECANCELED) { - LOG_DBG("CoAP request canceled"); - /* This is not actually an error, just use the error event to indicate that - * the transfer has been canceled - */ - evt.id = DOWNLOADER_EVT_ERROR; - evt.error = -ECANCELED; - (void)coap_dl_event_send(dl, &evt); - return; - } else if (result_code != COAP_RESPONSE_CODE_OK) { - LOG_ERR("Unexpected CoAP result: %d", result_code); - LOG_DBG("CoAP response: %.*s", len, payload); - evt.id = DOWNLOADER_EVT_ERROR; - /* Use -ECONNRESET to trigger retry mechanism used by fota_download and - * the P-GPS download event handler - */ - evt.error = -ECONNRESET; - stop_on_err = true; - } - - ret = coap_dl_event_send(dl, &evt); - - if (evt.id == DOWNLOADER_EVT_FRAGMENT) { - if (ret == 0) { - /* Fragment was successfully processed */ - dl->coap_rcvd_bytes += len; - } else if ((ret == -1) && (dl->type == NRF_CLOUD_DL_TYPE_FOTA)) { - /* For FOTA, -1 on a fragment event requires a closed event - * that will generate a request for restart. - */ - send_closed_evt = true; - send_done_evt = false; - ret = 0; - } - } else if ((ret == 0) && (evt.error == -ECONNRESET)) { - /* Retry if the event handler returned zero during an error event */ - dl->resume_offset = dl->coap_rcvd_bytes; - k_work_schedule(&resume_work, K_SECONDS(1)); - return; - } - - if (ret || stop_on_err) { - send_closed_evt = true; - send_done_evt = false; - stop_on_err = true; - } - - if (send_done_evt) { - LOG_INF("Download complete"); - - memset(&evt, 0, sizeof(evt)); - evt.id = DOWNLOADER_EVT_DONE; - - ret = coap_dl_event_send(dl, &evt); - if (ret) { - /* Send a closed event on error */ - send_closed_evt = true; - stop_on_err = true; - } - - ret = coap_dl_disconnect(); - if (ret && (ret != -ENOTCONN)) { - LOG_WRN("Failed to disconnect CoAP transport, error: %d", ret); - } + int err = 0; + struct nrf_cloud_coap_client *client = &coap_client; - if (dl->type == NRF_CLOUD_DL_TYPE_FOTA) { - /* fota_download expects a closed event when the download is done */ - send_closed_evt = true; - } + /* Initialize client */ + err = nrf_cloud_coap_transport_init(client); + if (err) { + LOG_ERR("Failed to initialize CoAP client, error: %d", err); + return err; } - if (send_closed_evt) { - memset(&evt, 0, sizeof(evt)); - evt.id = DOWNLOADER_EVT_STOPPED; - (void)coap_dl_event_send(dl, &evt); - } + /* We are already connected using the given socket */ + k_mutex_lock(&client->mutex, K_FOREVER); + client->sock = socket; + client->cc.fd = socket; + k_mutex_unlock(&client->mutex); - if (stop_on_err) { - LOG_ERR("CoAP download error, stopping download"); - nrf_cloud_download_end(); + /* Authenticate */ + err = nrf_cloud_coap_transport_authenticate(client); + if (err) { + LOG_ERR("Failed to authenticate CoAP client, error: %d", err); + return err; } -} -#define MAX_RETRIES 5 -#define PROXY_RSC_OFFSET_TMPLT NRF_CLOUD_COAP_PROXY_RSC "?offset=%u" -#define PROXY_RSC_BUF_SZ sizeof(PROXY_RSC_OFFSET_TMPLT) + 10 -static int coap_dl_start(struct nrf_cloud_download_data *const dl, const size_t offset) -{ - static char rsc_path_offset[PROXY_RSC_BUF_SZ]; - - int err; - int retry = 0; - struct coap_client *cc = &coap_client.cc; - - struct coap_client_request request = { - .method = COAP_METHOD_GET, - .confirmable = true, - .path = NRF_CLOUD_COAP_PROXY_RSC, - .fmt = COAP_CONTENT_FORMAT_APP_OCTET_STREAM, - .payload = NULL, - .len = 0, - .cb = coap_dl_cb, - .user_data = dl, - .options = cc_opts, - .num_options = OPT_CNT - }; - - if (offset > 0) { - /* Use the offset parameter in the resource path */ - err = snprintk(rsc_path_offset, sizeof(rsc_path_offset), - PROXY_RSC_OFFSET_TMPLT, offset); - if ((err < 0) || (err >= sizeof(rsc_path_offset))) { - LOG_ERR("Could not format CoAP proxy download resource"); - return -EIO; - } - request.path = rsc_path_offset; - } + /* Clean up client */ + k_mutex_lock(&client->mutex, K_FOREVER); + client->sock = -1; + client->cc.fd = -1; + client->authenticated = false; + k_mutex_unlock(&client->mutex); - while ((err = coap_client_req(cc, cc->fd, NULL, &request, NULL)) == -EAGAIN) { - if (retry++ > MAX_RETRIES) { - LOG_ERR("Timeout waiting for CoAP client to be available"); - return -ETIMEDOUT; - } - LOG_DBG("CoAP client busy"); - k_sleep(K_MSEC(500)); - } - - if (err == 0) { - LOG_DBG("Sent CoAP download request, offset: %u", offset); - } else { - LOG_ERR("Error sending CoAP request: %d", err); - } - - return err; + return 0; } static int coap_dl(struct nrf_cloud_download_data *const dl) { + static char proxy_uri[CONFIG_FOTA_DOWNLOAD_RESOURCE_LOCATOR_LENGTH]; #if defined(CONFIG_FOTA_DOWNLOAD) && defined(CONFIG_NRF_CLOUD_FOTA_TYPE_BOOT_SUPPORTED) - static char buf[CONFIG_FOTA_DOWNLOAD_RESOURCE_LOCATOR_LENGTH]; + char buf[CONFIG_FOTA_DOWNLOAD_RESOURCE_LOCATOR_LENGTH]; #endif const char *file_path = dl->path; - int ret = coap_dl_init(); + int ret = 0; + struct downloader_host_cfg host_cfg = { + .cid = true, + .auth_cb = nrf_cloud_download_handle_coap_auth, + .proxy_uri = proxy_uri, + }; if (ret) { LOG_ERR("Failed to initialize CoAP download, error: %d", ret); return ret; } - ret = coap_dl_connect_and_auth(); - if (ret) { - return ret; - } - #if defined(CONFIG_FOTA_DOWNLOAD) && defined(CONFIG_NRF_CLOUD_FOTA_TYPE_BOOT_SUPPORTED) if (dl->type == NRF_CLOUD_DL_TYPE_FOTA) { /* Copy file path to modifiable buffer and check for a bootloader file */ @@ -274,99 +98,23 @@ static int coap_dl(struct nrf_cloud_download_data *const dl) ret = fota_download_b1_file_parse(buf); if (ret == 0) { - /* A bootload file has been found */ + /* A bootloader file has been found */ file_path = buf; } } #endif - /* Reset the received count */ - dl->coap_rcvd_bytes = 0; - dl->resume_offset = 0; - - /* Get the options for the proxy download */ - ret = nrf_cloud_coap_transport_proxy_dl_opts_get(&cc_opts[ACPT_IDX], - &cc_opts[PRXY_IDX], - dl->host, file_path); + ret = nrf_cloud_coap_transport_proxy_dl_uri_get( + proxy_uri, ARRAY_SIZE(proxy_uri), dl->host, file_path); if (ret) { - LOG_ERR("Failed to set CoAP options, error: %d", ret); + LOG_ERR("Failed to get CoAP proxy URL, error: %d", ret); return ret; } - if (dl->type == NRF_CLOUD_DL_TYPE_FOTA) { -#if defined(CONFIG_FOTA_DOWNLOAD_EXTERNAL_DL) - ret = fota_download_external_start(dl->host, file_path, dl->fota.expected_type, - (size_t)dl->fota.img_sz); - if (ret) { - LOG_ERR("Failed to start FOTA download, error: %d", ret); - return ret; - } -#else - return -ENOTSUP; -#endif - } - - return coap_dl_start(dl, 0); -} - -int nrf_cloud_download_coap_offset_resume(const size_t offset) -{ - int err = 0; - - k_mutex_lock(&active_dl_mutex, K_FOREVER); - - if ((active_dl.type == NRF_CLOUD_DL_TYPE_FOTA) || - (active_dl.type == NRF_CLOUD_DL_TYPE_DL_CLIENT)) { - active_dl.resume_offset = offset; - k_work_schedule(&resume_work, K_SECONDS(1)); - } else if (active_dl.type == NRF_CLOUD_DL_TYPE_NONE) { - LOG_ERR("No active download, cannot resume"); - err = -ENODEV; - } else { - LOG_ERR("Invalid download type (%d), cannot resume", active_dl.type); - err = -EINVAL; - } - - k_mutex_unlock(&active_dl_mutex); - - return err; -} - -static void resume_work_fn(struct k_work *unused) -{ - int ret; - - if (active_dl.type == NRF_CLOUD_DL_TYPE_NONE) { - LOG_ERR("No active download, cannot resume"); - return; - } - - /* Ensure current request is canceled */ - coap_client_cancel_requests(&coap_client.cc); - - ret = coap_dl_connect_and_auth(); - if (ret == 0) { - LOG_DBG("Resuming download at offset: %u", active_dl.resume_offset); - ret = coap_dl_start(&active_dl, active_dl.resume_offset); - } - - /* On failure, send the events required to generate the error/done status */ - if (ret) { - struct downloader_evt evt = {0}; - - LOG_ERR("Failed to resume CoAP download"); - - /* Send a non-recoverable error event (not ECONN) */ - evt.id = DOWNLOADER_EVT_ERROR; - evt.error = -EIO; - (void)coap_dl_event_send(&active_dl, &evt); - - /* Send a closed event to ensure the terminal fota_download event is generated */ - if (active_dl.type == NRF_CLOUD_DL_TYPE_FOTA) { - memset(&evt, 0, sizeof(evt)); - evt.id = DOWNLOADER_EVT_STOPPED; - (void)coap_dl_event_send(&active_dl, &evt); - } - } + return fota_download_with_host_cfg("coaps://" CONFIG_NRF_CLOUD_COAP_SERVER_HOSTNAME, + "proxy", dl->dl_host_conf.sec_tag_count ? + dl->dl_host_conf.sec_tag_list[0] : -1, + dl->dl_host_conf.pdn_id, dl->dl_host_conf.range_override, + dl->fota.expected_type, &host_cfg); } #endif /* NRF_CLOUD_COAP_DOWNLOADS */ @@ -428,10 +176,6 @@ static int dl_start(struct nrf_cloud_download_data *const cloud_dl) static int dl_disconnect(struct nrf_cloud_download_data *const dl) { -#if defined(CONFIG_NRF_CLOUD_COAP_DOWNLOADS) - return coap_dl_disconnect(); -#endif /* CONFIG_NRF_CLOUD_COAP_DOWNLOADS */ - return downloader_cancel(dl->dl); } @@ -479,10 +223,6 @@ void nrf_cloud_download_cancel(void) void nrf_cloud_download_end(void) { -#if defined(CONFIG_NRF_CLOUD_COAP_DOWNLOADS) - coap_dl_disconnect(); -#endif - k_mutex_lock(&active_dl_mutex, K_FOREVER); active_dl_reset(); k_mutex_unlock(&active_dl_mutex); diff --git a/subsys/net/lib/nrf_cloud/src/nrf_cloud_fota_poll.c b/subsys/net/lib/nrf_cloud/src/nrf_cloud_fota_poll.c index 0b893b0a833e..b0173b25721d 100644 --- a/subsys/net/lib/nrf_cloud/src/nrf_cloud_fota_poll.c +++ b/subsys/net/lib/nrf_cloud/src/nrf_cloud_fota_poll.c @@ -212,29 +212,6 @@ static void http_fota_dl_handler(const struct fota_download_evt *evt) case FOTA_DOWNLOAD_EVT_PROGRESS: LOG_DBG("FOTA download percent: %d%%", evt->progress); break; - case FOTA_DOWNLOAD_EVT_RESUME_OFFSET: - LOG_DBG("FOTA download resume at offset: %u", evt->resume_offset); - /* Event is only applicable if CoAP downloads are enabled */ -#if defined(CONFIG_NRF_CLOUD_COAP_DOWNLOADS) - int err = nrf_cloud_download_coap_offset_resume(evt->resume_offset); - - if (err) { - LOG_ERR("Failed to resume download, error: %d", err); - nrf_cloud_download_end(); - fota_status = NRF_CLOUD_FOTA_FAILED; - fota_status_details = FOTA_STATUS_DETAILS_DL_ERR; - - if (ctx_ptr->is_nonblocking) { - k_work_cancel_delayable(&ctx_ptr->timeout_work); - ctx_ptr->status_fn(fota_status, fota_status_details); - - (void)update_job_status(ctx_ptr); - } else { - k_sem_give(&fota_download_sem); - } - } -#endif /* CONFIG_NRF_CLOUD_COAP_DOWNLOADS */ - break; default: break; } diff --git a/tests/subsys/net/lib/downloader/CMakeLists.txt b/tests/subsys/net/lib/downloader/CMakeLists.txt index 45a2aa1f4982..63a742c1ee6f 100644 --- a/tests/subsys/net/lib/downloader/CMakeLists.txt +++ b/tests/subsys/net/lib/downloader/CMakeLists.txt @@ -36,7 +36,7 @@ target_compile_options(app PRIVATE -DCONFIG_DOWNLOADER_MAX_HOSTNAME_SIZE=256 -DCONFIG_DOWNLOADER_MAX_FILENAME_SIZE=256 - -DCONFIG_DOWNLOADER_TRANSPORT_PARAMS_SIZE=128 + -DCONFIG_DOWNLOADER_TRANSPORT_PARAMS_SIZE=256 -DCONFIG_DOWNLOADER_STACK_SIZE=2048 -DCONFIG_NET_SOCKETS_POSIX_NAMES=y -DCONFIG_NET_IPV6=y diff --git a/tests/subsys/net/lib/fota_download/CMakeLists.txt b/tests/subsys/net/lib/fota_download/CMakeLists.txt index e61aa1a1523d..2182f4284821 100644 --- a/tests/subsys/net/lib/fota_download/CMakeLists.txt +++ b/tests/subsys/net/lib/fota_download/CMakeLists.txt @@ -34,7 +34,7 @@ target_compile_options(app -DCONFIG_DOWNLOADER_STACK_SIZE=500 -DCONFIG_DOWNLOADER_MAX_FILENAME_SIZE=192 -DCONFIG_DOWNLOADER_MAX_HOSTNAME_SIZE=128 - -DCONFIG_DOWNLOADER_TRANSPORT_PARAMS_SIZE=128 + -DCONFIG_DOWNLOADER_TRANSPORT_PARAMS_SIZE=256 -DCONFIG_FW_MAGIC_LEN=32 -DABI_INFO_MAGIC=0xdededede -DCONFIG_FW_FIRMWARE_INFO_OFFSET=0x200 diff --git a/tests/subsys/net/lib/lwm2m_client_utils/CMakeLists.txt b/tests/subsys/net/lib/lwm2m_client_utils/CMakeLists.txt index 57a583422203..793101a555e5 100644 --- a/tests/subsys/net/lib/lwm2m_client_utils/CMakeLists.txt +++ b/tests/subsys/net/lib/lwm2m_client_utils/CMakeLists.txt @@ -36,7 +36,7 @@ set(options -DCONFIG_DOWNLOADER_STACK_SIZE=4096 -DCONFIG_DOWNLOADER_MAX_HOSTNAME_SIZE=128 -DCONFIG_DOWNLOADER_MAX_FILENAME_SIZE=128 - -DCONFIG_DOWNLOADER_TRANSPORT_PARAMS_SIZE=128 + -DCONFIG_DOWNLOADER_TRANSPORT_PARAMS_SIZE=256 -DCONFIG_LWM2M_FIRMWARE_UPDATE_OBJ_SUPPORT -DCONFIG_LWM2M_FIRMWARE_UPDATE_PULL_SUPPORT -DCONFIG_DFU_TARGET_MCUBOOT diff --git a/tests/subsys/net/lib/lwm2m_fota_utils/CMakeLists.txt b/tests/subsys/net/lib/lwm2m_fota_utils/CMakeLists.txt index 470fa1e5ae86..bd9b682a3751 100644 --- a/tests/subsys/net/lib/lwm2m_fota_utils/CMakeLists.txt +++ b/tests/subsys/net/lib/lwm2m_fota_utils/CMakeLists.txt @@ -35,7 +35,7 @@ set(options -DCONFIG_DOWNLOADER_STACK_SIZE=4096 -DCONFIG_DOWNLOADER_MAX_HOSTNAME_SIZE=128 -DCONFIG_DOWNLOADER_MAX_FILENAME_SIZE=128 - -DCONFIG_DOWNLOADER_TRANSPORT_PARAMS_SIZE=128 + -DCONFIG_DOWNLOADER_TRANSPORT_PARAMS_SIZE=256 -DCONFIG_LWM2M_FIRMWARE_UPDATE_OBJ_SUPPORT -DCONFIG_LWM2M_FIRMWARE_UPDATE_PULL_SUPPORT -DCONFIG_DFU_TARGET_MCUBOOT=y diff --git a/tests/subsys/net/lib/mcumgr_smp_client/CMakeLists.txt b/tests/subsys/net/lib/mcumgr_smp_client/CMakeLists.txt index 118183771b2f..125663f7012a 100644 --- a/tests/subsys/net/lib/mcumgr_smp_client/CMakeLists.txt +++ b/tests/subsys/net/lib/mcumgr_smp_client/CMakeLists.txt @@ -44,7 +44,7 @@ target_compile_options(app -DCONFIG_FOTA_DOWNLOAD_RESOURCE_LOCATOR_LENGTH=512 -DCONFIG_DOWNLOADER_MAX_HOSTNAME_SIZE=128 -DCONFIG_DOWNLOADER_MAX_FILENAME_SIZE=128 - -DCONFIG_DOWNLOADER_TRANSPORT_PARAMS_SIZE=128 + -DCONFIG_DOWNLOADER_TRANSPORT_PARAMS_SIZE=256 -DCONFIG_DOWNLOADER_STACK_SIZE=1024 -DCONFIG_DFU_TARGET_SMP=1 )