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 3>;pmin=10,3/0>,3/0/1>,3/0/2>,3/0/3>,3/0/4>,3/0/6>,3/0/7>,3/0/8>,3/0/11>,3/0/16>
+ // 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 3/0>;pmax=60,3/0/1>,<3/0/2>,3/0/3>,3/0/4>,3/0/6>;dim=8,3/0/7>;dim=8;gt=50;lt=42.2,3/0/8>;dim=8,3/0/11>,3/0/16>
+ // 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
+ // 3/0/7>;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, "", 2);
+ *data += 2;
+ memcpy(*data, path, strlen(path));
+ *data += strlen(path);
+ 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.