From e526be9002b88806cea8652f8c8201f3377a9528 Mon Sep 17 00:00:00 2001 From: Teemu Takaluoma Date: Thu, 8 Jul 2021 12:31:51 +0300 Subject: [PATCH] mbed-cloud-client 4.10.0 --- CHANGELOG.md | 50 +- CONTRIBUTING.md | 3 +- DOXYGEN_FRONTPAGE.md | 64 +-- .../linux-os/ds_linux_metrics_report.cpp | 10 +- .../psa-driver/source/psa_driver_crypto.c | 1 + .../storage/source/key_slot_allocator.c | 41 +- .../storage/source/storage_psa.cpp | 2 +- fota/bspatch/{common.h => bspatch_common.h} | 0 fota/bspatch/bspatch_private.h | 2 +- fota/bspatch_fota_mbed.c | 4 +- fota/fota.c | 500 +++++++++++++----- fota/fota_app_ifs.c | 16 +- fota/fota_app_ifs.h | 34 +- fota/fota_base.h | 8 + fota/fota_candidate.c | 28 +- fota/fota_config.h | 64 ++- fota/fota_crypto.c | 227 +++++--- fota/fota_crypto.h | 32 +- fota/fota_device_key.cpp | 33 +- fota/fota_device_key.h | 10 +- fota/fota_header_info.h | 8 +- fota/fota_internal.h | 38 +- fota/fota_manifest.h | 17 +- fota/fota_manifest_v3.c | 263 ++++++--- fota/fota_nvm_int.h | 10 +- fota/fota_platform_hooks.h | 2 +- fota/fota_shim_layer.cpp | 5 + fota/fota_source_profile_full.cpp | 10 +- fota/fota_source_profile_lite.c | 4 +- fota/fota_status.h | 73 +-- fota/mbed_lib.json | 8 +- .../mbed-os/fota_block_device_mbed_os.cpp | 53 ++ .../Configs/mbedTLS/pelion_mbedtls_config.h | 2 +- .../Source/PAL-Impl/Modules/TLS/pal_TLS.c | 14 +- .../ZephyrOS/Networking/fd_work_poll.c | 2 +- .../ZephyrOS/Networking/fd_work_poll.h | 2 +- .../Networking/fd_work_poll_polling.c | 2 +- .../ZephyrOS/Networking/pal_plat_network.c | 2 +- .../ZephyrOS/Platform/FlashIAP.cpp | 2 +- .../OS_Specific/ZephyrOS/Platform/FlashIAP.h | 2 +- .../ZephyrOS/Platform/FlashMap.cpp | 2 +- .../OS_Specific/ZephyrOS/Platform/FlashMap.h | 2 +- .../OS_Specific/ZephyrOS/RTOS/pal_plat_rtos.c | 69 +-- mbed-client/mbed-client-c/source/sn_nsdl.c | 1 + .../source/m2mconnectionhandlerpimpl.cpp | 17 +- .../source/m2mconnectionsecuritypimpl.cpp | 5 +- mbed-client/mbed-client/m2mbase.h | 12 +- mbed-client/mbed-client/m2mconfig.h | 13 +- mbed-client/mbed-client/m2mconstants.h | 4 +- .../mbed-client/m2minterfaceobserver.h | 5 + mbed-client/mbed-client/m2mobject.h | 1 + mbed-client/mbed-client/m2mobjectinstance.h | 1 + mbed-client/mbed-client/m2mresource.h | 1 + mbed-client/mbed-client/m2mresourcebase.h | 2 + mbed-client/mbed-client/m2mresourceinstance.h | 1 + mbed-client/mbed_lib.json | 4 +- mbed-client/source/include/m2mdiscover.h | 80 +++ mbed-client/source/include/m2mreporthandler.h | 20 +- mbed-client/source/m2mdiscover.cpp | 344 ++++++++++++ mbed-client/source/m2minterfaceimpl.cpp | 36 +- mbed-client/source/m2mnsdlinterface.cpp | 52 +- mbed-client/source/m2mobject.cpp | 24 +- mbed-client/source/m2mobjectinstance.cpp | 24 +- mbed-client/source/m2mreporthandler.cpp | 46 ++ mbed-client/source/m2mresource.cpp | 25 +- mbed-client/source/m2mresourcebase.cpp | 25 +- mbed-cloud-client/MbedCloudClient.h | 5 +- .../MbedCloudClientConfigCheck.h | 4 + mbed-coap/mbed-coap/sn_coap_header.h | 17 +- mbed-coap/mbed-coap/sn_config.h | 17 + .../source/include/sn_coap_header_internal.h | 4 +- .../include/sn_coap_protocol_internal.h | 40 +- mbed-coap/source/sn_coap_builder.c | 333 ++++++------ mbed-coap/source/sn_coap_parser.c | 338 ++++++------ mbed-coap/source/sn_coap_protocol.c | 468 ++++++++-------- multicast/libota.c | 150 +++--- multicast/multicast.cpp | 100 ++-- multicast/multicast.h | 1 + multicast/otaLIB.h | 10 + network-manager/source/NetworkManager.cpp | 8 +- .../source/include/NetworkManager_internal.h | 63 ++- .../source/include/nm_cbor_helper.h | 5 + .../source/include/nm_interface_manager.h | 6 +- network-manager/source/nm_cbor_helper.c | 256 ++++++++- .../source/nm_interface_manager.cpp | 91 +++- .../source/nm_resource_manager.cpp | 52 ++ source/ConnectorClient.cpp | 63 ++- source/MbedCloudClient.cpp | 2 + source/ServiceClient.cpp | 68 ++- source/include/ConnectorClient.h | 5 +- source/include/ServiceClient.h | 12 +- .../source/arm_uc_pal_linux_extensions.c | 29 +- zephyr/config/zephyr_default.h | 2 +- zephyr/config/zephyr_update.h | 2 +- 94 files changed, 3251 insertions(+), 1364 deletions(-) rename fota/bspatch/{common.h => bspatch_common.h} (100%) create mode 100644 mbed-client/source/include/m2mdiscover.h create mode 100644 mbed-client/source/m2mdiscover.cpp diff --git a/CHANGELOG.md b/CHANGELOG.md index 3996aa7ea..6a3db8a54 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,14 +1,60 @@ ## Changelog for Pelion Device Management Client +### Release 4.10.0 (07.07.2021) + +### Device Management Client + +- Updated Mbed CoAP to v5.1.11. +- Improved handling of "Bad requests" during bootstrapping. Now client will handle the recovery internally without reporting fatal certificate errors to upper level. + - Previously this was resulting in factory resets as this was handled as fatal storage failure. +- Fixed duplication of sent notifications, which sometimes happened if the application called `set_value()`in the `MbedCloudClient::on_registered()`callback. +- Added sleep state for `MbedCloudClient::on_status_changed()`. + + This makes `MbedCloudClient::set_queue_sleep_handler(callback_handler handler)` redundant. It's marked as deprecated. + +- Added support for LwM2M Discover. +- Allowed the application to control the maximum reconnection timeout using the `MBED_CONF_MBED_CLIENT_MAX_RECONNECT_TIMEOUT` flag. + + This flag ensures that the reconnection time doesn't go above the set maximum value. The default value is 4hrs, and the lowest acceptable value is 5min. + +#### Device Management Update Client + +- Added support for updating device firmware with a server-encrypted update image. + - Enabled by the new `MBED_CLOUD_CLIENT_FOTA_ENCRYPTION_SUPPORT` macro. + - Limitation: Not supported when `MBED_CLOUD_CLIENT_FOTA_CANDIDATE_BLOCK_SIZE` is not 1024. +- Changes to implementation of update candidate image encryption: + - Added a new `FOTA_USE_ENCRYPTED_ONE_TIME_FW_KEY` option to the `MBED_CLOUD_CLIENT_FOTA_KEY_ENCRYPTION` macro. + - Replaced `FOTA_USE_DEVICE_KEY` with `FOTA_USE_ENCRYPTED_ONE_TIME_FW_KEY` as the default value for `MBED_CLOUD_CLIENT_FOTA_KEY_ENCRYPTION` following a security vulnerability found in `FOTA_USE_DEVICE_KEY`. + +
+ For Mbed OS devices, using `FOTA_USE_ENCRYPTED_ONE_TIME_FW_KEY` is a breaking change that requires the new bootloader introduced in Device Management Client 4.10.0. + + In Device Management Client 4.10.0, `FOTA_USE_ENCRYPTED_ONE_TIME_FW_KEY` is the default value of the `MBED_CLOUD_CLIENT_FOTA_KEY_ENCRYPTION` macro. + + If you are upgrading to Device Management Client 4.10.0 but using the bootloader from a previous release, you must explicitly define `FOTA_USE_DEVICE_KEY`. + + We highly recommend using the bootloader from Device Management Client 4.10.0, which fixes a security vulnerability found in the bootloader from the 4.8.0/4.9.0 releases. +
+ + - Deprecated the `FOTA_USE_DEVICE_KEY` option, which will be removed in a future version. +- Changed `fota_app_defer()` behavior so that candidate image download or install resumes only after the device application explicitly calls `fota_app_resume()`. When the device reboots, the client invokes the download or install callbacks to request the device application’s approval to continue the download or installation. +- Added support for calling `fota_app_reject()` after `fota_app_defer()`. +- Added the `fota_app_postpone_reboot()` API. Calling this API postpones device reboot, which is required to complete the FOTA process, until the device application explicitly initiates reboot. +- Fix: Resuming download from the last successfully downloaded fragment was not previously supported on devices with an SD card, like the K64F. +- Fix: Support for resuming installation after an unexpected interruption (for example, power loss): + - Of the main or component image on Linux. + - Of a component image on an Mbed OS devices. +- Fix: Removed the candidate image file from its original path in Linux after FOTA completion. + ### Release 4.9.1 (17.06.2021) ### Device Management Client - Fixed the incorrect overriding of CoAP retransmission buffer size. ### Platform Adaptation Layer (PAL) -- [Zephyr] Fixed a memory leak on DNs handling. +- [Zephyr] Fixed a memory leak on DNS handling. -### Release 4.9.0 (20.05.2021) +### Release 4.9.0 (21.05.2021) ### Device Management Client diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 0cbbd6699..b72f04712 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -8,6 +8,7 @@ Due to the release process, all new releases are squashed code drops. Therefore, | Author | Pull Request | Change title/summary | |----------------|---------------|----------------------------------------------------------| -| Garrett LoVerde (@40Grit) | [#46](https://github.com/ARMmbed/mbed-cloud-client/pull/46) | Remove redundant switch in `get_resource` | +| Garrett LoVerde (@40Grit) | [#46](https://github.com/PelionIoT/mbed-cloud-client/pull/46) | Remove redundant switch in `get_resource` | | Pawel Dunaj ([@pdunaj](https://github.com/pdunaj)) | N/A | Port Pelion Client to Zephyr OS | | Emil Obalski ([@emob-nordic](https://github.com/emob-nordic)) | N/A | Port Pelion Client to Zephyr OS | +| Emil Obalski ([@emob-nordic](https://github.com/emob-nordic)) | [#86](https://github.com/PelionIoT/mbed-cloud-client/pull/86) | Update pal Timers | diff --git a/DOXYGEN_FRONTPAGE.md b/DOXYGEN_FRONTPAGE.md index 83dae1c6a..1b67c082e 100644 --- a/DOXYGEN_FRONTPAGE.md +++ b/DOXYGEN_FRONTPAGE.md @@ -20,12 +20,12 @@ The C++ API allows quick application development. Device Management Client C++ API is essentially constructed around following classes, their base classes and derivatives: -* MbedCloudClient -* M2MInterface -* M2MObject -* M2MObjectInstance -* M2MResource -* M2MResourceInstance +* MbedCloudClient. +* M2MInterface. +* M2MObject. +* M2MObjectInstance. +* M2MResource. +* M2MResourceInstance. Device Management Client follows the architecture specified by LwM2M. `M2MObject`, `M2MObjectInstance`, `M2MResource`, `M2MResourceInstance` are C++ classes that represent what LwM2M specifies as *Object*, *Object Instance*, *Resouce* and *Resource Instance*. @@ -65,41 +65,41 @@ This process shows how you can create a client-based application. 1. Create a `MbedCloudClient` object and register certain callbacks with it: - ```.cpp - MbedCloudClient client; - client.on_registered(...); - client.on_unregistered(...); - client.on_error(...); - ``` + ```.cpp + MbedCloudClient client; + client.on_registered(...); + client.on_unregistered(...); + client.on_error(...); + ``` -1. Define your own resources: +2. Define your own resources: - ```.cpp - M2MObjectList list; + ```.cpp + M2MObjectList list; - M2MObject *object = M2MInterfaceFactory::create_object(name); - M2MObjectInstance* object_instance = object->create_object_instance(instance_id); - M2MResource* resource = object_instance->create_dynamic_resource(name, resource_type, data_type, observable); + M2MObject *object = M2MInterfaceFactory::create_object(name); + M2MObjectInstance* object_instance = object->create_object_instance(instance_id); + M2MResource* resource = object_instance->create_dynamic_resource(name, resource_type, data_type, observable); - resource->set_value((const unsigned char*)value, strlen(value)); - resource->set_operation(M2MBase::GET_PUT_ALLOWED); - resource->set_message_delivery_status_cb(...); - resource->set_value_updated_function((void(*)(const char*))cb); + resource->set_value((const unsigned char*)value, strlen(value)); + resource->set_operation(M2MBase::GET_PUT_ALLOWED); + resource->set_message_delivery_status_cb(...); + resource->set_value_updated_function((void(*)(const char*))cb); - list->push_back(object); - ``` + list->push_back(object); + ``` -1. Call `MbedCloudClient::add_objects()` to add LwM2M objects to the client: +3. Call `MbedCloudClient::add_objects()` to add LwM2M objects to the client: - ```.cpp - client.add_objects(_obj_list); - ``` + ```.cpp + client.add_objects(_obj_list); + ``` -1. Give a platform-specific pointer to the client (it uses this as its network interface): +4. Give a platform-specific pointer to the client (it uses this as its network interface): - ```.cpp - client.setup(mcc_platform_get_network_interface()); - ``` + ```.cpp + client.setup(mcc_platform_get_network_interface()); + ``` This initiates the client and starts its state machine. diff --git a/device-sentry-client/source/linux-os/ds_linux_metrics_report.cpp b/device-sentry-client/source/linux-os/ds_linux_metrics_report.cpp index 3b03c59f8..c75f96f5b 100644 --- a/device-sentry-client/source/linux-os/ds_linux_metrics_report.cpp +++ b/device-sentry-client/source/linux-os/ds_linux_metrics_report.cpp @@ -327,7 +327,7 @@ static ds_status_e extract_ip_addr_and_port(const char *rem_address_field, ds_st static bool avoid_report_remote_address(const char *rem_address_field, int connection_state_field, ds_net_protocol_type_t protocol) { - SA_PV_ERR_RECOVERABLE_RETURN_IF((rem_address_field == NULL), DS_STATUS_INVALID_PARAMETER, "Invalid parameter: rem_address_field is NULL"); + SA_PV_ERR_RECOVERABLE_RETURN_IF((rem_address_field == NULL), true, "Invalid parameter: rem_address_field is NULL"); SA_PV_LOG_TRACE_FUNC_ENTER("rem_address_field=%s, connection_state_field=%d, protocol=%d", rem_address_field, connection_state_field, protocol); bool ret_var = false; @@ -366,9 +366,9 @@ static const char* protocol_to_str(ds_net_protocol_type_t protocol) static bool is_ip_addr_and_port_already_reported(const ds_stat_ip_data_t *stats_array, uint32_t number_items_to_search, const ds_stat_ip_data_t* ip_data) { - SA_PV_ERR_RECOVERABLE_RETURN_IF((ip_data == NULL), DS_STATUS_INVALID_PARAMETER, "Invalid parameter: ip_data is NULL"); + SA_PV_ERR_RECOVERABLE_RETURN_IF((ip_data == NULL), true, "Invalid parameter: ip_data is NULL"); SA_PV_LOG_TRACE_FUNC_ENTER("ip address=%s, port=%" PRIu16, ip_data->ip_addr, ip_data->port); - SA_PV_ERR_RECOVERABLE_RETURN_IF((stats_array == NULL), DS_STATUS_INVALID_PARAMETER, "Invalid parameter: stats_array is NULL"); + SA_PV_ERR_RECOVERABLE_RETURN_IF((stats_array == NULL), true, "Invalid parameter: stats_array is NULL"); bool ret_var = false; for (uint32_t i = 0; i <= number_items_to_search; i++) { @@ -567,10 +567,10 @@ ds_status_e ds_plat_memory_stats_get(ds_stats_memory_t *mem_stats_out) uint64_t mem_total_kb = 0, mem_free_kb = 0; ds_status_e status = meminfo_fields_get_from_line(&mem_total_kb, "MemTotal:", fp); - SA_PV_ERR_RECOVERABLE_GOTO_IF((status != DS_STATUS_SUCCESS), status, release_resources, "Failed to get MemTotal field"); + SA_PV_ERR_RECOVERABLE_GOTO_IF((status != DS_STATUS_SUCCESS), (void)status, release_resources, "Failed to get MemTotal field"); status = meminfo_fields_get_from_line(&mem_free_kb, "MemFree:", fp); - SA_PV_ERR_RECOVERABLE_GOTO_IF((status != DS_STATUS_SUCCESS), status, release_resources, "Failed to get MemFree field"); + SA_PV_ERR_RECOVERABLE_GOTO_IF((status != DS_STATUS_SUCCESS), (void)status, release_resources, "Failed to get MemFree field"); release_resources: fclose (fp); diff --git a/factory-configurator-client/psa-driver/source/psa_driver_crypto.c b/factory-configurator-client/psa-driver/source/psa_driver_crypto.c index 7f4a28aed..bc9129828 100644 --- a/factory-configurator-client/psa-driver/source/psa_driver_crypto.c +++ b/factory-configurator-client/psa-driver/source/psa_driver_crypto.c @@ -561,6 +561,7 @@ kcm_status_e psa_drv_crypto_get_handle(uint16_t key_id, psa_key_handle_t *key_ha //Open key handle psa_status = psa_open_key(key_id, key_handle_out); SA_PV_ERR_RECOVERABLE_RETURN_IF((psa_status != PSA_SUCCESS), psa_drv_translate_to_kcm_error(psa_status), "Failed to open the key"); + SA_PV_LOG_TRACE("psa_open_key %" PRIu32 " handle %" PRIu32 "", key_id, key_handle_out); #else uint32_t extra_flags; uint8_t raw_key[KCM_EC_SECP256R1_MAX_PUB_KEY_RAW_SIZE + sizeof(extra_flags)]; // should be bigger than KCM_EC_SECP256R1_MAX_PRIV_KEY_RAW_SIZE diff --git a/factory-configurator-client/storage/source/key_slot_allocator.c b/factory-configurator-client/storage/source/key_slot_allocator.c index e7809e0fa..221471385 100644 --- a/factory-configurator-client/storage/source/key_slot_allocator.c +++ b/factory-configurator-client/storage/source/key_slot_allocator.c @@ -283,6 +283,21 @@ static kcm_status_e store_table(ksa_descriptor_s *table_descriptor) kcm_status_e kcm_status = KCM_STATUS_SUCCESS; SA_PV_LOG_TRACE_FUNC_ENTER_NO_ARGS(); +//#define PRINT_KSA_TABLE +#ifdef PRINT_KSA_TABLE + if(table_descriptor->ksa_table_uid == KSA_KEY_TABLE_ID_RESERVED_TYPE) { + printf("table id %d\n", table_descriptor->ksa_table_uid); + printf("| item name | active id | factory id | renewal id |\n"); + for(int i = 0; i < table_descriptor->ksa_num_of_table_entries; i++) { + printf("| %x | %d | %d | %d |", table_descriptor->ksa_start_entry[i].item_name, + table_descriptor->ksa_start_entry[i].active_item_id, + table_descriptor->ksa_start_entry[i].factory_item_id, + table_descriptor->ksa_start_entry[i].renewal_item_id); + + printf("\n"); + } + } +#endif //Save the new table kcm_status = psa_drv_ps_set_data_direct(table_descriptor->ksa_table_uid, (const void*)table_descriptor->ksa_start_entry, @@ -314,11 +329,11 @@ static void destroy_ksa_tables() } -static kcm_status_e set_entry_id(ksa_item_entry_s *item_entry, ksa_id_type_e item_id_type, uint16_t id_value) +static kcm_status_e set_entry_id(ksa_item_entry_s *item_entry, ksa_id_type_e item_id_type, uint16_t id_value, ksa_item_type_e table_index) { kcm_status_e kcm_status = KCM_STATUS_SUCCESS; - SA_PV_LOG_TRACE_FUNC_ENTER_NO_ARGS(); + SA_PV_LOG_TRACE_FUNC_ENTER("id type %" PRIu32 ", id value %" PRIu16 "", (uint32_t)item_id_type, id_value); SA_PV_ERR_RECOVERABLE_RETURN_IF((item_entry == NULL), KCM_STATUS_INVALID_PARAMETER, "table_entry is NULL"); @@ -338,7 +353,7 @@ static kcm_status_e set_entry_id(ksa_item_entry_s *item_entry, ksa_id_type_e ite } //Save the table - kcm_status = store_table(&g_ksa_desc[item_id_type]); + kcm_status = store_table(&g_ksa_desc[table_index]); SA_PV_ERR_RECOVERABLE_RETURN_IF((kcm_status != KCM_STATUS_SUCCESS), kcm_status, "Failed to store KSA table to persistent store"); SA_PV_LOG_TRACE_FUNC_EXIT_NO_ARGS(); @@ -422,7 +437,7 @@ static kcm_status_e destroy_all_ce_keys() kcm_status = delete_data(table_entry->renewal_item_id); SA_PV_ERR_RECOVERABLE_RETURN_IF((kcm_status != KCM_STATUS_SUCCESS && kcm_status != KCM_STATUS_INVALID_PARAMETER), kcm_status, "Failed to destroy key id"); //zero the entry - set_entry_id(table_entry, KSA_CE_PSA_ID_TYPE, PSA_INVALID_SLOT_ID); + set_entry_id(table_entry, KSA_CE_PSA_ID_TYPE, PSA_INVALID_SLOT_ID, KSA_KEY_ITEM); } table_entry++; } @@ -1159,7 +1174,7 @@ kcm_status_e ksa_factory_reset(void) SA_PV_ERR_RECOVERABLE_RETURN_IF((kcm_status != KCM_STATUS_SUCCESS), kcm_status, "Failed destroying CE item "); //zero the entry - set_entry_id(table_entry, KSA_CE_PSA_ID_TYPE, PSA_INVALID_SLOT_ID); + set_entry_id(table_entry, KSA_CE_PSA_ID_TYPE, PSA_INVALID_SLOT_ID, table_index); } //squeeze the entry, if it became empty after factory reset - e.g both active and factory entries are 0 @@ -1393,12 +1408,12 @@ kcm_status_e ksa_generate_ce_keys( kcm_status = psa_drv_crypto_generate_keys_from_existing_ids(prv_ksa_id, pub_ksa_id, &prv_ksa_id, &pub_ksa_id, psa_priv_key_handle, psa_pub_key_handle); SA_PV_ERR_RECOVERABLE_RETURN_IF((kcm_status != KCM_STATUS_SUCCESS), kcm_status, "Failed to generate keys"); - kcm_status = set_entry_id(priv_key_entry, KSA_CE_PSA_ID_TYPE, prv_ksa_id); + kcm_status = set_entry_id(priv_key_entry, KSA_CE_PSA_ID_TYPE, prv_ksa_id, KSA_KEY_ITEM); SA_PV_ERR_RECOVERABLE_GOTO_IF((kcm_status != KCM_STATUS_SUCCESS), kcm_status = kcm_status, exit, "Failed to set_entry_id"); if (public_key_name != NULL) { - kcm_status = set_entry_id(pub_key_entry, KSA_CE_PSA_ID_TYPE, pub_ksa_id); + kcm_status = set_entry_id(pub_key_entry, KSA_CE_PSA_ID_TYPE, pub_ksa_id, KSA_KEY_ITEM); SA_PV_ERR_RECOVERABLE_GOTO_IF((kcm_status != KCM_STATUS_SUCCESS), kcm_status = kcm_status, exit, "Failed to set_entry_id"); } @@ -1409,12 +1424,12 @@ kcm_status_e ksa_generate_ce_keys( //In case of error we need to close and destroy allocated key handles if (psa_priv_key_handle != 0) { psa_destroy_key(*psa_priv_key_handle); - set_entry_id(priv_key_entry, KSA_CE_PSA_ID_TYPE, PSA_INVALID_SLOT_ID); + set_entry_id(priv_key_entry, KSA_CE_PSA_ID_TYPE, PSA_INVALID_SLOT_ID, KSA_KEY_ITEM); *psa_priv_key_handle = 0; } if (psa_pub_key_handle != 0) { psa_destroy_key(*psa_pub_key_handle); - set_entry_id(pub_key_entry, KSA_CE_PSA_ID_TYPE, PSA_INVALID_SLOT_ID); + set_entry_id(pub_key_entry, KSA_CE_PSA_ID_TYPE, PSA_INVALID_SLOT_ID, KSA_KEY_ITEM); *psa_pub_key_handle = 0; } } @@ -1455,7 +1470,7 @@ kcm_status_e ksa_destroy_ce_key(const uint8_t *item_name, uint32_t item_type) SA_PV_ERR_RECOVERABLE_RETURN_IF((kcm_status != KCM_STATUS_SUCCESS && kcm_status != KCM_STATUS_INVALID_PARAMETER), kcm_status, "Failed to destroy key id"); //Clean the current id field - kcm_status = set_entry_id(ksa_key_entry, KSA_CE_PSA_ID_TYPE, PSA_INVALID_SLOT_ID); + kcm_status = set_entry_id(ksa_key_entry, KSA_CE_PSA_ID_TYPE, PSA_INVALID_SLOT_ID, ksa_item_type); SA_PV_ERR_RECOVERABLE_RETURN_IF((kcm_status != KCM_STATUS_SUCCESS), kcm_status, "Failed to update active id"); kcm_status = store_table(&g_ksa_desc[item_type]); @@ -1544,11 +1559,11 @@ kcm_status_e ksa_activate_ce_key(const uint8_t *key_name) SA_PV_ERR_RECOVERABLE_RETURN_IF((table_entry->renewal_item_id == 0), kcm_status = KCM_STATUS_ITEM_NOT_FOUND, "Renewal ID is not valid"); //Update active id of the entry with value of renewal id - kcm_status = set_entry_id(table_entry, KSA_ACTIVE_PSA_ID_TYPE, table_entry->renewal_item_id); + kcm_status = set_entry_id(table_entry, KSA_ACTIVE_PSA_ID_TYPE, table_entry->renewal_item_id, KSA_KEY_ITEM); SA_PV_ERR_RECOVERABLE_RETURN_IF((kcm_status != KCM_STATUS_SUCCESS), kcm_status, "Failed to update active id"); // default renewal id - kcm_status = set_entry_id(table_entry, KSA_CE_PSA_ID_TYPE, PSA_INVALID_SLOT_ID); + kcm_status = set_entry_id(table_entry, KSA_CE_PSA_ID_TYPE, PSA_INVALID_SLOT_ID, KSA_KEY_ITEM); SA_PV_ERR_RECOVERABLE_RETURN_IF((kcm_status != KCM_STATUS_SUCCESS), kcm_status, "Failed to zero renewal id"); SA_PV_LOG_INFO_FUNC_EXIT_NO_ARGS(); @@ -1643,7 +1658,7 @@ kcm_status_e ksa_update_key_id(const uint8_t *key_name, ksa_id_type_e key_id_typ SA_PV_ERR_RECOVERABLE_RETURN_IF((kcm_status != KCM_STATUS_SUCCESS), kcm_status, "Failed get_active_entry_of_existing_item"); //Update active id of the entry with value of renewal id - kcm_status = set_entry_id(table_entry, key_id_type, id_value); + kcm_status = set_entry_id(table_entry, key_id_type, id_value, KSA_KEY_ITEM); SA_PV_ERR_RECOVERABLE_RETURN_IF((kcm_status != KCM_STATUS_SUCCESS), kcm_status, "Failed to update active id"); SA_PV_LOG_INFO_FUNC_EXIT_NO_ARGS(); diff --git a/factory-configurator-client/storage/source/storage_psa.cpp b/factory-configurator-client/storage/source/storage_psa.cpp index 2b5bd1a53..1e87d8869 100644 --- a/factory-configurator-client/storage/source/storage_psa.cpp +++ b/factory-configurator-client/storage/source/storage_psa.cpp @@ -905,7 +905,7 @@ kcm_status_e storage_key_get_handle( SA_PV_ERR_RECOVERABLE_RETURN_IF((key_type != KCM_PRIVATE_KEY_ITEM && key_type != KCM_PUBLIC_KEY_ITEM), KCM_STATUS_INVALID_PARAMETER, "key type not supported"); SA_PV_ERR_RECOVERABLE_RETURN_IF((key_name == NULL), KCM_STATUS_INVALID_PARAMETER, "Invalid key_name"); SA_PV_ERR_RECOVERABLE_RETURN_IF((key_name_len == 0), KCM_STATUS_INVALID_PARAMETER, "Invalid key_name_len"); - SA_PV_LOG_INFO_FUNC_ENTER("item name = %.*s len = %" PRIu32 "", (int)key_name_len, (char*)key_name, (uint32_t)key_name_len); + SA_PV_LOG_INFO_FUNC_ENTER("item name = %.*s len = %" PRIu32 " type %" PRIu32 "", (int)key_name_len, (char*)key_name, (uint32_t)key_name_len, (uint32_t)item_prefix_type); SA_PV_ERR_RECOVERABLE_RETURN_IF((item_prefix_type != STORAGE_ITEM_PREFIX_KCM && item_prefix_type != STORAGE_ITEM_PREFIX_CE), KCM_STATUS_INVALID_PARAMETER, "Invalid key_source_type"); SA_PV_ERR_RECOVERABLE_RETURN_IF((key_type != KCM_PRIVATE_KEY_ITEM && key_type != KCM_PUBLIC_KEY_ITEM), KCM_STATUS_INVALID_PARAMETER, "Invalid key type"); SA_PV_ERR_RECOVERABLE_RETURN_IF((key_h_out == NULL), KCM_STATUS_INVALID_PARAMETER, "Invalid key_h_out"); diff --git a/fota/bspatch/common.h b/fota/bspatch/bspatch_common.h similarity index 100% rename from fota/bspatch/common.h rename to fota/bspatch/bspatch_common.h diff --git a/fota/bspatch/bspatch_private.h b/fota/bspatch/bspatch_private.h index 0d228e33c..a38f5c670 100644 --- a/fota/bspatch/bspatch_private.h +++ b/fota/bspatch/bspatch_private.h @@ -20,7 +20,7 @@ #define INCLUDE_BSPATCH_PRIVATE_H_ #include "bspatch.h" -#include "common.h" +#include "bspatch_common.h" /* Patch applied successfully, but new file is not ready yet. User should re-fill patch buffer and call bspatch again. */ #define BSPATCH_NEED_MORE_PATCH_DATA 1 diff --git a/fota/bspatch_fota_mbed.c b/fota/bspatch_fota_mbed.c index 741a2c54e..8462e9596 100644 --- a/fota/bspatch_fota_mbed.c +++ b/fota/bspatch_fota_mbed.c @@ -2,9 +2,11 @@ // in order to avoid collision with the ones used in UC-Hub // (due to the nature of mbed-os source file globbing) -#if (defined(__MBED__) || defined(__NANOSIMULATOR__)) && defined(MBED_CLOUD_CLIENT_FOTA_ENABLE) +#if !defined(FOTA_UNIT_TEST) #include "MbedCloudClientConfig.h" +#endif +#if (defined(__MBED__) || defined(__NANOSIMULATOR__)) && defined(MBED_CLOUD_CLIENT_FOTA_ENABLE) #include "bspatch/bspatch.c" #include "bspatch/lz4.c" #include "bspatch/varint.c" diff --git a/fota/fota.c b/fota/fota.c index 337dd9769..d9c48573a 100644 --- a/fota/fota.c +++ b/fota/fota.c @@ -66,23 +66,32 @@ #endif static fota_context_t *fota_ctx = NULL; +static fota_persistent_context_t fota_persistent_ctx; static int handle_fw_fragment(uint8_t *buf, size_t size, bool last); static int handle_manifest(uint8_t *manifest_buf, size_t manifest_size, bool is_resume, bool is_multicast); static void on_reboot(void); static int finalize_update(void); -static void fota_on_install_authorize(bool defer); +static void fota_on_download_authorize(); +static void fota_on_install_authorize(fota_install_state_e fota_install_type); static bool initialized = false; static size_t storage_available; static bool fota_defer_by_user = false; +static bool erase_candidate_image = true; + +bool fota_resume_download_after_user_auth = true; //indication if resume flow executed after reboot, used also in test_fota_core.cpp. +fota_install_state_e fota_install_state = FOTA_INSTALL_STATE_IDLE; //FOTA installation state, used also in test_fota_core.cpp. + // Multicast related variables here should not be part of the FOTA context, as they live also outside of FOTA scope #if (MBED_CLOUD_CLIENT_FOTA_MULTICAST_SUPPORT != FOTA_MULTICAST_UNSUPPORTED) static size_t mc_image_data_addr; #if (MBED_CLOUD_CLIENT_FOTA_MULTICAST_SUPPORT == FOTA_MULTICAST_BR_MODE) +#if !(defined(TARGET_LIKE_LINUX)) static int multicast_br_candidate_iterate_handler(fota_candidate_iterate_callback_info *info); +#endif static int multicast_br_post_install_handler(const char *component_name, const fota_header_info_t *expected_header_info); #elif (MBED_CLOUD_CLIENT_FOTA_MULTICAST_SUPPORT == FOTA_MULTICAST_NODE_MODE) #if MBED_CLOUD_CLIENT_FOTA_EXTERNAL_DOWNLOADER @@ -156,15 +165,13 @@ static void free_context_buffers(void) #endif // !defined(FOTA_DISABLE_DELTA) #if (MBED_CLOUD_CLIENT_FOTA_ENCRYPTION_SUPPORT == 1) - if (fota_ctx->enc_ctx) { - fota_encrypt_finalize(&fota_ctx->enc_ctx); - } + fota_encrypt_finalize(&fota_ctx->enc_ctx); #endif - if (fota_ctx->curr_fw_hash_ctx) { - fota_hash_finish(&fota_ctx->curr_fw_hash_ctx); - } - + fota_hash_finish(&fota_ctx->payload_hash_ctx); +#if !defined(FOTA_DISABLE_DELTA) + fota_hash_finish(&fota_ctx->installed_hash_ctx); +#endif #if (MBED_CLOUD_CLIENT_FOTA_MULTICAST_SUPPORT == FOTA_MULTICAST_NODE_MODE) free(fota_ctx->mc_node_frag_buf); fota_ctx->mc_node_frag_buf = NULL; @@ -204,17 +211,18 @@ static void update_cleanup(void) fota_source_enable_auto_observable_resources_reporting(true); } -static void abort_update(int ret, const char *msg) +static void do_abort_update(int ret, const char *msg) { int upd_res; bool do_terminate_update = true; - - if (!fota_is_active_update()) { - return; - } + bool do_report_update_result = true; FOTA_TRACE_ERROR("Update aborted: (ret code %d) %s", ret, msg); + if (ret == FOTA_STATUS_MULTICAST_UPDATE_ABORTED_INTERNAL) { + do_report_update_result = false; + } + if (ret == FOTA_STATUS_FAIL_UPDATE_STATE || ret == FOTA_STATUS_UPDATE_DEFERRED || ret == FOTA_STATUS_TRANSIENT_FAILURE) { @@ -224,7 +232,13 @@ static void abort_update(int ret, const char *msg) } if (do_terminate_update) { - fota_source_report_update_result(upd_res); + if (upd_res > -1 * FOTA_STATUS_INTERNAL_ERR_BASE) { + // map all internal errors to a generic internal error + upd_res = -1 * FOTA_STATUS_INTERNAL_ERROR; + } + if (do_report_update_result) { + fota_source_report_update_result(upd_res); + } fota_source_report_state(FOTA_SOURCE_STATE_IDLE, NULL, NULL); manifest_delete(); fota_nvm_fw_encryption_key_delete(); @@ -233,22 +247,43 @@ static void abort_update(int ret, const char *msg) } const fota_component_desc_t *comp_desc; - fota_component_get_desc(fota_ctx->comp_id, &comp_desc); + fota_component_get_desc(fota_persistent_ctx.comp_id, &comp_desc); fota_platform_abort_update_hook(comp_desc->name); #if (MBED_CLOUD_CLIENT_FOTA_MULTICAST_SUPPORT == FOTA_MULTICAST_BR_MODE) - if (fota_ctx->mc_br_update) { - FOTA_DBG_ASSERT(fota_ctx->mc_br_post_action_callback); - fota_ctx->mc_br_post_action_callback(ret); + if (fota_persistent_ctx.mc_br_update) { + FOTA_DBG_ASSERT(fota_persistent_ctx.mc_br_post_action_callback); + fota_persistent_ctx.mc_br_post_action_callback(ret); } #elif (MBED_CLOUD_CLIENT_FOTA_MULTICAST_SUPPORT == FOTA_MULTICAST_NODE_MODE) - if (fota_ctx->mc_node_update && fota_ctx->mc_node_post_action_callback) { - fota_ctx->mc_node_post_action_callback(ret); + if (fota_persistent_ctx.mc_node_update && fota_persistent_ctx.mc_node_post_action_callback) { + fota_persistent_ctx.mc_node_post_action_callback(ret); } #endif - handle_fota_app_on_complete(ret); //notify application + + fota_app_on_complete(ret); //notify application update_cleanup(); } +static void abort_update(int ret, const char *msg) +{ + if (!fota_is_active_update()) { + return; + } + + //fill FOTA persistent context + fota_persistent_ctx.comp_id = fota_ctx->comp_id; + fota_persistent_ctx.state = fota_ctx->state; +#if (MBED_CLOUD_CLIENT_FOTA_MULTICAST_SUPPORT == FOTA_MULTICAST_BR_MODE) + fota_persistent_ctx.mc_br_update = fota_ctx->mc_br_update; + fota_persistent_ctx.mc_br_post_action_callback = fota_ctx->mc_br_post_action_callback; +#elif (MBED_CLOUD_CLIENT_FOTA_MULTICAST_SUPPORT == FOTA_MULTICAST_NODE_MODE) + fota_persistent_ctx.mc_node_update = fota_ctx->mc_node_update; + fota_persistent_ctx.mc_node_post_action_callback = fota_ctx->mc_node_post_action_callback; +#endif + + do_abort_update(ret, msg); +} + static void on_state_set_failure(void) { abort_update(FOTA_STATUS_FAIL_UPDATE_STATE, "Failed to deliver FOTA state"); @@ -269,7 +304,8 @@ int fota_is_ready(uint8_t *data, size_t size, fota_state_e *fota_state) return FOTA_STATUS_OUT_OF_MEMORY; } int ret = manifest_get(manifest, FOTA_MANIFEST_MAX_SIZE, &manifest_size); - if (ret) { // cannot find saved manifest - ready to start an update + if (ret) { + // cannot find saved manifest - ready to start an update *fota_state = FOTA_STATE_IDLE; goto CLEANUP; } @@ -542,10 +578,12 @@ int fota_init(void *m2m_interface, void *resource_list) ret = manifest_get((uint8_t *)&dummy, sizeof(dummy), &manifest_size); if (ret != FOTA_STATUS_NOT_FOUND) { source_state = FOTA_SOURCE_STATE_PROCESSING_MANIFEST; + FOTA_TRACE_DEBUG("manifest exists on fota_init()"); + fota_resume_download_after_user_auth = true; //fota_init() was called and manifest exists - we assume that resume flow will be initiated after reboot } else { uint8_t fw_key[FOTA_ENCRYPT_KEY_SIZE]; ret = fota_nvm_fw_encryption_key_get(fw_key); - clear_buffer_from_mem(fw_key, sizeof(fw_key)); + fota_fi_memset(fw_key, 0, sizeof(fw_key)); after_upgrade = !ret; } @@ -642,7 +680,7 @@ int fota_init(void *m2m_interface, void *resource_list) #endif initialized = true; - + FOTA_TRACE_DEBUG("init complete"); return FOTA_STATUS_SUCCESS; @@ -675,7 +713,7 @@ int fota_deinit(void) return FOTA_STATUS_SUCCESS; } -static int init_encryption(void) +static int init_encryption(manifest_firmware_info_t *fw_info) { int ret = FOTA_STATUS_NOT_FOUND; @@ -697,24 +735,29 @@ static int init_encryption(void) if (ret) { for (;;) { uint8_t zero_key[FOTA_ENCRYPT_KEY_SIZE] = {0}; - size_t volatile loop_check; + volatile size_t loop_check; #if (MBED_CLOUD_CLIENT_FOTA_KEY_ENCRYPTION == FOTA_USE_DEVICE_KEY) ret = fota_get_device_key_128bit(fw_key, FOTA_ENCRYPT_KEY_SIZE); - if (ret) { - FOTA_TRACE_ERROR("Unable to generate random FW key. ret %d", ret); - return ret; +#elif (MBED_CLOUD_CLIENT_FOTA_KEY_ENCRYPTION == FOTA_USE_ENCRYPTED_ONE_TIME_FW_KEY) + if (fw_info->payload_format == FOTA_MANIFEST_PAYLOAD_FORMAT_ENCRYPTED_RAW) { + // copy the key from manifest_firmware_info_t + // and clear it from the fota_ctx + fota_fi_memcpy(fw_key, fota_ctx->encryption_key, sizeof(fw_key)); + fota_fi_memset(fota_ctx->encryption_key, 0, FOTA_ENCRYPT_KEY_SIZE); + ret = FOTA_STATUS_SUCCESS; + } else { + ret = fota_gen_random(fw_key, sizeof(fw_key)); } -#elif (MBED_CLOUD_CLIENT_FOTA_KEY_ENCRYPTION == FOTA_USE_ONE_TIME_FW_KEY) +#else + // encryption support disabled ret = fota_gen_random(fw_key, sizeof(fw_key)); +#endif if (ret) { FOTA_TRACE_ERROR("Unable to generate random FW key. ret %d", ret); return ret; } -#else -#error MBED_CLOUD_CLIENT_FOTA_KEY_ENCRYPTION wrong value -#endif - // safely check that generated key is non zero + // safely check that key is non zero FOTA_FI_SAFE_COND((fota_fi_memcmp(fw_key, zero_key, FOTA_ENCRYPT_KEY_SIZE, &loop_check) && (loop_check == FOTA_ENCRYPT_KEY_SIZE)), FOTA_STATUS_INTERNAL_ERROR, "Zero encryption key - retry"); @@ -724,10 +767,18 @@ static int init_encryption(void) FOTA_TRACE_ERROR("Unable to set FW key. ret %d", ret); return ret; } + // non zero key break; fail: - ;// retry here if zero + // zero key +#if (MBED_CLOUD_CLIENT_FOTA_KEY_ENCRYPTION == FOTA_USE_ENCRYPTED_ONE_TIME_FW_KEY) + if (fw_info->payload_format == FOTA_MANIFEST_PAYLOAD_FORMAT_ENCRYPTED_RAW) { + // don't retry since the fota_ctx->encryption_key will not changed + return ret; + } +#endif + ;// retry here } FOTA_TRACE_DEBUG("New FOTA key saved"); @@ -736,7 +787,7 @@ static int init_encryption(void) #if (MBED_CLOUD_CLIENT_FOTA_ENCRYPTION_SUPPORT == 1) ret = fota_encrypt_decrypt_start(&fota_ctx->enc_ctx, fw_key, sizeof(fw_key)); - clear_buffer_from_mem(fw_key, sizeof(fw_key)); + fota_fi_memset(fw_key, 0, sizeof(fw_key)); if (ret) { FOTA_TRACE_ERROR("Unable to start encryption engine. ret %d", ret); return ret; @@ -854,6 +905,15 @@ static int handle_manifest(uint8_t *manifest_buf, size_t manifest_size, bool is_ FOTA_TRACE_DEBUG("Pelion FOTA manifest is valid"); +#if (MBED_CLOUD_CLIENT_FOTA_ENCRYPTION_SUPPORT == 1) + if (fota_ctx->fw_info->payload_format == FOTA_MANIFEST_PAYLOAD_FORMAT_ENCRYPTED_RAW) { + // move encryption_key from fw_info to fota_ctx + // to hide it from fota_app_on_download_authorization + fota_fi_memcpy(fota_ctx->encryption_key, fota_ctx->fw_info->encryption_key, FOTA_ENCRYPT_KEY_SIZE); + fota_fi_memset(fota_ctx->fw_info->encryption_key, 0, FOTA_ENCRYPT_KEY_SIZE); + } +#endif + ret = fota_component_name_to_id(fota_ctx->fw_info->component_name, &fota_ctx->comp_id); if (ret) { FOTA_TRACE_ERROR("Manifest addresses unknown component %s", fota_ctx->fw_info->component_name); @@ -893,10 +953,17 @@ static int handle_manifest(uint8_t *manifest_buf, size_t manifest_size, bool is_ memcpy(fota_ctx->fw_info->precursor_digest, curr_fw_digest, FOTA_CRYPTO_HASH_SIZE); } - fota_ctx->state = FOTA_STATE_AWAIT_DOWNLOAD_AUTHORIZATION; - - fota_source_report_state(report_state, request_download_auth, on_state_set_failure); + if ((is_resume == false) || (fota_resume_download_after_user_auth == true)) { //ask for authorization + fota_ctx->state = FOTA_STATE_AWAIT_DOWNLOAD_AUTHORIZATION; + FOTA_TRACE_DEBUG("Ask for user authorization"); + fota_source_report_state(report_state, request_download_auth, on_state_set_failure); + } else { // resume without asking authorization + //skip asking authorization from user since he has already provided one + FOTA_TRACE_DEBUG("Resuming download..."); + fota_source_report_state(report_state, fota_on_download_authorize, on_state_set_failure); + } + fota_resume_download_after_user_auth = false; return FOTA_STATUS_SUCCESS; fail: @@ -923,7 +990,7 @@ void fota_on_manifest(uint8_t *data, size_t size) return; } // Not activated - unicast update should take precedence over multicast one. Abort multicast one. - abort_update(FOTA_STATUS_MULTICAST_UPDATE_ABORTED, "Overridden by unicast manifest"); + abort_update(FOTA_STATUS_MULTICAST_UPDATE_ABORTED_INTERNAL, "Overridden by unicast manifest"); } #endif @@ -935,30 +1002,51 @@ void fota_on_manifest(uint8_t *data, size_t size) void fota_on_reject(int32_t status) { - FOTA_ASSERT(fota_ctx); + FOTA_ASSERT(initialized == true); FOTA_TRACE_ERROR("Application rejected update - reason %" PRId32, status); - if (fota_ctx->state == FOTA_STATE_AWAIT_DOWNLOAD_AUTHORIZATION) { + if (!fota_ctx) { + // We just need to know whether manifest is present, so no need to allocate a full size manifest + size_t manifest_size = 0; + uint8_t dummy; + + if (manifest_get((uint8_t *)&dummy, sizeof(dummy), &manifest_size) != FOTA_STATUS_NOT_FOUND) { + // these steps should be performed even if fota context does not exits, but manifest exists. + // one possible scenario is if defer was called before reject, then the context is released (but manifest still exists). + // when fota reject called, manifest should be removed and fota flow terminated. + + if (fota_persistent_ctx.state == FOTA_STATE_AWAIT_DOWNLOAD_AUTHORIZATION) { + do_abort_update(FOTA_STATUS_DOWNLOAD_AUTH_NOT_GRANTED, "Download Authorization not granted"); + } else { + do_abort_update(FOTA_STATUS_INSTALL_AUTH_NOT_GRANTED, "Install Authorization not granted"); + } + } + return; + } else if (fota_ctx->state == FOTA_STATE_AWAIT_DOWNLOAD_AUTHORIZATION) { abort_update(FOTA_STATUS_DOWNLOAD_AUTH_NOT_GRANTED, "Download Authorization not granted"); - } else { + } else { //FOTA_STATE_AWAIT_INSTALL_AUTHORIZATION abort_update(FOTA_STATUS_INSTALL_AUTH_NOT_GRANTED, "Install Authorization not granted"); } } -void fota_on_defer(int32_t status) +void fota_on_defer(int32_t param) { - (void)status; + FOTA_ASSERT(initialized == true); if (!fota_ctx) { return; // gracefully ignore this call if update is not running } + + if (fota_ctx->state == FOTA_STATE_INSTALLING) { + return; //don't allow defer/postpone during install + } + /* mark call to defer only if FOTA is active */ fota_defer_by_user = true; // for now we assume that defer called always by user app if (fota_ctx->state == FOTA_STATE_AWAIT_INSTALL_AUTHORIZATION) { - FOTA_TRACE_INFO("Installation deferred by application."); - fota_on_install_authorize(true); + fota_on_install_authorize((fota_install_state_e) param); return; } @@ -1045,7 +1133,8 @@ static void install_component() int ret = FOTA_STATUS_SUCCESS; (void) ret; - manifest_delete(); + fota_ctx->state = FOTA_STATE_INSTALLING; + #if defined(__MBED__) // At this point we don't need our fota context buffers any more, for mbed @@ -1054,7 +1143,6 @@ static void install_component() #endif fota_component_get_desc(comp_id, &comp_desc); - FOTA_TRACE_INFO("Installing new version for component %s", comp_desc->name); // Code saving - only relevant if we have additional components other than the main one #if FOTA_COMPONENT_SUPPORT @@ -1076,6 +1164,8 @@ static void install_component() #endif if (do_install) { + FOTA_TRACE_INFO("Installing new version for component %s", comp_desc->name); + // Run the installer using the candidate iterate service ret = fota_candidate_iterate_image(true, (bool) MBED_CLOUD_CLIENT_FOTA_ENCRYPTION_SUPPORT, comp_desc->name, install_alignment, @@ -1118,22 +1208,44 @@ static void install_component() handle_fota_app_on_complete(ret); //notify application on after install, no reset } } + #endif // FOTA_COMPONENT_SUPPORT - if (comp_desc->desc_info.need_reboot) { + // remove manifest after candidate installation finished and before potential reboot. + // MAIN component for mbed-os will be installed by the bootloader + manifest_delete(); + + if ((comp_desc->desc_info.need_reboot) && (fota_install_state == FOTA_INSTALL_STATE_AUTHORIZE)) { + fota_ctx->state = FOTA_STATE_IDLE; fota_source_report_state(FOTA_SOURCE_STATE_REBOOTING, on_reboot, on_reboot); return; } + if (fota_install_state == FOTA_INSTALL_STATE_AUTHORIZE) { + #if (MBED_CLOUD_CLIENT_FOTA_MULTICAST_SUPPORT == FOTA_MULTICAST_NODE_MODE) - if (fota_ctx->mc_node_update) { - FOTA_DBG_ASSERT(fota_ctx->mc_node_post_action_callback); - fota_ctx->mc_node_post_action_callback(ret); - } + if (fota_ctx->mc_node_update) { + FOTA_DBG_ASSERT(fota_ctx->mc_node_post_action_callback); + fota_ctx->mc_node_post_action_callback(ret); + } #endif - fota_platform_finish_update_hook(comp_desc->name); - fota_source_report_update_result(FOTA_STATUS_FW_UPDATE_OK); - fota_source_report_state(FOTA_SOURCE_STATE_IDLE, NULL, NULL); + fota_platform_finish_update_hook(comp_desc->name); + fota_source_report_update_result(FOTA_STATUS_FW_UPDATE_OK); + fota_source_report_state(FOTA_SOURCE_STATE_IDLE, NULL, NULL); + +#if (MBED_CLOUD_CLIENT_FOTA_MULTICAST_SUPPORT == FOTA_MULTICAST_BR_MODE) + if (fota_ctx->mc_br_update) { + // don't erase candidate image in case of node update by border router + erase_candidate_image = false; + } +#endif + + if (erase_candidate_image == true) + { + fota_candidate_erase(); + } + } + update_cleanup(); } @@ -1160,10 +1272,36 @@ static int prepare_and_program_header(void) memcpy(header_info.signature, fota_ctx->fw_info->installed_signature, FOTA_IMAGE_RAW_SIGNATURE_SIZE); #endif // defined(MBED_CLOUD_CLIENT_FOTA_SIGNED_IMAGE_SUPPORT) - header_info.block_size = MBED_CLOUD_CLIENT_FOTA_CANDIDATE_BLOCK_SIZE; +#if (MBED_CLOUD_CLIENT_FOTA_ENCRYPTION_SUPPORT == 1) && \ + (MBED_CLOUD_CLIENT_FOTA_CANDIDATE_BLOCK_SIZE != FOTA_CLOUD_ENCRYPTION_BLOCK_SIZE) + if (fota_ctx->fw_info->payload_format == FOTA_MANIFEST_PAYLOAD_FORMAT_ENCRYPTED_RAW) { + header_info.block_size = FOTA_CLOUD_ENCRYPTION_BLOCK_SIZE; + } else +#endif + { + header_info.block_size = MBED_CLOUD_CLIENT_FOTA_CANDIDATE_BLOCK_SIZE; + } #if (MBED_CLOUD_CLIENT_FOTA_ENCRYPTION_SUPPORT == 1) header_info.flags |= FOTA_HEADER_ENCRYPTED_FLAG; +#if (MBED_CLOUD_CLIENT_FOTA_KEY_ENCRYPTION == FOTA_USE_ENCRYPTED_ONE_TIME_FW_KEY) + // encrypt fw_key buffer using device key and store it in the header + uint8_t fw_key[FOTA_ENCRYPT_KEY_SIZE]; + ret = fota_nvm_fw_encryption_key_get(fw_key); + if (ret) { + FOTA_TRACE_DEBUG("Encryption key not found"); + goto fail; + } + ret = fota_encrypt_fw_key(fw_key, + header_info.encrypted_fw_key, + header_info.encrypted_fw_key_tag, + &header_info.encrypted_fw_key_iv); + fota_fi_memset(fw_key, 0, sizeof(fw_key)); + if (ret) { + FOTA_TRACE_ERROR("Failed to start encryption engine. ret %d", ret); + goto fail; + } +#endif // FOTA_USE_ENCRYPTED_ONE_TIME_FW_KEY #endif #if MBED_CLOUD_CLIENT_FOTA_RESUME_SUPPORT == FOTA_RESUME_SUPPORT_RESUME @@ -1223,6 +1361,8 @@ static int analyze_resume_state(fota_state_e *next_fota_state) #if (MBED_CLOUD_CLIENT_FOTA_ENCRYPTION_SUPPORT != 1) fota_candidate_block_checksum_t checksum = 0; +#else + fota_hash_context_t *payload_temp_hash_ctx = NULL; #endif if (fota_ctx->resume_state == FOTA_RESUME_STATE_INACTIVE) { @@ -1294,6 +1434,15 @@ static int analyze_resume_state(fota_state_e *next_fota_state) goto no_resume; } +#if (MBED_CLOUD_CLIENT_FOTA_ENCRYPTION_SUPPORT == 1) + if (fota_ctx->fw_info->payload_format == FOTA_MANIFEST_PAYLOAD_FORMAT_ENCRYPTED_RAW) { + ret = fota_hash_start(&payload_temp_hash_ctx); + if (ret) { + goto no_resume; + } + } +#endif + num_blocks_available = storage_available / fota_ctx->page_buf_size; num_blocks_left = FOTA_ALIGN_UP(fota_ctx->fw_info->payload_size, fota_ctx->effective_page_buf_size) / fota_ctx->effective_page_buf_size; @@ -1321,8 +1470,22 @@ static int analyze_resume_state(fota_state_e *next_fota_state) } #if (MBED_CLOUD_CLIENT_FOTA_ENCRYPTION_SUPPORT == 1) + size_t data_offset = 0; + if (fota_ctx->fw_info->payload_format == FOTA_MANIFEST_PAYLOAD_FORMAT_ENCRYPTED_RAW) { + // update data offset to skip the tag + data_offset = FOTA_ENCRYPT_TAG_SIZE; + // on an encrypted payload, update payload_temp_hash_ctx before decrypting + // and copy it to payload_hash_ctx only if decrypt succeeds. + ret = fota_hash_update(payload_temp_hash_ctx, fota_ctx->effective_page_buf, chunk); + if (ret) { + goto no_resume; + } + } // decrypt data with tag (at the beginning of page_buf) - ret = fota_decrypt_data(fota_ctx->enc_ctx, fota_ctx->effective_page_buf, chunk, fota_ctx->effective_page_buf, + ret = fota_decrypt_data(fota_ctx->enc_ctx, + fota_ctx->effective_page_buf + data_offset, + chunk - data_offset, + fota_ctx->effective_page_buf + data_offset, fota_ctx->page_buf); if (ret) { // Decryption failure - Skip the block @@ -1342,11 +1505,22 @@ static int analyze_resume_state(fota_state_e *next_fota_state) } #endif - // Block verified as OK - update num blocks left, hash and IV (if encrypted) - ret = fota_hash_update(fota_ctx->curr_fw_hash_ctx, fota_ctx->effective_page_buf, chunk); - if (ret) { - goto no_resume; +#if (MBED_CLOUD_CLIENT_FOTA_ENCRYPTION_SUPPORT == 1) + if (fota_ctx->fw_info->payload_format == FOTA_MANIFEST_PAYLOAD_FORMAT_ENCRYPTED_RAW) { + // on encrypted payload, copy payload_temp_hash_ctx to payload_hash_ctx + fota_hash_clone(fota_ctx->payload_hash_ctx, payload_temp_hash_ctx); + } + else +#endif + { + // update payload_hash_ctx after decryption + ret = fota_hash_update(fota_ctx->payload_hash_ctx, fota_ctx->effective_page_buf, chunk); + if (ret) { + goto no_resume; + } } + + // Block verified as OK - update num blocks left num_blocks_left--; fota_ctx->payload_offset += chunk; fota_ctx->fw_bytes_written += chunk; @@ -1356,6 +1530,13 @@ static int analyze_resume_state(fota_state_e *next_fota_state) fota_ctx->storage_addr += fota_ctx->page_buf_size; } +#if !defined(FOTA_DISABLE_DELTA) + // for a delta patch, copy payload_hash_ctx to installed_hash_ctx + if (fota_ctx->fw_info->payload_format == FOTA_MANIFEST_PAYLOAD_FORMAT_DELTA) { + fota_hash_clone(fota_ctx->installed_hash_ctx, fota_ctx->payload_hash_ctx); + } +#endif + // Got here means that the whole firmware has been written, but candidate ready header is blank. // This means we can converge to the regular install authorization flow. *next_fota_state = FOTA_STATE_AWAIT_INSTALL_AUTHORIZATION; @@ -1369,8 +1550,17 @@ static int analyze_resume_state(fota_state_e *next_fota_state) fota_ctx->storage_addr = save_storage_addr; fota_ctx->fw_bytes_written = 0; fota_ctx->payload_offset = 0; - fota_hash_finish(&fota_ctx->curr_fw_hash_ctx); - fota_hash_start(&fota_ctx->curr_fw_hash_ctx); + // reset payload_hash_ctx + fota_hash_finish(&fota_ctx->payload_hash_ctx); + fota_hash_start(&fota_ctx->payload_hash_ctx); +#if !defined(FOTA_DISABLE_DELTA) + if (fota_ctx->fw_info->payload_format == FOTA_MANIFEST_PAYLOAD_FORMAT_DELTA) { + // reset installed_hash_ctx + fota_hash_finish(&fota_ctx->installed_hash_ctx); + fota_hash_start(&fota_ctx->installed_hash_ctx); + } +#endif + #if (MBED_CLOUD_CLIENT_FOTA_ENCRYPTION_SUPPORT == 1) fota_encryption_stream_reset(fota_ctx->enc_ctx); #endif @@ -1378,6 +1568,9 @@ static int analyze_resume_state(fota_state_e *next_fota_state) finish: free(fota_ctx->page_buf); fota_ctx->page_buf = NULL; +#if (MBED_CLOUD_CLIENT_FOTA_ENCRYPTION_SUPPORT == 1) + fota_hash_finish(&payload_temp_hash_ctx); +#endif return ret; } @@ -1457,6 +1650,7 @@ static void fota_on_download_authorize() size_t prog_size; const fota_component_desc_t *comp_desc; #if MBED_CLOUD_CLIENT_FOTA_RESUME_SUPPORT == FOTA_RESUME_SUPPORT_RESUME + int erase_val; fota_state_e next_fota_state = FOTA_STATE_DOWNLOADING; #endif @@ -1475,6 +1669,14 @@ static void fota_on_download_authorize() } FOTA_TRACE_DEBUG("FOTA BlockDevice initialized"); +#if (MBED_CLOUD_CLIENT_FOTA_RESUME_SUPPORT == FOTA_RESUME_SUPPORT_RESUME) + ret = fota_bd_get_erase_value(&erase_val); + if (ret || (erase_val < 0)) { + FOTA_TRACE_ERROR("Full resume not supported for devices that have no erase"); + FOTA_ASSERT(0); + } +#endif + ret = fota_bd_get_program_size(&prog_size); if (ret) { FOTA_TRACE_ERROR("Get program size failed. ret %d", ret); @@ -1487,9 +1689,17 @@ static void fota_on_download_authorize() goto fail; } - fota_ctx->page_buf_size = FOTA_ALIGN_UP(MBED_CLOUD_CLIENT_FOTA_CANDIDATE_BLOCK_SIZE, prog_size); +#if (MBED_CLOUD_CLIENT_FOTA_ENCRYPTION_SUPPORT == 1) && \ + (MBED_CLOUD_CLIENT_FOTA_CANDIDATE_BLOCK_SIZE != FOTA_CLOUD_ENCRYPTION_BLOCK_SIZE) + if (fota_ctx->fw_info->payload_format == FOTA_MANIFEST_PAYLOAD_FORMAT_ENCRYPTED_RAW) { + fota_ctx->page_buf_size = FOTA_ALIGN_UP(FOTA_CLOUD_ENCRYPTION_BLOCK_SIZE, prog_size); + } else +#endif + { + fota_ctx->page_buf_size = FOTA_ALIGN_UP(MBED_CLOUD_CLIENT_FOTA_CANDIDATE_BLOCK_SIZE, prog_size); + } - ret = init_encryption(); + ret = init_encryption(fota_ctx->fw_info); if (ret) { goto fail; } @@ -1497,17 +1707,29 @@ static void fota_on_download_authorize() fota_ctx->effective_page_buf_size = fota_ctx->page_buf_size; #if (MBED_CLOUD_CLIENT_FOTA_ENCRYPTION_SUPPORT == 1) - fota_ctx->effective_page_buf_size -= FOTA_ENCRYPT_TAG_SIZE; + if (fota_ctx->fw_info->payload_format != FOTA_MANIFEST_PAYLOAD_FORMAT_ENCRYPTED_RAW) { + // on encrypted payload, skip reducing tag size + fota_ctx->effective_page_buf_size -= FOTA_ENCRYPT_TAG_SIZE; + } #elif (MBED_CLOUD_CLIENT_FOTA_RESUME_SUPPORT == FOTA_RESUME_SUPPORT_RESUME) // Reduce checksum size fota_ctx->effective_page_buf_size -= sizeof(fota_candidate_block_checksum_t); #endif - ret = fota_hash_start(&fota_ctx->curr_fw_hash_ctx); + ret = fota_hash_start(&fota_ctx->payload_hash_ctx); if (ret) { goto fail; } +#if !defined(FOTA_DISABLE_DELTA) + if (fota_ctx->fw_info->payload_format == FOTA_MANIFEST_PAYLOAD_FORMAT_DELTA) { + ret = fota_hash_start(&fota_ctx->installed_hash_ctx); + if (ret) { + goto fail; + } + } +#endif + fota_ctx->fw_header_offset = fota_ctx->storage_addr - fota_ctx->fw_header_bd_size; ret = calc_available_storage(); @@ -1609,45 +1831,42 @@ static void fota_on_download_authorize() abort_update(ret, "Failed on download authorization event"); } -static void fota_on_install_authorize(bool defer) +static void fota_on_install_authorize(fota_install_state_e fota_install_type) { int ret; const fota_component_desc_t *comp_desc; + fota_install_state = fota_install_type; + fota_component_get_desc(fota_ctx->comp_id, &comp_desc); free(fota_ctx->page_buf); fota_ctx->page_buf = NULL; - if (fota_ctx->candidate_header_size) { - ret = write_candidate_ready(comp_desc->name); - } else { - ret = prepare_and_program_header(); - } - if (ret) { - FOTA_TRACE_ERROR("FOTA write final header - failed %d", ret); - goto fail; + if (fota_install_state != FOTA_INSTALL_STATE_DEFER) { + if (fota_ctx->candidate_header_size) { + ret = write_candidate_ready(comp_desc->name); + } else { + ret = prepare_and_program_header(); + } + if (ret) { + FOTA_TRACE_ERROR("FOTA write final header - failed %d", ret); + goto fail; + } } - // Install defer means that we skip the installation for now - if (defer) { - if (fota_ctx->comp_id == FOTA_COMPONENT_MAIN_COMP_NUM) { - // Main component is a special case - bootloader will install the FW upon next reset, - // so no need to keep the manifest. - manifest_delete(); - } else { - // All other components will use the resume flow for that, so manifest should be kept. -#if MBED_CLOUD_CLIENT_FOTA_RESUME_SUPPORT != FOTA_RESUME_SUPPORT_RESUME - abort_update(FOTA_STATUS_INTERNAL_ERROR, + if ((fota_install_state == FOTA_INSTALL_STATE_AUTHORIZE) || (fota_install_state == FOTA_INSTALL_STATE_POSTPONE_REBOOT)) { + fota_source_report_state(FOTA_SOURCE_STATE_UPDATING, install_component, on_state_set_failure); + } else { //FOTA_INSTALL_STATE_DEFER - we skip the installation for now +#if MBED_CLOUD_CLIENT_FOTA_RESUME_SUPPORT == FOTA_RESUME_SUPPORT_RESUME + FOTA_TRACE_INFO("FOTA install deferred until further user instruction"); +#else + abort_update(FOTA_STATUS_INTERNAL_ERROR, "Component install defer requires resume support"); - return; #endif - } update_cleanup(); - return; } - fota_source_report_state(FOTA_SOURCE_STATE_UPDATING, install_component, on_state_set_failure); return; fail: @@ -1655,10 +1874,8 @@ static void fota_on_install_authorize(bool defer) abort_update(ret, "Failed on install authorization event"); } -void fota_on_authorize(int32_t status) +void fota_on_authorize(int32_t param) { - (void)status; //unused warning - FOTA_ASSERT(fota_ctx); FOTA_ASSERT( @@ -1667,8 +1884,9 @@ void fota_on_authorize(int32_t status) ); if (fota_ctx->state == FOTA_STATE_AWAIT_INSTALL_AUTHORIZATION) { + FOTA_ASSERT(param == FOTA_INSTALL_STATE_AUTHORIZE); FOTA_TRACE_INFO("Install authorization granted."); - fota_on_install_authorize(false); + fota_on_install_authorize((fota_install_state_e)param); return; } @@ -1708,11 +1926,14 @@ static int program_to_storage(uint8_t *buf, size_t addr, uint32_t size) do { #if (MBED_CLOUD_CLIENT_FOTA_ENCRYPTION_SUPPORT == 1) - uint8_t *tag = fota_ctx->page_buf; - ret = fota_encrypt_data(fota_ctx->enc_ctx, src_buf, data_size, src_buf, tag); - if (ret) { - FOTA_TRACE_ERROR("encryption failed %d", ret); - return ret; + if (fota_ctx->fw_info->payload_format != FOTA_MANIFEST_PAYLOAD_FORMAT_ENCRYPTED_RAW) { + // on encrypted payload, data already encrypted + uint8_t *tag = fota_ctx->page_buf; + ret = fota_encrypt_data(fota_ctx->enc_ctx, src_buf, data_size, src_buf, tag); + if (ret) { + FOTA_TRACE_ERROR("encryption failed %d", ret); + return ret; + } } #elif MBED_CLOUD_CLIENT_FOTA_RESUME_SUPPORT == FOTA_RESUME_SUPPORT_RESUME fota_candidate_block_checksum_t *checksum = (fota_candidate_block_checksum_t *) fota_ctx->page_buf; @@ -1752,11 +1973,6 @@ static int handle_fw_fragment(uint8_t *buf, size_t size, bool last) uint32_t prog_size; uint32_t chunk; - int ret = fota_hash_update(fota_ctx->curr_fw_hash_ctx, buf, size); - if (ret) { - return ret; - } - while (size) { // Two cases here: // 1. The "hard" one - If our fragment is not aligned to a whole page: @@ -1778,7 +1994,7 @@ static int handle_fw_fragment(uint8_t *buf, size_t size, bool last) source_buf += chunk; if ((prog_size >= fota_ctx->effective_page_buf_size) || last) { - ret = program_to_storage(prog_buf, + int ret = program_to_storage(prog_buf, fota_ctx->storage_addr, prog_size); if (ret) { @@ -1803,7 +2019,17 @@ static void on_approve_state_delivered(void) static int finalize_update(void) { int ret; - uint8_t curr_fw_hash_buf[FOTA_CRYPTO_HASH_SIZE]; + uint8_t calced_hash_buf[FOTA_CRYPTO_HASH_SIZE]; + fota_hash_context_t *calced_hash_ctx = fota_ctx->payload_hash_ctx; + uint8_t *expected_digest = fota_ctx->fw_info->payload_digest; + +#if !defined(FOTA_DISABLE_DELTA) + // on delta, digest is calced on the install/unpatch data + if (fota_ctx->fw_info->payload_format == FOTA_MANIFEST_PAYLOAD_FORMAT_DELTA) { + calced_hash_ctx = fota_ctx->installed_hash_ctx; + expected_digest = fota_ctx->fw_info->installed_digest; + } +#endif // Ongoing resume state here means that all authentication has been done before. // Can jump straight to finish. @@ -1811,22 +2037,32 @@ static int finalize_update(void) goto finished; } - ret = fota_hash_result(fota_ctx->curr_fw_hash_ctx, curr_fw_hash_buf); + ret = fota_hash_result(calced_hash_ctx, calced_hash_buf); if (ret) { return ret; } + #if defined(MBED_CLOUD_CLIENT_FOTA_SIGNED_IMAGE_SUPPORT) - ret = fota_verify_signature_prehashed( - curr_fw_hash_buf, - fota_ctx->fw_info->installed_signature, FOTA_IMAGE_RAW_SIGNATURE_SIZE - ); - FOTA_FI_SAFE_COND( - (ret == FOTA_STATUS_SUCCESS), - FOTA_STATUS_MANIFEST_PAYLOAD_CORRUPTED, - "Candidate image is not authentic" - ); +#if (MBED_CLOUD_CLIENT_FOTA_ENCRYPTION_SUPPORT == 1) + if (fota_ctx->fw_info->payload_format != FOTA_MANIFEST_PAYLOAD_FORMAT_ENCRYPTED_RAW) + // on encrypted payload, skip verifing signature as + // we can't calc the hash of the installed payload. + // It will be verified later by the bootloader. +#endif + { + ret = fota_verify_signature_prehashed( + calced_hash_buf, + fota_ctx->fw_info->installed_signature, FOTA_IMAGE_RAW_SIGNATURE_SIZE + ); + FOTA_FI_SAFE_COND( + (ret == FOTA_STATUS_SUCCESS), + FOTA_STATUS_MANIFEST_PAYLOAD_CORRUPTED, + "Candidate image is not authentic" + ); + } #else - FOTA_FI_SAFE_MEMCMP(curr_fw_hash_buf, fota_ctx->fw_info->installed_digest, FOTA_CRYPTO_HASH_SIZE, + // compare expected_digest against calced digest + FOTA_FI_SAFE_MEMCMP(calced_hash_buf, expected_digest, FOTA_CRYPTO_HASH_SIZE, FOTA_STATUS_MANIFEST_PAYLOAD_CORRUPTED, "Downloaded FW hash does not match manifest hash"); #endif @@ -1847,7 +2083,7 @@ static int finalize_update(void) #if (MBED_CLOUD_CLIENT_FOTA_MULTICAST_SUPPORT == FOTA_MULTICAST_BR_MODE) if (fota_ctx->mc_br_update) { // No need to authorize on BR mode, jump straight to installation - fota_on_install_authorize(false); + fota_on_install_authorize(FOTA_INSTALL_STATE_AUTHORIZE); return FOTA_STATUS_SUCCESS; } #endif @@ -1915,6 +2151,9 @@ void fota_on_fragment(uint8_t *buf, size_t size) handle_fota_app_on_download_progress(fota_ctx->payload_offset, size, fota_ctx->fw_info->payload_size); + // update payload_hash_ctx with fragment + ret = fota_hash_update(fota_ctx->payload_hash_ctx, buf, size); + if (fota_ctx->fw_info->payload_format == FOTA_MANIFEST_PAYLOAD_FORMAT_DELTA) { #if !defined(FOTA_DISABLE_DELTA) bool finished = false; @@ -1947,6 +2186,11 @@ void fota_on_fragment(uint8_t *buf, size_t size) } if (actual_frag_size) { last_fragment = ((fota_ctx->fw_bytes_written + fota_ctx->page_buf_offset + actual_frag_size) == fota_ctx->fw_info->installed_size); + // update installed_hash_ctx with delta_buf + ret = fota_hash_update(fota_ctx->installed_hash_ctx, fota_ctx->delta_buf, actual_frag_size); + if (ret) { + goto fail; + } ret = handle_fw_fragment(fota_ctx->delta_buf, actual_frag_size, last_fragment); if (ret) { goto fail; @@ -1960,6 +2204,9 @@ void fota_on_fragment(uint8_t *buf, size_t size) FOTA_ASSERT(0); #endif // #if !defined(FOTA_DISABLE_DELTA) } else { + if (ret) { + goto fail; + } last_fragment = ((payload_bytes_left - size) == 0); ret = handle_fw_fragment(buf, size, last_fragment); if (ret) { @@ -2008,6 +2255,11 @@ void fota_on_resume(int32_t param) return; // FOTA is already running - ignore } + if (fota_install_state == FOTA_INSTALL_STATE_POSTPONE_REBOOT) { + FOTA_TRACE_DEBUG("FOTA resume not supported after postpone"); + return; + } + FOTA_TRACE_INFO("fota_on_resume - resume by %u", fota_resume_by_user); //if we got here, there is no fota context: @@ -2192,7 +2444,7 @@ int fota_multicast_node_on_manifest(uint8_t *data, size_t size, } else { if (memcmp(manifest_hash, fota_ctx->mc_node_manifest_hash, FOTA_CRYPTO_HASH_SIZE)) { FOTA_TRACE_DEBUG("Got a new multicast manifest, aborting previous FOTA session"); - abort_update(FOTA_STATUS_MULTICAST_UPDATE_ABORTED, "Multicast manifest overridden"); + abort_update(FOTA_STATUS_MULTICAST_UPDATE_ABORTED_INTERNAL, "Multicast manifest overridden"); } else { FOTA_TRACE_DEBUG("Same multicast manifest received, silently ignored"); return FOTA_STATUS_SUCCESS; @@ -2280,7 +2532,9 @@ int fota_multicast_node_get_ready_for_image(size_t image_size) FOTA_TRACE_DEBUG("Current multicast update activated, can't override it"); return FOTA_STATUS_MULTICAST_UPDATE_ACTIVATED; } else { - abort_update(FOTA_STATUS_MULTICAST_UPDATE_ABORTED, "Multicast update overridden"); + if (mc_node_new_image) { + FOTA_TRACE_INFO("Multicast - get ready for a new image again - silently ignored"); + } } } @@ -2428,11 +2682,13 @@ int fota_ext_downloader_on_image_ready(void) #elif (MBED_CLOUD_CLIENT_FOTA_MULTICAST_SUPPORT == FOTA_MULTICAST_BR_MODE) +#if !(defined(TARGET_LIKE_LINUX)) static int multicast_br_candidate_iterate_handler(fota_candidate_iterate_callback_info *info) { // Nothing to do - candidate already here return FOTA_STATUS_SUCCESS; } +#endif static int multicast_br_post_install_handler(const char *component_name, const fota_header_info_t *expected_header_info) { diff --git a/fota/fota_app_ifs.c b/fota/fota_app_ifs.c index ff4e72483..22d94eff7 100644 --- a/fota/fota_app_ifs.c +++ b/fota/fota_app_ifs.c @@ -38,7 +38,7 @@ void fota_app_authorize() { - fota_event_handler_defer_with_result(fota_on_authorize, 0); + fota_event_handler_defer_with_result(fota_on_authorize, FOTA_INSTALL_STATE_AUTHORIZE /*This parameter is relevant only to the FOTA install stage.*/); } void fota_app_reject(int32_t reason) @@ -48,7 +48,12 @@ void fota_app_reject(int32_t reason) void fota_app_defer() { - fota_event_handler_defer_with_result(fota_on_defer, 0); + fota_event_handler_defer_with_result(fota_on_defer, FOTA_INSTALL_STATE_DEFER /*This parameter is relevant only to the FOTA install stage.*/); +} + +void fota_app_postpone_reboot() +{ + fota_event_handler_defer_with_result(fota_on_defer, FOTA_INSTALL_STATE_POSTPONE_REBOOT /*This parameter is relevant only to the FOTA install stage.*/); } void fota_app_resume(void) @@ -91,7 +96,7 @@ int fota_app_on_complete(int32_t status) The user application is supposed to save all current work before rebooting. - Note: the authorization call can be postponed and called later. + Note: The authorization call can be deferred and called later. This doesn't affect the performance of the Cloud Client. */ int fota_app_on_install_authorization(void) @@ -134,6 +139,11 @@ int fota_app_on_download_authorization( candidate_info->payload_size, candidate_info->installed_size ); + } else if (candidate_info->payload_format == FOTA_MANIFEST_PAYLOAD_FORMAT_ENCRYPTED_RAW) { + FOTA_APP_PRINT("Update size %zuB (Encrypted image size %zuB)", + candidate_info->installed_size, + candidate_info->payload_size + ); } else { FOTA_APP_PRINT("Update size %zuB", candidate_info->payload_size); } diff --git a/fota/fota_app_ifs.h b/fota/fota_app_ifs.h index a68732018..e2a8e88a3 100644 --- a/fota/fota_app_ifs.h +++ b/fota/fota_app_ifs.h @@ -113,9 +113,10 @@ int fota_app_on_complete(int32_t status); * If the update process is interrupted, the application can call this function to resume the process. * This API invokes ::fota_app_on_download_authorization() CB. * - * \note The function is implemented only if ::MBED_CLOUD_CLIENT_FOTA_RESUME_SUPPORT build flag is not equal to ::FOTA_RESUME_UNSUPPORTED. - * \note If ::MBED_CLOUD_CLIENT_FOTA_RESUME_SUPPORT build flag is equal to ::FOTA_RESUME_SUPPORT_RESTART, the update flow will restart from the beginning. - * \note If ::MBED_CLOUD_CLIENT_FOTA_RESUME_SUPPORT build flag is equal to ::FOTA_RESUME_SUPPORT_RESUME, the update flow will resume from the point that it was interrupted. + * \note The function is implemented only if the ::MBED_CLOUD_CLIENT_FOTA_RESUME_SUPPORT build flag is not equal to ::FOTA_RESUME_UNSUPPORTED. + * \note If ::MBED_CLOUD_CLIENT_FOTA_RESUME_SUPPORT build flag is equal to ::FOTA_RESUME_SUPPORT_RESTART, the update flow restarts from the beginning. + * \note If ::MBED_CLOUD_CLIENT_FOTA_RESUME_SUPPORT build flag is equal to ::FOTA_RESUME_SUPPORT_RESUME, the update flow resumes from the point that it was interrupted. + * \note FOTA update resume is not supported after the device application calls ::fota_app_postpone_reboot(). * */ void fota_app_resume(void); @@ -129,7 +130,7 @@ void fota_app_resume(void); void fota_app_authorize(void); /** - * Reject Pelion FOTA update. + * Reject and terminate FOTA update. * * ::fota_app_on_download_authorization() and ::fota_app_on_install_authorization() application callbacks may call this API. * @@ -138,16 +139,34 @@ void fota_app_authorize(void); void fota_app_reject(int32_t reason); /** - * Defer Pelion FOTA update. + * Defer FOTA update. * - * The FOTA client releases resources and reattempts the update on the next boot after device registration or when the device application calls + * Stop all operations related to update process. + * The FOTA client pauses the FOTA process, releases resources and reattempts the update when the device application calls * the ::fota_app_resume() API. + * * ::fota_app_on_download_authorization() and ::fota_app_on_install_authorization() application callbacks may call this API. * - * \note The function is implemented only if ::MBED_CLOUD_CLIENT_FOTA_RESUME_SUPPORT build flag is not equal to ::FOTA_RESUME_UNSUPPORTED. + * \note The function is implemented only if the ::MBED_CLOUD_CLIENT_FOTA_RESUME_SUPPORT build flag is not equal to ::FOTA_RESUME_UNSUPPORTED. + * \note If the client rebooted, the client calls fota_app_on_download_authorization() or fota_app_on_install_authorization() again to re-check for the device application's approval. + * \note The client supports installation defer only before installation starts. Calling this API during the installation process has no effect. + * */ void fota_app_defer(void); +/** + * Postpone device reboot after FOTA update. + * + * For the MAIN mbed-os component, the FOTA client doesn't boot by itself after download is completed. The device application must trigger reboot. + * After reboot, the bootloader installs the MAIN mbed-os component and completes the FOTA process. + * For other components: The FOTA client installs the component but doesn't boot itself. The device application must trigger reboot. + * Only ::fota_app_on_install_authorization() application callbacks may call this API. + * + * \note The function is implemented only if the ::MBED_CLOUD_CLIENT_FOTA_RESUME_SUPPORT build flag is not equal to ::FOTA_RESUME_UNSUPPORTED. + * \note The FOTA client supports postpone reboot only before installation starts. Calling this API during installation process has no effect. + */ +void fota_app_postpone_reboot(void); + /** * Progress bar support for Pelion FOTA update. @@ -206,6 +225,7 @@ int fota_app_on_install_candidate(const char *candidate_fs_name, const manifest_ * It is only available if there is a single main file. * * \note This function does not validate candidate file integrity or authenticity. + * \note Candidate image file will be deleted from its original path after this callback execution. * * \param[in] candidate_file_name Candidate image file name as found in the file system. * diff --git a/fota/fota_base.h b/fota/fota_base.h index e0c85ab56..dc04b90ac 100644 --- a/fota/fota_base.h +++ b/fota/fota_base.h @@ -103,6 +103,14 @@ void unitest_halt(void); #define FOTA_ALIGN_DOWN(val, size) ((val) / (size) * (size)) + +#if defined(__GNUC__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +#define FOTA_UINT64_TO_LE __builtin_bswap64 +#else +#define FOTA_UINT64_TO_LE +#endif + + #ifdef __cplusplus } #endif diff --git a/fota/fota_candidate.c b/fota/fota_candidate.c index 362809779..a868f89b4 100644 --- a/fota/fota_candidate.c +++ b/fota/fota_candidate.c @@ -30,6 +30,11 @@ #include #include +#if defined(TARGET_LIKE_LINUX) +#include +#include "fota/platform/linux/fota_platform_linux.h" +#endif //(TARGET_LIKE_LINUX) + typedef struct { size_t bd_read_size; size_t bd_prog_size; @@ -134,9 +139,7 @@ static void cleanup() return; } #if (MBED_CLOUD_CLIENT_FOTA_ENCRYPTION_SUPPORT == 1) - if (ctx->enc_ctx) { - fota_encrypt_finalize(&ctx->enc_ctx); - } + fota_encrypt_finalize(&ctx->enc_ctx); #endif free(ctx->fragment_buf); free(ctx); @@ -266,7 +269,14 @@ static int fota_candidate_extract_start(bool force_encrypt, const char *expected uint8_t zero_key[FOTA_ENCRYPT_KEY_SIZE] = {0}; size_t volatile loop_check; +#if (MBED_CLOUD_CLIENT_FOTA_KEY_ENCRYPTION != FOTA_USE_ENCRYPTED_ONE_TIME_FW_KEY) ret = fota_nvm_fw_encryption_key_get(fw_key); +#else + ret = fota_decrypt_fw_key(fw_key, + ctx->header_info.encrypted_fw_key, + ctx->header_info.encrypted_fw_key_tag, + ctx->header_info.encrypted_fw_key_iv); +#endif if (ret) { FOTA_TRACE_ERROR("FW encryption key get failed. ret %d", ret); goto fail; @@ -539,9 +549,7 @@ int fota_candidate_iterate_image(uint8_t validate, bool force_encrypt, const cha } fail: - if (hash_ctx) { - fota_hash_finish(&hash_ctx); - } + fota_hash_finish(&hash_ctx); cleanup(); return ret; } @@ -554,6 +562,14 @@ int fota_candidate_erase(void) return ret; } ret = fota_bd_erase(fota_candidate_get_config()->storage_start_addr, erase_size); + +#if defined(TARGET_LIKE_LINUX) + // for Linux remove both "update_storage" (blockdevice file) and "candidate" file(the FOTA candidate) + FOTA_TRACE_DEBUG("removing blockdevice and candidate files %s, %s:", fota_linux_get_update_storage_file_name(), fota_linux_get_candidate_file_name()); + remove(fota_linux_get_update_storage_file_name()); + remove(fota_linux_get_candidate_file_name()); //might not exist if user app moved it. +#endif + return ret; } diff --git a/fota/fota_config.h b/fota/fota_config.h index 0cf376bd3..3c03fa1ff 100644 --- a/fota/fota_config.h +++ b/fota/fota_config.h @@ -206,6 +206,12 @@ extern char *program_invocation_name; #error "MBED_CLOUD_CLIENT_FOTA_STORAGE_START_ADDR must be set" #endif +#if (MBED_CLOUD_CLIENT_FOTA_RESUME_SUPPORT == FOTA_RESUME_SUPPORT_RESUME) +#if !defined(FOTA_BD_SIMULATE_ERASE) +#define FOTA_BD_SIMULATE_ERASE 1 +#endif +#endif + #endif // (MBED_CLOUD_CLIENT_FOTA_BLOCK_DEVICE_TYPE == FOTA_INTERNAL_FLASH_MBED_OS_BD) || (MBED_CLOUD_CLIENT_FOTA_BLOCK_DEVICE_TYPE == FOTA_DEFAULT_MBED_OS_BD ) || (MBED_CLOUD_CLIENT_FOTA_BLOCK_DEVICE_TYPE == FOTA_CUSTOM_MBED_OS_BD ) #if MBED_CLOUD_CLIENT_FOTA_BLOCK_DEVICE_TYPE == FOTA_EXTERNAL_BD @@ -225,7 +231,12 @@ extern char *program_invocation_name; #if !defined(FOTA_MANIFEST_VENDOR_DATA_SIZE) #define FOTA_MANIFEST_VENDOR_DATA_SIZE 0 #endif - +#if !defined(FOTA_VENDOR_ID_LEN) +#define FOTA_VENDOR_ID_LEN 16 +#endif +#if !defined(FOTA_CLASS_ID_LEN) +#define FOTA_CLASS_ID_LEN 16 +#endif #if (FOTA_MANIFEST_VENDOR_DATA_SIZE > 0) // asn.1 (TLV) overhead #define __FOTA_VENDOR_DATA_OVERHEAD 4 #else @@ -240,33 +251,40 @@ extern char *program_invocation_name; #define MBED_CLOUD_CLIENT_FOTA_CANDIDATE_BLOCK_SIZE 1024 #endif -#define FOTA_USE_ONE_TIME_FW_KEY 0 +#if !defined(MBED_CLOUD_CLIENT_FOTA_ENCRYPTION_SUPPORT) +#define MBED_CLOUD_CLIENT_FOTA_ENCRYPTION_SUPPORT 0 +#endif // !defined(MBED_CLOUD_CLIENT_FOTA_ENCRYPTION_SUPPORT) + #define FOTA_USE_DEVICE_KEY 1 +#define FOTA_USE_ENCRYPTED_ONE_TIME_FW_KEY 2 -#if !defined(MBED_CLOUD_CLIENT_FOTA_KEY_ENCRYPTION) -#if (MBED_CLOUD_CLIENT_FOTA_ENCRYPTION_SUPPORT == 1) && defined(__MBED__) -#define MBED_CLOUD_CLIENT_FOTA_KEY_ENCRYPTION FOTA_USE_DEVICE_KEY -#else -#define MBED_CLOUD_CLIENT_FOTA_KEY_ENCRYPTION FOTA_USE_ONE_TIME_FW_KEY -#endif +#if MBED_CLOUD_CLIENT_FOTA_ENCRYPTION_SUPPORT == 1 && !defined(MBED_CLOUD_CLIENT_FOTA_KEY_ENCRYPTION) +#define MBED_CLOUD_CLIENT_FOTA_KEY_ENCRYPTION FOTA_USE_ENCRYPTED_ONE_TIME_FW_KEY #endif -#if (MBED_CLOUD_CLIENT_FOTA_KEY_ENCRYPTION == FOTA_USE_DEVICE_KEY) -#if (MBED_CLOUD_CLIENT_FOTA_ENCRYPTION_SUPPORT == 0) || (!(defined(MBED_CONF_MBED_CLOUD_CLIENT_EXTERNAL_SST_SUPPORT)) && !(defined(__MBED__))) -#error FOTA_USE_DEVICE_KEY should be used only for with MBED_CONF_MBED_CLOUD_CLIENT_EXTERNAL_SST_SUPPORT or __MBED__ with encryption enabled +#if MBED_CLOUD_CLIENT_FOTA_ENCRYPTION_SUPPORT == 0 + +#if defined(MBED_CLOUD_CLIENT_FOTA_KEY_ENCRYPTION) +#warning MBED_CLOUD_CLIENT_FOTA_KEY_ENCRYPTION is ignored if MBED_CLOUD_CLIENT_FOTA_ENCRYPTION_SUPPORT is disabled #endif + +#else // MBED_CLOUD_CLIENT_FOTA_ENCRYPTION_SUPPORT == 1 + +#if (MBED_CLOUD_CLIENT_FOTA_KEY_ENCRYPTION != FOTA_USE_DEVICE_KEY) && \ + (MBED_CLOUD_CLIENT_FOTA_KEY_ENCRYPTION != FOTA_USE_ENCRYPTED_ONE_TIME_FW_KEY) +#error Unknown MBED_CLOUD_CLIENT_FOTA_KEY_ENCRYPTION type #endif -#define FOTA_ENCRYPT_KEY_NO_DERIVATION 0 -#define FOTA_ENCRYPT_KEY_ECB_DERIVATION 1 -#define FOTA_ENCRYPT_KEY_HMAC_DERIVATION 2 +#if (MBED_CLOUD_CLIENT_FOTA_KEY_ENCRYPTION == FOTA_USE_DEVICE_KEY) +#warning FOTA_USE_DEVICE_KEY is deprecated and contains security vulnerability. \ + Please consider using FOTA_USE_ENCRYPTED_ONE_TIME_FW_KEY instead. +#endif -#if !defined(MBED_CLOUD_CLIENT_FOTA_KEY_DERIVATION) -#if (MBED_CLOUD_CLIENT_FOTA_ENCRYPTION_SUPPORT == 1) -#define MBED_CLOUD_CLIENT_FOTA_KEY_DERIVATION FOTA_ENCRYPT_KEY_HMAC_DERIVATION -#else -#define MBED_CLOUD_CLIENT_FOTA_KEY_DERIVATION FOTA_ENCRYPT_KEY_NO_DERIVATION +#if (MBED_CLOUD_CLIENT_FOTA_CANDIDATE_BLOCK_SIZE != FOTA_CLOUD_ENCRYPTION_BLOCK_SIZE) +#warning 'encrypted-raw' payload format will not be supported because \ + MBED_CLOUD_CLIENT_FOTA_CANDIDATE_BLOCK_SIZE is different than cloud encryption block size. #endif + #endif #define FOTA_PUBLIC_KEY_NOT_SUPPORTED_FORMAT 0 @@ -349,10 +367,6 @@ extern char *program_invocation_name; #define FOTA_HEADER_HAS_CANDIDATE_READY 1 -#if !defined(MBED_CLOUD_CLIENT_FOTA_ENCRYPTION_SUPPORT) -#define MBED_CLOUD_CLIENT_FOTA_ENCRYPTION_SUPPORT 0 -#endif // !defined(MBED_CLOUD_CLIENT_FOTA_ENCRYPTION_SUPPORT) - #else // LEGACY profile (MBED_CLOUD_CLIENT_FOTA_FW_HEADER_VERSION == 2) #if (FOTA_NUM_COMPONENTS > 1) || defined(FOTA_INTERNAL_COMPONENTS_SUPPORT) @@ -364,9 +378,7 @@ extern char *program_invocation_name; #define FOTA_HEADER_HAS_CANDIDATE_READY 0 #endif -#if !defined(MBED_CLOUD_CLIENT_FOTA_ENCRYPTION_SUPPORT) -#define MBED_CLOUD_CLIENT_FOTA_ENCRYPTION_SUPPORT 0 -#elif (MBED_CLOUD_CLIENT_FOTA_ENCRYPTION_SUPPORT == 1) +#if (MBED_CLOUD_CLIENT_FOTA_ENCRYPTION_SUPPORT == 1) #error MBED_CLOUD_CLIENT_FOTA_ENCRYPTION_SUPPORT enabled only for header version >= 3 #endif // !defined(MBED_CLOUD_CLIENT_FOTA_ENCRYPTION_SUPPORT) diff --git a/fota/fota_crypto.c b/fota/fota_crypto.c index 67acd221a..126b4f75f 100644 --- a/fota/fota_crypto.c +++ b/fota/fota_crypto.c @@ -26,10 +26,12 @@ #include "fota/fota_status.h" #include "fota/fota_crypto_defs.h" #include "fota/fota_nvm.h" +#include "fota_device_key.h" #include "mbedtls/sha256.h" #include "mbedtls/entropy.h" #include "mbedtls/ccm.h" #include "mbedtls/aes.h" +#include "mbedtls/md.h" #include "mbedtls/platform_util.h" #if (MBED_CLOUD_CLIENT_FOTA_PUBLIC_KEY_FORMAT == FOTA_RAW_PUBLIC_KEY_FORMAT) && defined(MBEDTLS_USE_TINYCRYPT) @@ -58,10 +60,6 @@ #include "shared_rng.h" #endif -#if (MBED_CLOUD_CLIENT_FOTA_KEY_DERIVATION == FOTA_ENCRYPT_KEY_HMAC_DERIVATION) -#include "mbedtls/md.h" -#endif - #include #if !defined(MBEDTLS_SSL_CONF_RNG) @@ -82,8 +80,19 @@ typedef struct fota_encrypt_context_s { #define FOTA_DERIVE_KEY_BITS 128 -#if (MBED_CLOUD_CLIENT_FOTA_KEY_DERIVATION == FOTA_ENCRYPT_KEY_ECB_DERIVATION || MBED_CLOUD_CLIENT_FOTA_KEY_DERIVATION == FOTA_ENCRYPT_KEY_HMAC_DERIVATION) +#if (MBED_CLOUD_CLIENT_FOTA_KEY_ENCRYPTION == FOTA_USE_ENCRYPTED_ONE_TIME_FW_KEY) +#define INITIAL_IV_VALUE 1 +#else +#define INITIAL_IV_VALUE 0 +#endif + #if !defined(FOTA_USE_EXTERNAL_SECRET_DERIVATION_STRING) +// Key derivation according to NIST Special Publication 800-108 +// Using KDF in Counter Mode +// For i = 1 to n, do +// K(i) := PRF (KI, [i]2 || Label || 0x00 || Context || [L]2) +// We have only one iteration here, key size is 128 bits + // Building the input : // 01 - i // FOTA - Label @@ -92,17 +101,16 @@ typedef struct fota_encrypt_context_s { // [L]2 - key lenght const unsigned char* fota_get_derivation_string(void) { +#if (MBED_CLOUD_CLIENT_FOTA_KEY_ENCRYPTION == FOTA_USE_ENCRYPTED_ONE_TIME_FW_KEY) + static const unsigned char derivation_string[FOTA_ENCRYPT_KEY_SIZE] = + "\x01" "FOTA" "\x00\x56\x3b\xe9\x8a\x94\xfd\x0d\xc0\x65\x80"; + return derivation_string; +#else return (const unsigned char*)"01FOTA00563be98a94fd0dc0651c0a80"; -} #endif +} #endif -#if (MBED_CLOUD_CLIENT_FOTA_KEY_DERIVATION == FOTA_ENCRYPT_KEY_HMAC_DERIVATION) -// Key derivation according to NIST Special Publication 800-108 -// Using KDF in Counter Mode -// For i = 1 to n, do -// K(i) := PRF (KI, [i]2 || Label || 0x00 || Context || [L]2) -// We have only one iteration here, key size is 128 bits static int derive_key(uint8_t *key) { uint8_t key_buf_hmac[FOTA_CRYPTO_HASH_SIZE]; @@ -115,39 +123,6 @@ static int derive_key(uint8_t *key) return FOTA_STATUS_INTERNAL_CRYPTO_ERROR; } -#endif // FOTA_ENCRYPT_KEY_HMAC_DERIVATION - -#if (MBED_CLOUD_CLIENT_FOTA_KEY_DERIVATION == FOTA_ENCRYPT_KEY_ECB_DERIVATION) -static int derive_key(uint8_t *key) -{ - int ret; - int flow_control = 0; - FOTA_DBG_ASSERT(key); - - // We will only be using 128 bits secret key for key derivation. - // Larger input keys will be truncated to 128 bit length - mbedtls_aes_context ctx = {0}; - mbedtls_aes_init(&ctx); - ret = mbedtls_aes_setkey_enc(&ctx, key, FOTA_DERIVE_KEY_BITS); - if (ret) { - FOTA_TRACE_TLS_ERR(ret); - mbedtls_aes_free(&ctx); - return FOTA_STATUS_INTERNAL_CRYPTO_ERROR; - } - - flow_control++; - // Encrypting only first 128 bits, the reset is discarded, using precalculated hash - ret = mbedtls_aes_crypt_ecb(&ctx, MBEDTLS_AES_ENCRYPT, fota_get_derivation_string(), key); - mbedtls_aes_free(&ctx); - if (ret) { - FOTA_TRACE_TLS_ERR(ret); - return FOTA_STATUS_INTERNAL_CRYPTO_ERROR; - } - - flow_control++; - return (flow_control == 2) ? FOTA_STATUS_SUCCESS : FOTA_STATUS_INTERNAL_ERROR; -} -#endif // FOTA_ENCRYPT_KEY_ECB_DERIVATION int fota_encrypt_decrypt_start(fota_encrypt_context_t **ctx, const uint8_t *key, uint32_t key_size) { @@ -158,7 +133,7 @@ int fota_encrypt_decrypt_start(fota_encrypt_context_t **ctx, const uint8_t *key, const uint8_t *key_to_use = key; -#if (MBED_CLOUD_CLIENT_FOTA_KEY_DERIVATION == FOTA_ENCRYPT_KEY_ECB_DERIVATION || MBED_CLOUD_CLIENT_FOTA_KEY_DERIVATION == FOTA_ENCRYPT_KEY_HMAC_DERIVATION) +#if (MBED_CLOUD_CLIENT_FOTA_KEY_ENCRYPTION == FOTA_USE_DEVICE_KEY) uint8_t derived_key[key_size]; fota_fi_memcpy(derived_key, key_to_use, key_size); ret = derive_key(derived_key); @@ -166,7 +141,7 @@ int fota_encrypt_decrypt_start(fota_encrypt_context_t **ctx, const uint8_t *key, return ret; } key_to_use = derived_key; -#endif // FOTA_ENCRYPT_KEY_ECB_DERIVATION || FOTA_DEVICE_KEYFORCE_DERIVATION +#endif fota_encrypt_context_t *enc_ctx = (fota_encrypt_context_t *) malloc(sizeof(fota_encrypt_context_t)); if (!enc_ctx) { @@ -174,12 +149,13 @@ int fota_encrypt_decrypt_start(fota_encrypt_context_t **ctx, const uint8_t *key, } mbedtls_ccm_init(&enc_ctx->ccm_ctx); - enc_ctx->iv = 0; + enc_ctx->iv = INITIAL_IV_VALUE; ret = mbedtls_ccm_setkey(&enc_ctx->ccm_ctx, MBEDTLS_CIPHER_ID_AES, key_to_use, FOTA_DERIVE_KEY_BITS); if (ret) { FOTA_TRACE_TLS_ERR(ret); mbedtls_ccm_free(&enc_ctx->ccm_ctx); + free(enc_ctx); return FOTA_STATUS_INTERNAL_CRYPTO_ERROR; } @@ -191,7 +167,7 @@ int fota_encrypt_decrypt_start(fota_encrypt_context_t **ctx, const uint8_t *key, void fota_encryption_stream_reset(fota_encrypt_context_t *ctx) { FOTA_DBG_ASSERT(ctx); - ctx->iv = 0; + ctx->iv = INITIAL_IV_VALUE; } @@ -212,10 +188,12 @@ int fota_encrypt_data( FOTA_DBG_ASSERT(tag); int ret; - int flow_control = 0; + volatile int flow_control = 0; + uint64_t le_iv = FOTA_UINT64_TO_LE(ctx->iv); + ret = mbedtls_ccm_encrypt_and_tag( &ctx->ccm_ctx, buf_size, - (const unsigned char *) &ctx->iv, sizeof(ctx->iv), + (const unsigned char *) &le_iv, sizeof(ctx->iv), NULL, 0, in_buf, out_buf, tag, FOTA_ENCRYPT_TAG_SIZE); @@ -238,11 +216,13 @@ int fota_decrypt_data( FOTA_DBG_ASSERT(in_buf); FOTA_DBG_ASSERT(out_buf); FOTA_DBG_ASSERT(tag); + int ret; + uint64_t le_iv = FOTA_UINT64_TO_LE(ctx->iv); ret = mbedtls_ccm_auth_decrypt( &ctx->ccm_ctx, buf_size, - (const unsigned char *) &ctx->iv, sizeof(ctx->iv), + (const unsigned char *) &le_iv, sizeof(ctx->iv), NULL, 0, in_buf, out_buf, tag, FOTA_ENCRYPT_TAG_SIZE); @@ -259,8 +239,7 @@ int fota_decrypt_data( int fota_encrypt_finalize(fota_encrypt_context_t **ctx) { - FOTA_DBG_ASSERT(ctx); - if (*ctx) { + if (ctx && *ctx) { mbedtls_ccm_free(&(*ctx)->ccm_ctx); free(*ctx); *ctx = NULL; @@ -269,6 +248,127 @@ int fota_encrypt_finalize(fota_encrypt_context_t **ctx) return FOTA_STATUS_SUCCESS; } +#if (MBED_CLOUD_CLIENT_FOTA_KEY_ENCRYPTION == FOTA_USE_ENCRYPTED_ONE_TIME_FW_KEY) + +static int encrypt_decrypt_fw_key_start(fota_encrypt_context_t **ctx) +{ + int ret; + uint8_t dev_key[FOTA_ENCRYPT_KEY_SIZE] = {0}; + + // init CCM contex with key derived from device key + + ret = fota_get_device_key_128bit(dev_key, FOTA_ENCRYPT_KEY_SIZE); + if (ret) { + FOTA_TRACE_ERROR("Failed to encrypt key. ret %d", ret); + return ret; + } + + ret = derive_key(dev_key); + if (ret) { + FOTA_TRACE_ERROR("Failed to derive key. ret %d", ret); + goto fail; + } + + ret = fota_encrypt_decrypt_start(ctx, dev_key, sizeof(dev_key)); + if (ret) { + FOTA_TRACE_ERROR("Failed to start encryption engine. ret %d", ret); + goto fail; + } + +fail: + // Clear key's buffer from memory due to security reasons + memset(dev_key, 0, FOTA_ENCRYPT_KEY_SIZE); + return ret; +} + +/* + * Encrypt fw key. + * + * \param[in] plain_key Key buffer to encrypt + * \param[out] encrypted_fw_key Buffer holding the encrypted data + * \param[out] encrypted_fw_key_tag Buffer holding the encrypted tag + * \param[out] encrypted_fw_key_iv Buffer holding the encrypted buffer + * \return FOTA_STATUS_SUCCESS on success + */ +int fota_encrypt_fw_key(uint8_t plain_key[FOTA_ENCRYPT_KEY_SIZE], + uint8_t encrypted_fw_key[FOTA_ENCRYPT_KEY_SIZE], + uint8_t encrypted_fw_key_tag[FOTA_ENCRYPT_TAG_SIZE], + uint64_t *encrypted_fw_key_iv) +{ + FOTA_DBG_ASSERT(encrypted_fw_key_iv); + int ret; + fota_encrypt_context_t *temp_ctx = NULL; + + // encrypt gen_key buffer using device key and store it in the header + + ret = encrypt_decrypt_fw_key_start(&temp_ctx); + if (ret) { + return ret; + } + + // generate random iv + ret = fota_gen_random((uint8_t*)encrypted_fw_key_iv, sizeof(uint64_t)); + if (ret) { + FOTA_TRACE_ERROR("Unable to generate random data. ret %d", ret); + return ret; + } + + // set ccm to use generated iv + temp_ctx->iv = *encrypted_fw_key_iv; + + ret = fota_encrypt_data(temp_ctx, + plain_key, FOTA_ENCRYPT_KEY_SIZE, + encrypted_fw_key, encrypted_fw_key_tag); + if (ret) { + FOTA_TRACE_ERROR("Failed to encrypt buffer. ret %d", ret); + goto fail; + } + +fail: + fota_encrypt_finalize(&temp_ctx); + return ret; +} + +/* + * Decrypt fw key. + * + * \param[out] plain_key Key buffer to encrypt + * \param[in] encrypted_fw_key Buffer holding the encrypted data + * \param[in] encrypted_fw_key_tag Buffer holding the encrypted tag + * \param[in] encrypted_fw_key_iv Buffer holding the encrypted buffer + * \return FOTA_STATUS_SUCCESS on success + */ +int fota_decrypt_fw_key(uint8_t plain_key[FOTA_ENCRYPT_KEY_SIZE], + uint8_t encrypted_fw_key[FOTA_ENCRYPT_KEY_SIZE], + uint8_t encrypted_fw_key_tag[FOTA_ENCRYPT_TAG_SIZE], + uint64_t encrypted_fw_key_iv) +{ + int ret; + fota_encrypt_context_t *temp_ctx = NULL; + + // decrypt encrypted_fw_key buffer using key derived from device key + + ret = encrypt_decrypt_fw_key_start(&temp_ctx); + if (ret) { + return ret; + } + + // set ccm to use generated iv + temp_ctx->iv = encrypted_fw_key_iv; + + ret = fota_decrypt_data(temp_ctx, encrypted_fw_key, FOTA_ENCRYPT_KEY_SIZE, + plain_key, encrypted_fw_key_tag); + if (ret) { + FOTA_TRACE_ERROR("Failed to encrypt buffer. ret %d", ret); + goto fail; + } + +fail: + fota_encrypt_finalize(&temp_ctx); + return ret; +} +#endif // (MBED_CLOUD_CLIENT_FOTA_KEY_ENCRYPTION == FOTA_USE_ENCRYPTED_ONE_TIME_FW_KEY) + int fota_hash_start(fota_hash_context_t **ctx) { FOTA_DBG_ASSERT(ctx); @@ -303,6 +403,14 @@ int fota_hash_update(fota_hash_context_t *ctx, const uint8_t *buf, uint32_t buf_ return FOTA_STATUS_SUCCESS; } +void fota_hash_clone(fota_hash_context_t *dst_ctx, const fota_hash_context_t *src_ctx) +{ + FOTA_DBG_ASSERT(dst_ctx); + FOTA_DBG_ASSERT(src_ctx); + mbedtls_sha256_clone(&dst_ctx->sha256_ctx, &src_ctx->sha256_ctx); + return; +} + int fota_hash_result(fota_hash_context_t *ctx, uint8_t *hash_buf) { FOTA_DBG_ASSERT(ctx); @@ -317,8 +425,7 @@ int fota_hash_result(fota_hash_context_t *ctx, uint8_t *hash_buf) void fota_hash_finish(fota_hash_context_t **ctx) { - FOTA_DBG_ASSERT(ctx); - if (*ctx) { + if (ctx && *ctx) { mbedtls_sha256_free(&(*ctx)->sha256_ctx); free(*ctx); *ctx = NULL; @@ -392,7 +499,7 @@ int fota_verify_signature_prehashed( const uint8_t *sig, size_t sig_len ) { - int flow_control = 0; + volatile int flow_control = 0; uint8_t public_key[FOTA_UPDATE_RAW_PUBLIC_KEY_SIZE]; int ret = fota_nvm_get_update_public_key(public_key); @@ -425,7 +532,7 @@ int fota_verify_signature_prehashed( const uint8_t *sig, size_t sig_len ) { - int flow_control = 0; + volatile int flow_control = 0; uint8_t public_key[FOTA_UPDATE_RAW_PUBLIC_KEY_SIZE]; int ret = FOTA_STATUS_INTERNAL_ERROR; int tmp_ret = fota_nvm_get_update_public_key(public_key); @@ -528,7 +635,7 @@ int fota_verify_signature_prehashed( ) { int ret; - int flow_control = 0; + volatile int flow_control = 0; int fota_status = FOTA_STATUS_INTERNAL_ERROR; uint8_t *update_crt_data; mbedtls_pk_context *pk_ctx_ptr = NULL; @@ -623,7 +730,7 @@ int fota_verify_signature( const uint8_t *sig, size_t sig_len ) { - int flow_control = 0; + volatile int flow_control = 0; uint8_t digest[FOTA_CRYPTO_HASH_SIZE] = {0}; mbedtls_sha256_context sha256_ctx = {0}; mbedtls_sha256_init(&sha256_ctx); diff --git a/fota/fota_crypto.h b/fota/fota_crypto.h index a7073d872..45f1ef40d 100644 --- a/fota/fota_crypto.h +++ b/fota/fota_crypto.h @@ -49,10 +49,40 @@ int fota_decrypt_data( uint8_t *tag); int fota_encrypt_finalize(fota_encrypt_context_t **ctx); +#if (MBED_CLOUD_CLIENT_FOTA_KEY_ENCRYPTION == FOTA_USE_ENCRYPTED_ONE_TIME_FW_KEY) +/* + * Encrypt fw key. + * + * \param[in] plain_key Key buffer to encrypt + * \param[out] encrypted_fw_key Buffer holding the encrypted data + * \param[out] encrypted_fw_key_tag Buffer holding the encrypted tag + * \param[out] encrypted_fw_key_iv Buffer holding the encrypted buffer + * \return FOTA_STATUS_SUCCESS on success + */ +int fota_encrypt_fw_key(uint8_t plain_key[FOTA_ENCRYPT_KEY_SIZE], + uint8_t encrypted_fw_key[FOTA_ENCRYPT_KEY_SIZE], + uint8_t encrypted_fw_key_tag[FOTA_ENCRYPT_TAG_SIZE], + uint64_t *encrypted_fw_key_iv); +/* + * Decrypt fw key. + * + * \param[out] plain_key Key buffer to encrypt + * \param[in] encrypted_fw_key Buffer holding the encrypted data + * \param[in] encrypted_fw_key_tag Buffer holding the encrypted tag + * \param[in] encrypted_fw_key_iv Buffer holding the encrypted buffer + * \return FOTA_STATUS_SUCCESS on success + */ +int fota_decrypt_fw_key(uint8_t plain_key[FOTA_ENCRYPT_KEY_SIZE], + uint8_t encrypted_fw_key[FOTA_ENCRYPT_KEY_SIZE], + uint8_t encrypted_fw_key_tag[FOTA_ENCRYPT_TAG_SIZE], + uint64_t encrypted_fw_key_iv); +#endif // (MBED_CLOUD_CLIENT_FOTA_KEY_ENCRYPTION == FOTA_USE_ENCRYPTED_ONE_TIME_FW_KEY) + typedef struct fota_hash_context_s fota_hash_context_t; int fota_hash_start(fota_hash_context_t **ctx); int fota_hash_update(fota_hash_context_t *ctx, const uint8_t *buf, uint32_t buf_size); +void fota_hash_clone(fota_hash_context_t *dst_ctx, const fota_hash_context_t *src_ctx); int fota_hash_result(fota_hash_context_t *ctx, uint8_t *hash_buf); void fota_hash_finish(fota_hash_context_t **ctx); @@ -147,9 +177,7 @@ int fota_verify_signature_prehashed( const uint8_t *sig, size_t sig_len ); -#if (MBED_CLOUD_CLIENT_FOTA_KEY_DERIVATION == FOTA_ENCRYPT_KEY_ECB_DERIVATION || MBED_CLOUD_CLIENT_FOTA_KEY_DERIVATION == FOTA_ENCRYPT_KEY_HMAC_DERIVATION) const unsigned char* fota_get_derivation_string(void); -#endif #ifdef __cplusplus } diff --git a/fota/fota_device_key.cpp b/fota/fota_device_key.cpp index 4471205c3..eb57c4dbc 100644 --- a/fota/fota_device_key.cpp +++ b/fota/fota_device_key.cpp @@ -16,15 +16,21 @@ // limitations under the License. // ---------------------------------------------------------------------------- -#ifdef MBED_CLOUD_CLIENT_FOTA_ENABLE +#if defined(MBED_CLOUD_CLIENT_FOTA_ENABLE) && !defined(FOTA_UNIT_TEST) #include #include #include "fota_device_key.h" #include "fota/fota_crypto_defs.h" #include "fota/fota_status.h" -// fota_get_device_key_128bit in use only in case defined MBED_CLOUD_CLIENT_FOTA_KEY_ENCRYPTION == FOTA_USE_DEVICE_KEY or external legacy header -#if ((MBED_CLOUD_CLIENT_FOTA_FW_HEADER_VERSION == 2) && (MBED_CLOUD_CLIENT_FOTA_FW_HEADER_EXTERNAL == 1)) || (MBED_CLOUD_CLIENT_FOTA_KEY_ENCRYPTION == FOTA_USE_DEVICE_KEY) +#ifdef TARGET_LIKE_MBED +#include "mbed_error.h" +#endif + +#if ((MBED_CLOUD_CLIENT_FOTA_FW_HEADER_VERSION == 2) && (MBED_CLOUD_CLIENT_FOTA_FW_HEADER_EXTERNAL == 1)) || \ + (MBED_CLOUD_CLIENT_FOTA_ENCRYPTION_SUPPORT == 1) + +#if defined(MBED_CONF_MBED_CLOUD_CLIENT_EXTERNAL_SST_SUPPORT) #include "kv_config.h" #include "KVMap.h" @@ -62,5 +68,24 @@ extern "C" int8_t fota_get_device_key_128bit(uint8_t *key, uint32_t keyLenBytes) } -#endif // #if ((MBED_CLOUD_CLIENT_FOTA_FW_HEADER_VERSION == 2) && (MBED_CLOUD_CLIENT_FOTA_FW_HEADER_EXTERNAL == 1)) || (MBED_CLOUD_CLIENT_FOTA_KEY_ENCRYPTION == FOTA_USE_DEVICE_KEY) +#else + +#include "pal.h" + +int8_t fota_get_device_key_128bit(uint8_t *key, uint32_t keyLenBytes) +{ + palStatus_t ret = pal_osGetDeviceKey(palOsStorageEncryptionKey128Bit, key, keyLenBytes); + if (ret == PAL_SUCCESS) { + return FOTA_STATUS_SUCCESS; + } else if (ret == PAL_ERR_ITEM_NOT_EXIST) { + return FOTA_STATUS_NOT_FOUND; + } else { + return FOTA_STATUS_INTERNAL_ERROR; + } + + return FOTA_STATUS_SUCCESS; +} + +#endif // MBED_CONF_MBED_CLOUD_CLIENT_EXTERNAL_SST_SUPPORT +#endif #endif //MBED_CLOUD_CLIENT_FOTA_ENABLE diff --git a/fota/fota_device_key.h b/fota/fota_device_key.h index 0d583989a..e3d18e046 100644 --- a/fota/fota_device_key.h +++ b/fota/fota_device_key.h @@ -19,22 +19,18 @@ #ifndef FOTA_DEVICE_KEY #define FOTA_DEVICE_KEY -#ifdef __MBED__ - #ifdef __cplusplus extern "C" { #endif -#if ((MBED_CLOUD_CLIENT_FOTA_FW_HEADER_VERSION == 2) && (MBED_CLOUD_CLIENT_FOTA_FW_HEADER_EXTERNAL == 1)) || (MBED_CLOUD_CLIENT_FOTA_KEY_ENCRYPTION == FOTA_USE_DEVICE_KEY) - +#if ((MBED_CLOUD_CLIENT_FOTA_FW_HEADER_VERSION == 2) && (MBED_CLOUD_CLIENT_FOTA_FW_HEADER_EXTERNAL == 1)) || \ + (MBED_CLOUD_CLIENT_FOTA_ENCRYPTION_SUPPORT == 1) int8_t fota_get_device_key_128bit(uint8_t *key, uint32_t keyLenBytes); -#endif // #if (MBED_CLOUD_CLIENT_FOTA_FW_HEADER_VERSION == 2) || (MBED_CLOUD_CLIENT_FOTA_KEY_ENCRYPTION == FOTA_USE_DEVICE_KEY) +#endif #ifdef __cplusplus } #endif -#endif - #endif // FOTA_DEVICE_KEY diff --git a/fota/fota_header_info.h b/fota/fota_header_info.h index c6b5e849b..57f6755e0 100644 --- a/fota/fota_header_info.h +++ b/fota/fota_header_info.h @@ -92,8 +92,14 @@ typedef struct { uint16_t block_size; /*< Block size. Encryption block size if encrypted, validated block size if unencrypted and block validation turned on */ uint8_t precursor[FOTA_CRYPTO_HASH_SIZE]; /*< contains previously installed FW SHA256 digest */ - uint8_t vendor_data[FOTA_MANIFEST_VENDOR_DATA_SIZE]; /*< Vendor custom data as received in Pelion FOTA manifest. */ + uint8_t vendor_data[FOTA_MANIFEST_VENDOR_DATA_SIZE]; +#if (MBED_CLOUD_CLIENT_FOTA_KEY_ENCRYPTION == FOTA_USE_ENCRYPTED_ONE_TIME_FW_KEY) + /*< Encrypted info to encrypt\decrypt payload Encryption key */ + uint8_t encrypted_fw_key[FOTA_ENCRYPT_KEY_SIZE]; + uint8_t encrypted_fw_key_tag[FOTA_ENCRYPT_TAG_SIZE]; + uint64_t encrypted_fw_key_iv; +#endif uint32_t footer; // !New fields of the external header must me added in the end of the current structure, // otherwise additional field will break older version of the bootloader. diff --git a/fota/fota_internal.h b/fota/fota_internal.h index 2ae201d61..d90b5464c 100644 --- a/fota/fota_internal.h +++ b/fota/fota_internal.h @@ -40,6 +40,7 @@ typedef enum { FOTA_STATE_AWAIT_DOWNLOAD_AUTHORIZATION, FOTA_STATE_DOWNLOADING, FOTA_STATE_AWAIT_INSTALL_AUTHORIZATION, + FOTA_STATE_INSTALLING, FOTA_STATE_INVALID = 255, } fota_state_e; @@ -49,6 +50,17 @@ typedef enum { FOTA_RESUME_STATE_ONGOING, } fota_resume_state_e; +typedef enum { + FOTA_INSTALL_STATE_IDLE, + FOTA_INSTALL_STATE_AUTHORIZE, + FOTA_INSTALL_STATE_DEFER, + FOTA_INSTALL_STATE_POSTPONE_REBOOT +} fota_install_state_e; + + +// The encryption block size used to encrypt payload by the cloud +#define FOTA_CLOUD_ENCRYPTION_BLOCK_SIZE 1024 + // Internal component for BR downloader (must start with '%' as it's internal) #define FOTA_MULTICAST_BR_INT_COMP_NAME "%MC_BR" @@ -63,8 +75,14 @@ typedef struct { uint8_t *delta_buf; fota_delta_ctx_t *delta_ctx; #endif +#if (MBED_CLOUD_CLIENT_FOTA_ENCRYPTION_SUPPORT == 1) fota_encrypt_context_t *enc_ctx; - fota_hash_context_t *curr_fw_hash_ctx; + uint8_t encryption_key[FOTA_ENCRYPT_KEY_SIZE]; +#endif + fota_hash_context_t *payload_hash_ctx; +#if !defined(FOTA_DISABLE_DELTA) + fota_hash_context_t *installed_hash_ctx; +#endif uint8_t *page_buf; uint32_t page_buf_offset; uint32_t page_buf_size; @@ -86,17 +104,31 @@ typedef struct { bool mc_node_update_activated; fota_multicast_node_post_action_callback_t mc_node_post_action_callback; uint8_t *mc_node_frag_buf; - uint8_t *mc_node_manifest_hash[FOTA_CRYPTO_HASH_SIZE]; + uint8_t mc_node_manifest_hash[FOTA_CRYPTO_HASH_SIZE]; #endif } fota_context_t; + +typedef struct { + unsigned int comp_id; + fota_state_e state; +#if (MBED_CLOUD_CLIENT_FOTA_MULTICAST_SUPPORT == FOTA_MULTICAST_BR_MODE) + bool mc_br_update; + fota_multicast_br_post_action_callback_t mc_br_post_action_callback; +#elif (MBED_CLOUD_CLIENT_FOTA_MULTICAST_SUPPORT == FOTA_MULTICAST_NODE_MODE) + bool mc_node_update; + fota_multicast_node_post_action_callback_t mc_node_post_action_callback; +#endif +} fota_persistent_context_t; + + fota_context_t *fota_get_context(void); int fota_is_ready(uint8_t *data, size_t size, fota_state_e *fota_state); void fota_on_manifest(uint8_t *data, size_t size); void fota_on_reject(int32_t status); -void fota_on_defer(int32_t status); +void fota_on_defer(int32_t param); void fota_on_authorize(int32_t status); void fota_on_fragment(uint8_t *buf, size_t size); void fota_on_fragment_failure(int32_t status); diff --git a/fota/fota_manifest.h b/fota/fota_manifest.h index f59b823e4..6ccc5301a 100644 --- a/fota/fota_manifest.h +++ b/fota/fota_manifest.h @@ -36,8 +36,15 @@ extern "C" { #define FOTA_MANIFEST_TRACE_DEBUG(fmt, ...) #endif -#define FOTA_MANIFEST_PAYLOAD_FORMAT_RAW 1 -#define FOTA_MANIFEST_PAYLOAD_FORMAT_DELTA 5 +// Payload format types +#define FOTA_MANIFEST_PAYLOAD_FORMAT_RAW 0x0001 +#define FOTA_MANIFEST_PAYLOAD_FORMAT_DELTA 0x0005 +// V3 only +#define FOTA_MANIFEST_PAYLOAD_FORMAT_ENCRYPTED_RAW 0x0101 +#define FOTA_MANIFEST_PAYLOAD_FORMAT_ENCRYPTED_DELTA 0x0105 // not supported yet + +// Encryption key tags +#define FOTA_MANIFEST_ENCRYPTION_KEY_TAG_AES_128 0x1 /* * Update details as extracted from the Pelion FOTA manifest @@ -57,7 +64,11 @@ typedef struct { #if defined(MBED_CLOUD_CLIENT_FOTA_SIGNED_IMAGE_SUPPORT) uint8_t installed_signature[FOTA_IMAGE_RAW_SIGNATURE_SIZE]; /** Raw encoded signature over installed image */ #endif // defined(MBED_CLOUD_CLIENT_FOTA_SIGNED_IMAGE_SUPPORT) - +#if (MBED_CLOUD_CLIENT_FOTA_ENCRYPTION_SUPPORT == 1) + uint8_t encryption_key[FOTA_ENCRYPT_KEY_SIZE]; /*< Encryption key used to encrypt payload */ +#endif + uint8_t vendor_id[FOTA_VENDOR_ID_LEN]; /*< Vendor ID for passing this to the PT. */ + uint8_t class_id[FOTA_CLASS_ID_LEN]; /*< Class ID for passing to the PT. */ } manifest_firmware_info_t; /* diff --git a/fota/fota_manifest_v3.c b/fota/fota_manifest_v3.c index 039100313..423c8da0e 100644 --- a/fota/fota_manifest_v3.c +++ b/fota/fota_manifest_v3.c @@ -38,6 +38,7 @@ #include "fota/fota_base.h" #include "fota/fota_nvm.h" #include "fota/fota_crypto.h" +#include "fota/fota_internal.h" #include "mbedtls/asn1.h" #include "mbedtls/asn1write.h" #include "mbedtls/x509_crt.h" @@ -104,14 +105,20 @@ static inline int fota_der_encode_signature( #endif // #if (MBED_CLOUD_CLIENT_FOTA_PUBLIC_KEY_FORMAT==FOTA_X509_PUBLIC_KEY_FORMAT) /* - * DeltaMetadata ::= SEQUENCE { - * installed-size INTEGER, - * installed-digest OCTET STRING, - * precursor-digest OCTET STRING - * } + * -- Metadata for payload reconstruction + * PayloadMetadata ::= SEQUENCE { + * -- represents reconstructed payload size + * installed-size INTEGER, + * -- represents reconstructed payload digest + * installed-digest OCTET STRING, + * + * -- Used with 'arm-patch-stream' and 'encrypted-patch', + * -- never for other payload formats + * precursor-digest OCTET STRING OPTIONAL + * } */ -#if !defined(FOTA_DISABLE_DELTA) -static int parse_delta_metadata( +#if !defined(FOTA_DISABLE_DELTA) || (MBED_CLOUD_CLIENT_FOTA_ENCRYPTION_SUPPORT == 1) +static int parse_payload_metadata( const uint8_t *metadata, size_t metadata_size, manifest_firmware_info_t *fw_info, const uint8_t *input_data ) @@ -120,70 +127,93 @@ static int parse_delta_metadata( const unsigned char *metadata_end = metadata + metadata_size; size_t len; - FOTA_MANIFEST_TRACE_DEBUG("Parse DeltaMetadata:installed-size @%d", p - input_data); + FOTA_MANIFEST_TRACE_DEBUG("Parse PayloadMetadata:installed-size @%d", p - input_data); int tls_status = mbedtls_asn1_get_int(&p, metadata_end, (int *) &fw_info->installed_size); if (tls_status != 0) { - FOTA_TRACE_ERROR("Error reading DeltaMetadata:installed-size %d", tls_status); + FOTA_TRACE_ERROR("Error reading PayloadMetadata:installed-size %d", tls_status); return FOTA_STATUS_MANIFEST_MALFORMED; } - FOTA_MANIFEST_TRACE_DEBUG("DeltaMetadata:installed-size %" PRIu32, fw_info->installed_size); + FOTA_MANIFEST_TRACE_DEBUG("PayloadMetadata:installed-size %" PRIu32, fw_info->installed_size); - FOTA_MANIFEST_TRACE_DEBUG("Parse DeltaMetadata:installed-digest @%d", p - input_data); + FOTA_MANIFEST_TRACE_DEBUG("Parse PayloadMetadata:installed-digest @%d", p - input_data); tls_status = mbedtls_asn1_get_tag( &p, metadata_end, &len, MBEDTLS_ASN1_OCTET_STRING); if (tls_status != 0) { - FOTA_TRACE_ERROR("Error reading DeltaMetadata:installed-digest %d", tls_status); + FOTA_TRACE_ERROR("Error reading PayloadMetadata:installed-digest %d", tls_status); return FOTA_STATUS_MANIFEST_MALFORMED; } if (FOTA_CRYPTO_HASH_SIZE != len) { - FOTA_TRACE_ERROR("DeltaMetadata:installed-digest too long %zu", len); + FOTA_TRACE_ERROR("PayloadMetadata:installed-digest too long %zu", len); return FOTA_STATUS_INTERNAL_CRYPTO_ERROR; } memcpy(fw_info->installed_digest, p, len); p += len; - FOTA_MANIFEST_TRACE_DEBUG("Parse DeltaMetadata:precursor-digest @%d", p - input_data); - tls_status = mbedtls_asn1_get_tag( - &p, metadata_end, &len, - MBEDTLS_ASN1_OCTET_STRING); - if (tls_status != 0) { - FOTA_TRACE_ERROR("Error reading DeltaMetadata:precursor-digest %d", tls_status); - return FOTA_STATUS_MANIFEST_MALFORMED; - } +#if !defined(FOTA_DISABLE_DELTA) + if (fw_info->payload_format == FOTA_MANIFEST_PAYLOAD_FORMAT_DELTA) { + FOTA_MANIFEST_TRACE_DEBUG("Parse PayloadMetadata:precursor-digest @%d", p - input_data); + tls_status = mbedtls_asn1_get_tag( + &p, metadata_end, &len, + MBEDTLS_ASN1_OCTET_STRING); + if (tls_status != 0) { + FOTA_TRACE_ERROR("Error reading PayloadMetadata:precursor-digest %d", tls_status); + return FOTA_STATUS_MANIFEST_MALFORMED; + } - if (FOTA_CRYPTO_HASH_SIZE != len) { - FOTA_TRACE_ERROR("DeltaMetadata:precursor-digest too long %zu", len); - return FOTA_STATUS_INTERNAL_CRYPTO_ERROR; + if (FOTA_CRYPTO_HASH_SIZE != len) { + FOTA_TRACE_ERROR("PayloadMetadata:precursor-digest too long %zu", len); + return FOTA_STATUS_INTERNAL_CRYPTO_ERROR; + } + memcpy(fw_info->precursor_digest, p, len); } - memcpy(fw_info->precursor_digest, p, len); +#endif // !FOTA_DISABLE_DELTA return FOTA_STATUS_SUCCESS; } -#endif // !FOTA_DISABLE_DELTA +#endif // !FOTA_DISABLE_DELTA || (MBED_CLOUD_CLIENT_FOTA_ENCRYPTION_SUPPORT == 1) /* - * Manifest ::= SEQUENCE { - * vendor-id OCTET STRING, - * class-id OCTET STRING, - * update-priority INTEGER, - * component-name UTF8String, - * payload-version UTF8String, - * payload-digest OCTET STRING, - * payload-size INTEGER, - * payload-uri UTF8String, - * payload-format ENUMERATED { - * raw-binary(1), - * arm-patch-stream(5) - * }, - * installed-signature OCTET STRING, - * delta-metadata DeltaMetadata OPTIONAL, - * vendor-data OCTET STRING OPTIONAL - * } + * Manifest ::= SEQUENCE { + * + * -- identifier fields + * vendor-id OCTET STRING, + * class-id OCTET STRING, + * + * -- update priority to be passed to an application callback + * update-priority INTEGER, + * + * -- component name + * component-name UTF8String, + * + * -- payload description -- + * payload-version UTF8String, + * payload-digest OCTET STRING, + * payload-size INTEGER, + * payload-uri UTF8String, + * payload-format ENUMERATED { + * -- xx01-xxFF describe payload-format + * -- 01xx-FFxx describe encrypted-format + * raw-binary(1), + * arm-patch-stream(5), + * encrypted-raw(257), -- 0x0101 + * encrypted-patch(261) -- 0x0105 + * }, + * + * -- raw ECDSA signature (r||s) over installed payload + * installed-signature OCTET STRING, + * + * -- Used with 'arm-patch-stream', 'encrypted-raw' and 'encrypted-patch' + * -- never for 'raw-binary' + * payload-metadata PayloadMetadata OPTIONAL, + * + * -- custom data to be passed to an endpoint device + * vendor-data OCTET STRING OPTIONAL + * } */ int parse_manifest_internal( const uint8_t *manifest, size_t manifest_size, @@ -192,9 +222,6 @@ int parse_manifest_internal( int fota_status = FOTA_STATUS_INTERNAL_ERROR; const unsigned char *manifest_end = manifest + manifest_size; unsigned char *p = (unsigned char *) manifest; -#if !defined(FOTA_DISABLE_DELTA) - bool is_delta = false; -#endif size_t len; FOTA_MANIFEST_TRACE_DEBUG("Parse Manifest:vendor-id @%d", p - input_data); @@ -218,7 +245,7 @@ int parse_manifest_internal( return FOTA_STATUS_MANIFEST_WRONG_VENDOR_ID; } #endif // !defined(FOTA_TEST_MANIFEST_BYPASS_VALIDATION) - + memcpy(fw_info->vendor_id, p, len); p += len; FOTA_MANIFEST_TRACE_DEBUG("Parse Manifest:class-id @%d", p - input_data); @@ -242,6 +269,7 @@ int parse_manifest_internal( return FOTA_STATUS_MANIFEST_WRONG_CLASS_ID; } #endif // !defined(FOTA_TEST_MANIFEST_BYPASS_VALIDATION) + memcpy(fw_info->class_id, p, len); p += len; FOTA_MANIFEST_TRACE_DEBUG("Parse Manifest:update-priority @%d", p - input_data); @@ -330,24 +358,36 @@ int parse_manifest_internal( p += len; FOTA_MANIFEST_TRACE_DEBUG("Parse Manifest:payload-format @%d", p - input_data); - int payload_format_value = 0; - tls_status = mbedtls_asn1_get_enumerated_value(&p, manifest_end, &payload_format_value); + tls_status = mbedtls_asn1_get_enumerated_value(&p, manifest_end, &fw_info->payload_format); if (tls_status != 0) { FOTA_TRACE_ERROR("Error reading Manifest:payload-format %d", tls_status); return FOTA_STATUS_MANIFEST_MALFORMED; } - FOTA_MANIFEST_TRACE_DEBUG("Manifest:payload-format %d", payload_format_value); - fw_info->payload_format = payload_format_value; + FOTA_MANIFEST_TRACE_DEBUG("Manifest:payload-format %d", fw_info->payload_format); + switch (fw_info->payload_format) { + case FOTA_MANIFEST_PAYLOAD_FORMAT_RAW: + #if !defined(FOTA_DISABLE_DELTA) - if (payload_format_value == FOTA_MANIFEST_PAYLOAD_FORMAT_DELTA) { - is_delta = true; - } else + case FOTA_MANIFEST_PAYLOAD_FORMAT_DELTA: #endif - if (payload_format_value != FOTA_MANIFEST_PAYLOAD_FORMAT_RAW) { - FOTA_TRACE_ERROR("error unsupported payload format %d - ", payload_format_value); + break; +#if (MBED_CLOUD_CLIENT_FOTA_ENCRYPTION_SUPPORT == 1) + case FOTA_MANIFEST_PAYLOAD_FORMAT_ENCRYPTED_RAW: +#if (MBED_CLOUD_CLIENT_FOTA_CANDIDATE_BLOCK_SIZE != FOTA_CLOUD_ENCRYPTION_BLOCK_SIZE) + // reject manifest because we can't guarantee proper operation + // when device's block size is different then payload's encryption size. + FOTA_TRACE_ERROR("error device doesn't support encrypted-raw payload's block size"); return FOTA_STATUS_MANIFEST_PAYLOAD_UNSUPPORTED; - } +#endif +#endif + break; + + // FOTA_MANIFEST_PAYLOAD_FORMAT_ENCRYPTED_DELTA not supported yet + default: + FOTA_TRACE_ERROR("error unsupported payload format %d - ", fw_info->payload_format); + return FOTA_STATUS_MANIFEST_PAYLOAD_UNSUPPORTED; + } FOTA_MANIFEST_TRACE_DEBUG("Parse Manifest:installed-signature @%d", p - input_data); tls_status = mbedtls_asn1_get_tag( @@ -366,21 +406,21 @@ int parse_manifest_internal( FOTA_MANIFEST_TRACE_DEBUG("installed-signature not found ptr=%p", p); } -#if !defined(FOTA_DISABLE_DELTA) - if (is_delta) { - FOTA_MANIFEST_TRACE_DEBUG("Parse Manifest:delta-metadata @%d", p - input_data); +#if !defined(FOTA_DISABLE_DELTA) || (MBED_CLOUD_CLIENT_FOTA_ENCRYPTION_SUPPORT == 1) + if (fw_info->payload_format != FOTA_MANIFEST_PAYLOAD_FORMAT_RAW) { + FOTA_MANIFEST_TRACE_DEBUG("Parse Manifest:payload-metadata @%d", p - input_data); tls_status = mbedtls_asn1_get_tag( &p, manifest_end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE); if (tls_status != 0) { - FOTA_TRACE_ERROR("Error reading Manifest:delta-metadata %d", tls_status); + FOTA_TRACE_ERROR("Error reading Manifest:payload-metadata %d", tls_status); return FOTA_STATUS_MANIFEST_MALFORMED; } - fota_status = parse_delta_metadata(p, len, fw_info, input_data); + fota_status = parse_payload_metadata(p, len, fw_info, input_data); if (fota_status != 0) { - FOTA_TRACE_ERROR("Error parse_delta_metadata %d", fota_status); + FOTA_TRACE_ERROR("Error parse_payload_metadata %d", fota_status); return fota_status; } @@ -389,7 +429,8 @@ int parse_manifest_internal( } else #endif { - /*for the ease of use we will fill in payload size and digest values */ + /* FOTA_MANIFEST_PAYLOAD_FORMAT_RAW */ + /* for the ease of use we will fill in payload size and digest values */ memcpy(fw_info->installed_digest, fw_info->payload_digest, FOTA_CRYPTO_HASH_SIZE); fw_info->installed_size = fw_info->payload_size; } @@ -415,14 +456,73 @@ int parse_manifest_internal( return FOTA_STATUS_SUCCESS; } +#if (MBED_CLOUD_CLIENT_FOTA_ENCRYPTION_SUPPORT == 1) /* - * Assuming following ASN1 schema - * SignedResource ::= SEQUENCE { - * manifest-version ENUMERATED { - * v3(3) - * }, - * manifest Manifest, - * signature OCTET STRING + * -- Encryption Key Schema: + * -- the key used to encrypt the payload + * -- added by service after SignedResource + * EncryptionKeySchema DEFINITIONS IMPLICIT TAGS ::= BEGIN + * EncryptionKey ::= CHOICE { + * aes-128-bit [1] IMPLICIT OCTET STRING (SIZE(16)) + * } + */ +static int parse_encryption_key( + const uint8_t *int_key, size_t int_key_size, + uint8_t encryption_key[FOTA_ENCRYPT_KEY_SIZE], + const uint8_t *input_data +) +{ + size_t len = int_key_size; + unsigned char *p = (unsigned char *)int_key; + unsigned char *encryption_key_end = p + int_key_size; + + FOTA_MANIFEST_TRACE_DEBUG("Parse EncryptionKey @%d", p - input_data); + int ret = mbedtls_asn1_get_tag( + &p, encryption_key_end, &len, + MBEDTLS_ASN1_CONTEXT_SPECIFIC | FOTA_MANIFEST_ENCRYPTION_KEY_TAG_AES_128); + if (ret != 0) { + FOTA_TRACE_ERROR("Error EncryptionKey tag %d", ret); + return FOTA_STATUS_MANIFEST_MALFORMED; + } + + if (len != FOTA_ENCRYPT_KEY_SIZE) { + FOTA_TRACE_ERROR("Unexpected EncryptionKey size %zu", len); + return FOTA_STATUS_MANIFEST_MALFORMED; + } + + if (p + len > encryption_key_end) { + FOTA_TRACE_ERROR("Error got truncated manifest"); + return FOTA_STATUS_MANIFEST_MALFORMED; + } + + fota_fi_memcpy(encryption_key, p, FOTA_ENCRYPT_KEY_SIZE); + p += len; + + return FOTA_STATUS_SUCCESS; +} +#endif // (MBED_CLOUD_CLIENT_FOTA_ENCRYPTION_SUPPORT == 1) + +/* + * Assuming SignedResource followed by EncryptionKeySchema + * when the payload is pre-encrypted + * + * SignedResource ::= SEQUENCE { + * manifest-version ENUMERATED { + * v3(3) + * }, + * manifest Manifest, + * + * -- raw ECDSA signature (r||s) over Manifest + * signature OCTET STRING + * } + * + * -- Encryption Key Schema: + * -- the key used to encrypt the payload + * -- added by service after SignedResource + * EncryptionKeySchema DEFINITIONS IMPLICIT TAGS ::= BEGIN + * EncryptionKey ::= CHOICE { + * aes-128-bit [1] IMPLICIT OCTET STRING (SIZE(16)) + * } */ int fota_manifest_parse( const uint8_t *input_data, size_t input_size, @@ -459,8 +559,9 @@ int fota_manifest_parse( return FOTA_STATUS_MANIFEST_MALFORMED; } - // input data size may be bigger than real manifest due to storage limitations. - // update real resource end + // input data size may be bigger than real SignedResource size + // due to storage limitations or EncryptionKey. + // set to exact SignedResource end signed_resource_end = p + len; int manifest_format_version = 0; @@ -547,6 +648,22 @@ int fota_manifest_parse( return tmp_status; } +#if (MBED_CLOUD_CLIENT_FOTA_ENCRYPTION_SUPPORT == 1) + if (fw_info->payload_format == FOTA_MANIFEST_PAYLOAD_FORMAT_ENCRYPTED_RAW) { + + unsigned char *int_key = p; + size_t int_key_size = input_size - (size_t)(p - input_data); + tmp_status = parse_encryption_key( + int_key, int_key_size, + fw_info->encryption_key, input_data); + if (tmp_status != 0) { + FOTA_TRACE_ERROR("parse_manifest_internal failed %d", tmp_status); + return tmp_status; + } + + } +#endif + FOTA_MANIFEST_TRACE_DEBUG("status = %d", FOTA_STATUS_SUCCESS); return FOTA_STATUS_SUCCESS; fail: diff --git a/fota/fota_nvm_int.h b/fota/fota_nvm_int.h index 95a1bee41..898d587a2 100644 --- a/fota/fota_nvm_int.h +++ b/fota/fota_nvm_int.h @@ -33,11 +33,11 @@ extern "C" { typedef uint8_t ccs_item_type_e; -#define CCS_PRIVATE_KEY_ITEM 0x1 -#define CCS_PUBLIC_KEY_ITEM 0x2 -#define CCS_SYMMETRIC_KEY_ITEM 0x4 -#define CCS_CERTIFICATE_ITEM 0x8 -#define CCS_CONFIG_ITEM 0x10 +#define CCS_PRIVATE_KEY_ITEM 0 +#define CCS_PUBLIC_KEY_ITEM 1 +#define CCS_SYMMETRIC_KEY_ITEM 2 +#define CCS_CERTIFICATE_ITEM 3 +#define CCS_CONFIG_ITEM 4 #else // (MBED_CLOUD_CLIENT_PROFILE == MBED_CLOUD_CLIENT_PROFILE_FULL) diff --git a/fota/fota_platform_hooks.h b/fota/fota_platform_hooks.h index f292c206b..eb64c4a19 100644 --- a/fota/fota_platform_hooks.h +++ b/fota/fota_platform_hooks.h @@ -41,7 +41,7 @@ extern "C" { * Platform init hook. * Called when the FOTA module is initialized. * - * \param[in] after_upgrade Indicates that the hook is called after a successful upgrade of the installed image. + * \param[in] after_upgrade Indicates whether the FOTA client is being initiated after a successful upgrade of the installed image, or as part of a regular boot. * \return ::FOTA_STATUS_SUCCESS on success. */ int fota_platform_init_hook(bool after_upgrade); diff --git a/fota/fota_shim_layer.cpp b/fota/fota_shim_layer.cpp index fbf4fdbdb..fbb077b88 100644 --- a/fota/fota_shim_layer.cpp +++ b/fota/fota_shim_layer.cpp @@ -138,6 +138,11 @@ int fota_app_on_download_authorization( candidate_info->payload_size, candidate_info->installed_size ); + } else if (candidate_info->payload_format == FOTA_MANIFEST_PAYLOAD_FORMAT_ENCRYPTED_RAW) { + FOTA_APP_PRINT("Update size %zuB (Encrypted image size %zuB)", + candidate_info->installed_size, + candidate_info->payload_size + ); } else { FOTA_APP_PRINT("Update size %zuB", candidate_info->payload_size); } diff --git a/fota/fota_source_profile_full.cpp b/fota/fota_source_profile_full.cpp index 0092b7ed0..e8f70af0f 100644 --- a/fota/fota_source_profile_full.cpp +++ b/fota/fota_source_profile_full.cpp @@ -349,6 +349,8 @@ int fota_source_init( resource->set_operation(M2MBase::GET_ALLOWED); resource->set_value(FOTA_MCCP_PROTOCOL_VERSION); resource->publish_value_in_registration_msg(true); + resource->set_auto_observable(true); + // Create vendor resource /10255/0/2 resource = lwm2m_object_instance->create_dynamic_resource( @@ -360,6 +362,7 @@ int fota_source_init( resource->set_operation(M2MBase::GET_ALLOWED); resource->set_value(vendor_id, vendor_id_size); resource->publish_value_in_registration_msg(true); + resource->set_auto_observable(true); // Create class resource /10255/0/4 resource = lwm2m_object_instance->create_dynamic_resource( @@ -372,6 +375,7 @@ int fota_source_init( resource->set_operation(M2MBase::GET_ALLOWED); resource->set_value(class_id, class_id_size); resource->publish_value_in_registration_msg(true); + resource->set_auto_observable(true); m2m_object_list->push_back(g_lwm2m_dev_metadata_object); @@ -446,8 +450,8 @@ static int report_int(M2MResource *resource, int value, report_sent_callback_t o return FOTA_STATUS_SUCCESS; } - FOTA_DBG_ASSERT(!g_on_sent_callback); - FOTA_DBG_ASSERT(!g_on_failure_callback); + FOTA_DBG_ASSERT(!(on_sent && g_on_sent_callback)); + FOTA_DBG_ASSERT(!(on_failure && g_on_failure_callback)); // must assign values before calling registry_set_value_int because of special way unit-tests are implemented g_on_sent_callback = on_sent; @@ -527,7 +531,7 @@ int fota_source_firmware_request_fragment(const char *uri, size_t offset) true, //async data_req_callback, // data_cb data_req_error_callback, // error_cb - NULL // context + (void *) offset // context ); return FOTA_STATUS_SUCCESS; diff --git a/fota/fota_source_profile_lite.c b/fota/fota_source_profile_lite.c index 860ad86a8..7dffe6b19 100644 --- a/fota/fota_source_profile_lite.c +++ b/fota/fota_source_profile_lite.c @@ -619,8 +619,8 @@ static int report_int(int value, int16_t resource_id, report_sent_callback_t on_ return FOTA_STATUS_SUCCESS; } - FOTA_DBG_ASSERT(!g_on_sent_callback); - FOTA_DBG_ASSERT(!g_on_failure_callback); + FOTA_DBG_ASSERT(!(on_sent && g_on_sent_callback)); + FOTA_DBG_ASSERT(!(on_failure && g_on_failure_callback)); // must assign values before calling registry_set_value_int because of special way unit-tests are implemented g_on_sent_callback = on_sent; diff --git a/fota/fota_status.h b/fota/fota_status.h index 41428de1f..e955ec3a3 100644 --- a/fota/fota_status.h +++ b/fota/fota_status.h @@ -26,44 +26,45 @@ extern "C" { typedef enum { FOTA_STATUS_FW_UPDATE_OK = 18, /**< Asset update successfully completed */ - FOTA_STATUS_MANIFEST_INVALID_URI = -21, /**< FW payload URI in manifest is too long */ - FOTA_STATUS_MANIFEST_MALFORMED = -22, /**< Failure to parse an update manifest */ - FOTA_STATUS_MANIFEST_SIGNATURE_INVALID = -23, /**< Signature verification failed */ - FOTA_STATUS_DOWNLOAD_FRAGMENT_FAILED = -24, /**< Connection lost during download */ - FOTA_STATUS_MANIFEST_PAYLOAD_UNSUPPORTED = -25, /**< Payload format specified by manifest is unsupported */ - FOTA_STATUS_MANIFEST_PAYLOAD_CORRUPTED = -26, /**< Payload authenticity check failed */ - FOTA_STATUS_MANIFEST_VERSION_REJECTED = -27, /**< FW candidate version is rejected (is older or equals to installed one) */ - FOTA_STATUS_MANIFEST_SCHEMA_UNSUPPORTED = -28, /**< Manifest schema version unsupported (incompatible manifest-tool version) */ - FOTA_STATUS_MANIFEST_CUSTOM_DATA_TOO_BIG = -29, /**< Vendor data specified in a manifest is too big. */ - FOTA_STATUS_MANIFEST_WRONG_VENDOR_ID = -30, /**< Manifest with wrong vendor id */ - FOTA_STATUS_MANIFEST_WRONG_CLASS_ID = -31, /**< Manifest with wrong class id */ - FOTA_STATUS_MANIFEST_PRECURSOR_MISMATCH = -32, /**< Installed FW digest differs from the one specified in manifest (precursor) */ - FOTA_STATUS_INSUFFICIENT_STORAGE = -33, /**< Insufficient storage on a device for saving update candidate */ - FOTA_STATUS_OUT_OF_MEMORY = -34, /**< Not enough RAM */ - FOTA_STATUS_STORAGE_WRITE_FAILED = -35, /**< Storage write error */ - FOTA_STATUS_STORAGE_READ_FAILED = -36, /**< Storage read error */ - FOTA_STATUS_INSTALL_AUTH_NOT_GRANTED = -37, /**< Application rejected install authorization request */ - FOTA_STATUS_DOWNLOAD_AUTH_NOT_GRANTED = -38, /**< Application rejected download authorization request */ - FOTA_STATUS_UNEXPECTED_COMPONENT = -39, /**< Component name in manifest targets unknown component */ - FOTA_STATUS_MANIFEST_UNKNOWN_COMPONENT = FOTA_STATUS_UNEXPECTED_COMPONENT, // TODO: remove - FOTA_STATUS_FW_INSTALLATION_FAILED = -40, /**< Update failed at installation phase */ - FOTA_STATUS_INTERNAL_ERROR = -41, /**< Non-specific internal error */ - FOTA_STATUS_INTERNAL_DELTA_ERROR = -42, /**< Non-specific internal error - delta engine */ - FOTA_STATUS_INTERNAL_CRYPTO_ERROR = -43, /**< Non-specific internal error - crypto engine */ - FOTA_STATUS_NOT_FOUND = -44, /**< Expected asset is not found in NVM */ + FOTA_STATUS_MANIFEST_INVALID_URI = -21, /**< FW payload URI in manifest is too long */ + FOTA_STATUS_MANIFEST_MALFORMED = -22, /**< Failure to parse an update manifest */ + FOTA_STATUS_MANIFEST_SIGNATURE_INVALID = -23, /**< Signature verification failed */ + FOTA_STATUS_DOWNLOAD_FRAGMENT_FAILED = -24, /**< Connection lost during download */ + FOTA_STATUS_MANIFEST_PAYLOAD_UNSUPPORTED = -25, /**< Payload format specified by manifest is unsupported */ + FOTA_STATUS_MANIFEST_PAYLOAD_CORRUPTED = -26, /**< Payload authenticity check failed */ + FOTA_STATUS_MANIFEST_VERSION_REJECTED = -27, /**< FW candidate version is rejected (is older or equals to installed one) */ + FOTA_STATUS_MANIFEST_SCHEMA_UNSUPPORTED = -28, /**< Manifest schema version unsupported (incompatible manifest-tool version) */ + FOTA_STATUS_MANIFEST_CUSTOM_DATA_TOO_BIG = -29, /**< Vendor data specified in a manifest is too big. */ + FOTA_STATUS_MANIFEST_WRONG_VENDOR_ID = -30, /**< Manifest with wrong vendor id */ + FOTA_STATUS_MANIFEST_WRONG_CLASS_ID = -31, /**< Manifest with wrong class id */ + FOTA_STATUS_MANIFEST_PRECURSOR_MISMATCH = -32, /**< Installed FW digest differs from the one specified in manifest (precursor) */ + FOTA_STATUS_INSUFFICIENT_STORAGE = -33, /**< Insufficient storage on a device for saving update candidate */ + FOTA_STATUS_OUT_OF_MEMORY = -34, /**< Not enough RAM */ + FOTA_STATUS_STORAGE_WRITE_FAILED = -35, /**< Storage write error */ + FOTA_STATUS_STORAGE_READ_FAILED = -36, /**< Storage read error */ + FOTA_STATUS_INSTALL_AUTH_NOT_GRANTED = -37, /**< Application rejected install authorization request */ + FOTA_STATUS_DOWNLOAD_AUTH_NOT_GRANTED = -38, /**< Application rejected download authorization request */ + FOTA_STATUS_UNEXPECTED_COMPONENT = -39, /**< Component name in manifest targets unknown component */ + FOTA_STATUS_FW_INSTALLATION_FAILED = -40, /**< Update failed at installation phase */ + FOTA_STATUS_INTERNAL_ERROR = -41, /**< Non-specific internal error */ + FOTA_STATUS_INTERNAL_DELTA_ERROR = -42, /**< Non-specific internal error - delta engine */ + FOTA_STATUS_INTERNAL_CRYPTO_ERROR = -43, /**< Non-specific internal error - crypto engine */ + FOTA_STATUS_NOT_FOUND = -44, /**< Expected asset is not found in NVM */ + FOTA_STATUS_MULTICAST_UPDATE_ABORTED = -45, /**< Received abort request from Multicast */ // internal transient errors - should not be reported to service - FOTA_STATUS_SUCCESS = 0, /**< all good */ - FOTA_STATUS_INVALID_ERR_CODE = -1, /**< Invalid error code, for internal purposes */ - FOTA_STATUS_FAIL_UPDATE_STATE = -80, /**< Failed to deliver FOTA state */ - FOTA_STATUS_UPDATE_DEFERRED = -81, /**< Application deferred the update */ - FOTA_STATUS_TRANSIENT_FAILURE = -82, /**< transient failure during update **/ - FOTA_STATUS_FW_DELTA_REQUIRED_MORE_DATA = -83, /**< Delta engine requires more data to proceed */ - FOTA_STATUS_FW_SIZE_MISMATCH = -84, /**< FW fetching returned more data than expected - should not happen */ - FOTA_STATUS_RESOURCE_BUSY = -85, /**< Resource (typically storage) is busy */ - FOTA_STATUS_MULTICAST_UPDATE_ABORTED = -86, /**< Received abort request from Multicast */ - FOTA_STATUS_MULTICAST_UPDATE_ACTIVATED = -87, /**< Received abort request or new manifest from Multicast, when previous one was activated*/ - FOTA_STATUS_INVALID_ARGUMENT = -88 /**< Invalid argument was received */ + FOTA_STATUS_SUCCESS = 0, /**< all good */ + FOTA_STATUS_INVALID_ERR_CODE = -1, /**< Invalid error code, for internal purposes */ + FOTA_STATUS_INTERNAL_ERR_BASE = -80, + FOTA_STATUS_FAIL_UPDATE_STATE = FOTA_STATUS_INTERNAL_ERR_BASE, /**< Failed to deliver FOTA state */ + FOTA_STATUS_UPDATE_DEFERRED = -81, /**< Application deferred the update */ + FOTA_STATUS_TRANSIENT_FAILURE = -82, /**< transient failure during update **/ + FOTA_STATUS_FW_DELTA_REQUIRED_MORE_DATA = -83, /**< Delta engine requires more data to proceed */ + FOTA_STATUS_FW_SIZE_MISMATCH = -84, /**< FW fetching returned more data than expected - should not happen */ + FOTA_STATUS_RESOURCE_BUSY = -85, /**< Resource (typically storage) is busy */ + FOTA_STATUS_MULTICAST_UPDATE_ABORTED_INTERNAL = -86, /**< Abort Multicast not report to service*/ + FOTA_STATUS_MULTICAST_UPDATE_ACTIVATED = -87, /**< Received abort request or new manifest from Multicast, when previous one was activated*/ + FOTA_STATUS_INVALID_ARGUMENT = -88 /**< Invalid argument was received */ } fota_status_e; diff --git a/fota/mbed_lib.json b/fota/mbed_lib.json index 14f2be495..9f72760f1 100644 --- a/fota/mbed_lib.json +++ b/fota/mbed_lib.json @@ -31,13 +31,7 @@ "key-encryption": { "help": "Encryption key options", "macro_name": "MBED_CLOUD_CLIENT_FOTA_KEY_ENCRYPTION", - "accepted_values": ["FOTA_USE_ONE_TIME_FW_KEY", "FOTA_USE_DEVICE_KEY"], - "value": null - }, - "key-derivation": { - "help": "Encryption key derivation", - "macro_name": "MBED_CLOUD_CLIENT_FOTA_KEY_DERIVATION", - "accepted_values": ["FOTA_ENCRYPT_KEY_NO_DERIVATION", "FOTA_ENCRYPT_KEY_ECB_DERIVATION", "FOTA_ENCRYPT_KEY_HMAC_DERIVATION"], + "accepted_values": ["FOTA_USE_DEVICE_KEY", "FOTA_USE_ENCRYPTED_ONE_TIME_FW_KEY"], "value": null }, "public-key-format": { diff --git a/fota/platform/mbed-os/fota_block_device_mbed_os.cpp b/fota/platform/mbed-os/fota_block_device_mbed_os.cpp index 7f9420f5c..cb88c3383 100644 --- a/fota/platform/mbed-os/fota_block_device_mbed_os.cpp +++ b/fota/platform/mbed-os/fota_block_device_mbed_os.cpp @@ -24,6 +24,11 @@ #include "fota/fota_block_device.h" #include "fota/fota_status.h" +#include + +#if FOTA_BD_SIMULATE_ERASE +static const uint8_t sim_erase_val = 0xFF; +#endif // External BD should supply all these APIs @@ -90,6 +95,7 @@ int fota_bd_init(void) int ret = bd->init(); if (!ret) { + FOTA_TRACE_DEBUG("BlockDevice type %s", bd->get_type()); initialized = true; return FOTA_STATUS_SUCCESS; } @@ -145,6 +151,46 @@ int fota_bd_erase(size_t addr, size_t size) int ret; FOTA_ASSERT(bd); +#if FOTA_BD_SIMULATE_ERASE + int erase_value = bd->get_erase_value(); + if (erase_value < 0) { + uint8_t *erase_buf = NULL; + while (size) { + size_t erase_size, prev_erase_size = 0; + if (fota_bd_get_erase_size(addr, &erase_size)) { + ret = FOTA_STATUS_STORAGE_WRITE_FAILED; + goto end; + } + if ((addr % erase_size) || (size < erase_size)) { + ret = FOTA_STATUS_STORAGE_WRITE_FAILED; + goto end; + } + + if (erase_size > prev_erase_size) { + free(erase_buf); + erase_buf = (uint8_t *) malloc(erase_size); + if (!erase_buf) { + ret = FOTA_STATUS_STORAGE_WRITE_FAILED; + goto end; + } + } + + memset(erase_buf, sim_erase_val, erase_size); + if (bd->program(erase_buf, addr, erase_size)) { + ret = FOTA_STATUS_STORAGE_WRITE_FAILED; + goto end; + } + prev_erase_size = erase_size; + addr += erase_size; + size -= erase_size; + } + ret = FOTA_STATUS_SUCCESS; +end: + free(erase_buf); + return ret; + } +#endif // FOTA_BD_SIMULATE_ERASE + ret = bd->erase(addr, size); if (ret) { return FOTA_STATUS_STORAGE_WRITE_FAILED; @@ -181,6 +227,13 @@ int fota_bd_get_erase_value(int *erase_value) FOTA_ASSERT(bd); *erase_value = bd->get_erase_value(); + +#if FOTA_BD_SIMULATE_ERASE + if (*erase_value < 0) { + *erase_value = sim_erase_val; + } +#endif + return FOTA_STATUS_SUCCESS; } diff --git a/mbed-client-pal/Configs/mbedTLS/pelion_mbedtls_config.h b/mbed-client-pal/Configs/mbedTLS/pelion_mbedtls_config.h index d8521a47c..74063f566 100644 --- a/mbed-client-pal/Configs/mbedTLS/pelion_mbedtls_config.h +++ b/mbed-client-pal/Configs/mbedTLS/pelion_mbedtls_config.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2021 Pelion IoT +/* Copyright (c) 2021 Pelion * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/mbed-client-pal/Source/PAL-Impl/Modules/TLS/pal_TLS.c b/mbed-client-pal/Source/PAL-Impl/Modules/TLS/pal_TLS.c index 384bce3c6..67398de87 100644 --- a/mbed-client-pal/Source/PAL-Impl/Modules/TLS/pal_TLS.c +++ b/mbed-client-pal/Source/PAL-Impl/Modules/TLS/pal_TLS.c @@ -819,7 +819,7 @@ int32_t pal_loadSslSessionFromStorage(palTLSHandle_t palTLSHandle, palTLSConfHan PAL_LOG_DBG("pal_loadSslSessionFromStorage - feature not enabled !"); return return_value; } - if(!palTLSConfCtx->isDtlsMode) { + if (!palTLSConfCtx->isDtlsMode) { size_t act_size = 0; kcm_status_e kcm_status = kcm_item_get_data_size((uint8_t *)kcm_session_item_name, strlen(kcm_session_item_name), @@ -827,7 +827,11 @@ int32_t pal_loadSslSessionFromStorage(palTLSHandle_t palTLSHandle, palTLSConfHan if (kcm_status != KCM_STATUS_SUCCESS) { - PAL_LOG_ERR("pal_loadSslSessionFromStorage - failed to get item size!"); + if (kcm_status != KCM_STATUS_ITEM_NOT_FOUND) { + PAL_LOG_ERR("pal_loadSslSessionFromStorage - failed to get item size: %d!", kcm_status); + } else { + PAL_LOG_DBG("pal_loadSslSessionFromStorage - session not found"); + } return return_value; } @@ -861,13 +865,13 @@ int32_t pal_loadSslSessionFromStorage(palTLSHandle_t palTLSHandle, palTLSConfHan if (kcm_status != KCM_STATUS_SUCCESS && kcm_status != KCM_STATUS_ITEM_NOT_FOUND) { - PAL_LOG_ERR("pal_loadSslSessionFromStorage - failed to get item size!"); + PAL_LOG_ERR("pal_loadSslSessionFromStorage - failed to get item size: %d!", kcm_status); return return_value; } - if(pal_plat_sslSessionAvailable()) { + if (pal_plat_sslSessionAvailable()) { return_value = pal_plat_loadSslSession(palTLSCtx->platTlsHandle); - } else if(act_size > 0) { + } else if (act_size > 0) { size_t data_out = 0; uint8_t *existing_session = (uint8_t*)malloc(act_size); kcm_item_get_data((uint8_t *)kcm_session_item_name, diff --git a/mbed-client-pal/Source/Port/Reference-Impl/OS_Specific/ZephyrOS/Networking/fd_work_poll.c b/mbed-client-pal/Source/Port/Reference-Impl/OS_Specific/ZephyrOS/Networking/fd_work_poll.c index dcd7a4a63..ce6c67892 100644 --- a/mbed-client-pal/Source/Port/Reference-Impl/OS_Specific/ZephyrOS/Networking/fd_work_poll.c +++ b/mbed-client-pal/Source/Port/Reference-Impl/OS_Specific/ZephyrOS/Networking/fd_work_poll.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2021 Pelion IoT +/* Copyright (c) 2021 Pelion * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/mbed-client-pal/Source/Port/Reference-Impl/OS_Specific/ZephyrOS/Networking/fd_work_poll.h b/mbed-client-pal/Source/Port/Reference-Impl/OS_Specific/ZephyrOS/Networking/fd_work_poll.h index 0315c8829..3de3ced64 100644 --- a/mbed-client-pal/Source/Port/Reference-Impl/OS_Specific/ZephyrOS/Networking/fd_work_poll.h +++ b/mbed-client-pal/Source/Port/Reference-Impl/OS_Specific/ZephyrOS/Networking/fd_work_poll.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2021 Pelion IoT +/* Copyright (c) 2021 Pelion * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/mbed-client-pal/Source/Port/Reference-Impl/OS_Specific/ZephyrOS/Networking/fd_work_poll_polling.c b/mbed-client-pal/Source/Port/Reference-Impl/OS_Specific/ZephyrOS/Networking/fd_work_poll_polling.c index c95ca0bd4..022368462 100644 --- a/mbed-client-pal/Source/Port/Reference-Impl/OS_Specific/ZephyrOS/Networking/fd_work_poll_polling.c +++ b/mbed-client-pal/Source/Port/Reference-Impl/OS_Specific/ZephyrOS/Networking/fd_work_poll_polling.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2021 Pelion IoT +/* Copyright (c) 2021 Pelion * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/mbed-client-pal/Source/Port/Reference-Impl/OS_Specific/ZephyrOS/Networking/pal_plat_network.c b/mbed-client-pal/Source/Port/Reference-Impl/OS_Specific/ZephyrOS/Networking/pal_plat_network.c index 6985512b4..22fa81632 100644 --- a/mbed-client-pal/Source/Port/Reference-Impl/OS_Specific/ZephyrOS/Networking/pal_plat_network.c +++ b/mbed-client-pal/Source/Port/Reference-Impl/OS_Specific/ZephyrOS/Networking/pal_plat_network.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2021 Pelion IoT +/* Copyright (c) 2021 Pelion * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/mbed-client-pal/Source/Port/Reference-Impl/OS_Specific/ZephyrOS/Platform/FlashIAP.cpp b/mbed-client-pal/Source/Port/Reference-Impl/OS_Specific/ZephyrOS/Platform/FlashIAP.cpp index 50f71c149..2d88889bc 100644 --- a/mbed-client-pal/Source/Port/Reference-Impl/OS_Specific/ZephyrOS/Platform/FlashIAP.cpp +++ b/mbed-client-pal/Source/Port/Reference-Impl/OS_Specific/ZephyrOS/Platform/FlashIAP.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2021 Pelion IoT +/* Copyright (c) 2021 Pelion * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/mbed-client-pal/Source/Port/Reference-Impl/OS_Specific/ZephyrOS/Platform/FlashIAP.h b/mbed-client-pal/Source/Port/Reference-Impl/OS_Specific/ZephyrOS/Platform/FlashIAP.h index 34210bd74..b4d6e533c 100644 --- a/mbed-client-pal/Source/Port/Reference-Impl/OS_Specific/ZephyrOS/Platform/FlashIAP.h +++ b/mbed-client-pal/Source/Port/Reference-Impl/OS_Specific/ZephyrOS/Platform/FlashIAP.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2021 Pelion IoT +/* Copyright (c) 2021 Pelion * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/mbed-client-pal/Source/Port/Reference-Impl/OS_Specific/ZephyrOS/Platform/FlashMap.cpp b/mbed-client-pal/Source/Port/Reference-Impl/OS_Specific/ZephyrOS/Platform/FlashMap.cpp index ff0852b3a..4b61da67c 100644 --- a/mbed-client-pal/Source/Port/Reference-Impl/OS_Specific/ZephyrOS/Platform/FlashMap.cpp +++ b/mbed-client-pal/Source/Port/Reference-Impl/OS_Specific/ZephyrOS/Platform/FlashMap.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2021 Pelion IoT +/* Copyright (c) 2021 Pelion * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/mbed-client-pal/Source/Port/Reference-Impl/OS_Specific/ZephyrOS/Platform/FlashMap.h b/mbed-client-pal/Source/Port/Reference-Impl/OS_Specific/ZephyrOS/Platform/FlashMap.h index a2a1c18e5..38cd319c6 100644 --- a/mbed-client-pal/Source/Port/Reference-Impl/OS_Specific/ZephyrOS/Platform/FlashMap.h +++ b/mbed-client-pal/Source/Port/Reference-Impl/OS_Specific/ZephyrOS/Platform/FlashMap.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2021 Pelion IoT +/* Copyright (c) 2021 Pelion * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/mbed-client-pal/Source/Port/Reference-Impl/OS_Specific/ZephyrOS/RTOS/pal_plat_rtos.c b/mbed-client-pal/Source/Port/Reference-Impl/OS_Specific/ZephyrOS/RTOS/pal_plat_rtos.c index 409d990e5..317b54569 100644 --- a/mbed-client-pal/Source/Port/Reference-Impl/OS_Specific/ZephyrOS/RTOS/pal_plat_rtos.c +++ b/mbed-client-pal/Source/Port/Reference-Impl/OS_Specific/ZephyrOS/RTOS/pal_plat_rtos.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2021 Pelion IoT +/* Copyright (c) 2021 Pelion * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -181,11 +181,11 @@ palStatus_t pal_plat_osDelay(uint32_t milliseconds) } struct timer_data { - struct k_work_delayable work; + struct k_work_delayable dwork; + struct k_work_sync work_sync; palTimerFuncPtr callback; void *arg; struct k_mutex lock; - struct k_sem busy; uint64_t timeout; uint64_t period; }; @@ -193,9 +193,10 @@ struct timer_data { static void work_fn(struct k_work *work) { struct k_work_delayable *dwork = CONTAINER_OF(work, struct k_work_delayable, work); - struct timer_data *timer_data = CONTAINER_OF(dwork, struct timer_data, work); + struct timer_data *timer_data = CONTAINER_OF(dwork, struct timer_data, dwork); uint64_t uptime = k_uptime_get(); + int ret = 0; k_mutex_lock(&timer_data->lock, K_FOREVER); @@ -219,27 +220,16 @@ static void work_fn(struct k_work *work) /* Timer was restarted - timeout was updated. */ } - /* Calculate work delay. */ - int64_t delay = timer_data->timeout - k_uptime_get(); - if (delay < 0) { - /* Timer is late. Can happen for long callbacks. */ - delay = 0; - } - - k_work_reschedule(&timer_data->work, K_MSEC(delay)); - - /* If timer was started reference is already taken. */ - k_sem_take(&timer_data->busy, K_NO_WAIT); + ret = k_work_reschedule(&timer_data->dwork, K_TIMEOUT_ABS_MS(timer_data->timeout)); + __ASSERT_NO_MSG(ret > 0); } } else { - if (!k_work_reschedule(&timer_data->work, - K_MSEC(timer_data->timeout - uptime))) { - k_sem_take(&timer_data->busy, K_NO_WAIT); - } + /* Theoretically impossible but could be handled, reschedule remaining time. */ + ret = k_work_reschedule(&timer_data->dwork, K_MSEC(timer_data->timeout - uptime)); + __ASSERT_NO_MSG(ret > 0); } /* Release the timer. */ - k_sem_give(&timer_data->busy); k_mutex_unlock(&timer_data->lock); } @@ -259,15 +249,11 @@ palStatus_t pal_plat_osTimerCreate(palTimerFuncPtr function, timer_data->callback = function; /* Non-zero period marks periodic timer. */ - timer_data->period = (timerType == palOsTimerPeriodic) ? - UINT64_MAX : 0; + timer_data->period = (timerType == palOsTimerPeriodic) ? UINT64_MAX : 0; timer_data->timeout = 0; - /* Two references - extra one is for unstoppable callback. */ - k_sem_init(&timer_data->busy, 2, 2); - k_mutex_init(&timer_data->lock); - k_work_init_delayable(&timer_data->work, work_fn); + k_work_init_delayable(&timer_data->dwork, work_fn); *timerID = (palTimerID_t)timer_data; return PAL_SUCCESS; @@ -295,18 +281,8 @@ palStatus_t pal_plat_osTimerStart(palTimerID_t timerID, uint32_t millisec) timer_data->period = millisec; } - if (!k_work_cancel_delayable(&timer_data->work)) { - k_sem_give(&timer_data->busy); - k_work_reschedule(&timer_data->work, get_timeout(millisec)); - k_sem_take(&timer_data->busy, K_NO_WAIT); - } else if (!k_work_reschedule(&timer_data->work, get_timeout(millisec))) { - k_sem_take(&timer_data->busy, K_NO_WAIT); - } else { - /* Callback cannot be stopped or resubmitted. - * Let in-callback code to handle the restart. - */ - } - + int ret = k_work_reschedule(&timer_data->dwork, K_TIMEOUT_ABS_MS(timer_data->timeout)); + __ASSERT_NO_MSG(ret > 0); k_mutex_unlock(&timer_data->lock); return PAL_SUCCESS; @@ -327,14 +303,11 @@ palStatus_t pal_plat_osTimerStop(palTimerID_t timerID) timer_data->period = UINT64_MAX; } - if (!k_work_cancel_delayable(&timer_data->work)) { - k_sem_give(&timer_data->busy); - } else { - /* Callback cannot be stopped. - * Let in-callback code to handle the restart. - */ - } - + /* Return code is not relevant. + * If Stop was called from timer callback it cannot be stopped. + * Let in-callback code handle the stop. + */ + (void)k_work_cancel_delayable(&timer_data->dwork); k_mutex_unlock(&timer_data->lock); return PAL_SUCCESS; @@ -359,9 +332,7 @@ palStatus_t pal_plat_osTimerDelete(palTimerID_t *timerID) palStatus_t ret = pal_plat_osTimerStop(*timerID); __ASSERT_NO_MSG(ret == PAL_SUCCESS); - /* Wait until timer callback completes. */ - k_sem_take(&timer_data->busy, K_FOREVER); - k_sem_take(&timer_data->busy, K_FOREVER); + (void)k_work_cancel_delayable_sync(&timer_data->dwork, &timer_data->work_sync); /* Nothing is using the resources - delete the timer. */ free(timer_data); diff --git a/mbed-client/mbed-client-c/source/sn_nsdl.c b/mbed-client/mbed-client-c/source/sn_nsdl.c index 57c0210b6..ec3f97518 100755 --- a/mbed-client/mbed-client-c/source/sn_nsdl.c +++ b/mbed-client/mbed-client-c/source/sn_nsdl.c @@ -223,6 +223,7 @@ struct nsdl_s *sn_nsdl_init(uint8_t (*sn_nsdl_tx_cb)(struct nsdl_s *, sn_nsdl_ca handle->sn_nsdl_endpoint_registered = SN_NSDL_ENDPOINT_NOT_REGISTERED; handle->context = NULL; + randLIB_seed_random(); randLIB_get_n_bytes_random(&handle->token_seed, sizeof(handle->token_seed)); if (handle->token_seed == 0) { handle->token_seed++; diff --git a/mbed-client/mbed-client-classic/source/m2mconnectionhandlerpimpl.cpp b/mbed-client/mbed-client-classic/source/m2mconnectionhandlerpimpl.cpp index 7b5eb4258..5c903d230 100644 --- a/mbed-client/mbed-client-classic/source/m2mconnectionhandlerpimpl.cpp +++ b/mbed-client/mbed-client-classic/source/m2mconnectionhandlerpimpl.cpp @@ -32,6 +32,15 @@ #include "mbed-trace/mbed_trace.h" #include // free() and malloc() +#ifdef MBED_CLOUD_CLIENT_SUPPORT_MULTICAST_UPDATE +// Copied from socket_api.h since not part of mbed-os master yet + +/** Helper Traffic class Differentiated Services Code for QoS 0-63. 0 is default which define Lowest Priority + * + * */ +#define traffic_class_dsc_set(x) (uint8_t)((x & 63) << 2) +#endif + #define TRACE_GROUP "mClt" #if (PAL_DNS_API_VERSION == 1) && defined(TARGET_LIKE_MBED) @@ -396,7 +405,7 @@ bool M2MConnectionHandlerPimpl::resolve_server_address(const String &server_addr // we should skip over the DNS query. In case of CID there might be situation that we have a valid CID for ip address x, now if we query // dns again we might get ip address to y and COAP sending with the CID will fail. We will skip unnecessary dns query also if CID is not in use. if ((_socket_state == ESocketStateSecureConnection) && - (server_type == M2MConnectionObserver::LWM2MServer) && (_server_address == server_address)) { + (server_type == M2MConnectionObserver::LWM2MServer) && (_server_address == server_address)) { _is_server_ping = is_server_ping; if (is_server_ping) { // skip over dns query to handshake. This will reset tls and do a clean tls handshake @@ -1154,7 +1163,13 @@ bool M2MConnectionHandlerPimpl::set_socket_priority(M2MConnectionHandler::Socket } palStatus_t status; + +#ifdef MBED_CLOUD_CLIENT_SUPPORT_MULTICAST_UPDATE + int16_t traffic_class = traffic_class_dsc_set(priority); +#else int16_t traffic_class = priority; +#endif // MBED_CLOUD_CLIENT_SUPPORT_MULTICAST_UPDATE + status = pal_setSocketOptionsWithLevel(_socket, PAL_SOL_IPPROTO_IPV6, PAL_SO_IPV6_TRAFFIC_CLASS, diff --git a/mbed-client/mbed-client-mbed-tls/source/m2mconnectionsecuritypimpl.cpp b/mbed-client/mbed-client-mbed-tls/source/m2mconnectionsecuritypimpl.cpp index d81dff616..24a3178df 100644 --- a/mbed-client/mbed-client-mbed-tls/source/m2mconnectionsecuritypimpl.cpp +++ b/mbed-client/mbed-client-mbed-tls/source/m2mconnectionsecuritypimpl.cpp @@ -110,8 +110,9 @@ int M2MConnectionSecurityPimpl::init(const M2MSecurity *security, uint16_t secur if (_sec_mode == M2MConnectionSecurity::DTLS) { // convert to milliseconds and scale to reasonable range based on the network latency - uint32_t dtls_min = _network_rtt_estimate * 1000; - uint32_t dtls_max = _network_rtt_estimate * 1000 * 5; + // add a bit of overhead for the initial timeout which is based on the round-trip estimate + uint32_t dtls_min = _network_rtt_estimate * 1000 * 4 / 3; + uint32_t dtls_max = dtls_min * 8; pal_setHandShakeTimeOut(_conf, dtls_min, dtls_max); } diff --git a/mbed-client/mbed-client/m2mbase.h b/mbed-client/mbed-client/m2mbase.h index 4c28da66b..6ae6e18d6 100644 --- a/mbed-client/mbed-client/m2mbase.h +++ b/mbed-client/mbed-client/m2mbase.h @@ -691,6 +691,12 @@ class M2MBase : public M2MReportObserver { #endif // MBED_CLOUD_CLIENT_EDGE_EXTENSION + /** + * \brief Returns the Report Handler object. + * \return M2MReportHandler object. + */ + M2MReportHandler *report_handler() const; + protected: // from M2MReportObserver virtual bool observation_to_be_sent(const m2m::Vector &changed_instance_ids, @@ -747,12 +753,6 @@ class M2MBase : public M2MReportObserver { */ M2MReportHandler *create_report_handler(); - /** - * \brief Returns the Report Handler object. - * \return M2MReportHandler object. - */ - M2MReportHandler *report_handler() const; - static bool build_path(StringBuffer &buffer, const char *s1, uint16_t i1, const char *s2, uint16_t i2); static bool build_path(StringBuffer &buffer, const char *s1, uint16_t i1, const char *s2); diff --git a/mbed-client/mbed-client/m2mconfig.h b/mbed-client/mbed-client/m2mconfig.h index b7860c853..b664b0649 100644 --- a/mbed-client/mbed-client/m2mconfig.h +++ b/mbed-client/mbed-client/m2mconfig.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 ARM Limited. All rights reserved. + * Copyright (c) 2015-2021 Pelion. All rights reserved. * SPDX-License-Identifier: Apache-2.0 * Licensed under the Apache License, Version 2.0 (the License); you may * not use this file except in compliance with the License. @@ -184,6 +184,10 @@ typedef struct mbedtls_entropy { #define MBED_CONF_MBED_CLIENT_ENABLE_OBSERVATION_PARAMETERS 1 #endif +#ifndef MBED_CONF_MBED_CLIENT_ENABLE_DISCOVERY +#define MBED_CONF_MBED_CLIENT_ENABLE_DISCOVERY 1 +#endif + #ifdef MBED_CONF_MBED_CLIENT_BOOTSTRAP_PIGGYBACKED_RESPONSE #define MBED_CLIENT_BOOTSTRAP_PIGGYBACKED_RESPONSE MBED_CONF_MBED_CLIENT_BOOTSTRAP_PIGGYBACKED_RESPONSE #endif @@ -191,7 +195,12 @@ typedef struct mbedtls_entropy { #define MBED_CLIENT_BOOTSTRAP_PIGGYBACKED_RESPONSE 1 #endif -// Define defaults if not defined yet. +#ifdef MBED_CONF_MBED_CLIENT_MAX_RECONNECT_TIMEOUT +#define MBED_CLIENT_MAX_RECONNECT_TIMEOUT MBED_CONF_MBED_CLIENT_MAX_RECONNECT_TIMEOUT +#endif +#ifndef MBED_CLIENT_MAX_RECONNECT_TIMEOUT +#define MBED_CLIENT_MAX_RECONNECT_TIMEOUT 14400 // 4 hours +#endif #ifndef MBED_CLIENT_RECONNECTION_COUNT #define MBED_CLIENT_RECONNECTION_COUNT 3 diff --git a/mbed-client/mbed-client/m2mconstants.h b/mbed-client/mbed-client/m2mconstants.h index 67198f95b..62ff80e17 100644 --- a/mbed-client/mbed-client/m2mconstants.h +++ b/mbed-client/mbed-client/m2mconstants.h @@ -212,7 +212,8 @@ const uint32_t HANDSHAKE_TIMEOUT_MSECS = (30 * 60 * 1000); #define ERROR_NO_MEMORY "Memory allocation failed" #define ERROR_FAILED_TO_READ_CREDENTIALS "Failed to read credentials" -#define MAX_RECONNECT_TIMEOUT 604800 +#define MAX_RECONNECT_TIMEOUT_LOW 300 // 5 minutes + #define RECONNECT_INCREMENT_FACTOR 2 #define AUTO_OBS_TOKEN_MIN 1 @@ -240,5 +241,6 @@ const uint8_t COAP_CONTENT_OMA_TLV_TYPE_OLD = 99; const uint16_t COAP_CONTENT_OMA_TLV_TYPE = 11542; const uint16_t COAP_CONTENT_OMA_JSON_TYPE = 11543; const uint8_t COAP_CONTENT_OMA_OPAQUE_TYPE = 42; +const uint8_t COAP_CONTENT_OMA_LINK_FORMAT_TYPE = 40;// COAP_CT_LINK_FORMAT; #endif // M2MCONSTANTS_H diff --git a/mbed-client/mbed-client/m2minterfaceobserver.h b/mbed-client/mbed-client/m2minterfaceobserver.h index b76f62200..86371a53f 100644 --- a/mbed-client/mbed-client/m2minterfaceobserver.h +++ b/mbed-client/mbed-client/m2minterfaceobserver.h @@ -103,6 +103,11 @@ class M2MInterfaceObserver { * \brief A callback indicating that client is in alert mode. */ virtual void alert_mode() = 0; + + /** + * \brief A callback indicating that client is sleeping. + */ + virtual void sleep() = 0; }; #endif // M2M_INTERFACE_OBSERVER_H diff --git a/mbed-client/mbed-client/m2mobject.h b/mbed-client/mbed-client/m2mobject.h index c98fe399a..adf041396 100644 --- a/mbed-client/mbed-client/m2mobject.h +++ b/mbed-client/mbed-client/m2mobject.h @@ -230,6 +230,7 @@ friend class Test_M2MSecurity; friend class Test_M2MServer; friend class Test_M2MReportHandler; friend class Test_M2MResourceInstance; +friend class Test_M2MDiscover; }; #endif // M2M_OBJECT_H diff --git a/mbed-client/mbed-client/m2mobjectinstance.h b/mbed-client/mbed-client/m2mobjectinstance.h index 5bd201120..470169113 100644 --- a/mbed-client/mbed-client/m2mobjectinstance.h +++ b/mbed-client/mbed-client/m2mobjectinstance.h @@ -375,6 +375,7 @@ friend class M2MObject; friend class Test_M2MReportHandler; friend class TestFactory; friend class Test_M2MInterfaceImpl; + friend class Test_M2MDiscover; }; inline M2MObject& M2MObjectInstance::get_parent_object() const diff --git a/mbed-client/mbed-client/m2mresource.h b/mbed-client/mbed-client/m2mresource.h index 50eefa51d..8385e4f14 100644 --- a/mbed-client/mbed-client/m2mresource.h +++ b/mbed-client/mbed-client/m2mresource.h @@ -350,6 +350,7 @@ friend class Test_M2MBase; friend class Test_M2MResourceInstance; friend class TestFactory; friend class Test_M2MInterfaceImpl; +friend class Test_M2MDiscover; }; /** diff --git a/mbed-client/mbed-client/m2mresourcebase.h b/mbed-client/mbed-client/m2mresourcebase.h index 62bc14dbd..c95d36a11 100644 --- a/mbed-client/mbed-client/m2mresourcebase.h +++ b/mbed-client/mbed-client/m2mresourcebase.h @@ -19,6 +19,8 @@ #include "mbed-client/m2mbase.h" #include "mbed-client/functionpointer.h" +// (space needed for -3.402823 × 10^38) + (magic decimal 6 digits added as no precision is added to "%f") + trailing zero +#define REGISTRY_FLOAT_STRING_MAX_LEN 48 /*! \file m2mresourcebase.h \brief header for M2MResourceBase. */ diff --git a/mbed-client/mbed-client/m2mresourceinstance.h b/mbed-client/mbed-client/m2mresourceinstance.h index 0824da6c0..0f61ae089 100644 --- a/mbed-client/mbed-client/m2mresourceinstance.h +++ b/mbed-client/mbed-client/m2mresourceinstance.h @@ -163,6 +163,7 @@ friend class M2MResource; friend class Test_M2MNsdlInterface; friend class Test_M2MTLVSerializer; friend class Test_M2MTLVDeserializer; + friend class Test_M2MDiscover; }; #endif // M2M_RESOURCE_INSTANCE_H diff --git a/mbed-client/mbed_lib.json b/mbed-client/mbed_lib.json index 36b4ff10f..54593cc35 100644 --- a/mbed-client/mbed_lib.json +++ b/mbed-client/mbed_lib.json @@ -4,6 +4,7 @@ "event-loop-size": 1024, "reconnection-count": 3, "reconnection-interval": null, + "max-reconnect-timeout": null, "tcp-keepalive-interval": 100, "disable-bootstrap-feature": null, "coap-disable-obs-feature":null, @@ -26,6 +27,7 @@ "value": 1024 }, "enable-observation-parameters" : 1, - "bootstrap-piggybacked-response" : null + "bootstrap-piggybacked-response" : null, + "enable-discovery" : 1 } } diff --git a/mbed-client/source/include/m2mdiscover.h b/mbed-client/source/include/m2mdiscover.h new file mode 100644 index 000000000..2e3467730 --- /dev/null +++ b/mbed-client/source/include/m2mdiscover.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2021 Pelion. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef M2M_DISCOVER_H +#define M2M_DISCOVER_H + +#include "mbed-client/m2mobject.h" +#include "include/m2mreporthandler.h" + +#if defined (MBED_CONF_MBED_CLIENT_ENABLE_DISCOVERY) && (MBED_CONF_MBED_CLIENT_ENABLE_DISCOVERY == 1) + +class M2MDiscover { + +public: + + /** + * \brief Creates Discover request payload from the given M2MObject. + * @param object M2MObject which is to create payload. + * @param data_length reference which is updated to length of the data returned. Initial value does not mather. + * \return NULL if allocation failed, otherwise allocated uint8_t* with payload. + */ + static uint8_t *create_object_payload(const M2MObject *object, uint32_t &data_length); + + /** + * \brief Creates Discover request payload from the given M2MObjectInstance. + * @param obj_instance M2MObjectInstance which is to create payload. + * @param data_length reference which is updated to length of the data returned. Initial value does not mather. + * \return NULL if allocation failed, otherwise allocated uint8_t* with payload. + */ + static uint8_t *create_object_instance_payload(const M2MObjectInstance *obj_instance, uint32_t &data_length); + + /** + * \brief Creates Discover request payload from the given M2MResource. + * @param res M2MResource which is to create payload. + * @param data_length reference which is updated to length of the data returned. Initial value does not mather. + * \return NULL if allocation failed, otherwise allocated uint8_t* with payload. + */ + static uint8_t *create_resource_payload(const M2MResource *res, uint32_t &data_length); + +private: + // Prevent instantiate of this class + M2MDiscover(); + + static void create_object_payload(const M2MObject *object, uint8_t **data, uint32_t &data_length); + + static void create_object_instance_payload(const M2MObjectInstance *obj_instance, uint8_t **data, uint32_t &data_length, bool add_resource_dimension, bool add_resource_attribute, bool add_object_attributes); + + static void create_resource_payload(const M2MResource *res, uint8_t **data, uint32_t &data_length, bool add_resource_dimension, bool add_resource_attribute, bool add_inherited = false); + + static void set_path(const char *path, uint8_t **data, uint32_t &data_length); + + static void set_path_and_attributes(M2MReportHandler *report_handler, const char *path, uint8_t **data, uint32_t &data_length); + + static void set_string_and_value(uint8_t **data, uint32_t &data_length, const char* str, float value, int32_t int_value, bool float_type); + + static void set_comma(uint8_t **data, uint32_t &data_length); + +#if defined (MBED_CONF_MBED_CLIENT_ENABLE_OBSERVATION_PARAMETERS) && (MBED_CONF_MBED_CLIENT_ENABLE_OBSERVATION_PARAMETERS == 1) + static void set_resource_attributes(const M2MResource &res, uint8_t **data, uint32_t &data_length, bool add_inherited); + + static const char *get_attribute_string(M2MReportHandler::WriteAttribute attribute); + + static void get_write_attributes(M2MReportHandler &report_handler, M2MReportHandler:: WriteAttribute attribute, float &attribute_value_float, uint32_t &attribute_value_int, bool float_val); +#endif +}; + +#endif // defined (MBED_CONF_MBED_CLIENT_ENABLE_DISCOVERY) && (MBED_CONF_MBED_CLIENT_ENABLE_DISCOVERY == 1) +#endif // M2M_DISCOVER_H diff --git a/mbed-client/source/include/m2mreporthandler.h b/mbed-client/source/include/m2mreporthandler.h index f832bc5da..f37cdc90e 100644 --- a/mbed-client/source/include/m2mreporthandler.h +++ b/mbed-client/source/include/m2mreporthandler.h @@ -74,15 +74,16 @@ class M2MReportHandler /** * Enum defining which write attributes are set. + * Note! Do not change order or values. Used in m2mDiscovery. */ - enum { + typedef enum { Cancel = 1, Pmin = 2, Pmax = 4, Lt = 8, Gt = 16, St = 32 - }; + } WriteAttribute; /** * Destructor @@ -127,6 +128,21 @@ class M2MReportHandler bool parse_notification_attribute(const char *query, M2MBase::BaseType type, M2MResourceInstance::ResourceType resource_type = M2MResourceInstance::OPAQUE); + + /** + * @brief Get the float value of the given Write attribute. + * Will return valid value only for floats, e.g. M2MReportHandler::Lt, M2MReportHandler::Gt and M2MReportHandler::St. + * @param attribute, write attribute value to return. + * @return float value of the given attribute + */ + float get_notification_attribute_float(WriteAttribute attribute); + + /** @brief Get the int value of the given Write attribute. + * Will return valid value only for int32_t's, e.g. M2MReportHandler::Pmin and M2MReportHandler::Pmax. + * @param attribute, write attribute value to return. + * @return int32_t value of the given attribute + */ + int32_t get_notification_attribute_int(WriteAttribute attribute); #endif /** diff --git a/mbed-client/source/m2mdiscover.cpp b/mbed-client/source/m2mdiscover.cpp new file mode 100644 index 000000000..50000dfb3 --- /dev/null +++ b/mbed-client/source/m2mdiscover.cpp @@ -0,0 +1,344 @@ +/* + * Copyright (c) 2021 Pelion. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "include/m2mdiscover.h" +#include "include/m2mreporthandler.h" +#include "mbed-trace/mbed_trace.h" + +#include +#include + +#if defined (MBED_CONF_MBED_CLIENT_ENABLE_DISCOVERY) && (MBED_CONF_MBED_CLIENT_ENABLE_DISCOVERY == 1) + +#define TRACE_GROUP "mDisc" + +uint8_t *M2MDiscover::create_object_payload(const M2MObject *object, uint32_t &data_length) +{ + // First we do a dryrun to calculate the needed space + uint32_t len = 0; + uint8_t *data = 0; + create_object_payload(object, &data, len); + + // Then allocate memory and fill the data + data = (uint8_t *)malloc(len + 1); + len = 0; + + if (data) { + // copy pointer as it's moved inside the function + uint8_t *tmp_data = data; + create_object_payload(object, &tmp_data, len); + + tr_debug("M2MDiscover::create_object_payload - len: %d, data:\n%.*s", len, len, (char *)data); + data_length = len; + } + return data; +} + +uint8_t *M2MDiscover::create_object_instance_payload(const M2MObjectInstance *obj_instance, uint32_t &data_length) +{ + // First we do a dryrun to calculate the needed space + uint32_t len = 0; + uint8_t *data = 0; + create_object_instance_payload(obj_instance, &data, len, true, true, true); + + // Then allocate memory and fill the data + data = (uint8_t *)malloc(len + 1); + len = 0; + + if (data) { + // copy pointer as it's moved inside the function + uint8_t *tmp_data = data; + create_object_instance_payload(obj_instance, &tmp_data, len, true, true, true); + + tr_debug("M2MDiscover::create_object_instance_payload - len: %d, data:\n%.*s", len, len, (char *)data); + data_length = len; + } + return data; +} + +uint8_t *M2MDiscover::create_resource_payload(const M2MResource *res, uint32_t &data_length) +{ + // First we do a dryrun to calculate the needed space + uint32_t len = 0; + uint8_t *data = 0; + create_resource_payload(res, &data, len, true, true, true); + + // Then allocate memory and fill the data + data = (uint8_t *)malloc(len + 1); + len = 0; + + if (data) { + // copy pointer as it's moved inside the function + uint8_t *tmp_data = data; + create_resource_payload(res, &tmp_data, len, true, true, true); + + tr_debug("M2MDiscover::create_resource_payload - len: %d, data:\n%.*s", len, len, (char *)data); + data_length = len; + } + return data; +} + +void M2MDiscover::create_object_payload(const M2MObject *object, uint8_t **data, uint32_t &data_length) +{ + // when Discover is done to object level, only object level attributes are listed and then list of object instances and their resources + // for example ;pmin=10,,,,,,,,,, + // which means that the LwM2M Client supports the Device Info Object (Instance 0) Resources with IDs 1,2,3,4 + // 6,7,8,11, and 16 among the Resources of Device Info Object, with an R-Attributes assigned to the Object level. + const M2MObjectInstanceList &object_instance_list = object->instances(); + + // Add object path and it's Write-Attributes to payload + set_path_and_attributes(object->report_handler(), object->uri_path(), data, data_length); + + // Add object instances paths and their resource paths to payload + if (!object_instance_list.empty()) { + // add comma between object and object instances + set_comma(data, data_length); + + M2MObjectInstanceList::const_iterator it; + it = object_instance_list.begin(); + for (; it != object_instance_list.end();) { + create_object_instance_payload((const M2MObjectInstance *)*it, data, data_length, false, false, false); + it++; + if (it != object_instance_list.end()) { + // add comma between object instances + set_comma(data, data_length); + } + } + } +} + +void M2MDiscover::create_object_instance_payload(const M2MObjectInstance *obj_instance, uint8_t **data, uint32_t &data_length, bool add_resource_dimension, + bool add_resource_attribute, bool add_object_attribute) +{ + // when Discover is done to object instance level, attributes for object instance must be listed, resources and their attibutes + // For example ;pmax=60,,<3/0/2>,,,;dim=8,;dim=8;gt=50;lt=42.2,;dim=8,, + // means that regarding the Device Info Object Instance, an R-Attribute has been assigned to this Instance level. And + // the LwM2M Client supports the multiple Resources 6, 7, and 8 with a dimension of 8 and has 2 additional + // Notification parameters assigned for Resource 7. + const M2MResourceList &resource_list = obj_instance->resources(); + + // Add object instance path and it's Write-Attributes to payload + if (add_object_attribute) { + set_path_and_attributes(obj_instance->report_handler(), obj_instance->uri_path(), data, data_length); + } else { + set_path(obj_instance->uri_path(), data, data_length); + } + + // Add resource paths to payload and possible Write-Attributes to payload + if (!resource_list.empty()) { + // add comma between object instance and resources + set_comma(data, data_length); + + M2MResourceList::const_iterator it; + it = resource_list.begin(); + for (; it != resource_list.end();) { + create_resource_payload((const M2MResource *)*it, data, data_length, add_resource_dimension, add_resource_attribute); + it++; + if (it != resource_list.end()) { + // add comma between resources + set_comma(data, data_length); + } + } + } +} + +void M2MDiscover::create_resource_payload(const M2MResource *res, uint8_t **data, uint32_t &data_length, bool add_resource_dimension, bool add_resource_attribute, bool add_inherited) +{ + // when Discover is done to resource level, list resource and it's attributes, + // including the assigned R-Attributes and the R-Attributes inherited from the Object and Object Instance + // For example: if Object ID is 3, and Resource ID is 7, then + // ;dim=8;pmin=10;pmax=60;gt=50;lt=42.2 + // with pmin assigned at the Object level, and pmax assigned at the Object Instance level + + // Add resource path to payload + set_path(res->uri_path(), data, data_length); + + // add dimension, e.g. how many resource instances does this resource have, if none, then nothing is added to payload + if (add_resource_dimension && res->supports_multiple_instances()) { + set_string_and_value(data, data_length, ";dim=", 0, res->resource_instance_count(), false); + } + +#if defined (MBED_CONF_MBED_CLIENT_ENABLE_OBSERVATION_PARAMETERS) && (MBED_CONF_MBED_CLIENT_ENABLE_OBSERVATION_PARAMETERS == 1) + // Add possible Write-Attributes to payload + if (add_resource_attribute) { + set_resource_attributes(*res, data, data_length, add_inherited); + } +#endif +} + +void M2MDiscover::set_comma(uint8_t **data, uint32_t &data_length) +{ + if (*data) { + memcpy(*data, ",", 1); + *data += 1; + } + data_length++; +} + +void M2MDiscover::set_string_and_value(uint8_t **data, uint32_t &data_length, const char* str, float float_value, int32_t int_value, bool float_type) +{ + int max_val_len = REGISTRY_FLOAT_STRING_MAX_LEN; + if (*data == NULL) { + max_val_len = 0; + } + uint32_t tmp_len = strlen(str); + data_length += tmp_len; + if (*data) { + memcpy(*data, str, tmp_len); + *data += tmp_len; + } + +#if MBED_MINIMAL_PRINTF + if (float_type) { + tmp_len = snprintf((char *)*data, max_val_len, "%f", float_value); + } else { + tmp_len = snprintf((char *)*data, max_val_len, "%d", int_value); + } +#else + tmp_len = snprintf((char *)*data, max_val_len, "%g", float_type ? float_value : int_value); +#endif + + data_length += tmp_len; + if (*data) { + // move data pointer to point after the added data + *data += tmp_len; + } +} + +#if defined (MBED_CONF_MBED_CLIENT_ENABLE_OBSERVATION_PARAMETERS) && (MBED_CONF_MBED_CLIENT_ENABLE_OBSERVATION_PARAMETERS == 1) +void M2MDiscover::set_resource_attributes(const M2MResource &res, uint8_t **data, uint32_t &data_length, bool add_inherited) +{ + float attribute_value_float; + uint32_t attribute_value_int; + bool set_attribute = false; + bool float_val = true; + M2MReportHandler *report_handler = res.report_handler(); + + for (int attribute = M2MReportHandler::Pmin; attribute <= M2MReportHandler::St; attribute *= 2) { + if ((attribute == M2MReportHandler::Pmin) || (attribute == M2MReportHandler::Pmax)) { + float_val = false; + } else { + float_val = true; + } + + report_handler = res.report_handler(); + set_attribute = false; + + if (report_handler && report_handler->attribute_flags() & attribute) { + get_write_attributes(*report_handler, (M2MReportHandler::WriteAttribute)attribute, attribute_value_float, attribute_value_int, float_val); + set_attribute = true; + } else if (add_inherited) { + // check if inherited from object or object instance + M2MObjectInstance &obj_inst = res.get_parent_object_instance(); + report_handler = obj_inst.report_handler(); + if (report_handler && (report_handler->attribute_flags() & attribute)) { + get_write_attributes(*report_handler, (M2MReportHandler::WriteAttribute)attribute, attribute_value_float, attribute_value_int, float_val); + set_attribute = true; + } else { + M2MObject &obj = obj_inst.get_parent_object(); + report_handler = obj.report_handler(); + if (report_handler && (report_handler->attribute_flags() & attribute)) { + get_write_attributes(*report_handler, (M2MReportHandler::WriteAttribute)attribute, attribute_value_float, attribute_value_int, float_val); + set_attribute = true; + } + } + } + if (set_attribute) { + set_string_and_value(data, data_length, get_attribute_string((M2MReportHandler::WriteAttribute)attribute), attribute_value_float, attribute_value_int, float_val); + } + } +} + +void M2MDiscover::get_write_attributes(M2MReportHandler &report_handler, M2MReportHandler:: WriteAttribute attribute, float &attribute_value_float, uint32_t &attribute_value_int, bool float_val) +{ + if (float_val) { + attribute_value_float = report_handler.get_notification_attribute_float(attribute); + } else { + attribute_value_int = report_handler.get_notification_attribute_int(attribute); + } +} + +const char *M2MDiscover::get_attribute_string(M2MReportHandler::WriteAttribute attribute) +{ + const char *tmp = 0; + switch (attribute) { + case M2MReportHandler::Pmin: + tmp = ";pmin="; + break; + case M2MReportHandler::Pmax: + tmp = ";pmax="; + break; + case M2MReportHandler::Lt: + tmp = ";lt="; + break; + case M2MReportHandler::Gt: + tmp = ";gt="; + break; + case M2MReportHandler::St: + tmp = ";st="; + break; + case M2MReportHandler::Cancel: + /* fall-thru */ + default: + // Can't actually come here as we start looping from pmin, but let's satisfy the compiler + tr_error("Invalid attrubute type: %d", attribute); + assert(true); + break; + } + return tmp; +} +#endif + +void M2MDiscover::set_path_and_attributes(M2MReportHandler *report_handler, const char *path, uint8_t **data, uint32_t &data_length) +{ + set_path(path, data, data_length); + +#if defined (MBED_CONF_MBED_CLIENT_ENABLE_OBSERVATION_PARAMETERS) && (MBED_CONF_MBED_CLIENT_ENABLE_OBSERVATION_PARAMETERS == 1) + if (report_handler) { + float attribute_value_float; + uint32_t attribute_value_int; + bool float_val = true; + for (int i = M2MReportHandler::Pmin; i <= M2MReportHandler::St; i *= 2) { + if (report_handler->attribute_flags() & i) { + if ((i == M2MReportHandler::Pmin) || (i == M2MReportHandler::Pmax)) { + float_val = false; + } else { + float_val = true; + } + get_write_attributes(*report_handler, (M2MReportHandler::WriteAttribute)i, attribute_value_float, attribute_value_int, float_val); + set_string_and_value(data, data_length, get_attribute_string((M2MReportHandler::WriteAttribute)i), attribute_value_float, attribute_value_int, float_val); + } + } + } +#endif +} + +void M2MDiscover::set_path(const char *path, uint8_t **data, uint32_t &data_length) +{ + data_length += 3; // + data_length += strlen(path); // e.g. "3" or "3/0" or "3/0/7" + + if (*data) { + memcpy(*data, "", 1); + *data += 1; + } +} + +#endif // defined (MBED_CONF_MBED_CLIENT_ENABLE_DISCOVERY) && (MBED_CONF_MBED_CLIENT_ENABLE_DISCOVERY == 1) diff --git a/mbed-client/source/m2minterfaceimpl.cpp b/mbed-client/source/m2minterfaceimpl.cpp index c99eba1ac..85f26bec3 100644 --- a/mbed-client/source/m2minterfaceimpl.cpp +++ b/mbed-client/source/m2minterfaceimpl.cpp @@ -56,7 +56,6 @@ M2MInterfaceImpl::M2MInterfaceImpl(M2MInterfaceObserver &observer, const String &con_addr, const String &version) : _event_data(NULL), - _server_address{stack, NULL, 0, 0}, _server_port(0), _listen_port(listen_port), _life_time(l_time), @@ -84,6 +83,10 @@ M2MInterfaceImpl::M2MInterfaceImpl(M2MInterfaceObserver &observer, _reconnection_time(0) { tr_debug("M2MInterfaceImpl::M2MInterfaceImpl() -IN"); + memset(&_server_address, 0, sizeof(_server_address)); + _server_address._stack = stack; + + randLIB_seed_random(); #ifndef DISABLE_ERROR_DESCRIPTION memset(_error_description, 0, sizeof(_error_description)); @@ -236,8 +239,8 @@ void M2MInterfaceImpl::register_object(M2MSecurity *security, const M2MBaseList TRANSITION_MAP_ENTRY(EVENT_IGNORED) // state_bootstrap_wait TRANSITION_MAP_ENTRY(EVENT_IGNORED) // state_bootstrap_error_wait TRANSITION_MAP_ENTRY(STATE_REGISTER) // state_bootstrapped - TRANSITION_MAP_ENTRY(EVENT_IGNORED) // state_register - TRANSITION_MAP_ENTRY(EVENT_IGNORED) // state_register_address_resolved + TRANSITION_MAP_ENTRY(STATE_REGISTER) // state_register + TRANSITION_MAP_ENTRY(STATE_REGISTER) // state_register_address_resolved TRANSITION_MAP_ENTRY(STATE_REGISTER) // state_registered TRANSITION_MAP_ENTRY(EVENT_IGNORED) // state_update_registration TRANSITION_MAP_ENTRY(EVENT_IGNORED) // state_unregister @@ -528,7 +531,7 @@ void M2MInterfaceImpl::bootstrap_error(M2MInterface::Error error, const char *re _observer.error(error); internal_event(STATE_IDLE); - if (error == M2MInterface::InvalidParameters || error == M2MInterface::InvalidCertificates) { + if (error == M2MInterface::InvalidParameters) { // These failures are not recoverable on this level. Requires recovery on higher level. return; } @@ -546,9 +549,9 @@ void M2MInterfaceImpl::bootstrap_error(M2MInterface::Error error, const char *re // The timeout is randomized to + 10% and -10% range from reconnection value _reconnection_time = randLIB_randomise_base(_reconnection_time, 0x7333, 0x8CCD); - if (_reconnection_time >= MAX_RECONNECT_TIMEOUT) { + if (_reconnection_time >= MBED_CLIENT_MAX_RECONNECT_TIMEOUT) { // The max timeout is randomized to + 10% and -10% range from maximum value - _reconnection_time = randLIB_randomise_base(MAX_RECONNECT_TIMEOUT, 0x7333, 0x8CCD); + _reconnection_time = randLIB_randomise_base(MBED_CLIENT_MAX_RECONNECT_TIMEOUT, 0x7333, 0x8CCD); } } #endif //MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE @@ -612,11 +615,9 @@ void M2MInterfaceImpl::socket_error(int error_code, bool retry) } // Ignore errors while client is sleeping - if (queue_mode()) { - if (_callback_handler && _queue_mode_timer_ongoing) { - tr_info("M2MInterfaceImpl::socket_error - Queue Mode - don't try to reconnect while in QueueMode"); - return; - } + if (queue_mode() && _queue_mode_timer_ongoing) { + tr_info("M2MInterfaceImpl::socket_error - Queue Mode - don't try to reconnect while in QueueMode"); + return; } _queue_sleep_timer.stop_timer(); @@ -690,9 +691,9 @@ void M2MInterfaceImpl::socket_error(int error_code, bool retry) // The timeout is randomized to + 10% and -10% range from reconnection value _reconnection_time = randLIB_randomise_base(_reconnection_time, 0x7333, 0x8CCD); - if (_reconnection_time >= MAX_RECONNECT_TIMEOUT) { + if (_reconnection_time >= MBED_CLIENT_MAX_RECONNECT_TIMEOUT) { // The max timeout is randomized to + 10% and -10% range from maximum value - _reconnection_time = randLIB_randomise_base(MAX_RECONNECT_TIMEOUT, 0x7333, 0x8CCD); + _reconnection_time = randLIB_randomise_base(MBED_CLIENT_MAX_RECONNECT_TIMEOUT, 0x7333, 0x8CCD); } #ifndef DISABLE_ERROR_DESCRIPTION snprintf(_error_description, sizeof(_error_description), ERROR_REASON_9, error_code_des); @@ -740,9 +741,7 @@ void M2MInterfaceImpl::address_ready(const M2MConnectionObserver::SocketAddress void M2MInterfaceImpl::data_sent() { tr_debug("M2MInterfaceImpl::data_sent()"); - if (queue_mode() && - _callback_handler && - _nsdl_interface.is_registered()) { + if (queue_mode() && _nsdl_interface.is_registered()) { _queue_sleep_timer.stop_timer(); #if (PAL_USE_SSL_SESSION_RESUME == 0) _queue_sleep_timer.start_timer(_nsdl_interface.total_retransmission_time(_nsdl_interface.get_resend_count()) * (uint64_t)1000, @@ -789,6 +788,7 @@ void M2MInterfaceImpl::timer_expired(M2MTimerObserver::Type type) if (_callback_handler) { _callback_handler(); } + _observer.sleep(); } } else if (M2MTimerObserver::RetryTimer == type) { tr_debug("M2MInterfaceImpl::timer_expired() - retry"); @@ -1147,7 +1147,7 @@ void M2MInterfaceImpl::state_registered(EventData */*data*/) if (_reconnection_state == M2MInterfaceImpl::Unregistration) { internal_event(STATE_UNREGISTER); } else { - if (queue_mode() && _callback_handler) { + if (queue_mode()) { _queue_sleep_timer.stop_timer(); #if (PAL_USE_SSL_SESSION_RESUME == 0) _queue_sleep_timer.start_timer(_nsdl_interface.total_retransmission_time(_nsdl_interface.get_resend_count()) * (uint64_t)1000, @@ -1568,7 +1568,6 @@ void M2MInterfaceImpl::network_interface_status_change(NetworkInterfaceStatus st // Estimate new reconnection time based on Stagger. This ensures controlled recovery in constrained network with large number of devices. uint32_t rand_time = 10 + _nsdl_interface.get_network_stagger_estimate(false); // The new timeout is randomized to + 10% and -10% range from original random value - randLIB_seed_random(); rand_time = randLIB_randomise_base(rand_time, 0x7333, 0x8CCD); // If the new randomized time is significantly smaller than current running reconnection time, take the new value in use. // In mesh the is reported in regular internals. This tries to ensure that we do not end up in situation where @@ -1595,7 +1594,6 @@ void M2MInterfaceImpl::network_interface_status_change(NetworkInterfaceStatus st void M2MInterfaceImpl::create_random_initial_reconnection_time() { if (_initial_reconnection_time == 0) { - randLIB_seed_random(); _initial_reconnection_time = 10 + _nsdl_interface.get_network_rtt_estimate(); // The initial timeout is randomized to + 10% and -10% range from original random value diff --git a/mbed-client/source/m2mnsdlinterface.cpp b/mbed-client/source/m2mnsdlinterface.cpp index 8dc9e347b..b17489976 100644 --- a/mbed-client/source/m2mnsdlinterface.cpp +++ b/mbed-client/source/m2mnsdlinterface.cpp @@ -88,7 +88,7 @@ #define REGISTRATION_UPDATE_DELAY 10 // wait 10ms before sending registration update for PUT to resource 1/0/1 -const char *MCC_VERSION = "mccv=4.9.1"; +const char *MCC_VERSION = "mccv=4.10.0"; int8_t M2MNsdlInterface::_tasklet_id = -1; @@ -125,6 +125,13 @@ extern "C" void nsdlinterface_tasklet_func(arm_event_s *event) M2MNsdlInterface::memory_free(coap_data); eventOS_scheduler_mutex_release(); + } else if (event->event_type == MBED_CLIENT_NSDLINTERFACE_MESSAGE_STATUS_CB_EVENT) { + M2MObject *object = (M2MObject *)event->data_ptr; + uint8_t status = event->event_data >> 8; + uint8_t type = event->event_data; + object->send_message_delivery_status(*object, + (M2MBase::MessageDeliveryStatus)status, + (M2MBase::MessageType)type); } #ifndef MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE else if (event->event_type == MBED_CLIENT_NSDLINTERFACE_BS_EVENT) { @@ -136,16 +143,16 @@ extern "C" void nsdlinterface_tasklet_func(arm_event_s *event) coap_data->received_coap_header->msg_code); if (coap_response) { #if (MBED_CLIENT_BOOTSTRAP_PIGGYBACKED_RESPONSE == 0) - coap_response->msg_type = coap_data->received_coap_header->msg_type; - // Let CoAP to choose next message id - coap_response->msg_id = 0; + coap_response->msg_type = coap_data->received_coap_header->msg_type; + // Let CoAP to choose next message id + coap_response->msg_id = 0; #endif // MBED_CLIENT_BOOTSTRAP_PIGGYBACKED_RESPONSE - if (sn_nsdl_send_coap_message(coap_data->nsdl_handle, &coap_data->address, coap_response) == 0) { - interface->store_bs_finished_response_id(coap_response->msg_id); - } else { - tr_error("Failed to send final response for BS finished"); - } + if (sn_nsdl_send_coap_message(coap_data->nsdl_handle, &coap_data->address, coap_response) == 0) { + interface->store_bs_finished_response_id(coap_response->msg_id); + } else { + tr_error("Failed to send final response for BS finished"); + } sn_coap_parser_release_allocated_coap_msg_mem(coap_data->nsdl_handle->grs->coap, coap_response); @@ -179,13 +186,6 @@ extern "C" void nsdlinterface_tasklet_func(arm_event_s *event) nsdl_s *nsdl_handle = (nsdl_s *)event->data_ptr; M2MNsdlInterface *interface = (M2MNsdlInterface *)sn_nsdl_get_context(nsdl_handle); interface->handle_bootstrap_finish_ack(event->event_data); - } else if (event->event_type == MBED_CLIENT_NSDLINTERFACE_MESSAGE_STATUS_CB_EVENT) { - M2MObject *object = (M2MObject *)event->data_ptr; - uint8_t status = event->event_data >> 8; - uint8_t type = event->event_data; - object->send_message_delivery_status(*object, - (M2MBase::MessageDeliveryStatus)status, - (M2MBase::MessageType)type); } #endif //MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE } @@ -904,7 +904,7 @@ uint8_t M2MNsdlInterface::received_from_server_callback(struct nsdl_s *nsdl_hand if (base && resp->type != M2MBase::NOTIFICATION) { handle_message_status_callback(base, resp->type, M2MBase::MESSAGE_STATUS_SEND_FAILED); } - remove_item_from_response_list(resp->uri_path, coap_header->msg_id); + free_response_list(); } _observer.registration_error(M2MInterface::NetworkError, true); @@ -3415,28 +3415,22 @@ void M2MNsdlInterface::handle_request_response(const sn_coap_hdr_s *coap_header, // Start retry logic, only for file download operation } else if (coap_header->msg_code == COAP_MSG_CODE_RESPONSE_SERVICE_UNAVAILABLE && request_context->msg_code == COAP_MSG_CODE_REQUEST_GET) { - bool retry = true; if (!_download_retry_time) { // Range is from 1 sec to 10 sec _download_retry_time = randLIB_get_random_in_range(1, 10); } else { _download_retry_time *= RECONNECT_INCREMENT_FACTOR; - if (_download_retry_time > MAX_RECONNECT_TIMEOUT) { - tr_error("M2MNsdlInterface::handle_request_response - file download failed, retry completed"); - retry = false; - failed_to_send_request(request_context, coap_header); + if (_download_retry_time >= MBED_CLIENT_MAX_RECONNECT_TIMEOUT) { + _download_retry_time = MBED_CLIENT_MAX_RECONNECT_TIMEOUT; } } - if (retry) { - tr_info("M2MNsdlInterface::handle_request_response - continue file download after %" PRIu32, _download_retry_time); - set_request_context_to_be_resend(coap_header->token_ptr, coap_header->token_len); - _download_retry_timer.start_timer(_download_retry_time * 1000, M2MTimerObserver::RetryTimer); - } - - // Message sending has failed, inform application + tr_info("M2MNsdlInterface::handle_request_response - continue file download after %" PRIu32, _download_retry_time); + set_request_context_to_be_resend(coap_header->token_ptr, coap_header->token_len); + _download_retry_timer.start_timer(_download_retry_time * 1000, M2MTimerObserver::RetryTimer); } else { + // Message sending has failed, inform application failed_to_send_request(request_context, coap_header); } } diff --git a/mbed-client/source/m2mobject.cpp b/mbed-client/source/m2mobject.cpp index 3f1eea0e0..6ffc77fe0 100644 --- a/mbed-client/source/m2mobject.cpp +++ b/mbed-client/source/m2mobject.cpp @@ -30,6 +30,7 @@ #include "mbed-trace/mbed_trace.h" #include "mbed-client/m2mstringbuffer.h" #include "include/m2mcallbackstorage.h" +#include "include/m2mdiscover.h" #include @@ -250,8 +251,12 @@ sn_coap_hdr_s *M2MObject::handle_get_request(nsdl_s *nsdl, // Check if preferred content type is supported if (content_type_present) { - if (coap_response->content_format != COAP_CONTENT_OMA_TLV_TYPE_OLD && - coap_response->content_format != COAP_CONTENT_OMA_TLV_TYPE) { + if ((coap_response->content_format != COAP_CONTENT_OMA_TLV_TYPE_OLD) && + (coap_response->content_format != COAP_CONTENT_OMA_TLV_TYPE) +#if defined (MBED_CONF_MBED_CLIENT_ENABLE_DISCOVERY) && (MBED_CONF_MBED_CLIENT_ENABLE_DISCOVERY == 1) + && (coap_response->content_format != COAP_CONTENT_OMA_LINK_FORMAT_TYPE) +#endif + ) { is_content_type_supported = false; } } @@ -269,7 +274,17 @@ sn_coap_hdr_s *M2MObject::handle_get_request(nsdl_s *nsdl, set_coap_content_type(coap_response->content_format); data = M2MTLVSerializer::serialize(_instance_list, data_length); } - +#if defined (MBED_CONF_MBED_CLIENT_ENABLE_DISCOVERY) && (MBED_CONF_MBED_CLIENT_ENABLE_DISCOVERY == 1) + else if (coap_response->content_format == COAP_CONTENT_OMA_LINK_FORMAT_TYPE) { + // Discover + data_length = 0; + data = M2MDiscover::create_object_payload(this, data_length); + if (!data) { + data_length = 0; + tr_error("M2MObject::handle_get_request() - Discover data allocation failed!"); + } + } +#endif coap_response->payload_len = data_length; coap_response->payload_ptr = data; if (data) { @@ -482,6 +497,9 @@ sn_coap_hdr_s *M2MObject::handle_post_request(nsdl_s *nsdl, case M2MTLVDeserializer::OutOfMemory: msg_code = COAP_MSG_CODE_RESPONSE_REQUEST_ENTITY_TOO_LARGE; break; + case M2MTLVDeserializer::NotAccepted: + msg_code = COAP_MSG_CODE_RESPONSE_NOT_ACCEPTABLE; + break; } } else { diff --git a/mbed-client/source/m2mobjectinstance.cpp b/mbed-client/source/m2mobjectinstance.cpp index 81b3b917a..21dee20ad 100644 --- a/mbed-client/source/m2mobjectinstance.cpp +++ b/mbed-client/source/m2mobjectinstance.cpp @@ -33,6 +33,7 @@ #include "include/m2mreporthandler.h" #include "mbed-trace/mbed_trace.h" #include "include/m2mcallbackstorage.h" +#include "include/m2mdiscover.h" #include #include @@ -497,8 +498,12 @@ sn_coap_hdr_s *M2MObjectInstance::handle_get_request(nsdl_s *nsdl, // Check if preferred content type is supported if (content_type_present) { - if (coap_response->content_format != COAP_CONTENT_OMA_TLV_TYPE_OLD && - coap_response->content_format != COAP_CONTENT_OMA_TLV_TYPE) { + if ((coap_response->content_format != COAP_CONTENT_OMA_TLV_TYPE_OLD) && + (coap_response->content_format != COAP_CONTENT_OMA_TLV_TYPE) +#if defined (MBED_CONF_MBED_CLIENT_ENABLE_DISCOVERY) && (MBED_CONF_MBED_CLIENT_ENABLE_DISCOVERY == 1) + && (coap_response->content_format != COAP_CONTENT_OMA_LINK_FORMAT_TYPE) +#endif + ) { is_content_type_supported = false; } } @@ -516,7 +521,17 @@ sn_coap_hdr_s *M2MObjectInstance::handle_get_request(nsdl_s *nsdl, set_coap_content_type(coap_response->content_format); data = M2MTLVSerializer::serialize(_resource_list, data_length); } - +#if defined (MBED_CONF_MBED_CLIENT_ENABLE_DISCOVERY) && (MBED_CONF_MBED_CLIENT_ENABLE_DISCOVERY == 1) + else if (coap_response->content_format == COAP_CONTENT_OMA_LINK_FORMAT_TYPE) { + // Discover + data_length = 0; + data = M2MDiscover::create_object_instance_payload(this, data_length); + if (!data) { + data_length = 0; + tr_error("M2MObjectInstance::handle_get_request() - Discover data allocation failed!"); + } + } +#endif coap_response->payload_len = data_length; coap_response->payload_ptr = data; @@ -630,6 +645,9 @@ sn_coap_hdr_s *M2MObjectInstance::handle_put_request(nsdl_s *nsdl, case M2MTLVDeserializer::OutOfMemory: msg_code = COAP_MSG_CODE_RESPONSE_REQUEST_ENTITY_TOO_LARGE; break; + case M2MTLVDeserializer::NotAccepted: + msg_code = COAP_MSG_CODE_RESPONSE_NOT_ACCEPTABLE; + break; } } } else { diff --git a/mbed-client/source/m2mreporthandler.cpp b/mbed-client/source/m2mreporthandler.cpp index 5a366b5f3..fdb8ca973 100644 --- a/mbed-client/source/m2mreporthandler.cpp +++ b/mbed-client/source/m2mreporthandler.cpp @@ -247,6 +247,52 @@ bool M2MReportHandler::parse_notification_attribute(const char *query, return success; } +float M2MReportHandler::get_notification_attribute_float(WriteAttribute attribute) +{ + float retval = 0; + switch (attribute) { + case M2MReportHandler::Lt: + retval = _lt; + break; + case M2MReportHandler::Gt: + retval = _gt; + break; + case M2MReportHandler::St: + retval = _st; + break; + case M2MReportHandler::Pmin: + case M2MReportHandler::Pmax: + /* fall-thru */ + default: + tr_error("M2MReportHandler::get_notification_attribute_float - invalid attribute: %d", attribute); + assert(true); + break; + } + return retval; +} + +int32_t M2MReportHandler::get_notification_attribute_int(WriteAttribute attribute) +{ + int32_t retval = 0; + switch (attribute) { + case M2MReportHandler::Pmin: + retval = _pmin; + break; + case M2MReportHandler::Pmax: + retval = _pmax; + break; + case M2MReportHandler::Lt: + case M2MReportHandler::Gt: + case M2MReportHandler::St: + /* fall-thru */ + default: + tr_error("M2MReportHandler::get_notification_attribute_int - invalid attribute: %d", attribute); + assert(true); + break; + } + return retval; +} + void M2MReportHandler::timer_expired(M2MTimerObserver::Type type) { switch (type) { diff --git a/mbed-client/source/m2mresource.cpp b/mbed-client/source/m2mresource.cpp index c0b21fd61..88634c953 100644 --- a/mbed-client/source/m2mresource.cpp +++ b/mbed-client/source/m2mresource.cpp @@ -19,6 +19,7 @@ #include "include/m2mreporthandler.h" #include "include/m2mtlvserializer.h" #include "include/m2mtlvdeserializer.h" +#include "include/m2mdiscover.h" #include "mbed-trace/mbed_trace.h" #include @@ -338,8 +339,12 @@ sn_coap_hdr_s* M2MResource::handle_get_request(nsdl_s *nsdl, // Check if preferred content type is supported if (content_type_present) { - if (coap_response->content_format != COAP_CONTENT_OMA_TLV_TYPE_OLD && - coap_response->content_format != COAP_CONTENT_OMA_TLV_TYPE) { + if ((coap_response->content_format != COAP_CONTENT_OMA_TLV_TYPE_OLD) && + (coap_response->content_format != COAP_CONTENT_OMA_TLV_TYPE) +#if defined (MBED_CONF_MBED_CLIENT_ENABLE_DISCOVERY) && (MBED_CONF_MBED_CLIENT_ENABLE_DISCOVERY == 1) + && (coap_response->content_format != COAP_CONTENT_OMA_LINK_FORMAT_TYPE) +#endif + ) { is_content_type_supported = false; } } @@ -356,12 +361,22 @@ sn_coap_hdr_s* M2MResource::handle_get_request(nsdl_s *nsdl, uint8_t *data = NULL; uint32_t data_length = 0; // fill in the CoAP response payload - if(COAP_CONTENT_OMA_TLV_TYPE == coap_response->content_format || - COAP_CONTENT_OMA_TLV_TYPE_OLD == coap_response->content_format) { + if (COAP_CONTENT_OMA_TLV_TYPE == coap_response->content_format || + COAP_CONTENT_OMA_TLV_TYPE_OLD == coap_response->content_format) { set_coap_content_type(coap_response->content_format); data = M2MTLVSerializer::serialize(this, data_length); } - +#if defined (MBED_CONF_MBED_CLIENT_ENABLE_DISCOVERY) && (MBED_CONF_MBED_CLIENT_ENABLE_DISCOVERY == 1) + else if (coap_response->content_format == COAP_CONTENT_OMA_LINK_FORMAT_TYPE) { + // Discover + data_length = 0; + data = M2MDiscover::create_resource_payload(this, data_length); + if (!data) { + data_length = 0; + tr_error("M2MResource::handle_get_request() - Discover data allocation failed!"); + } + } +#endif coap_response->payload_len = data_length; coap_response->payload_ptr = data; diff --git a/mbed-client/source/m2mresourcebase.cpp b/mbed-client/source/m2mresourcebase.cpp index 9636417fe..027cca638 100644 --- a/mbed-client/source/m2mresourcebase.cpp +++ b/mbed-client/source/m2mresourcebase.cpp @@ -31,6 +31,7 @@ #include "mbed-client/m2mobject.h" #include "mbed-client/m2mobjectinstance.h" #include "include/m2mcallbackstorage.h" +#include "include/m2mdiscover.h" #include "include/m2mreporthandler.h" #include "include/nsdllinker.h" #include "include/m2mtlvserializer.h" @@ -46,9 +47,6 @@ // -9223372036854775808 - +9223372036854775807 // max length of int64_t string is 20 bytes + nil #define REGISTRY_INT64_STRING_MAX_LEN 21 -// (space needed for -3.402823 × 10^38) + (magic decimal 6 digits added as no precision is added to "%f") + trailing zero -#define REGISTRY_FLOAT_STRING_MAX_LEN 48 - M2MResourceBase::M2MResourceBase( @@ -607,7 +605,11 @@ sn_coap_hdr_s *M2MResourceBase::handle_get_request(nsdl_s *nsdl, if ((received_coap_header->options_list_ptr->accept == COAP_CONTENT_OMA_OPAQUE_TYPE) || (received_coap_header->options_list_ptr->accept == COAP_CONTENT_OMA_PLAIN_TEXT_TYPE) || (received_coap_header->options_list_ptr->accept == COAP_CONTENT_OMA_TLV_TYPE_OLD) || - (received_coap_header->options_list_ptr->accept == COAP_CONTENT_OMA_TLV_TYPE)) { + (received_coap_header->options_list_ptr->accept == COAP_CONTENT_OMA_TLV_TYPE) +#if defined (MBED_CONF_MBED_CLIENT_ENABLE_DISCOVERY) && (MBED_CONF_MBED_CLIENT_ENABLE_DISCOVERY == 1) + || (received_coap_header->options_list_ptr->accept == COAP_CONTENT_OMA_LINK_FORMAT_TYPE) +#endif + ) { // COAP_CONTENT_OMA_LINK_FORMAT_TYPE if for Discover coap_response->content_format = received_coap_header->options_list_ptr->accept; set_coap_content_type(coap_response->content_format); } else { @@ -654,7 +656,20 @@ sn_coap_hdr_s *M2MResourceBase::handle_get_request(nsdl_s *nsdl, if (coap_response->content_format == COAP_CONTENT_OMA_TLV_TYPE || coap_response->content_format == COAP_CONTENT_OMA_TLV_TYPE_OLD) { coap_response->payload_ptr = M2MTLVSerializer::serialize(&get_parent_resource(), payload_len); - } else { + } +#if defined (MBED_CONF_MBED_CLIENT_ENABLE_DISCOVERY) && (MBED_CONF_MBED_CLIENT_ENABLE_DISCOVERY == 1) + else if (coap_response->content_format == COAP_CONTENT_OMA_LINK_FORMAT_TYPE) { + // Discover + payload_len = 0; + uint8_t *data = M2MDiscover::create_resource_payload((const M2MResource *)this, payload_len); + if (!data) { + payload_len = 0; + tr_error("M2MResource::handle_get_request() - Discover data allocation failed!"); + } + coap_response->payload_ptr = data; + } +#endif + else { get_value(coap_response->payload_ptr, (uint32_t &)payload_len); } } diff --git a/mbed-cloud-client/MbedCloudClient.h b/mbed-cloud-client/MbedCloudClient.h index 497de02f9..97d6c5ccf 100644 --- a/mbed-cloud-client/MbedCloudClient.h +++ b/mbed-cloud-client/MbedCloudClient.h @@ -218,7 +218,8 @@ class MbedCloudClient : public ServiceClientCallback { Registered, RegistrationUpdated, AlertMode, - Paused + Paused, + Sleep } Status; /** @@ -469,7 +470,7 @@ class MbedCloudClient : public ServiceClientCallback { * \param callback Function pointer that is called when Device Management Client * goes to sleep. */ - void set_queue_sleep_handler(callback_handler handler); + void set_queue_sleep_handler(callback_handler handler) m2m_deprecated; /** * \brief Set the function callback that is called by Device Management Client to diff --git a/mbed-cloud-client/MbedCloudClientConfigCheck.h b/mbed-cloud-client/MbedCloudClientConfigCheck.h index 138bea5ad..fb30eca43 100644 --- a/mbed-cloud-client/MbedCloudClientConfigCheck.h +++ b/mbed-cloud-client/MbedCloudClientConfigCheck.h @@ -96,4 +96,8 @@ defined (MBED_CLOUD_CLIENT_TRANSPORT_MODE_UDP_QUEUE) || defined(MBED_CLOUD_CLIEN #error "MBED_CLIENT_EVENT_LOOP_SIZE is mandatory parameter which should be defined always." #endif +#if defined (MBED_CONF_MBED_CLIENT_MAX_RECONNECT_TIMEOUT) && (MBED_CONF_MBED_CLIENT_MAX_RECONNECT_TIMEOUT < MAX_RECONNECT_TIMEOUT_LOW) +#error "MBED_CONF_MBED_CLIENT_MAX_RECONNECT_TIMEOUT must be at least 300 seconds." +#endif + #endif // MBED_CLOUD_CONFIG_CHECK_H diff --git a/mbed-coap/mbed-coap/sn_coap_header.h b/mbed-coap/mbed-coap/sn_coap_header.h index 881770d84..d6964e228 100644 --- a/mbed-coap/mbed-coap/sn_coap_header.h +++ b/mbed-coap/mbed-coap/sn_coap_header.h @@ -23,6 +23,9 @@ #ifndef SN_COAP_HEADER_H_ #define SN_COAP_HEADER_H_ +#include "sn_config.h" +#include "ns_types.h" + #ifdef __cplusplus extern "C" { #endif @@ -180,8 +183,8 @@ typedef enum sn_coap_status_ { */ typedef struct sn_coap_options_list_ { uint8_t etag_len; /**< 1-8 bytes. Repeatable */ - unsigned int use_size1:1; - unsigned int use_size2:1; + bool use_size1; + bool use_size2; uint16_t proxy_uri_len; /**< 1-1034 bytes. */ uint16_t uri_host_len; /**< 1-255 bytes. */ @@ -351,7 +354,10 @@ extern int16_t sn_coap_builder(uint8_t *dst_packet_data_ptr, const sn_coap_hdr_s * \return Return value is count of needed memory as bytes for build Packet data * Null if failed */ -extern uint16_t sn_coap_builder_calc_needed_packet_data_size(const sn_coap_hdr_s *src_coap_msg_ptr); +extern uint16_t (sn_coap_builder_calc_needed_packet_data_size)(const sn_coap_hdr_s *src_coap_msg_ptr); +#ifdef SN_COAP_CONSTANT_NEEDED_SIZE +#define sn_coap_builder_calc_needed_packet_data_size(m) (SN_COAP_CONSTANT_NEEDED_SIZE) +#endif /** * \fn int16_t sn_coap_builder_2(uint8_t *dst_packet_data_ptr, sn_coap_hdr_s *src_coap_msg_ptr, uint16_t blockwise_size) @@ -382,7 +388,10 @@ extern int16_t sn_coap_builder_2(uint8_t *dst_packet_data_ptr, const sn_coap_hdr * \return Return value is count of needed memory as bytes for build Packet data * Null if failed */ -extern uint16_t sn_coap_builder_calc_needed_packet_data_size_2(const sn_coap_hdr_s *src_coap_msg_ptr, uint16_t blockwise_payload_size); +extern uint16_t (sn_coap_builder_calc_needed_packet_data_size_2)(const sn_coap_hdr_s *src_coap_msg_ptr, uint16_t blockwise_payload_size); +#ifdef SN_COAP_CONSTANT_NEEDED_SIZE +#define sn_coap_builder_calc_needed_packet_data_size_2(m, p) (SN_COAP_CONSTANT_NEEDED_SIZE) +#endif /** * \fn sn_coap_hdr_s *sn_coap_build_response(struct coap_s *handle, sn_coap_hdr_s *coap_packet_ptr, uint8_t msg_code) diff --git a/mbed-coap/mbed-coap/sn_config.h b/mbed-coap/mbed-coap/sn_config.h index 4ad6b14ed..e46da064b 100644 --- a/mbed-coap/mbed-coap/sn_config.h +++ b/mbed-coap/mbed-coap/sn_config.h @@ -68,6 +68,23 @@ #define SN_COAP_MAX_BLOCKWISE_PAYLOAD_SIZE 0 /**< Must be 2^x and x is at least 4. Suitable values: 0, 16, 32, 64, 128, 256, 512 and 1024 */ #endif +/** + * \def SN_COAP_CONSTANT_NEEDED_SIZE + * \brief Avoid needed size calculations + * If this is defined, sn_coap_builder_calc_needed_packet_data_size always returns that value, + * saving a lot of calculation code, at the cost of outgoing TX buffers being oversized, and + * with danger of them being undersized. + * + * sn_coap_builder_payload_build does not have any size input to limit its output, so it is + * always wise for users to assert that it has not output more than the size returned by + * sn_coap_builder_calc_needed_packet_size, whether this option is defined or not. + */ +#ifdef MBED_CONF_MBED_CLIENT_SN_COAP_CONSTANT_NEEDED_SIZE +#define SN_COAP_CONSTANT_NEEDED_SIZE MBED_CONF_MBED_CLIENT_SN_COAP_CONSTANT_NEEDED_SIZE +#endif + +//#define SN_COAP_CONSTANT_NEEDED_SIZE 1024 + /** * \def SN_COAP_DISABLE_RESENDINGS * \brief Disables resending feature. Resending feature should not be needed diff --git a/mbed-coap/source/include/sn_coap_header_internal.h b/mbed-coap/source/include/sn_coap_header_internal.h index ef62e1742..13197899e 100644 --- a/mbed-coap/source/include/sn_coap_header_internal.h +++ b/mbed-coap/source/include/sn_coap_header_internal.h @@ -58,12 +58,12 @@ extern "C" { * \brief This structure is returned by sn_coap_exec() for sending */ typedef struct sn_nsdl_transmit_ { + uint8_t *packet_ptr; + uint16_t packet_len; sn_nsdl_addr_s dst_addr_ptr; sn_nsdl_capab_e protocol; - uint16_t packet_len; - uint8_t *packet_ptr; } sn_nsdl_transmit_s; /* * * * * * * * * * * * * * * * * * * * * * */ diff --git a/mbed-coap/source/include/sn_coap_protocol_internal.h b/mbed-coap/source/include/sn_coap_protocol_internal.h index f0cfffa5a..c846abedb 100644 --- a/mbed-coap/source/include/sn_coap_protocol_internal.h +++ b/mbed-coap/source/include/sn_coap_protocol_internal.h @@ -45,7 +45,7 @@ int8_t prepare_blockwise_message(struct coap_s *handle, struct sn_coap_hdr_ *coa /* Structure which is stored to Linked list for message sending purposes */ typedef struct coap_send_msg_ { - uint8_t resending_counter; /* Tells how many times message is still tried to resend */ + uint_fast8_t resending_counter; /* Tells how many times message is still tried to resend */ uint32_t resending_time; /* Tells next resending time */ sn_nsdl_transmit_s send_msg_ptr; @@ -86,25 +86,35 @@ typedef NS_LIST_HEAD(coap_blockwise_msg_s, link) coap_blockwise_msg_list_t; /* Structure which is stored to Linked list for blockwise messages receiving purposes */ typedef struct coap_blockwise_payload_ { - uint32_t timestamp; /* Tells when Payload is stored to Linked list */ - uint8_t addr_len; - uint8_t *addr_ptr; + uint8_t token_len; + bool use_size1; uint16_t port; + uint16_t payload_len; + uint8_t *addr_ptr; uint32_t block_number; uint8_t *token_ptr; - uint8_t token_len; - - uint16_t payload_len; uint8_t *payload_ptr; - unsigned int use_size1:1; - + uint32_t timestamp; /* Tells when Payload is stored to Linked list */ ns_list_link_t link; } coap_blockwise_payload_s; typedef NS_LIST_HEAD(coap_blockwise_payload_s, link) coap_blockwise_payload_list_t; struct coap_s { + uint8_t sn_coap_resending_queue_msgs; + uint8_t sn_coap_resending_count; + uint8_t sn_coap_resending_intervall; + uint8_t sn_coap_duplication_buffer_size; + uint8_t sn_coap_internal_block2_resp_handling; /* If this is set then coap itself sends a next GET request automatically */ + uint16_t sn_coap_block_data_size; + #if ENABLE_RESENDINGS + uint16_t count_resent_msgs; + #endif +#if SN_COAP_DUPLICATION_MAX_MSGS_COUNT + uint16_t count_duplication_msgs; +#endif + void *(*sn_coap_protocol_malloc)(uint16_t); void (*sn_coap_protocol_free)(void *); @@ -113,12 +123,10 @@ struct coap_s { #if ENABLE_RESENDINGS /* If Message resending is not used at all, this part of code will not be compiled */ coap_send_msg_list_t linked_list_resent_msgs; /* Active resending messages are stored to this Linked list */ - uint16_t count_resent_msgs; #endif #if SN_COAP_DUPLICATION_MAX_MSGS_COUNT /* If Message duplication detection is not used at all, this part of code will not be compiled */ coap_duplication_info_list_t linked_list_duplication_msgs; /* Messages for duplicated messages detection is stored to this Linked list */ - uint16_t count_duplication_msgs; #endif #if SN_COAP_BLOCKWISE_ENABLED || SN_COAP_MAX_BLOCKWISE_PAYLOAD_SIZE /* If Message blockwise is not enabled, this part of code will not be compiled */ @@ -127,20 +135,14 @@ struct coap_s { #endif uint32_t system_time; /* System time seconds */ - uint16_t sn_coap_block_data_size; - uint8_t sn_coap_resending_queue_msgs; uint32_t sn_coap_resending_queue_bytes; - uint8_t sn_coap_resending_count; - uint8_t sn_coap_resending_intervall; - uint8_t sn_coap_duplication_buffer_size; - uint8_t sn_coap_internal_block2_resp_handling; /* If this is set then coap itself sends a next GET request automatically */ }; /* Utility function which performs a call to sn_coap_protocol_malloc() and memset's the result to zero. */ -void *sn_coap_protocol_calloc(struct coap_s *handle, uint16_t length); +void *sn_coap_protocol_calloc(struct coap_s *handle, uint_fast16_t length); /* Utility function which performs a call to sn_coap_protocol_malloc() and memcopy's the source to result buffer. */ -void *sn_coap_protocol_malloc_copy(struct coap_s *handle, const void *source, uint16_t length); +void *sn_coap_protocol_malloc_copy(struct coap_s *handle, const void *source, uint_fast16_t length); #ifdef __cplusplus } diff --git a/mbed-coap/source/sn_coap_builder.c b/mbed-coap/source/sn_coap_builder.c index 928274364..e7aae6d7a 100644 --- a/mbed-coap/source/sn_coap_builder.c +++ b/mbed-coap/source/sn_coap_builder.c @@ -37,17 +37,18 @@ #define TRACE_GROUP "coap" /* * * * LOCAL FUNCTION PROTOTYPES * * * */ -static int8_t sn_coap_builder_header_build(uint8_t **dst_packet_data_pptr, const sn_coap_hdr_s *src_coap_msg_ptr); -static int8_t sn_coap_builder_options_build(uint8_t **dst_packet_data_pptr, const sn_coap_hdr_s *src_coap_msg_ptr); -static uint16_t sn_coap_builder_options_calc_option_size(uint16_t query_len, const uint8_t *query_ptr, sn_coap_option_numbers_e option); -static int16_t sn_coap_builder_options_build_add_one_option(uint8_t **dst_packet_data_pptr, uint16_t option_len, const uint8_t *option_ptr, sn_coap_option_numbers_e option_number, uint16_t *previous_option_number); -static void sn_coap_builder_options_build_add_multiple_option(uint8_t **dst_packet_data_pptr, const uint8_t *src_pptr, uint16_t src_len_ptr, sn_coap_option_numbers_e option, uint16_t *previous_option_number); -static uint8_t sn_coap_builder_options_build_add_uint_option(uint8_t **dst_packet_data_pptr, uint32_t value, sn_coap_option_numbers_e option_number, uint16_t *previous_option_number); -static uint8_t sn_coap_builder_options_get_option_part_count(uint16_t query_len, const uint8_t *query_ptr, sn_coap_option_numbers_e option); -static uint16_t sn_coap_builder_options_get_option_part_length_from_whole_option_string(uint16_t query_len, const uint8_t *query_ptr, uint8_t query_index, sn_coap_option_numbers_e option); -static int16_t sn_coap_builder_options_get_option_part_position(uint16_t query_len, const uint8_t *query_ptr, uint8_t query_index, sn_coap_option_numbers_e option); -static void sn_coap_builder_payload_build(uint8_t **dst_packet_data_pptr, const sn_coap_hdr_s *src_coap_msg_ptr); -static uint8_t sn_coap_builder_options_calculate_jump_need(const sn_coap_hdr_s *src_coap_msg_ptr); +static uint8_t *sn_coap_builder_header_build(uint8_t *dst_packet_data_pptr, const sn_coap_hdr_s *src_coap_msg_ptr); +static uint8_t *sn_coap_builder_options_build(uint8_t *dst_packet_data_ptr, const sn_coap_hdr_s *src_coap_msg_ptr); +static uint_fast16_t sn_coap_builder_options_calc_option_size(uint16_t query_len, const uint8_t *query_ptr, sn_coap_option_numbers_e option); +static uint8_t *sn_coap_builder_options_build_add_one_option(uint8_t *dst_packet_data_ptr, uint_fast16_t option_len, const uint8_t *option_ptr, sn_coap_option_numbers_e option_number, uint16_t *previous_option_number); +static uint8_t *sn_coap_builder_options_build_add_multiple_option(uint8_t *dst_packet_data_pptr, const uint8_t *src_pptr, uint_fast16_t src_len, sn_coap_option_numbers_e option, uint16_t *previous_option_number); +static uint_fast8_t sn_coap_builder_options_calc_uint_option_size(uint32_t option_value); +static uint8_t *sn_coap_builder_options_build_add_uint_option(uint8_t *dst_packet_data_ptr, uint32_t value, sn_coap_option_numbers_e option_number, uint16_t *previous_option_number); +static uint_fast8_t sn_coap_builder_options_get_option_part_count(uint_fast16_t query_len, const uint8_t *query_ptr, sn_coap_option_numbers_e option); +static uint_fast16_t sn_coap_builder_options_get_option_part_length_from_whole_option_string(uint_fast16_t query_len, const uint8_t *query_ptr, uint_fast8_t query_index, sn_coap_option_numbers_e option); +static int_fast16_t sn_coap_builder_options_get_option_part_position(uint_fast16_t query_len, const uint8_t *query_ptr, uint_fast8_t query_index, sn_coap_option_numbers_e option); +static uint8_t *sn_coap_builder_payload_build(uint8_t *dst_packet_data_ptr, const sn_coap_hdr_s *src_coap_msg_ptr); +static uint_fast8_t sn_coap_builder_options_calculate_jump_need(const sn_coap_hdr_s *src_coap_msg_ptr); sn_coap_hdr_s *sn_coap_build_response(struct coap_s *handle, const sn_coap_hdr_s *coap_packet_ptr, uint8_t msg_code) { @@ -101,7 +102,7 @@ int16_t sn_coap_builder(uint8_t *dst_packet_data_ptr, const sn_coap_hdr_s *src_c return sn_coap_builder_2(dst_packet_data_ptr, src_coap_msg_ptr, SN_COAP_MAX_BLOCKWISE_PAYLOAD_SIZE); } -int16_t sn_coap_builder_2(uint8_t *dst_packet_data_ptr, const sn_coap_hdr_s *src_coap_msg_ptr, uint16_t blockwise_payload_size) +int16_t sn_coap_builder_2(uint8_t * restrict dst_packet_data_ptr, const sn_coap_hdr_s * restrict src_coap_msg_ptr, uint16_t blockwise_payload_size) { uint8_t *base_packet_data_ptr; @@ -110,23 +111,22 @@ int16_t sn_coap_builder_2(uint8_t *dst_packet_data_ptr, const sn_coap_hdr_s *src return -2; } - /* Initialize given Packet data memory area with zero values */ + /* This serves as a pre-validity check for various src_coap_msg_ptr fields */ + /* (as long as SN_COAP_CONSTANT_NEEDED_SIZE is not set) */ uint16_t dst_byte_count_to_be_built = sn_coap_builder_calc_needed_packet_data_size_2(src_coap_msg_ptr, blockwise_payload_size); if (!dst_byte_count_to_be_built) { tr_error("sn_coap_builder_2 - failed to allocate message!"); return -1; } - // XXX: this should not be needed anymore but I have no courage to remove it yet. - memset(dst_packet_data_ptr, 0, dst_byte_count_to_be_built); - /* * * * Store base (= original) destination Packet data pointer for later usage * * * */ base_packet_data_ptr = dst_packet_data_ptr; /* * * * * * * * * * * * * * * * * * */ /* * * * Header part building * * * */ /* * * * * * * * * * * * * * * * * * */ - if (sn_coap_builder_header_build(&dst_packet_data_ptr, src_coap_msg_ptr) != 0) { + dst_packet_data_ptr = sn_coap_builder_header_build(dst_packet_data_ptr, src_coap_msg_ptr); + if (!dst_packet_data_ptr) { /* Header building failed */ tr_error("sn_coap_builder_2 - header building failed!"); return -1; @@ -137,23 +137,34 @@ int16_t sn_coap_builder_2(uint8_t *dst_packet_data_ptr, const sn_coap_hdr_s *src /* * * * * * * * * * * * * * * * * * */ /* * * * Options part building * * * */ /* * * * * * * * * * * * * * * * * * */ - sn_coap_builder_options_build(&dst_packet_data_ptr, src_coap_msg_ptr); + dst_packet_data_ptr = sn_coap_builder_options_build(dst_packet_data_ptr, src_coap_msg_ptr); /* * * * * * * * * * * * * * * * * * */ /* * * * Payload part building * * * */ /* * * * * * * * * * * * * * * * * * */ - sn_coap_builder_payload_build(&dst_packet_data_ptr, src_coap_msg_ptr); + dst_packet_data_ptr = sn_coap_builder_payload_build(dst_packet_data_ptr, src_coap_msg_ptr); + } + + /* Shout as much as we can about overflow - if we exceed this, may have overrun user's buffer */ + if (dst_packet_data_ptr - base_packet_data_ptr > dst_byte_count_to_be_built) { + tr_error("sn_coap_builder_2 - overflowed expected size!"); + return -1; } + /* * * * Return built Packet data length * * * */ return (dst_packet_data_ptr - base_packet_data_ptr); } -uint16_t sn_coap_builder_calc_needed_packet_data_size(const sn_coap_hdr_s *src_coap_msg_ptr) + +uint16_t (sn_coap_builder_calc_needed_packet_data_size)(const sn_coap_hdr_s *src_coap_msg_ptr) { return sn_coap_builder_calc_needed_packet_data_size_2(src_coap_msg_ptr, SN_COAP_MAX_BLOCKWISE_PAYLOAD_SIZE); } -uint16_t sn_coap_builder_calc_needed_packet_data_size_2(const sn_coap_hdr_s *src_coap_msg_ptr, uint16_t blockwise_payload_size) +uint16_t (sn_coap_builder_calc_needed_packet_data_size_2)(const sn_coap_hdr_s *src_coap_msg_ptr, uint16_t blockwise_payload_size) { +#ifdef SN_COAP_CONSTANT_NEEDED_SIZE + return SN_COAP_CONSTANT_NEEDED_SIZE; +#else (void)blockwise_payload_size; uint_fast32_t returned_byte_count = 0; @@ -169,7 +180,7 @@ uint16_t sn_coap_builder_calc_needed_packet_data_size_2(const sn_coap_hdr_s *src /* If else than Reset message because Reset message must be empty */ if (src_coap_msg_ptr->msg_type != COAP_MSG_TYPE_RESET) { - uint16_t repeatable_option_size = 0; + uint_fast16_t repeatable_option_size = 0; /* TOKEN - Length is 1-8 bytes */ if (src_coap_msg_ptr->token_ptr != NULL) { if (src_coap_msg_ptr->token_len > 8 || src_coap_msg_ptr->token_len < 1) { /* Check that option is not longer than defined */ @@ -190,19 +201,18 @@ uint16_t sn_coap_builder_calc_needed_packet_data_size_2(const sn_coap_hdr_s *src } } - uint16_t tempInt = 0; /* CONTENT FORMAT - An integer option, up to 2 bytes */ if (src_coap_msg_ptr->content_format != COAP_CT_NONE) { if ((uint32_t) src_coap_msg_ptr->content_format > 0xffff) { tr_error("sn_coap_builder_calc_needed_packet_data_size_2 - content format too large!"); return 0; } - returned_byte_count += sn_coap_builder_options_build_add_uint_option(NULL, src_coap_msg_ptr->content_format, COAP_OPTION_CONTENT_FORMAT, &tempInt); + returned_byte_count += sn_coap_builder_options_calc_uint_option_size(src_coap_msg_ptr->content_format); } /* If options list pointer exists */ if (src_coap_msg_ptr->options_list_ptr != NULL) { - const sn_coap_options_list_s *src_options_list_ptr = src_coap_msg_ptr->options_list_ptr; + const sn_coap_options_list_s * restrict src_options_list_ptr = src_coap_msg_ptr->options_list_ptr; /* ACCEPT - An integer option, up to 2 bytes */ if (src_options_list_ptr->accept != COAP_CT_NONE) { @@ -210,11 +220,11 @@ uint16_t sn_coap_builder_calc_needed_packet_data_size_2(const sn_coap_hdr_s *src tr_error("sn_coap_builder_calc_needed_packet_data_size_2 - accept too large!"); return 0; } - returned_byte_count += sn_coap_builder_options_build_add_uint_option(NULL, src_options_list_ptr->accept, COAP_OPTION_ACCEPT, &tempInt); + returned_byte_count += sn_coap_builder_options_calc_uint_option_size(src_options_list_ptr->accept); } /* MAX AGE - An integer option, omitted for default. Up to 4 bytes */ if (src_options_list_ptr->max_age != COAP_OPTION_MAX_AGE_DEFAULT) { - returned_byte_count += sn_coap_builder_options_build_add_uint_option(NULL, src_options_list_ptr->max_age, COAP_OPTION_MAX_AGE, &tempInt); + returned_byte_count += sn_coap_builder_options_calc_uint_option_size(src_options_list_ptr->max_age); } /* PROXY URI - Length of this option is 1-1034 bytes */ if (src_options_list_ptr->proxy_uri_ptr != NULL) { @@ -282,7 +292,7 @@ uint16_t sn_coap_builder_calc_needed_packet_data_size_2(const sn_coap_hdr_s *src tr_error("sn_coap_builder_calc_needed_packet_data_size_2 - uri port too large!"); return 0; } - returned_byte_count += sn_coap_builder_options_build_add_uint_option(NULL, src_options_list_ptr->uri_port, COAP_OPTION_URI_PORT, &tempInt); + returned_byte_count += sn_coap_builder_options_calc_uint_option_size(src_options_list_ptr->uri_port); } /* lOCATION QUERY - Repeatable option. Length of this option is 0-255 bytes */ if (src_options_list_ptr->location_query_ptr != NULL) { @@ -300,7 +310,7 @@ uint16_t sn_coap_builder_calc_needed_packet_data_size_2(const sn_coap_hdr_s *src if ((uint32_t) src_options_list_ptr->observe > 0xffffff) { return 0; } - returned_byte_count += sn_coap_builder_options_build_add_uint_option(NULL, src_options_list_ptr->observe, COAP_OPTION_OBSERVE, &tempInt); + returned_byte_count += sn_coap_builder_options_calc_uint_option_size(src_options_list_ptr->observe); } /* URI QUERY - Repeatable option. Length of this option is 1-255 */ if (src_options_list_ptr->uri_query_ptr != NULL) { @@ -320,11 +330,11 @@ uint16_t sn_coap_builder_calc_needed_packet_data_size_2(const sn_coap_hdr_s *src tr_error("sn_coap_builder_calc_needed_packet_data_size_2 - block1 too large!"); return 0; } - returned_byte_count += sn_coap_builder_options_build_add_uint_option(NULL, src_options_list_ptr->block1, COAP_OPTION_BLOCK1, &tempInt); + returned_byte_count += sn_coap_builder_options_calc_uint_option_size(src_options_list_ptr->block1); } /* SIZE1 - Length of this option is 0-4 bytes */ if (src_options_list_ptr->use_size1) { - returned_byte_count += sn_coap_builder_options_build_add_uint_option(NULL, src_options_list_ptr->size1, COAP_OPTION_SIZE1, &tempInt); + returned_byte_count += sn_coap_builder_options_calc_uint_option_size(src_options_list_ptr->size1); } /* BLOCK 2 - An integer option, up to 3 bytes */ if (src_options_list_ptr->block2 != COAP_OPTION_BLOCK_NONE) { @@ -332,11 +342,11 @@ uint16_t sn_coap_builder_calc_needed_packet_data_size_2(const sn_coap_hdr_s *src tr_error("sn_coap_builder_calc_needed_packet_data_size_2 - block2 too large!"); return 0; } - returned_byte_count += sn_coap_builder_options_build_add_uint_option(NULL, src_options_list_ptr->block2, COAP_OPTION_BLOCK2, &tempInt); + returned_byte_count += sn_coap_builder_options_calc_uint_option_size(src_options_list_ptr->block2); } /* SIZE2 - Length of this option is 0-4 bytes */ if (src_coap_msg_ptr->options_list_ptr->use_size2) { - returned_byte_count += sn_coap_builder_options_build_add_uint_option(NULL, src_options_list_ptr->size2, COAP_OPTION_SIZE2, &tempInt); + returned_byte_count += sn_coap_builder_options_calc_uint_option_size(src_options_list_ptr->size2); } } #if SN_COAP_BLOCKWISE_ENABLED || SN_COAP_MAX_BLOCKWISE_PAYLOAD_SIZE @@ -360,6 +370,7 @@ uint16_t sn_coap_builder_calc_needed_packet_data_size_2(const sn_coap_hdr_s *src return 0; } return (uint16_t)returned_byte_count; +#endif } /** @@ -374,10 +385,10 @@ uint16_t sn_coap_builder_calc_needed_packet_data_size_2(const sn_coap_hdr_s *src * \return Returns bytes needed for jumping */ -static uint8_t sn_coap_builder_options_calculate_jump_need(const sn_coap_hdr_s *src_coap_msg_ptr) +static uint_fast8_t sn_coap_builder_options_calculate_jump_need(const sn_coap_hdr_s *src_coap_msg_ptr) { uint8_t previous_option_number = 0; - uint8_t needed_space = 0; + uint_fast8_t needed_space = 0; const sn_coap_options_list_s* options_list_ptr = src_coap_msg_ptr->options_list_ptr; @@ -489,54 +500,52 @@ static uint8_t sn_coap_builder_options_calculate_jump_need(const sn_coap_hdr_s * } /** - * \fn static int8_t sn_coap_builder_header_build(uint8_t **dst_packet_data_pptr, sn_coap_hdr_s *src_coap_msg_ptr) + * \fn static int8_t sn_coap_builder_header_build(uint8_t *dst_packet_data_ptr, sn_coap_hdr_s *src_coap_msg_ptr) * * \brief Builds Header part of Packet data * - * \param **dst_packet_data_pptr is destination for built Packet data + * \param *dst_packet_data_ptr is destination for built Packet data * * \param *src_coap_msg_ptr is source for building Packet data * * \return Return value is 0 in ok case and -1 in failure case **************************************************************************** */ -static int8_t sn_coap_builder_header_build(uint8_t **dst_packet_data_pptr, const sn_coap_hdr_s *src_coap_msg_ptr) +static uint8_t *sn_coap_builder_header_build(uint8_t * restrict dst_packet_data_ptr, const sn_coap_hdr_s * restrict src_coap_msg_ptr) { /* * * * Check validity of Header values * * * */ if (sn_coap_header_validity_check(src_coap_msg_ptr, COAP_VERSION) != 0) { tr_error("sn_coap_builder_header_build - header build failed!"); - return -1; + return NULL; } - uint8_t* dest_packet = *dst_packet_data_pptr; - /* Set CoAP Version, Message type and Token length */ - dest_packet[0] = COAP_VERSION | src_coap_msg_ptr->msg_type | src_coap_msg_ptr->token_len; + dst_packet_data_ptr[0] = COAP_VERSION | src_coap_msg_ptr->msg_type | src_coap_msg_ptr->token_len; /* * * Add Message code * * */ - dest_packet[1] = src_coap_msg_ptr->msg_code; + dst_packet_data_ptr[1] = src_coap_msg_ptr->msg_code; /* * * Add Message ID * * */ - dest_packet[2] = (uint8_t)(src_coap_msg_ptr->msg_id >> COAP_HEADER_MSG_ID_MSB_SHIFT); /* MSB part */ - dest_packet[3] = (uint8_t)src_coap_msg_ptr->msg_id; /* LSB part */ + dst_packet_data_ptr[2] = (uint8_t)(src_coap_msg_ptr->msg_id >> COAP_HEADER_MSG_ID_MSB_SHIFT); /* MSB part */ + dst_packet_data_ptr[3] = (uint8_t)src_coap_msg_ptr->msg_id; /* LSB part */ - *dst_packet_data_pptr = dest_packet + 4; + dst_packet_data_ptr += 4; /* Success */ - return 0; + return dst_packet_data_ptr; } /** - * \fn static int8_t sn_coap_builder_options_build(uint8_t **dst_packet_data_pptr, sn_coap_hdr_s *src_coap_msg_ptr) + * \fn static int8_t sn_coap_builder_options_build(uint8_t *dst_packet_data_ptr, sn_coap_hdr_s *src_coap_msg_ptr) * * \brief Builds Options part of Packet data * - * \param **dst_packet_data_pptr is destination for built Packet data + * \param *dst_packet_data_ptr is destination for built Packet data * * \param *src_coap_msg_ptr is source for building Packet data * - * \return Return value is 0 in every case + * \return Returns updated output pointer */ -static int8_t sn_coap_builder_options_build(uint8_t **dst_packet_data_pptr, const sn_coap_hdr_s *src_coap_msg_ptr) +static uint8_t *sn_coap_builder_options_build(uint8_t * restrict dst_packet_data_ptr, const sn_coap_hdr_s * restrict src_coap_msg_ptr) { /* * * * Check if Options are used at all * * * */ if (src_coap_msg_ptr->uri_path_ptr == NULL && src_coap_msg_ptr->token_ptr == NULL && @@ -545,14 +554,14 @@ static int8_t sn_coap_builder_options_build(uint8_t **dst_packet_data_pptr, cons if (src_coap_msg_ptr->msg_type != COAP_MSG_TYPE_CONFIRMABLE) { tr_error("sn_coap_builder_options_build - options not used!"); } - return 0; + return dst_packet_data_ptr; } /* * * * First add Token option * * * */ if (src_coap_msg_ptr->token_len && src_coap_msg_ptr->token_ptr) { - memcpy(*dst_packet_data_pptr, src_coap_msg_ptr->token_ptr, src_coap_msg_ptr->token_len); + memcpy(dst_packet_data_ptr, src_coap_msg_ptr->token_ptr, src_coap_msg_ptr->token_len); } - (*dst_packet_data_pptr) += src_coap_msg_ptr->token_len; + dst_packet_data_ptr += src_coap_msg_ptr->token_len; /* Then build rest of the options */ @@ -561,105 +570,105 @@ static int8_t sn_coap_builder_options_build(uint8_t **dst_packet_data_pptr, cons //missing: COAP_OPTION_IF_MATCH, COAP_OPTION_IF_NONE_MATCH, COAP_OPTION_SIZE - const sn_coap_options_list_s *src_options_list_ptr = src_coap_msg_ptr->options_list_ptr; + const sn_coap_options_list_s * restrict src_options_list_ptr = src_coap_msg_ptr->options_list_ptr; /* Check if less used options are used at all */ if (src_options_list_ptr != NULL) { /* * * * Build Uri-Host option * * * */ - sn_coap_builder_options_build_add_one_option(dst_packet_data_pptr, src_options_list_ptr->uri_host_len, + dst_packet_data_ptr = sn_coap_builder_options_build_add_one_option(dst_packet_data_ptr, src_options_list_ptr->uri_host_len, src_options_list_ptr->uri_host_ptr, COAP_OPTION_URI_HOST, &previous_option_number); /* * * * Build ETag option * * * */ - sn_coap_builder_options_build_add_multiple_option(dst_packet_data_pptr, src_options_list_ptr->etag_ptr, + dst_packet_data_ptr = sn_coap_builder_options_build_add_multiple_option(dst_packet_data_ptr, src_options_list_ptr->etag_ptr, src_options_list_ptr->etag_len, COAP_OPTION_ETAG, &previous_option_number); /* * * * Build Observe option * * * * */ if (src_options_list_ptr->observe != COAP_OBSERVE_NONE) { - sn_coap_builder_options_build_add_uint_option(dst_packet_data_pptr, src_options_list_ptr->observe, + dst_packet_data_ptr = sn_coap_builder_options_build_add_uint_option(dst_packet_data_ptr, src_options_list_ptr->observe, COAP_OPTION_OBSERVE, &previous_option_number); } /* * * * Build Uri-Port option * * * */ if (src_options_list_ptr->uri_port != COAP_OPTION_URI_PORT_NONE) { - sn_coap_builder_options_build_add_uint_option(dst_packet_data_pptr, src_options_list_ptr->uri_port, + dst_packet_data_ptr = sn_coap_builder_options_build_add_uint_option(dst_packet_data_ptr, src_options_list_ptr->uri_port, COAP_OPTION_URI_PORT, &previous_option_number); } /* * * * Build Location-Path option * * * */ - sn_coap_builder_options_build_add_multiple_option(dst_packet_data_pptr, src_options_list_ptr->location_path_ptr, + dst_packet_data_ptr = sn_coap_builder_options_build_add_multiple_option(dst_packet_data_ptr, src_options_list_ptr->location_path_ptr, src_options_list_ptr->location_path_len, COAP_OPTION_LOCATION_PATH, &previous_option_number); } /* * * * Build Uri-Path option * * * */ - sn_coap_builder_options_build_add_multiple_option(dst_packet_data_pptr, src_coap_msg_ptr->uri_path_ptr, + dst_packet_data_ptr = sn_coap_builder_options_build_add_multiple_option(dst_packet_data_ptr, src_coap_msg_ptr->uri_path_ptr, src_coap_msg_ptr->uri_path_len, COAP_OPTION_URI_PATH, &previous_option_number); /* * * * Build Content-Type option * * * */ if (src_coap_msg_ptr->content_format != COAP_CT_NONE) { - sn_coap_builder_options_build_add_uint_option(dst_packet_data_pptr, src_coap_msg_ptr->content_format, + dst_packet_data_ptr = sn_coap_builder_options_build_add_uint_option(dst_packet_data_ptr, src_coap_msg_ptr->content_format, COAP_OPTION_CONTENT_FORMAT, &previous_option_number); } if (src_options_list_ptr != NULL) { /* * * * Build Max-Age option * * * */ if (src_options_list_ptr->max_age != COAP_OPTION_MAX_AGE_DEFAULT) { - sn_coap_builder_options_build_add_uint_option(dst_packet_data_pptr, src_options_list_ptr->max_age, + dst_packet_data_ptr = sn_coap_builder_options_build_add_uint_option(dst_packet_data_ptr, src_options_list_ptr->max_age, COAP_OPTION_MAX_AGE, &previous_option_number); } /* * * * Build Uri-Query option * * * * */ - sn_coap_builder_options_build_add_multiple_option(dst_packet_data_pptr, src_options_list_ptr->uri_query_ptr, + dst_packet_data_ptr = sn_coap_builder_options_build_add_multiple_option(dst_packet_data_ptr, src_options_list_ptr->uri_query_ptr, src_options_list_ptr->uri_query_len, COAP_OPTION_URI_QUERY, &previous_option_number); /* * * * Build Accept option * * * * */ if (src_coap_msg_ptr->options_list_ptr->accept != COAP_CT_NONE) { - sn_coap_builder_options_build_add_uint_option(dst_packet_data_pptr, src_options_list_ptr->accept, + dst_packet_data_ptr = sn_coap_builder_options_build_add_uint_option(dst_packet_data_ptr, src_options_list_ptr->accept, COAP_OPTION_ACCEPT, &previous_option_number); } /* * * * Build Location-Query option * * * */ - sn_coap_builder_options_build_add_multiple_option(dst_packet_data_pptr, src_options_list_ptr->location_query_ptr, + dst_packet_data_ptr = sn_coap_builder_options_build_add_multiple_option(dst_packet_data_ptr, src_options_list_ptr->location_query_ptr, src_options_list_ptr->location_query_len, COAP_OPTION_LOCATION_QUERY, &previous_option_number); /* * * * Build Block2 option * * * * */ if (src_coap_msg_ptr->options_list_ptr->block2 != COAP_OPTION_BLOCK_NONE) { - sn_coap_builder_options_build_add_uint_option(dst_packet_data_pptr, src_options_list_ptr->block2, + dst_packet_data_ptr = sn_coap_builder_options_build_add_uint_option(dst_packet_data_ptr, src_options_list_ptr->block2, COAP_OPTION_BLOCK2, &previous_option_number); } /* * * * Build Block1 option * * * * */ if (src_coap_msg_ptr->options_list_ptr->block1 != COAP_OPTION_BLOCK_NONE) { - sn_coap_builder_options_build_add_uint_option(dst_packet_data_pptr, src_options_list_ptr->block1, + dst_packet_data_ptr = sn_coap_builder_options_build_add_uint_option(dst_packet_data_ptr, src_options_list_ptr->block1, COAP_OPTION_BLOCK1, &previous_option_number); } /* * * * Build Size2 option * * * */ if (src_coap_msg_ptr->options_list_ptr->use_size2) { - sn_coap_builder_options_build_add_uint_option(dst_packet_data_pptr, src_options_list_ptr->size2, + dst_packet_data_ptr = sn_coap_builder_options_build_add_uint_option(dst_packet_data_ptr, src_options_list_ptr->size2, COAP_OPTION_SIZE2, &previous_option_number); } /* * * * Build Proxy-Uri option * * * */ - sn_coap_builder_options_build_add_one_option(dst_packet_data_pptr, src_options_list_ptr->proxy_uri_len, + dst_packet_data_ptr = sn_coap_builder_options_build_add_one_option(dst_packet_data_ptr, src_options_list_ptr->proxy_uri_len, src_options_list_ptr->proxy_uri_ptr, COAP_OPTION_PROXY_URI, &previous_option_number); /* * * * Build Size1 option * * * */ if (src_options_list_ptr->use_size1) { - sn_coap_builder_options_build_add_uint_option(dst_packet_data_pptr, src_options_list_ptr->size1, + dst_packet_data_ptr = sn_coap_builder_options_build_add_uint_option(dst_packet_data_ptr, src_options_list_ptr->size1, COAP_OPTION_SIZE1, &previous_option_number); } } /* Success */ - return 0; + return dst_packet_data_ptr; } /** - * \fn static int16_t sn_coap_builder_options_build_add_one_option(uint8_t **dst_packet_data_pptr, uint16_t option_value_len, uint8_t *option_value_ptr, sn_coap_option_numbers_e option_number) + * \fn static uint8_t *sn_coap_builder_options_build_add_one_option(uint8_t *dst_packet_data_ptr, uint16_t option_value_len, uint8_t *option_value_ptr, sn_coap_option_numbers_e option_number) * * \brief Adds Options part of Packet data * - * \param **dst_packet_data_pptr is destination for built Packet data + * \param *dst_packet_data_ptr is destination for built Packet data * * \param option_value_len is Option value length to be added * @@ -667,20 +676,20 @@ static int8_t sn_coap_builder_options_build(uint8_t **dst_packet_data_pptr, cons * * \param option_number is Option number to be added * - * \return Return value is 0 if option was not added, 1 if added + * \return Advanced destination */ -static int16_t sn_coap_builder_options_build_add_one_option(uint8_t **dst_packet_data_pptr, uint16_t option_len, - const uint8_t *option_ptr, sn_coap_option_numbers_e option_number, uint16_t *previous_option_number) +static uint8_t *sn_coap_builder_options_build_add_one_option(uint8_t * restrict dst_packet_data_ptr, uint_fast16_t option_len, + const uint8_t * restrict option_ptr, sn_coap_option_numbers_e option_number, uint16_t * restrict previous_option_number) { /* Check if there is option at all */ if (option_ptr != NULL) { - uint16_t option_delta; + uint_fast16_t option_delta; option_delta = (option_number - *previous_option_number); /* * * Build option header * * */ - uint8_t first_byte; + uint_fast8_t first_byte; /* First option length without extended part */ if (option_len <= 12) { @@ -695,101 +704,97 @@ static int16_t sn_coap_builder_options_build_add_one_option(uint8_t **dst_packet first_byte = 0x0E; } - uint8_t *dest_packet = *dst_packet_data_pptr; - /* Then option delta with extensions, and move pointer */ if (option_delta <= 12) { - dest_packet[0] = first_byte + (option_delta << 4); - dest_packet += 1; + *dst_packet_data_ptr++ = first_byte + (option_delta << 4); } else if (option_delta > 12 && option_delta < 269) { - dest_packet[0] = first_byte + 0xD0; + *dst_packet_data_ptr++ = first_byte + 0xD0; option_delta -= 13; - dest_packet[1] = (uint8_t)option_delta; - dest_packet += 2; + *dst_packet_data_ptr++ = (uint8_t)option_delta; } //This is currently dead code (but possibly needed in future) else /*if (option_delta >= 269)*/ { - dest_packet[0] = first_byte + 0xE0; + *dst_packet_data_ptr++ = first_byte + 0xE0; option_delta -= 269; - dest_packet[1] = (option_delta >> 8); - dest_packet[2] = (uint8_t)option_delta; - dest_packet += 3; + *dst_packet_data_ptr++ = (option_delta >> 8); + *dst_packet_data_ptr++ = (uint8_t)option_delta; } /* Now option length extensions, if needed */ if (option_len > 12 && option_len < 269) { - dest_packet[0] = (uint8_t)(option_len - 13); - dest_packet += 1; + *dst_packet_data_ptr++ = (uint8_t)(option_len - 13); } else if (option_len >= 269) { - dest_packet[0] = ((option_len - 269) >> 8); - dest_packet[1] = (uint8_t)(option_len - 269); - dest_packet += 2; + *dst_packet_data_ptr++ = ((option_len - 269) >> 8); + *dst_packet_data_ptr++ = (uint8_t)(option_len - 269); } *previous_option_number = option_number; /* Write Option value */ - memcpy(dest_packet, option_ptr, option_len); + memcpy(dst_packet_data_ptr, option_ptr, option_len); /* Increase destination Packet data pointer */ - dest_packet += option_len; + dst_packet_data_ptr += option_len; + } - *dst_packet_data_pptr = dest_packet; + /* Success */ + return dst_packet_data_ptr; +} - return 1; +static uint_fast8_t sn_coap_builder_options_calc_uint_option_size(uint32_t option_value) +{ + // Calculation assumes option type/len is always 1 byte. + // Length certainly fits, and any extra for option type is accounted for + // separately by sn_coap_builder_options_calculate_jump_need. + uint_fast8_t len = 1; + + while (option_value != 0) { + len++; + option_value >>= 8; } - /* Success */ - return 0; + return len; } /** * \brief Constructs a uint Options part of Packet data * - * \param **dst_packet_data_pptr is destination for built Packet data; NULL + * \param *dst_packet_data_pptr is destination for built Packet data; NULL * to compute size only. * * \param option_value is Option value to be added * * \param option_number is Option number to be added * - * \return Return value is total option size, or -1 in write failure case + * \return Updated destination pointer */ -static uint8_t sn_coap_builder_options_build_add_uint_option(uint8_t **dst_packet_data_pptr, uint32_t option_value, sn_coap_option_numbers_e option_number, uint16_t *previous_option_number) +static uint8_t *sn_coap_builder_options_build_add_uint_option(uint8_t * restrict dst_packet_data_ptr, uint32_t option_value, sn_coap_option_numbers_e option_number, uint16_t * restrict previous_option_number) { uint8_t payload[4]; - uint8_t len = 0; + uint_fast8_t len = 0; /* Construct the variable-length payload representing the value */ - for (uint8_t i = 0; i < 4; i++) { + for (uint_fast8_t i = 0; i < 4; i++) { if (len > 0 || (option_value & 0xff000000)) { payload[len++] = option_value >> 24; } option_value <<= 8; } - /* If output pointer isn't NULL, write it out */ - if (dst_packet_data_pptr) { - // No need to check & handle return value, as the function returns failure only if the option pointer is zero - // and it is pointing to a local variable here. - sn_coap_builder_options_build_add_one_option(dst_packet_data_pptr, len, payload, option_number, previous_option_number); - } - - /* Return the total option size */ - return 1 + len; + return sn_coap_builder_options_build_add_one_option(dst_packet_data_ptr, len, payload, option_number, previous_option_number); } /** - * \fn static int16_t sn_coap_builder_options_build_add_multiple_option(uint8_t **dst_packet_data_pptr, uint8_t **src_pptr, uint16_t *src_len_ptr, sn_coap_option_numbers_e option) + * \fn static int16_t sn_coap_builder_options_build_add_multiple_option(uint8_t *dst_packet_data_pptr, uint8_t **src_pptr, uint16_t *src_len_ptr, sn_coap_option_numbers_e option) * * \brief Builds Option Uri-Query from given CoAP Header structure to Packet data * - * \param **dst_packet_data_pptr is destination for built Packet data + * \param *dst_packet_data_ptr is destination for built Packet data * * \param uint8_t **src_ptr * @@ -797,17 +802,17 @@ static uint8_t sn_coap_builder_options_build_add_uint_option(uint8_t **dst_packe * * \paramsn_coap_option_numbers_e option option to be added * - * \return Return value is 0 always + * \return Returns updated output pointer */ -static void sn_coap_builder_options_build_add_multiple_option(uint8_t **dst_packet_data_pptr, const uint8_t *src_pptr, uint16_t src_len, sn_coap_option_numbers_e option, uint16_t *previous_option_number) +static uint8_t *sn_coap_builder_options_build_add_multiple_option(uint8_t * restrict dst_packet_data_ptr, const uint8_t * restrict src_pptr, uint_fast16_t src_len, sn_coap_option_numbers_e option, uint16_t * restrict previous_option_number) { /* Check if there is option at all */ if (src_pptr != NULL) { - const uint8_t *query_ptr = src_pptr; - uint8_t query_part_count = 0; - uint16_t query_len = src_len; - uint8_t i = 0; - uint16_t query_part_offset = 0; + const uint8_t * restrict query_ptr = src_pptr; + uint_fast8_t query_part_count = 0; + uint_fast16_t query_len = src_len; + uint_fast8_t i = 0; + uint_fast16_t query_part_offset = 0; /* Get query part count */ query_part_count = sn_coap_builder_options_get_option_part_count(query_len, query_ptr, option); @@ -815,16 +820,17 @@ static void sn_coap_builder_options_build_add_multiple_option(uint8_t **dst_pack /* * * * Options by adding all parts to option * * * */ for (i = 0; i < query_part_count; i++) { /* Get length of query part */ - uint16_t one_query_part_len = sn_coap_builder_options_get_option_part_length_from_whole_option_string(query_len, query_ptr, i, option); + uint_fast16_t one_query_part_len = sn_coap_builder_options_get_option_part_length_from_whole_option_string(query_len, query_ptr, i, option); /* Get position of query part */ query_part_offset = sn_coap_builder_options_get_option_part_position(query_len, query_ptr, i, option); /* Add Uri-query's one part to Options */ - sn_coap_builder_options_build_add_one_option(dst_packet_data_pptr, one_query_part_len, src_pptr + query_part_offset, option, previous_option_number); + dst_packet_data_ptr = sn_coap_builder_options_build_add_one_option(dst_packet_data_ptr, one_query_part_len, src_pptr + query_part_offset, option, previous_option_number); } } /* Success */ + return dst_packet_data_ptr; } @@ -839,11 +845,11 @@ static void sn_coap_builder_options_build_add_multiple_option(uint8_t **dst_pack * * \return Return value is count of needed memory as bytes for Uri-query option */ -static uint16_t sn_coap_builder_options_calc_option_size(uint16_t query_len, const uint8_t *query_ptr, sn_coap_option_numbers_e option) +static uint_fast16_t sn_coap_builder_options_calc_option_size(uint16_t query_len, const uint8_t *query_ptr, sn_coap_option_numbers_e option) { - uint8_t query_part_count = sn_coap_builder_options_get_option_part_count(query_len, query_ptr, option); - uint8_t i = 0; - uint16_t ret_value = 0; + uint_fast8_t query_part_count = sn_coap_builder_options_get_option_part_count(query_len, query_ptr, option); + uint_fast8_t i = 0; + uint_fast16_t ret_value = 0; /* * * * * * * * * * * * * * * * * * * * * * * * */ /* * * * Calculate Uri-query options length * * */ @@ -852,7 +858,7 @@ static uint16_t sn_coap_builder_options_calc_option_size(uint16_t query_len, con /* * * Length of Option number and Option value length * * */ /* Get length of Query part */ - uint16_t one_query_part_len = sn_coap_builder_options_get_option_part_length_from_whole_option_string(query_len, query_ptr, i, option); + uint_fast16_t one_query_part_len = sn_coap_builder_options_get_option_part_length_from_whole_option_string(query_len, query_ptr, i, option); /* Check option length */ switch (option) { @@ -920,25 +926,27 @@ static uint16_t sn_coap_builder_options_calc_option_size(uint16_t query_len, con * * \return Return value is count of query parts */ -static uint8_t sn_coap_builder_options_get_option_part_count(uint16_t query_len, const uint8_t *query_ptr, sn_coap_option_numbers_e option) +static uint_fast8_t sn_coap_builder_options_get_option_part_count(uint_fast16_t query_len, const uint8_t *query_ptr, sn_coap_option_numbers_e option) { - uint8_t returned_query_count = 0; - uint16_t query_len_index = 0; - uint8_t char_to_search = '&'; + if (query_len <= 2) { + return 1; + } + + const uint8_t *query_end = query_ptr + query_len - 1; + uint8_t char_to_search = '&'; if (option == COAP_OPTION_URI_PATH || option == COAP_OPTION_LOCATION_PATH) { char_to_search = '/'; } /* Loop whole query and search '\0' characters (not first and last char) */ - for (query_len_index = 1; query_len_index < query_len - 1; query_len_index++) { - /* If new query part starts */ - if (*(query_ptr + query_len_index) == char_to_search) { /* If match */ + uint_fast8_t returned_query_count = 1; + query_ptr++; + do { + if (*query_ptr++ == char_to_search) { /* If match */ returned_query_count++; } - } - - returned_query_count++; + } while (query_ptr < query_end); return returned_query_count; } @@ -960,13 +968,13 @@ static uint8_t sn_coap_builder_options_get_option_part_count(uint16_t query_len, * * \return Return value is length of query part */ -static uint16_t sn_coap_builder_options_get_option_part_length_from_whole_option_string(uint16_t query_len, const uint8_t *query_ptr, - uint8_t query_index, sn_coap_option_numbers_e option) +static uint_fast16_t sn_coap_builder_options_get_option_part_length_from_whole_option_string(uint_fast16_t query_len, const uint8_t *query_ptr, + uint_fast8_t query_index, sn_coap_option_numbers_e option) { - uint16_t returned_query_part_len = 0; - uint8_t temp_query_index = 0; - uint16_t query_len_index = 0; - uint8_t char_to_search = '&'; + uint_fast16_t returned_query_part_len = 0; + uint_fast8_t temp_query_index = 0; + uint_fast16_t query_len_index = 0; + uint_fast8_t char_to_search = '&'; if (option == COAP_OPTION_URI_PATH || option == COAP_OPTION_LOCATION_PATH) { char_to_search = '/'; @@ -975,7 +983,7 @@ static uint16_t sn_coap_builder_options_get_option_part_length_from_whole_option /* Loop whole query and search '\0' characters */ for (query_len_index = 0; query_len_index < query_len; query_len_index++) { /* Store character to temp_char for helping debugging */ - uint8_t temp_char = *query_ptr; + uint_fast8_t temp_char = *query_ptr; /* If new query part starts */ if (temp_char == char_to_search && returned_query_part_len > 0) { /* returned_query_part_len > 0 is for querys which start with "\0" */ @@ -1018,13 +1026,13 @@ static uint16_t sn_coap_builder_options_get_option_part_length_from_whole_option * \return Return value is position (= offset) of query part in whole query. In * fail cases -1 is returned. */ -static int16_t sn_coap_builder_options_get_option_part_position(uint16_t query_len, const uint8_t *query_ptr, - uint8_t query_index, sn_coap_option_numbers_e option) +static int_fast16_t sn_coap_builder_options_get_option_part_position(uint_fast16_t query_len, const uint8_t *query_ptr, + uint_fast8_t query_index, sn_coap_option_numbers_e option) { - uint16_t returned_query_part_offset = 0; - uint8_t temp_query_index = 0; - uint16_t query_len_index = 0; - uint8_t char_to_search = '&'; + uint_fast16_t returned_query_part_offset = 0; + uint_fast8_t temp_query_index = 0; + uint_fast16_t query_len_index = 0; + uint_fast8_t char_to_search = '&'; if (option == COAP_OPTION_URI_PATH || option == COAP_OPTION_LOCATION_PATH) { char_to_search = '/'; @@ -1041,7 +1049,7 @@ static int16_t sn_coap_builder_options_get_option_part_position(uint16_t query_l /* Loop whole query and search separator characters */ for (query_len_index = 0; query_len_index < query_len; query_len_index++) { /* Store character to temp_char for helping debugging */ - uint8_t temp_char = *query_ptr; + uint_fast8_t temp_char = *query_ptr; /* If new query part starts */ if (temp_char == char_to_search && returned_query_part_offset > 0) { /* returned_query_part_offset > 0 is for querys which start with searched char */ @@ -1065,27 +1073,28 @@ static int16_t sn_coap_builder_options_get_option_part_position(uint16_t query_l /** - * \fn static void sn_coap_builder_payload_build(uint8_t **dst_packet_data_pptr, sn_coap_hdr_s *src_coap_msg_ptr) + * \fn static void sn_coap_builder_payload_build(uint8_t *dst_packet_data_pptr, sn_coap_hdr_s *src_coap_msg_ptr) * * \brief Builds Options part of Packet data * - * \param **dst_packet_data_pptr is destination for built Packet data + * \param *dst_packet_data_ptr is destination for built Packet data * * \param *src_coap_msg_ptr is source for building Packet data */ -static void sn_coap_builder_payload_build(uint8_t **dst_packet_data_pptr, const sn_coap_hdr_s *src_coap_msg_ptr) +static uint8_t *sn_coap_builder_payload_build(uint8_t * restrict dst_packet_data_ptr, const sn_coap_hdr_s * restrict src_coap_msg_ptr) { /* Check if Payload is used at all */ if (src_coap_msg_ptr->payload_len && src_coap_msg_ptr->payload_ptr != NULL) { /* Write Payload marker */ - **dst_packet_data_pptr = 0xff; - (*dst_packet_data_pptr)++; + *dst_packet_data_ptr++ = 0xff; /* Write Payload */ - memcpy(*dst_packet_data_pptr, src_coap_msg_ptr->payload_ptr, src_coap_msg_ptr->payload_len); + memcpy(dst_packet_data_ptr, src_coap_msg_ptr->payload_ptr, src_coap_msg_ptr->payload_len); /* Increase destination Packet data pointer */ - (*dst_packet_data_pptr) += src_coap_msg_ptr->payload_len; + dst_packet_data_ptr += src_coap_msg_ptr->payload_len; } + + return dst_packet_data_ptr; } diff --git a/mbed-coap/source/sn_coap_parser.c b/mbed-coap/source/sn_coap_parser.c index 8145a0856..7764afd36 100644 --- a/mbed-coap/source/sn_coap_parser.c +++ b/mbed-coap/source/sn_coap_parser.c @@ -42,11 +42,11 @@ /* * * * LOCAL FUNCTION PROTOTYPES * * * */ /* * * * * * * * * * * * * * * * * * * * */ -static void sn_coap_parser_header_parse(uint8_t **packet_data_pptr, sn_coap_hdr_s *dst_coap_msg_ptr, coap_version_e *coap_version_ptr); -static int8_t sn_coap_parser_options_parse(struct coap_s *handle, uint8_t **packet_data_pptr, sn_coap_hdr_s *dst_coap_msg_ptr, uint8_t *packet_data_start_ptr, uint16_t packet_len); -static int8_t sn_coap_parser_options_parse_multiple_options(struct coap_s *handle, uint8_t **packet_data_pptr, uint16_t packet_left_len, uint8_t **dst_pptr, uint16_t *dst_len_ptr, sn_coap_option_numbers_e option, uint16_t option_number_len); -static int16_t sn_coap_parser_options_count_needed_memory_multiple_option(uint8_t *packet_data_ptr, uint16_t packet_left_len, sn_coap_option_numbers_e option, uint16_t option_number_len); -static int8_t sn_coap_parser_payload_parse(uint16_t packet_data_len, uint8_t *packet_data_start_ptr, uint8_t **packet_data_pptr, sn_coap_hdr_s *dst_coap_msg_ptr); +static const uint8_t *sn_coap_parser_header_parse(const uint8_t *packet_data_ptr, sn_coap_hdr_s *dst_coap_msg_ptr, coap_version_e *coap_version_ptr); +static const uint8_t *sn_coap_parser_options_parse(const uint8_t *packet_data_ptr, struct coap_s *handle, sn_coap_hdr_s *dst_coap_msg_ptr, const uint8_t *packet_data_start_ptr, uint_fast16_t packet_len); +static const uint8_t *sn_coap_parser_options_parse_multiple_options(const uint8_t *packet_data_ptr, struct coap_s *handle, uint_fast16_t packet_left_len, uint8_t **dst_pptr, uint16_t *dst_len_ptr, sn_coap_option_numbers_e option, uint_fast16_t option_number_len); +static int sn_coap_parser_options_count_needed_memory_multiple_option(const uint8_t *packet_data_ptr, uint_fast16_t packet_left_len, sn_coap_option_numbers_e option, uint_fast16_t option_number_len); +static const uint8_t *sn_coap_parser_payload_parse(const uint8_t *packet_data_ptr, uint16_t packet_data_len, uint8_t *packet_data_start_ptr, sn_coap_hdr_s *dst_coap_msg_ptr); sn_coap_hdr_s *sn_coap_parser_init_message(sn_coap_hdr_s *coap_msg_ptr) { @@ -138,7 +138,7 @@ sn_coap_options_list_s *sn_coap_parser_alloc_options(struct coap_s *handle, sn_c sn_coap_hdr_s *sn_coap_parser(struct coap_s *handle, uint16_t packet_data_len, uint8_t *packet_data_ptr, coap_version_e *coap_version_ptr) { - uint8_t *data_temp_ptr = packet_data_ptr; + const uint8_t *data_temp_ptr = packet_data_ptr; sn_coap_hdr_s *parsed_and_returned_coap_msg_ptr = NULL; /* * * * Check given pointer * * * */ @@ -155,15 +155,18 @@ sn_coap_hdr_s *sn_coap_parser(struct coap_s *handle, uint16_t packet_data_len, u } /* * * * Header parsing, move pointer over the header... * * * */ - sn_coap_parser_header_parse(&data_temp_ptr, parsed_and_returned_coap_msg_ptr, coap_version_ptr); + data_temp_ptr = sn_coap_parser_header_parse(data_temp_ptr, parsed_and_returned_coap_msg_ptr, coap_version_ptr); + /* * * * Options parsing, move pointer over the options... * * * */ - if (sn_coap_parser_options_parse(handle, &data_temp_ptr, parsed_and_returned_coap_msg_ptr, packet_data_ptr, packet_data_len) != 0) { + data_temp_ptr = sn_coap_parser_options_parse(data_temp_ptr, handle, parsed_and_returned_coap_msg_ptr, packet_data_ptr, packet_data_len); + if (!data_temp_ptr) { parsed_and_returned_coap_msg_ptr->coap_status = COAP_STATUS_PARSER_ERROR_IN_HEADER; return parsed_and_returned_coap_msg_ptr; } /* * * * Payload parsing * * * */ - if (sn_coap_parser_payload_parse(packet_data_len, packet_data_ptr, &data_temp_ptr, parsed_and_returned_coap_msg_ptr) == -1) { + data_temp_ptr = sn_coap_parser_payload_parse(data_temp_ptr, packet_data_len, packet_data_ptr, parsed_and_returned_coap_msg_ptr); + if (!data_temp_ptr) { parsed_and_returned_coap_msg_ptr->coap_status = COAP_STATUS_PARSER_ERROR_IN_HEADER; return parsed_and_returned_coap_msg_ptr; } @@ -224,22 +227,20 @@ void sn_coap_parser_release_allocated_coap_msg_mem(struct coap_s *handle, sn_coa * * \param *coap_version_ptr is destination for parsed CoAP specification version */ -static void sn_coap_parser_header_parse(uint8_t **packet_data_pptr, sn_coap_hdr_s *dst_coap_msg_ptr, coap_version_e *coap_version_ptr) +static const uint8_t *sn_coap_parser_header_parse(const uint8_t * restrict packet_data_ptr, sn_coap_hdr_s * restrict dst_coap_msg_ptr, coap_version_e * restrict coap_version_ptr) { /* Parse CoAP Version and message type*/ - *coap_version_ptr = (coap_version_e)(**packet_data_pptr & COAP_HEADER_VERSION_MASK); - dst_coap_msg_ptr->msg_type = (sn_coap_msg_type_e)(**packet_data_pptr & COAP_HEADER_MSG_TYPE_MASK); - (*packet_data_pptr) += 1; + *coap_version_ptr = (coap_version_e)(*packet_data_ptr & COAP_HEADER_VERSION_MASK); + dst_coap_msg_ptr->msg_type = (sn_coap_msg_type_e)(*packet_data_ptr++ & COAP_HEADER_MSG_TYPE_MASK); /* Parse Message code */ - dst_coap_msg_ptr->msg_code = (sn_coap_msg_code_e) **packet_data_pptr; - (*packet_data_pptr) += 1; + dst_coap_msg_ptr->msg_code = (sn_coap_msg_code_e) *packet_data_ptr++; /* Parse Message ID */ - dst_coap_msg_ptr->msg_id = *(*packet_data_pptr + 1); - dst_coap_msg_ptr->msg_id += **packet_data_pptr << COAP_HEADER_MSG_ID_MSB_SHIFT; - (*packet_data_pptr) += 2; + dst_coap_msg_ptr->msg_id = *packet_data_ptr++ << COAP_HEADER_MSG_ID_MSB_SHIFT; + dst_coap_msg_ptr->msg_id |= *packet_data_ptr++; + return packet_data_ptr; } /** @@ -250,13 +251,15 @@ static void sn_coap_parser_header_parse(uint8_t **packet_data_pptr, sn_coap_hdr_ * * \return Return value is value of uint */ -static uint32_t sn_coap_parser_options_parse_uint(uint8_t **packet_data_pptr, uint8_t option_len) +static uint32_t sn_coap_parser_options_parse_uint(const uint8_t * restrict * restrict packet_data_pptr, uint_fast8_t option_len) { uint32_t value = 0; + const uint8_t *packet_data_ptr = *packet_data_pptr; while (option_len--) { value <<= 8; - value |= *(*packet_data_pptr)++; + value |= *packet_data_ptr++; } + *packet_data_pptr = packet_data_ptr; return value; } @@ -267,15 +270,15 @@ static uint32_t sn_coap_parser_options_parse_uint(uint8_t **packet_data_pptr, ui * \param b second term of addion * \param result pointer to the result variable * - * \return Return 0 if there was no overflow, -1 otherwise + * \return Return 0 if there was no overflow, non-zero otherwise */ -static int8_t sn_coap_parser_add_u16_limit(uint16_t a, uint16_t b, uint16_t *result) +static int_fast8_t sn_coap_parser_add_u16_limit(uint_fast16_t a, uint_fast16_t b, uint_fast16_t *result) { uint16_t c; c = a + b; if (c < a || c < b) { - return -1; + return 1; } *result = c; @@ -291,19 +294,19 @@ static int8_t sn_coap_parser_add_u16_limit(uint16_t a, uint16_t b, uint16_t *res * \param packet_len total packet length * \param delta the number of bytes forward to check * - * \return Return 0 if the data is within the bounds, -1 otherwise + * \return Return 0 if the data is within the bounds, non-zero otherwise */ -static int8_t sn_coap_parser_check_packet_ptr(uint8_t *packet_data_ptr, uint8_t *packet_data_start_ptr, uint16_t packet_len, uint16_t delta) +static int_fast8_t sn_coap_parser_check_packet_ptr(const uint8_t *packet_data_ptr, const uint8_t *packet_data_start_ptr, uint_fast16_t packet_len, uint_fast16_t delta) { - uint8_t *packet_end = packet_data_start_ptr + packet_len; - uint8_t *new_data_ptr = packet_data_ptr + delta; + const uint8_t *packet_end = packet_data_start_ptr + packet_len; + const uint8_t *new_data_ptr = packet_data_ptr + delta; if (delta > packet_len) { - return -1; + return 1; } if (new_data_ptr < packet_data_start_ptr || new_data_ptr > packet_end) { - return -1; + return 1; } return 0; @@ -319,10 +322,10 @@ static int8_t sn_coap_parser_check_packet_ptr(uint8_t *packet_data_ptr, uint8_t * * \return Return The remaining packet data length */ -static uint16_t sn_coap_parser_move_packet_ptr(uint8_t **packet_data_pptr, uint8_t *packet_data_start_ptr, uint16_t packet_len, uint16_t delta) +static uint_fast16_t sn_coap_parser_move_packet_ptr(const uint8_t * restrict *packet_data_pptr, const uint8_t *packet_data_start_ptr, uint_fast16_t packet_len, uint_fast16_t delta) { - uint8_t *packet_end = packet_data_start_ptr + packet_len; - uint8_t *new_data_ptr = *packet_data_pptr + delta; + const uint8_t *packet_end = packet_data_start_ptr + packet_len; + const uint8_t *new_data_ptr = *packet_data_pptr + delta; if (new_data_ptr < packet_data_start_ptr) { return 0; @@ -333,7 +336,7 @@ static uint16_t sn_coap_parser_move_packet_ptr(uint8_t **packet_data_pptr, uint8 *packet_data_pptr = new_data_ptr; - return (uint16_t)(packet_end - new_data_ptr); + return (uint_fast16_t)(packet_end - new_data_ptr); } /** @@ -344,11 +347,11 @@ static uint16_t sn_coap_parser_move_packet_ptr(uint8_t **packet_data_pptr, uint8 * \param packet_data_start_ptr pointer to data packet start * \param packet_len total packet length * - * \return Return 0 if the data is within the bounds, -1 otherwise + * \return Return 0 if the data is within the bounds, non-zero otherwise */ -static int8_t sn_coap_parser_read_packet_u8(uint8_t *dst, uint8_t *packet_data_ptr, uint8_t *packet_data_start_ptr, uint16_t packet_len) +static int8_t sn_coap_parser_read_packet_u8(uint8_t *dst, const uint8_t *packet_data_ptr, const uint8_t *packet_data_start_ptr, uint_fast16_t packet_len) { - int8_t ptr_check_result; + int_fast8_t ptr_check_result; ptr_check_result = sn_coap_parser_check_packet_ptr(packet_data_ptr, packet_data_start_ptr, packet_len, 1); @@ -371,12 +374,12 @@ static int8_t sn_coap_parser_read_packet_u8(uint8_t *dst, uint8_t *packet_data_p * \param packet_data_start_ptr pointer to data packet start * \param packet_len total packet length * - * \return Return 0 if the data is within the bounds, -1 otherwise + * \return Return 0 if the data is within the bounds, non-zero otherwise */ -static int8_t sn_coap_parser_read_packet_u16(uint16_t *dst, uint8_t *packet_data_ptr, uint8_t *packet_data_start_ptr, uint16_t packet_len) +static int_fast8_t sn_coap_parser_read_packet_u16(uint_fast16_t *dst, const uint8_t *packet_data_ptr, const uint8_t *packet_data_start_ptr, uint16_t packet_len) { - int8_t ptr_check_result; - uint16_t value; + int_fast8_t ptr_check_result; + uint_fast16_t value; ptr_check_result = sn_coap_parser_check_packet_ptr(packet_data_ptr, packet_data_start_ptr, packet_len, 2); @@ -402,9 +405,9 @@ static int8_t sn_coap_parser_read_packet_u16(uint16_t *dst, uint8_t *packet_data * * \return Return 0 if the read was successful, -1 otherwise */ -static int8_t parse_ext_option(uint16_t *dst, uint8_t **packet_data_pptr, uint8_t *packet_data_start_ptr, uint16_t packet_len, uint16_t *message_left) +static int_fast8_t parse_ext_option(uint_fast16_t *dst, const uint8_t * restrict *packet_data_pptr, const uint8_t *packet_data_start_ptr, uint_fast16_t packet_len, uint_fast16_t *message_left) { - uint16_t option_number = *dst; + uint_fast16_t option_number = *dst; if (option_number == 13) { uint8_t option_ext; @@ -421,7 +424,7 @@ static int8_t parse_ext_option(uint16_t *dst, uint8_t **packet_data_pptr, uint8_ *message_left = sn_coap_parser_move_packet_ptr(packet_data_pptr, packet_data_start_ptr, packet_len, 1); } } else if (option_number == 14) { - int8_t read_result = sn_coap_parser_read_packet_u16(&option_number, *packet_data_pptr, packet_data_start_ptr, packet_len); + int_fast8_t read_result = sn_coap_parser_read_packet_u16(&option_number, *packet_data_pptr, packet_data_start_ptr, packet_len); if (read_result != 0) { /* packet_data_pptr would overflow! */ tr_error("sn_coap_parser_options_parse - **packet_data_pptr overflow !"); @@ -449,67 +452,68 @@ static int8_t parse_ext_option(uint16_t *dst, uint8_t **packet_data_pptr, uint8_ * * \brief Parses CoAP message's Options part from given Packet data * - * \param **packet_data_pptr is source of Packet data to be parsed to CoAP message + * \param *packet_data_ptr is source of Packet data to be parsed to CoAP message * \param *dst_coap_msg_ptr is destination for parsed CoAP message * - * \return Return value is 0 in ok case and -1 in failure case + * \return Return value is advanced input pointer in ok case and NULL in failure case */ -static int8_t sn_coap_parser_options_parse(struct coap_s *handle, uint8_t **packet_data_pptr, sn_coap_hdr_s *dst_coap_msg_ptr, uint8_t *packet_data_start_ptr, uint16_t packet_len) +static const uint8_t * sn_coap_parser_options_parse(const uint8_t * restrict packet_data_ptr, struct coap_s * restrict handle, sn_coap_hdr_s * restrict dst_coap_msg_ptr, const uint8_t *packet_data_start_ptr, uint_fast16_t packet_len) { - uint8_t previous_option_number = 0; - int8_t ret_status = 0; - uint16_t message_left = sn_coap_parser_move_packet_ptr(packet_data_pptr, packet_data_start_ptr, packet_len, 0); + uint_fast16_t previous_option_number = 0; + uint_fast16_t message_left = sn_coap_parser_move_packet_ptr(&packet_data_ptr, packet_data_start_ptr, packet_len, 0); /* Parse token, if exists */ dst_coap_msg_ptr->token_len = *packet_data_start_ptr & COAP_HEADER_TOKEN_LENGTH_MASK; if (dst_coap_msg_ptr->token_len) { - int8_t ptr_check_result; + int_fast8_t ptr_check_result; if ((dst_coap_msg_ptr->token_len > 8) || dst_coap_msg_ptr->token_ptr) { tr_error("sn_coap_parser_options_parse - token not valid!"); - return -1; + return NULL; } - ptr_check_result = sn_coap_parser_check_packet_ptr(*packet_data_pptr, packet_data_start_ptr, packet_len, dst_coap_msg_ptr->token_len); + ptr_check_result = sn_coap_parser_check_packet_ptr(packet_data_ptr, packet_data_start_ptr, packet_len, dst_coap_msg_ptr->token_len); if (0 != ptr_check_result) { - tr_error("sn_coap_parser_options_parse - **packet_data_pptr overflow !"); - return -1; + tr_error("sn_coap_parser_options_parse - *packet_data_ptr overflow !"); + return NULL; } - dst_coap_msg_ptr->token_ptr = sn_coap_protocol_malloc_copy(handle, *packet_data_pptr, dst_coap_msg_ptr->token_len); + dst_coap_msg_ptr->token_ptr = sn_coap_protocol_malloc_copy(handle, packet_data_ptr, dst_coap_msg_ptr->token_len); if (dst_coap_msg_ptr->token_ptr == NULL) { tr_error("sn_coap_parser_options_parse - failed to allocate token!"); - return -1; + return NULL; } - message_left = sn_coap_parser_move_packet_ptr(packet_data_pptr, packet_data_start_ptr, packet_len, dst_coap_msg_ptr->token_len); + message_left = sn_coap_parser_move_packet_ptr(&packet_data_ptr, packet_data_start_ptr, packet_len, dst_coap_msg_ptr->token_len); } + message_left = packet_len - (packet_data_ptr - packet_data_start_ptr); + /* Loop all Options */ - while (message_left && (**packet_data_pptr != 0xff)) { + uint_fast8_t option_byte; + while (message_left && ((option_byte = *packet_data_ptr) != 0xff)) { /* Get option length WITHOUT extensions */ - uint16_t option_len = (**packet_data_pptr & 0x0F); + uint_fast16_t option_len = (option_byte & 0x0F); /* Get option number WITHOUT extensions */ - uint16_t option_number = (**packet_data_pptr >> COAP_OPTIONS_OPTION_NUMBER_SHIFT); + uint_fast16_t option_number = (option_byte >> COAP_OPTIONS_OPTION_NUMBER_SHIFT); - message_left = sn_coap_parser_move_packet_ptr(packet_data_pptr, packet_data_start_ptr, packet_len, 1); - - int8_t option_parse_result; + message_left = sn_coap_parser_move_packet_ptr(&packet_data_ptr, packet_data_start_ptr, packet_len, 1); + int_fast8_t option_parse_result; /* Add possible option delta extension */ - option_parse_result = parse_ext_option(&option_number, packet_data_pptr, packet_data_start_ptr, packet_len, &message_left); + option_parse_result = parse_ext_option(&option_number, &packet_data_ptr, packet_data_start_ptr, packet_len, &message_left); if (option_parse_result != 0) { - return -1; + return NULL; } /* Add previous option to option delta and get option number */ if (sn_coap_parser_add_u16_limit(option_number, previous_option_number, &option_number) != 0) { - return -1; + return NULL; } /* Add possible option length extension to resolve full length of the option */ - option_parse_result = parse_ext_option(&option_len, packet_data_pptr, packet_data_start_ptr, packet_len, &message_left); + option_parse_result = parse_ext_option(&option_len, &packet_data_ptr, packet_data_start_ptr, packet_len, &message_left); if (option_parse_result != 0) { - return -1; + return NULL; } /* * * Parse option itself * * */ @@ -533,15 +537,15 @@ static int8_t sn_coap_parser_options_parse(struct coap_s *handle, uint8_t **pack case COAP_OPTION_SIZE2: if (sn_coap_parser_alloc_options(handle, dst_coap_msg_ptr) == NULL) { tr_error("sn_coap_parser_options_parse - failed to allocate options!"); - return -1; + return NULL; } break; } if (message_left < option_len){ - /* packet_data_pptr would overflow! */ - tr_error("sn_coap_parser_options_parse - **packet_data_pptr would overflow when parsing options!"); - return -1; + /* packet_data_ptr would overflow! */ + tr_error("sn_coap_parser_options_parse - *packet_data_ptr would overflow when parsing options!"); + return NULL; } /* Parse option */ @@ -549,100 +553,102 @@ static int8_t sn_coap_parser_options_parse(struct coap_s *handle, uint8_t **pack case COAP_OPTION_CONTENT_FORMAT: if ((option_len > 2) || (dst_coap_msg_ptr->content_format != COAP_CT_NONE)) { tr_error("sn_coap_parser_options_parse - COAP_OPTION_CONTENT_FORMAT not valid!"); - return -1; + return NULL; } - dst_coap_msg_ptr->content_format = (sn_coap_content_format_e) sn_coap_parser_options_parse_uint(packet_data_pptr, option_len); + dst_coap_msg_ptr->content_format = (sn_coap_content_format_e) sn_coap_parser_options_parse_uint(&packet_data_ptr, option_len); break; case COAP_OPTION_MAX_AGE: if (option_len > 4) { tr_error("sn_coap_parser_options_parse - COAP_OPTION_MAX_AGE not valid!"); - return -1; + return NULL; } - dst_coap_msg_ptr->options_list_ptr->max_age = sn_coap_parser_options_parse_uint(packet_data_pptr, option_len); + dst_coap_msg_ptr->options_list_ptr->max_age = sn_coap_parser_options_parse_uint(&packet_data_ptr, option_len); break; case COAP_OPTION_PROXY_URI: if ((option_len > 1034) || (option_len < 1) || dst_coap_msg_ptr->options_list_ptr->proxy_uri_ptr) { tr_error("sn_coap_parser_options_parse - COAP_OPTION_PROXY_URI not valid!"); - return -1; + return NULL; } dst_coap_msg_ptr->options_list_ptr->proxy_uri_len = option_len; - dst_coap_msg_ptr->options_list_ptr->proxy_uri_ptr = sn_coap_protocol_malloc_copy(handle, *packet_data_pptr, option_len); + dst_coap_msg_ptr->options_list_ptr->proxy_uri_ptr = sn_coap_protocol_malloc_copy(handle, packet_data_ptr, option_len); if (dst_coap_msg_ptr->options_list_ptr->proxy_uri_ptr == NULL) { tr_error("sn_coap_parser_options_parse - COAP_OPTION_PROXY_URI allocation failed!"); - return -1; + return NULL; } - message_left = sn_coap_parser_move_packet_ptr(packet_data_pptr, packet_data_start_ptr, packet_len, option_len); + message_left = sn_coap_parser_move_packet_ptr(&packet_data_ptr, packet_data_start_ptr, packet_len, option_len); break; case COAP_OPTION_ETAG: if (dst_coap_msg_ptr->options_list_ptr->etag_ptr) { tr_error("sn_coap_parser_options_parse - COAP_OPTION_ETAG exists!"); - return -1; + return NULL; } /* This is managed independently because User gives this option in one character table */ - ret_status = sn_coap_parser_options_parse_multiple_options(handle, packet_data_pptr, + uint16_t len; + packet_data_ptr = sn_coap_parser_options_parse_multiple_options(packet_data_ptr, handle, message_left, &dst_coap_msg_ptr->options_list_ptr->etag_ptr, - (uint16_t *)&dst_coap_msg_ptr->options_list_ptr->etag_len, + &len, COAP_OPTION_ETAG, option_len); - if (ret_status < 0) { + if (!packet_data_ptr) { tr_error("sn_coap_parser_options_parse - COAP_OPTION_ETAG not valid!"); - return -1; + return NULL; } + dst_coap_msg_ptr->options_list_ptr->etag_len = (uint8_t) len; break; case COAP_OPTION_URI_HOST: if ((option_len > 255) || (option_len < 1) || dst_coap_msg_ptr->options_list_ptr->uri_host_ptr) { tr_error("sn_coap_parser_options_parse - COAP_OPTION_URI_HOST not valid!"); - return -1; + return NULL; } dst_coap_msg_ptr->options_list_ptr->uri_host_len = option_len; - dst_coap_msg_ptr->options_list_ptr->uri_host_ptr = sn_coap_protocol_malloc_copy(handle, *packet_data_pptr, option_len); + dst_coap_msg_ptr->options_list_ptr->uri_host_ptr = sn_coap_protocol_malloc_copy(handle, packet_data_ptr, option_len); if (dst_coap_msg_ptr->options_list_ptr->uri_host_ptr == NULL) { tr_error("sn_coap_parser_options_parse - COAP_OPTION_URI_HOST allocation failed!"); - return -1; + return NULL; } - message_left = sn_coap_parser_move_packet_ptr(packet_data_pptr, packet_data_start_ptr, packet_len, option_len); + message_left = sn_coap_parser_move_packet_ptr(&packet_data_ptr, packet_data_start_ptr, packet_len, option_len); break; case COAP_OPTION_LOCATION_PATH: if (dst_coap_msg_ptr->options_list_ptr->location_path_ptr) { tr_error("sn_coap_parser_options_parse - COAP_OPTION_LOCATION_PATH exists!"); - return -1; + return NULL; } /* This is managed independently because User gives this option in one character table */ - ret_status = sn_coap_parser_options_parse_multiple_options(handle, packet_data_pptr, message_left, + packet_data_ptr = sn_coap_parser_options_parse_multiple_options(packet_data_ptr, handle, message_left, &dst_coap_msg_ptr->options_list_ptr->location_path_ptr, &dst_coap_msg_ptr->options_list_ptr->location_path_len, COAP_OPTION_LOCATION_PATH, option_len); - if (ret_status < 0) { + if (!packet_data_ptr) { tr_error("sn_coap_parser_options_parse - COAP_OPTION_LOCATION_PATH not valid!"); - return -1; + return NULL; } break; case COAP_OPTION_URI_PORT: if ((option_len > 2) || dst_coap_msg_ptr->options_list_ptr->uri_port != COAP_OPTION_URI_PORT_NONE) { tr_error("sn_coap_parser_options_parse - COAP_OPTION_URI_PORT not valid!"); - return -1; + return NULL; } - dst_coap_msg_ptr->options_list_ptr->uri_port = sn_coap_parser_options_parse_uint(packet_data_pptr, option_len); + dst_coap_msg_ptr->options_list_ptr->uri_port = sn_coap_parser_options_parse_uint(&packet_data_ptr, option_len); break; case COAP_OPTION_LOCATION_QUERY: if (dst_coap_msg_ptr->options_list_ptr->location_query_ptr) { tr_error("sn_coap_parser_options_parse - COAP_OPTION_LOCATION_QUERY exists!"); - return -1; + return NULL; } - ret_status = sn_coap_parser_options_parse_multiple_options(handle, packet_data_pptr, message_left, + packet_data_ptr = sn_coap_parser_options_parse_multiple_options(packet_data_ptr, handle, message_left, &dst_coap_msg_ptr->options_list_ptr->location_query_ptr, &dst_coap_msg_ptr->options_list_ptr->location_query_len, COAP_OPTION_LOCATION_QUERY, option_len); - if (ret_status < 0) { + if (!packet_data_ptr) { tr_error("sn_coap_parser_options_parse - COAP_OPTION_LOCATION_QUERY not valid!"); - return -1; + return NULL; } break; @@ -650,99 +656,99 @@ static int8_t sn_coap_parser_options_parse(struct coap_s *handle, uint8_t **pack case COAP_OPTION_URI_PATH: if (dst_coap_msg_ptr->uri_path_ptr) { tr_error("sn_coap_parser_options_parse - COAP_OPTION_URI_PATH exists!"); - return -1; + return NULL; } - ret_status = sn_coap_parser_options_parse_multiple_options(handle, packet_data_pptr, message_left, + packet_data_ptr = sn_coap_parser_options_parse_multiple_options(packet_data_ptr, handle, message_left, &dst_coap_msg_ptr->uri_path_ptr, &dst_coap_msg_ptr->uri_path_len, COAP_OPTION_URI_PATH, option_len); - if (ret_status < 0) { + if (!packet_data_ptr) { tr_error("sn_coap_parser_options_parse - COAP_OPTION_URI_PATH not valid!"); - return -1; + return NULL; } break; case COAP_OPTION_OBSERVE: if ((option_len > 2) || dst_coap_msg_ptr->options_list_ptr->observe != COAP_OBSERVE_NONE) { tr_error("sn_coap_parser_options_parse - COAP_OPTION_OBSERVE not valid!"); - return -1; + return NULL; } - dst_coap_msg_ptr->options_list_ptr->observe = sn_coap_parser_options_parse_uint(packet_data_pptr, option_len); + dst_coap_msg_ptr->options_list_ptr->observe = sn_coap_parser_options_parse_uint(&packet_data_ptr, option_len); break; case COAP_OPTION_URI_QUERY: - ret_status = sn_coap_parser_options_parse_multiple_options(handle, packet_data_pptr, message_left, + packet_data_ptr = sn_coap_parser_options_parse_multiple_options(packet_data_ptr, handle, message_left, &dst_coap_msg_ptr->options_list_ptr->uri_query_ptr, &dst_coap_msg_ptr->options_list_ptr->uri_query_len, COAP_OPTION_URI_QUERY, option_len); - if (ret_status < 0) { + if (!packet_data_ptr) { tr_error("sn_coap_parser_options_parse - COAP_OPTION_URI_QUERY not valid!"); - return -1; + return NULL; } break; case COAP_OPTION_BLOCK2: if ((option_len > 3) || dst_coap_msg_ptr->options_list_ptr->block2 != COAP_OPTION_BLOCK_NONE) { tr_error("sn_coap_parser_options_parse - COAP_OPTION_BLOCK2 not valid!"); - return -1; + return NULL; } - dst_coap_msg_ptr->options_list_ptr->block2 = sn_coap_parser_options_parse_uint(packet_data_pptr, option_len); + dst_coap_msg_ptr->options_list_ptr->block2 = sn_coap_parser_options_parse_uint(&packet_data_ptr, option_len); break; case COAP_OPTION_BLOCK1: if ((option_len > 3) || dst_coap_msg_ptr->options_list_ptr->block1 != COAP_OPTION_BLOCK_NONE) { tr_error("sn_coap_parser_options_parse - COAP_OPTION_BLOCK1 not valid!"); - return -1; + return NULL; } - dst_coap_msg_ptr->options_list_ptr->block1 = sn_coap_parser_options_parse_uint(packet_data_pptr, option_len); + dst_coap_msg_ptr->options_list_ptr->block1 = sn_coap_parser_options_parse_uint(&packet_data_ptr, option_len); break; case COAP_OPTION_ACCEPT: if ((option_len > 2) || (dst_coap_msg_ptr->options_list_ptr->accept != COAP_CT_NONE)) { tr_error("sn_coap_parser_options_parse - COAP_OPTION_ACCEPT not valid!"); - return -1; + return NULL; } - dst_coap_msg_ptr->options_list_ptr->accept = (sn_coap_content_format_e) sn_coap_parser_options_parse_uint(packet_data_pptr, option_len); + dst_coap_msg_ptr->options_list_ptr->accept = (sn_coap_content_format_e) sn_coap_parser_options_parse_uint(&packet_data_ptr, option_len); break; case COAP_OPTION_SIZE1: if ((option_len > 4) || dst_coap_msg_ptr->options_list_ptr->use_size1) { tr_error("sn_coap_parser_options_parse - COAP_OPTION_SIZE1 not valid!"); - return -1; + return NULL; } dst_coap_msg_ptr->options_list_ptr->use_size1 = true; - dst_coap_msg_ptr->options_list_ptr->size1 = sn_coap_parser_options_parse_uint(packet_data_pptr, option_len); + dst_coap_msg_ptr->options_list_ptr->size1 = sn_coap_parser_options_parse_uint(&packet_data_ptr, option_len); break; case COAP_OPTION_SIZE2: if ((option_len > 4) || dst_coap_msg_ptr->options_list_ptr->use_size2) { tr_error("sn_coap_parser_options_parse - COAP_OPTION_SIZE2 not valid!"); - return -1; + return NULL; } dst_coap_msg_ptr->options_list_ptr->use_size2 = true; - dst_coap_msg_ptr->options_list_ptr->size2 = sn_coap_parser_options_parse_uint(packet_data_pptr, option_len); + dst_coap_msg_ptr->options_list_ptr->size2 = sn_coap_parser_options_parse_uint(&packet_data_ptr, option_len); break; default: tr_error("sn_coap_parser_options_parse - unknown option!"); - return -1; + return NULL; } /* Check for overflow */ - if ((*packet_data_pptr - packet_data_start_ptr) > packet_len) { - return -1; + if ((packet_data_ptr - packet_data_start_ptr) > packet_len) { + return NULL; } - message_left = sn_coap_parser_move_packet_ptr(packet_data_pptr, packet_data_start_ptr, packet_len, 0); + message_left = packet_len - (packet_data_ptr - packet_data_start_ptr); } - return 0; + return packet_data_ptr; } /** - * \fn static int8_t sn_coap_parser_options_parse_multiple_options(uint8_t **packet_data_pptr, uint8_t options_count_left, uint8_t *previous_option_number_ptr, uint8_t **dst_pptr, + * \fn static int8_t sn_coap_parser_options_parse_multiple_options(uint8_t *packet_data_pptr, uint8_t options_count_left, uint8_t *previous_option_number_ptr, uint8_t **dst_pptr, * uint16_t *dst_len_ptr, sn_coap_option_numbers_e option, uint16_t option_number_len) * * \brief Parses CoAP message's Uri-query options * - * \param **packet_data_pptr is source for Packet data to be parsed to CoAP message + * \param *packet_data_ptr is source for Packet data to be parsed to CoAP message * * \param *dst_coap_msg_ptr is destination for parsed CoAP message * @@ -750,26 +756,27 @@ static int8_t sn_coap_parser_options_parse(struct coap_s *handle, uint8_t **pack * * \param *previous_option_number_ptr is pointer to used and returned previous Option number * - * \return Return value is count of Uri-query optios parsed. In failure case -1 is returned. + * \return Return value is advanced input pointer. In failure case NULL is returned. */ -static int8_t sn_coap_parser_options_parse_multiple_options(struct coap_s *handle, uint8_t **packet_data_pptr, uint16_t packet_left_len, uint8_t **dst_pptr, uint16_t *dst_len_ptr, sn_coap_option_numbers_e option, uint16_t option_number_len) +static const uint8_t *sn_coap_parser_options_parse_multiple_options(const uint8_t * restrict packet_data_ptr, struct coap_s * restrict handle, uint_fast16_t packet_left_len, uint8_t ** restrict dst_pptr, uint16_t * restrict dst_len_ptr, sn_coap_option_numbers_e option, uint_fast16_t option_number_len) { - int16_t uri_query_needed_heap = sn_coap_parser_options_count_needed_memory_multiple_option(*packet_data_pptr, packet_left_len, option, option_number_len); - uint8_t *temp_parsed_uri_query_ptr = NULL; - uint8_t returned_option_counter = 0; - uint8_t *start_ptr = *packet_data_pptr; - uint16_t message_left = packet_left_len; + + int uri_query_needed_heap = sn_coap_parser_options_count_needed_memory_multiple_option(packet_data_ptr, packet_left_len, option, option_number_len); + uint8_t * restrict temp_parsed_uri_query_ptr = NULL; + const uint8_t *start_ptr = packet_data_ptr; + uint_fast16_t message_left = packet_left_len; + bool first_option = true; if (uri_query_needed_heap == -1) { - return -1; + return NULL; } if (uri_query_needed_heap) { - *dst_pptr = (uint8_t *) handle->sn_coap_protocol_malloc(uri_query_needed_heap); + *dst_pptr = handle->sn_coap_protocol_malloc(uri_query_needed_heap); if (*dst_pptr == NULL) { tr_error("sn_coap_parser_options_parse_multiple_options - failed to allocate options!"); - return -1; + return NULL; } } @@ -779,7 +786,7 @@ static int8_t sn_coap_parser_options_parse_multiple_options(struct coap_s *handl /* Loop all Uri-Query options */ while ((temp_parsed_uri_query_ptr - *dst_pptr) < uri_query_needed_heap && message_left) { /* Check if this is first Uri-Query option */ - if (returned_option_counter > 0) { + if (!first_option) { /* Uri-Query is modified to following format: temp1'\0'temp2'\0'temp3 i.e. */ /* Uri-Path is modified to following format: temp1\temp2\temp3 i.e. */ if (option == COAP_OPTION_URI_QUERY || option == COAP_OPTION_LOCATION_QUERY || option == COAP_OPTION_ETAG || option == COAP_OPTION_ACCEPT) { @@ -789,43 +796,42 @@ static int8_t sn_coap_parser_options_parse_multiple_options(struct coap_s *handl } temp_parsed_uri_query_ptr++; + } else { + first_option = false; } - returned_option_counter++; - if (((temp_parsed_uri_query_ptr - *dst_pptr) + option_number_len) > uri_query_needed_heap) { - return -1; + return NULL; } - - if (0 != sn_coap_parser_check_packet_ptr(*packet_data_pptr, start_ptr, packet_left_len, option_number_len)) { + if (0 != sn_coap_parser_check_packet_ptr(packet_data_ptr, start_ptr, packet_left_len, option_number_len)) { /* Buffer read overflow. */ - return -1; + return NULL; } /* Copy the option value to URI query buffer */ - memcpy(temp_parsed_uri_query_ptr, *packet_data_pptr, option_number_len); + memcpy(temp_parsed_uri_query_ptr, packet_data_ptr, option_number_len); - message_left = sn_coap_parser_move_packet_ptr(packet_data_pptr, start_ptr, packet_left_len, option_number_len); + message_left = sn_coap_parser_move_packet_ptr(&packet_data_ptr, start_ptr, packet_left_len, option_number_len); temp_parsed_uri_query_ptr += option_number_len; /* Check if there is more input to process */ - if (message_left == 0 || ((**packet_data_pptr >> COAP_OPTIONS_OPTION_NUMBER_SHIFT) != 0)) { - return returned_option_counter; + if (message_left == 0 || ((*packet_data_ptr >> COAP_OPTIONS_OPTION_NUMBER_SHIFT) != 0)) { + return packet_data_ptr; } /* Process next option */ - option_number_len = (**packet_data_pptr & 0x0F); - message_left = sn_coap_parser_move_packet_ptr(packet_data_pptr, start_ptr, packet_left_len, 1); + option_number_len = (*packet_data_ptr & 0x0F); + message_left = sn_coap_parser_move_packet_ptr(&packet_data_ptr, start_ptr, packet_left_len, 1); /* Add possible option length extension to resolve full length of the option */ - int8_t option_parse_result = parse_ext_option(&option_number_len, packet_data_pptr, start_ptr, packet_left_len, &message_left); + int_fast8_t option_parse_result = parse_ext_option(&option_number_len, &packet_data_ptr, start_ptr, packet_left_len, &message_left); if (option_parse_result != 0) { /* Extended option parsing failed. */ - return -1; + return NULL; } } - return returned_option_counter; + return packet_data_ptr; } /** @@ -843,11 +849,11 @@ static int8_t sn_coap_parser_options_parse_multiple_options(struct coap_s *handl * * \param uint16_t option_number_len length of the first option part */ -static int16_t sn_coap_parser_options_count_needed_memory_multiple_option(uint8_t *packet_data_ptr, uint16_t packet_left_len, sn_coap_option_numbers_e option, uint16_t option_number_len) +static int sn_coap_parser_options_count_needed_memory_multiple_option(const uint8_t * restrict packet_data_ptr, uint_fast16_t packet_left_len, sn_coap_option_numbers_e option, uint_fast16_t option_number_len) { - uint16_t ret_value = 0; - uint16_t message_left = packet_left_len; - uint8_t *start_ptr = packet_data_ptr; + int ret_value = 0; + uint_fast16_t message_left = packet_left_len; + const uint8_t *start_ptr = packet_data_ptr; /* Loop all Uri-Query options */ while (message_left > 0) { @@ -871,7 +877,7 @@ static int16_t sn_coap_parser_options_count_needed_memory_multiple_option(uint8_ } /* Check if the value length is within buffer limits */ - int8_t ptr_check_result = sn_coap_parser_check_packet_ptr(packet_data_ptr, start_ptr, packet_left_len, option_number_len); + int_fast8_t ptr_check_result = sn_coap_parser_check_packet_ptr(packet_data_ptr, start_ptr, packet_left_len, option_number_len); if (ptr_check_result != 0) { return -1; } @@ -896,7 +902,7 @@ static int16_t sn_coap_parser_options_count_needed_memory_multiple_option(uint8_ message_left = sn_coap_parser_move_packet_ptr(&packet_data_ptr, start_ptr, packet_left_len, 1); /* Add possible option length extension to resolve full length of the option */ - int8_t option_parse_result = parse_ext_option(&option_number_len, &packet_data_ptr, start_ptr, packet_left_len, &message_left); + int_fast8_t option_parse_result = parse_ext_option(&option_number_len, &packet_data_ptr, start_ptr, packet_left_len, &message_left); if (option_parse_result != 0) { return -1; } @@ -922,29 +928,29 @@ static int16_t sn_coap_parser_options_count_needed_memory_multiple_option(uint8_ * * \param *dst_coap_msg_ptr is destination for parsed CoAP message *****************************************************************************/ -static int8_t sn_coap_parser_payload_parse(uint16_t packet_data_len, uint8_t *packet_data_start_ptr, uint8_t **packet_data_pptr, sn_coap_hdr_s *dst_coap_msg_ptr) +static const uint8_t *sn_coap_parser_payload_parse(const uint8_t * restrict packet_data_ptr, uint16_t packet_data_len, uint8_t *packet_data_start_ptr, sn_coap_hdr_s * restrict dst_coap_msg_ptr) { /* If there is payload */ - if ((*packet_data_pptr - packet_data_start_ptr) < packet_data_len) { - if (**packet_data_pptr == 0xff) { - (*packet_data_pptr)++; + if ((packet_data_ptr - packet_data_start_ptr) < packet_data_len) { + if (*packet_data_ptr == 0xff) { + packet_data_ptr++; /* Parse Payload length */ - dst_coap_msg_ptr->payload_len = packet_data_len - (*packet_data_pptr - packet_data_start_ptr); + dst_coap_msg_ptr->payload_len = packet_data_len - (packet_data_ptr - packet_data_start_ptr); /* The presence of a marker followed by a zero-length payload MUST be processed as a message format error */ if (dst_coap_msg_ptr->payload_len == 0) { - return -1; + return NULL; } /* Parse Payload by setting CoAP message's payload_ptr to point Payload in Packet data */ - dst_coap_msg_ptr->payload_ptr = *packet_data_pptr; + dst_coap_msg_ptr->payload_ptr = (uint8_t *) packet_data_ptr; } /* No payload marker.. */ else { tr_error("sn_coap_parser_payload_parse - payload marker not found!"); - return -1; + return NULL; } } - return 0; + return packet_data_ptr; } diff --git a/mbed-coap/source/sn_coap_protocol.c b/mbed-coap/source/sn_coap_protocol.c index 855bfb928..5f6f68c96 100644 --- a/mbed-coap/source/sn_coap_protocol.c +++ b/mbed-coap/source/sn_coap_protocol.c @@ -52,8 +52,8 @@ static void sn_coap_protocol_linked_list_duplication_info_store static coap_duplication_info_s *sn_coap_protocol_linked_list_duplication_info_search(const struct coap_s *handle, const sn_nsdl_addr_s *scr_addr_ptr, const uint16_t msg_id); static void sn_coap_protocol_linked_list_duplication_info_remove_old_ones(struct coap_s *handle); static void sn_coap_protocol_duplication_info_free(struct coap_s *handle, coap_duplication_info_s *duplication_info_ptr); -static bool sn_coap_protocol_update_duplicate_package_data(const struct coap_s *handle, const sn_nsdl_addr_s *dst_addr_ptr, const sn_coap_hdr_s *coap_msg_ptr, const int16_t data_size, const uint8_t *dst_packet_data_ptr); -static bool sn_coap_protocol_update_duplicate_package_data_all(const struct coap_s *handle, const sn_nsdl_addr_s *dst_addr_ptr, const sn_coap_hdr_s *coap_msg_ptr, const int16_t data_size, const uint8_t *dst_packet_data_ptr); +static bool sn_coap_protocol_update_duplicate_package_data(const struct coap_s *handle, const sn_nsdl_addr_s *dst_addr_ptr, const sn_coap_hdr_s *coap_msg_ptr, const int_fast16_t data_size, const uint8_t *dst_packet_data_ptr); +static bool sn_coap_protocol_update_duplicate_package_data_all(const struct coap_s *handle, const sn_nsdl_addr_s *dst_addr_ptr, const sn_coap_hdr_s *coap_msg_ptr, const int_fast16_t data_size, const uint8_t *dst_packet_data_ptr); #endif @@ -65,8 +65,8 @@ static coap_blockwise_payload_s *sn_coap_protocol_linked_list_blockwise_search(s static bool sn_coap_protocol_linked_list_blockwise_payload_search_compare_block_number(struct coap_s *handle, const sn_nsdl_addr_s *src_addr_ptr, const uint8_t *token_ptr, uint8_t token_len, uint32_t block_number); static void sn_coap_protocol_linked_list_blockwise_payload_remove(struct coap_s *handle, coap_blockwise_payload_s *removed_payload_ptr); static uint32_t sn_coap_protocol_linked_list_blockwise_payloads_get_len(struct coap_s *handle, const sn_nsdl_addr_s *src_addr_ptr, const uint8_t *token_ptr, uint8_t token_len); -static void sn_coap_protocol_handle_blockwise_timout(struct coap_s *handle); -static sn_coap_hdr_s *sn_coap_handle_blockwise_message(struct coap_s *handle, sn_nsdl_addr_s *src_addr_ptr, sn_coap_hdr_s *received_coap_msg_ptr, void *param); +static void sn_coap_protocol_handle_blockwise_timeout(struct coap_s *handle); +static sn_coap_hdr_s *sn_coap_handle_blockwise_message(struct coap_s *handle, sn_nsdl_addr_s *src_addr_ptr, sn_coap_hdr_s *received_coap_msg_ptr, void *param, bool *keep_in_resend_queue); static bool sn_coap_handle_last_blockwise(struct coap_s *handle, const sn_nsdl_addr_s *src_addr_ptr, sn_coap_hdr_s *received_coap_msg_ptr); static sn_coap_hdr_s *sn_coap_protocol_copy_header(struct coap_s *handle, const sn_coap_hdr_s *source_header_ptr); static coap_blockwise_msg_s *search_sent_blockwise_message(struct coap_s *handle, uint16_t msg_id); @@ -74,18 +74,18 @@ static int16_t store_blockwise_copy(struct coap_s *handle, cons #endif #if ENABLE_RESENDINGS -static uint8_t sn_coap_protocol_linked_list_send_msg_store(struct coap_s *handle, sn_nsdl_addr_s *dst_addr_ptr, uint16_t send_packet_data_len, uint8_t *send_packet_data_ptr, uint32_t sending_time, void *param); +static uint8_t sn_coap_protocol_linked_list_send_msg_store(struct coap_s *handle, sn_nsdl_addr_s *dst_addr_ptr, uint_fast16_t send_packet_data_len, uint8_t *send_packet_data_ptr, uint32_t sending_time, void *param); static void sn_coap_protocol_linked_list_send_msg_remove(struct coap_s *handle, const sn_nsdl_addr_s *src_addr_ptr, uint16_t msg_id); -static coap_send_msg_s *sn_coap_protocol_allocate_mem_for_msg(struct coap_s *handle, sn_nsdl_addr_s *dst_addr_ptr, uint16_t packet_data_len); +static coap_send_msg_s *sn_coap_protocol_allocate_mem_for_msg(struct coap_s *handle, sn_nsdl_addr_s *dst_addr_ptr, uint_fast16_t packet_data_len); static void sn_coap_protocol_release_allocated_send_msg_mem(struct coap_s *handle, coap_send_msg_s *freed_send_msg_ptr); -static uint16_t sn_coap_count_linked_list_size(const coap_send_msg_list_t *linked_list_ptr); +static uint_fast16_t sn_coap_count_linked_list_size(const coap_send_msg_list_t *linked_list_ptr); static uint32_t sn_coap_calculate_new_resend_time(const uint32_t current_time, const uint8_t interval, const uint8_t counter); #endif static uint16_t read_packet_msg_id(const coap_send_msg_s *stored_msg); static uint16_t get_new_message_id(void); -static bool compare_port(const sn_nsdl_addr_s* left, const sn_nsdl_addr_s* right); +static bool compare_port(const sn_nsdl_addr_s *left, const sn_nsdl_addr_s *right); /* * * * * * * * * * * * * * * * * */ /* * * * GLOBAL DECLARATIONS * * * */ @@ -202,19 +202,9 @@ int8_t sn_coap_protocol_set_block_size(struct coap_s *handle, uint16_t block_siz if (handle == NULL) { return -1; } - switch (block_size) { - case 0: - case 16: - case 32: - case 64: - case 128: - case 256: - case 512: - case 1024: - handle->sn_coap_block_data_size = block_size; - return 0; - default: - break; + if (sn_coap_convert_block_size(block_size) >= 0) { + handle->sn_coap_block_data_size = block_size; + return 0; } #endif return -1; @@ -268,7 +258,7 @@ int8_t sn_coap_protocol_set_duplicate_buffer_size(struct coap_s *handle, uint8_t } int8_t sn_coap_protocol_set_retransmission_parameters(struct coap_s *handle, - uint8_t resending_count, uint8_t resending_intervall) + uint8_t resending_count, uint8_t resending_intervall) { #if ENABLE_RESENDINGS if (handle == NULL) { @@ -290,14 +280,14 @@ int8_t sn_coap_protocol_set_retransmission_parameters(struct coap_s *handle, } int8_t sn_coap_protocol_set_retransmission_buffer(struct coap_s *handle, - uint8_t buffer_size_messages, uint16_t buffer_size_bytes) + uint8_t buffer_size_messages, uint16_t buffer_size_bytes) { #if ENABLE_RESENDINGS if (handle == NULL) { return -1; } if (buffer_size_bytes <= SN_COAP_MAX_ALLOWED_RESENDING_BUFF_SIZE_BYTES && - buffer_size_messages <= SN_COAP_MAX_ALLOWED_RESENDING_BUFF_SIZE_MSGS ) { + buffer_size_messages <= SN_COAP_MAX_ALLOWED_RESENDING_BUFF_SIZE_MSGS) { handle->sn_coap_resending_queue_bytes = buffer_size_bytes; handle->sn_coap_resending_queue_msgs = buffer_size_messages; return 0; @@ -317,8 +307,8 @@ void sn_coap_protocol_clear_retransmission_buffer(struct coap_s *handle) ns_list_foreach_safe(coap_send_msg_s, tmp, &handle->linked_list_resent_msgs) { ns_list_remove(&handle->linked_list_resent_msgs, tmp); sn_coap_protocol_release_allocated_send_msg_mem(handle, tmp); - --handle->count_resent_msgs; } + handle->count_resent_msgs = 0; #endif } @@ -352,7 +342,7 @@ int8_t sn_coap_protocol_delete_retransmission_by_token(struct coap_s *handle, co } ns_list_foreach(coap_send_msg_s, stored_msg, &handle->linked_list_resent_msgs) { - uint8_t stored_token_len = (stored_msg->send_msg_ptr.packet_ptr[0] & 0x0F); + uint8_t stored_token_len = (stored_msg->send_msg_ptr.packet_ptr[0] & 0x0F); if (stored_token_len == token_len) { if (memcmp(&stored_msg->send_msg_ptr.packet_ptr[4], token, stored_token_len) == 0) { @@ -384,8 +374,8 @@ int8_t prepare_blockwise_message(struct coap_s *handle, sn_coap_hdr_s *src_coap_ #if SN_COAP_BLOCKWISE_ENABLED || SN_COAP_MAX_BLOCKWISE_PAYLOAD_SIZE /* If Message blockwising is not enabled, this part of code will not be compiled */ if ((src_coap_msg_ptr->payload_len > SN_COAP_MAX_NONBLOCKWISE_PAYLOAD_SIZE) && - (src_coap_msg_ptr->payload_len > handle->sn_coap_block_data_size) && - (handle->sn_coap_block_data_size > 0)) { + (src_coap_msg_ptr->payload_len > handle->sn_coap_block_data_size) && + (handle->sn_coap_block_data_size > 0)) { /* * * * Add Blockwise option to send CoAP message * * */ /* Allocate memory for less used options */ @@ -448,8 +438,8 @@ int16_t sn_coap_protocol_build(struct coap_s *handle, sn_nsdl_addr_s *dst_addr_p #if SN_COAP_BLOCKWISE_ENABLED || SN_COAP_MAX_BLOCKWISE_PAYLOAD_SIZE /* If Message blockwising is not enabled, this part of code will not be compiled */ /* If blockwising needed */ if ((src_coap_msg_ptr->payload_len > SN_COAP_MAX_NONBLOCKWISE_PAYLOAD_SIZE) && - (src_coap_msg_ptr->payload_len > handle->sn_coap_block_data_size) && - (handle->sn_coap_block_data_size > 0)) { + (src_coap_msg_ptr->payload_len > handle->sn_coap_block_data_size) && + (handle->sn_coap_block_data_size > 0)) { /* Store original Payload length */ original_payload_len = src_coap_msg_ptr->payload_len; /* Change Payload length of send message because Payload is blockwised */ @@ -474,8 +464,8 @@ int16_t sn_coap_protocol_build(struct coap_s *handle, sn_nsdl_addr_s *dst_addr_p /* Store message to Linked list for resending purposes */ uint32_t resend_time = sn_coap_calculate_new_resend_time(handle->system_time, handle->sn_coap_resending_intervall, 0); if (sn_coap_protocol_linked_list_send_msg_store(handle, dst_addr_ptr, byte_count_built, dst_packet_data_ptr, - resend_time, - param) == 0) { + resend_time, + param) == 0) { return -4; } } @@ -523,7 +513,7 @@ int16_t sn_coap_protocol_build(struct coap_s *handle, sn_nsdl_addr_s *dst_addr_p #if SN_COAP_BLOCKWISE_ENABLED || SN_COAP_MAX_BLOCKWISE_PAYLOAD_SIZE static int16_t store_blockwise_copy(struct coap_s *handle, const sn_coap_hdr_s *src_coap_msg_ptr, void *param, uint16_t original_payload_len, bool copy_payload) { - coap_blockwise_msg_s *stored_blockwise_msg_ptr; + coap_blockwise_msg_s *restrict stored_blockwise_msg_ptr; stored_blockwise_msg_ptr = sn_coap_protocol_calloc(handle, sizeof(coap_blockwise_msg_s)); if (!stored_blockwise_msg_ptr) { @@ -535,20 +525,21 @@ static int16_t store_blockwise_copy(struct coap_s *handle, const sn_coap_hdr_s * /* Fill struct */ stored_blockwise_msg_ptr->timestamp = handle->system_time; - stored_blockwise_msg_ptr->coap_msg_ptr = sn_coap_protocol_copy_header(handle, src_coap_msg_ptr); - if( stored_blockwise_msg_ptr->coap_msg_ptr == NULL ){ + sn_coap_hdr_s *restrict copied_msg_ptr = sn_coap_protocol_copy_header(handle, src_coap_msg_ptr); + if (copied_msg_ptr == NULL) { handle->sn_coap_protocol_free(stored_blockwise_msg_ptr); tr_error("sn_coap_protocol_build - block header copy failed!"); return -2; } + stored_blockwise_msg_ptr->coap_msg_ptr = copied_msg_ptr; if (copy_payload) { - stored_blockwise_msg_ptr->coap_msg_ptr->payload_len = original_payload_len; - stored_blockwise_msg_ptr->coap_msg_ptr->payload_ptr = sn_coap_protocol_malloc_copy(handle, src_coap_msg_ptr->payload_ptr, stored_blockwise_msg_ptr->coap_msg_ptr->payload_len); + copied_msg_ptr->payload_len = original_payload_len; + copied_msg_ptr->payload_ptr = sn_coap_protocol_malloc_copy(handle, src_coap_msg_ptr->payload_ptr, stored_blockwise_msg_ptr->coap_msg_ptr->payload_len); - if (!stored_blockwise_msg_ptr->coap_msg_ptr->payload_ptr) { + if (!copied_msg_ptr->payload_ptr) { //block payload save failed, only first block can be build. Perhaps we should return error. - sn_coap_parser_release_allocated_coap_msg_mem(handle, stored_blockwise_msg_ptr->coap_msg_ptr); + sn_coap_parser_release_allocated_coap_msg_mem(handle, copied_msg_ptr); handle->sn_coap_protocol_free(stored_blockwise_msg_ptr); tr_error("sn_coap_protocol_build - block payload allocation failed!"); return -2; @@ -556,7 +547,7 @@ static int16_t store_blockwise_copy(struct coap_s *handle, const sn_coap_hdr_s * } stored_blockwise_msg_ptr->param = param; - stored_blockwise_msg_ptr->msg_id = stored_blockwise_msg_ptr->coap_msg_ptr->msg_id; + stored_blockwise_msg_ptr->msg_id = copied_msg_ptr->msg_id; ns_list_add_to_end(&handle->linked_list_blockwise_sent_msgs, stored_blockwise_msg_ptr); @@ -564,19 +555,18 @@ static int16_t store_blockwise_copy(struct coap_s *handle, const sn_coap_hdr_s * } #endif -sn_coap_hdr_s *sn_coap_protocol_parse(struct coap_s *handle, sn_nsdl_addr_s *src_addr_ptr, uint16_t packet_data_len, uint8_t *packet_data_ptr, void *param) +sn_coap_hdr_s *sn_coap_protocol_parse(struct coap_s *restrict handle, sn_nsdl_addr_s *restrict src_addr_ptr, uint16_t packet_data_len, uint8_t *restrict packet_data_ptr, void *param) { - sn_coap_hdr_s *returned_dst_coap_msg_ptr = NULL; coap_version_e coap_version = COAP_VERSION_UNKNOWN; /* * * * Check given pointer * * * */ if (src_addr_ptr == NULL || src_addr_ptr->addr_ptr == NULL || - packet_data_ptr == NULL || handle == NULL) { + packet_data_ptr == NULL || handle == NULL) { return NULL; } /* * * * Parse Packet data to CoAP message by using CoAP Header parser * * * */ - returned_dst_coap_msg_ptr = sn_coap_parser(handle, packet_data_len, packet_data_ptr, &coap_version); + sn_coap_hdr_s *restrict returned_dst_coap_msg_ptr = sn_coap_parser(handle, packet_data_len, packet_data_ptr, &coap_version); /* Check status of returned pointer */ if (returned_dst_coap_msg_ptr == NULL) { @@ -651,12 +641,10 @@ sn_coap_hdr_s *sn_coap_protocol_parse(struct coap_s *handle, sn_nsdl_addr_s *src // If no message duplication detected if ((returned_dst_coap_msg_ptr->msg_type == COAP_MSG_TYPE_CONFIRMABLE || - returned_dst_coap_msg_ptr->msg_type == COAP_MSG_TYPE_NON_CONFIRMABLE || - (returned_dst_coap_msg_ptr->msg_type == COAP_MSG_TYPE_ACKNOWLEDGEMENT && - returned_dst_coap_msg_ptr->msg_code != COAP_MSG_CODE_EMPTY)) && - handle->sn_coap_duplication_buffer_size != 0) { + returned_dst_coap_msg_ptr->msg_type == COAP_MSG_TYPE_NON_CONFIRMABLE) && + handle->sn_coap_duplication_buffer_size != 0) { - coap_duplication_info_s* response = sn_coap_protocol_linked_list_duplication_info_search(handle, + coap_duplication_info_s *response = sn_coap_protocol_linked_list_duplication_info_search(handle, src_addr_ptr, returned_dst_coap_msg_ptr->msg_id); if (response == NULL) { @@ -686,12 +674,12 @@ sn_coap_hdr_s *sn_coap_protocol_parse(struct coap_s *handle, sn_nsdl_addr_s *src returned_dst_coap_msg_ptr->coap_status = COAP_STATUS_PARSER_DUPLICATED_MSG; // Send ACK response - if (response && returned_dst_coap_msg_ptr->msg_type != COAP_MSG_TYPE_ACKNOWLEDGEMENT) { + if (response) { // Check that response has been created if (response->packet_ptr) { tr_debug("sn_coap_protocol_parse - send ack for duplicate message"); handle->sn_coap_tx_callback(response->packet_ptr, - response->packet_len, response->address, response->param); + response->packet_len, response->address, response->param); } else { tr_error("sn_coap_protocol_parse - response not yet build"); } @@ -705,15 +693,15 @@ sn_coap_hdr_s *sn_coap_protocol_parse(struct coap_s *handle, sn_nsdl_addr_s *src /*** And here we check if message was block message ***/ /*** If so, we call own block handling function and ***/ /*** return to caller. ***/ - + bool keep_in_resend_queue = false; #if SN_COAP_BLOCKWISE_ENABLED || SN_COAP_MAX_BLOCKWISE_PAYLOAD_SIZE if (returned_dst_coap_msg_ptr->options_list_ptr != NULL && - (returned_dst_coap_msg_ptr->options_list_ptr->block1 != COAP_OPTION_BLOCK_NONE || - returned_dst_coap_msg_ptr->options_list_ptr->block2 != COAP_OPTION_BLOCK_NONE)) { + (returned_dst_coap_msg_ptr->options_list_ptr->block1 != COAP_OPTION_BLOCK_NONE || + returned_dst_coap_msg_ptr->options_list_ptr->block2 != COAP_OPTION_BLOCK_NONE)) { // the sn_coap_handle_blockwise_message() will return the given message on success or NULL on error - if (sn_coap_handle_blockwise_message(handle, src_addr_ptr, returned_dst_coap_msg_ptr, param) == NULL) { + if (sn_coap_handle_blockwise_message(handle, src_addr_ptr, returned_dst_coap_msg_ptr, param, &keep_in_resend_queue) == NULL) { tr_error("sn_coap_protocol_parse - handle blockwise returns null!"); @@ -794,22 +782,22 @@ sn_coap_hdr_s *sn_coap_protocol_parse(struct coap_s *handle, sn_nsdl_addr_s *src /* Get ... */ coap_blockwise_msg_s *stored_blockwise_msg_temp_ptr = search_sent_blockwise_message(handle, returned_dst_coap_msg_ptr->msg_id); - /* Remove from the list if not an notification message. + /* Remove from the list if not a notification message. * Initial notification message is needed for sending rest of the blocks (GET request). */ - bool remove_from_the_list = false; if (stored_blockwise_msg_temp_ptr) { + bool remove_from_the_list; if (stored_blockwise_msg_temp_ptr->coap_msg_ptr && - stored_blockwise_msg_temp_ptr->coap_msg_ptr->options_list_ptr && - stored_blockwise_msg_temp_ptr->coap_msg_ptr->options_list_ptr->observe != COAP_OBSERVE_NONE) { + stored_blockwise_msg_temp_ptr->coap_msg_ptr->options_list_ptr && + stored_blockwise_msg_temp_ptr->coap_msg_ptr->options_list_ptr->observe != COAP_OBSERVE_NONE) { remove_from_the_list = false; } else { remove_from_the_list = true; } - } - if (remove_from_the_list) { - sn_coap_protocol_linked_list_blockwise_msg_remove(handle, stored_blockwise_msg_temp_ptr); + if (remove_from_the_list) { + sn_coap_protocol_linked_list_blockwise_msg_remove(handle, stored_blockwise_msg_temp_ptr); + } } } @@ -830,7 +818,7 @@ sn_coap_hdr_s *sn_coap_protocol_parse(struct coap_s *handle, sn_nsdl_addr_s *src /* Get node count i.e. count of active resending messages */ uint16_t stored_resending_msgs_count = handle->count_resent_msgs; /* Check if there is ongoing active message resendings */ - if (stored_resending_msgs_count > 0) { + if (stored_resending_msgs_count > 0 && !keep_in_resend_queue) { /* Remove resending message from active message resending Linked list, if any exists */ sn_coap_protocol_linked_list_send_msg_remove(handle, src_addr_ptr, returned_dst_coap_msg_ptr->msg_id); } @@ -844,8 +832,8 @@ sn_coap_hdr_s *sn_coap_protocol_parse(struct coap_s *handle, sn_nsdl_addr_s *src int8_t sn_coap_protocol_exec(struct coap_s *handle, uint32_t current_time) { - if( !handle ){ - return -1; + if (!handle) { + return -1; } /* * * * Store current System time * * * */ @@ -853,7 +841,7 @@ int8_t sn_coap_protocol_exec(struct coap_s *handle, uint32_t current_time) #if SN_COAP_BLOCKWISE_ENABLED || SN_COAP_MAX_BLOCKWISE_PAYLOAD_SIZE /* * * * Handle block transfer timed outs * * * */ - sn_coap_protocol_handle_blockwise_timout(handle); + sn_coap_protocol_handle_blockwise_timeout(handle); #endif #if SN_COAP_DUPLICATION_MAX_MSGS_COUNT @@ -888,6 +876,9 @@ int8_t sn_coap_protocol_exec(struct coap_s *handle, uint32_t current_time) tmp_coap_hdr_ptr = sn_coap_parser(handle, stored_msg_ptr->send_msg_ptr.packet_len, stored_msg_ptr->send_msg_ptr.packet_ptr, &coap_version); if (tmp_coap_hdr_ptr != 0) { +#if SN_COAP_BLOCKWISE_ENABLED || SN_COAP_MAX_BLOCKWISE_PAYLOAD_SIZE + sn_coap_protocol_remove_sent_blockwise_message(handle, tmp_coap_hdr_ptr->msg_id); +#endif // SN_COAP_BLOCKWISE_ENABLED || SN_COAP_MAX_BLOCKWISE_PAYLOAD_SIZE tmp_coap_hdr_ptr->coap_status = COAP_STATUS_BUILDER_MESSAGE_SENDING_FAILED; handle->sn_coap_rx_callback(tmp_coap_hdr_ptr, &stored_msg_ptr->send_msg_ptr.dst_addr_ptr, stored_msg_ptr->param); @@ -900,7 +891,7 @@ int8_t sn_coap_protocol_exec(struct coap_s *handle, uint32_t current_time) } else { /* Send message */ handle->sn_coap_tx_callback(stored_msg_ptr->send_msg_ptr.packet_ptr, - stored_msg_ptr->send_msg_ptr.packet_len, &stored_msg_ptr->send_msg_ptr.dst_addr_ptr, stored_msg_ptr->param); + stored_msg_ptr->send_msg_ptr.packet_len, &stored_msg_ptr->send_msg_ptr.dst_addr_ptr, stored_msg_ptr->param); /* * * Count new Resending time * * */ stored_msg_ptr->resending_time = sn_coap_calculate_new_resend_time(current_time, @@ -938,11 +929,11 @@ int8_t sn_coap_protocol_exec(struct coap_s *handle, uint32_t current_time) * \return 1 Msg stored properly *****************************************************************************/ -static uint8_t sn_coap_protocol_linked_list_send_msg_store(struct coap_s *handle, sn_nsdl_addr_s *dst_addr_ptr, uint16_t send_packet_data_len, - uint8_t *send_packet_data_ptr, uint32_t sending_time, void *param) +static uint8_t sn_coap_protocol_linked_list_send_msg_store(struct coap_s *restrict handle, sn_nsdl_addr_s *restrict dst_addr_ptr, uint_fast16_t send_packet_data_len, + uint8_t *restrict send_packet_data_ptr, uint32_t sending_time, void *param) { - coap_send_msg_s *stored_msg_ptr; + coap_send_msg_s *restrict stored_msg_ptr; /* If both queue parameters are "0" or resending count is "0", then re-sending is disabled */ if (((handle->sn_coap_resending_queue_msgs == 0) && (handle->sn_coap_resending_queue_bytes == 0)) || (handle->sn_coap_resending_count == 0)) { @@ -1005,7 +996,7 @@ static uint8_t sn_coap_protocol_linked_list_send_msg_store(struct coap_s *handle * \param msg_id is searching key for removed message *****************************************************************************/ -static void sn_coap_protocol_linked_list_send_msg_remove(struct coap_s *handle, const sn_nsdl_addr_s *src_addr_ptr, uint16_t msg_id) +static void sn_coap_protocol_linked_list_send_msg_remove(struct coap_s *restrict handle, const sn_nsdl_addr_s *restrict src_addr_ptr, uint16_t msg_id) { /* Loop all stored resending messages in Linked list */ ns_list_foreach(coap_send_msg_s, stored_msg_ptr, &handle->linked_list_resent_msgs) { @@ -1075,10 +1066,10 @@ uint16_t sn_coap_protocol_get_configured_blockwise_size(struct coap_s *handle) * \param *addr_ptr is pointer to Address information to be stored *****************************************************************************/ -static void sn_coap_protocol_linked_list_duplication_info_store(struct coap_s *handle, sn_nsdl_addr_s *addr_ptr, - uint16_t msg_id, void *param) +static void sn_coap_protocol_linked_list_duplication_info_store(struct coap_s *restrict handle, sn_nsdl_addr_s *restrict addr_ptr, + uint16_t msg_id, void *param) { - coap_duplication_info_s *stored_duplication_info_ptr = NULL; + coap_duplication_info_s *restrict stored_duplication_info_ptr = NULL; /* * * * Allocating memory for stored Duplication info * * * */ @@ -1131,8 +1122,8 @@ static void sn_coap_protocol_linked_list_duplication_info_store(struct coap_s *h * \return Return value is 0 when message found and -1 if not found *****************************************************************************/ -static coap_duplication_info_s* sn_coap_protocol_linked_list_duplication_info_search(const struct coap_s *handle, - const sn_nsdl_addr_s *addr_ptr, const uint16_t msg_id) +static coap_duplication_info_s *sn_coap_protocol_linked_list_duplication_info_search(const struct coap_s *handle, + const sn_nsdl_addr_s *addr_ptr, const uint16_t msg_id) { /* Loop all nodes in Linked list for searching Message ID */ ns_list_foreach(coap_duplication_info_s, stored_duplication_info_ptr, &handle->linked_list_duplication_msgs) { @@ -1209,14 +1200,14 @@ void sn_coap_protocol_linked_list_duplication_info_remove(struct coap_s *handle, #if SN_COAP_DUPLICATION_MAX_MSGS_COUNT static void sn_coap_protocol_duplication_info_free(struct coap_s *handle, coap_duplication_info_s *duplication_info_ptr) { - if (duplication_info_ptr) { - if (duplication_info_ptr->address) { - handle->sn_coap_protocol_free(duplication_info_ptr->address->addr_ptr); - handle->sn_coap_protocol_free(duplication_info_ptr->address); - } - handle->sn_coap_protocol_free(duplication_info_ptr->packet_ptr); - handle->sn_coap_protocol_free(duplication_info_ptr); - } + // General purpose free functions ignore null pointer inputs - this + // private one knows it never receives null. + if (duplication_info_ptr->address) { + handle->sn_coap_protocol_free(duplication_info_ptr->address->addr_ptr); + handle->sn_coap_protocol_free(duplication_info_ptr->address); + } + handle->sn_coap_protocol_free(duplication_info_ptr->packet_ptr); + handle->sn_coap_protocol_free(duplication_info_ptr); } #endif // SN_COAP_DUPLICATION_MAX_MSGS_COUNT @@ -1257,14 +1248,14 @@ static void sn_coap_protocol_linked_list_blockwise_msg_remove(struct coap_s *han * \param size1 Size of the whole incoming message *****************************************************************************/ -static void sn_coap_protocol_linked_list_blockwise_payload_store(struct coap_s *handle, sn_nsdl_addr_s *addr_ptr, - uint16_t payload_len, - uint8_t *payload_ptr, - uint8_t *token_ptr, - uint8_t token_len, - uint32_t block_number, - uint16_t block_size, - uint32_t size1) +static void sn_coap_protocol_linked_list_blockwise_payload_store(struct coap_s *restrict handle, sn_nsdl_addr_s *restrict addr_ptr, + uint16_t payload_len, + uint8_t *restrict payload_ptr, + uint8_t *restrict token_ptr, + uint8_t token_len, + uint32_t block_number, + uint16_t block_size, + uint32_t size1) { if (!addr_ptr || !payload_len || !payload_ptr) { return; @@ -1272,14 +1263,14 @@ static void sn_coap_protocol_linked_list_blockwise_payload_store(struct coap_s * // Do not add duplicates to list, this could happen if server needs to retransmit block message again if (sn_coap_protocol_linked_list_blockwise_payload_search_compare_block_number(handle, - addr_ptr, - token_ptr, - token_len, - block_number)) { + addr_ptr, + token_ptr, + token_len, + block_number)) { return; } - coap_blockwise_payload_s *stored_blockwise_payload_ptr = sn_coap_protocol_linked_list_blockwise_search(handle, addr_ptr, token_ptr, token_len); + coap_blockwise_payload_s *restrict stored_blockwise_payload_ptr = sn_coap_protocol_linked_list_blockwise_search(handle, addr_ptr, token_ptr, token_len); if (stored_blockwise_payload_ptr && stored_blockwise_payload_ptr->use_size1) { memcpy(stored_blockwise_payload_ptr->payload_ptr + (block_number * block_size), payload_ptr, payload_len); @@ -1287,7 +1278,7 @@ static void sn_coap_protocol_linked_list_blockwise_payload_store(struct coap_s * uint16_t new_len = stored_blockwise_payload_ptr->payload_len + payload_len; tr_debug("sn_coap_protocol_linked_list_blockwise_payload_store - reallocate from %d to %d", stored_blockwise_payload_ptr->payload_len, new_len); - uint8_t *temp_ptr = handle->sn_coap_protocol_malloc(stored_blockwise_payload_ptr->payload_len); + uint8_t *restrict temp_ptr = handle->sn_coap_protocol_malloc(stored_blockwise_payload_ptr->payload_len); if (temp_ptr == NULL) { tr_error("sn_coap_protocol_linked_list_blockwise_payload_store - failed to allocate temp buffer!"); sn_coap_protocol_linked_list_blockwise_payload_remove(handle, stored_blockwise_payload_ptr); @@ -1448,10 +1439,10 @@ static coap_blockwise_payload_s *sn_coap_protocol_linked_list_blockwise_search(s } static bool sn_coap_protocol_linked_list_blockwise_payload_search_compare_block_number(struct coap_s *handle, - const sn_nsdl_addr_s *src_addr_ptr, - const uint8_t *token_ptr, - uint8_t token_len, - uint32_t block_number) + const sn_nsdl_addr_s *src_addr_ptr, + const uint8_t *token_ptr, + uint8_t token_len, + uint32_t block_number) { /* Loop all stored blockwise payloads in Linked list */ ns_list_foreach(coap_blockwise_payload_s, stored_payload_info_ptr, &handle->linked_list_blockwise_received_payloads) { @@ -1515,7 +1506,7 @@ static uint32_t sn_coap_protocol_linked_list_blockwise_payloads_get_len(struct c if ((0 == memcmp(src_addr_ptr->addr_ptr, searched_payload_info_ptr->addr_ptr, src_addr_ptr->addr_len)) && (searched_payload_info_ptr->port == src_addr_ptr->port)) { /* Check token */ if (token_ptr) { - if(!searched_payload_info_ptr->token_ptr || (token_len != searched_payload_info_ptr->token_len) || (memcmp(searched_payload_info_ptr->token_ptr, token_ptr, token_len))) { + if (!searched_payload_info_ptr->token_ptr || (token_len != searched_payload_info_ptr->token_len) || (memcmp(searched_payload_info_ptr->token_ptr, token_ptr, token_len))) { continue; } } else if (searched_payload_info_ptr->token_ptr) { @@ -1530,50 +1521,15 @@ static uint32_t sn_coap_protocol_linked_list_blockwise_payloads_get_len(struct c } /**************************************************************************//** - * \fn static void sn_coap_protocol_handle_blockwise_timout(struct coap_s *handle) + * \fn static void sn_coap_protocol_handle_blockwise_timeout(struct coap_s *handle) * * \brief Check incoming and outgoing blockwise messages for time out. * Remove timed out messages from lists. Notify application if * outgoing message times out. *****************************************************************************/ -static void sn_coap_protocol_handle_blockwise_timout(struct coap_s *handle) +static void sn_coap_protocol_handle_blockwise_timeout(struct coap_s *handle) { - /* Loop all outgoing blockwise messages */ - /* foreach_safe isn't sufficient because callback routine could remove messages. */ -rescan: - ns_list_foreach_safe(coap_blockwise_msg_s, removed_blocwise_msg_ptr, &handle->linked_list_blockwise_sent_msgs) { - if ((handle->system_time - removed_blocwise_msg_ptr->timestamp) > SN_COAP_BLOCKWISE_MAX_TIME_DATA_STORED) { - bool callback_called = false; - // Item must be removed from the list before calling the rx_callback function. - // Callback could actually clear the list and free the item and cause a use after free when callback returns. - ns_list_remove(&handle->linked_list_blockwise_sent_msgs, removed_blocwise_msg_ptr); - - /* * * * This messages has timed out, remove it from Linked list * * * */ - if( removed_blocwise_msg_ptr->coap_msg_ptr ){ - if (handle->sn_coap_rx_callback) { - /* Notify the application about the time out */ - removed_blocwise_msg_ptr->coap_msg_ptr->coap_status = COAP_STATUS_BUILDER_BLOCK_SENDING_FAILED; - removed_blocwise_msg_ptr->coap_msg_ptr->msg_id = removed_blocwise_msg_ptr->msg_id; - sn_coap_protocol_delete_retransmission(handle, removed_blocwise_msg_ptr->msg_id); - handle->sn_coap_rx_callback(removed_blocwise_msg_ptr->coap_msg_ptr, NULL, removed_blocwise_msg_ptr->param); - callback_called = true; - } - handle->sn_coap_protocol_free(removed_blocwise_msg_ptr->coap_msg_ptr->payload_ptr); - sn_coap_parser_release_allocated_coap_msg_mem(handle, removed_blocwise_msg_ptr->coap_msg_ptr); - } - - handle->sn_coap_protocol_free(removed_blocwise_msg_ptr); - - if (callback_called) { - /* Callback routine could have wiped the list already */ - /* Be super cautious and rescan from the start */ - goto rescan; - } - } - } - - /* Loop all incoming Blockwise messages */ ns_list_foreach_safe(coap_blockwise_payload_s, removed_blocwise_payload_ptr, &handle->linked_list_blockwise_received_payloads) { if ((handle->system_time - removed_blocwise_payload_ptr->timestamp) > SN_COAP_BLOCKWISE_MAX_TIME_DATA_STORED) { @@ -1599,7 +1555,7 @@ static void sn_coap_protocol_handle_blockwise_timout(struct coap_s *handle) * \return pointer to allocated struct *****************************************************************************/ -coap_send_msg_s *sn_coap_protocol_allocate_mem_for_msg(struct coap_s *handle, sn_nsdl_addr_s *dst_addr_ptr, uint16_t packet_data_len) +coap_send_msg_s *sn_coap_protocol_allocate_mem_for_msg(struct coap_s *handle, sn_nsdl_addr_s *dst_addr_ptr, uint_fast16_t packet_data_len) { coap_send_msg_s *msg_ptr = sn_coap_protocol_calloc(handle, sizeof(coap_send_msg_s)); @@ -1613,7 +1569,7 @@ coap_send_msg_s *sn_coap_protocol_allocate_mem_for_msg(struct coap_s *handle, sn msg_ptr->send_msg_ptr.dst_addr_ptr.addr_ptr = sn_coap_protocol_calloc(handle, dst_addr_ptr->addr_len); if ((msg_ptr->send_msg_ptr.dst_addr_ptr.addr_ptr == NULL) || - (msg_ptr->send_msg_ptr.packet_ptr == NULL)) { + (msg_ptr->send_msg_ptr.packet_ptr == NULL)) { sn_coap_protocol_release_allocated_send_msg_mem(handle, msg_ptr); return 0; @@ -1650,9 +1606,9 @@ static void sn_coap_protocol_release_allocated_send_msg_mem(struct coap_s *handl * * \param const coap_send_msg_list_t *linked_list_ptr pointer to linked list *****************************************************************************/ -static uint16_t sn_coap_count_linked_list_size(const coap_send_msg_list_t *linked_list_ptr) +static uint_fast16_t sn_coap_count_linked_list_size(const coap_send_msg_list_t *linked_list_ptr) { - uint16_t total_size = 0; + uint_fast16_t total_size = 0; ns_list_foreach(coap_send_msg_s, stored_msg_ptr, linked_list_ptr) { total_size += stored_msg_ptr->send_msg_ptr.packet_len; @@ -1665,7 +1621,7 @@ static uint16_t sn_coap_count_linked_list_size(const coap_send_msg_list_t *linke #if SN_COAP_BLOCKWISE_ENABLED || SN_COAP_MAX_BLOCKWISE_PAYLOAD_SIZE -static coap_blockwise_msg_s* search_sent_blockwise_message(struct coap_s *handle, uint16_t msg_id) +static coap_blockwise_msg_s *search_sent_blockwise_message(struct coap_s *handle, uint16_t msg_id) { ns_list_foreach(coap_blockwise_msg_s, tmp, &handle->linked_list_blockwise_sent_msgs) { if (tmp->coap_msg_ptr && tmp->coap_msg_ptr->msg_id == msg_id) { @@ -1711,12 +1667,11 @@ void sn_coap_protocol_block_remove(struct coap_s *handle, sn_nsdl_addr_s *source } /* Check the payload */ - if(payload_length != stored_payload_info_ptr->payload_len){ + if (payload_length != stored_payload_info_ptr->payload_len) { continue; } - if(!memcmp(stored_payload_info_ptr->payload_ptr, payload, stored_payload_info_ptr->payload_len)) - { + if (!memcmp(stored_payload_info_ptr->payload_ptr, payload, stored_payload_info_ptr->payload_len)) { /* Everything matches, remove and return. */ sn_coap_protocol_linked_list_blockwise_payload_remove(handle, stored_payload_info_ptr); return; @@ -1754,11 +1709,11 @@ static coap_blockwise_msg_s *sn_coap_stored_blockwise_msg_get(struct coap_s *han * \param *received_coap_msg_ptr pointer to parsed CoAP message structure *****************************************************************************/ -static sn_coap_hdr_s *sn_coap_handle_blockwise_message(struct coap_s *handle, sn_nsdl_addr_s *src_addr_ptr, sn_coap_hdr_s *received_coap_msg_ptr, void *param) +static sn_coap_hdr_s *sn_coap_handle_blockwise_message(struct coap_s *handle, sn_nsdl_addr_s *src_addr_ptr, sn_coap_hdr_s *received_coap_msg_ptr, void *param, bool *keep_in_resend_queue) { sn_coap_hdr_s *src_coap_blockwise_ack_msg_ptr = NULL; uint16_t dst_packed_data_needed_mem = 0; - uint8_t *dst_ack_packet_data_ptr = NULL; + uint8_t *restrict dst_ack_packet_data_ptr = NULL; uint8_t block_temp = 0; uint16_t original_payload_len = 0; @@ -1768,27 +1723,29 @@ static sn_coap_hdr_s *sn_coap_handle_blockwise_message(struct coap_s *handle, sn // Blocked request sending, received ACK, sending next block.. if (received_coap_msg_ptr->options_list_ptr->block1 != COAP_OPTION_BLOCK_NONE) { if (received_coap_msg_ptr->msg_code > COAP_MSG_CODE_REQUEST_DELETE) { - if (received_coap_msg_ptr->options_list_ptr->block1 & 0x08) { - coap_blockwise_msg_s *stored_blockwise_msg_temp_ptr; - /* Get */ - stored_blockwise_msg_temp_ptr = search_sent_blockwise_message(handle, received_coap_msg_ptr->msg_id); + coap_blockwise_msg_s *stored_blockwise_msg_temp_ptr; + stored_blockwise_msg_temp_ptr = search_sent_blockwise_message(handle, received_coap_msg_ptr->msg_id); + + if (received_coap_msg_ptr->options_list_ptr->block1 & 0x08) { + received_coap_msg_ptr->coap_status = COAP_STATUS_PARSER_BLOCKWISE_ACK; if (stored_blockwise_msg_temp_ptr) { /* Build response message */ - uint16_t block_size; + uint_fast16_t block_size; uint32_t block_number; + uint32_t req_block_number; + + src_coap_blockwise_ack_msg_ptr = stored_blockwise_msg_temp_ptr->coap_msg_ptr; /* Get block option parameters from received message */ block_number = received_coap_msg_ptr->options_list_ptr->block1 >> 4; block_temp = received_coap_msg_ptr->options_list_ptr->block1 & 0x07; - block_size = 1u << (block_temp + 4); - - /* Build next block message */ - src_coap_blockwise_ack_msg_ptr = stored_blockwise_msg_temp_ptr->coap_msg_ptr; + block_size = 16u << block_temp; if (src_coap_blockwise_ack_msg_ptr->options_list_ptr) { + req_block_number = src_coap_blockwise_ack_msg_ptr->options_list_ptr->block1 >> 4; src_coap_blockwise_ack_msg_ptr->options_list_ptr->block1 = COAP_OPTION_BLOCK_NONE; // Do not clear block2 as it might have been set in the original request to request // specific size blocks @@ -1797,71 +1754,89 @@ static sn_coap_hdr_s *sn_coap_handle_blockwise_message(struct coap_s *handle, sn tr_error("sn_coap_handle_blockwise_message - (send block1) failed to allocate ack message!"); return 0; } + + // pass through to send a next request + req_block_number = block_number; } - block_number++; - src_coap_blockwise_ack_msg_ptr->options_list_ptr->block1 = (block_number << 4) | block_temp; + // Make sure that block number is the one we requested. If it's the old one just ignore it and wait for next response. + if (req_block_number == block_number) { - original_payload_len = stored_blockwise_msg_temp_ptr->coap_msg_ptr->payload_len; - original_payload_ptr = stored_blockwise_msg_temp_ptr->coap_msg_ptr->payload_ptr; + /* Build next block message */ + block_number++; + src_coap_blockwise_ack_msg_ptr->options_list_ptr->block1 = (block_number << 4) | block_temp; - if ((block_size * (block_number + 1)) > stored_blockwise_msg_temp_ptr->coap_msg_ptr->payload_len) { - src_coap_blockwise_ack_msg_ptr->payload_len = stored_blockwise_msg_temp_ptr->coap_msg_ptr->payload_len - (block_size * (block_number)); - src_coap_blockwise_ack_msg_ptr->payload_ptr = src_coap_blockwise_ack_msg_ptr->payload_ptr + (block_size * block_number); - } + original_payload_len = stored_blockwise_msg_temp_ptr->coap_msg_ptr->payload_len; + original_payload_ptr = stored_blockwise_msg_temp_ptr->coap_msg_ptr->payload_ptr; - /* Not last block */ - else { - /* set more - bit */ - src_coap_blockwise_ack_msg_ptr->options_list_ptr->block1 |= 0x08; - src_coap_blockwise_ack_msg_ptr->payload_len = block_size; - src_coap_blockwise_ack_msg_ptr->payload_ptr = src_coap_blockwise_ack_msg_ptr->payload_ptr + (block_size * block_number); - } + if ((block_size * (block_number + 1)) > stored_blockwise_msg_temp_ptr->coap_msg_ptr->payload_len) { + src_coap_blockwise_ack_msg_ptr->payload_len = stored_blockwise_msg_temp_ptr->coap_msg_ptr->payload_len - (block_size * (block_number)); + src_coap_blockwise_ack_msg_ptr->payload_ptr = src_coap_blockwise_ack_msg_ptr->payload_ptr + (block_size * block_number); + } - /* Build and send block message */ - dst_packed_data_needed_mem = sn_coap_builder_calc_needed_packet_data_size_2(src_coap_blockwise_ack_msg_ptr, handle->sn_coap_block_data_size); + /* Not last block */ + else { + /* set more - bit */ + src_coap_blockwise_ack_msg_ptr->options_list_ptr->block1 |= 0x08; + src_coap_blockwise_ack_msg_ptr->payload_len = block_size; + src_coap_blockwise_ack_msg_ptr->payload_ptr = src_coap_blockwise_ack_msg_ptr->payload_ptr + (block_size * block_number); + } - dst_ack_packet_data_ptr = handle->sn_coap_protocol_malloc(dst_packed_data_needed_mem); - if (!dst_ack_packet_data_ptr) { - tr_error("sn_coap_handle_blockwise_message - (send block1) failed to allocate ack message!"); - handle->sn_coap_protocol_free(src_coap_blockwise_ack_msg_ptr->options_list_ptr); - handle->sn_coap_protocol_free(original_payload_ptr); - handle->sn_coap_protocol_free(src_coap_blockwise_ack_msg_ptr); - stored_blockwise_msg_temp_ptr->coap_msg_ptr = NULL; - return NULL; - } - src_coap_blockwise_ack_msg_ptr->msg_id = get_new_message_id(); + /* Build and send block message */ + dst_packed_data_needed_mem = sn_coap_builder_calc_needed_packet_data_size_2(src_coap_blockwise_ack_msg_ptr, handle->sn_coap_block_data_size); + + dst_ack_packet_data_ptr = handle->sn_coap_protocol_malloc(dst_packed_data_needed_mem); + if (!dst_ack_packet_data_ptr) { + tr_error("sn_coap_handle_blockwise_message - (send block1) failed to allocate ack message!"); + handle->sn_coap_protocol_free(src_coap_blockwise_ack_msg_ptr->options_list_ptr); + handle->sn_coap_protocol_free(original_payload_ptr); + handle->sn_coap_protocol_free(src_coap_blockwise_ack_msg_ptr); + stored_blockwise_msg_temp_ptr->coap_msg_ptr = NULL; + return NULL; + } + src_coap_blockwise_ack_msg_ptr->msg_id = get_new_message_id(); - sn_coap_builder_2(dst_ack_packet_data_ptr, src_coap_blockwise_ack_msg_ptr, handle->sn_coap_block_data_size); + sn_coap_builder_2(dst_ack_packet_data_ptr, src_coap_blockwise_ack_msg_ptr, handle->sn_coap_block_data_size); - handle->sn_coap_tx_callback(dst_ack_packet_data_ptr, dst_packed_data_needed_mem, src_addr_ptr, param); + handle->sn_coap_tx_callback(dst_ack_packet_data_ptr, dst_packed_data_needed_mem, src_addr_ptr, param); #if ENABLE_RESENDINGS - uint32_t resend_time = sn_coap_calculate_new_resend_time(handle->system_time, handle->sn_coap_resending_intervall, 0); - if (src_coap_blockwise_ack_msg_ptr->msg_type == COAP_MSG_TYPE_CONFIRMABLE) { - sn_coap_protocol_linked_list_send_msg_store(handle, src_addr_ptr, - dst_packed_data_needed_mem, - dst_ack_packet_data_ptr, - resend_time, param); - } -#endif + uint32_t resend_time = sn_coap_calculate_new_resend_time(handle->system_time, handle->sn_coap_resending_intervall, 0); - handle->sn_coap_protocol_free(dst_ack_packet_data_ptr); - dst_ack_packet_data_ptr = 0; + if (src_coap_blockwise_ack_msg_ptr->msg_type == COAP_MSG_TYPE_CONFIRMABLE) { + sn_coap_protocol_linked_list_send_msg_store(handle, src_addr_ptr, + dst_packed_data_needed_mem, + dst_ack_packet_data_ptr, + resend_time, param); + } +#endif - stored_blockwise_msg_temp_ptr->coap_msg_ptr->payload_len = original_payload_len; - stored_blockwise_msg_temp_ptr->coap_msg_ptr->payload_ptr = original_payload_ptr; + handle->sn_coap_protocol_free(dst_ack_packet_data_ptr); + dst_ack_packet_data_ptr = 0; - received_coap_msg_ptr->coap_status = COAP_STATUS_PARSER_BLOCKWISE_ACK; + stored_blockwise_msg_temp_ptr->coap_msg_ptr->payload_len = original_payload_len; + stored_blockwise_msg_temp_ptr->coap_msg_ptr->payload_ptr = original_payload_ptr; - // Remove original message from the list when last block has been sent. - if (!((src_coap_blockwise_ack_msg_ptr->options_list_ptr->block1) & 0x08)) { - sn_coap_protocol_remove_sent_blockwise_message(handle, stored_blockwise_msg_temp_ptr->coap_msg_ptr->msg_id); + // Remove original message from the list when last block has been sent. + if (!((src_coap_blockwise_ack_msg_ptr->options_list_ptr->block1) & 0x08)) { + sn_coap_protocol_remove_sent_blockwise_message(handle, stored_blockwise_msg_temp_ptr->coap_msg_ptr->msg_id); + } + } else { + tr_warn("sn_coap_handle_blockwise_message - blocks not in order, requested: %"PRIu32" received: %"PRIu32" --> ignore", req_block_number, block_number); + src_coap_blockwise_ack_msg_ptr->options_list_ptr->block1 = (req_block_number << 4) | block_temp; + *keep_in_resend_queue = true; } } } else { - // XXX what was this trying to free? - received_coap_msg_ptr->coap_status = COAP_STATUS_OK; + if (stored_blockwise_msg_temp_ptr) { + // Last block received but some blocks are not yet sent. Ignore it and wait for next response. + tr_warn("sn_coap_handle_blockwise_message - last block received but some blocks are missing --> ignore"); + received_coap_msg_ptr->coap_status = COAP_STATUS_PARSER_BLOCKWISE_ACK; + *keep_in_resend_queue = true; + } else { + // XXX what was this trying to free? + received_coap_msg_ptr->coap_status = COAP_STATUS_OK; + } } } @@ -1876,11 +1851,11 @@ static sn_coap_hdr_s *sn_coap_handle_blockwise_message(struct coap_s *handle, sn bool blocks_in_order = true; if (block_number > 0 && - !sn_coap_protocol_linked_list_blockwise_payload_search_compare_block_number(handle, - src_addr_ptr, - received_coap_msg_ptr->token_ptr, - received_coap_msg_ptr->token_len, - block_number - 1)) { + !sn_coap_protocol_linked_list_blockwise_payload_search_compare_block_number(handle, + src_addr_ptr, + received_coap_msg_ptr->token_ptr, + received_coap_msg_ptr->token_len, + block_number - 1)) { blocks_in_order = false; } @@ -1912,24 +1887,23 @@ static sn_coap_hdr_s *sn_coap_handle_blockwise_message(struct coap_s *handle, sn // Include maximum size that stack can handle into response tr_info("sn_coap_handle_blockwise_message - (recv block1) entity too large"); src_coap_blockwise_ack_msg_ptr->msg_code = COAP_MSG_CODE_RESPONSE_REQUEST_ENTITY_TOO_LARGE; - } - else { + } else { src_coap_blockwise_ack_msg_ptr->options_list_ptr->block1 = received_coap_msg_ptr->options_list_ptr->block1; src_coap_blockwise_ack_msg_ptr->msg_type = COAP_MSG_TYPE_ACKNOWLEDGEMENT; /* Check block size */ block_temp = (src_coap_blockwise_ack_msg_ptr->options_list_ptr->block1 & 0x07); - uint16_t block_size = 1u << (block_temp + 4); + uint_fast16_t block_size = 16u << block_temp; if (block_size > handle->sn_coap_block_data_size) { - // Include maximum size that stack can handle into response + // Include maximum size that stack can handle into response tr_info("sn_coap_handle_blockwise_message - (recv block1) entity too large"); - src_coap_blockwise_ack_msg_ptr->msg_code = COAP_MSG_CODE_RESPONSE_REQUEST_ENTITY_TOO_LARGE; - src_coap_blockwise_ack_msg_ptr->options_list_ptr->size1 = handle->sn_coap_block_data_size; + src_coap_blockwise_ack_msg_ptr->msg_code = COAP_MSG_CODE_RESPONSE_REQUEST_ENTITY_TOO_LARGE; + src_coap_blockwise_ack_msg_ptr->options_list_ptr->size1 = handle->sn_coap_block_data_size; } if (block_temp > sn_coap_convert_block_size(handle->sn_coap_block_data_size)) { - src_coap_blockwise_ack_msg_ptr->options_list_ptr->block1 &= 0xFFFFF8; + src_coap_blockwise_ack_msg_ptr->options_list_ptr->block1 &= 0xFFFFFFF8; src_coap_blockwise_ack_msg_ptr->options_list_ptr->block1 |= sn_coap_convert_block_size(handle->sn_coap_block_data_size); } } @@ -1968,7 +1942,7 @@ static sn_coap_hdr_s *sn_coap_handle_blockwise_message(struct coap_s *handle, sn #endif // Store only in success case if (src_coap_blockwise_ack_msg_ptr->msg_code != COAP_MSG_CODE_RESPONSE_REQUEST_ENTITY_INCOMPLETE && - src_coap_blockwise_ack_msg_ptr->msg_code != COAP_MSG_CODE_RESPONSE_REQUEST_ENTITY_TOO_LARGE) { + src_coap_blockwise_ack_msg_ptr->msg_code != COAP_MSG_CODE_RESPONSE_REQUEST_ENTITY_TOO_LARGE) { uint16_t block_size = 1u << ((received_coap_msg_ptr->options_list_ptr->block1 & 0x07) + 4); sn_coap_protocol_linked_list_blockwise_payload_store(handle, src_addr_ptr, @@ -2136,9 +2110,9 @@ static sn_coap_hdr_s *sn_coap_handle_blockwise_message(struct coap_s *handle, sn #if ENABLE_RESENDINGS uint32_t resend_time = sn_coap_calculate_new_resend_time(handle->system_time, handle->sn_coap_resending_intervall, 0); sn_coap_protocol_linked_list_send_msg_store(handle, src_addr_ptr, - dst_packed_data_needed_mem, - dst_ack_packet_data_ptr, - resend_time, param); + dst_packed_data_needed_mem, + dst_ack_packet_data_ptr, + resend_time, param); #endif handle->sn_coap_protocol_free(dst_ack_packet_data_ptr); dst_ack_packet_data_ptr = 0; @@ -2175,7 +2149,7 @@ static sn_coap_hdr_s *sn_coap_handle_blockwise_message(struct coap_s *handle, sn block_temp = received_coap_msg_ptr->options_list_ptr->block2 & 0x07; /* Resolve block parameters */ - const uint16_t block_size = 1u << (block_temp + 4); + const uint_fast16_t block_size = 16u << block_temp; const uint32_t block_number = received_coap_msg_ptr->options_list_ptr->block2 >> 4; @@ -2220,7 +2194,7 @@ static sn_coap_hdr_s *sn_coap_handle_blockwise_message(struct coap_s *handle, sn * This is needed only in case of notification message. */ if (src_coap_blockwise_ack_msg_ptr->options_list_ptr && - src_coap_blockwise_ack_msg_ptr->options_list_ptr->observe != COAP_OBSERVE_NONE) { + src_coap_blockwise_ack_msg_ptr->options_list_ptr->observe != COAP_OBSERVE_NONE) { if (src_coap_blockwise_ack_msg_ptr->token_ptr) { handle->sn_coap_protocol_free(src_coap_blockwise_ack_msg_ptr->token_ptr); if (received_coap_msg_ptr->token_len) { @@ -2228,8 +2202,7 @@ static sn_coap_hdr_s *sn_coap_handle_blockwise_message(struct coap_s *handle, sn if (src_coap_blockwise_ack_msg_ptr->token_ptr) { src_coap_blockwise_ack_msg_ptr->token_len = received_coap_msg_ptr->token_len; } - } - else { + } else { src_coap_blockwise_ack_msg_ptr->token_ptr = NULL; src_coap_blockwise_ack_msg_ptr->token_len = 0; } @@ -2318,28 +2291,17 @@ static bool sn_coap_handle_last_blockwise(struct coap_s *handle, const sn_nsdl_a int8_t sn_coap_convert_block_size(uint16_t block_size) { - if (block_size == 16) { - return 0; - } else if (block_size == 32) { - return 1; - } else if (block_size == 64) { - return 2; - } else if (block_size == 128) { - return 3; - } else if (block_size == 256) { - return 4; - } else if (block_size == 512) { - return 5; - } else if (block_size == 1024) { - return 6; - } else { - return 0; + for (int n = 0; n <= 6; n++) { + if (block_size == (16 << n)) { + return n; + } } + return -1; } -static sn_coap_hdr_s *sn_coap_protocol_copy_header(struct coap_s *handle, const sn_coap_hdr_s *source_header_ptr) +static sn_coap_hdr_s *sn_coap_protocol_copy_header(struct coap_s *restrict handle, const sn_coap_hdr_s *restrict source_header_ptr) { - sn_coap_hdr_s *destination_header_ptr; + sn_coap_hdr_s *restrict destination_header_ptr; destination_header_ptr = sn_coap_parser_alloc_message(handle); if (!destination_header_ptr) { @@ -2382,8 +2344,8 @@ static sn_coap_hdr_s *sn_coap_protocol_copy_header(struct coap_s *handle, const return 0; } - const sn_coap_options_list_s *source_options_list_ptr = source_header_ptr->options_list_ptr; - sn_coap_options_list_s *destination_options_list_ptr = destination_header_ptr->options_list_ptr; + const sn_coap_options_list_s *restrict source_options_list_ptr = source_header_ptr->options_list_ptr; + sn_coap_options_list_s *restrict destination_options_list_ptr = destination_header_ptr->options_list_ptr; destination_options_list_ptr->max_age = source_options_list_ptr->max_age; @@ -2464,11 +2426,11 @@ static sn_coap_hdr_s *sn_coap_protocol_copy_header(struct coap_s *handle, const static bool sn_coap_protocol_update_duplicate_package_data(const struct coap_s *handle, const sn_nsdl_addr_s *dst_addr_ptr, const sn_coap_hdr_s *coap_msg_ptr, - const int16_t data_size, + const int_fast16_t data_size, const uint8_t *dst_packet_data_ptr) { if (coap_msg_ptr->msg_type == COAP_MSG_TYPE_ACKNOWLEDGEMENT && - handle->sn_coap_duplication_buffer_size != 0) { + handle->sn_coap_duplication_buffer_size != 0) { return sn_coap_protocol_update_duplicate_package_data_all(handle, dst_addr_ptr, coap_msg_ptr, data_size, dst_packet_data_ptr); } return true; @@ -2477,10 +2439,10 @@ static bool sn_coap_protocol_update_duplicate_package_data(const struct coap_s * static bool sn_coap_protocol_update_duplicate_package_data_all(const struct coap_s *handle, const sn_nsdl_addr_s *dst_addr_ptr, const sn_coap_hdr_s *coap_msg_ptr, - const int16_t data_size, + const int_fast16_t data_size, const uint8_t *dst_packet_data_ptr) { - coap_duplication_info_s* info = sn_coap_protocol_linked_list_duplication_info_search(handle, + coap_duplication_info_s *info = sn_coap_protocol_linked_list_duplication_info_search(handle, dst_addr_ptr, coap_msg_ptr->msg_id); @@ -2500,7 +2462,7 @@ static bool sn_coap_protocol_update_duplicate_package_data_all(const struct coap } #endif -void *sn_coap_protocol_malloc_copy(struct coap_s *handle, const void *source, uint16_t length) +void *sn_coap_protocol_malloc_copy(struct coap_s *handle, const void *source, uint_fast16_t length) { void *dest = handle->sn_coap_protocol_malloc(length); @@ -2515,7 +2477,7 @@ void *sn_coap_protocol_malloc_copy(struct coap_s *handle, const void *source, ui * are, but that would require the client to fill one up, as a wrapper filled from this * class would need access to the handle itself. */ -void *sn_coap_protocol_calloc(struct coap_s *handle, uint16_t length) +void *sn_coap_protocol_calloc(struct coap_s *handle, uint_fast16_t length) { void *result = handle->sn_coap_protocol_malloc(length); @@ -2525,7 +2487,7 @@ void *sn_coap_protocol_calloc(struct coap_s *handle, uint16_t length) return result; } -static bool compare_port(const sn_nsdl_addr_s* left, const sn_nsdl_addr_s* right) +static bool compare_port(const sn_nsdl_addr_s *left, const sn_nsdl_addr_s *right) { bool match = false; if (left->port == right->port) { diff --git a/multicast/libota.c b/multicast/libota.c index c97d6d924..6796ebaf6 100644 --- a/multicast/libota.c +++ b/multicast/libota.c @@ -36,7 +36,6 @@ #include "libota.h" static void ota_start_timer(ota_timers_e timer_id, uint32_t start_time, uint32_t random_window); -static void ota_send_error(ota_error_code_e error); static void ota_send_estimated_resend_time(uint32_t resend_time_in_secs); static void ota_get_state(char *ota_state_ptr); static bool check_session(uint8_t *payload_ptr, uint16_t *payload_index); @@ -59,21 +58,20 @@ static size_t resend_payload_size = 0; // OTA_CHECKSUM_CALCULATING_INTERVAL time for avoiding interrupting other operations for too long time #define OTA_CHECKSUM_CALCULATING_BYTE_COUNT 512 // In bytes #define OTA_CHECKSUM_CALCULATING_INTERVAL 10 // In milliseconds -#define CRITICAL_MESSAGE_SEND_COUNT 3 // How many times critical messages are sent (manifest, start and activate) +// * * * Timer random timeout values (values are seconds) * * * #if defined(MBED_CLOUD_CLIENT_MULTICAST_SMALL_NETWORK) || defined(__NANOSIMULATOR__) +#define CRITICAL_MESSAGE_SEND_COUNT 2 // How many times critical messages are sent (manifest, start and activate) #define OTA_MISSING_FRAGMENTS_REQUESTING_TIMEOUT_START 5 // After this random timeout, device will send request for its missing fragments. #define OTA_FRAGMENTS_REQUEST_SERVICE_TIMEOUT_START 5 // After this random timeout, device will start sending fragments to requester. #define OTA_TIMER_RANDOM_WINDOW 5 // Random window for timer. #define OTA_NOTIFICATION_TIMER_DELAY 2 // This is start time in seconds for random timeout, which OTA library uses for sending ack to backend. -#define OTA_ONE_FRAGMENT_WAITTIME_SECS 300 // After this timeout service will fail the campaign if nodes are not in correct state and threshold is not met - -#define OTA_MULTICAST_INTERVAL 10 // Delay between multicast messages +#define OTA_ONE_FRAGMENT_WAITTIME_SECS 120 // After this timeout service will fail the campaign if nodes are not in correct state and threshold is not met +#define OTA_MULTICAST_INTERVAL 5 // Delay between multicast messages #define OTA_MISSING_FRAGMENT_FALLBACK_TIMEOUT 120 /* After this timeout, device will start requesting its missing fragments. This is needed if node did not receive END FRAGMENT command. */ - #else -// * * * Timer random timeout values (values are seconds) * * * +#define CRITICAL_MESSAGE_SEND_COUNT 3 // How many times critical messages are sent (manifest, start and activate) #define OTA_MISSING_FRAGMENTS_REQUESTING_TIMEOUT_START 30 // After this random timeout, device will send request for its missing fragments. #define OTA_FRAGMENTS_REQUEST_SERVICE_TIMEOUT_START 5 // After this random timeout, device will start sending fragments to requester. #define OTA_TIMER_RANDOM_WINDOW 60 // Random window for timer. @@ -99,7 +97,6 @@ static size_t resend_payload_size = 0; // going into missing fragments requesting state. #define OTA_START_RESEND_DELAY (OTA_MISSING_FRAGMENT_FALLBACK_TIMEOUT / CRITICAL_MESSAGE_SEND_COUNT) - void ota_lib_reset() { if (ota_free_fptr) { @@ -131,13 +128,13 @@ ota_error_code_e ota_lib_configure(ota_lib_config_data_t *lib_config_data_ptr, } if (func_pointers_ptr->mem_alloc_fptr == NULL || func_pointers_ptr->mem_free_fptr == NULL || - func_pointers_ptr->request_timer_fptr == NULL || func_pointers_ptr->cancel_timer_fptr == NULL || - func_pointers_ptr->store_new_ota_process_fptr == NULL || func_pointers_ptr->remove_stored_ota_process_fptr == NULL || - func_pointers_ptr->store_parameters_fptr == NULL || func_pointers_ptr->read_parameters_fptr == NULL || - func_pointers_ptr->write_fw_bytes_fptr == NULL || func_pointers_ptr->read_fw_bytes_fptr == NULL || - func_pointers_ptr->send_update_fw_cmd_received_info_fptr == NULL || func_pointers_ptr->socket_send_fptr == NULL || - func_pointers_ptr->update_resource_value_fptr == NULL || func_pointers_ptr->manifest_received_fptr == NULL || - func_pointers_ptr->firmware_ready_fptr == NULL || func_pointers_ptr->get_parent_addr_fptr == NULL) { + func_pointers_ptr->request_timer_fptr == NULL || func_pointers_ptr->cancel_timer_fptr == NULL || + func_pointers_ptr->store_new_ota_process_fptr == NULL || func_pointers_ptr->remove_stored_ota_process_fptr == NULL || + func_pointers_ptr->store_parameters_fptr == NULL || func_pointers_ptr->read_parameters_fptr == NULL || + func_pointers_ptr->write_fw_bytes_fptr == NULL || func_pointers_ptr->read_fw_bytes_fptr == NULL || + func_pointers_ptr->send_update_fw_cmd_received_info_fptr == NULL || func_pointers_ptr->socket_send_fptr == NULL || + func_pointers_ptr->update_resource_value_fptr == NULL || func_pointers_ptr->manifest_received_fptr == NULL || + func_pointers_ptr->firmware_ready_fptr == NULL || func_pointers_ptr->get_parent_addr_fptr == NULL) { tr_err("Some given function pointer is null"); returned_status = OTA_PARAMETER_FAIL; goto done; @@ -205,7 +202,7 @@ ota_error_code_e ota_lib_configure(ota_lib_config_data_t *lib_config_data_ptr, if (ota_parameters.ota_state == OTA_STATE_MISSING_FRAGMENTS_REQUESTING) { ota_start_timer(OTA_MISSING_FRAGMENTS_REQUESTING_TIMER, OTA_MISSING_FRAGMENTS_REQUESTING_TIMEOUT_START, - OTA_TIMER_RANDOM_WINDOW ); + OTA_TIMER_RANDOM_WINDOW); } else { if (ota_parameters.ota_state != OTA_STATE_ABORTED) { ota_start_timer(OTA_FALLBACK_TIMER, OTA_MISSING_FRAGMENT_FALLBACK_TIMEOUT, 0); @@ -213,17 +210,17 @@ ota_error_code_e ota_lib_configure(ota_lib_config_data_t *lib_config_data_ptr, } } else { if (ota_parameters.ota_state != OTA_STATE_ABORTED && - ota_parameters.ota_state != OTA_STATE_CHECKSUM_FAILED && - ota_parameters.ota_state != OTA_STATE_PROCESS_COMPLETED && - ota_parameters.ota_state != OTA_STATE_UPDATE_FW && - ota_parameters.ota_state != OTA_STATE_INVALID && - ota_parameters.ota_state != OTA_STATE_IDLE) { + ota_parameters.ota_state != OTA_STATE_CHECKSUM_FAILED && + ota_parameters.ota_state != OTA_STATE_PROCESS_COMPLETED && + ota_parameters.ota_state != OTA_STATE_UPDATE_FW && + ota_parameters.ota_state != OTA_STATE_INVALID && + ota_parameters.ota_state != OTA_STATE_IDLE) { ota_parameters.ota_state = OTA_STATE_CHECKSUM_CALCULATING; } } tr_info("Missing fragments total count: %u Received fragment total count: %u", - missing_fragment_total_count, (ota_parameters.fw_fragment_count - missing_fragment_total_count)); + missing_fragment_total_count, (ota_parameters.fw_fragment_count - missing_fragment_total_count)); ota_get_and_log_first_missing_segment(NULL); @@ -247,9 +244,9 @@ ota_error_code_e ota_lib_configure(ota_lib_config_data_t *lib_config_data_ptr, } else { tr_err("OTA library configuration failed! Error code: %d (NODE)", returned_status); } - } + } - return returned_status; + return returned_status; } void ota_socket_receive_data(uint16_t payload_length, uint8_t *payload_ptr, ota_ip_address_t *source_addr_ptr) @@ -609,14 +606,10 @@ static ota_error_code_e ota_border_router_manage_command(uint16_t payload_length ota_parameters.fw_segment_count = (ota_parameters.fw_fragment_count / OTA_SEGMENT_SIZE); - if (ota_parameters.pull_url_ptr != NULL) { - ota_free_fptr(ota_parameters.pull_url_ptr); - ota_parameters.pull_url_ptr = NULL; - } - ota_parameters.pull_url_length = payload_length - MULTICAST_CMD_URL_INDEX; if (ota_parameters.pull_url_length > 0) { + ota_free_fptr(ota_parameters.pull_url_ptr); ota_parameters.pull_url_ptr = ota_malloc_fptr(ota_parameters.pull_url_length); if (ota_parameters.pull_url_ptr != NULL) { memset(ota_parameters.pull_url_ptr, 0, ota_parameters.pull_url_length); @@ -722,8 +715,8 @@ static void ota_manage_fragment_command(uint16_t payload_length, uint8_t *payloa payload_index += 2; if (ota_parameters.ota_state != OTA_STATE_STARTED && - ota_parameters.ota_state != OTA_STATE_MISSING_FRAGMENTS_REQUESTING && - ota_fragments_request_service == false) { + ota_parameters.ota_state != OTA_STATE_MISSING_FRAGMENTS_REQUESTING && + ota_fragments_request_service == false) { tr_warn("OTA in wrong state when received FW fragment %u / %u. Current state: %d Fragments requesting service OTA process ID index: %u", fragment_id, ota_parameters.fw_fragment_count, ota_parameters.ota_state, @@ -744,14 +737,14 @@ static void ota_manage_fragment_command(uint16_t payload_length, uint8_t *payloa } uint16_t calculated_fragment_checksum = ota_calculate_checksum_over_one_fragment(&payload_ptr[OTA_FRAGMENT_CMD_FRAGMENT_BYTES_INDEX], - ota_parameters.fw_fragment_byte_count); + ota_parameters.fw_fragment_byte_count); if (fragment_checksum != calculated_fragment_checksum) { tr_err("Checksums mismatch. Fragment checksum: 0x%X Calculated checksum: 0x%X", fragment_checksum, calculated_fragment_checksum); } if (fragment_checksum == calculated_fragment_checksum && - fragment_id > 0 && fragment_id <= ota_parameters.fw_fragment_count){ + fragment_id > 0 && fragment_id <= ota_parameters.fw_fragment_count) { if (ota_fragments_request_service == false) { bool fragment_already_received_flag = ota_check_if_fragment_already_received(fragment_id); @@ -793,7 +786,7 @@ static void ota_manage_fragment_command(uint16_t payload_length, uint8_t *payloa ota_parameters.ota_state = OTA_STATE_CHECKSUM_CALCULATING; rc = ota_store_parameters_fptr(&ota_parameters); - if (rc != OTA_OK){ + if (rc != OTA_OK) { tr_err("Storing OTA parameters failed, RC: %d", rc); } @@ -823,10 +816,10 @@ static void ota_manage_fragment_command(uint16_t payload_length, uint8_t *payloa } tr_info("Current requested Fragment bitmasks: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X", - ota_fragments_request_service_bitmask_tbl[0], ota_fragments_request_service_bitmask_tbl[1], ota_fragments_request_service_bitmask_tbl[2], ota_fragments_request_service_bitmask_tbl[3], - ota_fragments_request_service_bitmask_tbl[4], ota_fragments_request_service_bitmask_tbl[5], ota_fragments_request_service_bitmask_tbl[6], ota_fragments_request_service_bitmask_tbl[7], - ota_fragments_request_service_bitmask_tbl[8], ota_fragments_request_service_bitmask_tbl[9], ota_fragments_request_service_bitmask_tbl[10], ota_fragments_request_service_bitmask_tbl[11], - ota_fragments_request_service_bitmask_tbl[12], ota_fragments_request_service_bitmask_tbl[13], ota_fragments_request_service_bitmask_tbl[14], ota_fragments_request_service_bitmask_tbl[15]); + ota_fragments_request_service_bitmask_tbl[0], ota_fragments_request_service_bitmask_tbl[1], ota_fragments_request_service_bitmask_tbl[2], ota_fragments_request_service_bitmask_tbl[3], + ota_fragments_request_service_bitmask_tbl[4], ota_fragments_request_service_bitmask_tbl[5], ota_fragments_request_service_bitmask_tbl[6], ota_fragments_request_service_bitmask_tbl[7], + ota_fragments_request_service_bitmask_tbl[8], ota_fragments_request_service_bitmask_tbl[9], ota_fragments_request_service_bitmask_tbl[10], ota_fragments_request_service_bitmask_tbl[11], + ota_fragments_request_service_bitmask_tbl[12], ota_fragments_request_service_bitmask_tbl[13], ota_fragments_request_service_bitmask_tbl[14], ota_fragments_request_service_bitmask_tbl[15]); uint16_t missing_fragment_count_for_requester = ota_get_next_missing_fragment_id_for_requester(false); if (missing_fragment_count_for_requester > 0) { @@ -842,7 +835,7 @@ static void ota_manage_fragment_command(uint16_t payload_length, uint8_t *payloa } } else { tr_err("OTA will not store data to given data storage because fragment cmd validity checks failed (%u %u %u %u)", - fragment_checksum, calculated_fragment_checksum, fragment_id, ota_parameters.fw_fragment_count); + fragment_checksum, calculated_fragment_checksum, fragment_id, ota_parameters.fw_fragment_count); } if (ota_parameters.ota_state == OTA_STATE_MISSING_FRAGMENTS_REQUESTING) { @@ -1009,7 +1002,7 @@ static void ota_manage_update_fw_command(uint16_t payload_length, uint8_t *paylo ota_cancel_timer_fptr(OTA_FALLBACK_TIMER); if (ota_parameters.ota_state != OTA_STATE_PROCESS_COMPLETED && - ota_parameters.ota_state != OTA_STATE_UPDATE_FW) { + ota_parameters.ota_state != OTA_STATE_UPDATE_FW) { tr_warn("OTA not in PROCESS COMPLETED or in UPDATE FW state when tried to change to FW UPDATE state. Current state: %d", ota_parameters.ota_state); return; @@ -1078,7 +1071,7 @@ static void ota_manage_fragments_request_command(uint16_t payload_length, uint8_ } if (ota_parameters.ota_state == OTA_STATE_PROCESS_COMPLETED || - ota_parameters.ota_state == OTA_STATE_UPDATE_FW) { + ota_parameters.ota_state == OTA_STATE_UPDATE_FW) { if (payload_length < OTA_FRAGMENTS_REQ_LENGTH) { tr_err("Received FRAGMENTS REQUEST command data length not correct: %u (%u)", payload_length, OTA_FRAGMENTS_REQ_LENGTH); return; @@ -1165,7 +1158,7 @@ static uint16_t ota_get_missing_fragment_total_count() static uint16_t ota_get_and_log_first_missing_segment(uint8_t *missing_fragment_bitmasks_ptr) { uint8_t *segment_bitmask_temp_ptr = - &ota_parameters.fragments_bitmask_ptr[ota_parameters.fragments_bitmask_length - 1]; + &ota_parameters.fragments_bitmask_ptr[ota_parameters.fragments_bitmask_length - 1]; if (missing_fragment_bitmasks_ptr != NULL) { memset(missing_fragment_bitmasks_ptr, 0, OTA_FRAGMENTS_REQ_BITMASK_LENGTH); @@ -1177,7 +1170,7 @@ static uint16_t ota_get_and_log_first_missing_segment(uint8_t *missing_fragment_ if (missing_fragment_bitmasks_ptr != NULL) { memcpy(missing_fragment_bitmasks_ptr, &ota_parameters.fragments_bitmask_ptr[(ota_parameters.fragments_bitmask_length) - (segment_id * OTA_FRAGMENTS_REQ_BITMASK_LENGTH)], - OTA_FRAGMENTS_REQ_BITMASK_LENGTH); + OTA_FRAGMENTS_REQ_BITMASK_LENGTH); } for (uint8_t j = 0; j < OTA_FRAGMENTS_REQ_BITMASK_LENGTH; j++, segment_bitmask_temp_ptr--) { @@ -1380,7 +1373,7 @@ static void ota_manage_whole_fw_checksum_calculating(void) } if (ota_checksum_calculating_ptr.current_byte_id == fw_total_data_byte_count || - read_byte_count != pushed_fw_data_byte_count) { + read_byte_count != pushed_fw_data_byte_count) { uint8_t sha256_result[OTA_WHOLE_FW_CHECKSUM_LENGTH]; memset(sha256_result, 0, OTA_WHOLE_FW_CHECKSUM_LENGTH); @@ -1462,7 +1455,7 @@ static void ota_start_timer(ota_timers_e timer_id, uint32_t start_time, uint32_t start_time *= 1000; if (random_window) { //Random is taken as 100ms slots - start_time += 100*(randLIB_get_32bit()%(random_window *10)); + start_time += 100 * (randLIB_get_32bit() % (random_window * 10)); } ota_request_timer_fptr(timer_id, start_time); } @@ -1508,7 +1501,7 @@ uint8_t ota_lwm2m_command(struct nsdl_s *handle_ptr, sn_coap_hdr_s *coap_ptr, sn // Free the block message from the CoAP list, data copied into a resource sn_nsdl_remove_coap_block(handle_ptr, address_ptr, coap_ptr->payload_len, coap_ptr->payload_ptr); #else - handle_ptr->sn_nsdl_free(coap_ptr->payload_ptr); + handle_ptr->sn_nsdl_free(coap_ptr->payload_ptr); #endif } @@ -1537,7 +1530,7 @@ uint8_t ota_fragment_size_command(struct nsdl_s *handle_ptr, sn_coap_hdr_s *coap coap_response_code = COAP_MSG_CODE_RESPONSE_CONTENT; char buf[6]; resp_ptr->payload_len = sprintf(buf, "%"PRIu16, fragment_size); - resp_ptr->payload_ptr = (uint8_t*)buf; + resp_ptr->payload_ptr = (uint8_t *)buf; } else if (coap_ptr->msg_code == COAP_MSG_CODE_REQUEST_PUT) { // Allow at max 4 digits if (coap_ptr->payload_ptr && coap_ptr->payload_len <= 4) { @@ -1546,9 +1539,9 @@ uint8_t ota_fragment_size_command(struct nsdl_s *handle_ptr, sn_coap_hdr_s *coap memcpy(value_buf, coap_ptr->payload_ptr, coap_ptr->payload_len); if (sscanf(value_buf, "%hd", &value)) { if (value >= OTA_MIN_FRAGMENT_SIZE && - value <= OTA_MAX_MULTICAST_MESSAGE_SIZE && - value <= ARM_UC_HUB_BUFFER_SIZE_MAX && - value % LIBOTA_FRAGMENT_SIZE_DIVISOR == 0) { + value <= OTA_MAX_MULTICAST_MESSAGE_SIZE && + value <= ARM_UC_HUB_BUFFER_SIZE_MAX && + value % LIBOTA_FRAGMENT_SIZE_DIVISOR == 0) { coap_response_code = COAP_MSG_CODE_RESPONSE_CHANGED; tr_info("ota_fragment_size_command - fragment size set to %d", value); // New value is taken into use when new multicast process is started by border router @@ -1589,11 +1582,11 @@ static void ota_init_fragments_bit_mask(uint8_t init_value) memset(ota_parameters.fragments_bitmask_ptr, 0xFF, ota_parameters.fragments_bitmask_length); uint8_t *fragment_bitmask_temp_ptr = - &ota_parameters.fragments_bitmask_ptr[ota_parameters.fragments_bitmask_length - 1]; + &ota_parameters.fragments_bitmask_ptr[ota_parameters.fragments_bitmask_length - 1]; for (uint16_t fragment_counter_temp = 0; - fragment_counter_temp < ota_parameters.fw_fragment_count; - fragment_bitmask_temp_ptr--) { + fragment_counter_temp < ota_parameters.fw_fragment_count; + fragment_bitmask_temp_ptr--) { for (uint8_t j = 0; j < 8; j++) { if (init_value == 0) { @@ -1640,7 +1633,7 @@ static ota_error_code_e ota_add_new_process(uint8_t *session_id) static uint8_t ota_get_first_missing_fragments_process_id(bool fallback_flag) { if ((fallback_flag || ota_parameters.ota_state == OTA_STATE_MISSING_FRAGMENTS_REQUESTING) && - ota_parameters.ota_state != OTA_STATE_ABORTED) { + ota_parameters.ota_state != OTA_STATE_ABORTED) { uint16_t missing_fragment_count = ota_get_missing_fragment_total_count(); if (missing_fragment_count != 0) { return 0; @@ -1656,10 +1649,10 @@ static void ota_update_status_resource() uint8_t *uuid = ota_parameters.ota_session_id; sprintf(status, - "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", - uuid[0], uuid[1], uuid[2], uuid[3], uuid[4], uuid[5], uuid[6], uuid[7], - uuid[8], uuid[9], uuid[10], uuid[11], uuid[12], uuid[13], uuid[14], uuid[15] - ); + "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", + uuid[0], uuid[1], uuid[2], uuid[3], uuid[4], uuid[5], uuid[6], uuid[7], + uuid[8], uuid[9], uuid[10], uuid[11], uuid[12], uuid[13], uuid[14], uuid[15] + ); if (ota_lib_config_data.device_type != OTA_DEVICE_TYPE_BORDER_ROUTER) { uint16_t missing_fragment_total_count = ota_get_missing_fragment_total_count(); @@ -1672,7 +1665,7 @@ static void ota_update_status_resource() ota_get_state(&status[strlen(status)]); tr_info("ota_update_status_resource - status %s", status); - if (ota_update_resource_value_fptr(MULTICAST_STATUS, (uint8_t*)status, strlen(status)) == 0) { + if (ota_update_resource_value_fptr(MULTICAST_STATUS, (uint8_t *)status, strlen(status)) == 0) { tr_err("ota_update_status_resource - failed to update status resource!"); } } @@ -1697,16 +1690,15 @@ static void ota_delete_process(uint8_t *session_id) ota_fw_update_received = false; - if (ota_parameters.fragments_bitmask_ptr != NULL) { - ota_free_fptr(ota_parameters.fragments_bitmask_ptr); - ota_parameters.fragments_bitmask_ptr = NULL; - } + ota_free_fptr(ota_parameters.fragments_bitmask_ptr); + ota_parameters.fragments_bitmask_ptr = NULL; - if (ota_checksum_calculating_ptr.ota_sha256_context_ptr != NULL) { - mbedtls_sha256_free(ota_checksum_calculating_ptr.ota_sha256_context_ptr); - ota_free_fptr(ota_checksum_calculating_ptr.ota_sha256_context_ptr); - ota_checksum_calculating_ptr.ota_sha256_context_ptr = NULL; - } + ota_free_fptr(ota_parameters.pull_url_ptr); + ota_parameters.pull_url_ptr = NULL; + + mbedtls_sha256_free(ota_checksum_calculating_ptr.ota_sha256_context_ptr); + ota_free_fptr(ota_checksum_calculating_ptr.ota_sha256_context_ptr); + ota_checksum_calculating_ptr.ota_sha256_context_ptr = NULL; memset(&ota_parameters, 0, sizeof(ota_parameters)); @@ -1715,8 +1707,8 @@ static void ota_delete_process(uint8_t *session_id) ota_update_resource_value_fptr(MULTICAST_READY, payload, 1); ota_update_resource_value_fptr(MULTICAST_SESSION_ID, - (uint8_t*)&ota_parameters.ota_session_id, - sizeof(ota_parameters.ota_session_id)); + (uint8_t *)&ota_parameters.ota_session_id, + sizeof(ota_parameters.ota_session_id)); ota_cancel_timer_fptr(OTA_CHECKSUM_CALCULATING_TIMER); ota_cancel_timer_fptr(OTA_FRAGMENTS_DELIVERING_TIMER); @@ -1754,8 +1746,10 @@ ota_error_code_e ota_send_multicast_command(ota_commands_e command, uint8_t *pay case OTA_CMD_MANIFEST: create_multicast_header(OTA_CMD_MANIFEST); - memcpy(socket_buf.ptr + 17, &payload_ptr[MULTICAST_CMD_SESSION_ID_INDEX + 16], payload_length - MULTICAST_CMD_SESSION_ID_INDEX + 16); - multicast_payload_len = payload_length - MULTICAST_CMD_SESSION_ID_INDEX + 16 + 5; + memcpy(&socket_buf.ptr[17], &payload_ptr[MULTICAST_CMD_SESSION_ID_INDEX + 16], payload_length - MULTICAST_CMD_SESSION_ID_INDEX + 16); + // version and command type bytes removed from the multicast message + multicast_payload_len = payload_length - 2; + tr_debug("Sending manifest command 1. time."); break; @@ -1776,17 +1770,21 @@ ota_error_code_e ota_send_multicast_command(ota_commands_e command, uint8_t *pay socket_buf.ptr[17] = OTA_DEVICE_TYPE_NODE; // Device type uint32_t reboot_delay = common_read_32_bit(&payload_ptr[19]); + + // In simulator case accept any activation delay from payload +#if !defined(__NANOSIMULATOR__) || !defined(MBED_CLOUD_CLIENT_MULTICAST_SMALL_NETWORK) if (reboot_delay < OTA_ONE_FRAGMENT_WAITTIME_SECS) { tr_warn("Given activation delay was too short: %" PRIu32 ". Changed it to minimum %" PRIu32 ".", reboot_delay, OTA_ONE_FRAGMENT_WAITTIME_SECS); reboot_delay = OTA_ONE_FRAGMENT_WAITTIME_SECS; } +#endif // __NANOSIMULATOR__ common_write_32_bit(reboot_delay, &socket_buf.ptr[18]); // Reboot delay multicast_payload_len = 22; tr_debug("Sending activate command with reboot delay %" PRIu32 "s.", reboot_delay); - } - break; + } + break; default: break; @@ -1824,7 +1822,7 @@ static void ota_send_estimated_resend_time(uint32_t resend_time_in_secs) ota_update_resource_value_fptr(MULTICAST_ESTIMATED_RESEND_TIME, payload, 21); } -static void ota_send_error(ota_error_code_e error) +void ota_send_error(ota_error_code_e error) { tr_info("ota_send_error() - error code: %d, session %s", error, tr_array(ota_parameters.ota_session_id, OTA_SESSION_ID_SIZE)); uint8_t payload[18]; @@ -1838,7 +1836,7 @@ static void ota_send_error(ota_error_code_e error) ota_update_resource_value_fptr(MULTICAST_READY, payload, 1); } -void ota_delete_session(uint8_t* session) +void ota_delete_session(uint8_t *session) { ota_delete_process(session); } diff --git a/multicast/multicast.cpp b/multicast/multicast.cpp index 7f8062c65..97e3e3baa 100644 --- a/multicast/multicast.cpp +++ b/multicast/multicast.cpp @@ -89,7 +89,7 @@ static ota_error_code_e arm_uc_multicast_start_received(ota_parameters_t *ota_pa static void arm_uc_multicast_process_finished(uint8_t *session_id); static bool read_dodag_info(char *dodag_address); static ota_error_code_e arm_uc_multicast_get_parent_addr(uint8_t *addr); -static void arm_uc_multicast_update_client_event(uintptr_t event_data); +static void arm_uc_multicast_update_client_event(struct arm_event_s *event); static void arm_uc_multicast_update_client_init(); static void arm_uc_multicast_update_client_external_update_event(struct arm_event_s *event); @@ -291,7 +291,12 @@ multicast_status_e arm_uc_multicast_init(M2MBaseList &list, ConnectorClient &cli tr_debug("arm_uc_multicast_init"); if (tasklet_id < 0) { - tr_error("Trying to pass invalid tasklet_id for arm_uc_multicast_init"); + tr_error("arm_uc_multicast_init - trying to pass invalid tasklet_id for arm_uc_multicast_init"); + return MULTICAST_STATUS_INIT_FAILED; + } + + if (arm_uc_multicast_interface_id < 0) { + tr_error("arm_uc_multicast_init - mesh interface not set!"); return MULTICAST_STATUS_INIT_FAILED; } @@ -357,7 +362,7 @@ void arm_uc_multicast_tasklet(struct arm_event_s *event) if (ARM_UC_OTA_MULTICAST_TIMER_EVENT == event->event_type) { ota_timer_expired(event->event_id); } else if (ARM_UC_OTA_MULTICAST_UPDATE_CLIENT_EVENT == event->event_type) { - arm_uc_multicast_update_client_event(event->event_data); + arm_uc_multicast_update_client_event(event); } else if (ARM_UC_OTA_MULTICAST_DL_DONE_EVENT == event->event_type) { tr_info("arm_uc_multicast_tasklet - download completed"); ota_firmware_pulled(); @@ -376,8 +381,8 @@ void arm_uc_multicast_tasklet(struct arm_event_s *event) arm_uc_multicast_event.data.priority = ARM_LIB_MED_PRIORITY_EVENT; arm_uc_multicast_event.data.receiver = arm_uc_multicast_tasklet_id; eventOS_event_send_user_allocated(&arm_uc_multicast_event); - } else { - tr_error("arm_uc_multicast_tasklet - unknown event!"); + } else if (ARM_UC_OTA_MULTICAST_INIT_EVENT != event->event_type) { + tr_error("arm_uc_multicast_tasklet - unknown event! (%d)", event->event_type); } } @@ -385,7 +390,7 @@ void arm_uc_multicast_network_connected() { char addr[45] = {0}; if (read_dodag_info(addr)) { - if(arm_uc_multicast_update_resource_value(MULTICAST_NETWORK_ID, reinterpret_cast(addr), strlen(addr)) == 2) { + if (arm_uc_multicast_update_resource_value(MULTICAST_NETWORK_ID, reinterpret_cast(addr), strlen(addr)) == 2) { // return value 2 means value actually changed from previous, so in netid case we need to trigger full // registration to update device directory tr_info("dodag info changed during network global up. triggering full register."); @@ -468,17 +473,16 @@ static void arm_uc_multicast_socket_callback(void *port) // Read from the right socket if ((intptr_t)port == OTA_SOCKET_MULTICAST_PORT) { status = pal_receiveFrom(arm_uc_multicast_socket, recv_buffer, RECEIVE_BUFFER_SIZE, &address, &addrlen, &recv); + // Skip data coming from multicast loop + if (arm_uc_multicast_send_in_progress) { + tr_info("arm_uc_multicast_socket_callback - multicast loopback data --> skip"); + arm_uc_multicast_send_in_progress = false; + return; + } } else { status = pal_receiveFrom(arm_uc_multicast_missing_frag_socket, recv_buffer, RECEIVE_BUFFER_SIZE, &address, &addrlen, &recv); } - // Skip data coming from multicast loop - if (arm_uc_multicast_send_in_progress) { - tr_info("arm_uc_multicast_socket_callback - multicast loopback data --> skip"); - arm_uc_multicast_send_in_progress = false; - return; - } - if (status == PAL_SUCCESS) { uint16_t recv_port; ota_ip_address_t ota_addr; @@ -548,7 +552,9 @@ static int8_t arm_uc_multicast_socket_send(ota_ip_address_t *destination, uint16 return -1; } - arm_uc_multicast_send_in_progress = true; + if (destination->port == OTA_SOCKET_MULTICAST_PORT) { + arm_uc_multicast_send_in_progress = true; + } return pal_sendTo(socket, payload, count, &pal_addr, sizeof(pal_addr), &sent); } @@ -895,7 +901,7 @@ static bool arm_uc_multicast_create_static_resources(M2MBaseList &list) if (!multicast_command_res) { tr_error("arm_uc_multicast_create_static_resources - failed to create multicast_command_res!"); return false; - } + } /*multicast_estimated_total_time_res = object_inst->create_static_resource(&arm_uc_multicast_estimated_total_time_res, M2MResourceInstance::OPAQUE); if (!multicast_estimated_total_time_res) { @@ -1170,7 +1176,7 @@ static void arm_uc_multicast_send_event(arm_uc_hub_state_t state) ota_error_code_e arm_uc_multicast_manifest_received(uint8_t *payload_ptr, uint32_t payload_len) { - if(ARM_UC_HUB_setManifest(payload_ptr, payload_len)) { + if (ARM_UC_HUB_setManifest(payload_ptr, payload_len)) { arm_uc_multicast_send_event(ARM_UC_HUB_STATE_MANIFEST_FETCHED); } @@ -1182,9 +1188,9 @@ void arm_uc_multicast_firmware_ready() arm_uc_multicast_send_event(ARM_UC_HUB_STATE_LAST_FRAGMENT_STORE_DONE); } -void arm_uc_multicast_update_client_event(uintptr_t event_data) +void arm_uc_multicast_update_client_event(struct arm_event_s *event) { - ARM_UC_HUB_setState((arm_uc_hub_state_t)event_data); + ARM_UC_HUB_setState((arm_uc_hub_state_t)event->event_data); } void arm_uc_multicast_update_client_external_update_event(struct arm_event_s *event) @@ -1327,8 +1333,8 @@ static ota_error_code_e arm_uc_multicast_start_received(ota_parameters_t *ota_pa fota_br_image_params.payload_size = ota_parameters->fw_total_byte_count; memcpy(fota_br_image_params.payload_digest, ota_parameters->whole_fw_checksum_tbl, OTA_WHOLE_FW_CHECKSUM_LENGTH); arm_uc_multicast_event.data.data_ptr = NULL; - arm_uc_multicast_event.data.event_data = MULTICAST_FOTA_EVENT_MANIFEST_RECEIVED; - arm_uc_multicast_event.data.event_id = 0; + arm_uc_multicast_event.data.event_data = 0; + arm_uc_multicast_event.data.event_id = MULTICAST_FOTA_EVENT_MANIFEST_RECEIVED; arm_uc_multicast_event.data.sender = 0; arm_uc_multicast_event.data.event_type = ARM_UC_OTA_MULTICAST_UPDATE_CLIENT_EVENT; arm_uc_multicast_event.data.priority = ARM_LIB_MED_PRIORITY_EVENT; @@ -1366,6 +1372,15 @@ static ota_error_code_e arm_uc_multicast_start_received(ota_parameters_t *ota_pa static void arm_uc_multicast_process_finished(uint8_t */*session_id*/) { tr_info("arm_uc_multicast_process_finished"); + arm_uc_multicast_event.data.data_ptr = NULL; + arm_uc_multicast_event.data.event_data = 0; + arm_uc_multicast_event.data.event_id = 0; + arm_uc_multicast_event.data.sender = 0; + arm_uc_multicast_event.data.event_type = ARM_UC_OTA_DELETE_SESSION_EVENT; + arm_uc_multicast_event.data.priority = ARM_LIB_MED_PRIORITY_EVENT; + arm_uc_multicast_event.data.receiver = arm_uc_multicast_tasklet_id; + + eventOS_event_send_user_allocated(&arm_uc_multicast_event); } /* @@ -1380,7 +1395,22 @@ ota_error_code_e arm_uc_multicast_manifest_received(uint8_t *payload_ptr, uint32 { int result = FOTA_STATUS_SUCCESS; #if defined(ARM_UC_MULTICAST_NODE_MODE) - result = fota_multicast_node_on_manifest(payload_ptr, payload_len, arm_uc_multicast_fota_multicast_node_post_manifest_received_action_callback); + uint8_t *payload = (uint8_t *)malloc(payload_len); + if (payload) { + memcpy(payload, payload_ptr, payload_len); + arm_uc_multicast_event.data.data_ptr = (void *)payload; + arm_uc_multicast_event.data.event_data = payload_len; + arm_uc_multicast_event.data.event_id = MULTICAST_FOTA_EVENT_MANIFEST_RECEIVED; + arm_uc_multicast_event.data.sender = 0; + arm_uc_multicast_event.data.event_type = ARM_UC_OTA_MULTICAST_UPDATE_CLIENT_EVENT; + arm_uc_multicast_event.data.priority = ARM_LIB_MED_PRIORITY_EVENT; + arm_uc_multicast_event.data.receiver = arm_uc_multicast_tasklet_id; + + eventOS_event_send_user_allocated(&arm_uc_multicast_event); + } else { + tr_error("arm_uc_multicast_manifest_received - failed to allocate memory"); + result = FOTA_STATUS_OUT_OF_MEMORY; + } #else (void)payload_ptr; (void)payload_len; @@ -1420,8 +1450,7 @@ void arm_uc_multicast_fota_multicast_node_post_manifest_received_action_callback if (result != FOTA_STATUS_SUCCESS) { tr_error("Error setting manifest to fota: %d", result); arm_uc_multicast_manifest_rejected = true; - } - else { + } else { tr_debug("Manifest set to fota."); arm_uc_multicast_manifest_rejected = false; } @@ -1442,8 +1471,7 @@ void arm_uc_multicast_fota_multicast_br_post_start_received_action_callback(int arm_uc_multicast_event.data.receiver = arm_uc_multicast_tasklet_id; eventOS_event_send_user_allocated(&arm_uc_multicast_event); - } - else { + } else { // TODO: abort libota? } } @@ -1451,23 +1479,29 @@ void arm_uc_multicast_fota_multicast_br_post_start_received_action_callback(int /* * Event queue callback for decoupling libota callbacks and Update client process */ -void arm_uc_multicast_update_client_event(uintptr_t event_data) +void arm_uc_multicast_update_client_event(struct arm_event_s *event) { -#if defined(ARM_UC_MULTICAST_BORDER_ROUTER_MODE) - multicast_fota_event fota_event = (multicast_fota_event)event_data; - switch(fota_event) { + multicast_fota_event fota_event = (multicast_fota_event)event->event_id; + + switch (fota_event) { case MULTICAST_FOTA_EVENT_MANIFEST_RECEIVED: +#if defined(ARM_UC_MULTICAST_BORDER_ROUTER_MODE) // TODO: check error code? fota_multicast_br_on_image_request(&fota_br_image_params, arm_uc_multicast_fota_multicast_br_post_start_received_action_callback); +#else + if (fota_multicast_node_on_manifest((uint8_t *)event->data_ptr, + event->event_data, + arm_uc_multicast_fota_multicast_node_post_manifest_received_action_callback) != FOTA_STATUS_SUCCESS) { + ota_send_error(OTA_PARAMETER_FAIL); + } + + free(event->data_ptr); +#endif // ARM_UC_MULTICAST_BORDER_ROUTER_MODE break; default: tr_error("Unknown event in arm_uc_multicast_update_client_event! (%d)", (int)fota_event); break; } -#else - (void)event_data; - tr_error("Unexpected call to arm_uc_multicast_update_client_event!"); -#endif } void arm_uc_multicast_update_client_external_update_event(struct arm_event_s *event) diff --git a/multicast/multicast.h b/multicast/multicast.h index 038c56ad5..946e6a2c0 100644 --- a/multicast/multicast.h +++ b/multicast/multicast.h @@ -22,6 +22,7 @@ #include "eventOS_event.h" #include "eventOS_event_timer.h" +#define ARM_UC_OTA_MULTICAST_INIT_EVENT 0 #define ARM_UC_OTA_MULTICAST_UPDATE_CLIENT_EVENT 1 #define ARM_UC_OTA_MULTICAST_TIMER_EVENT 2 #define ARM_UC_OTA_MULTICAST_DL_DONE_EVENT 3 diff --git a/multicast/otaLIB.h b/multicast/otaLIB.h index b8b6f2eaf..1ab688ecd 100644 --- a/multicast/otaLIB.h +++ b/multicast/otaLIB.h @@ -370,8 +370,18 @@ void ota_socket_receive_data(uint16_t payload_length, */ void ota_firmware_pulled(); +/** + * \brief A function to delete multicast session + * \param session Session identifier. + */ void ota_delete_session(uint8_t* session); +/** + * \brief A function to send an error to the backend + * \param error Error code to be sent. + */ +void ota_send_error(ota_error_code_e error); + #ifdef __cplusplus } #endif diff --git a/network-manager/source/NetworkManager.cpp b/network-manager/source/NetworkManager.cpp index dbc2b7cef..a51fc1c2b 100644 --- a/network-manager/source/NetworkManager.cpp +++ b/network-manager/source/NetworkManager.cpp @@ -125,7 +125,7 @@ static void nm_event_handler(arm_event_s *event) nm_error_t NetworkManager::configure_factory_mac_address(void *mesh_iface, void *backhaul_iface) { - if (nm_mesh_configure_factory_mac_address((NetworkInterface *)mesh_iface) == NM_STATUS_FAIL) { + if (nm_mesh_configure_factory_mac_address((WisunInterface *)mesh_iface) == NM_STATUS_FAIL) { tr_error("Could not configure Factory MAC Address on Mesh Interface"); return NM_ERROR_UNKNOWN; } @@ -140,7 +140,7 @@ nm_error_t NetworkManager::configure_factory_mac_address(void *mesh_iface, void nm_error_t NetworkManager::configure_factory_mac_address(void *mesh_iface) { - if (nm_mesh_configure_factory_mac_address((NetworkInterface *)mesh_iface) == NM_STATUS_FAIL) { + if (nm_mesh_configure_factory_mac_address((WisunInterface *)mesh_iface) == NM_STATUS_FAIL) { tr_error("Could not configure Factory MAC Address on Mesh Interface"); return NM_ERROR_UNKNOWN; } @@ -150,7 +150,7 @@ nm_error_t NetworkManager::configure_factory_mac_address(void *mesh_iface) nm_error_t NetworkManager::reg_and_config_iface(void *mesh_iface, void *backhaul_iface, void *br_iface) { - register_interfaces((NetworkInterface *)mesh_iface, (NetworkInterface *)backhaul_iface, (WisunBorderRouter *)br_iface); + register_interfaces((WisunInterface *)mesh_iface, (NetworkInterface *)backhaul_iface, (WisunBorderRouter *)br_iface); if (nm_factory_configure_mesh_iface() == NM_STATUS_FAIL) { tr_error("Could not SET Factory Configuration on Mesh Interface"); @@ -174,7 +174,7 @@ nm_error_t NetworkManager::reg_and_config_iface(void *mesh_iface, void *backhaul nm_error_t NetworkManager::reg_and_config_iface(void *mesh_iface) { - register_interfaces((NetworkInterface *)mesh_iface, NULL, NULL); + register_interfaces((WisunInterface *)mesh_iface, NULL, NULL); if (nm_factory_configure_mesh_iface() == NM_STATUS_FAIL) { tr_error("Could not SET Factory Configuration on Mesh Interface"); diff --git a/network-manager/source/include/NetworkManager_internal.h b/network-manager/source/include/NetworkManager_internal.h index 0c2d877b1..a5c7349de 100644 --- a/network-manager/source/include/NetworkManager_internal.h +++ b/network-manager/source/include/NetworkManager_internal.h @@ -32,7 +32,8 @@ typedef enum config { WS, BR, NM, - NI + NI, + NS } config_type_t; typedef enum nm_status { @@ -147,22 +148,34 @@ typedef struct { uint16_t pan_id; } ws_common_id_statistics_t; -/* Wi-Sun RPL Statistics */ +/* Wi-Sun mesh Statistics */ typedef struct { uint32_t rpl_total_memory; /*ws_rpl_statistics.rpl_total_memory); + encode_uint32_value(&map, ws_stats->ws_mesh_statistics.rpl_total_memory); } // asynch_tx_count if (encode_text_string(&map, CBOR_TAG_ASYNC_TX_CNT, sizeof(CBOR_TAG_ASYNC_TX_CNT) - 1)) { - encode_uint32_value(&map, ws_stats->ws_mac_statistics.asynch_tx_count); + encode_uint32_value(&map, ws_stats->ws_mesh_statistics.asynch_tx_count); } // asynch_rx_count if (encode_text_string(&map, CBOR_TAG_ASYNC_RX_CNT, sizeof(CBOR_TAG_ASYNC_RX_CNT) - 1)) { - encode_uint32_value(&map, ws_stats->ws_mac_statistics.asynch_rx_count); + encode_uint32_value(&map, ws_stats->ws_mesh_statistics.asynch_rx_count); + } + + // join_state_1 + if (encode_text_string(&map, CBOR_TAG_JOIN_STATE_1, sizeof(CBOR_TAG_JOIN_STATE_1) - 1)) { + encode_uint32_value(&map, ws_stats->ws_mesh_statistics.join_state_1); + } + + // join_state_2 + if (encode_text_string(&map, CBOR_TAG_JOIN_STATE_2, sizeof(CBOR_TAG_JOIN_STATE_2) - 1)) { + encode_uint32_value(&map, ws_stats->ws_mesh_statistics.join_state_2); + } + + // join_state_3 + if (encode_text_string(&map, CBOR_TAG_JOIN_STATE_3, sizeof(CBOR_TAG_JOIN_STATE_3) - 1)) { + encode_uint32_value(&map, ws_stats->ws_mesh_statistics.join_state_3); + } + + // join_state_4 + if (encode_text_string(&map, CBOR_TAG_JOIN_STATE_4, sizeof(CBOR_TAG_JOIN_STATE_4) - 1)) { + encode_uint32_value(&map, ws_stats->ws_mesh_statistics.join_state_4); + } + + // join_state_5 + if (encode_text_string(&map, CBOR_TAG_JOIN_STATE_5, sizeof(CBOR_TAG_JOIN_STATE_5) - 1)) { + encode_uint32_value(&map, ws_stats->ws_mesh_statistics.join_state_5); + } + + // sent_PAS + if (encode_text_string(&map, CBOR_TAG_SEND_PAS, sizeof(CBOR_TAG_SEND_PAS) - 1)) { + encode_uint32_value(&map, ws_stats->ws_mesh_statistics.sent_PAS); + } + + // sent_PA + if (encode_text_string(&map, CBOR_TAG_SEND_PA, sizeof(CBOR_TAG_SEND_PA) - 1)) { + encode_uint32_value(&map, ws_stats->ws_mesh_statistics.sent_PA); + } + + // sent_PCS + if (encode_text_string(&map, CBOR_TAG_SEND_PCS, sizeof(CBOR_TAG_SEND_PCS) - 1)) { + encode_uint32_value(&map, ws_stats->ws_mesh_statistics.sent_PCS); + } + + // sent_PC + if (encode_text_string(&map, CBOR_TAG_SEND_PC, sizeof(CBOR_TAG_SEND_PC) - 1)) { + encode_uint32_value(&map, ws_stats->ws_mesh_statistics.sent_PC); + } + + // recv_PAS + if (encode_text_string(&map, CBOR_TAG_RECV_PAS, sizeof(CBOR_TAG_RECV_PAS) - 1)) { + encode_uint32_value(&map, ws_stats->ws_mesh_statistics.recv_PAS); + } + + // recv_PA + if (encode_text_string(&map, CBOR_TAG_RECV_PA, sizeof(CBOR_TAG_RECV_PA) - 1)) { + encode_uint32_value(&map, ws_stats->ws_mesh_statistics.recv_PA); + } + + // recv_PCS + if (encode_text_string(&map, CBOR_TAG_RECV_PCS, sizeof(CBOR_TAG_RECV_PCS) - 1)) { + encode_uint32_value(&map, ws_stats->ws_mesh_statistics.recv_PCS); + } + + // recv_PC + if (encode_text_string(&map, CBOR_TAG_RECV_PC, sizeof(CBOR_TAG_RECV_PC) - 1)) { + encode_uint32_value(&map, ws_stats->ws_mesh_statistics.recv_PC); + } + + // neighbour_add + if (encode_text_string(&map, CBOR_TAG_NEIGHBOUR_ADD, sizeof(CBOR_TAG_NEIGHBOUR_ADD) - 1)) { + encode_uint32_value(&map, ws_stats->ws_mesh_statistics.neighbour_add); + } + + // neighbour_remove + if (encode_text_string(&map, CBOR_TAG_NEIGHBOUR_REMOVE, sizeof(CBOR_TAG_NEIGHBOUR_REMOVE) - 1)) { + encode_uint32_value(&map, ws_stats->ws_mesh_statistics.neighbour_remove); + } + + // child_add + if (encode_text_string(&map, CBOR_TAG_CHILD_ADD, sizeof(CBOR_TAG_CHILD_ADD) - 1)) { + encode_uint32_value(&map, ws_stats->ws_mesh_statistics.child_add); + } + + // child_remove + if (encode_text_string(&map, CBOR_TAG_CHILD_REMOVE, sizeof(CBOR_TAG_CHILD_REMOVE) - 1)) { + encode_uint32_value(&map, ws_stats->ws_mesh_statistics.child_remove); } // pan_id @@ -1182,6 +1296,136 @@ static nm_status_t node_stats_to_cbor(void *stats_ni, uint8_t *cbor_data, size_t return NM_STATUS_SUCCESS; } +static nm_status_t neighbor_stats_to_cbor(void *stats_ns, uint8_t *cbor_data, size_t *len) +{ + + CborError cbor_error = CborNoError; + CborEncoder encoder; + CborEncoder map; + CborEncoder stu_array; + CborEncoder remap; + + nbr_info_t *nbr_info = (nbr_info_t *)stats_ns; + + cbor_encoder_init(&encoder, cbor_data,(nbr_info->count * (sizeof(nm_ws_nbr_info_t)) + NEIGHBOR_INFO_MAX_ENCODING_BUFF(nbr_info->count)), 0); + + // Create map + cbor_error = cbor_encoder_create_map(&encoder, &map, CborIndefiniteLength); + if (cbor_error) { + tr_warn("Failed creating presence map with error code %d", cbor_error); + return NM_STATUS_FAIL; + } + + // neighbor_count + if (encode_text_string(&map, CBOR_TAG_NBR_COUNT, sizeof(CBOR_TAG_NBR_COUNT) - 1)) { + encode_uint32_value(&map, (uint32_t)nbr_info->count); + } + + if(nbr_info->count == 0) { + // Close map + cbor_error = cbor_encoder_close_container(&encoder, &map); + if (cbor_error) { + tr_warn("Failed closing presence map with error code %d", cbor_error); + return NM_STATUS_FAIL; + } + + size_t ret = cbor_encoder_get_buffer_size(&encoder, cbor_data); + tr_debug("Length of neighbor_info_to_cbor buffer is %d", ret); + *len = ret; + + return NM_STATUS_SUCCESS; + } + + // neighbor_info + if(encode_text_string(&map, CBOR_TAG_NBR_INFO, sizeof(CBOR_TAG_NBR_INFO) - 1)) { + + // Create array + cbor_error = cbor_encoder_create_array(&map, &stu_array, nbr_info->count); + if (cbor_error) { + tr_warn("Failed creating array for map with error code %d", cbor_error); + return NM_STATUS_FAIL; + } + + for (int i = 0; i < nbr_info->count; i++) { + // Create remap + cbor_error = cbor_encoder_create_map(&stu_array, &remap, CborIndefiniteLength); + if (cbor_error) { + tr_warn("Failed creating presence remap with error code %d", cbor_error); + return NM_STATUS_FAIL; + } + + // link_local_addr + if (encode_text_string(&remap, CBOR_TAG_NBR_LINK_LOCAL_ADDR, sizeof(CBOR_TAG_NBR_LINK_LOCAL_ADDR) - 1)) { + encode_byte_array(&remap, nbr_info->nbr_info_ptr[i].link_local_address, sizeof(nbr_info->nbr_info_ptr[i].link_local_address)); + } + + // global_addr + if (encode_text_string(&remap, CBOR_TAG_NBR_GLOGBAL_ADDR, sizeof(CBOR_TAG_NBR_GLOGBAL_ADDR) - 1)) { + encode_byte_array(&remap, nbr_info->nbr_info_ptr[i].global_address, sizeof(nbr_info->nbr_info_ptr[i].global_address)); + } + + // rsl_out + if (encode_text_string(&remap, CBOR_TAG_NBR_RSL_OUT, sizeof(CBOR_TAG_NBR_RSL_OUT) - 1)) { + encode_uint32_value(&remap, (uint32_t)nbr_info->nbr_info_ptr[i].rsl_out); + } + + // rsl_in + if (encode_text_string(&remap, CBOR_TAG_NBR_RSL_IN, sizeof(CBOR_TAG_NBR_RSL_IN) - 1)) { + encode_uint32_value(&remap, (uint32_t)nbr_info->nbr_info_ptr[i].rsl_in); + } + + // rpl_rank + if (encode_text_string(&remap, CBOR_TAG_NBR_RPL_RANK, sizeof(CBOR_TAG_NBR_RPL_RANK) - 1)) { + encode_uint32_value(&remap, (uint32_t)nbr_info->nbr_info_ptr[i].rpl_rank); + } + + // etx + if (encode_text_string(&remap, CBOR_TAG_NBR_ETX, sizeof(CBOR_TAG_NBR_ETX) - 1)) { + encode_uint32_value(&remap, (uint32_t)nbr_info->nbr_info_ptr[i].etx); + } + + // lifetime + if (encode_text_string(&remap, CBOR_TAG_NBR_LIFETIME, sizeof(CBOR_TAG_NBR_LIFETIME) - 1)) { + encode_uint32_value(&remap, (uint32_t)nbr_info->nbr_info_ptr[i].lifetime); + } + + // type + if (encode_text_string(&remap, CBOR_TAG_NBR_TYPE, sizeof(CBOR_TAG_NBR_TYPE) - 1)) { + encode_uint32_value(&remap, (uint32_t)nbr_info->nbr_info_ptr[i].type); + } + + // Close remap + cbor_error = cbor_encoder_close_container(&stu_array, &remap); + if (cbor_error) { + tr_debug("Failed closing presence remap with error code %d", cbor_error); + return NM_STATUS_FAIL; + } + } + + // Close array + cbor_error = cbor_encoder_close_container(&map, &stu_array); + if (cbor_error) { + tr_warn("Failed closing presence array of map with error code %d", cbor_error); + return NM_STATUS_FAIL; + } + + // Close map + cbor_error = cbor_encoder_close_container(&encoder, &map); + if (cbor_error) { + tr_warn("Failed closing presence map with error code %d", cbor_error); + return NM_STATUS_FAIL; + } + + } + + size_t ret = cbor_encoder_get_buffer_size(&encoder, cbor_data); + tr_debug("Length of neighbor_info_to_cbor buffer is %d", ret); + *len = ret; + + return NM_STATUS_SUCCESS; +} + + nm_status_t nm_statistics_to_cbor(void *stats, uint8_t *cbor_data, config_type_t type, size_t *len) { nm_status_t status = NM_STATUS_FAIL; @@ -1219,6 +1463,12 @@ nm_status_t nm_statistics_to_cbor(void *stats, uint8_t *cbor_data, config_type_t tr_info("NI statistics cbor encoder fail"); } break; + case NS: + status = neighbor_stats_to_cbor(stats, cbor_data, len); + if (status) { + tr_info("Neighbor statistics cbor encoder fail"); + } + break; } return status; } diff --git a/network-manager/source/nm_interface_manager.cpp b/network-manager/source/nm_interface_manager.cpp index 564d7972f..c525c16d4 100644 --- a/network-manager/source/nm_interface_manager.cpp +++ b/network-manager/source/nm_interface_manager.cpp @@ -39,6 +39,7 @@ #define NM_STAT_MAX_BUF NM_STAT_MAX_ENCODER_BUF #define BR_STAT_MAX_BUF BR_STAT_MAX_ENCODER_BUF #define NI_STAT_MAX_BUF NI_STAT_MAX_ENCODER_BUF +#define NS_STAT_MAX_BUF NS_STAT_MAX_ENCODER_BUF #define DEFAULT_CONFIG_DELAY 0 #define MESH_MAC_ADDR_LEN 8 @@ -86,10 +87,10 @@ static nm_status_t nm_iface_kvstore_read_cfg(char *key, void *struct_val, config return status; } -void register_interfaces(NetworkInterface *mesh_iface, NetworkInterface *backhaul_iface, WisunBorderRouter *br_iface) +void register_interfaces(WisunInterface *mesh_iface, NetworkInterface *backhaul_iface, WisunBorderRouter *br_iface) { backhaul_interface = backhaul_iface; - ws_iface = reinterpret_cast(mesh_iface); + ws_iface = mesh_iface; ws_br = br_iface; } @@ -467,7 +468,7 @@ nm_status_t string2hex_mac_address(uint8_t **mac_addr, uint8_t *recv_buffer, uin return NM_STATUS_SUCCESS; } -nm_status_t nm_mesh_configure_factory_mac_address(NetworkInterface *mesh_iface) +nm_status_t nm_mesh_configure_factory_mac_address(WisunInterface *mesh_iface) { #if ((MBED_VERSION >= MBED_ENCODE_VERSION(6, 8, 0)) || ((MBED_VERSION < MBED_ENCODE_VERSION(6, 0, 0)) && (MBED_VERSION >= MBED_ENCODE_VERSION(5, 15, 7)))) uint8_t *mesh_mac_address = NULL; @@ -772,9 +773,28 @@ nm_status_t nm_res_get_ws_stats(uint8_t **datap, size_t *length) return NM_STATUS_FAIL; } - ws_stats.ws_rpl_statistics.rpl_total_memory = ws_stats_temp.rpl_total_memory; - ws_stats.ws_mac_statistics.asynch_rx_count = ws_stats_temp.asynch_rx_count; - ws_stats.ws_mac_statistics.asynch_tx_count = ws_stats_temp.asynch_tx_count; + ws_stats.ws_mesh_statistics.rpl_total_memory = ws_stats_temp.rpl_total_memory; + ws_stats.ws_mesh_statistics.asynch_rx_count = ws_stats_temp.asynch_rx_count; + ws_stats.ws_mesh_statistics.asynch_tx_count = ws_stats_temp.asynch_tx_count; +#if ((MBED_VERSION > MBED_ENCODE_VERSION(6, 10, 0)) || ((MBED_VERSION < MBED_ENCODE_VERSION(6, 0, 0)) && (MBED_VERSION > MBED_ENCODE_VERSION(5, 15, 7)))) + ws_stats.ws_mesh_statistics.join_state_1 = ws_stats_temp.join_state_1; + ws_stats.ws_mesh_statistics.join_state_2 = ws_stats_temp.join_state_2; + ws_stats.ws_mesh_statistics.join_state_3 = ws_stats_temp.join_state_3; + ws_stats.ws_mesh_statistics.join_state_4 = ws_stats_temp.join_state_4; + ws_stats.ws_mesh_statistics.join_state_5 = ws_stats_temp.join_state_5; + ws_stats.ws_mesh_statistics.sent_PAS = ws_stats_temp.sent_PAS; + ws_stats.ws_mesh_statistics.sent_PA = ws_stats_temp.sent_PA; + ws_stats.ws_mesh_statistics.sent_PCS = ws_stats_temp.sent_PCS; + ws_stats.ws_mesh_statistics.sent_PC = ws_stats_temp.sent_PC; + ws_stats.ws_mesh_statistics.recv_PAS = ws_stats_temp.recv_PAS; + ws_stats.ws_mesh_statistics.recv_PA = ws_stats_temp.recv_PA; + ws_stats.ws_mesh_statistics.recv_PCS = ws_stats_temp.recv_PCS; + ws_stats.ws_mesh_statistics.recv_PC = ws_stats_temp.recv_PC; + ws_stats.ws_mesh_statistics.neighbour_add = ws_stats_temp.Neighbour_add; + ws_stats.ws_mesh_statistics.neighbour_remove = ws_stats_temp.Neighbour_remove; + ws_stats.ws_mesh_statistics.child_add = ws_stats_temp.Child_add; + ws_stats.ws_mesh_statistics.child_remove = ws_stats_temp.child_remove; +#endif memcpy(ws_stats.ws_common_id_statistics.rpl_dodag_id, rpl_stats_temp.rpl_dodag_id, sizeof(rpl_stats_temp.rpl_dodag_id)); ws_stats.ws_common_id_statistics.instance_id = rpl_stats_temp.instance_id; @@ -910,9 +930,9 @@ nm_status_t nm_res_get_ch_noise_stats(uint8_t **datap, size_t *length) return NM_STATUS_SUCCESS; } +#if ((MBED_VERSION > MBED_ENCODE_VERSION(6, 10, 0)) || ((MBED_VERSION < MBED_ENCODE_VERSION(6, 0, 0)) && (MBED_VERSION > MBED_ENCODE_VERSION(5, 15, 7)))) nm_status_t nm_reset_parameters(void) { -#if ((MBED_VERSION > MBED_ENCODE_VERSION(6, 10, 0)) || ((MBED_VERSION < MBED_ENCODE_VERSION(6, 0, 0)) && (MBED_VERSION > MBED_ENCODE_VERSION(5, 15, 7)))) if (ws_iface == NULL) { tr_warn("FAILED: Wi-SUN Interface is not initialized yet"); return NM_STATUS_FAIL; @@ -924,11 +944,62 @@ nm_status_t nm_reset_parameters(void) } else { tr_info("Reset Parameter Success"); } -#else - tr_warn("Not supported in this version"); -#endif return NM_STATUS_SUCCESS; } + +nm_status_t nm_res_get_nbr_info_stats(uint8_t **datap, size_t *length) +{ + nbr_info_t nw_nbr_info = {'\0'}; + + if (ws_iface == NULL) { + tr_warn("FAILED: Wi-SUN Interface is not initialized yet"); + return NM_STATUS_FAIL; + } + + /* Get neighbors count first to allocate dynamic memory allocation */ + if (ws_iface->nbr_info_get(NULL, &nw_nbr_info.count) != MESH_ERROR_NONE) { + tr_warn("FAILED to read Neighbors count info from Nanostack"); + return NM_STATUS_FAIL; + } + + if(nw_nbr_info.count != 0 ){ + + nw_nbr_info.nbr_info_ptr = (nm_ws_nbr_info_t *)nm_dyn_mem_alloc(nw_nbr_info.count * (sizeof(nm_ws_nbr_info_t))); + if (nw_nbr_info.nbr_info_ptr == NULL) { + tr_warn("FAILED to allocate memory for neighbor information"); + return NM_STATUS_FAIL; + } + + /* Get neighbors information*/ + if (ws_iface->nbr_info_get((ws_nbr_info_t *)(nw_nbr_info.nbr_info_ptr), &nw_nbr_info.count) != MESH_ERROR_NONE) { + /* Free dynamically allocated memory */ + nm_dyn_mem_free(nw_nbr_info.nbr_info_ptr); + tr_warn("FAILED to read Neighbors info from Nanostack"); + return NM_STATUS_FAIL; + } + } + + *datap = (uint8_t *)nm_dyn_mem_alloc(((nw_nbr_info.count * (sizeof(nm_ws_nbr_info_t))) + NEIGHBOR_INFO_MAX_ENCODING_BUFF(nw_nbr_info.count))); + if (*datap == NULL) { + tr_warn("FAILED to allocate memory to CBORise data for neighbors information"); + /* Free dynamically allocated memory */ + nm_dyn_mem_free(nw_nbr_info.nbr_info_ptr); + return NM_STATUS_FAIL; + } + + if (nm_statistics_to_cbor(&nw_nbr_info, *datap, NS, length) == NM_STATUS_FAIL) { + tr_warn("FAILED to CBORise Wi-SUN Statistics"); + /* Free dynamically allocated memory */ + nm_dyn_mem_free(nw_nbr_info.nbr_info_ptr); + nm_dyn_mem_free(*datap); + return NM_STATUS_FAIL; + } + + /* Free dynamically allocated memory */ + nm_dyn_mem_free(nw_nbr_info.nbr_info_ptr); + return NM_STATUS_SUCCESS; +} +#endif //((MBED_VERSION > MBED_ENCODE_VERSION(6, 10, 0)) || ((MBED_VERSION < MBED_ENCODE_VERSION(6, 0, 0)) && (MBED_VERSION > MBED_ENCODE_VERSION(5, 15, 7)))) /************************************************************************/ diff --git a/network-manager/source/nm_resource_manager.cpp b/network-manager/source/nm_resource_manager.cpp index 654600240..92e9b9956 100644 --- a/network-manager/source/nm_resource_manager.cpp +++ b/network-manager/source/nm_resource_manager.cpp @@ -46,7 +46,10 @@ static M2MResource *nm_stats; static M2MResource *br_stats; static M2MResource *node_stats; static M2MResource *ch_noise; +#if ((MBED_VERSION > MBED_ENCODE_VERSION(6, 10, 0)) || ((MBED_VERSION < MBED_ENCODE_VERSION(6, 0, 0)) && (MBED_VERSION > MBED_ENCODE_VERSION(5, 15, 7)))) static M2MResource *reset_parameter; +static M2MResource *nbr_info; +#endif typedef struct { M2MResource *res_obj; @@ -66,8 +69,12 @@ static uint8_t *ch_noise_buf = NULL; static uint8_t *br_stats_buf = NULL; static uint8_t *routing_table_buf = NULL; static uint8_t *node_stats_buf = NULL; +#if ((MBED_VERSION > MBED_ENCODE_VERSION(6, 10, 0)) || ((MBED_VERSION < MBED_ENCODE_VERSION(6, 0, 0)) && (MBED_VERSION > MBED_ENCODE_VERSION(5, 15, 7)))) +static uint8_t *nbr_info_buf = NULL; +#endif static uint8_t *res_data = NULL; + /* Function to overcome limitation of 32 bytes of length in tr_array */ static void print_stream(uint8_t *datap, uint32_t datal) { @@ -125,6 +132,7 @@ static void br_config_cb(const char * /*object_name*/) nm_post_event(NM_EVENT_RESOURCE_SET, 0, res_data); } +#if ((MBED_VERSION > MBED_ENCODE_VERSION(6, 10, 0)) || ((MBED_VERSION < MBED_ENCODE_VERSION(6, 0, 0)) && (MBED_VERSION > MBED_ENCODE_VERSION(5, 15, 7)))) static void reset_parameter_cb(const char * /*object_name*/) { res_set_data_t *res_data = (res_set_data_t *)nm_dyn_mem_alloc(sizeof(res_set_data_t)); @@ -137,6 +145,7 @@ static void reset_parameter_cb(const char * /*object_name*/) res_data->data = NULL; nm_post_event(NM_EVENT_RESOURCE_SET, 0, res_data); } +#endif static nm_status_t nm_res_get_ws_config_from_kvstore(uint8_t **datap, size_t *length) { @@ -255,6 +264,11 @@ static coap_response_code_e resource_read_requested(const M2MResourceBase &resou } else if (obj == node_stats) { status = nm_res_get_node_stats(&node_stats_buf, &len); res_data = node_stats_buf; +#if ((MBED_VERSION > MBED_ENCODE_VERSION(6, 10, 0)) || ((MBED_VERSION < MBED_ENCODE_VERSION(6, 0, 0)) && (MBED_VERSION > MBED_ENCODE_VERSION(5, 15, 7)))) + } else if (obj == nbr_info) { + status = nm_res_get_nbr_info_stats(&nbr_info_buf, &len); + res_data = nbr_info_buf; +#endif } else { tr_err("FAILED: Unknown client_args received in %s", __func__); } @@ -342,6 +356,14 @@ void msg_delivery_handle(const M2MBase &base, node_stats_buf = NULL; tr_debug("node_stats data Memory freed"); } +#if ((MBED_VERSION > MBED_ENCODE_VERSION(6, 10, 0)) || ((MBED_VERSION < MBED_ENCODE_VERSION(6, 0, 0)) && (MBED_VERSION > MBED_ENCODE_VERSION(5, 15, 7)))) + } else if (obj == nbr_info) { + if (nbr_info_buf != NULL) { + nm_dyn_mem_free(nbr_info_buf); + nbr_info_buf = NULL; + tr_debug("nbr_info data Memory freed"); + } +#endif } else { tr_err("FAILED: Unknown client_args received in %s", __func__); } @@ -391,12 +413,19 @@ nm_status_t nm_res_manager_create(void *obj_list) ch_noise->set_read_resource_function(resource_read_requested, ch_noise); ch_noise->set_observable(true); +#if ((MBED_VERSION > MBED_ENCODE_VERSION(6, 10, 0)) || ((MBED_VERSION < MBED_ENCODE_VERSION(6, 0, 0)) && (MBED_VERSION > MBED_ENCODE_VERSION(5, 15, 7)))) reset_parameter = M2MInterfaceFactory::create_resource(*m2m_obj_list, 33455, 0, 8, M2MResourceInstance::OPAQUE, M2MBase::PUT_ALLOWED); if (reset_parameter->set_value_updated_function(reset_parameter_cb) != true) { tr_error("reset_parameter->set_value_updated_function() failed"); return NM_STATUS_FAIL; } + nbr_info = M2MInterfaceFactory::create_resource(*m2m_obj_list, 33455, 0, 11, M2MResourceInstance::OPAQUE, M2MBase::GET_ALLOWED); + nbr_info->set_message_delivery_status_cb(msg_delivery_handle, nbr_info); + nbr_info->set_read_resource_function(resource_read_requested, nbr_info); + nbr_info->set_observable(true); +#endif + if (MBED_CONF_MBED_MESH_API_WISUN_DEVICE_TYPE == MESH_DEVICE_TYPE_WISUN_BORDER_ROUTER) { br_stats = M2MInterfaceFactory::create_resource(*m2m_obj_list, 33455, 0, 6, M2MResourceInstance::OPAQUE, M2MBase::GET_ALLOWED); br_stats->set_message_delivery_status_cb(msg_delivery_handle, br_stats); @@ -540,6 +569,24 @@ nm_status_t nm_res_manager_get(void *resource_object) return NM_STATUS_FAIL; } +#if ((MBED_VERSION > MBED_ENCODE_VERSION(6, 10, 0)) || ((MBED_VERSION < MBED_ENCODE_VERSION(6, 0, 0)) && (MBED_VERSION > MBED_ENCODE_VERSION(5, 15, 7)))) + if (res_obj == nbr_info) { + if (nm_res_get_nbr_info_stats(&buf, &len) == NM_STATUS_SUCCESS) { + tr_info("Setting value of resource nbr_info [len = %u] in Cloud Client", len); + print_stream(buf, len); + if (res_obj->set_value(buf, len) != true) { + tr_warn("FAILED to set Neighbor Info. resource to Cloud Client"); + return NM_STATUS_FAIL; + } + tr_info("Neighbor Info. resource value Set to Cloud Client"); + nm_dyn_mem_free(buf); + return NM_STATUS_SUCCESS; + } + tr_warn("FAILED to fetch Neighbor Info."); + return NM_STATUS_FAIL; + } +#endif + return NM_STATUS_FAIL; } @@ -574,6 +621,7 @@ nm_status_t nm_res_manager_set(void *resource_data) return NM_STATUS_SUCCESS; } +#if ((MBED_VERSION > MBED_ENCODE_VERSION(6, 10, 0)) || ((MBED_VERSION < MBED_ENCODE_VERSION(6, 0, 0)) && (MBED_VERSION > MBED_ENCODE_VERSION(5, 15, 7)))) if (res_data->res_obj == reset_parameter) { if(nm_reset_parameters() == NM_STATUS_FAIL) { @@ -585,6 +633,7 @@ nm_status_t nm_res_manager_set(void *resource_data) return NM_STATUS_SUCCESS; } +#endif /* To-Do :: Implement for other resources */ return NM_STATUS_FAIL; @@ -596,6 +645,9 @@ void nm_manager_res_refresh(void) nm_post_event(NM_EVENT_RESOURCE_GET, 0, nm_stats); nm_post_event(NM_EVENT_RESOURCE_GET, 0, ws_stats); nm_post_event(NM_EVENT_RESOURCE_GET, 0, ch_noise); +#if ((MBED_VERSION > MBED_ENCODE_VERSION(6, 10, 0)) || ((MBED_VERSION < MBED_ENCODE_VERSION(6, 0, 0)) && (MBED_VERSION > MBED_ENCODE_VERSION(5, 15, 7)))) + nm_post_event(NM_EVENT_RESOURCE_GET, 0, nbr_info); +#endif if (MBED_CONF_MBED_MESH_API_WISUN_DEVICE_TYPE == MESH_DEVICE_TYPE_WISUN_BORDER_ROUTER) { nm_post_event(NM_EVENT_RESOURCE_GET, 0, br_stats); nm_post_event(NM_EVENT_RESOURCE_GET, 0, routing_table); diff --git a/source/ConnectorClient.cpp b/source/ConnectorClient.cpp index 7c177a88c..25e68376c 100644 --- a/source/ConnectorClient.cpp +++ b/source/ConnectorClient.cpp @@ -436,6 +436,15 @@ bool ConnectorClient::create_bootstrap_object() tr_info("ConnectorClient::create_bootstrap_object - M2MServerUri %.*s", (int)real_size, buffer); if (_security->set_resource_value(M2MSecurity::M2MServerUri, buffer, real_size, bs_id)) { success = true; + String server_uri = String((const char *)buffer, real_size); + tr_info("ConnectorClient::create_bootstrap_object check security mode"); + if (!strstr(server_uri.c_str(),"coaps")) { + success = false; + if (_security->set_resource_value(M2MSecurity::SecurityMode, M2MSecurity::NoSecurity, bs_id)) { + tr_info("ConnectorClient::create_bootstrap_object set no security mode"); + success = true; + } + } } } } @@ -678,6 +687,8 @@ bool ConnectorClient::create_register_object() success = true; } + tr_debug("ConnectorClient::create_register_object() - success %d", success); + // Add ResourceID's and values to the security ObjectID/ObjectInstance if (success) { success = false; @@ -691,7 +702,7 @@ bool ConnectorClient::create_register_object() } // Endpoint - if (success) { + if (success && _endpoint_info.mode != M2MSecurity::NoSecurity) { success = false; // 64 characters for common name + 1 for null terminator char device_id[65]; @@ -1189,29 +1200,38 @@ ccs_status_e ConnectorClient::set_connector_credentials(M2MSecurity *security) if (m2m_id == -1) { return status; } + uint32_t sec_mode = _security->resource_value_int(M2MSecurity::SecurityMode, m2m_id); + _endpoint_info.mode = (M2MSecurity::SecurityModeType)sec_mode; size_t buffer_size = MAX_CERTIFICATE_SIZE; uint8_t public_key[MAX_CERTIFICATE_SIZE]; uint8_t *public_key_ptr = (uint8_t *)&public_key; - // TODO! Update to use chain api - if (security->resource_value_buffer(M2MSecurity::PublicKey, public_key_ptr, m2m_id, &buffer_size) != 0) { - return status; - } - char device_id[64]; - memset(device_id, 0, 64); - if (extract_field_from_certificate(public_key, buffer_size, "L", device_id)) { - tr_info("ConnectorClient::set_connector_credentials - L internal_endpoint_name : %s", device_id); - _endpoint_info.internal_endpoint_name = String(device_id); - ccs_delete_item(KEY_INTERNAL_ENDPOINT, CCS_CONFIG_ITEM); - status = ccs_set_item(KEY_INTERNAL_ENDPOINT, (uint8_t *)device_id, strlen(device_id), CCS_CONFIG_ITEM); - } - memset(device_id, 0, 64); - if (extract_field_from_certificate(public_key, buffer_size, "CN", device_id)) { - tr_info("ConnectorClient::set_connector_credentials - CN endpoint_name : %s", device_id); - _endpoint_info.endpoint_name = String(device_id); + if (sec_mode != M2MSecurity::NoSecurity) { + + // TODO! Update to use chain api + if (security->resource_value_buffer(M2MSecurity::PublicKey, public_key_ptr, m2m_id, &buffer_size) != 0) { + return status; + } + + char device_id[64]; + memset(device_id, 0, 64); + if (extract_field_from_certificate(public_key, buffer_size, "L", device_id)) { + tr_info("ConnectorClient::set_connector_credentials - L internal_endpoint_name : %s", device_id); + _endpoint_info.internal_endpoint_name = String(device_id); + ccs_delete_item(KEY_INTERNAL_ENDPOINT, CCS_CONFIG_ITEM); + status = ccs_set_item(KEY_INTERNAL_ENDPOINT, (uint8_t *)device_id, strlen(device_id), CCS_CONFIG_ITEM); + } + + memset(device_id, 0, 64); + if (extract_field_from_certificate(public_key, buffer_size, "CN", device_id)) { + tr_info("ConnectorClient::set_connector_credentials - CN endpoint_name : %s", device_id); + _endpoint_info.endpoint_name = String(device_id); + } + } else { + status = CCS_STATUS_SUCCESS; } if (status == CCS_STATUS_SUCCESS) { @@ -1529,7 +1549,9 @@ void ConnectorClient::bootstrap_again() { if (!_rebootstrap_time_initialized) { randLIB_seed_random(); - _rebootstrap_time = randLIB_get_random_in_range(1, 10); + // TODO: this should use stagger/rtt logic instead. + // Using reasonable calm backoff if hitting rebootstrapping timers. + _rebootstrap_time = randLIB_get_random_in_range(20, 100); _rebootstrap_time_initialized = true; } @@ -1569,6 +1591,11 @@ void ConnectorClient::alert_mode() _callback->registration_process_result(ConnectorClient::State_Alert_Mode); } +void ConnectorClient::sleep() +{ + _callback->registration_process_result(ConnectorClient::State_Sleep); +} + bool ConnectorClient::bootstrapped() { if (connector_credentials_available() || !use_bootstrap()) { diff --git a/source/MbedCloudClient.cpp b/source/MbedCloudClient.cpp index c7334faf1..23789c2d1 100755 --- a/source/MbedCloudClient.cpp +++ b/source/MbedCloudClient.cpp @@ -313,6 +313,8 @@ void MbedCloudClient::complete(ServiceClientCallbackStatus status) _on_status_changed.call(Paused); } else if (status == Service_Client_Status_Alert_Mode) { _on_status_changed.call(AlertMode); + } else if (status == Service_Client_Status_Sleep) { + _on_status_changed.call(Sleep); } // ToDo: should we have some handling for Service_Client_Status_Failure } diff --git a/source/ServiceClient.cpp b/source/ServiceClient.cpp index f3a97fb99..58368a824 100644 --- a/source/ServiceClient.cpp +++ b/source/ServiceClient.cpp @@ -21,7 +21,7 @@ #ifndef __STDC_FORMAT_MACROS #define __STDC_FORMAT_MACROS #endif - +#include "MbedCloudClient.h" #include "include/ServiceClient.h" #include "include/CloudClientStorage.h" @@ -40,6 +40,7 @@ #include "fota/fota_internal_ifs.h" #include "mbed-cloud-client/MbedCloudClientConfig.h" + #ifndef MBED_CONF_MBED_CLOUD_CLIENT_DISABLE_CERTIFICATE_ENROLLMENT #include "CertificateEnrollmentClient.h" #endif // MBED_CONF_MBED_CLOUD_CLIENT_DISABLE_CERTIFICATE_ENROLLMENT @@ -71,6 +72,18 @@ const uint8_t ServiceClient::hex_table[16] = { '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; +#define SERVICE_CLIENT_TASKLET_INIT_EVENT 0 +#define SERVICE_CLIENT_TASKLET_COMPLETE_EVENT 1 + +extern "C" void service_client_tasklet_func(arm_event_s *event) +{ + event->event_id = 0; + if (event->event_type == SERVICE_CLIENT_TASKLET_COMPLETE_EVENT) { + ServiceClientCallback *callback = (ServiceClientCallback *)event->data_ptr; + callback->complete((ServiceClientCallback::ServiceClientCallbackStatus)event->event_data); + } +} + ServiceClient::ServiceClient(ServiceClientCallback &callback) : _service_callback(callback), _service_uri(NULL), @@ -86,7 +99,8 @@ ServiceClient::ServiceClient(ServiceClientCallback &callback) #ifdef SERVICE_CLIENT_SUPPORT_MULTICAST _multicast_tasklet_id(-1), #endif // MBED_CLOUD_CLIENT_SUPPORT_MULTICAST_UPDATE - _connector_client(this) + _connector_client(this), + _tasklet_id(-1) { } @@ -115,6 +129,14 @@ bool ServiceClient::init() // The ns_hal_init() needs to be called by someone before create_interface(), // as it will also initialize the tasklet. ns_hal_init(NULL, MBED_CLIENT_EVENT_LOOP_SIZE, NULL, NULL); + if (_tasklet_id < 0) { + _tasklet_id = eventOS_event_handler_create(service_client_tasklet_func, SERVICE_CLIENT_TASKLET_INIT_EVENT); + if (_tasklet_id < 0) { + tr_error("ServiceClient::init - failed to create tasklet (%d)", _tasklet_id); + _service_callback.error((int)MbedCloudClient::ConnectMemoryConnectFail, "Failed to create event handler"); + return false; + } + } #if defined(MBED_CLOUD_CLIENT_SUPPORT_UPDATE) && !defined(MBED_CLOUD_CLIENT_FOTA_ENABLE) if (_uc_hub_tasklet_id < 0) { _uc_hub_tasklet_id = eventOS_event_handler_create(UpdateClient::event_handler, UpdateClient::UPDATE_CLIENT_EVENT_CREATE); @@ -134,7 +156,7 @@ bool ServiceClient::init() #endif // defined(MBED_CLOUD_CLIENT_SUPPORT_UPDATE) && !defined(MBED_CLOUD_CLIENT_FOTA_ENABLE) #ifdef SERVICE_CLIENT_SUPPORT_MULTICAST if (_multicast_tasklet_id < 0) { - _multicast_tasklet_id = eventOS_event_handler_create(&arm_uc_multicast_tasklet, 0); + _multicast_tasklet_id = eventOS_event_handler_create(&arm_uc_multicast_tasklet, ARM_UC_OTA_MULTICAST_INIT_EVENT); if (_multicast_tasklet_id < 0) { tr_error("ServiceClient::init - failed to create multicast event handler (%d)", _multicast_tasklet_id); #ifdef MBED_CLOUD_CLIENT_SUPPORT_UPDATE @@ -145,6 +167,10 @@ bool ServiceClient::init() } #endif // SERVICE_CLIENT_SUPPORT_MULTICAST + memset(&_event, 0, sizeof(_event)); + _event.data.priority = ARM_LIB_MED_PRIORITY_EVENT; + _event.data.receiver = _tasklet_id; + return true; } @@ -408,15 +434,19 @@ void ServiceClient::registration_process_result(ConnectorClient::StartupSubState #if defined(MBED_CLOUD_CLIENT_FOTA_ENABLE) fota_internal_resume(); #endif - _service_callback.complete(ServiceClientCallback::Service_Client_Status_Register_Updated); + send_complete_event(ServiceClientCallback::Service_Client_Status_Register_Updated); break; case ConnectorClient::State_Paused: - _service_callback.complete(ServiceClientCallback::Service_Client_Status_Paused); + send_complete_event(ServiceClientCallback::Service_Client_Status_Paused); break; case ConnectorClient::State_Alert_Mode: - _service_callback.complete(ServiceClientCallback::Service_Client_Status_Alert_Mode); + send_complete_event(ServiceClientCallback::Service_Client_Status_Alert_Mode); + break; + + case ConnectorClient::State_Sleep: + send_complete_event(ServiceClientCallback::Service_Client_Status_Sleep); break; default: @@ -435,16 +465,15 @@ void ServiceClient::connector_error(M2MInterface::Error error, const char *reaso else if (_current_state == State_Bootstrap) { registration_process_result(ConnectorClient::State_Bootstrap_Failure); } - // Client is in State_Failure and failing to bootstrap on InvalidCertificates. - // Factory reset the credentials to clear invalid/broken certificates and try again. - else if (_current_state == State_Failure && (error == M2MInterface::InvalidCertificates - || error == M2MInterface::FailedToStoreCredentials + // Client is in State_Failure and failing to bootstrap due to storage failures. + // Factory reset the credentials to clear invalid/broken certificates and re-bootstrap. + else if (_current_state == State_Failure && (error == M2MInterface::FailedToStoreCredentials || error == M2MInterface::FailedToReadCredentials)) { _connector_client.factory_reset_credentials(); _connector_client.bootstrap_again(); } // Client is in State Failure and fails bootstrap in invalid parameters. - // Try to recover with rebootstrapping. + // Try to recover with re-bootstrapping. else if (_current_state == State_Failure && error == M2MInterface::InvalidParameters) { _connector_client.bootstrap_again(); } @@ -480,19 +509,19 @@ void ServiceClient::state_success() { tr_info("ServiceClient::state_success()"); // this is verified already at client API level, but this might still catch some logic failures - _service_callback.complete(ServiceClientCallback::Service_Client_Status_Registered); + send_complete_event(ServiceClientCallback::Service_Client_Status_Registered); } void ServiceClient::state_failure() { tr_error("ServiceClient::state_failure()"); - _service_callback.complete(ServiceClientCallback::Service_Client_Status_Failure); + send_complete_event(ServiceClientCallback::Service_Client_Status_Failure); } void ServiceClient::state_unregister() { tr_debug("ServiceClient::state_unregister()"); - _service_callback.complete(ServiceClientCallback::Service_Client_Status_Unregistered); + send_complete_event(ServiceClientCallback::Service_Client_Status_Unregistered); } M2MDevice *ServiceClient::device_object_from_storage() @@ -717,6 +746,17 @@ void ServiceClient::m2mdevice_reboot_execute() pal_osReboot(); } +void ServiceClient::send_complete_event(ServiceClientCallback::ServiceClientCallbackStatus status) +{ + if (!_event.data.event_id) { + _event.data.event_id = true; + _event.data.event_data = status; + _event.data.event_type = SERVICE_CLIENT_TASKLET_COMPLETE_EVENT; + _event.data.data_ptr = (void *)&_service_callback; + eventOS_event_send_user_allocated(&_event); + } +} + #ifdef MBED_CLOUD_CLIENT_SUPPORT_UPDATE void ServiceClient::set_update_authorize_handler(void (*handler)(int32_t request)) { diff --git a/source/include/ConnectorClient.h b/source/include/ConnectorClient.h index 82c1d48e8..f6ef256f3 100644 --- a/source/include/ConnectorClient.h +++ b/source/include/ConnectorClient.h @@ -101,7 +101,8 @@ class ConnectorClient : public M2MInterfaceObserver State_Registration_Updated, State_Unregistered, State_Alert_Mode, - State_Paused + State_Paused, + State_Sleep }; public: @@ -302,6 +303,8 @@ class ConnectorClient : public M2MInterfaceObserver virtual void alert_mode(); + virtual void sleep(); + /** * \brief Resumes client's timed functionality and network connection * to the Cloud. Updates registration. Can be only called after diff --git a/source/include/ServiceClient.h b/source/include/ServiceClient.h index af8c12a80..f09c518fb 100644 --- a/source/include/ServiceClient.h +++ b/source/include/ServiceClient.h @@ -28,6 +28,7 @@ #include "mbed-client/m2minterface.h" #include "mbed-client/m2mdevice.h" #include "ConnectorClient.h" +#include "eventOS_event.h" #include @@ -62,7 +63,8 @@ class ServiceClientCallback { Service_Client_Status_Unregistered = 1, Service_Client_Status_Register_Updated = 2, Service_Client_Status_Alert_Mode = 3, - Service_Client_Status_Paused = 4 + Service_Client_Status_Paused = 4, + Service_Client_Status_Sleep = 5 } ServiceClientCallbackStatus; /** @@ -309,6 +311,12 @@ protected : */ void state_unregister(); + /** + * Send complete event. + * \param status, Indicates success or failure in terms of status code. + */ + void send_complete_event(ServiceClientCallback::ServiceClientCallbackStatus status); + private: M2MDevice *device_object_from_storage(); @@ -338,6 +346,8 @@ protected : int8_t _multicast_tasklet_id; #endif // SERVICE_CLIENT_SUPPORT_MULTICAST ConnectorClient _connector_client; + int8_t _tasklet_id; + arm_event_storage_t _event; }; #endif // !__SERVICE_CLIENT_H__ diff --git a/update-client-hub/modules/pal-filesystem/source/arm_uc_pal_linux_extensions.c b/update-client-hub/modules/pal-filesystem/source/arm_uc_pal_linux_extensions.c index 66a14e2c0..08422f526 100644 --- a/update-client-hub/modules/pal-filesystem/source/arm_uc_pal_linux_extensions.c +++ b/update-client-hub/modules/pal-filesystem/source/arm_uc_pal_linux_extensions.c @@ -49,6 +49,8 @@ #define MBED_CONF_UPDATE_CLIENT_APPLICATION_DETAILS 0 #endif +#define CURRENT_FW_HASH_CALCULATION_BUFFER_SIZE 4096 + #ifndef MBED_CONF_UPDATE_CLIENT_BOOTLOADER_DETAILS #define MBED_CONF_UPDATE_CLIENT_BOOTLOADER_DETAILS 0 #endif @@ -74,7 +76,7 @@ static palImageId_t arm_ucex_activate_image_id; * @return ERR_NONE if success, otherwise error */ #if defined(ARM_UC_FEATURE_DELTA_PAAL) && (ARM_UC_FEATURE_DELTA_PAAL == 1) -static int original_file_stat(uint64_t* file_size) +static int original_file_stat(uint64_t *file_size) { arm_uc_error_t result; char file_path[ORIG_FILENAME_MAX_PATH] = { 0 }; @@ -146,7 +148,7 @@ arm_uc_error_t pal_ext_imageGetActiveDetails(arm_uc_firmware_details_t *details) result = arm_uc_parse_external_header_v2(read_buffer, details); } else { /* invalid header format */ - tr_err("Unrecognized firmware header: magic = 0x%" PRIx32 ", version = 0x%" PRIx32 ", size = %" PRIu32 , + tr_err("Unrecognized firmware header: magic = 0x%" PRIx32 ", version = 0x%" PRIx32 ", size = %" PRIu32, headerMagic, headerVersion, bytes_read); } } @@ -156,6 +158,7 @@ arm_uc_error_t pal_ext_imageGetActiveDetails(arm_uc_firmware_details_t *details) // In this version info is fetched only from header file which is created // during update process. tr_info("pal_fsOpen returned status = %" PRIu32, status); + result.code = ERR_NONE; } if (PAL_SUCCESS != status || ERR_NONE != result.code) { @@ -172,12 +175,12 @@ arm_uc_error_t pal_ext_imageGetActiveDetails(arm_uc_firmware_details_t *details) arm_uc_error_t res = ARM_UC_cryptoHashSetup(&mdHandle, ARM_UC_CU_SHA256); if (res.error == ERR_NONE) { // buffer - uint8_t data_buf[ARM_UC_SHA256_SIZE]; + uint8_t data_buf[CURRENT_FW_HASH_CALCULATION_BUFFER_SIZE]; // arm buffer arm_uc_buffer_t buffer; buffer.size = 0; - buffer.size_max = ARM_UC_SHA256_SIZE; + buffer.size_max = CURRENT_FW_HASH_CALCULATION_BUFFER_SIZE; buffer.ptr = data_buf; // reading offset @@ -187,14 +190,14 @@ arm_uc_error_t pal_ext_imageGetActiveDetails(arm_uc_firmware_details_t *details) uint64_t len; // trim to max of file size - if (f_size < ARM_UC_SHA256_SIZE) { + if (f_size < CURRENT_FW_HASH_CALCULATION_BUFFER_SIZE) { len = f_size; } else { - len = ARM_UC_SHA256_SIZE; + len = CURRENT_FW_HASH_CALCULATION_BUFFER_SIZE; } // read original file - while(len > 0 && arm_uc_deltapaal_original_reader(buffer.ptr, len, offset) == ERR_NONE) { + while (len > 0 && arm_uc_deltapaal_original_reader(buffer.ptr, len, offset) == ERR_NONE) { // update hash buffer.size = len; ARM_UC_cryptoHashUpdate(&mdHandle, &buffer); @@ -203,10 +206,10 @@ arm_uc_error_t pal_ext_imageGetActiveDetails(arm_uc_firmware_details_t *details) offset += len; // trim next read to file size if necessary - if (f_size - offset < ARM_UC_SHA256_SIZE) { + if (f_size - offset < CURRENT_FW_HASH_CALCULATION_BUFFER_SIZE) { len = f_size - offset; } else { - len = ARM_UC_SHA256_SIZE; + len = CURRENT_FW_HASH_CALCULATION_BUFFER_SIZE; } } @@ -215,16 +218,14 @@ arm_uc_error_t pal_ext_imageGetActiveDetails(arm_uc_firmware_details_t *details) if (offset == 0) { tr_warn("Original reader failed with first read => keep zero hash"); - } - else { + } else { // copy hash to otherwise zeroed details memcpy(details->hash, buffer.ptr, ARM_UC_SHA256_SIZE); } } else { tr_warn("ARM_UC_cryptoHashSetup failed with %" PRIu32, res.error); } - } - else { + } else { tr_warn("arm_uc_deltapaal_original_stat failed with %d", stat_res); } #endif // #if defined(ARM_UC_FEATURE_DELTA_PAAL) && (ARM_UC_FEATURE_DELTA_PAAL == 1) @@ -269,7 +270,7 @@ static void pal_ext_imageActivationWorker(const void *location) path_buf, PAL_MAX_FILE_AND_FOLDER_LENGTH); #else arm_uc_error_t result = arm_uc_pal_filesystem_get_path(*(palImageId_t *)location, FIRMWARE_IMAGE_ITEM_DATA, - path_buf, PAL_MAX_FILE_AND_FOLDER_LENGTH); + path_buf, PAL_MAX_FILE_AND_FOLDER_LENGTH); #endif palStatus_t rc = PAL_ERR_GENERIC_FAILURE; diff --git a/zephyr/config/zephyr_default.h b/zephyr/config/zephyr_default.h index 2cda874cd..68db10472 100644 --- a/zephyr/config/zephyr_default.h +++ b/zephyr/config/zephyr_default.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2021 Pelion IoT +/* Copyright (c) 2021 Pelion * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/zephyr/config/zephyr_update.h b/zephyr/config/zephyr_update.h index 5b45a8c97..96dc82149 100644 --- a/zephyr/config/zephyr_update.h +++ b/zephyr/config/zephyr_update.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2021 Pelion IoT +/* Copyright (c) 2021 Pelion * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License.