aboutsummaryrefslogtreecommitdiff
path: root/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/lwm2m/lwm2m.c
diff options
context:
space:
mode:
Diffstat (limited to 'thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/lwm2m/lwm2m.c')
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/lwm2m/lwm2m.c885
1 files changed, 885 insertions, 0 deletions
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/lwm2m/lwm2m.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/lwm2m/lwm2m.c
new file mode 100644
index 0000000..bc022f1
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/lwm2m/lwm2m.c
@@ -0,0 +1,885 @@
+/**
+ * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+
+#include "lwm2m_api.h"
+#include "lwm2m_register.h"
+#include "lwm2m_bootstrap.h"
+#include "sdk_os.h"
+#include "lwm2m.h"
+#include "sdk_config.h"
+
+#if LWM2M_CONFIG_LOG_ENABLED
+
+#define NRF_LOG_MODULE_NAME lwm2m
+
+#define NRF_LOG_LEVEL LWM2M_CONFIG_LOG_LEVEL
+#define NRF_LOG_INFO_COLOR LWM2M_CONFIG_INFO_COLOR
+#define NRF_LOG_DEBUG_COLOR LWM2M_CONFIG_DEBUG_COLOR
+
+#include "nrf_log.h"
+NRF_LOG_MODULE_REGISTER();
+
+#define LWM2M_TRC NRF_LOG_DEBUG /**< Used for getting trace of execution in the module. */
+#define LWM2M_ERR NRF_LOG_ERROR /**< Used for logging errors in the module. */
+#define LWM2M_DUMP NRF_LOG_HEXDUMP_DEBUG /**< Used for dumping octet information to get details of bond information etc. */
+
+#define LWM2M_ENTRY() LWM2M_TRC(">> %s", __func__)
+#define LWM2M_EXIT() LWM2M_TRC("<< %s", __func__)
+
+#else // LWM2M_CONFIG_LOG_ENABLED
+
+#define LWM2M_TRC(...) /**< Disables traces. */
+#define LWM2M_DUMP(...) /**< Disables dumping of octet streams. */
+#define LWM2M_ERR(...) /**< Disables error logs. */
+
+#define LWM2M_ENTRY(...)
+#define LWM2M_EXIT(...)
+
+#endif // LWM2M_CONFIG_LOG_ENABLED
+
+#if (LWM2M_CONFIG_LOG_ENABLED != 0)
+
+static uint8_t op_desc_idx_lookup(uint8_t bitmask)
+{
+ for (uint8_t i = 0; i < 8; i++)
+ {
+ if ((bitmask > i) == 0x1)
+ {
+ return i;
+ }
+ }
+
+ // If no bits where set in the bitmask.
+ return 0;
+}
+
+static const char m_operation_desc[8][9] = {
+ "NONE",
+ "READ",
+ "WRITE",
+ "EXECUTE",
+ "DELETE",
+ "CREATE",
+ "DISCOVER",
+ "OBSERVE"
+};
+
+#endif
+
+SDK_MUTEX_DEFINE(m_lwm2m_mutex) /**< Mutex variable. Currently unused, this declaration does not occupy any space in RAM. */
+
+static lwm2m_object_prototype_t * m_objects[LWM2M_COAP_HANDLER_MAX_OBJECTS];
+static lwm2m_instance_prototype_t * m_instances[LWM2M_COAP_HANDLER_MAX_INSTANCES];
+static uint16_t m_num_objects;
+static uint16_t m_num_instances;
+
+static void coap_error_handler(uint32_t error_code, coap_message_t * p_message)
+{
+ LWM2M_ERR("[CoAP]: Unhandled coap message recieved. Error code: %lu", error_code);
+}
+
+static void internal_coap_handler_init(void)
+{
+ memset(m_objects, 0, sizeof(m_objects));
+ memset(m_instances, 0, sizeof(m_instances));
+
+ m_num_objects = 0;
+ m_num_instances = 0;
+}
+
+
+static bool numbers_only(const char * p_str, uint16_t str_len)
+{
+ for (uint16_t i = 0; i < str_len; i++)
+ {
+ if (isdigit(p_str[i]) == 0)
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
+
+static uint32_t instance_resolve(lwm2m_instance_prototype_t ** p_instance,
+ uint16_t object_id,
+ uint16_t instance_id)
+{
+ for (int i = 0; i < m_num_instances; ++i)
+ {
+ if (m_instances[i]->object_id == object_id &&
+ m_instances[i]->instance_id == instance_id)
+ {
+ if (m_instances[i]->callback == NULL)
+ {
+ return NRF_ERROR_NULL;
+ }
+
+ *p_instance = m_instances[i];
+
+ return NRF_SUCCESS;
+ }
+ }
+
+ return NRF_ERROR_NOT_FOUND;
+}
+
+
+static uint32_t object_resolve(lwm2m_object_prototype_t ** p_instance,
+ uint16_t object_id)
+{
+ for (int i = 0; i < m_num_objects; ++i)
+ {
+ if (m_objects[i]->object_id == object_id)
+ {
+ if (m_objects[i]->callback == NULL)
+ {
+ return NRF_ERROR_NULL;
+ }
+
+ *p_instance = m_objects[i];
+
+ return NRF_SUCCESS;
+ }
+ }
+
+ return NRF_ERROR_NOT_FOUND;
+}
+
+static uint32_t op_code_resolve(lwm2m_instance_prototype_t * p_instance,
+ uint16_t resource_id,
+ uint8_t * operation)
+{
+ uint8_t * operations = (uint8_t *) p_instance + p_instance->operations_offset;
+ uint16_t * operations_ids = (uint16_t *)((uint8_t *) p_instance +
+ p_instance->resource_ids_offset);
+
+ for (int j = 0; j < p_instance->num_resources; ++j)
+ {
+ if (operations_ids[j] == resource_id)
+ {
+ *operation = operations[j];
+ return NRF_SUCCESS;
+ }
+ }
+
+ return NRF_ERROR_NOT_FOUND;
+}
+
+static uint32_t internal_request_handle(coap_message_t * p_request,
+ uint16_t * p_path,
+ uint8_t path_len)
+{
+ uint32_t err_code;
+ uint8_t operation = LWM2M_OPERATION_CODE_NONE;
+ uint32_t content_type = 0;
+
+ err_code = coap_message_ct_mask_get(p_request, &content_type);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ /**
+ * TODO: the methods should check if we have read / write / execute rights
+ * through ACL and resource operations
+ */
+
+ switch (p_request->header.code)
+ {
+ case COAP_CODE_GET:
+ {
+ LWM2M_TRC("[CoAP]: CoAP GET request");
+ if (content_type == COAP_CT_APP_LINK_FORMAT) // Discover
+ {
+ operation = LWM2M_OPERATION_CODE_DISCOVER;
+ }
+ else // Read
+ {
+ operation = LWM2M_OPERATION_CODE_READ;
+ }
+ break;
+ }
+
+ case COAP_CODE_PUT:
+ {
+ operation = LWM2M_OPERATION_CODE_WRITE;
+ break;
+ }
+
+ case COAP_CODE_POST:
+ {
+ operation = LWM2M_OPERATION_CODE_WRITE;
+ break;
+ }
+
+ case COAP_CODE_DELETE:
+ {
+ operation = LWM2M_OPERATION_CODE_DELETE;
+ break;
+ }
+
+ default:
+ break; // Maybe send response with unsupported method not allowed?
+ }
+
+ err_code = NRF_ERROR_NOT_FOUND;
+
+ switch (path_len)
+ {
+ case 0:
+ {
+ if (operation == LWM2M_OPERATION_CODE_DELETE)
+ {
+ LWM2M_TRC("[CoAP]: >> %s root /",
+ m_operation_desc[op_desc_idx_lookup(operation)]);
+
+ LWM2M_MUTEX_UNLOCK();
+
+ err_code = lwm2m_coap_handler_root(LWM2M_OPERATION_CODE_DELETE, p_request);
+
+ LWM2M_MUTEX_LOCK();
+
+ LWM2M_TRC("[CoAP]: << %s root /",
+ m_operation_desc[op_desc_idx_lookup(operation)]);
+ }
+ break;
+ }
+
+ case 1:
+ {
+ LWM2M_TRC("[CoAP]: >> %s object /%u/",
+ m_operation_desc[op_desc_idx_lookup(operation)],
+ p_path[0]);
+
+ lwm2m_object_prototype_t * p_object;
+
+ err_code = object_resolve(&p_object, p_path[0]);
+
+ if (err_code != NRF_SUCCESS)
+ {
+ break;
+ }
+
+ LWM2M_MUTEX_UNLOCK();
+
+ err_code = p_object->callback(p_object, LWM2M_INVALID_INSTANCE, operation, p_request);
+
+ LWM2M_MUTEX_LOCK();
+
+ LWM2M_TRC("[CoAP]: << %s object /%u/, result: %s",
+ m_operation_desc[op_desc_idx_lookup(operation)],
+ p_path[0],
+ (err_code == NRF_SUCCESS) ? "SUCCESS" : "NOT_FOUND");
+
+ break;
+ }
+
+ case 2:
+ {
+ LWM2M_TRC("[CoAP]: >> %s instance /%u/%u/",
+ m_operation_desc[op_desc_idx_lookup(operation)],
+ p_path[0],
+ p_path[1]);
+
+ lwm2m_instance_prototype_t * p_instance;
+
+ err_code = instance_resolve(&p_instance, p_path[0], p_path[1]);
+ if (err_code == NRF_SUCCESS)
+ {
+ LWM2M_MUTEX_UNLOCK();
+
+ err_code = p_instance->callback(p_instance, LWM2M_INVALID_RESOURCE, operation, p_request);
+
+ LWM2M_MUTEX_LOCK();
+
+ LWM2M_TRC("[CoAP]: << %s instance /%u/%u/, result: %s",
+ m_operation_desc[op_desc_idx_lookup(operation)],
+ p_path[0],
+ p_path[1],
+ (err_code == NRF_SUCCESS) ? "SUCCESS" : "NOT_FOUND");
+ break;
+ }
+
+ // Bootstrap can write to non-existing instances
+ if (err_code == NRF_ERROR_NOT_FOUND &&
+ operation == LWM2M_OPERATION_CODE_WRITE &&
+ p_request->header.code == COAP_CODE_PUT)
+ {
+ LWM2M_TRC("[CoAP]: >> %s object /%u/%u/",
+ m_operation_desc[op_desc_idx_lookup(operation)],
+ p_path[0],
+ p_path[1]);
+
+ lwm2m_object_prototype_t * p_object;
+
+ err_code = object_resolve(&p_object, p_path[0]);
+
+ if (err_code != NRF_SUCCESS)
+ {
+ break;
+ }
+
+ LWM2M_MUTEX_UNLOCK();
+
+ err_code = p_object->callback(p_object, p_path[1], operation, p_request);
+
+ LWM2M_MUTEX_LOCK();
+
+ LWM2M_TRC("[CoAP]: << %s object /%u/%u/, result: %s",
+ m_operation_desc[op_desc_idx_lookup(operation)],
+ p_path[0],
+ p_path[1],
+ (err_code == NRF_SUCCESS) ? "SUCCESS" : "NOT_FOUND");
+ }
+
+ if (err_code == NRF_ERROR_NOT_FOUND &&
+ operation == LWM2M_OPERATION_CODE_WRITE &&
+ p_request->header.code == COAP_CODE_POST)
+ {
+ LWM2M_TRC("[CoAP]: >> CREATE object /%u/%u/",
+ p_path[0],
+ p_path[1]);
+
+ lwm2m_object_prototype_t * p_object;
+
+ err_code = object_resolve(&p_object, p_path[0]);
+
+ if (err_code != NRF_SUCCESS)
+ {
+ break;
+ }
+
+ LWM2M_MUTEX_UNLOCK();
+
+ err_code = p_object->callback(p_object, p_path[1], LWM2M_OPERATION_CODE_CREATE, p_request);
+
+ LWM2M_MUTEX_LOCK();
+
+ LWM2M_TRC("[CoAP]: << CREATE object /%u/%u/, result: %s",
+ p_path[0],
+ p_path[1],
+ (err_code == NRF_SUCCESS) ? "SUCCESS" : "NOT_FOUND");
+ break;
+ }
+
+ break;
+ }
+
+ case 3:
+ {
+ if (operation == LWM2M_OPERATION_CODE_DELETE)
+ {
+ // Deleting resources within an instance not allowed.
+ break;
+ }
+
+ if (p_request->header.code == COAP_CODE_POST)
+ {
+ for (int i = 0; i < m_num_instances; ++i)
+ {
+ if ((m_instances[i]->object_id == p_path[0]) &&
+ (m_instances[i]->instance_id == p_path[1]))
+ {
+ if (m_instances[i]->callback == NULL)
+ {
+ err_code = NRF_ERROR_NULL;
+ break;
+ }
+
+ uint8_t resource_operation = 0;
+ err_code = op_code_resolve(m_instances[i], p_path[2], &resource_operation);
+
+ if (err_code != NRF_SUCCESS)
+ break;
+
+ if ((resource_operation & LWM2M_OPERATION_CODE_EXECUTE) > 0)
+ {
+ operation = LWM2M_OPERATION_CODE_EXECUTE;
+ }
+
+ if ((resource_operation & LWM2M_OPERATION_CODE_WRITE) > 0)
+ {
+ operation = LWM2M_OPERATION_CODE_WRITE;
+ }
+
+ LWM2M_TRC("[CoAP]: >> %s instance /%u/%u/%u/",
+ m_operation_desc[op_desc_idx_lookup(operation)],
+ m_instances[i]->object_id,
+ m_instances[i]->instance_id,
+ p_path[2]);
+
+ LWM2M_MUTEX_UNLOCK();
+
+ (void)m_instances[i]->callback(m_instances[i],
+ p_path[2],
+ operation,
+ p_request);
+
+ LWM2M_MUTEX_LOCK();
+
+ err_code = NRF_SUCCESS;
+
+ LWM2M_TRC("[CoAP]: << %s instance /%u/%u/%u/",
+ m_operation_desc[op_desc_idx_lookup(operation)],
+ m_instances[i]->object_id,
+ m_instances[i]->instance_id,
+ p_path[2]);
+
+ break;
+ }
+ }
+ }
+ else
+ {
+ LWM2M_TRC("[CoAP]: >> %s instance /%u/%u/%u/",
+ m_operation_desc[op_desc_idx_lookup(operation)],
+ p_path[0],
+ p_path[1],
+ p_path[2]);
+
+ lwm2m_instance_prototype_t * p_instance;
+
+ err_code = instance_resolve(&p_instance, p_path[0], p_path[1]);
+ if (err_code != NRF_SUCCESS)
+ {
+ break;
+ }
+
+ LWM2M_MUTEX_UNLOCK();
+
+ err_code = p_instance->callback(p_instance, p_path[2], operation, p_request);
+
+ LWM2M_MUTEX_LOCK();
+
+ LWM2M_TRC("[CoAP]: << %s instance /%u/%u/%u/, result: %s",
+ m_operation_desc[op_desc_idx_lookup(operation)],
+ p_path[0],
+ p_path[1],
+ p_path[2],
+ (err_code == NRF_SUCCESS) ? "SUCCESS" : "NOT_FOUND");
+ }
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ return err_code;
+}
+
+
+static uint32_t lwm2m_coap_handler_handle_request(coap_message_t * p_request)
+{
+ LWM2M_ENTRY();
+
+ uint16_t index;
+ uint16_t path[3];
+ char * endptr;
+
+ bool is_numbers_only = true;
+ uint16_t path_index = 0;
+ uint32_t err_code = NRF_SUCCESS;
+
+ LWM2M_MUTEX_LOCK();
+
+ for (index = 0; index < p_request->options_count; index++)
+ {
+ if (p_request->options[index].number == COAP_OPT_URI_PATH)
+ {
+ uint16_t option_len = p_request->options[index].length;
+ bool numbers = numbers_only((char *)p_request->options[index].p_data,
+ option_len);
+
+ if (numbers)
+ {
+ // Declare a temporary array that is 1 byte longer than the
+ // option data in order to leave space for a terminating character.
+ uint8_t option_data[option_len + 1];
+ // Set the temporary array to zero.
+ memset(option_data, 0, sizeof(option_data));
+ // Copy the option data string to the temporary array.
+ memcpy(option_data, p_request->options[index].p_data, option_len);
+
+ // Convert the zero-terminated string to a long int value.
+ path[path_index] = strtol((char *)option_data, &endptr, 10);
+
+ ++path_index;
+
+ if (endptr == ((char *)option_data))
+ {
+ err_code = NRF_ERROR_NOT_FOUND;
+ break;
+ }
+
+ if (endptr != ((char *)option_data + option_len))
+ {
+ err_code = NRF_ERROR_NOT_FOUND;
+ break;
+ }
+ }
+ else
+ {
+ is_numbers_only = false;
+ break;
+ }
+ }
+ }
+
+ if (err_code == NRF_SUCCESS)
+ {
+ if (is_numbers_only == true)
+ {
+ err_code = internal_request_handle(p_request, path, path_index);
+ }
+ else
+ {
+ // If uri path did not consist of numbers only.
+ char * requested_uri = NULL;
+ for (index = 0; index < p_request->options_count; index++)
+ {
+ if (p_request->options[index].number == COAP_OPT_URI_PATH)
+ {
+ requested_uri = (char *)p_request->options[index].p_data;
+
+ // Stop on first URI hit.
+ break;
+ }
+ }
+
+ if (requested_uri == NULL)
+ {
+ err_code = NRF_ERROR_NOT_FOUND;
+ }
+ else
+ {
+ // Try to look up if there is a match with object with an alias name.
+ for (int i = 0; i < m_num_objects; ++i)
+ {
+ if (m_objects[i]->object_id == LWM2M_NAMED_OBJECT)
+ {
+ size_t size = strlen(m_objects[i]->p_alias_name);
+ if ((strncmp(m_objects[i]->p_alias_name, requested_uri, size) == 0))
+ {
+ if (m_objects[i]->callback == NULL)
+ {
+ err_code = NRF_ERROR_NULL;
+ break;
+ }
+
+ LWM2M_MUTEX_UNLOCK();
+
+ err_code = m_objects[i]->callback(m_objects[i],
+ LWM2M_INVALID_INSTANCE,
+ LWM2M_OPERATION_CODE_NONE,
+ p_request);
+
+ LWM2M_MUTEX_LOCK();
+
+ break;
+ }
+ }
+ else
+ {
+ // This is not a name object, return error code.
+ err_code = NRF_ERROR_NOT_FOUND;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ LWM2M_MUTEX_UNLOCK();
+
+ LWM2M_EXIT();
+
+ return err_code;
+}
+
+
+uint32_t lwm2m_coap_handler_instance_add(lwm2m_instance_prototype_t * p_instance)
+{
+ LWM2M_ENTRY();
+
+ NULL_PARAM_CHECK(p_instance);
+
+ LWM2M_MUTEX_LOCK();
+
+ if (m_num_instances == LWM2M_COAP_HANDLER_MAX_INSTANCES)
+ {
+ LWM2M_MUTEX_UNLOCK();
+
+ return NRF_ERROR_NO_MEM;
+ }
+
+ m_instances[m_num_instances] = p_instance;
+ ++m_num_instances;
+
+ LWM2M_MUTEX_UNLOCK();
+
+ return NRF_SUCCESS;
+}
+
+
+uint32_t lwm2m_coap_handler_instance_delete(lwm2m_instance_prototype_t * p_instance)
+{
+ LWM2M_ENTRY();
+
+ NULL_PARAM_CHECK(p_instance);
+
+ LWM2M_MUTEX_LOCK();
+
+ for (int i = 0; i < m_num_instances; ++i)
+ {
+ if ((m_instances[i]->object_id == p_instance->object_id) &&
+ (m_instances[i]->instance_id == p_instance->instance_id))
+ {
+ // Move current last entry into this index position, and trim down the length.
+ // If this is the last element, it cannot be accessed because the m_num_instances
+ // count is 0.
+ m_instances[i] = m_instances[m_num_instances - 1];
+ --m_num_instances;
+
+ LWM2M_MUTEX_UNLOCK();
+
+ return NRF_SUCCESS;
+ }
+ }
+
+ LWM2M_MUTEX_UNLOCK();
+
+ return NRF_ERROR_NOT_FOUND;
+}
+
+
+uint32_t lwm2m_coap_handler_object_add(lwm2m_object_prototype_t * p_object)
+{
+ LWM2M_ENTRY();
+
+ NULL_PARAM_CHECK(p_object);
+
+ LWM2M_MUTEX_LOCK();
+
+ if (m_num_objects == LWM2M_COAP_HANDLER_MAX_INSTANCES)
+ {
+ LWM2M_MUTEX_UNLOCK();
+
+ return NRF_ERROR_NO_MEM;
+ }
+
+ m_objects[m_num_objects] = p_object;
+ ++m_num_objects;
+
+ LWM2M_MUTEX_UNLOCK();
+
+ return NRF_SUCCESS;
+}
+
+
+uint32_t lwm2m_coap_handler_object_delete(lwm2m_object_prototype_t * p_object)
+{
+ LWM2M_ENTRY();
+
+ NULL_PARAM_CHECK(p_object);
+
+ LWM2M_MUTEX_LOCK();
+
+ for (int i = 0; i < m_num_objects; ++i)
+ {
+ if ( m_objects[i]->object_id == p_object->object_id)
+ {
+ // Move current last entry into this index position, and trim down the length.
+ // If this is the last element, it cannot be accessed because the m_num_objects
+ // count is 0.
+ m_objects[i] = m_objects[m_num_objects - 1];
+ --m_num_objects;
+
+ LWM2M_MUTEX_UNLOCK();
+
+ return NRF_SUCCESS;
+ }
+ }
+
+ LWM2M_MUTEX_UNLOCK();
+
+ return NRF_ERROR_NOT_FOUND;
+}
+
+
+uint32_t lwm2m_coap_handler_gen_link_format(uint8_t * p_buffer, uint16_t * p_buffer_len)
+{
+
+ LWM2M_ENTRY();
+
+ NULL_PARAM_CHECK(p_buffer_len);
+
+ LWM2M_MUTEX_LOCK();
+
+ uint16_t buffer_index = 0;
+ uint8_t * p_string_buffer;
+ uint16_t buffer_max_size;
+
+ uint8_t dry_run_buffer[16];
+ bool dry_run = false;
+ uint16_t dry_run_size = 0;
+
+ if (p_buffer == NULL)
+ {
+ // Dry-run only, in order to calculate the size of the needed buffer.
+ dry_run = true;
+ p_string_buffer = dry_run_buffer;
+ buffer_max_size = sizeof(dry_run_buffer);
+ }
+ else
+ {
+ p_string_buffer = p_buffer;
+ buffer_max_size = *p_buffer_len;
+ }
+
+ for (int i = 0; i < m_num_objects; ++i)
+ {
+ // We need more than 3 chars to write a new link
+ if (buffer_max_size - buffer_index <= 3)
+ {
+ LWM2M_MUTEX_UNLOCK();
+
+ return NRF_ERROR_NO_MEM;
+ }
+
+ uint16_t curr_object = m_objects[i]->object_id;
+
+ if (curr_object == LWM2M_NAMED_OBJECT)
+ {
+ // Skip this object as it is a named object.
+ continue;
+ }
+
+ bool instance_present = false;
+ for (int j = 0; j < m_num_instances; ++j)
+ {
+ if (m_instances[j]->object_id == curr_object)
+ {
+ instance_present = true;
+
+ buffer_index += snprintf((char *)&p_string_buffer[buffer_index],
+ buffer_max_size - buffer_index,
+ "</%u/%u>,",
+ m_instances[j]->object_id,
+ m_instances[j]->instance_id);
+ if (dry_run == true)
+ {
+ dry_run_size += buffer_index;
+ buffer_index = 0;
+ }
+ }
+ }
+
+ if (!instance_present)
+ {
+ buffer_index += snprintf((char *)&p_string_buffer[buffer_index],
+ buffer_max_size - buffer_index,
+ "</%u>,",
+ curr_object);
+ if (dry_run == true)
+ {
+ dry_run_size += buffer_index;
+ buffer_index = 0;
+ }
+ }
+ }
+
+ if (dry_run == true)
+ {
+ *p_buffer_len = dry_run_size - 1;
+ }
+ else
+ {
+ *p_buffer_len = buffer_index - 1; // Remove the last comma
+ }
+
+ LWM2M_MUTEX_UNLOCK();
+
+ return NRF_SUCCESS;
+}
+
+
+uint32_t lwm2m_init(void)
+{
+ SDK_MUTEX_INIT(m_lwm2m_mutex);
+
+ LWM2M_MUTEX_LOCK();
+
+ uint32_t err_code;
+
+ err_code = internal_lwm2m_register_init();
+ if (err_code != NRF_SUCCESS)
+ {
+ LWM2M_MUTEX_UNLOCK();
+ return err_code;
+ }
+
+ err_code = internal_lwm2m_bootstrap_init();
+ if (err_code != NRF_SUCCESS)
+ {
+ LWM2M_MUTEX_UNLOCK();
+ return err_code;
+ }
+
+ err_code = coap_error_handler_register(coap_error_handler);
+ if (err_code != NRF_SUCCESS)
+ {
+ LWM2M_MUTEX_UNLOCK();
+ return err_code;
+ }
+
+ internal_coap_handler_init();
+
+ err_code = coap_request_handler_register(lwm2m_coap_handler_handle_request);
+
+ LWM2M_MUTEX_UNLOCK();
+
+ return err_code;
+}